webrtc_signaling_client: Add internal API set for client of signaling server 51/251251/22
authorSangchul Lee <sc11.lee@samsung.com>
Tue, 12 Jan 2021 03:53:06 +0000 (12:53 +0900)
committerSangchul Lee <sc11.lee@samsung.com>
Mon, 1 Feb 2021 10:27:17 +0000 (19:27 +0900)
Functions are added as below.
 - webrtc_signaling_connect()
 - webrtc_signaling_request_session()
 - webrtc_signaling_send_message()
 - webrtc_signaling_get_id()
 - webrtc_signaling_disconnect()

[Version] 0.1.94
[Issue Type] API

Change-Id: I95fe182d70cb6f255abee96a7e99793b3777a269
Signed-off-by: Sangchul Lee <sc11.lee@samsung.com>
CMakeLists.txt
include/webrtc_internal.h
include/webrtc_private.h
packaging/capi-media-webrtc.spec
src/webrtc_signaling_client.c [new file with mode: 0644]

index 2e07c5222ece938914ef8a66f379bd525a8655b1..c1f7afa6f9d8b5c2f8829a33741ce49053d73a54 100644 (file)
@@ -13,7 +13,7 @@ INCLUDE_DIRECTORIES(${INC_DIR})
 
 SET(dependents "dlog glib-2.0 gstreamer-1.0 gstreamer-webrtc-1.0 gstreamer-video-1.0 gstreamer-audio-1.0 \
                 json-glib-1.0 iniparser mm-common mm-display-interface capi-media-tool libtbm libwebsockets \
-                cynara-client libsmack")
+                cynara-client libsmack libsoup-2.4")
 IF(TIZEN_FEATURE_RESOURCE_MANAGER)
 SET(dependents "${dependents} mm-resource-manager")
 ADD_DEFINITIONS("-DTIZEN_FEATURE_RES_MGR")
