From: Sangchul Lee Date: Tue, 1 Dec 2020 08:09:05 +0000 (+0900) Subject: webrtc_test: Add support for making up to four connections X-Git-Tag: submit/tizen/20210729.023123~175 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=259ee0d44f6ffcd45df547dbcb34ff951b6d1552;p=platform%2Fcore%2Fapi%2Fwebrtc.git webrtc_test: Add support for making up to four connections Now it can make up to four connections to the signaling server. Each connection can have one webrtc handle. A test case for webrtc_set_display() is added. [Version] 0.1.67 [Issue Type] Test application Change-Id: I4d7d3d7991ef3a74018435c4e95ca16df6a0c1b7 Signed-off-by: Sangchul Lee --- diff --git a/packaging/capi-media-webrtc.spec b/packaging/capi-media-webrtc.spec index 699a6476..cc168e3d 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.1.66 +Version: 0.1.67 Release: 0 Group: Multimedia/API License: Apache-2.0 diff --git a/test/webrtc_test.c b/test/webrtc_test.c index b8b1105d..c1d7ad2f 100644 --- a/test/webrtc_test.c +++ b/test/webrtc_test.c @@ -36,6 +36,7 @@ #define MAX_STRING_LEN 512 #define MAX_CHANNEL_LEN 10 +#define MAX_CONNECTION_LEN 4 enum { CURRENT_STATUS_MAINMENU, @@ -43,6 +44,7 @@ enum { CURRENT_STATUS_REMOVE_MEDIA_SOURCE, CURRENT_STATUS_GET_TRANSCEIVER_DIRECTION, CURRENT_STATUS_SET_TRANSCEIVER_DIRECTION, + CURRENT_STATUS_SET_DISPLAY_TYPE, CURRENT_STATUS_DATA_CHANNEL_SEND_STRING, CURRENT_STATUS_DATA_CHANNEL_SEND_STRING_AS_BYTES, CURRENT_STATUS_DATA_CHANNEL_SEND_FILE, @@ -51,6 +53,7 @@ enum { CURRENT_STATUS_SET_REMOTE_DESCRIPTION, CURRENT_STATUS_SETTING_SIGNALING_SERVER, CURRENT_STATUS_SETTING_PROXY, + CURRENT_STATUS_CHANGE_CONNECTION, CURRENT_STATUS_REQUEST_SESSION, CURRENT_STATUS_SEND_LOCAL_DESCRIPTION, }; @@ -87,36 +90,47 @@ static const char* g_webrtc_transceiver_direction_str[] = { }; /* for video display */ -static Evas_Object *g_eo; static Evas_Object *g_win_id; static Evas_Object *g_selected_win_id; typedef struct { Evas_Object *win; Evas_Object *layout_main; -} appdata; - -static appdata ad; -static webrtc_h g_webrtc; -static webrtc_data_channel_h g_channels[MAX_CHANNEL_LEN]; -static int g_channel_index; -static webrtc_data_channel_h g_recv_channels[MAX_CHANNEL_LEN]; -static char *g_offer; -static char *g_answer; -static char *g_remote_desc; -static GList *g_ice_candidates; -static SoupWebsocketConnection *g_ws_conn; -static gint32 g_local_peer_id; +} appdata_s; + +typedef struct _connection_s { + SoupWebsocketConnection *ws_conn; + gint32 local_peer_id; + int server_status; + + webrtc_h webrtc; + webrtc_data_channel_h channels[MAX_CHANNEL_LEN]; + int channel_index; + webrtc_data_channel_h recv_channels[MAX_CHANNEL_LEN]; + char *offer; + char *answer; + char *remote_desc; + GList *ice_candidates; + + int menu_state; + int cnt; + + /* receive data & dump file */ + int sum_size; + gchar *expected_name; + int expected_size; + char* receive_buffer; + + webrtc_display_type_e display_type; + Evas_Object *eo; +} connection_s; + static gchar g_signaling_server[MAX_STRING_LEN]; static gchar g_proxy[MAX_STRING_LEN]; -static int g_server_status = SERVER_STATUS_DISCONNECTED; -static int g_menu_state = CURRENT_STATUS_MAINMENU; -static int g_cnt; -/* receive data & dump file */ -static gchar *g_expected_name; -static int g_expected_size; -static char* g_receive_buffer; +static appdata_s ad; +static connection_s g_conns[MAX_CONNECTION_LEN]; +static int g_conn_index; static void win_del(void *data, Evas_Object *obj, void *event) { @@ -137,7 +151,7 @@ static Evas_Object *create_win(const char *name) elm_win_borderless_set(eo, EINA_TRUE); evas_object_smart_callback_add(eo, "delete,request", win_del, NULL); elm_win_screen_size_get(eo, NULL, NULL, &w, &h); - g_print("window size :%d,%d", w, h); + g_print("window size: %d x %d\n", w, h); evas_object_resize(eo, w, h); elm_win_autodel_set(eo, EINA_TRUE); elm_win_alpha_set(eo, EINA_TRUE); @@ -147,14 +161,17 @@ static Evas_Object *create_win(const char *name) static Evas_Object *create_image_object(Evas_Object *eo_parent) { + Evas_Object *eo = NULL; + Evas *evas; + if (!eo_parent) return NULL; - Evas *evas = evas_object_evas_get(eo_parent); - Evas_Object *eo = NULL; - + evas = evas_object_evas_get(eo_parent); eo = evas_object_image_add(evas); + g_print("eo [%p]\n", eo); + return eo; } @@ -185,10 +202,14 @@ void create_render_rect_and_bg(Evas_Object *win) evas_object_show(win); } +#define EO_ONE_SIDE_LEN 512 +#define PADDING_HIGHT 480 + static int app_create(void *data) { - appdata *ad = data; + appdata_s *ad = data; Evas_Object *win = NULL; + int i; /* use gl backend */ elm_config_accel_preference_set("opengl"); @@ -201,12 +222,15 @@ static int app_create(void *data) g_win_id = win; g_selected_win_id = g_win_id; create_render_rect_and_bg(ad->win); - /* Create evas image object for EVAS surface */ - g_eo = create_image_object(ad->win); - evas_object_image_size_set(g_eo, 500, 500); - evas_object_image_fill_set(g_eo, 0, 0, 500, 500); - evas_object_resize(g_eo, 500, 500); + /* Create evas image object for EVAS surface */ + for (i = 0; i < MAX_CONNECTION_LEN; i++) { + g_conns[i].eo = create_image_object(ad->win); + evas_object_image_size_set(g_conns[i].eo, EO_ONE_SIDE_LEN, EO_ONE_SIDE_LEN); + evas_object_image_fill_set(g_conns[i].eo, 0, 0, EO_ONE_SIDE_LEN, EO_ONE_SIDE_LEN); + evas_object_resize(g_conns[i].eo, EO_ONE_SIDE_LEN, EO_ONE_SIDE_LEN); + evas_object_move(g_conns[i].eo, (i % 2) * EO_ONE_SIDE_LEN, ((i / 2) * EO_ONE_SIDE_LEN) + PADDING_HIGHT); + } elm_win_activate(win); evas_object_show(win); @@ -215,7 +239,15 @@ static int app_create(void *data) static int app_terminate(void *data) { - appdata *ad = data; + appdata_s *ad = data; + int i; + + for (i = 0; i < MAX_CONNECTION_LEN; i++) { + if (g_conns[i].eo) { + evas_object_del(g_conns[i].eo); + g_conns[i].eo = NULL; + } + } if (g_win_id) { evas_object_del(g_win_id); @@ -233,127 +265,127 @@ struct appcore_ops ops = { .terminate = app_terminate, }; -static void _webrtc_create() +static void _webrtc_create(int index) { int ret = WEBRTC_ERROR_NONE; - if (g_webrtc) { + if (g_conns[index].webrtc) { g_print("failed to _webrtc_create(), already created\n"); return; } - ret = webrtc_create(&g_webrtc); + ret = webrtc_create(&g_conns[index].webrtc); if (ret != WEBRTC_ERROR_NONE) g_print("webrtc_create() returned [0x%x]\n", ret); else - g_print("webrtc_create() success, g_webrtc[%p]\n", g_webrtc); + g_print("webrtc[%p, index:%d] is created\n", g_conns[index].webrtc, index); } -static void _webrtc_destroy() +static void _webrtc_destroy(int index) { int ret = WEBRTC_ERROR_NONE; int i; - if (!g_webrtc) { - g_print("failed to _webrtc_destroy(), g_webrtc is NULL\n"); + if (!g_conns[index].webrtc) { + g_print("failed to _webrtc_destroy(), webrtc is NULL\n"); return; } - ret = webrtc_destroy(g_webrtc); + ret = webrtc_destroy(g_conns[index].webrtc); if (ret != WEBRTC_ERROR_NONE) { g_print("webrtc_destroy() returned [0x%x]\n", ret); } else { - g_print("webrtc_destroy() success\n"); - g_webrtc = NULL; + g_print("webrtc[%p, index:%d] is destroyed\n", g_conns[index].webrtc, index); + g_conns[index].webrtc = NULL; for (i = 0; i < MAX_CHANNEL_LEN; i++) { - if (g_channels[i] != NULL) - g_channels[i] = NULL; - if (g_recv_channels[i] != NULL) - g_recv_channels[i] = NULL; + if (g_conns[index].channels[i] != NULL) + g_conns[index].channels[i] = NULL; + if (g_conns[index].recv_channels[i] != NULL) + g_conns[index].recv_channels[i] = NULL; } - g_channel_index = 0; + g_conns[index].channel_index = 0; } } -static void _webrtc_start() +static void _webrtc_start(int index) { int ret = WEBRTC_ERROR_NONE; - if (!g_webrtc) { - g_print("failed to _webrtc_start(), g_webrtc is NULL\n"); + if (!g_conns[index].webrtc) { + g_print("failed to _webrtc_start(), webrtc is NULL\n"); return; } - ret = webrtc_start(g_webrtc); + ret = webrtc_start(g_conns[index].webrtc); if (ret != WEBRTC_ERROR_NONE) g_print("webrtc_start() returned [0x%x]\n", ret); else g_print("webrtc_start() success\n"); } -static void _webrtc_stop() +static void _webrtc_stop(int index) { int ret = WEBRTC_ERROR_NONE; int i; - if (!g_webrtc) { - g_print("failed to _webrtc_stop(), g_webrtc is NULL\n"); + if (!g_conns[index].webrtc) { + g_print("failed to _webrtc_stop(), webrtc is NULL\n"); return; } - ret = webrtc_stop(g_webrtc); + ret = webrtc_stop(g_conns[index].webrtc); if (ret != WEBRTC_ERROR_NONE) { g_print("webrtc_stop() returned [0x%x]\n", ret); } else { g_print("webrtc_stop() success\n"); for (i = 0; i < MAX_CHANNEL_LEN; i++) { - if (g_recv_channels[i] != NULL) - g_recv_channels[i] = NULL; + if (g_conns[index].recv_channels[i] != NULL) + g_conns[index].recv_channels[i] = NULL; } } } -static void _webrtc_get_state() +static void _webrtc_get_state(int index) { int ret = WEBRTC_ERROR_NONE; webrtc_state_e state; - ret = webrtc_get_state(g_webrtc, &state); + ret = webrtc_get_state(g_conns[index].webrtc, &state); if (ret != WEBRTC_ERROR_NONE) g_print("webrtc_get_state() returned [0x%x]\n", ret); else g_print("state: [%s]\n", g_webrtc_state_str[state]); } -static void _webrtc_add_media_source(int type) +static void _webrtc_add_media_source(int index, int type) { int ret = WEBRTC_ERROR_NONE; unsigned int source_id = 0; - ret = webrtc_add_media_source(g_webrtc, (webrtc_media_source_type_e)type, &source_id); + ret = webrtc_add_media_source(g_conns[index].webrtc, (webrtc_media_source_type_e)type, &source_id); if (ret != WEBRTC_ERROR_NONE) g_print("failed to webrtc_add_media_source(), ret[0x%x]\n", ret); else g_print("webrtc_add_media_source() success, source_id[%u]\n", source_id); } -static void _webrtc_remove_media_source(unsigned int source_id) +static void _webrtc_remove_media_source(int index, unsigned int source_id) { int ret = WEBRTC_ERROR_NONE; - ret = webrtc_remove_media_source(g_webrtc, source_id); + ret = webrtc_remove_media_source(g_conns[index].webrtc, source_id); if (ret != WEBRTC_ERROR_NONE) g_print("failed to webrtc_remove_media_source(), source_id[%u], ret[0x%x]\n", source_id, ret); else g_print("webrtc_remove_media_source() success, source_id[%u]\n", source_id); } -static void _webrtc_get_transceiver_direction(unsigned int source_id, webrtc_media_type_e media_type) +static void _webrtc_get_transceiver_direction(int index, unsigned int source_id, webrtc_media_type_e media_type) { int ret = WEBRTC_ERROR_NONE; webrtc_transceiver_direction_e direction; - ret = webrtc_get_transceiver_direction(g_webrtc, source_id, media_type, &direction); + ret = webrtc_get_transceiver_direction(g_conns[index].webrtc, source_id, media_type, &direction); if (ret != WEBRTC_ERROR_NONE) g_print("failed to webrtc_get_transceiver_direction(), ret[0x%x]\n", ret); else @@ -361,11 +393,11 @@ static void _webrtc_get_transceiver_direction(unsigned int source_id, webrtc_med source_id, g_webrtc_media_type_str[media_type], g_webrtc_transceiver_direction_str[direction]); } -static void _webrtc_set_transceiver_direction(unsigned int source_id, webrtc_media_type_e media_type, webrtc_transceiver_direction_e direction) +static void _webrtc_set_transceiver_direction(int index, unsigned int source_id, webrtc_media_type_e media_type, webrtc_transceiver_direction_e direction) { int ret = WEBRTC_ERROR_NONE; - ret = webrtc_set_transceiver_direction(g_webrtc, source_id, media_type, direction); + ret = webrtc_set_transceiver_direction(g_conns[index].webrtc, source_id, media_type, direction); if (ret != WEBRTC_ERROR_NONE) g_print("failed to webrtc_set_transceiver_direction(), source_id[%u], ret[0x%x]\n", source_id, ret); else @@ -373,6 +405,13 @@ static void _webrtc_set_transceiver_direction(unsigned int source_id, webrtc_med source_id, g_webrtc_media_type_str[media_type], g_webrtc_transceiver_direction_str[direction]); } +static void _webrtc_set_display_type(int index, int type) +{ + g_conns[index].display_type = type; + + g_print("display type[%d] is set, it'll be applied when starting rendering video.\n", type); +} + static int __copy_string_arr(gchar *dest_arr, char *string) { int len = 0; @@ -392,16 +431,16 @@ static int __copy_string_arr(gchar *dest_arr, char *string) return 0; } -static void _webrtc_data_channel_send_string(const char *string) +static void _webrtc_data_channel_send_string(int index, const char *string) { int ret = WEBRTC_ERROR_NONE; int i; for (i = 0; i < MAX_CHANNEL_LEN; i++) { - if (g_channels[i] == NULL) + if (g_conns[index].channels[i] == NULL) continue; - g_print("data_channel[%p], index[%d]: ", g_channels[i], i); - ret = webrtc_data_channel_send_string(g_channels[i], string); + g_print("data_channel[%p], index[%d]: ", g_conns[index].channels[i], i); + ret = webrtc_data_channel_send_string(g_conns[index].channels[i], string); if (ret != WEBRTC_ERROR_NONE) g_print("failed to webrtc_data_channel_send_string(), string[%s]\n", string); else @@ -409,16 +448,16 @@ static void _webrtc_data_channel_send_string(const char *string) } } -static void _webrtc_data_channel_send_string_as_bytes(const char *string) +static void _webrtc_data_channel_send_string_as_bytes(int index, const char *string) { int ret = WEBRTC_ERROR_NONE; int i; for (i = 0; i < MAX_CHANNEL_LEN; i++) { - if (g_channels[i] == NULL) + if (g_conns[index].channels[i] == NULL) continue; - g_print("data_channel[%p], index[%d]: ", g_channels[i], i); - ret = webrtc_data_channel_send_bytes(g_channels[i], string, strlen(string)); + g_print("data_channel[%p], index[%d]: ", g_conns[index].channels[i], i); + ret = webrtc_data_channel_send_bytes(g_conns[index].channels[i], string, strlen(string)); if (ret != WEBRTC_ERROR_NONE) g_print("failed to webrtc_data_channel_send_bytes(), string[%s]\n", string); else @@ -426,7 +465,7 @@ static void _webrtc_data_channel_send_string_as_bytes(const char *string) } } -static void _webrtc_data_channel_send_file(const char *file_path) +static void _webrtc_data_channel_send_file(int index, const char *file_path) { #define BUFFER_SIZE 16 * 1024 /* 16 kbytes */ int ret = WEBRTC_ERROR_NONE; @@ -440,9 +479,9 @@ static void _webrtc_data_channel_send_file(const char *file_path) int fd; for (i = 0; i < MAX_CHANNEL_LEN; i++) { - if (g_channels[i] == NULL) + if (g_conns[index].channels[i] == NULL) continue; - g_print("data_channel[%p], index[%d]: ", g_channels[i], i); + g_print("data_channel[%p], index[%d]: ", g_conns[index].channels[i], i); fd = open(file_path, O_RDONLY); if (fd == -1) { @@ -460,13 +499,13 @@ static void _webrtc_data_channel_send_file(const char *file_path) expected_size = g_strdup_printf("expected size:%llu", st.st_size); expected_name = g_strdup_printf("expected name:%s", basename((char *)file_path)); - ret = webrtc_data_channel_send_string(g_channels[i], expected_size); + ret = webrtc_data_channel_send_string(g_conns[index].channels[i], expected_size); if (ret != WEBRTC_ERROR_NONE) g_print("failed to webrtc_data_channel_send_string(), string[%s]\n", expected_size); else g_print("webrtc_data_channel_send_string() success, string[%s]\n", expected_size); - ret = webrtc_data_channel_send_string(g_channels[i], expected_name); + ret = webrtc_data_channel_send_string(g_conns[index].channels[i], expected_name); if (ret != WEBRTC_ERROR_NONE) g_print("failed to webrtc_data_channel_send_string(), string[%s]\n", expected_name); else @@ -480,7 +519,7 @@ static void _webrtc_data_channel_send_file(const char *file_path) sum_size += read_size; g_print("[%zd / %llu]bytes is read", sum_size, st.st_size); - ret = webrtc_data_channel_send_bytes(g_channels[i], buffer, (unsigned int)read_size); + ret = webrtc_data_channel_send_bytes(g_conns[index].channels[i], buffer, (unsigned int)read_size); if (ret != WEBRTC_ERROR_NONE) g_print("failed to webrtc_data_channel_send_bytes(), file_path[%s], size[%zd]\n", file_path, read_size); else @@ -491,26 +530,26 @@ static void _webrtc_data_channel_send_file(const char *file_path) } } -static void _webrtc_set_stun_server(char *uri) +static void _webrtc_set_stun_server(int index, char *uri) { int ret = 0; if (!uri) return; - webrtc_set_stun_server(g_webrtc, uri); + webrtc_set_stun_server(g_conns[index].webrtc, uri); if (ret != WEBRTC_ERROR_NONE) g_print("failed to webrtc_set_stun_server(), uri[%s], ret[0x%x]\n", uri, ret); else g_print("webrtc_set_stun_server() success, uri[%s]\n", uri); } -static void _webrtc_get_stun_server(void) +static void _webrtc_get_stun_server(int index) { int ret = WEBRTC_ERROR_NONE; char *stun_server; - ret = webrtc_get_stun_server(g_webrtc, &stun_server); + ret = webrtc_get_stun_server(g_conns[index].webrtc, &stun_server); if (ret != WEBRTC_ERROR_NONE) { g_print("failed to webrtc_get_stun_server(), ret[0x%x]\n", ret); } else { @@ -521,7 +560,9 @@ static void _webrtc_get_stun_server(void) static void __data_channel_open_cb(webrtc_data_channel_h channel, void *user_data) { - g_print("__data_channel_open_cb() is called, channel[%p]\n", channel); + connection_s *conn = (connection_s*)user_data; + + g_print("__data_channel_open_cb() is called, channel[%p], conn[%p]\n", channel, conn); } static void __file_dump(const gchar *file_name, void *src_buffer, int size) @@ -558,7 +599,14 @@ end: static void __data_channel_message_cb(webrtc_data_channel_h channel, webrtc_data_channel_type_e type, void *message, void *user_data) { - g_print("__data_channel_message_cb() is called, channel[%p], type[%d], ", channel, type); + connection_s *conn = (connection_s*)user_data; + + g_print("__data_channel_message_cb() is called, channel[%p], type[%d], conn[%p]", channel, type, conn); + + if (conn == NULL) { + g_printerr("conn is NULL\n"); + return; + } if (type == WEBRTC_DATA_CHANNEL_TYPE_STRING) { gchar **str_arr = NULL; @@ -567,16 +615,16 @@ static void __data_channel_message_cb(webrtc_data_channel_h channel, webrtc_data if (g_str_has_prefix((const gchar *)message, "expected name:")) { str_arr = g_strsplit((const gchar *)message, ":", 2); - g_free(g_expected_name); - g_expected_name = g_strdup(str_arr[1]); + g_free(conn->expected_name); + conn->expected_name = g_strdup(str_arr[1]); } else if (g_str_has_prefix((const gchar *)message, "expected size:")) { str_arr = g_strsplit((const gchar *)message, ":", 2); - g_expected_size = atoi(str_arr[1]); + conn->expected_size = atoi(str_arr[1]); - if (g_receive_buffer) - free(g_receive_buffer); - g_receive_buffer = (char *)calloc(g_expected_size, sizeof(char)); + if (conn->receive_buffer) + free(conn->receive_buffer); + conn->receive_buffer = (char *)calloc(conn->expected_size, sizeof(char)); } if (str_arr) @@ -591,24 +639,22 @@ static void __data_channel_message_cb(webrtc_data_channel_h channel, webrtc_data webrtc_get_data(data, &data_p, &size); g_print("bytes message[%p, size:%u]\n", data_p, size); - if (g_expected_size > 0 && g_expected_name) { - static int sum_size = 0; - - g_print("downloading [%s], size[%d / %d]\n", g_expected_name, sum_size, g_expected_size); + if (conn->expected_size > 0 && conn->expected_name) { + g_print("downloading [%s], size[%d / %d]\n", conn->expected_name, conn->sum_size, conn->expected_size); - memcpy(&g_receive_buffer[sum_size], ((uint8_t*)data_p), size); + memcpy(&conn->receive_buffer[conn->sum_size], ((uint8_t*)data_p), size); - sum_size += size; - if (sum_size >= g_expected_size) { - __file_dump(g_expected_name, g_receive_buffer, sum_size); + conn->sum_size += size; + if (conn->sum_size >= conn->expected_size) { + __file_dump(conn->expected_name, conn->receive_buffer, conn->sum_size); - sum_size = 0; - g_expected_size = 0; - g_free(g_expected_name); - g_expected_name = NULL; - if (g_receive_buffer) { - free(g_receive_buffer); - g_receive_buffer = NULL; + conn->sum_size = 0; + conn->expected_size = 0; + g_free(conn->expected_name); + conn->expected_name = NULL; + if (conn->receive_buffer) { + free(conn->receive_buffer); + conn->receive_buffer = NULL; } } @@ -622,49 +668,59 @@ static void __data_channel_message_cb(webrtc_data_channel_h channel, webrtc_data static void __data_channel_error_cb(webrtc_data_channel_h channel, webrtc_error_e error, void *user_data) { - g_print("__data_channel_error_cb() is called, channel[%p]\n", channel); + connection_s *conn = (connection_s*)user_data; + + g_print("__data_channel_error_cb() is called, channel[%p], conn[%p]\n", channel, conn); } static void __data_channel_close_cb(webrtc_data_channel_h channel, void *user_data) { - g_print("__data_channel_close_cb() is called, channel[%p]\n", channel); + connection_s *conn = (connection_s*)user_data; + + g_print("__data_channel_close_cb() is called, channel[%p], conn[%p]\n", channel, conn); } static void __data_channel_cb(webrtc_h webrtc, webrtc_data_channel_h channel, void *user_data) { int i; + connection_s *conn = (connection_s*)user_data; + + if (conn == NULL) { + g_printerr("conn is NULL\n"); + return; + } for (i = 0; i < MAX_CHANNEL_LEN; i++) { - if (g_recv_channels[i] == NULL) { - g_print("__data_channel_cb() is called, append all the callbacks.\n"); - - g_recv_channels[i] = channel; - webrtc_data_channel_set_open_cb(channel, __data_channel_open_cb, webrtc); - webrtc_data_channel_set_message_cb(channel, __data_channel_message_cb, webrtc); - webrtc_data_channel_set_error_cb(channel, __data_channel_error_cb, webrtc); - webrtc_data_channel_set_close_cb(channel, __data_channel_close_cb, webrtc); + if (conn->recv_channels[i] == NULL) { + g_print("__data_channel_cb() is called for conn[%p], append all the callbacks.\n", conn); + + conn->recv_channels[i] = channel; + webrtc_data_channel_set_open_cb(channel, __data_channel_open_cb, (void *)conn); + webrtc_data_channel_set_message_cb(channel, __data_channel_message_cb, (void *)conn); + webrtc_data_channel_set_error_cb(channel, __data_channel_error_cb, (void *)conn); + webrtc_data_channel_set_close_cb(channel, __data_channel_close_cb, (void *)conn); return; } } g_print("__data_channel_cb() is called, but g_recv_channels is full\n"); } -static void _webrtc_set_data_channel_cb() +static void _webrtc_set_data_channel_cb(int index) { int ret = WEBRTC_ERROR_NONE; - ret = webrtc_set_data_channel_cb(g_webrtc, __data_channel_cb, g_webrtc); + ret = webrtc_set_data_channel_cb(g_conns[index].webrtc, __data_channel_cb, &g_conns[index]); if (ret != WEBRTC_ERROR_NONE) g_print("failed to webrtc_set_data_channel_cb()\n"); else g_print("webrtc_set_data_channel_cb() success\n"); } -static void _webrtc_unset_data_channel_cb() +static void _webrtc_unset_data_channel_cb(int index) { int ret = WEBRTC_ERROR_NONE; - ret = webrtc_unset_data_channel_cb(g_webrtc); + ret = webrtc_unset_data_channel_cb(g_conns[index].webrtc); if (ret != WEBRTC_ERROR_NONE) g_print("failed to webrtc_unset_data_channel_cb()\n"); else @@ -677,22 +733,22 @@ static void __error_cb(webrtc_h webrtc, webrtc_error_e error, webrtc_state_e sta webrtc, error, state, user_data); } -static void _webrtc_set_error_cb() +static void _webrtc_set_error_cb(int index) { int ret = WEBRTC_ERROR_NONE; - ret = webrtc_set_error_cb(g_webrtc, __error_cb, g_webrtc); + ret = webrtc_set_error_cb(g_conns[index].webrtc, __error_cb, g_conns[index].webrtc); if (ret != WEBRTC_ERROR_NONE) g_print("failed to webrtc_set_error_cb()\n"); else g_print("webrtc_set_error_cb() success\n"); } -static void _webrtc_unset_error_cb() +static void _webrtc_unset_error_cb(int index) { int ret = WEBRTC_ERROR_NONE; - ret = webrtc_unset_error_cb(g_webrtc); + ret = webrtc_unset_error_cb(g_conns[index].webrtc); if (ret != WEBRTC_ERROR_NONE) g_print("failed to webrtc_unset_error_cb()\n"); else @@ -705,22 +761,22 @@ static void __state_changed_cb(webrtc_h webrtc, webrtc_state_e previous, webrtc_ webrtc, g_webrtc_state_str[previous], g_webrtc_state_str[current], user_data); } -static void _webrtc_set_state_changed_cb() +static void _webrtc_set_state_changed_cb(int index) { int ret = WEBRTC_ERROR_NONE; - ret = webrtc_set_state_changed_cb(g_webrtc, __state_changed_cb, g_webrtc); + ret = webrtc_set_state_changed_cb(g_conns[index].webrtc, __state_changed_cb, g_conns[index].webrtc); if (ret != WEBRTC_ERROR_NONE) g_print("failed to webrtc_set_state_changed_cb()\n"); else g_print("webrtc_set_state_changed_cb() success\n"); } -static void _webrtc_unset_state_changed_cb() +static void _webrtc_unset_state_changed_cb(int index) { int ret = WEBRTC_ERROR_NONE; - ret = webrtc_unset_state_changed_cb(g_webrtc); + ret = webrtc_unset_state_changed_cb(g_conns[index].webrtc); if (ret != WEBRTC_ERROR_NONE) g_print("failed to webrtc_unset_state_changed_cb()\n"); else @@ -732,22 +788,22 @@ 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 _webrtc_set_negotiation_needed_cb() +static void _webrtc_set_negotiation_needed_cb(int index) { int ret = WEBRTC_ERROR_NONE; - ret = webrtc_set_negotiation_needed_cb(g_webrtc, __negotiation_needed_cb, g_webrtc); + ret = webrtc_set_negotiation_needed_cb(g_conns[index].webrtc, __negotiation_needed_cb, g_conns[index].webrtc); if (ret != WEBRTC_ERROR_NONE) g_print("failed to webrtc_set_negotiation_needed_cb()\n"); else g_print("webrtc_set_negotiation_needed_cb() success\n"); } -static void _webrtc_unset_negotiation_needed_cb() +static void _webrtc_unset_negotiation_needed_cb(int index) { int ret = WEBRTC_ERROR_NONE; - ret = webrtc_unset_negotiation_needed_cb(g_webrtc); + ret = webrtc_unset_negotiation_needed_cb(g_conns[index].webrtc); if (ret != WEBRTC_ERROR_NONE) g_print("failed to webrtc_unset_negotiation_needed_cb()\n"); else @@ -759,25 +815,25 @@ static void __ice_candidate_cb(webrtc_h webrtc, const char *candidate, void *use g_print("__ice_candidate_cb() is invoked\n"); g_print("\n[to SERVER > ICE]\n%s\n", candidate); - soup_websocket_connection_send_text(g_ws_conn, candidate); + soup_websocket_connection_send_text(g_conns[g_conn_index].ws_conn, candidate); } -static void _webrtc_set_ice_candidate_cb() +static void _webrtc_set_ice_candidate_cb(int index) { int ret = WEBRTC_ERROR_NONE; - ret = webrtc_set_ice_candidate_cb(g_webrtc, __ice_candidate_cb, g_webrtc); + ret = webrtc_set_ice_candidate_cb(g_conns[index].webrtc, __ice_candidate_cb, g_conns[index].webrtc); if (ret != WEBRTC_ERROR_NONE) g_print("failed to webrtc_set_ice_candidate_cb()\n"); else g_print("webrtc_set_ice_candidate_cb() success\n"); } -static void _webrtc_unset_ice_candidate_cb() +static void _webrtc_unset_ice_candidate_cb(int index) { int ret = WEBRTC_ERROR_NONE; - ret = webrtc_unset_ice_candidate_cb(g_webrtc); + ret = webrtc_unset_ice_candidate_cb(g_conns[index].webrtc); if (ret != WEBRTC_ERROR_NONE) g_print("failed to webrtc_unset_ice_candidate_cb()\n"); else @@ -786,79 +842,103 @@ static void _webrtc_unset_ice_candidate_cb() static void __track_added_cb(webrtc_h webrtc, webrtc_media_type_e type, unsigned int id, void *user_data) { - g_print("__track_added_cb() is invoked, webrtc[%p], type[%d], id[%u], user_data[%p]\n", webrtc, type, id, user_data); + connection_s *conn = (connection_s *)user_data; + + if (conn == NULL) { + g_printerr("conn is NULL\n"); + return; + } + + g_print("__track_added_cb() is invoked, webrtc[%p], type[%d], id[%u], conn[%p]\n", webrtc, type, id, conn); + + if (type == WEBRTC_MEDIA_TYPE_VIDEO) { + g_print("Video track is added, "); + if (conn->display_type == WEBRTC_DISPLAY_TYPE_OVERLAY) { + g_print("set display - overlay\n"); + /* FIXME: set window id here */ + + } else if (conn->display_type == WEBRTC_DISPLAY_TYPE_EVAS) { + g_print("set display - evas object[%p]\n", conn->eo); + webrtc_set_display(conn->webrtc, id, WEBRTC_DISPLAY_TYPE_EVAS, conn->eo); + + } else { + g_print("invalid display type[%d]\n", conn->display_type); + } + } else if (type == WEBRTC_MEDIA_TYPE_AUDIO) { + g_print("Audio track is added\n"); + } } -static void _webrtc_set_track_added_cb() +static void _webrtc_set_track_added_cb(int index) { int ret = WEBRTC_ERROR_NONE; - ret = webrtc_set_track_added_cb(g_webrtc, __track_added_cb, g_webrtc); + ret = webrtc_set_track_added_cb(g_conns[index].webrtc, __track_added_cb, &g_conns[index]); if (ret != WEBRTC_ERROR_NONE) g_print("failed to webrtc_set_track_added_cb()\n"); else g_print("webrtc_set_track_added_cb() success\n"); } -static void _webrtc_unset_track_added_cb() +static void _webrtc_unset_track_added_cb(int index) { int ret = WEBRTC_ERROR_NONE; - ret = webrtc_unset_track_added_cb(g_webrtc); + ret = webrtc_unset_track_added_cb(g_conns[index].webrtc); if (ret != WEBRTC_ERROR_NONE) g_print("failed to webrtc_unset_track_added_cb()\n"); else g_print("webrtc_unset_track_added_cb() success\n"); } -static void _webrtc_create_offer() +static void _webrtc_create_offer(int index) { int ret = WEBRTC_ERROR_NONE; - if (g_offer) { - free(g_offer); - g_offer = NULL; + if (g_conns[index].offer) { + free(g_conns[index].offer); + g_conns[index].offer = NULL; } - ret = webrtc_create_offer(g_webrtc, &g_offer); + ret = webrtc_create_offer(g_conns[index].webrtc, &g_conns[index].offer); if (ret != WEBRTC_ERROR_NONE) g_print("failed to webrtc_create_offer()\n"); else - g_print("webrtc_create_offer() success\noffer:\n%s\n", g_offer); + g_print("webrtc_create_offer() success\noffer:\n%s\n", g_conns[index].offer); } -static void _webrtc_create_answer() +static void _webrtc_create_answer(int index) { int ret = WEBRTC_ERROR_NONE; - if (g_answer) { - free(g_answer); - g_answer = NULL; + if (g_conns[index].answer) { + free(g_conns[index].answer); + g_conns[index].answer = NULL; } - ret = webrtc_create_answer(g_webrtc, &g_answer); + ret = webrtc_create_answer(g_conns[index].webrtc, &g_conns[index].answer); if (ret != WEBRTC_ERROR_NONE) g_print("failed to webrtc_create_answer()\n"); else - g_print("webrtc_create_answer() success\nanswer:\n%s\n", g_answer); + g_print("webrtc_create_answer() success\nanswer:\n%s\n", g_conns[index].answer); } -static void _webrtc_set_local_description(char *desc) +static void _webrtc_set_local_description(int index, bool is_offer) { int ret = WEBRTC_ERROR_NONE; - ret = webrtc_set_local_description(g_webrtc, desc); + ret = webrtc_set_local_description(g_conns[index].webrtc, is_offer ? g_conns[index].offer : g_conns[index].answer); if (ret != WEBRTC_ERROR_NONE) g_print("failed to webrtc_set_local_description()\n"); else g_print("webrtc_set_local_description() success\n"); } -static void _webrtc_set_remote_description(void) +static void _webrtc_set_remote_description(int index) { int ret = WEBRTC_ERROR_NONE; - ret = webrtc_set_remote_description(g_webrtc, g_remote_desc); + ret = webrtc_set_remote_description(g_conns[index].webrtc, g_conns[index].remote_desc); if (ret != WEBRTC_ERROR_NONE) g_print("failed to webrtc_set_remote_description()\n"); else @@ -869,65 +949,66 @@ static void __foreach_ice_candidate(gpointer data, gpointer user_data) { int ret = WEBRTC_ERROR_NONE; - ret = webrtc_add_ice_candidate(g_webrtc, (const char *)data); + ret = webrtc_add_ice_candidate(g_conns[g_conn_index].webrtc, (const char *)data); if (ret != WEBRTC_ERROR_NONE) g_print("failed to webrtc_ice_candidate()\n"); else g_print("webrtc_ice_candidate() success\n"); } -static void _webrtc_add_ice_candidate(void) +static void _webrtc_add_ice_candidate(int index) { - g_list_foreach(g_ice_candidates, __foreach_ice_candidate, NULL); + g_list_foreach(g_conns[index].ice_candidates, __foreach_ice_candidate, NULL); - g_list_free_full(g_ice_candidates, free); + g_list_free_full(g_conns[index].ice_candidates, free); - g_ice_candidates = NULL; + g_conns[index].ice_candidates = NULL; } -static void _webrtc_create_data_channel(void) +static void _webrtc_create_data_channel(int index) { int ret = WEBRTC_ERROR_NONE; gchar *label; - if (g_channel_index == MAX_CHANNEL_LEN) { + if (g_conns[index].channel_index == MAX_CHANNEL_LEN) { g_print("%d channels are already created, skip it\n", MAX_CHANNEL_LEN); return; } - label = g_strdup_printf("data_channel_%d", g_channel_index); + label = g_strdup_printf("data_channel_%d_%d", index, g_conns[index].channel_index); - ret = webrtc_create_data_channel(g_webrtc, label, &g_channels[g_channel_index]); + ret = webrtc_create_data_channel(g_conns[index].webrtc, label, &g_conns[index].channels[g_conns[index].channel_index]); if (ret != WEBRTC_ERROR_NONE) { g_print("failed to webrtc_create_data_channel()\n"); } else { - g_print("webrtc_create_data_channel() success, channel[%p], index[%d]\n", g_channels[g_channel_index], g_channel_index); - webrtc_data_channel_set_open_cb(g_channels[g_channel_index], __data_channel_open_cb, g_webrtc); - webrtc_data_channel_set_error_cb(g_channels[g_channel_index], __data_channel_error_cb, g_webrtc); - webrtc_data_channel_set_close_cb(g_channels[g_channel_index], __data_channel_close_cb, g_webrtc); - g_channel_index++; + g_print("webrtc_create_data_channel() success, channel[%p], index[%d]\n", + g_conns[index].channels[g_conns[index].channel_index], g_conns[index].channel_index); + webrtc_data_channel_set_open_cb(g_conns[index].channels[g_conns[index].channel_index], __data_channel_open_cb, &g_conns[index]); + webrtc_data_channel_set_error_cb(g_conns[index].channels[g_conns[index].channel_index], __data_channel_error_cb, &g_conns[index]); + webrtc_data_channel_set_close_cb(g_conns[index].channels[g_conns[index].channel_index], __data_channel_close_cb, &g_conns[index]); + g_conns[index].channel_index++; } g_free(label); } -static void _webrtc_destroy_data_channel(void) +static void _webrtc_destroy_data_channel(int index) { int ret = WEBRTC_ERROR_NONE; int i; for (i = 0; i < MAX_CHANNEL_LEN; i++) { - if (g_channels[i] == NULL) + if (g_conns[index].channels[i] == NULL) continue; - ret = webrtc_destroy_data_channel(g_channels[i]); + ret = webrtc_destroy_data_channel(g_conns[index].channels[i]); if (ret != WEBRTC_ERROR_NONE) { g_print("failed to _webrtc_destroy_data_channel(), index[%d]\n", i); } else { g_print("_webrtc_destroy_data_channel() success, index[%d]\n", i); - g_channels[i] = NULL; + g_conns[index].channels[i] = NULL; } } - g_channel_index = 0; + g_conns[index].channel_index = 0; } static void _setting_uri(gchar *dest_arr, char *uri) @@ -946,16 +1027,16 @@ static void _setting_uri(gchar *dest_arr, char *uri) } } -static void _request_session(int remote_peer_id) +static void _request_session(int index, int remote_peer_id) { gchar *msg; - if (!g_ws_conn) { + if (!g_conns[index].ws_conn) { g_printerr("server[%s] is not connected\n", g_signaling_server); return; } - if (soup_websocket_connection_get_state(g_ws_conn) != SOUP_WEBSOCKET_STATE_OPEN) { + if (soup_websocket_connection_get_state(g_conns[index].ws_conn) != SOUP_WEBSOCKET_STATE_OPEN) { g_printerr("websocket is not opened\n"); return; } @@ -963,50 +1044,71 @@ static void _request_session(int remote_peer_id) msg = g_strdup_printf("SESSION %d", remote_peer_id); g_print("\n[to SERVER > %s]\n", msg); - soup_websocket_connection_send_text(g_ws_conn, msg); + soup_websocket_connection_send_text(g_conns[index].ws_conn, msg); g_free(msg); } -static void _send_local_description(char *desc) +static void _send_local_description(int index, bool is_offer) { - if (!g_ws_conn) { + char *desc; + + if (!g_conns[index].ws_conn) { g_printerr("server[%s] is not connected\n", g_signaling_server); return; } + desc = is_offer ? g_conns[index].offer : g_conns[index].answer; + g_print("\n[to SERVER > local description]\n%s\n", desc); - soup_websocket_connection_send_text(g_ws_conn, desc); + soup_websocket_connection_send_text(g_conns[index].ws_conn, desc); } -static void __close_websocket(SoupWebsocketConnection *conn) +static void __close_websocket(connection_s *conn) { if (!conn) { g_printerr("conn is NULL\n"); return; } - if (soup_websocket_connection_get_state(conn) == SOUP_WEBSOCKET_STATE_OPEN) - soup_websocket_connection_close(conn, 1000, ""); + if (soup_websocket_connection_get_state(conn->ws_conn) == SOUP_WEBSOCKET_STATE_OPEN) + soup_websocket_connection_close(conn->ws_conn, 1000, ""); else - g_object_unref(conn); + g_object_unref(conn->ws_conn); + + g_print("conn[%p] is closed\n",conn->ws_conn); - g_ws_conn = NULL; - g_server_status = SERVER_STATUS_DISCONNECTED; + conn->ws_conn = NULL; + conn->server_status = SERVER_STATUS_DISCONNECTED; } -static void __websocket_closed_cb(SoupWebsocketConnection *conn, gpointer user_data) +static void __websocket_closed_cb(SoupWebsocketConnection *ws_conn, gpointer user_data) { - g_print("[%s] is closed\n", g_signaling_server); + connection_s *conn = (connection_s *)user_data; + + if (!conn || !ws_conn) { + g_printerr("conn[%p] or ws_conn[%p] is NULL\n", conn, ws_conn); + return; + } + if (conn->ws_conn != ws_conn) { + g_printerr("not matched ws_conn[%p, %p]\n", conn->ws_conn, ws_conn); + return; + } + __close_websocket(conn); } -static void __handle_json_structured_message(const gchar *text) +static void __handle_json_structured_message(connection_s *conn, const gchar *text) { JsonNode *root; JsonObject *object; JsonParser *parser; + if (!conn) { + g_printerr("conn is NULL\n"); + return; + } + if (!text) { g_printerr("text is NULL\n"); return; @@ -1030,13 +1132,13 @@ static void __handle_json_structured_message(const gchar *text) object = json_node_get_object(root); if (json_object_has_member(object, "sdp")){ g_print("\n[from SERVER > SDP]\n%s\n", text); - if (g_remote_desc) - free(g_remote_desc); - g_remote_desc = strdup(text); + if (conn->remote_desc) + free(conn->remote_desc); + conn->remote_desc = strdup(text); } else if (json_object_has_member(object, "ice")){ g_print("\n[from SERVER > ICE]\n%s\n", text); - g_ice_candidates = g_list_append(g_ice_candidates, strdup(text)); + 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); @@ -1045,11 +1147,21 @@ static void __handle_json_structured_message(const gchar *text) g_object_unref(parser); } -static void __websocket_message_cb(SoupWebsocketConnection *conn, SoupWebsocketDataType type, GBytes *message, gpointer user_data) +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; + + if (!conn || !ws_conn) { + g_printerr("conn[%p] or ws_conn[%p] is NULL\n", conn, ws_conn); + return; + } + if (conn->ws_conn != ws_conn) { + g_printerr("not matched ws_conn[%p, %p]\n", conn->ws_conn, ws_conn); + return; + } if (type != SOUP_WEBSOCKET_DATA_TEXT) { g_printerr("invalid data type(%d)\n", type); @@ -1060,18 +1172,18 @@ static void __websocket_message_cb(SoupWebsocketConnection *conn, SoupWebsocketD /* NOTE: Logics below can be different in each server */ if (g_strcmp0(text, "HELLO") == 0) { - g_print("\n[from SERVER > %s] registered done, g_local_peer_id[%d]\n", text, g_local_peer_id); + g_print("\n[from SERVER > %s] registered done, g_local_peer_id[%d]\n", text, conn->local_peer_id); } else if (g_strcmp0(text, "SESSION_OK") == 0) { g_print("\n[from SERVER > %s]\n", text); - g_server_status = SERVER_STATUS_SESSION_ESTABLISHED; + conn->server_status = SERVER_STATUS_SESSION_ESTABLISHED; } else if (g_str_has_prefix(text, "ERROR")) { g_print("\n[from SERVER > %s]\n", text); - g_server_status = SERVER_STATUS_ERROR_FOUND; + conn->server_status = SERVER_STATUS_ERROR_FOUND; } else { - __handle_json_structured_message(text); + __handle_json_structured_message(conn, text); } g_free(text); @@ -1102,29 +1214,41 @@ static gint32 __send_greeting_to_register(SoupWebsocketConnection *conn) return id; } -static void __websocket_connected_cb(SoupSession *session, GAsyncResult *res, SoupMessage *message) +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; + + if (conn == NULL) { + g_printerr("conn is NULL\n"); + return; + } - g_print("\n[%s] is connected\n", g_signaling_server); ws_conn = soup_session_websocket_connect_finish(session, res, &error); if (error) { - __close_websocket(ws_conn); + 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_signaling_server, conn); + + conn->ws_conn = ws_conn; + conn->server_status = SERVER_STATUS_CONNECTED; - g_signal_connect(ws_conn, "closed", G_CALLBACK(__websocket_closed_cb), NULL); - g_signal_connect(ws_conn, "message", G_CALLBACK(__websocket_message_cb), NULL); + g_signal_connect(ws_conn, "closed", G_CALLBACK(__websocket_closed_cb), conn); + g_signal_connect(ws_conn, "message", G_CALLBACK(__websocket_message_cb), conn); - g_local_peer_id = __send_greeting_to_register(ws_conn); - g_ws_conn = ws_conn; - g_server_status = SERVER_STATUS_CONNECTED; + conn->local_peer_id = __send_greeting_to_register(ws_conn); } -static void _connect_signaling_server(void) +static void _connect_signaling_server(int index) { SoupMessage *message; SoupSession *session; @@ -1150,19 +1274,26 @@ static void _connect_signaling_server(void) g_print("connecting to signaling server[%s]...\n", g_signaling_server); soup_session_websocket_connect_async(session, message, NULL, NULL, NULL, - (GAsyncReadyCallback) __websocket_connected_cb, message); + (GAsyncReadyCallback) __websocket_connected_cb, &g_conns[index]); } void quit_program() { - if (g_webrtc != NULL) { - _webrtc_stop(); - _webrtc_destroy(); + int i; + for (i = 0; i < MAX_CONNECTION_LEN; i++) { + if (g_conns[i].webrtc != NULL) { + _webrtc_stop(i); + _webrtc_destroy(i); + } + if (g_conns[i].offer) + free(g_conns[i].offer); + if (g_conns[i].answer) + free(g_conns[i].answer); + if (g_conns[i].remote_desc) + free(g_conns[i].remote_desc); + g_list_free_full(g_conns[i].ice_candidates, free); } - free(g_offer); - free(g_answer); - free(g_remote_desc); - g_list_free_full(g_ice_candidates, free); + elm_exit(); } @@ -1171,25 +1302,25 @@ void _interpret_main_menu(char *cmd) int len = strlen(cmd); if (len == 1) { if (strncmp(cmd, "c", 1) == 0) { - _webrtc_create(); + _webrtc_create(g_conn_index); } else if (strncmp(cmd, "a", 1) == 0) { - g_menu_state = CURRENT_STATUS_ADD_MEDIA_SOURCE; + g_conns[g_conn_index].menu_state = CURRENT_STATUS_ADD_MEDIA_SOURCE; } else if (strncmp(cmd, "r", 1) == 0) { - g_menu_state = CURRENT_STATUS_REMOVE_MEDIA_SOURCE; + g_conns[g_conn_index].menu_state = CURRENT_STATUS_REMOVE_MEDIA_SOURCE; } else if (strncmp(cmd, "s", 1) == 0) { - _webrtc_start(); + _webrtc_start(g_conn_index); } else if (strncmp(cmd, "t", 1) == 0) { - _webrtc_stop(); + _webrtc_stop(g_conn_index); } else if (strncmp(cmd, "d", 1) == 0) { - _webrtc_destroy(); + _webrtc_destroy(g_conn_index); } else if (strncmp(cmd, "g", 1) == 0) { - _webrtc_get_state(); + _webrtc_get_state(g_conn_index); } else { g_print("unknown menu \n"); @@ -1197,97 +1328,103 @@ void _interpret_main_menu(char *cmd) } else if (len == 2) { if (strncmp(cmd, "gd", 2) == 0) { - g_menu_state = CURRENT_STATUS_GET_TRANSCEIVER_DIRECTION; + g_conns[g_conn_index].menu_state = CURRENT_STATUS_GET_TRANSCEIVER_DIRECTION; } else if (strncmp(cmd, "td", 2) == 0) { - g_menu_state = CURRENT_STATUS_SET_TRANSCEIVER_DIRECTION; + g_conns[g_conn_index].menu_state = CURRENT_STATUS_SET_TRANSCEIVER_DIRECTION; + + } else if (strncmp(cmd, "dt", 2) == 0) { + g_conns[g_conn_index].menu_state = CURRENT_STATUS_SET_DISPLAY_TYPE; } else if (strncmp(cmd, "cd", 2) == 0) { - _webrtc_create_data_channel(); + _webrtc_create_data_channel(g_conn_index); } else if (strncmp(cmd, "dd", 2) == 0) { - _webrtc_destroy_data_channel(); + _webrtc_destroy_data_channel(g_conn_index); } else if (strncmp(cmd, "sz", 2) == 0) { - _webrtc_set_data_channel_cb(); + _webrtc_set_data_channel_cb(g_conn_index); } else if (strncmp(cmd, "uz", 2) == 0) { - _webrtc_unset_data_channel_cb(); + _webrtc_unset_data_channel_cb(g_conn_index); } else if (strncmp(cmd, "zs", 2) == 0) { - g_menu_state = CURRENT_STATUS_DATA_CHANNEL_SEND_STRING; + g_conns[g_conn_index].menu_state = CURRENT_STATUS_DATA_CHANNEL_SEND_STRING; } else if (strncmp(cmd, "zb", 2) == 0) { - g_menu_state = CURRENT_STATUS_DATA_CHANNEL_SEND_STRING_AS_BYTES; + g_conns[g_conn_index].menu_state = CURRENT_STATUS_DATA_CHANNEL_SEND_STRING_AS_BYTES; } else if (strncmp(cmd, "zf", 2) == 0) { - g_menu_state = CURRENT_STATUS_DATA_CHANNEL_SEND_FILE; + g_conns[g_conn_index].menu_state = CURRENT_STATUS_DATA_CHANNEL_SEND_FILE; } else if (strncmp(cmd, "se", 2) == 0) { - _webrtc_set_error_cb(); + _webrtc_set_error_cb(g_conn_index); } else if (strncmp(cmd, "ue", 2) == 0) { - _webrtc_unset_error_cb(); + _webrtc_unset_error_cb(g_conn_index); } else if (strncmp(cmd, "sc", 2) == 0) { - _webrtc_set_state_changed_cb(); + _webrtc_set_state_changed_cb(g_conn_index); } else if (strncmp(cmd, "us", 2) == 0) { - _webrtc_unset_state_changed_cb(); + _webrtc_unset_state_changed_cb(g_conn_index); } else if (strncmp(cmd, "sn", 2) == 0) { - _webrtc_set_negotiation_needed_cb(); + _webrtc_set_negotiation_needed_cb(g_conn_index); } else if (strncmp(cmd, "un", 2) == 0) { - _webrtc_unset_negotiation_needed_cb(); + _webrtc_unset_negotiation_needed_cb(g_conn_index); } else if (strncmp(cmd, "si", 2) == 0) { - _webrtc_set_ice_candidate_cb(); + _webrtc_set_ice_candidate_cb(g_conn_index); } else if (strncmp(cmd, "ui", 2) == 0) { - _webrtc_unset_ice_candidate_cb(); + _webrtc_unset_ice_candidate_cb(g_conn_index); } else if (strncmp(cmd, "sk", 2) == 0) { - _webrtc_set_track_added_cb(); + _webrtc_set_track_added_cb(g_conn_index); } else if (strncmp(cmd, "uk", 2) == 0) { - _webrtc_unset_track_added_cb(); + _webrtc_unset_track_added_cb(g_conn_index); } else if (strncmp(cmd, "co", 2) == 0) { - _webrtc_create_offer(); + _webrtc_create_offer(g_conn_index); } else if (strncmp(cmd, "ca", 2) == 0) { - _webrtc_create_answer(); + _webrtc_create_answer(g_conn_index); } else if (strncmp(cmd, "sl", 2) == 0) { - g_menu_state = CURRENT_STATUS_SET_LOCAL_DESCRIPTION; + g_conns[g_conn_index].menu_state = CURRENT_STATUS_SET_LOCAL_DESCRIPTION; } else if (strncmp(cmd, "sr", 2) == 0) { - _webrtc_set_remote_description(); + _webrtc_set_remote_description(g_conn_index); } else if (strncmp(cmd, "st", 2) == 0) { - g_menu_state = CURRENT_STATUS_SET_STUN_SERVER; + g_conns[g_conn_index].menu_state = CURRENT_STATUS_SET_STUN_SERVER; } else if (strncmp(cmd, "gt", 2) == 0) { - _webrtc_get_stun_server(); + _webrtc_get_stun_server(g_conn_index); } else if (strncmp(cmd, "ss", 2) == 0) { - g_menu_state = CURRENT_STATUS_SETTING_SIGNALING_SERVER; + g_conns[g_conn_index].menu_state = CURRENT_STATUS_SETTING_SIGNALING_SERVER; } else if (strncmp(cmd, "px", 2) == 0) { - g_menu_state = CURRENT_STATUS_SETTING_PROXY; + g_conns[g_conn_index].menu_state = CURRENT_STATUS_SETTING_PROXY; + + } else if (strncmp(cmd, "cc", 2) == 0) { + g_conns[g_conn_index].menu_state = CURRENT_STATUS_CHANGE_CONNECTION; } else if (strncmp(cmd, "cs", 2) == 0) { - _connect_signaling_server(); + _connect_signaling_server(g_conn_index); } else if (strncmp(cmd, "rs", 2) == 0) { - g_menu_state = CURRENT_STATUS_REQUEST_SESSION; + g_conns[g_conn_index].menu_state = CURRENT_STATUS_REQUEST_SESSION; } else if (strncmp(cmd, "sd", 2) == 0) { - g_menu_state = CURRENT_STATUS_SEND_LOCAL_DESCRIPTION; + g_conns[g_conn_index].menu_state = CURRENT_STATUS_SEND_LOCAL_DESCRIPTION; } else if (strncmp(cmd, "ac", 2) == 0) { - _webrtc_add_ice_candidate(); + _webrtc_add_ice_candidate(g_conn_index); } else { g_print("unknown menu \n"); @@ -1295,12 +1432,12 @@ void _interpret_main_menu(char *cmd) } else if (len == 3) { if (strncmp(cmd, "sac", 3) == 0) { - _webrtc_set_error_cb(); - _webrtc_set_state_changed_cb(); - _webrtc_set_negotiation_needed_cb(); - _webrtc_set_ice_candidate_cb(); - _webrtc_set_track_added_cb(); - _webrtc_set_data_channel_cb(); + _webrtc_set_error_cb(g_conn_index); + _webrtc_set_state_changed_cb(g_conn_index); + _webrtc_set_negotiation_needed_cb(g_conn_index); + _webrtc_set_ice_candidate_cb(g_conn_index); + _webrtc_set_track_added_cb(g_conn_index); + _webrtc_set_data_channel_cb(g_conn_index); } else { g_print("unknown menu \n"); @@ -1311,23 +1448,24 @@ void _interpret_main_menu(char *cmd) } } -void display_handle_status() +void display_handle_status(int index) { int ret = WEBRTC_ERROR_NONE; webrtc_state_e state; char *stun_server; - if (g_webrtc == NULL) + if (g_conns[index].webrtc == NULL) return; - ret = webrtc_get_state(g_webrtc, &state); + ret = webrtc_get_state(g_conns[index].webrtc, &state); if (ret != WEBRTC_ERROR_NONE) return; - ret = webrtc_get_stun_server(g_webrtc, &stun_server); + ret = webrtc_get_stun_server(g_conns[index].webrtc, &stun_server); if (ret != WEBRTC_ERROR_NONE) return; + g_print(" webrtc[%p]", g_conns[index].webrtc); g_print(" state[%s]", g_webrtc_state_str[state]); if (strlen(stun_server) > 0) g_print(" STUN server[%s]", stun_server); @@ -1341,6 +1479,7 @@ void display_setting_status() { int len_proxy = strlen(g_proxy); int len_server = strlen(g_signaling_server); + int i; if (len_proxy == 0 && len_server == 0) return; @@ -1348,10 +1487,16 @@ void display_setting_status() if (len_proxy > 0) g_print(" proxy[%s]", g_proxy); if (len_server > 0) { - g_print(" server[%s]", g_signaling_server); - g_print("[%s]", g_server_status_str[g_server_status]); + g_print(" server[%s]\n", g_signaling_server); + for (i = 0; i < MAX_CONNECTION_LEN; i++) { + if (i == g_conn_index) + g_print(" [*]"); + else + g_print(" [ ]"); + g_print("[%d][%s]\n", i, g_server_status_str[g_conns[i].server_status]); + } } - g_print("\n-----------------------------------------------------------------------------------------\n"); + g_print("-----------------------------------------------------------------------------------------\n"); } void display_sub_basic() @@ -1360,7 +1505,7 @@ void display_sub_basic() g_print("=========================================================================================\n"); g_print(" Native WebRTC Test (press q to quit) \n"); g_print("-----------------------------------------------------------------------------------------\n"); - display_handle_status(); + display_handle_status(g_conn_index); g_print("c. Create\t"); g_print("d. Destroy\n"); g_print("s. Start\t"); @@ -1370,6 +1515,7 @@ void display_sub_basic() g_print("r. Remove media source\n"); g_print("gd. Get transceiver direction\t"); g_print("td. Set transceiver direction\n"); + g_print("dt. Set display type\n"); g_print("cd. Create data channel\t"); g_print("dd. Destroy data channel\n"); g_print("zs. Send string via data channel\n"); @@ -1401,6 +1547,7 @@ void display_sub_basic() display_setting_status(); g_print("px. Set proxy URL\n"); g_print("ss. Set signaling server URL\n"); + g_print("cc. Change connection\n"); g_print("cs. Connect to the signaling server\n"); g_print("rs. Request session of remote peer id\n"); g_print("sd. Send local description\n"); @@ -1410,54 +1557,60 @@ void display_sub_basic() static void displaymenu() { - if (g_menu_state == CURRENT_STATUS_MAINMENU) { + if (g_conns[g_conn_index].menu_state == CURRENT_STATUS_MAINMENU) { display_sub_basic(); - } else if (g_menu_state == CURRENT_STATUS_ADD_MEDIA_SOURCE) { + } else if (g_conns[g_conn_index].menu_state == CURRENT_STATUS_ADD_MEDIA_SOURCE) { g_print("*** input media source type.(1:camera, 2:mic, 3:audiotest, 4:videotest)\n"); - } else if (g_menu_state == CURRENT_STATUS_REMOVE_MEDIA_SOURCE) { + } else if (g_conns[g_conn_index].menu_state == CURRENT_STATUS_REMOVE_MEDIA_SOURCE) { g_print("*** input media source id to remove.\n"); - } else if (g_menu_state == CURRENT_STATUS_GET_TRANSCEIVER_DIRECTION) { - if (g_cnt == 0) + } else if (g_conns[g_conn_index].menu_state == CURRENT_STATUS_GET_TRANSCEIVER_DIRECTION) { + if (g_conns[g_conn_index].cnt == 0) g_print("*** input source id.\n"); - else if (g_cnt == 1) + else if (g_conns[g_conn_index].cnt == 1) g_print("*** input media type.(1:audio 2:video)\n"); - } else if (g_menu_state == CURRENT_STATUS_SET_TRANSCEIVER_DIRECTION) { - if (g_cnt == 0) + } else if (g_conns[g_conn_index].menu_state == CURRENT_STATUS_SET_TRANSCEIVER_DIRECTION) { + if (g_conns[g_conn_index].cnt == 0) g_print("*** input source id.\n"); - else if (g_cnt == 1) + else if (g_conns[g_conn_index].cnt == 1) g_print("*** input media type.(1:audio 2:video)\n"); - else if (g_cnt == 2) + else if (g_conns[g_conn_index].cnt == 2) g_print("*** input transceiver direction.(1:sendonly 2:recvonly, 3:sendrecv)\n"); - } else if (g_menu_state == CURRENT_STATUS_DATA_CHANNEL_SEND_STRING) { + } else if (g_conns[g_conn_index].menu_state == CURRENT_STATUS_SET_DISPLAY_TYPE) { + g_print("*** input display type.(1:overlay, 2:evas)\n"); + + } else if (g_conns[g_conn_index].menu_state == CURRENT_STATUS_DATA_CHANNEL_SEND_STRING) { g_print("*** input string to send.\n"); - } else if (g_menu_state == CURRENT_STATUS_DATA_CHANNEL_SEND_STRING_AS_BYTES) { + } else if (g_conns[g_conn_index].menu_state == CURRENT_STATUS_DATA_CHANNEL_SEND_STRING_AS_BYTES) { g_print("*** input string to send.(it will be converted to bytes data)\n"); - } else if (g_menu_state == CURRENT_STATUS_DATA_CHANNEL_SEND_FILE) { + } else if (g_conns[g_conn_index].menu_state == CURRENT_STATUS_DATA_CHANNEL_SEND_FILE) { g_print("*** input file path to send.\n"); - } else if (g_menu_state == CURRENT_STATUS_SET_STUN_SERVER) { + } else if (g_conns[g_conn_index].menu_state == CURRENT_STATUS_SET_STUN_SERVER) { g_print("*** input STUN server address.\n"); - } else if (g_menu_state == CURRENT_STATUS_SET_LOCAL_DESCRIPTION) { + } else if (g_conns[g_conn_index].menu_state == CURRENT_STATUS_SET_LOCAL_DESCRIPTION) { g_print("*** input type of local description.(1:offer, 2:answer)\n"); - } else if (g_menu_state == CURRENT_STATUS_SETTING_SIGNALING_SERVER) { + } else if (g_conns[g_conn_index].menu_state == CURRENT_STATUS_SETTING_SIGNALING_SERVER) { g_print("*** input signaling server URL.\n"); - } else if (g_menu_state == CURRENT_STATUS_SETTING_PROXY) { + } else if (g_conns[g_conn_index].menu_state == CURRENT_STATUS_SETTING_PROXY) { g_print("*** input proxy URL.\n"); - } else if (g_menu_state == CURRENT_STATUS_REQUEST_SESSION) { + } else if (g_conns[g_conn_index].menu_state == CURRENT_STATUS_CHANGE_CONNECTION) { + g_print("*** input to connection index.(0 ~ 3)\n"); + + } else if (g_conns[g_conn_index].menu_state == CURRENT_STATUS_REQUEST_SESSION) { g_print("*** input remote peer id.\n"); - } else if (g_menu_state == CURRENT_STATUS_SEND_LOCAL_DESCRIPTION) { + } else if (g_conns[g_conn_index].menu_state == CURRENT_STATUS_SEND_LOCAL_DESCRIPTION) { g_print("*** input type of local description to send to the server.(1:offer, 2:answer)\n"); } else { @@ -1482,26 +1635,26 @@ gboolean timeout_quit_program(void *data) void reset_menu_state(void) { - g_menu_state = CURRENT_STATUS_MAINMENU; + g_conns[g_conn_index].menu_state = CURRENT_STATUS_MAINMENU; } static void interpret(char *cmd) { int value; - switch (g_menu_state) { + switch (g_conns[g_conn_index].menu_state) { case CURRENT_STATUS_MAINMENU: _interpret_main_menu(cmd); break; case CURRENT_STATUS_ADD_MEDIA_SOURCE: { value = atoi(cmd); - _webrtc_add_media_source(value - 1); + _webrtc_add_media_source(g_conn_index, value - 1); reset_menu_state(); break; } case CURRENT_STATUS_REMOVE_MEDIA_SOURCE: { value = atoi(cmd); - _webrtc_remove_media_source(value); + _webrtc_remove_media_source(g_conn_index, value); reset_menu_state(); break; } @@ -1510,16 +1663,16 @@ static void interpret(char *cmd) static unsigned int media_type; value = atoi(cmd); - switch (g_cnt) { + switch (g_conns[g_conn_index].cnt) { case 0: id = value; - g_cnt++; + g_conns[g_conn_index].cnt++; break; case 1: media_type = value - 1; - _webrtc_get_transceiver_direction(id, media_type); + _webrtc_get_transceiver_direction(g_conn_index, id, media_type); id = media_type = 0; - g_cnt = 0; + g_conns[g_conn_index].cnt = 0; reset_menu_state(); break; } @@ -1531,51 +1684,57 @@ static void interpret(char *cmd) static unsigned int direction; value = atoi(cmd); - switch (g_cnt) { + switch (g_conns[g_conn_index].cnt) { case 0: id = value; - g_cnt++; + g_conns[g_conn_index].cnt++; break; case 1: media_type = value - 1; - g_cnt++; + g_conns[g_conn_index].cnt++; break; case 2: direction = value - 1; - _webrtc_set_transceiver_direction(id, media_type, direction); + _webrtc_set_transceiver_direction(g_conn_index, id, media_type, direction); id = media_type = direction = 0; - g_cnt = 0; + g_conns[g_conn_index].cnt = 0; reset_menu_state(); break; } break; } + case CURRENT_STATUS_SET_DISPLAY_TYPE: { + value = atoi(cmd); + _webrtc_set_display_type(g_conn_index, value - 1); + reset_menu_state(); + break; + } case CURRENT_STATUS_DATA_CHANNEL_SEND_STRING: { - _webrtc_data_channel_send_string(cmd); + _webrtc_data_channel_send_string(g_conn_index, cmd); reset_menu_state(); break; } case CURRENT_STATUS_DATA_CHANNEL_SEND_STRING_AS_BYTES: { - _webrtc_data_channel_send_string_as_bytes(cmd); + _webrtc_data_channel_send_string_as_bytes(g_conn_index, cmd); reset_menu_state(); break; } case CURRENT_STATUS_DATA_CHANNEL_SEND_FILE: { - _webrtc_data_channel_send_file(cmd); + _webrtc_data_channel_send_file(g_conn_index, cmd); reset_menu_state(); break; } case CURRENT_STATUS_SET_STUN_SERVER: { - _webrtc_set_stun_server(cmd); + _webrtc_set_stun_server(g_conn_index, cmd); reset_menu_state(); break; } case CURRENT_STATUS_SET_LOCAL_DESCRIPTION: { value = atoi(cmd); if (value == 1) - _webrtc_set_local_description(g_offer); + _webrtc_set_local_description(g_conn_index, true); else if (value == 2) - _webrtc_set_local_description(g_answer); + _webrtc_set_local_description(g_conn_index, false); else g_print("invalid value[%d]\n", value); @@ -1592,18 +1751,27 @@ static void interpret(char *cmd) reset_menu_state(); break; } + case CURRENT_STATUS_CHANGE_CONNECTION: { + value = atoi(cmd); + if (value < 0 || value > 3) + g_print("invalid value[%d]", value); + else + g_conn_index = value; + reset_menu_state(); + break; + } case CURRENT_STATUS_REQUEST_SESSION: { value = atoi(cmd); - _request_session(value); + _request_session(g_conn_index, value); reset_menu_state(); break; } case CURRENT_STATUS_SEND_LOCAL_DESCRIPTION: { value = atoi(cmd); if (value == 1) - _send_local_description(g_offer); + _send_local_description(g_conn_index, true); else if (value == 2) - _send_local_description(g_answer); + _send_local_description(g_conn_index, false); else g_print("invalid value[%d]\n", value); @@ -1637,7 +1805,7 @@ int main(int argc, char *argv[]) g_io_add_watch(stdin_channel, G_IO_IN, (GIOFunc)input, NULL); displaymenu(); - memset(&ad, 0x0, sizeof(appdata)); + memset(&ad, 0x0, sizeof(appdata_s)); ops.data = &ad; return appcore_efl_main(PACKAGE, &argc, &argv, &ops);