Add WebRTC sample app 05/235805/22
authorHyunil <hyunil46.park@samsung.com>
Wed, 10 Jun 2020 02:10:32 +0000 (11:10 +0900)
committerHyunil <hyunil46.park@samsung.com>
Wed, 24 Jun 2020 06:27:27 +0000 (15:27 +0900)
- Add creating mediastreamer pipeline for WebRTC
- Add message callback for posting session description and ICE candidate
- Add decoded ready callback for making audio/video rendering nodes
- Add calling APIs for setting session description and ICE candidate

[Version] 0.1.72
[Issue Type] Test

Change-Id: Iea62f45b8ea7fde8a5890c5de4929907dec011ca
Signed-off-by: Hyunil <hyunil46.park@samsung.com>
packaging/capi-media-streamer.spec
test/media_streamer_test.c

index fac9403b3f5f94f0b5f7f29c72d3b1253495c00c..67eecad1c2ec8c4991b008b131ab882f07a37e27 100644 (file)
@@ -1,6 +1,6 @@
 Name:       capi-media-streamer
 Summary:    A Media Streamer API
-Version:    0.1.71
+Version:    0.1.72
 Release:    0
 Group:      Multimedia/API
 License:    Apache-2.0
index a0a9cc9b0ecd8f271f230d1a074f78de4cd5b510..155bee8a6839422215a11f346658b8082ad70e59 100644 (file)
 #include <Ecore.h>
 #include <Elementary.h>
 #include <appcore-efl.h>
+#include <media_streamer.h>
 
-/* For signalling */
+/* For WebRTC */
 #include <libsoup/soup.h>
 #include <json-glib/json-glib.h>
-#include <media_streamer.h>
 
 #ifdef PACKAGE
 #undef PACKAGE
 #endif
 #define PACKAGE "media_streamer_test"
 
