*/
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.
*/
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);
+
/**
* @}
*/
--- /dev/null
+/*
+ * 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