#include "webrtc_test_priv.h"
#include <tbm_surface_internal.h>
-#include <json-glib/json-glib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
g_cond_clear(&packet_source->cond);
}
-static void _webrtc_create(int index)
+void _webrtc_create(int index)
{
int ret = WEBRTC_ERROR_NONE;
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;
#endif
}
-static void _webrtc_start(int index)
+void _webrtc_start(int index)
{
int ret = WEBRTC_ERROR_NONE;
#endif
}
-static void _webrtc_stop(int index)
+void _webrtc_stop(int index)
{
int ret = WEBRTC_ERROR_NONE;
int i;
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;
*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;
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;
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;
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;
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;
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");
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;
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);
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;
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)
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);
}
}
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)
}
}
-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);
}
}
-static void _webrtc_create_data_channel(int index)
+void _webrtc_create_data_channel(int index)
{
int ret = WEBRTC_ERROR_NONE;
gchar *label;
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;
}
}
-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;
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;
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;
--- /dev/null
+/*
+ * 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 <json-glib/json-glib.h>
+
+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