From: Sangchul Lee Date: Wed, 27 Jul 2022 08:02:44 +0000 (+0900) Subject: webrtc_test: Add webrtc_test_signaling.c and move related codes to it X-Git-Tag: submit/tizen/20220729.014452^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=17849660023f8ea22f92220e39284e6668aeb18c;p=platform%2Fcore%2Fapi%2Fwebrtc.git webrtc_test: Add webrtc_test_signaling.c and move related codes to it [Version] 0.3.180 [Issue Type] Refactoring Change-Id: I4b75e65616d28a2bda6da4bc95f9c45160ff5ac5 Signed-off-by: Sangchul Lee --- diff --git a/packaging/capi-media-webrtc.spec b/packaging/capi-media-webrtc.spec index 0b125f80..6a72dfa6 100644 --- a/packaging/capi-media-webrtc.spec +++ b/packaging/capi-media-webrtc.spec @@ -1,6 +1,6 @@ Name: capi-media-webrtc Summary: A WebRTC library in Tizen Native API -Version: 0.3.179 +Version: 0.3.180 Release: 0 Group: Multimedia/API License: Apache-2.0 diff --git a/test/webrtc_test.c b/test/webrtc_test.c index 1b475ead..fb138960 100644 --- a/test/webrtc_test.c +++ b/test/webrtc_test.c @@ -17,7 +17,6 @@ #include "webrtc_test_priv.h" #include -#include #include #include #include @@ -162,7 +161,7 @@ static void __release_packet_source(int conn_idx, unsigned int source_idx) g_cond_clear(&packet_source->cond); } -static void _webrtc_create(int index) +void _webrtc_create(int index) { int ret = WEBRTC_ERROR_NONE; @@ -175,7 +174,7 @@ static void _webrtc_create(int index) g_print("webrtc[%p, index:%d] is created\n", g_ad.conns[index].webrtc, index); } -static void _webrtc_destroy(int index) +void _webrtc_destroy(int index) { int ret = WEBRTC_ERROR_NONE; int i; @@ -236,7 +235,7 @@ static void _webrtc_destroy(int index) #endif } -static void _webrtc_start(int index) +void _webrtc_start(int index) { int ret = WEBRTC_ERROR_NONE; @@ -251,7 +250,7 @@ static void _webrtc_start(int index) #endif } -static void _webrtc_stop(int index) +void _webrtc_stop(int index) { int ret = WEBRTC_ERROR_NONE; int i; @@ -452,7 +451,7 @@ error: return -1; } -static void _webrtc_add_media_source(int index, int type, unsigned int *source_id) +void _webrtc_add_media_source(int index, int type, unsigned int *source_id) { int ret = WEBRTC_ERROR_NONE; unsigned int _source_id = 0; @@ -492,7 +491,7 @@ static void _webrtc_add_media_source(int index, int type, unsigned int *source_i *source_id = _source_id; } -static void _webrtc_add_mic_source(int index, bool aec, unsigned int *source_id) +void _webrtc_add_mic_source(int index, bool aec, unsigned int *source_id) { int ret = WEBRTC_ERROR_NONE; unsigned int _source_id = 0; @@ -783,7 +782,7 @@ static void _webrtc_media_source_set_transceiver_codec(int index, unsigned int s source_id, g_webrtc_media_type_str[media_type], g_webrtc_transceiver_codec_str[codec]); } -static void _webrtc_set_display_type(int index, int type) +void _webrtc_set_display_type(int index, int type) { g_ad.conns[index].render.display_type = type; @@ -858,7 +857,7 @@ static void _webrtc_media_source_unset_audio_loopback(int index, unsigned int so g_print("webrtc_media_source_unset_audio_loopback() success, source_id[%u]\n", source_id); } -static void _webrtc_media_source_set_video_loopback(int index, unsigned int source_id) +void _webrtc_media_source_set_video_loopback(int index, unsigned int source_id) { int ret = WEBRTC_ERROR_NONE; unsigned int track_id; @@ -880,25 +879,6 @@ static void _webrtc_media_source_unset_video_loopback(int index, unsigned int so g_print("webrtc_media_source_unset_video_loopback() success, source_id[%u]\n", source_id); } -static int __copy_string_arr(gchar *dest_arr, char *string) -{ - int len = 0; - gsize src_size = 0; - - if (!string) - return -1; - - len = strlen(string); - - src_size = g_strlcpy(dest_arr, string, MAX_STRING_LEN); - if ((int)src_size != len) { - g_print("failed to g_strlcpy()\n"); - return -1; - } - - return 0; -} - static void _webrtc_data_channel_send_string(const char *string, bool send_as_bytes) { int ret; @@ -1119,7 +1099,7 @@ static void _webrtc_set_local_description(connection_s *conn, bool is_offer) g_print("webrtc_set_local_description() success\n"); } -static void _webrtc_set_remote_description(connection_s *conn) +void _webrtc_set_remote_description(connection_s *conn) { int ret = WEBRTC_ERROR_NONE; @@ -1144,7 +1124,7 @@ static void __foreach_ice_candidate(gpointer data, gpointer user_data) g_print("webrtc_ice_candidate() success\n"); } -static void _webrtc_add_ice_candidate(connection_s *conn, const gchar *candidate) +void _webrtc_add_ice_candidate(connection_s *conn, const gchar *candidate) { RET_IF(!conn, "conn is NULL"); @@ -1648,19 +1628,6 @@ static void __error_cb(webrtc_h webrtc, webrtc_error_e error, webrtc_state_e sta webrtc, error, state, user_data); } -static void _websocket_connection_send_text_for_room(connection_s *conn, int remote_peer_id, const char *message) -{ - gchar *message_for_room; - - RET_IF(!conn, "conn is NULL"); - RET_IF(!conn->is_for_room, "conn[%p] is not for room", conn); - RET_IF(!message, "message is NULL"); - - message_for_room = g_strdup_printf ("ROOM_PEER_MSG %d %s", remote_peer_id, message); - soup_websocket_connection_send_text(g_ad.signaling_server.public.ws_conn, message_for_room); - g_free(message_for_room); -} - static void __state_changed_cb(webrtc_h webrtc, webrtc_state_e previous, webrtc_state_e current, void *user_data) { connection_s *conn = (connection_s *)user_data; @@ -1677,7 +1644,7 @@ static void __state_changed_cb(webrtc_h webrtc, webrtc_state_e previous, webrtc_ if (conn->is_offer) { _webrtc_create_offer(conn, false); _webrtc_set_local_description(conn, true); - _websocket_connection_send_text_for_room(conn, conn->remote_peer_id, conn->offer); + _websocket_send_text_for_room(conn, conn->remote_peer_id, conn->offer); } else { if (conn->remote_desc) _webrtc_set_remote_description(conn); @@ -1692,104 +1659,6 @@ static void __negotiation_needed_cb(webrtc_h webrtc, void *user_data) g_print("__negotiation_needed_cb() is invoked, webrtc[%p], user_data[%p]\n", webrtc, user_data); } -static void __signaling_message_cb(webrtc_signaling_message_type_e type, const char *message, void *user_data) -{ - connection_s *conn = (connection_s *)user_data; - - g_print("__signaling_message_cb(), type[%d] message[%s] conn[%p]\n", type, message, conn); - - if (type == SIGNALING_MESSAGE_TYPE_CONNECTED) { - g_print("\n[from SERVER > CONNECTED %s]\n", message); - g_ad.signaling_server.is_connected = true; - g_ad.signaling_server.server_status = SERVER_STATUS_CONNECTED; - g_ad.signaling_server.local_peer_id = atoi(message); - - } else if (type == SIGNALING_MESSAGE_TYPE_DISCONNECTED) { - g_print("\n[from SERVER > DISCONNECTED %s]\n", message); - g_ad.signaling_server.is_connected = false; - g_ad.signaling_server.server_status = SERVER_STATUS_DISCONNECTED; - - } else if (type == SIGNALING_MESSAGE_TYPE_SESSION_ESTABLISHED) { - g_print("\n[from SERVER > SESSION_ESTABLISHED with %s]\n", message); - g_ad.signaling_server.server_status = SERVER_STATUS_SESSION_ESTABLISHED; - - } else if (type == SIGNALING_MESSAGE_TYPE_SESSION_CLOSED) { - g_print("\n[from SERVER > SESSION_CLOSED with %s]\n", message); - g_ad.signaling_server.server_status = SERVER_STATUS_SESSION_CLOSED; - - } else if (type == SIGNALING_MESSAGE_TYPE_SDP) { - g_print("\n[from SERVER > SDP]\n%s\n", message); - if (conn->remote_desc) - free(conn->remote_desc); - conn->remote_desc = strdup(message); - - } else if (type == SIGNALING_MESSAGE_TYPE_ICE_CANDIDATE) { - g_print("\n[from SERVER > ICE]\n%s\n", message); - conn->ice_candidates = g_list_append(conn->ice_candidates, strdup(message)); - } -} - -static int _webrtc_signaling_connect(const char *ip, int port) -{ - int ret; - - if (strlen(g_ad.signaling_server.public.url) > 0) { - g_printerr("server[%s] is already set by 'ss'\n", g_ad.signaling_server.public.url); - return -1; - } - - ret = webrtc_signaling_connect(ip, port, __signaling_message_cb, &g_ad.conns[0], &g_ad.signaling_server.private.client); - RET_VAL_IF(ret != WEBRTC_ERROR_NONE, -1, "failed to webrtc_signaling_connect(), ret[0x%x]", ret); - - if (g_ad.signaling_server.private.ip) - free(g_ad.signaling_server.private.ip); - g_ad.signaling_server.private.ip = strdup(ip); - g_ad.signaling_server.private.port = port; - - g_print("webrtc_signaling_connect() success\n"); - - return 0; -} - -static void _webrtc_signaling_disconnect(void) -{ - int ret; - - RET_IF(!g_ad.signaling_server.is_connected, "signaling server is not connected"); - - ret = webrtc_signaling_disconnect(g_ad.signaling_server.private.client); - RET_IF(ret != WEBRTC_ERROR_NONE, "ret[0x%x]", ret); - - g_print("webrtc_signaling_disconnect() success\n"); - - g_ad.signaling_server.private.client = NULL; -} - -static void _webrtc_signaling_request_session(int peer_id) -{ - int ret; - - RET_IF(!g_ad.signaling_server.is_connected, "signaling server is not connected"); - - ret = webrtc_signaling_request_session(g_ad.signaling_server.private.client, peer_id); - RET_IF(ret != WEBRTC_ERROR_NONE, "ret[0x%x]", ret); - - g_print("webrtc_signaling_request_session() success\n"); -} - -static void _webrtc_signaling_send_message(const char *message) -{ - int ret; - - RET_IF(!message, "message is NULL"); - RET_IF(!g_ad.signaling_server.is_connected, "signaling server is not connected"); - - ret = webrtc_signaling_send_message(g_ad.signaling_server.private.client, message); - RET_IF(ret != WEBRTC_ERROR_NONE, "ret[0x%x]", ret); - - g_print("webrtc_signaling_send_message() success\n"); -} - static void __ice_candidate_cb(webrtc_h webrtc, const char *candidate, void *user_data) { connection_s *conn = (connection_s *)user_data; @@ -1799,17 +1668,7 @@ static void __ice_candidate_cb(webrtc_h webrtc, const char *candidate, void *use g_print("\n[to SERVER > ICE]\n%s\n", candidate); - RET_IF(!g_ad.signaling_server.is_connected, "signaling server is not connected"); - - if (g_ad.signaling_server.public.ws_conn) { - if (conn->is_for_room) - _websocket_connection_send_text_for_room(conn, conn->remote_peer_id, candidate); - else - soup_websocket_connection_send_text(g_ad.signaling_server.public.ws_conn, candidate); - - } else if (g_ad.signaling_server.private.client) { - _webrtc_signaling_send_message(candidate); - } + _send_ice_candidate(conn, candidate); } static void __peer_connection_state_change_cb(webrtc_h webrtc, webrtc_peer_connection_state_e state, void *user_data) @@ -1833,7 +1692,7 @@ static void __signaling_state_change_cb(webrtc_h webrtc, webrtc_signaling_state_ if (conn->is_for_room && state == WEBRTC_SIGNALING_STATE_HAVE_REMOTE_OFFER) { _webrtc_create_answer(conn, false); _webrtc_set_local_description(conn, false); - _websocket_connection_send_text_for_room(conn, conn->remote_peer_id, conn->answer); + _websocket_send_text_for_room(conn, conn->remote_peer_id, conn->answer); } } @@ -1855,7 +1714,7 @@ static void __ice_connection_state_change_cb(webrtc_h webrtc, webrtc_ice_connect g_print("__ice_connection_state_change_cb() is invoked, state[%u, %u]\n", state, _state); } -static void _webrtc_set_all_negotiation_state_change_cbs(int index) +void _webrtc_set_all_negotiation_state_change_cbs(int index) { int ret = webrtc_set_peer_connection_state_change_cb(g_ad.conns[index].webrtc, __peer_connection_state_change_cb, &g_ad.conns[index]); if (ret != WEBRTC_ERROR_NONE) @@ -2006,7 +1865,7 @@ static void __track_added_cb(webrtc_h webrtc, webrtc_media_type_e type, unsigned } } -static void _webrtc_set_all_basic_cbs(int index) +void _webrtc_set_all_basic_cbs(int index) { /* COMMON */ int ret = webrtc_set_error_cb(g_ad.conns[index].webrtc, __error_cb, g_ad.conns[index].webrtc); @@ -2267,7 +2126,7 @@ static void _webrtc_unset_all_cbs(int index) } } -static void _webrtc_create_data_channel(int index) +void _webrtc_create_data_channel(int index) { int ret = WEBRTC_ERROR_NONE; gchar *label; @@ -2292,7 +2151,7 @@ static void _webrtc_create_data_channel(int index) g_free(label); } -static void _webrtc_destroy_data_channel(int index) +void _webrtc_destroy_data_channel(int index) { int ret = WEBRTC_ERROR_NONE; int i; @@ -2334,95 +2193,6 @@ static void _webrtc_data_channel_get_label(int index) } } -static int _setting_uri(gchar *dest_arr, char *uri) -{ - int ret = 0; - - if (!uri) - return -1; - - if (g_ad.signaling_server.private.client) { - g_printerr("already set by 'scc'\n"); - return -1; - } - - if (strlen(uri) > strlen("0.0.0.0")) { - ret = __copy_string_arr(dest_arr, uri); - if (ret != 0) { - g_print("failed to __copy_string_arr()\n"); - return -1; - } - } else { - g_print("invalid value, uri[%s]\n", uri); - return -1; - } - - return 0; -} - -static void _request_session(int remote_peer_id) -{ - RET_IF(!g_ad.signaling_server.is_connected, "signaling server is not connected"); - - if (g_ad.signaling_server.public.ws_conn) { - gchar *msg; - if (soup_websocket_connection_get_state(g_ad.signaling_server.public.ws_conn) != SOUP_WEBSOCKET_STATE_OPEN) { - g_printerr("websocket is not opened\n"); - return; - } - - msg = g_strdup_printf("SESSION %d", remote_peer_id); - - g_print("\n[to SERVER > %s]\n", msg); - soup_websocket_connection_send_text(g_ad.signaling_server.public.ws_conn, msg); - g_free(msg); - - } else if (g_ad.signaling_server.private.client) { - _webrtc_signaling_request_session(remote_peer_id); - - } else { - g_printerr("Neither public nor private signaling server is connected\n"); - } -} - -static void _request_join_room(char *room_name) -{ - gchar *msg; - - RET_IF(!room_name, "room_name is NULL"); - RET_IF(!g_ad.signaling_server.is_connected, "signaling server is not connected"); - RET_IF(!g_ad.signaling_server.public.ws_conn, "ws_conn is NULL"); - - if (soup_websocket_connection_get_state(g_ad.signaling_server.public.ws_conn) != SOUP_WEBSOCKET_STATE_OPEN) { - g_printerr("websocket is not opened\n"); - return; - } - - msg = g_strdup_printf("ROOM %s", room_name); - - g_print("\n[to SERVER > %s]\n", msg); - soup_websocket_connection_send_text(g_ad.signaling_server.public.ws_conn, msg); - g_free(msg); -} - -static void _send_local_description(bool is_offer) -{ - char *desc; - - RET_IF(!g_ad.signaling_server.is_connected, "signaling server is not connected"); - - desc = is_offer ? g_ad.conns[0].offer : g_ad.conns[0].answer; - - g_print("\n[to SERVER > local description]\n%s\n", desc); - - if (g_ad.signaling_server.public.ws_conn) - soup_websocket_connection_send_text(g_ad.signaling_server.public.ws_conn, desc); - else if (g_ad.signaling_server.private.client) - _webrtc_signaling_send_message(desc); - else - g_printerr("Neither public nor private signaling server is connected\n"); -} - gulong _connect_signal(GObject *obj, const char *signal_name, GCallback callback, gpointer user_data) { gulong signal_id; @@ -3135,427 +2905,6 @@ static void _webrtc_file_source_get_looping(int index, unsigned int source_id) g_print("webrtc_file_source_get_looping() success, source_id[%u] looping_state[%u]\n", source_id, looping_state); } -static void __close_websocket(signaling_server_s *ss) -{ - RET_IF(!ss, "ss is NULL"); - - g_print("close websocket, ws_conn[%p]\n", ss->public.ws_conn); - - if (soup_websocket_connection_get_state(ss->public.ws_conn) == SOUP_WEBSOCKET_STATE_OPEN) - soup_websocket_connection_close(ss->public.ws_conn, 1000, ""); - else - g_object_unref(ss->public.ws_conn); - - ss->public.ws_conn = NULL; - ss->server_status = SERVER_STATUS_DISCONNECTED; - ss->is_connected = false; -} - -static void __websocket_closed_cb(SoupWebsocketConnection *ws_conn, gpointer user_data) -{ - signaling_server_s *ss = (signaling_server_s *)user_data; - - RET_IF(!ss, "ss is NULL"); - RET_IF(!ws_conn, "ws_conn is NULL"); - RET_IF(ss->public.ws_conn != ws_conn, "not matched ws_conn[%p, %p]", ss->public.ws_conn, ws_conn); - - __close_websocket(ss); -} - -static void __auto_configure_add_peer(gchar *peer_id, bool is_offer) -{ - int i; - - RET_IF(!peer_id, "peer_id is NULL"); - - if (!strcmp(peer_id,"")) - return; - - g_print("add peer[%s] to make an %s\n", peer_id, is_offer ? "offer" : "answer"); - - for (i = 0; i < MAX_CONNECTION_LEN; i++) { - unsigned int source_id = 0; - - if (g_ad.conns[i].webrtc) - continue; - - g_ad.conns[i].remote_peer_id = atoi((const char *)peer_id); - g_ad.conns[i].is_for_room = true; - g_ad.conns[i].is_offer = is_offer; - if (i > 0) /* follow the source type of the first one */ - g_ad.conns[i].room_source_type = g_ad.conns[0].room_source_type; - - _webrtc_create(i); - _webrtc_set_all_basic_cbs(i); - _webrtc_set_all_negotiation_state_change_cbs(i); - _webrtc_create_data_channel(i); - - switch (g_ad.conns[i].room_source_type) { - case 1: - _webrtc_add_media_source(i, WEBRTC_MEDIA_SOURCE_TYPE_AUDIOTEST, NULL); - _webrtc_add_media_source(i, WEBRTC_MEDIA_SOURCE_TYPE_VIDEOTEST, &source_id); - if (i == 0) /* only set loopback video of the first one */ - _webrtc_media_source_set_video_loopback(i, source_id); - break; - case 2: - _webrtc_add_mic_source(i, false, NULL); - _webrtc_add_media_source(i, WEBRTC_MEDIA_SOURCE_TYPE_CAMERA, &source_id); - if (i == 0) /* only set loopback video of the first one */ - _webrtc_media_source_set_video_loopback(i, source_id); - break; - case 3: - _webrtc_add_mic_source(i, false, NULL); - break; - default: - return; - } - - _webrtc_start(i); - _webrtc_set_display_type(i, WEBRTC_DISPLAY_TYPE_EVAS); - - return; - } - g_printerr("failed to __auto_configure_add_peer_to_offer()\n"); -} - -static connection_s *__get_conn_from_peer_id(gchar *peer_id, int *index) -{ - int i; - - if (!peer_id) { - g_printerr("peer_id is NULL\n"); - return NULL; - } - - for (i = 0; i < MAX_CONNECTION_LEN; i++) { - if (g_ad.conns[i].remote_peer_id <= 0) - continue; - if (g_ad.conns[i].remote_peer_id == atoi((const char *)peer_id)) { - if (index) - *index = i; - return &g_ad.conns[i]; - } - } - - g_printerr("not found matching conn from peer_id[%s]", peer_id); - return NULL; -} - -static void __auto_configure_release_peer(gchar *peer_id) -{ - connection_s *conn; - int i; - - RET_IF(!peer_id, "peer_id is NULL"); - - g_print("release peer[%s] related resources\n", peer_id); - - if (!(conn = __get_conn_from_peer_id(peer_id, &i))) - return; - - _webrtc_stop(i); - _webrtc_destroy_data_channel(i); - _webrtc_destroy(i); -} - -static void __handle_json_structured_message(connection_s *conn, const gchar *text) -{ - JsonNode *root; - JsonObject *object; - JsonParser *parser; - - RET_IF(!conn, "conn is NULL"); - RET_IF(!text, "text is NULL"); - - parser = json_parser_new(); - - if (!json_parser_load_from_data(parser, text, -1, NULL)) { - g_printerr("unknown message [%s]\n", text); - g_object_unref(parser); - return; - } - - root = json_parser_get_root(parser); - if (!JSON_NODE_HOLDS_OBJECT(root)) { - g_printerr("unknown JSON message [%s]\n", text); - g_object_unref(parser); - return; - } - - object = json_node_get_object(root); - if (json_object_has_member(object, "sdp")){ - g_print("\n[from SERVER > SDP]\n%s\n", text); - if (conn->remote_desc) - free(conn->remote_desc); - conn->remote_desc = strdup(text); - - if (conn->is_for_room) { - webrtc_state_e state = WEBRTC_STATE_IDLE; - webrtc_get_state(conn->webrtc, &state); - if (state == WEBRTC_STATE_NEGOTIATING) - _webrtc_set_remote_description(conn); - } - - } else if (json_object_has_member(object, "ice")){ - g_print("\n[from SERVER > ICE]\n%s\n", text); - if (conn->is_for_room) { - webrtc_state_e state = WEBRTC_STATE_IDLE; - webrtc_get_state(conn->webrtc, &state); - if (state == WEBRTC_STATE_NEGOTIATING) - _webrtc_add_ice_candidate(conn, text); - else - conn->ice_candidates = g_list_append(conn->ice_candidates, strdup(text)); - } else { - conn->ice_candidates = g_list_append(conn->ice_candidates, strdup(text)); - } - - } else { - g_printerr("neither 'sdp' nor 'ice' member exist in JSON message [%s]\n", text); - } - - g_object_unref(parser); -} - -static void __auto_configure_handle_room_message(gchar *peer_id, gchar *message) -{ - connection_s *conn; - - RET_IF(!peer_id, "peer_id is NULL"); - RET_IF(!message, "message is NULL"); - - g_print("peer[%s], message[%s]\n", peer_id, message); - - if (!(conn = __get_conn_from_peer_id(peer_id, NULL))) - return; - - __handle_json_structured_message(conn, message); -} - -static void __handle_room_related_message(const gchar *text) -{ - g_auto(GStrv) tokens = NULL; - guint len; - guint i; - - RET_IF(!text, "text is NULL"); - - if (g_str_has_prefix(text, "ROOM_OK")) { - g_print("\n[from SERVER > %s]\n", text); - g_ad.signaling_server.server_status = SERVER_STATUS_ROOM_ESTABLISHED; - - /* parse text, get the previous peers in the room and negotiate to each other */ - if (strlen(text) > strlen("ROOM_OK")) { - /* e.g. ROOM_OK 1234 5311 324 */ - tokens = g_strsplit(text, " ", 0); - len = g_strv_length(tokens); - for (i = 1; i < len; i++) { - if (i > MAX_CONNECTION_LEN) { - g_print("connection[%d], out of range\n", i); - break; - } - __auto_configure_add_peer(tokens[i], true); - } - } - - } else if (g_str_has_prefix(text, "ROOM_PEER_JOINED")) { - g_print("\n[from SERVER > %s]\n", text); - /* e.g. ROOM_PEER_JOINED 1234 */ - tokens = g_strsplit(text, " ", 2); - __auto_configure_add_peer(tokens[1], false); - - } else if (g_str_has_prefix(text, "ROOM_PEER_LEFT")) { - g_print("\n[from SERVER > %s]\n", text); - /* e.g. ROOM_PEER_LEFT 1234 */ - tokens = g_strsplit(text, " ", 2); - __auto_configure_release_peer(tokens[1]); - - } else if (g_str_has_prefix(text, "ROOM_PEER_MSG")) { - g_print("\n[from SERVER > %s]\n", text); - /* e.g. ROOM_PEER_MSG 1234 msg */ - tokens = g_strsplit(text, " ", 3); - __auto_configure_handle_room_message(tokens[1], tokens[2]); - - } else { - g_print("\n[from SERVER > %s]\n", text); - g_ad.signaling_server.server_status = SERVER_STATUS_ERROR_FOUND; - } -} - -static void __websocket_message_cb(SoupWebsocketConnection *ws_conn, SoupWebsocketDataType type, GBytes *message, gpointer user_data) -{ - gchar *text; - gsize size; - const gchar *data; - connection_s *conn = (connection_s *)user_data; - - RET_IF(!conn, "conn is NULL"); - RET_IF(!ws_conn, "ws_conn is NULL"); - RET_IF(g_ad.signaling_server.public.ws_conn != ws_conn, "not matched ws_conn[%p, %p]", g_ad.signaling_server.public.ws_conn, ws_conn); - RET_IF(type != SOUP_WEBSOCKET_DATA_TEXT, "invalid data type(%d)", type); - - data = g_bytes_get_data(message, &size); - text = g_strndup(data, size); - - /* NOTE: Logics below can be different in each server */ - if (g_strcmp0(text, "HELLO") == 0) { - g_print("\n[from SERVER > %s] registered done, local_peer_id[%d]\n", text, g_ad.signaling_server.local_peer_id); - - } else if (g_strcmp0(text, "SESSION_OK") == 0) { - g_print("\n[from SERVER > %s]\n", text); - g_ad.signaling_server.server_status = SERVER_STATUS_SESSION_ESTABLISHED; - - } else if (g_str_has_prefix(text, "ROOM_")) { - __handle_room_related_message(text); - - } else if (g_str_has_prefix(text, "ERROR")) { - g_print("\n[from SERVER > %s]\n", text); - g_ad.signaling_server.server_status = SERVER_STATUS_ERROR_FOUND; - - } else { - __handle_json_structured_message(conn, text); - } - - g_free(text); -} - -static gint32 __send_greeting_to_register(SoupWebsocketConnection *conn) -{ - gchar *hello; - gint32 id; - - if (!conn) { - g_printerr("conn is NULL\n"); - return -1; - } - - if (soup_websocket_connection_get_state(conn) != SOUP_WEBSOCKET_STATE_OPEN) { - g_printerr("websocket is not opened\n"); - return -1; - } - - id = g_random_int_range(10, 10000); - hello = g_strdup_printf("HELLO %i", id); - - soup_websocket_connection_send_text(conn, hello); - - g_free(hello); - - return id; -} - -static void __websocket_connected_cb(SoupSession *session, GAsyncResult *res, void *user_data) -{ - GError *error = NULL; - SoupWebsocketConnection *ws_conn; - connection_s *conn = (connection_s *)user_data; - - RET_IF(!conn, "conn is NULL"); - - ws_conn = soup_session_websocket_connect_finish(session, res, &error); - if (error) { - if (soup_websocket_connection_get_state(ws_conn) == SOUP_WEBSOCKET_STATE_OPEN) - soup_websocket_connection_close(ws_conn, 1000, ""); - else { - g_print("NOT OPENED\n"); - g_object_unref(ws_conn); - } - g_print("failed to soup_session_websocket_connect_finish(), error[%s]\n", error->message); - g_error_free(error); - return; - } - g_print("\n[%s] is connected, conn[%p]\n", g_ad.signaling_server.public.url, conn); - - g_ad.signaling_server.public.ws_conn = ws_conn; - g_ad.signaling_server.server_status = SERVER_STATUS_CONNECTED; - - g_signal_connect(ws_conn, "closed", G_CALLBACK(__websocket_closed_cb), &g_ad.signaling_server); - g_signal_connect(ws_conn, "message", G_CALLBACK(__websocket_message_cb), conn); - - g_ad.signaling_server.local_peer_id = __send_greeting_to_register(ws_conn); - g_ad.signaling_server.is_connected = true; -} - -static int _connect_signaling_server(void) -{ - SoupMessage *message; - SoupSession *session; - SoupURI *proxy_uri; - const char *https_aliases[] = {"wss", NULL}; - - RET_VAL_IF(g_ad.signaling_server.private.client, -1, "already set by 'scc'"); - - if (strlen(g_ad.proxy) == 0) { - session = soup_session_new_with_options(SOUP_SESSION_SSL_STRICT, TRUE, - SOUP_SESSION_HTTPS_ALIASES, https_aliases, NULL); - } else { - g_print("use proxy [%s]\n", g_ad.proxy); - proxy_uri = soup_uri_new(g_ad.proxy); - session = soup_session_new_with_options(SOUP_SESSION_SSL_STRICT, TRUE, - SOUP_SESSION_SSL_USE_SYSTEM_CA_FILE, TRUE, - SOUP_SESSION_PROXY_URI, proxy_uri, - SOUP_SESSION_SSL_CA_FILE, "/opt/var/lib/ca-certificates/ca-bundle.pem", - SOUP_SESSION_HTTPS_ALIASES, https_aliases, NULL); - soup_uri_free(proxy_uri); - } - - message = soup_message_new(SOUP_METHOD_GET, g_ad.signaling_server.public.url); - - g_print("connecting to signaling server[%s]...\n", g_ad.signaling_server.public.url); - - soup_session_websocket_connect_async(session, message, NULL, NULL, NULL, - (GAsyncReadyCallback) __websocket_connected_cb, &g_ad.conns[0]); - - return 0; -} - -static int _webrtc_signaling_server_create(int port) -{ - int ret; - - ret = webrtc_signaling_server_create(port, &(g_ad.signaling_server.private.server)); - RET_VAL_IF(ret != WEBRTC_ERROR_NONE, -1, "failed to webrtc_signaling_server_create(), ret[0x%x]", ret); - - g_print("webrtc_signaling_server_create() success, port[%d] g_ad.signaling_server.private.server[%p]\n", - port, g_ad.signaling_server.private.server); - - g_ad.signaling_server.private.server_port = port; - - return 0; -} - -static void _webrtc_signaling_server_destroy(void) -{ - int ret; - - ret = webrtc_signaling_server_destroy(g_ad.signaling_server.private.server); - RET_IF(ret != WEBRTC_ERROR_NONE, "failed to webrtc_signaling_server_destroy(), ret[0x%x]", ret); - - g_print("webrtc_signaling_server_destroy() success\n"); - g_ad.signaling_server.private.server = NULL; -} - -static int _webrtc_signaling_server_start(void) -{ - int ret; - - ret = webrtc_signaling_server_start(g_ad.signaling_server.private.server); - RET_VAL_IF(ret != WEBRTC_ERROR_NONE, -1, "webrtc_signaling_server_start(), ret[0x%x]", ret); - - g_print("webrtc_signaling_server_start() success\n"); - - return 0; -} - -static void _webrtc_signaling_server_stop(void) -{ - int ret; - - ret = webrtc_signaling_server_stop(g_ad.signaling_server.private.server); - RET_IF(ret != WEBRTC_ERROR_NONE, "ret[0x%x]", ret); - - g_print("webrtc_signaling_server_stop() success\n"); -} - void quit_program(void) { int i; @@ -4344,7 +3693,7 @@ static void app_setting_and_signaling(char *cmd) g_ad.input_count++; break; case 1: - _request_join_room(cmd); + _websocket_request_join_room(cmd); g_ad.input_count = 0; reset_menu_state(); break; diff --git a/test/webrtc_test_priv.h b/test/webrtc_test_priv.h index bf51f607..e006a703 100644 --- a/test/webrtc_test_priv.h +++ b/test/webrtc_test_priv.h @@ -296,6 +296,21 @@ extern menu_info_s g_menu_infos[]; extern const char *g_server_status_str[]; extern const char *g_webrtc_state_str[]; +void _webrtc_create(int index); +void _webrtc_start(int index); +void _webrtc_stop(int index); +void _webrtc_destroy(int index); +void _webrtc_set_all_basic_cbs(int index); +void _webrtc_set_all_negotiation_state_change_cbs(int index); +void _webrtc_add_media_source(int index, int type, unsigned int *source_id); +void _webrtc_add_mic_source(int index, bool aec, unsigned int *source_id); +void _webrtc_media_source_set_video_loopback(int index, unsigned int source_id); +void _webrtc_create_data_channel(int index); +void _webrtc_destroy_data_channel(int index); +void _webrtc_set_display_type(int index, int type); +void _webrtc_set_remote_description(connection_s *conn); +void _webrtc_add_ice_candidate(connection_s *conn, const gchar *candidate); + appdata_s *get_appdata(void); void display_handle_status(int index); void display_setting_status(void); @@ -326,6 +341,22 @@ void _render_text_message(void **eo, int i, const char *text); void _app_start(int *argc, char **argv); void _app_stop(void); +int _setting_uri(gchar *dest_arr, char *uri); +int _connect_signaling_server(void); +int _webrtc_signaling_server_create(int port); +void _webrtc_signaling_server_destroy(void); +int _webrtc_signaling_server_start(void); +void _webrtc_signaling_server_stop(void); +int _webrtc_signaling_connect(const char *ip, int port); +void _webrtc_signaling_disconnect(void); +void _webrtc_signaling_request_session(int peer_id); +void _webrtc_signaling_send_message(const char *message); +void _request_session(int remote_peer_id); +void _send_local_description(bool is_offer); +void _send_ice_candidate(connection_s *conn, const char *candidate); +void _websocket_request_join_room(char *room_name); +void _websocket_send_text_for_room(connection_s *conn, int remote_peer_id, const char *message); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/test/webrtc_test_signaling.c b/test/webrtc_test_signaling.c new file mode 100644 index 00000000..7cae3a8b --- /dev/null +++ b/test/webrtc_test_signaling.c @@ -0,0 +1,674 @@ +/* + * Copyright (c) 2022 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "webrtc_test_priv.h" +#include + +static int __copy_string_arr(gchar *dest_arr, char *string) +{ + int len = 0; + gsize src_size = 0; + + if (!string) + return -1; + + len = strlen(string); + + src_size = g_strlcpy(dest_arr, string, MAX_STRING_LEN); + if ((int)src_size != len) { + g_print("failed to g_strlcpy()\n"); + return -1; + } + + return 0; +} + +int _setting_uri(gchar *dest_arr, char *uri) +{ + int ret = 0; + + if (!uri) + return -1; + + if (get_appdata()->signaling_server.private.client) { + g_printerr("already set by 'scc'\n"); + return -1; + } + + if (strlen(uri) > strlen("0.0.0.0")) { + ret = __copy_string_arr(dest_arr, uri); + if (ret != 0) { + g_print("failed to __copy_string_arr()\n"); + return -1; + } + } else { + g_print("invalid value, uri[%s]\n", uri); + return -1; + } + + return 0; +} + +static gint32 __send_greeting_to_register(SoupWebsocketConnection *conn) +{ + gchar *hello; + gint32 id; + + if (!conn) { + g_printerr("conn is NULL\n"); + return -1; + } + + if (soup_websocket_connection_get_state(conn) != SOUP_WEBSOCKET_STATE_OPEN) { + g_printerr("websocket is not opened\n"); + return -1; + } + + id = g_random_int_range(10, 10000); + hello = g_strdup_printf("HELLO %i", id); + + soup_websocket_connection_send_text(conn, hello); + + g_free(hello); + + return id; +} + +static void __close_websocket(signaling_server_s *ss) +{ + RET_IF(!ss, "ss is NULL"); + + g_print("close websocket, ws_conn[%p]\n", ss->public.ws_conn); + + if (soup_websocket_connection_get_state(ss->public.ws_conn) == SOUP_WEBSOCKET_STATE_OPEN) + soup_websocket_connection_close(ss->public.ws_conn, 1000, ""); + else + g_object_unref(ss->public.ws_conn); + + ss->public.ws_conn = NULL; + ss->server_status = SERVER_STATUS_DISCONNECTED; + ss->is_connected = false; +} + +static void __websocket_closed_cb(SoupWebsocketConnection *ws_conn, gpointer user_data) +{ + signaling_server_s *ss = (signaling_server_s *)user_data; + + RET_IF(!ss, "ss is NULL"); + RET_IF(!ws_conn, "ws_conn is NULL"); + RET_IF(ss->public.ws_conn != ws_conn, "not matched ws_conn[%p, %p]", ss->public.ws_conn, ws_conn); + + __close_websocket(ss); +} + +static void __auto_configure_add_peer(gchar *peer_id, bool is_offer) +{ + int i; + + RET_IF(!peer_id, "peer_id is NULL"); + + if (!strcmp(peer_id,"")) + return; + + g_print("add peer[%s] to make an %s\n", peer_id, is_offer ? "offer" : "answer"); + + for (i = 0; i < MAX_CONNECTION_LEN; i++) { + unsigned int source_id = 0; + + if (get_appdata()->conns[i].webrtc) + continue; + + get_appdata()->conns[i].remote_peer_id = atoi((const char *)peer_id); + get_appdata()->conns[i].is_for_room = true; + get_appdata()->conns[i].is_offer = is_offer; + if (i > 0) /* follow the source type of the first one */ + get_appdata()->conns[i].room_source_type = get_appdata()->conns[0].room_source_type; + + _webrtc_create(i); + _webrtc_set_all_basic_cbs(i); + _webrtc_set_all_negotiation_state_change_cbs(i); + _webrtc_create_data_channel(i); + + switch (get_appdata()->conns[i].room_source_type) { + case 1: + _webrtc_add_media_source(i, WEBRTC_MEDIA_SOURCE_TYPE_AUDIOTEST, NULL); + _webrtc_add_media_source(i, WEBRTC_MEDIA_SOURCE_TYPE_VIDEOTEST, &source_id); + if (i == 0) /* only set loopback video of the first one */ + _webrtc_media_source_set_video_loopback(i, source_id); + break; + case 2: + _webrtc_add_mic_source(i, false, NULL); + _webrtc_add_media_source(i, WEBRTC_MEDIA_SOURCE_TYPE_CAMERA, &source_id); + if (i == 0) /* only set loopback video of the first one */ + _webrtc_media_source_set_video_loopback(i, source_id); + break; + case 3: + _webrtc_add_mic_source(i, false, NULL); + break; + default: + return; + } + + _webrtc_start(i); + _webrtc_set_display_type(i, WEBRTC_DISPLAY_TYPE_EVAS); + + return; + } + g_printerr("failed to __auto_configure_add_peer_to_offer()\n"); +} + +static connection_s *__get_conn_from_peer_id(gchar *peer_id, int *index) +{ + int i; + + if (!peer_id) { + g_printerr("peer_id is NULL\n"); + return NULL; + } + + for (i = 0; i < MAX_CONNECTION_LEN; i++) { + if (get_appdata()->conns[i].remote_peer_id <= 0) + continue; + if (get_appdata()->conns[i].remote_peer_id == atoi((const char *)peer_id)) { + if (index) + *index = i; + return &get_appdata()->conns[i]; + } + } + + g_printerr("not found matching conn from peer_id[%s]", peer_id); + return NULL; +} + +static void __auto_configure_release_peer(gchar *peer_id) +{ + connection_s *conn; + int i; + + RET_IF(!peer_id, "peer_id is NULL"); + + g_print("release peer[%s] related resources\n", peer_id); + + if (!(conn = __get_conn_from_peer_id(peer_id, &i))) + return; + + _webrtc_stop(i); + _webrtc_destroy_data_channel(i); + _webrtc_destroy(i); +} + +static void __handle_json_structured_message(connection_s *conn, const gchar *text) +{ + JsonNode *root; + JsonObject *object; + JsonParser *parser; + + RET_IF(!conn, "conn is NULL"); + RET_IF(!text, "text is NULL"); + + parser = json_parser_new(); + + if (!json_parser_load_from_data(parser, text, -1, NULL)) { + g_printerr("unknown message [%s]\n", text); + g_object_unref(parser); + return; + } + + root = json_parser_get_root(parser); + if (!JSON_NODE_HOLDS_OBJECT(root)) { + g_printerr("unknown JSON message [%s]\n", text); + g_object_unref(parser); + return; + } + + object = json_node_get_object(root); + if (json_object_has_member(object, "sdp")){ + g_print("\n[from SERVER > SDP]\n%s\n", text); + if (conn->remote_desc) + free(conn->remote_desc); + conn->remote_desc = strdup(text); + + if (conn->is_for_room) { + webrtc_state_e state = WEBRTC_STATE_IDLE; + webrtc_get_state(conn->webrtc, &state); + if (state == WEBRTC_STATE_NEGOTIATING) + _webrtc_set_remote_description(conn); + } + + } else if (json_object_has_member(object, "ice")){ + g_print("\n[from SERVER > ICE]\n%s\n", text); + if (conn->is_for_room) { + webrtc_state_e state = WEBRTC_STATE_IDLE; + webrtc_get_state(conn->webrtc, &state); + if (state == WEBRTC_STATE_NEGOTIATING) + _webrtc_add_ice_candidate(conn, text); + else + conn->ice_candidates = g_list_append(conn->ice_candidates, strdup(text)); + } else { + conn->ice_candidates = g_list_append(conn->ice_candidates, strdup(text)); + } + + } else { + g_printerr("neither 'sdp' nor 'ice' member exist in JSON message [%s]\n", text); + } + + g_object_unref(parser); +} + +static void __auto_configure_handle_room_message(gchar *peer_id, gchar *message) +{ + connection_s *conn; + + RET_IF(!peer_id, "peer_id is NULL"); + RET_IF(!message, "message is NULL"); + + g_print("peer[%s], message[%s]\n", peer_id, message); + + if (!(conn = __get_conn_from_peer_id(peer_id, NULL))) + return; + + __handle_json_structured_message(conn, message); +} + +static void __handle_room_related_message(const gchar *text) +{ + g_auto(GStrv) tokens = NULL; + guint len; + guint i; + + RET_IF(!text, "text is NULL"); + + if (g_str_has_prefix(text, "ROOM_OK")) { + g_print("\n[from SERVER > %s]\n", text); + get_appdata()->signaling_server.server_status = SERVER_STATUS_ROOM_ESTABLISHED; + + /* parse text, get the previous peers in the room and negotiate to each other */ + if (strlen(text) > strlen("ROOM_OK")) { + /* e.g. ROOM_OK 1234 5311 324 */ + tokens = g_strsplit(text, " ", 0); + len = g_strv_length(tokens); + for (i = 1; i < len; i++) { + if (i > MAX_CONNECTION_LEN) { + g_print("connection[%d], out of range\n", i); + break; + } + __auto_configure_add_peer(tokens[i], true); + } + } + + } else if (g_str_has_prefix(text, "ROOM_PEER_JOINED")) { + g_print("\n[from SERVER > %s]\n", text); + /* e.g. ROOM_PEER_JOINED 1234 */ + tokens = g_strsplit(text, " ", 2); + __auto_configure_add_peer(tokens[1], false); + + } else if (g_str_has_prefix(text, "ROOM_PEER_LEFT")) { + g_print("\n[from SERVER > %s]\n", text); + /* e.g. ROOM_PEER_LEFT 1234 */ + tokens = g_strsplit(text, " ", 2); + __auto_configure_release_peer(tokens[1]); + + } else if (g_str_has_prefix(text, "ROOM_PEER_MSG")) { + g_print("\n[from SERVER > %s]\n", text); + /* e.g. ROOM_PEER_MSG 1234 msg */ + tokens = g_strsplit(text, " ", 3); + __auto_configure_handle_room_message(tokens[1], tokens[2]); + + } else { + g_print("\n[from SERVER > %s]\n", text); + get_appdata()->signaling_server.server_status = SERVER_STATUS_ERROR_FOUND; + } +} + +static void __websocket_message_cb(SoupWebsocketConnection *ws_conn, SoupWebsocketDataType type, GBytes *message, gpointer user_data) +{ + gchar *text; + gsize size; + const gchar *data; + connection_s *conn = (connection_s *)user_data; + + RET_IF(!conn, "conn is NULL"); + RET_IF(!ws_conn, "ws_conn is NULL"); + RET_IF(get_appdata()->signaling_server.public.ws_conn != ws_conn, "not matched ws_conn[%p, %p]", get_appdata()->signaling_server.public.ws_conn, ws_conn); + RET_IF(type != SOUP_WEBSOCKET_DATA_TEXT, "invalid data type(%d)", type); + + data = g_bytes_get_data(message, &size); + text = g_strndup(data, size); + + /* NOTE: Logics below can be different in each server */ + if (g_strcmp0(text, "HELLO") == 0) { + g_print("\n[from SERVER > %s] registered done, local_peer_id[%d]\n", text, get_appdata()->signaling_server.local_peer_id); + + } else if (g_strcmp0(text, "SESSION_OK") == 0) { + g_print("\n[from SERVER > %s]\n", text); + get_appdata()->signaling_server.server_status = SERVER_STATUS_SESSION_ESTABLISHED; + + } else if (g_str_has_prefix(text, "ROOM_")) { + __handle_room_related_message(text); + + } else if (g_str_has_prefix(text, "ERROR")) { + g_print("\n[from SERVER > %s]\n", text); + get_appdata()->signaling_server.server_status = SERVER_STATUS_ERROR_FOUND; + + } else { + __handle_json_structured_message(conn, text); + } + + g_free(text); +} + +static void __websocket_connected_cb(SoupSession *session, GAsyncResult *res, void *user_data) +{ + GError *error = NULL; + SoupWebsocketConnection *ws_conn; + connection_s *conn = (connection_s *)user_data; + + RET_IF(!conn, "conn is NULL"); + + ws_conn = soup_session_websocket_connect_finish(session, res, &error); + if (error) { + if (soup_websocket_connection_get_state(ws_conn) == SOUP_WEBSOCKET_STATE_OPEN) + soup_websocket_connection_close(ws_conn, 1000, ""); + else { + g_print("NOT OPENED\n"); + g_object_unref(ws_conn); + } + g_print("failed to soup_session_websocket_connect_finish(), error[%s]\n", error->message); + g_error_free(error); + return; + } + g_print("\n[%s] is connected, conn[%p]\n", get_appdata()->signaling_server.public.url, conn); + + get_appdata()->signaling_server.public.ws_conn = ws_conn; + get_appdata()->signaling_server.server_status = SERVER_STATUS_CONNECTED; + + g_signal_connect(ws_conn, "closed", G_CALLBACK(__websocket_closed_cb), &get_appdata()->signaling_server); + g_signal_connect(ws_conn, "message", G_CALLBACK(__websocket_message_cb), conn); + + get_appdata()->signaling_server.local_peer_id = __send_greeting_to_register(ws_conn); + get_appdata()->signaling_server.is_connected = true; +} + +int _connect_signaling_server(void) +{ + SoupMessage *message; + SoupSession *session; + SoupURI *proxy_uri; + const char *https_aliases[] = {"wss", NULL}; + + RET_VAL_IF(get_appdata()->signaling_server.private.client, -1, "already set by 'scc'"); + + if (strlen(get_appdata()->proxy) == 0) { + session = soup_session_new_with_options(SOUP_SESSION_SSL_STRICT, TRUE, + SOUP_SESSION_HTTPS_ALIASES, https_aliases, NULL); + } else { + g_print("use proxy [%s]\n", get_appdata()->proxy); + proxy_uri = soup_uri_new(get_appdata()->proxy); + session = soup_session_new_with_options(SOUP_SESSION_SSL_STRICT, TRUE, + SOUP_SESSION_SSL_USE_SYSTEM_CA_FILE, TRUE, + SOUP_SESSION_PROXY_URI, proxy_uri, + SOUP_SESSION_SSL_CA_FILE, "/opt/var/lib/ca-certificates/ca-bundle.pem", + SOUP_SESSION_HTTPS_ALIASES, https_aliases, NULL); + soup_uri_free(proxy_uri); + } + + message = soup_message_new(SOUP_METHOD_GET, get_appdata()->signaling_server.public.url); + + g_print("connecting to signaling server[%s]...\n", get_appdata()->signaling_server.public.url); + + soup_session_websocket_connect_async(session, message, NULL, NULL, NULL, + (GAsyncReadyCallback) __websocket_connected_cb, &get_appdata()->conns[0]); + + return 0; +} + +int _webrtc_signaling_server_create(int port) +{ + int ret; + + ret = webrtc_signaling_server_create(port, &(get_appdata()->signaling_server.private.server)); + RET_VAL_IF(ret != WEBRTC_ERROR_NONE, -1, "failed to webrtc_signaling_server_create(), ret[0x%x]", ret); + + g_print("webrtc_signaling_server_create() success, port[%d] signaling_server.private.server[%p]\n", + port, get_appdata()->signaling_server.private.server); + + get_appdata()->signaling_server.private.server_port = port; + + return 0; +} + +void _webrtc_signaling_server_destroy(void) +{ + int ret; + + ret = webrtc_signaling_server_destroy(get_appdata()->signaling_server.private.server); + RET_IF(ret != WEBRTC_ERROR_NONE, "failed to webrtc_signaling_server_destroy(), ret[0x%x]", ret); + + g_print("webrtc_signaling_server_destroy() success\n"); + get_appdata()->signaling_server.private.server = NULL; +} + +int _webrtc_signaling_server_start(void) +{ + int ret; + + ret = webrtc_signaling_server_start(get_appdata()->signaling_server.private.server); + RET_VAL_IF(ret != WEBRTC_ERROR_NONE, -1, "webrtc_signaling_server_start(), ret[0x%x]", ret); + + g_print("webrtc_signaling_server_start() success\n"); + + return 0; +} + +void _webrtc_signaling_server_stop(void) +{ + int ret; + + ret = webrtc_signaling_server_stop(get_appdata()->signaling_server.private.server); + RET_IF(ret != WEBRTC_ERROR_NONE, "ret[0x%x]", ret); + + g_print("webrtc_signaling_server_stop() success\n"); +} + +static void __signaling_message_cb(webrtc_signaling_message_type_e type, const char *message, void *user_data) +{ + connection_s *conn = (connection_s *)user_data; + + g_print("__signaling_message_cb(), type[%d] message[%s] conn[%p]\n", type, message, conn); + + if (type == SIGNALING_MESSAGE_TYPE_CONNECTED) { + g_print("\n[from SERVER > CONNECTED %s]\n", message); + get_appdata()->signaling_server.is_connected = true; + get_appdata()->signaling_server.server_status = SERVER_STATUS_CONNECTED; + get_appdata()->signaling_server.local_peer_id = atoi(message); + + } else if (type == SIGNALING_MESSAGE_TYPE_DISCONNECTED) { + g_print("\n[from SERVER > DISCONNECTED %s]\n", message); + get_appdata()->signaling_server.is_connected = false; + get_appdata()->signaling_server.server_status = SERVER_STATUS_DISCONNECTED; + + } else if (type == SIGNALING_MESSAGE_TYPE_SESSION_ESTABLISHED) { + g_print("\n[from SERVER > SESSION_ESTABLISHED with %s]\n", message); + get_appdata()->signaling_server.server_status = SERVER_STATUS_SESSION_ESTABLISHED; + + } else if (type == SIGNALING_MESSAGE_TYPE_SESSION_CLOSED) { + g_print("\n[from SERVER > SESSION_CLOSED with %s]\n", message); + get_appdata()->signaling_server.server_status = SERVER_STATUS_SESSION_CLOSED; + + } else if (type == SIGNALING_MESSAGE_TYPE_SDP) { + g_print("\n[from SERVER > SDP]\n%s\n", message); + if (conn->remote_desc) + free(conn->remote_desc); + conn->remote_desc = strdup(message); + + } else if (type == SIGNALING_MESSAGE_TYPE_ICE_CANDIDATE) { + g_print("\n[from SERVER > ICE]\n%s\n", message); + conn->ice_candidates = g_list_append(conn->ice_candidates, strdup(message)); + } +} + +int _webrtc_signaling_connect(const char *ip, int port) +{ + int ret; + + if (strlen(get_appdata()->signaling_server.public.url) > 0) { + g_printerr("server[%s] is already set by 'ss'\n", get_appdata()->signaling_server.public.url); + return -1; + } + + ret = webrtc_signaling_connect(ip, port, __signaling_message_cb, &get_appdata()->conns[0], &get_appdata()->signaling_server.private.client); + RET_VAL_IF(ret != WEBRTC_ERROR_NONE, -1, "failed to webrtc_signaling_connect(), ret[0x%x]", ret); + + if (get_appdata()->signaling_server.private.ip) + free(get_appdata()->signaling_server.private.ip); + get_appdata()->signaling_server.private.ip = strdup(ip); + get_appdata()->signaling_server.private.port = port; + + g_print("webrtc_signaling_connect() success\n"); + + return 0; +} + +void _webrtc_signaling_disconnect(void) +{ + int ret; + + RET_IF(!get_appdata()->signaling_server.is_connected, "signaling server is not connected"); + + ret = webrtc_signaling_disconnect(get_appdata()->signaling_server.private.client); + RET_IF(ret != WEBRTC_ERROR_NONE, "ret[0x%x]", ret); + + g_print("webrtc_signaling_disconnect() success\n"); + + get_appdata()->signaling_server.private.client = NULL; +} + +void _webrtc_signaling_request_session(int peer_id) +{ + int ret; + + RET_IF(!get_appdata()->signaling_server.is_connected, "signaling server is not connected"); + + ret = webrtc_signaling_request_session(get_appdata()->signaling_server.private.client, peer_id); + RET_IF(ret != WEBRTC_ERROR_NONE, "ret[0x%x]", ret); + + g_print("webrtc_signaling_request_session() success\n"); +} + +void _webrtc_signaling_send_message(const char *message) +{ + int ret; + + RET_IF(!message, "message is NULL"); + RET_IF(!get_appdata()->signaling_server.is_connected, "signaling server is not connected"); + + ret = webrtc_signaling_send_message(get_appdata()->signaling_server.private.client, message); + RET_IF(ret != WEBRTC_ERROR_NONE, "ret[0x%x]", ret); + + g_print("webrtc_signaling_send_message() success\n"); +} + +void _request_session(int remote_peer_id) +{ + RET_IF(!get_appdata()->signaling_server.is_connected, "signaling server is not connected"); + + if (get_appdata()->signaling_server.public.ws_conn) { + gchar *msg; + if (soup_websocket_connection_get_state(get_appdata()->signaling_server.public.ws_conn) != SOUP_WEBSOCKET_STATE_OPEN) { + g_printerr("websocket is not opened\n"); + return; + } + + msg = g_strdup_printf("SESSION %d", remote_peer_id); + + g_print("\n[to SERVER > %s]\n", msg); + soup_websocket_connection_send_text(get_appdata()->signaling_server.public.ws_conn, msg); + g_free(msg); + + } else if (get_appdata()->signaling_server.private.client) { + _webrtc_signaling_request_session(remote_peer_id); + + } else { + g_printerr("Neither public nor private signaling server is connected\n"); + } +} + +void _send_local_description(bool is_offer) +{ + char *desc; + + RET_IF(!get_appdata()->signaling_server.is_connected, "signaling server is not connected"); + + desc = is_offer ? get_appdata()->conns[0].offer : get_appdata()->conns[0].answer; + + g_print("\n[to SERVER > local description]\n%s\n", desc); + + if (get_appdata()->signaling_server.public.ws_conn) + soup_websocket_connection_send_text(get_appdata()->signaling_server.public.ws_conn, desc); + else if (get_appdata()->signaling_server.private.client) + _webrtc_signaling_send_message(desc); + else + g_printerr("Neither public nor private signaling server is connected\n"); +} + +void _send_ice_candidate(connection_s *conn, const char *candidate) +{ + RET_IF(!conn, "conn is NULL"); + RET_IF(!get_appdata()->signaling_server.is_connected, "signaling server is not connected"); + + if (get_appdata()->signaling_server.public.ws_conn) { + if (conn->is_for_room) + _websocket_send_text_for_room(conn, conn->remote_peer_id, candidate); + else + soup_websocket_connection_send_text(get_appdata()->signaling_server.public.ws_conn, candidate); + + } else if (get_appdata()->signaling_server.private.client) { + _webrtc_signaling_send_message(candidate); + } +} + +void _websocket_request_join_room(char *room_name) +{ + gchar *msg; + + RET_IF(!room_name, "room_name is NULL"); + RET_IF(!get_appdata()->signaling_server.is_connected, "signaling server is not connected"); + RET_IF(!get_appdata()->signaling_server.public.ws_conn, "ws_conn is NULL"); + + if (soup_websocket_connection_get_state(get_appdata()->signaling_server.public.ws_conn) != SOUP_WEBSOCKET_STATE_OPEN) { + g_printerr("websocket is not opened\n"); + return; + } + + msg = g_strdup_printf("ROOM %s", room_name); + + g_print("\n[to SERVER > %s]\n", msg); + soup_websocket_connection_send_text(get_appdata()->signaling_server.public.ws_conn, msg); + g_free(msg); +} + +void _websocket_send_text_for_room(connection_s *conn, int remote_peer_id, const char *message) +{ + gchar *message_for_room; + + RET_IF(!conn, "conn is NULL"); + RET_IF(!conn->is_for_room, "conn[%p] is not for room", conn); + RET_IF(!message, "message is NULL"); + + message_for_room = g_strdup_printf ("ROOM_PEER_MSG %d %s", remote_peer_id, message); + soup_websocket_connection_send_text(get_appdata()->signaling_server.public.ws_conn, message_for_room); + g_free(message_for_room); +} \ No newline at end of file