index 1e2c53b951a30a17622d1146107d9778b1331977..26cf05ac8cce158dc0bf73517cc3d7fb0ffb8171 100644 (file)
@@ -38,6 +38,39 @@ extern "C" {
  */
 typedef void *webrtc_signaling_server_h;
 
+/**
+ * @internal
+ * @brief WebRTC signaling client handle type.
+ * @since_tizen 6.5
+ */
+typedef void *webrtc_signaling_client_h;
+
+/**
+ * @internal
+ * @brief Enumeration for WebRTC signaling message type.
+ * @since_tizen 6.5
+ */
+typedef enum {
+       SIGNALING_MESSAGE_TYPE_CONNECTED,           /**< Connected */
+       SIGNALING_MESSAGE_TYPE_DISCONNECTED,        /**< Disconnected */
+       SIGNALING_MESSAGE_TYPE_SESSION_ESTABLISHED, /**< Session established */
+       SIGNALING_MESSAGE_TYPE_SESSION_CLOSED,      /**< Session closed */
+       SIGNALING_MESSAGE_TYPE_SDP,                 /**< SDP */
+       SIGNALING_MESSAGE_TYPE_ICE_CANDIDATE,       /**< ICE candidate */
+       SIGNALING_MESSAGE_TYPE_ERROR,               /**< Error */
+} webrtc_signaling_message_type_e;
+
+/**
+ * @internal
+ * @brief Called when a message to be handled is sent from the remote peer or the signaling server.
+ * @since_tizen 6.5
+ * @param[in] type       The signaling message type
+ * @param[in] message    The message
+ * @param[in] user_data  The user data passed from the callback registration function
+ * @see webrtc_signaling_connect_server()
+ */
+typedef void (*webrtc_signaling_message_cb)(webrtc_signaling_message_type_e type, const char *message, void *user_data);
+
 /**
  * @internal
  * @brief Set an ecore wayland display to the media track.
@@ -121,6 +154,96 @@ int webrtc_signaling_server_stop(webrtc_signaling_server_h server);
  */
 int webrtc_signaling_server_destroy(webrtc_signaling_server_h server);
 
+/**
+ * @internal
+ * @brief Connects to a signaling server for private network.
+ * @since_tizen 6.5
+ * @param[in] server_ip      The signaling server IP address
+ * @param[in] port           The port number
+ * @param[in] callback       Callback function pointer
+ * @param[in] user_data      The user data to be passed to the callback function
+ * @param[out] client        Signaling client handle
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #WEBRTC_ERROR_NONE    Successful
+ * @retval #WEBRTC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #WEBRTC_ERROR_INVALID_OPERATION Invalid operation
+ * @see webrtc_signaling_get_id()
+ * @see webrtc_signaling_request_session()
+ * @see webrtc_signaling_send_message()
+ * @see webrtc_signaling_disconnect_server()
+ */
+int webrtc_signaling_connect(const char *server_ip, int port, webrtc_signaling_message_cb callback, void *user_data, webrtc_signaling_client_h *client);
+
+/**
+ * @internal
+ * @brief Requests session to the peer id.
+ * @since_tizen 6.5
+ * @param[in] client         Signaling client handle
+ * @param[in] peer_id        The peer client handle id
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #WEBRTC_ERROR_NONE    Successful
+ * @retval #WEBRTC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #WEBRTC_ERROR_INVALID_OPERATION Invalid operation
+ * @pre Call webrtc_signaling_connect_server() before calling this function.
+ * @see webrtc_signaling_get_id()
+ * @see webrtc_signaling_send_message()
+ */
+int webrtc_signaling_request_session(webrtc_signaling_client_h client, int peer_id);
+
+/**
+ * @internal
+ * @brief Sends message to the peer client.
+ * @since_tizen 6.5
+ * @param[in] client         Signaling client handle
+ * @param[in] message        The message
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #WEBRTC_ERROR_NONE    Successful
+ * @retval #WEBRTC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #WEBRTC_ERROR_INVALID_OPERATION Invalid operation
+ * @retval #WEBRTC_ERROR_INVALID_STATE Invalid state
+ * @pre Call webrtc_signaling_connect_server() before calling this function.
+ * @pre Call webrtc_signaling_request_session() before calling this function.
+ * @see webrtc_signaling_get_id()
+ * @see webrtc_signaling_request_session()
+ */
+int webrtc_signaling_send_message(webrtc_signaling_client_h client, const char *message);
+
+/**
+ * @internal
+ * @brief Gets the id of the signaling client handle.
+ * @since_tizen 6.5
+ * @param[in] client         Signaling client handle
+ * @param[out] id            Signaling client handle id
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #WEBRTC_ERROR_NONE    Successful
+ * @retval #WEBRTC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #WEBRTC_ERROR_INVALID_OPERATION Invalid operation
+ * @pre Call webrtc_signaling_connect_server() before calling this function.
+ * @see webrtc_signaling_request_session()
+ * @see webrtc_signaling_send_message()
+ */
+int webrtc_signaling_get_id(webrtc_signaling_client_h client, int *id);
+
+/**
+ * @internal
+ * @brief Disconnects from the signaling server.
+ * @since_tizen 6.5
+ * @param[in] client         Signaling client handle
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #WEBRTC_ERROR_NONE    Successful
+ * @retval #WEBRTC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @pre Call webrtc_signaling_connect_server() before calling this function.
+ * @see webrtc_signaling_get_id()
+ * @see webrtc_signaling_request_session()
+ * @see webrtc_signaling_send_message()
+ */
+int webrtc_signaling_disconnect(webrtc_signaling_client_h client);
+
 /**
  * @}
  */
index b95831967f14b0cd64095936fb53752ba950bb91..6019e5d475dcaa0c1d8faa37b462bb83b52e765f 100644 (file)
@@ -31,6 +31,7 @@
 #endif
 #include <tbm_bufmgr.h>
 #include <libwebsockets.h>
+#include <libsoup/soup.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -374,6 +375,14 @@ typedef struct _webrtc_signaling_server_s {
        GHashTable *clients;
 } webrtc_signaling_server_s;
 
+typedef struct webrtc_signaling_client_s {
+       SoupSession *session;
+       SoupWebsocketConnection *ws_conn;
+       int id;
+
+       webrtc_callbacks_s message_cb;
+} webrtc_signaling_client_s;
+
 int _load_ini(webrtc_s *webrtc);
 void _unload_ini(webrtc_s *webrtc);
 ini_item_media_source_s* _ini_get_source_by_type(webrtc_ini_s *ini, webrtc_media_source_type_e type);
index 8947b966489c734b50db64c6bbcb1848b50b9a50..4f72d4d50a884d3bdaa677f8613fb7801247c04b 100644 (file)
@@ -1,6 +1,6 @@
 Name:       capi-media-webrtc
 Summary:    A WebRTC library in Tizen Native API
-Version:    0.1.93
+Version:    0.1.94
 Release:    0
 Group:      Multimedia/API
 License:    Apache-2.0