-/* webrtc */
+/* For WebRTC */
 enum AppState {
        APP_STATE_UNKNOWN = 0,
-       APP_STATE_ERROR = 1, /* generic error */
+       APP_STATE_ERROR = 1,
        SERVER_CONNECTING = 1000,
        SERVER_CONNECTION_ERROR,
-       SERVER_CONNECTED, /* Ready to register */
+       SERVER_CONNECTED,       /* Ready to register */
        SERVER_REGISTERING = 2000,
        SERVER_REGISTRATION_ERROR,
-       SERVER_REGISTERED, /* Ready to call a peer */
-       SERVER_CLOSED, /* server connection closed by us or the server */
+       SERVER_REGISTERED,      /* Ready to call a peer */
+       SERVER_CLOSED,
        PEER_CONNECTING = 3000,
        PEER_CONNECTION_ERROR,
        PEER_CONNECTED,
@@ -72,6 +72,7 @@ typedef enum {
        SUBMENU_STATE_UNKNOWN,
        SUBMENU_STATE_GETTING_PEER_ID,
        SUBMENU_STATE_GETTING_PROXY_ADDR,
+       SUBMENU_STATE_GETTING_SERVER_URL,
        SUBMENU_STATE_GETTING_IP,
        SUBMENU_STATE_GETTING_SEEK_POS,
        SUBMENU_STATE_GETTING_FILE_URI,
@@ -147,7 +148,7 @@ typedef enum {
 #define DEFAULT_SEGMENT_PATH "/tmp/segment%05d.ts"
 #define DEFAULT_PLAYLIST_PATH "/tmp/playlist.m3u8"
 
-#define ENTER g_print ("%s:%d>%s\n",__FILE__, __LINE__, __FUNCTION__);
+#define ENTER g_print("%s:%d>%s\n",__FILE__, __LINE__, __FUNCTION__);
 
 /*---------------------------------------------------------------------------
 |    GLOBAL VARIABLE DEFINITIONS:                     |
@@ -163,7 +164,6 @@ int g_node_counter = 0;
 #define APPEND_NODE(x) {g_nodes[g_node_counter++] = x; }
 
 gchar *g_broadcast_address = NULL;
-gchar *g_proxy_address = NULL;
 int g_seek_pos = 0;
 int g_time = 0;
 int g_peer_id = 0;
@@ -179,13 +179,18 @@ gboolean use_tbm = FALSE;
 gboolean g_autoplug_mode = FALSE;
 gboolean g_video_is_on = FALSE;
 gboolean g_audio_is_on = FALSE;
-gboolean g_use_proxy = FALSE;
-static gint32 our_id = 0;
-static SoupWebsocketConnection *ws_conn = NULL;
-static const gchar *server_url = "wss://webrtc.nirbheek.in:8443";
-static enum AppState app_state = 0;
+
+/* For WebRTC */
+static gint32 g_our_id = 0;
+static SoupWebsocketConnection *g_ws_conn = NULL;
+static gchar *g_proxy_address = NULL;
+static gchar *g_server_url = NULL;
+static enum AppState g_app_state = 0;
 static gboolean disable_ssl = FALSE;
-media_streamer_node_h webrtcbin = NULL;
+media_streamer_node_h g_webrtc = NULL;
+media_streamer_node_h g_video_converter = NULL;
+media_streamer_node_h g_video_sink = NULL;
+media_streamer_node_h g_audio_sink = NULL;
 
 media_format_h vfmt_vp8 = NULL;
 media_format_h vfmt_i420 = NULL;
@@ -196,6 +201,7 @@ media_format_h afmt_f32le = NULL;
 media_format_h afmt_encoded = NULL;
 media_format_h afmt_aac = NULL;
 media_format_h afmt_mp3 = NULL;
+media_format_h afmt_opus = NULL;
 media_format_h cfmt_mpeg2ts = NULL;
 media_format_h cfmt_mp4 = NULL;
 
@@ -217,6 +223,59 @@ struct appcore_ops ops = {
 
 appdata ad;
 
+static void webrtc_decoded_ready_cb(media_streamer_node_h node, const char *src_pad_name, const char *media_type, void *user_data)
+{
+       media_streamer_node_h video_converter = NULL;
+       media_streamer_node_h video_sink = NULL;
+       media_streamer_node_h audio_sink = NULL;
+
+       g_print("WebRTC node's decoded ready callback is called, src_pad_name[%s], media_type[%s]\n", src_pad_name, media_type);
+
+       if (node == NULL) {
+               g_print("node is NULL\n");
+               return;
+       }
+       if (src_pad_name == NULL) {
+               g_print("src_pad_name is NULL\n");
+               return;
+       }
+       if (media_type == NULL) {
+               g_print("media_type is NULL\n");
+               return;
+       }
+
+       if (g_str_has_prefix (media_type, "video")) {
+               g_print("linking video renderer\n");
+
+               media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_VIDEO_CONVERTER, NULL, NULL, &video_converter);
+               media_streamer_node_add(current_media_streamer, video_converter);
+               APPEND_NODE(video_converter);
+
+               media_streamer_node_create_sink(MEDIA_STREAMER_NODE_SINK_TYPE_OVERLAY, &video_sink);
+               media_streamer_node_add(current_media_streamer, video_sink);
+               media_streamer_node_set_param(video_sink, MEDIA_STREAMER_PARAM_DISPLAY, (void*)ad.win);
+               media_streamer_node_set_param(video_sink, MEDIA_STREAMER_PARAM_DISPLAY_GEOMETRY_METHOD, "1");
+               APPEND_NODE(video_sink);
+
+               media_streamer_node_link(node , src_pad_name, video_converter, "sink");
+               media_streamer_node_link(video_converter, "src", video_sink, "sink");
+       } else if (g_str_has_prefix (media_type, "audio")) {
+               g_print("linking audio renderer\n");
+
+               media_streamer_node_create_sink(MEDIA_STREAMER_NODE_SINK_TYPE_AUDIO, &audio_sink);
+               media_streamer_node_add(current_media_streamer, audio_sink);
+               APPEND_NODE(audio_sink);
+
+               media_streamer_node_link(node , src_pad_name, audio_sink, "sink");
+       }
+}
+
+static void webrtc_message_cb(media_streamer_node_h webrtc_node, const char *message, void *user_data)
+{
+       g_print("Media Streamer webrtc posted message [%s] \n", message);
+       soup_websocket_connection_send_text (g_ws_conn, message);
+}
+
 static void streamer_error_cb(media_streamer_h streamer, media_streamer_error_e error, void *user_data)
 {
        g_print("Media Streamer posted error [%d] \n", error);
@@ -438,6 +497,14 @@ static void create_formats(void)
        media_format_set_audio_channel(afmt_encoded, AUDIO_CHANNEL);
        media_format_set_audio_samplerate(afmt_encoded, AUDIO_SAMPLERATE);
 
+       media_format_create(&afmt_opus);
+       if (media_format_set_audio_mime(afmt_opus, MEDIA_FORMAT_OPUS) != MEDIA_FORMAT_ERROR_NONE)
+               g_print("media_format_set_audio_mime failed!\n");
+
+       media_format_set_audio_channel(afmt_opus, AUDIO_CHANNEL);
+       media_format_set_audio_samplerate(afmt_opus, AUDIO_SAMPLERATE);
+
+
     /* Define audio mp3 format */
        media_format_create(&afmt_mp3);
        if (media_format_set_audio_mime(afmt_mp3, MEDIA_FORMAT_MP3) != MEDIA_FORMAT_ERROR_NONE)
@@ -463,260 +530,327 @@ static void create_formats(void)
                g_print("media_format_set_container_mime failed!\n");
 }
 
-static gboolean
-cleanup_webrtc (const gchar * msg, enum AppState state)
+static void start_webrtc_pipeline()
+{
+
+       /* Video */
+       media_streamer_node_h video_src = NULL;
+#if 0
+       media_streamer_node_create_src(MEDIA_STREAMER_NODE_SRC_TYPE_CAMERA, &video_src);
+       media_streamer_node_add(current_media_streamer, video_src);
+       media_streamer_node_set_param(video_src, MEDIA_STREAMER_PARAM_CAMERA_ID, "1");
+       APPEND_NODE(video_src);
+#else
+       media_streamer_node_create_src(MEDIA_STREAMER_NODE_SRC_TYPE_VIDEO_TEST, &video_src);
+       media_streamer_node_set_param(video_src, MEDIA_STREAMER_PARAM_IS_LIVE_STREAM, "true");
+       media_streamer_node_set_param(video_src, "pattern", "ball");
+       media_streamer_node_add(current_media_streamer, video_src);
+       APPEND_NODE(video_src);
+#endif
+
+       /* it is important to link filter for camera output regardless of codec input format */
+       media_streamer_node_h video_filter = NULL;
+       media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_FILTER, NULL, vfmt_i420, &video_filter);
+       media_streamer_node_add(current_media_streamer, video_filter);
+       APPEND_NODE(video_filter);
+
+       media_streamer_node_h video_queue0 = NULL;
+       media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_QUEUE, NULL, NULL, &video_queue0);
+       media_streamer_node_add(current_media_streamer, video_queue0);
+       APPEND_NODE(video_queue0);
+
+       media_streamer_node_h video_enc = NULL;
+       media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_VIDEO_ENCODER, vfmt_i420, vfmt_vp8, &video_enc);
+       media_streamer_node_add(current_media_streamer, video_enc);
+       APPEND_NODE(video_enc);
+
+       media_streamer_node_h video_pay = NULL;
+       media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_VIDEO_PAY, vfmt_vp8, NULL, &video_pay);
+       media_streamer_node_add(current_media_streamer, video_pay);
+       APPEND_NODE(video_pay);
+
+       media_streamer_node_h video_queue1 = NULL;
+       media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_QUEUE, NULL, NULL, &video_queue1);
+       media_streamer_node_add(current_media_streamer, video_queue1);
+       APPEND_NODE(video_queue1);
+
+       /* Audio */
+       media_streamer_node_h audio_src = NULL;
+       //media_streamer_node_create_src(MEDIA_STREAMER_NODE_SRC_TYPE_AUDIO_CAPTURE, &audio_src);
+       media_streamer_node_create_src(MEDIA_STREAMER_NODE_SRC_TYPE_AUDIO_TEST, &audio_src);
+       media_streamer_node_add(current_media_streamer, audio_src);
+       APPEND_NODE(audio_src);
+
+       media_streamer_node_h audio_queue0 = NULL;
+       media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_QUEUE, NULL, NULL, &audio_queue0);
+       media_streamer_node_add(current_media_streamer, audio_queue0);
+       APPEND_NODE(audio_queue0);
+
+       media_streamer_node_h audio_enc = NULL;
+       media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_AUDIO_ENCODER, afmt_pcm, afmt_opus, &audio_enc);
+       media_streamer_node_add(current_media_streamer, audio_enc);
+       APPEND_NODE(audio_enc);
+
+       media_streamer_node_h audio_pay = NULL;
+       media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_AUDIO_PAY, afmt_opus, NULL, &audio_pay);
+       media_streamer_node_add(current_media_streamer, audio_pay);
+       APPEND_NODE(audio_pay);
+
+       media_streamer_node_h audio_queue1 = NULL;
+       media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_QUEUE, NULL, NULL, &audio_queue1);
+       media_streamer_node_add(current_media_streamer, audio_queue1);
+       APPEND_NODE(audio_queue1);
+
+       media_streamer_node_h webrtc = NULL;
+       media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_WEBRTC, NULL, NULL, &webrtc);
+       media_streamer_node_add(current_media_streamer, webrtc);
+       APPEND_NODE(webrtc);
+       if (g_peer_id)
+               media_streamer_node_set_param(webrtc, MEDIA_STREAMER_PARAM_WEBRTC_PEER_TYPE, "offer");
+       else
+               media_streamer_node_set_param(webrtc, MEDIA_STREAMER_PARAM_WEBRTC_PEER_TYPE, "answer");
+       media_streamer_webrtc_node_set_message_cb(webrtc, webrtc_message_cb, NULL);
+       media_streamer_node_set_decoded_ready_cb(webrtc, webrtc_decoded_ready_cb, NULL);
+
+       /* Video link */
+       media_streamer_node_link(video_src, "src", video_filter, "sink");
+       media_streamer_node_link(video_filter, "src", video_queue0, "sink");
+       media_streamer_node_link(video_queue0, "src", video_enc, "sink");
+       media_streamer_node_link(video_enc, "src", video_pay, "sink");
+       media_streamer_node_link(video_pay, "src", video_queue1, "sink");
+       media_streamer_node_link(video_queue1, "src",webrtc, "video_in");
+
+       /* Audio link */
+       media_streamer_node_link(audio_src, "src", audio_queue0, "sink");
+       media_streamer_node_link(audio_queue0, "src", audio_enc, "sink");
+       media_streamer_node_link(audio_enc, "src", audio_pay, "sink");
+       media_streamer_node_link(audio_pay, "src", audio_queue1, "sink");
+       media_streamer_node_link(audio_queue1, "src", webrtc, "audio_in");
+
+
+       /* Note that setting pad format to WebRTC node is necessary, WebRTC use this format as media information for SDP */
+       media_streamer_node_set_pad_format(webrtc, "audio_in", afmt_opus);
+       media_streamer_node_set_pad_format(webrtc, "video_in", vfmt_vp8);
+
+       g_webrtc = webrtc;
+}
+
+static void __cleanup_webrtc(const gchar * msg, enum AppState state)
 {
        ENTER;
        if (msg)
-               g_printerr ("%s\n", msg);
+               g_printerr("%s\n", msg);
        if (state > 0)
-               app_state = state;
+               g_app_state = state;
 
-       if (ws_conn) {
-               if (soup_websocket_connection_get_state (ws_conn) ==
-                       SOUP_WEBSOCKET_STATE_OPEN)
+       if (g_ws_conn) {
+               if (soup_websocket_connection_get_state(g_ws_conn) == SOUP_WEBSOCKET_STATE_OPEN)
                        /* This will call us again */
-                       soup_websocket_connection_close (ws_conn, 1000, "");
+                       soup_websocket_connection_close(g_ws_conn, 1000, "");
                else
-               g_object_unref (ws_conn);
+                       g_object_unref(g_ws_conn);
        }
-       /* To allow usage as a GSourceFunc */
-       return G_SOURCE_REMOVE;
 }
 
-static gboolean
-setup_call (void)
+static gboolean __setup_call(void)
 {
        gchar *msg;
        ENTER;
 
-       if (soup_websocket_connection_get_state (ws_conn) !=
-               SOUP_WEBSOCKET_STATE_OPEN)
+       if (soup_websocket_connection_get_state(g_ws_conn) != SOUP_WEBSOCKET_STATE_OPEN)
                return FALSE;
        if (!g_peer_id)
                return FALSE;
 
-       g_print ("Setting up signalling server call with %d\n", g_peer_id);
-       app_state = PEER_CONNECTING;
-       msg = g_strdup_printf ("SESSION %d", g_peer_id);
-       soup_websocket_connection_send_text (ws_conn, msg);
-       g_free (msg);
+       g_print("Setting up signalling server call with %d\n", g_peer_id);
+       g_app_state = PEER_CONNECTING;
+       msg = g_strdup_printf("SESSION %d", g_peer_id);
+       soup_websocket_connection_send_text(g_ws_conn, msg);
+
+       g_free(msg);
+
        return TRUE;
 }
 
-/* One mega message handler for our asynchronous calling mechanism */
-static void
-on_server_message (SoupWebsocketConnection * conn, SoupWebsocketDataType type,
-    GBytes * message, gpointer user_data)
+static void __on_server_message(SoupWebsocketConnection * conn, SoupWebsocketDataType type,
+       GBytes * message, gpointer user_data)
 {
        gchar *text;
        ENTER;
 
        switch (type) {
        case SOUP_WEBSOCKET_DATA_BINARY:
-               g_printerr ("Received unknown binary message, ignoring\n");
+               g_printerr("Received unknown binary message, ignoring\n");
                return;
        case SOUP_WEBSOCKET_DATA_TEXT: {
                gsize size;
-               const gchar *data = g_bytes_get_data (message, &size);
+               const gchar *data = g_bytes_get_data(message, &size);
                /* Convert to NULL-terminated string */
-               text = g_strndup (data, size);
-               g_print ("Received text message, [%s]\n", text);
+               text = g_strndup(data, size);
+               g_print("Received text message, [%s]\n", text);
                break;
        }
        default:
-               g_assert_not_reached ();
+               g_assert_not_reached();
        }
 
        /* Server has accepted our registration, we are ready to send commands */
-       if (g_strcmp0 (text, "HELLO") == 0) {
-               if (app_state != SERVER_REGISTERING) {
-                       cleanup_webrtc ("ERROR: Received HELLO when not registering",
-                       APP_STATE_ERROR);
+       if (g_strcmp0(text, "HELLO") == 0) {
+               if (g_app_state != SERVER_REGISTERING) {
+                       __cleanup_webrtc("ERROR: Received HELLO when not registering",APP_STATE_ERROR);
                        goto out;
                }
-               app_state = SERVER_REGISTERED;
-               g_print ("Registered with server\n");
+               g_app_state = SERVER_REGISTERED;
+               g_print("Registered with server\n");
                /* Ask signalling server to connect us with a specific peer */
                if (g_peer_id) {
-                       if (!setup_call ()) {
-                               cleanup_webrtc ("ERROR: Failed to setup call", PEER_CALL_ERROR);
+                       if (!__setup_call()) {
+                               __cleanup_webrtc("ERROR: Failed to setup call", PEER_CALL_ERROR);
                                goto out;
                        }
                } else {
                        /* should WAIT for another peer */
-                       g_print ("need to wait for another peer...(our id:%d)\n", our_id);
-                       app_state = PEER_CALL_WAITING;
-                       /* Start negotiation (exchange SDP and ICE candidates) */
-                       /* need to start pipeline_answer */
+                       g_print("need to wait for another peer...(our id:%d)\n", g_our_id);
+                       g_app_state = PEER_CALL_WAITING;
+
+                       /* For answerer */
+                       start_webrtc_pipeline();
                }
        /* Call has been setup by the server, now we can start negotiation */
-       } else if (g_strcmp0 (text, "SESSION_OK") == 0) {
-               if (app_state != PEER_CONNECTING) {
-                       cleanup_webrtc ("ERROR: Received SESSION_OK when not calling",
-                       PEER_CONNECTION_ERROR);
+       } else if (g_strcmp0(text, "SESSION_OK") == 0) {
+               if (g_app_state != PEER_CONNECTING) {
+                       __cleanup_webrtc("ERROR: Received SESSION_OK when not calling", PEER_CONNECTION_ERROR);
                        goto out;
                }
 
-           app_state = PEER_CONNECTED;
+               g_app_state = PEER_CONNECTED;
                /* Start negotiation (exchange SDP and ICE candidates) */
                /* need to start pipeline */
+               start_webrtc_pipeline();
        /* Handle errors */
-       } else if (g_str_has_prefix (text, "ERROR")) {
-               switch (app_state) {
+       } else if (g_str_has_prefix(text, "ERROR")) {
+               switch (g_app_state) {
                case SERVER_CONNECTING:
-                       app_state = SERVER_CONNECTION_ERROR;
+                       g_app_state = SERVER_CONNECTION_ERROR;
                        break;
                case SERVER_REGISTERING:
-                       app_state = SERVER_REGISTRATION_ERROR;
+                       g_app_state = SERVER_REGISTRATION_ERROR;
                        break;
                case PEER_CONNECTING:
-                       app_state = PEER_CONNECTION_ERROR;
+                       g_app_state = PEER_CONNECTION_ERROR;
                        break;
                case PEER_CALL_WAITING:
                case PEER_CONNECTED:
                case PEER_CALL_NEGOTIATING:
-                       app_state = PEER_CALL_ERROR;
+                       g_app_state = PEER_CALL_ERROR;
                        break;
                default:
-                       app_state = APP_STATE_ERROR;
-    }
-       cleanup_webrtc (text, 0);
+                       g_app_state = APP_STATE_ERROR;
+               }
+               __cleanup_webrtc(text, 0);
        /* Look for JSON messages containing SDP and ICE candidates */
        } else {
                JsonNode *root;
-               JsonObject *object, *child;
-               JsonParser *parser = json_parser_new ();
-               if (!json_parser_load_from_data (parser, text, -1, NULL)) {
-                       g_printerr ("Unknown message '%s', ignoring", text);
-                       g_object_unref (parser);
+               JsonObject *object;
+               JsonParser *parser = json_parser_new();
+
+               if (!json_parser_load_from_data(parser, text, -1, NULL)) {
+                       g_printerr("Unknown message '%s', ignoring", text);
+                       g_object_unref(parser);
                        goto out;
                }
 
-               root = json_parser_get_root (parser);
-               if (!JSON_NODE_HOLDS_OBJECT (root)) {
-                       g_printerr ("Unknown json message '%s', ignoring", text);
-                       g_object_unref (parser);
+               root = json_parser_get_root(parser);
+               if (!JSON_NODE_HOLDS_OBJECT(root)) {
+                       g_printerr("Unknown json message '%s', ignoring", text);
+                       g_object_unref(parser);
                        goto out;
                }
 
-               object = json_node_get_object (root);
                /* Check type of JSON message */
-               if (json_object_has_member (object, "sdp")) {
-                       const gchar *text, *sdptype;
-
-                       if (g_peer_id)
-                               g_assert_cmphex (app_state, ==, PEER_CALL_NEGOTIATING);
-                       else
-                       g_assert_cmphex (app_state, ==, PEER_CALL_WAITING);
-
-                       child = json_object_get_object_member (object, "sdp");
-
-                       if (!json_object_has_member (child, "type")) {
-                               cleanup_webrtc ("ERROR: received SDP without 'type'",
-                               PEER_CALL_ERROR);
-                               goto out;
-                       }
-
-                       sdptype = json_object_get_string_member (child, "type");
-                       text = json_object_get_string_member (child, "sdp");
-
-
-                       if (g_str_equal (sdptype, "answer")) {
-                               g_print ("Received answer:\n%s\n", text);
-
-                               /* need to API: set remote description */
-
-                               app_state = PEER_CALL_STARTED;
-                       } else {
-                               g_print ("Received offer:\n%s\n", text);
-                               /* need to API: set remote description */
-                       }
-
-               } else if (json_object_has_member (object, "ice")) {
-                       /*need to API: Add ice candidate sent by remote peer */
+               object = json_node_get_object(root);
+               if (json_object_has_member(object, "sdp")){
+                       /* set remote session description */
+                       if (media_streamer_node_set_param(g_webrtc, MEDIA_STREAMER_PARAM_WEBRTC_REMOTE_SESSION_DESCRIPTION, text) == MEDIA_STREAMER_ERROR_NONE)
+                               g_app_state = PEER_CALL_STARTED;
+               } else if (json_object_has_member(object, "ice")){
+                       /* add ice candidates, several candidates arrive from the peer */
+                       media_streamer_node_set_param(g_webrtc, MEDIA_STREAMER_PARAM_WEBRTC_ADD_ICE_CANDIDATE, text);
                } else {
-                       g_printerr ("Ignoring unknown JSON message:\n%s\n", text);
+                       g_printerr("Ignoring unknown JSON message:\n%s\n", text);
                }
-               g_object_unref (parser);
+               g_object_unref(parser);
        }
-
 out:
        g_free (text);
 }
 
-static gint32
-register_with_server (void)
+static gint32 __register_with_server(void)
 {
        gchar *hello;
        gint32 our_id;
        ENTER;
 
-       if (soup_websocket_connection_get_state (ws_conn) !=
-               SOUP_WEBSOCKET_STATE_OPEN)
+       if (soup_websocket_connection_get_state(g_ws_conn) != SOUP_WEBSOCKET_STATE_OPEN)
                return -1;
 
-       our_id = g_random_int_range (10, 10000);
-       g_print ("Registering id %i with server\n", our_id);
-       app_state = SERVER_REGISTERING;
+       our_id = g_random_int_range(10, 10000);
+       g_print("Registering id %i with server\n", our_id);
+       g_app_state = SERVER_REGISTERING;
 
        /* Register with the server with a random integer id. Reply will be received
         * by on_server_message() */
-       hello = g_strdup_printf ("HELLO %i", our_id);
-       soup_websocket_connection_send_text (ws_conn, hello);
-       g_free (hello);
+       hello = g_strdup_printf("HELLO %i", our_id);
+       soup_websocket_connection_send_text(g_ws_conn, hello);
+
+       g_free(hello);
 
        return our_id;
 }
 
 /* Answer created by our pipeline, to be sent to the peer */
-static void
-on_server_closed (SoupWebsocketConnection * conn G_GNUC_UNUSED,
-    gpointer user_data G_GNUC_UNUSED)
+static void __on_server_closed(SoupWebsocketConnection * conn G_GNUC_UNUSED, gpointer user_data G_GNUC_UNUSED)
 {
-       app_state = SERVER_CLOSED;
+       g_app_state = SERVER_CLOSED;
        ENTER;
 
-       cleanup_webrtc ("Server connection closed", 0);
+       __cleanup_webrtc("Server connection closed", 0);
 }
 
-static void
-on_server_connected (SoupSession * session, GAsyncResult * res,
-    SoupMessage *msg)
+static void __on_server_connected(SoupSession * session, GAsyncResult * res, SoupMessage *msg)
 {
        GError *error = NULL;
        ENTER;
 
-       g_print("on_server_connected\n");
-       ws_conn = soup_session_websocket_connect_finish (session, res, &error);
+       g_print("__on_server_connected\n");
+       g_ws_conn = soup_session_websocket_connect_finish(session, res, &error);
        if (error) {
-               cleanup_webrtc (error->message, SERVER_CONNECTION_ERROR);
-               g_error_free (error);
+               __cleanup_webrtc(error->message, SERVER_CONNECTION_ERROR);
+               g_error_free(error);
                return;
        }
 
-       g_assert_nonnull (ws_conn);
+       g_assert_nonnull(g_ws_conn);
 
-       app_state = SERVER_CONNECTED;
-       g_print ("Connected to signalling server\n");
+       g_app_state = SERVER_CONNECTED;
+       g_print("Connected to signalling server\n");
 
-       g_signal_connect (ws_conn, "closed", G_CALLBACK (on_server_closed), NULL);
-       g_signal_connect (ws_conn, "message", G_CALLBACK (on_server_message), NULL);
+       g_signal_connect(g_ws_conn, "closed", G_CALLBACK(__on_server_closed), NULL);
+       g_signal_connect(g_ws_conn, "message", G_CALLBACK(__on_server_message), NULL);
 
        /* Register with the server so it knows about us and can accept commands */
-       our_id = register_with_server ();
+       g_our_id = __register_with_server();
 }
 
 /* TIZEN: add for log */
-static inline gchar
-gst_soup_util_log_make_level_tag (SoupLoggerLogLevel level)
+static inline gchar __convert_log_level_tag(SoupLoggerLogLevel level)
 {
        gchar c;
 
-       if (G_UNLIKELY ((gint) level > 9))
+       if (G_UNLIKELY((gint) level > 9))
                return '?';
 
-       switch (level) {
+       switch(level) {
        case SOUP_LOGGER_LOG_MINIMAL:
                c = 'M';
                break;
@@ -736,19 +870,16 @@ gst_soup_util_log_make_level_tag (SoupLoggerLogLevel level)
        return c;
 }
 
-static void
-_log_printer_cb (SoupLogger G_GNUC_UNUSED * logger,
-    SoupLoggerLogLevel level, char direction, const char *data,
-    gpointer user_data)
+static void __log_printer_cb(SoupLogger G_GNUC_UNUSED * logger, SoupLoggerLogLevel level,
+                               char direction, const char *data, gpointer user_data)
 {
        gchar c;
 
-       c = gst_soup_util_log_make_level_tag (level);
+       c = __convert_log_level_tag(level);
        g_print("HTTP_SESSION(%c): %c %s\n", c, direction, data);
 }
 
-static void
-connect_to_websocket_server_async (void)
+static void __connect_to_websocket_server_async(void)
 {
        SoupLogger *logger;
        SoupMessage *message;
@@ -757,35 +888,35 @@ connect_to_websocket_server_async (void)
        const char *https_aliases[] = {"wss", NULL};
        ENTER;
 
-       if (!g_use_proxy){
-               session = soup_session_new_with_options (SOUP_SESSION_SSL_STRICT, !disable_ssl,
+       if (!g_proxy_address){
+               session = soup_session_new_with_options(SOUP_SESSION_SSL_STRICT, !disable_ssl,
                        SOUP_SESSION_HTTPS_ALIASES, https_aliases, NULL);
        } else {
-           proxy_uri = soup_uri_new (g_proxy_address);
-               session = soup_session_new_with_options (SOUP_SESSION_SSL_STRICT, !disable_ssl,
+               g_print("Use proxy\n");
+               proxy_uri = soup_uri_new(g_proxy_address);
+               session = soup_session_new_with_options(SOUP_SESSION_SSL_STRICT, !disable_ssl,
                        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);
+                       soup_uri_free(proxy_uri);
        }
 
-       logger = soup_logger_new (SOUP_LOGGER_LOG_BODY, -1);
+       logger = soup_logger_new(SOUP_LOGGER_LOG_BODY, -1);
 
-       /* TIZEN: add for log */
-       soup_logger_set_printer (logger, _log_printer_cb, NULL, NULL);
+       soup_logger_set_printer(logger, __log_printer_cb, NULL, NULL);
 
-       soup_session_add_feature (session, SOUP_SESSION_FEATURE (logger));
-       g_object_unref (logger);
+       soup_session_add_feature(session, SOUP_SESSION_FEATURE (logger));
+       g_object_unref(logger);
 
-       message = soup_message_new (SOUP_METHOD_GET, server_url);
+       message = soup_message_new(SOUP_METHOD_GET, g_server_url);
 
-       g_print ("Connecting to server[%s]...\n", server_url);
+       g_print("Connecting to server[%s]...\n", g_server_url);
 
        /* Once connected, we will register */
-       soup_session_websocket_connect_async (session, message, NULL, NULL, NULL,
-               (GAsyncReadyCallback) on_server_connected, message);
-       app_state = SERVER_CONNECTING;
+       soup_session_websocket_connect_async(session, message, NULL, NULL, NULL,
+               (GAsyncReadyCallback) __on_server_connected, message);
+       g_app_state = SERVER_CONNECTING;
 }
 
 static void set_rtp_params(media_streamer_node_h rtp_node, const char *ip, int video_port, int audio_port, gboolean port_reverse)
@@ -1493,25 +1624,20 @@ void reset_current_menu_state(void)
                g_media_streamer_2 = NULL;
        }
 
-       if (g_broadcast_address != NULL) {
-               g_free(g_broadcast_address);
-               g_broadcast_address = NULL;
-       }
+       g_free(g_broadcast_address);
+       g_broadcast_address = NULL;
 
-       if (g_proxy_address != NULL) {
-               g_free(g_proxy_address);
-               g_proxy_address = NULL;
-       }
+       g_free(g_proxy_address);
+       g_proxy_address = NULL;
 
-       if (g_uri != NULL) {
-               g_free(g_uri);
-               g_uri = NULL;
-       }
+       g_free(g_server_url);
+       g_server_url = NULL;
 
-       if (g_sub_uri != NULL) {
-               g_free(g_sub_uri);
-               g_sub_uri = NULL;
-       }
+       g_free(g_uri);
+       g_uri = NULL;
+
+       g_free(g_sub_uri);
+       g_sub_uri = NULL;
 
        /* Clean Up Nodes */
        int i = g_node_counter - 1;
@@ -1538,6 +1664,14 @@ static void display_getting_proxy_addr_menu(void)
        g_print("----------------------------------------------------\n");
 }
 
+static void display_getting_server_url_menu(void)
+{
+       g_print("\n");
+       g_print("====================================================\n");
+       g_print("Please input server URL to handshake with peer \n");
+       g_print("----------------------------------------------------\n");
+}
+
 static void display_getting_peer_id_menu(void)
 {
        g_print("\n");
@@ -1791,6 +1925,9 @@ static void display_menu(void)
                case SUBMENU_STATE_GETTING_PROXY_ADDR:
                        display_getting_proxy_addr_menu();
                        break;
+               case SUBMENU_STATE_GETTING_SERVER_URL:
+                       display_getting_server_url_menu();
+                       break;
                case SUBMENU_STATE_GETTING_IP:
                        display_getting_ip_menu();
                        break;
@@ -1897,7 +2034,7 @@ void run_webrtc_preset(void)
 {
        if ((g_scenario_mode == SCENARIO_MODE_WEBRTC_SENDRECV_VIDEO_AUDIO)) {
                create_formats();
-               connect_to_websocket_server_async ();
+               __connect_to_websocket_server_async();
        } else {
                g_print("Invalid scenario menu preset was selected!");
        }
@@ -2143,7 +2280,7 @@ void _interpret_webrtc_scenario_menu(char *cmd)
                        g_printf("g_sub_menu_state (%d)\n", g_sub_menu_state);
                }
        }
-       g_sub_menu_state = SUBMENU_STATE_GETTING_PROXY_ADDR;
+       g_sub_menu_state = SUBMENU_STATE_GETTING_SERVER_URL;
 }
 
 void _interpret_scenario_menu(char *cmd)
@@ -2206,6 +2343,24 @@ void _interpret_scenario_menu(char *cmd)
        }
 }
 
+void _interpret_getting_server_url_menu(char *cmd)
+{
+       int min_len = strlen("0.0.0.0");
+       int cmd_len = strlen(cmd);
+
+       if (g_server_url != NULL)
+               g_free(g_server_url);
+
+       if (cmd_len > min_len) {
+               g_server_url = g_strdup(cmd);
+               g_print("User set server URL[%s]\n", g_server_url);
+       } else {
+               g_print("Invalid value\n");
+       }
+
+       g_sub_menu_state = SUBMENU_STATE_GETTING_PROXY_ADDR;
+}
+
 void _interpret_getting_proxy_addr_menu(char *cmd)
 {
        int min_len = strlen("0.0.0.0");
@@ -2215,11 +2370,11 @@ void _interpret_getting_proxy_addr_menu(char *cmd)
 
        if (cmd_len == 1) {
                if (cmd[0] == '0') {
-                       g_use_proxy = FALSE;
+                       g_print("Skip set proxy address\n");
                }
        } else if (cmd_len > min_len) {
                g_proxy_address = g_strdup(cmd);
-               g_print("User set proxy address set to [%s]\n", g_proxy_address);
+               g_print("User set proxy address[%s]\n", g_proxy_address);
        } else {
                g_print("Invalid value\n");
        }
@@ -2446,6 +2601,9 @@ static void interpret_cmd(char *cmd)
                case SUBMENU_STATE_GETTING_PROXY_ADDR:
                        _interpret_getting_proxy_addr_menu(cmd);
                        break;
+               case SUBMENU_STATE_GETTING_SERVER_URL:
+                       _interpret_getting_server_url_menu(cmd);
+                       break;
                case SUBMENU_STATE_GETTING_PEER_ID:
                        _interpret_getting_peer_id_menu(cmd);
                        break;