diff --git a/src/webrtc_signaling_client.c b/src/webrtc_signaling_client.c
new file mode 100644 (file)
index 0000000..db66d0c
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2021 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.h"
+#include "webrtc_private.h"
+#include "webrtc_internal.h"
+
+static void __websocket_message_cb(SoupWebsocketConnection *ws_conn, SoupWebsocketDataType type, GBytes *message, gpointer user_data)
+{
+       gchar *text;
+       gsize size;
+       const gchar *data;
+       webrtc_signaling_client_s *client = (webrtc_signaling_client_s *)user_data;
+
+       RET_IF(client == NULL, "client is NULL");
+       RET_IF(client->ws_conn == NULL, "ws_conn is NULL");
+       RET_IF(client->ws_conn != ws_conn, "invalid 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);
+
+       LOG_DEBUG("receive message:\n%s", text);
+
+       /* FIXME: assign id and invoke message callback */
+
+       g_free(text);
+}
+
+static void __close_websocket(webrtc_signaling_client_s *client)
+{
+       RET_IF(client == NULL, "client is NULL");
+
+       if (client->ws_conn == NULL) {
+               LOG_DEBUG("ws_conn is NULL, it might be already closed");
+               return;
+       }
+
+       if (soup_websocket_connection_get_state(client->ws_conn) == SOUP_WEBSOCKET_STATE_OPEN)
+               soup_websocket_connection_close(client->ws_conn, 1000, NULL); /* 1000 for the normal closure */
+       else
+               g_object_unref(client->ws_conn);
+
+       LOG_DEBUG("client[%p, ws_conn:%p, id:%d] is closed\n", client, client->ws_conn, client->id);
+
+       client->ws_conn = NULL;
+       client->id = 0;
+}
+
+static void __websocket_closed_cb(SoupWebsocketConnection *ws_conn, gpointer user_data)
+{
+       webrtc_signaling_client_s *client = (webrtc_signaling_client_s *)user_data;
+
+       RET_IF(client == NULL, "client is NULL");
+       RET_IF(client->ws_conn == NULL, "ws_conn is NULL");
+       RET_IF(client->ws_conn != ws_conn, "invalid ws_conn");
+
+       __close_websocket(client);
+}
+
+static void __websocket_connected_cb(SoupSession *session, GAsyncResult *res, void *user_data)
+{
+       GError *error = NULL;
+       SoupWebsocketConnection *ws_conn;
+       webrtc_signaling_client_s *client = (webrtc_signaling_client_s *)user_data;
+
+       RET_IF(client == NULL, "conn is NULL");
+
+       ws_conn = soup_session_websocket_connect_finish(session, res, &error);
+       if (!ws_conn) {
+               LOG_ERROR("failed to soup_session_websocket_connect_finish(), error[%s]", error->message);
+               g_error_free(error);
+               return;
+       }
+
+       g_signal_connect(ws_conn, "closed", G_CALLBACK(__websocket_closed_cb), client);
+       g_signal_connect(ws_conn, "message", G_CALLBACK(__websocket_message_cb), client);
+
+       client->ws_conn = ws_conn;
+
+       LOG_DEBUG("client[%p, ws_conn:%p, id:%d]", client, client->ws_conn, client->id);
+}
+
+static SoupSession* __connect_websocket(const char *ip, int port, webrtc_signaling_client_s *client)
+{
+       SoupSession *session;
+       SoupMessage *message;
+       const char *http_aliases[] = {"ws", NULL};
+       gchar *url;
+
+       RET_VAL_IF(ip == NULL, NULL, "ip is NULL");
+       RET_VAL_IF(port <= 0, NULL, "invalid port(%d)", port);
+       RET_VAL_IF(client == NULL, NULL, "client is NULL");
+
+       session = soup_session_new_with_options(SOUP_SESSION_HTTP_ALIASES, http_aliases, NULL);
+
+       url = g_strdup_printf("ws://%s:%d", ip, port);
+
+       message = soup_message_new(SOUP_METHOD_GET, url);
+
+       LOG_DEBUG("connecting to signaling server[%s]...\n", url);
+
+       g_free(url);
+
+       soup_session_websocket_connect_async(session, message, NULL, NULL, NULL,
+               (GAsyncReadyCallback)__websocket_connected_cb, client);
+
+       return session;
+}
+
+int webrtc_signaling_connect(const char *server_ip, int port, webrtc_signaling_message_cb callback, void *user_data, webrtc_signaling_client_h *client)
+{
+       webrtc_signaling_client_s *_client;
+
+       RET_VAL_IF(server_ip == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "server_ip is NULL");
+       RET_VAL_IF(port <= 0, WEBRTC_ERROR_INVALID_PARAMETER, "invalid port(%d)", port);
+       RET_VAL_IF(callback == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "callback is NULL");
+       RET_VAL_IF(client == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "client is NULL");
+
+       _client = g_new0(webrtc_signaling_client_s, 1);
+
+       _client->message_cb.callback = callback;
+       _client->message_cb.user_data = user_data;
+
+       _client->session = __connect_websocket(server_ip, port, _client);
+       if (!_client->session) {
+               LOG_ERROR("failed_to __connect_websocket()");
+               g_free(_client);
+               return WEBRTC_ERROR_INVALID_OPERATION;
+       }
+
+       *client = _client;
+
+       LOG_DEBUG("client[%p, session:%p, callback:%p]", _client, _client->session, _client->message_cb.callback);
+
+       return WEBRTC_ERROR_NONE;
+}
+
+int webrtc_signaling_request_session(webrtc_signaling_client_h client, int peer_id)
+{
+       webrtc_signaling_client_s *_client = (webrtc_signaling_client_s *)client;
+       gchar *message;
+
+       RET_VAL_IF(_client == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "client is NULL");
+       RET_VAL_IF(peer_id <= 0, WEBRTC_ERROR_INVALID_PARAMETER, "invalid peer_id(%d)", peer_id);
+       RET_VAL_IF(_client->ws_conn == NULL, WEBRTC_ERROR_INVALID_OPERATION, "ws_conn is NULL");
+       RET_VAL_IF(soup_websocket_connection_get_state(_client->ws_conn) != SOUP_WEBSOCKET_STATE_OPEN,
+               WEBRTC_ERROR_INVALID_STATE, "websocket is not opened yet");
+       RET_VAL_IF(_client->id == 0, WEBRTC_ERROR_INVALID_STATE, "not ready, id is 0");
+
+       LOG_DEBUG("request session with %d", peer_id);
+
+       message = g_strdup_printf("REQUEST_SESSION %d", peer_id);
+
+       soup_websocket_connection_send_text(_client->ws_conn, message);
+
+       g_free(message);
+
+       return WEBRTC_ERROR_NONE;
+}
+
+int webrtc_signaling_send_message(webrtc_signaling_client_h client, const char *message)
+{
+       webrtc_signaling_client_s *_client = (webrtc_signaling_client_s *)client;
+
+       RET_VAL_IF(_client == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "client is NULL");
+       RET_VAL_IF(message == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "message is NULL");
+       RET_VAL_IF(_client->ws_conn == NULL, WEBRTC_ERROR_INVALID_OPERATION, "ws_conn is NULL");
+       RET_VAL_IF(soup_websocket_connection_get_state(_client->ws_conn) != SOUP_WEBSOCKET_STATE_OPEN,
+               WEBRTC_ERROR_INVALID_STATE, "websocket is not opened yet");
+       RET_VAL_IF(_client->id == 0, WEBRTC_ERROR_INVALID_STATE, "not ready, id is 0");
+
+       LOG_DEBUG("send message:\n%s", message);
+
+       soup_websocket_connection_send_text(_client->ws_conn, message);
+
+       return WEBRTC_ERROR_NONE;
+}
+
+int webrtc_signaling_disconnect(webrtc_signaling_client_h client)
+{
+       webrtc_signaling_client_s *_client = (webrtc_signaling_client_s *)client;
+
+       RET_VAL_IF(client == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "client is NULL");
+
+       LOG_DEBUG("client[%p, session:%p, callback:%p]", _client, _client->session, _client->message_cb.callback);
+
+       __close_websocket(_client);
+
+       g_object_unref(_client->session);
+       g_free(_client);
+
+       return WEBRTC_ERROR_NONE;
+}
+
+int webrtc_signaling_get_id(webrtc_signaling_client_h client, int *id)
+{
+       webrtc_signaling_client_s *_client = (webrtc_signaling_client_s *)client;
+
+       RET_VAL_IF(_client == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "client is NULL");
+       RET_VAL_IF(id == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "id is NULL");
+       RET_VAL_IF(_client->ws_conn == NULL, WEBRTC_ERROR_INVALID_OPERATION, "ws_conn is NULL");
+       RET_VAL_IF(soup_websocket_connection_get_state(_client->ws_conn) != SOUP_WEBSOCKET_STATE_OPEN,
+               WEBRTC_ERROR_INVALID_STATE, "websocket is not opened yet");
+       RET_VAL_IF(_client->id == 0, WEBRTC_ERROR_INVALID_STATE, "not ready, id is 0");
+
+       LOG_DEBUG("client[%p, id:%d]", _client, _client->id);
+
+       *id = _client->id;
+
+       return WEBRTC_ERROR_NONE;
+}
\ No newline at end of file