Add API to send byte data via data channel 05/246205/15
authorSangchul Lee <sc11.lee@samsung.com>
Tue, 27 Oct 2020 02:13:45 +0000 (11:13 +0900)
committerSangchul Lee <sc11.lee@samsung.com>
Tue, 17 Nov 2020 10:24:45 +0000 (19:24 +0900)
New handle is added to be used inside of the data channel message callback
 - webrtc_bytes_data_h

Functions are added as below.
 - webrtc_data_channel_send_bytes()
 - webrtc_get_data()

Test cases for these functions are added to webrtc_test.

Some descriptions are fixed correctly.

[Version] 0.1.54
[Issue Type] API

Change-Id: I9e6937e7cf0f9ce5c5bd28419156b8e4382d37c9
Signed-off-by: Sangchul Lee <sc11.lee@samsung.com>
include/webrtc.h
include/webrtc_private.h
packaging/capi-media-webrtc.spec
src/webrtc.c
src/webrtc_data_channel.c
test/webrtc_test.c

index 611dfe5bf78ac7ff2beff61ab67d93e024ef97f6..a528383a5febe18aa29e5fbe53783277bff9faa8 100644 (file)
@@ -49,6 +49,12 @@ typedef void *webrtc_h;
  */
 typedef void *webrtc_data_channel_h;
 
+/**
+ * @brief WebRTC bytes data handle type.
+ * @since_tizen 6.5
+ */
+typedef void *webrtc_bytes_data_h;
+
 /**
  * @brief Enumeration for WebRTC error.
  * @since_tizen 6.5
@@ -187,8 +193,9 @@ typedef void (*webrtc_track_added_cb)(webrtc_h webrtc, webrtc_media_type_e type,
 /**
  * @brief Called when the data channel is created to the connection by the remote peer.
  * @since_tizen 6.5
- * @remarks The @a webrtc is the same object for which the callback was set.\nThe @a webrtc should not be released.
- * @remarks The @a channel should not be released.
+ * @remarks The @a webrtc is the same object for which the callback was set.\nThe @a webrtc should not be released.\n
+ *          The @a channel should not be released.
+ * @param[in] webrtc     WebRTC handle
  * @param[in] channel    WebRTC data channel handle
  * @param[in] user_data  The user data passed from the callback registration function
  * @see webrtc_data_channel_set_open_cb()
@@ -218,15 +225,20 @@ typedef void (*webrtc_data_channel_open_cb)(webrtc_data_channel_h channel, void
 /**
  * @brief Called when a message is received from other peer via the data channel.
  * @since_tizen 6.5
- * @remarks The @a channel is the same object for which the callback was set.\nThe @a channel should not be released.
+ * @remarks The @a channel is the same object for which the callback was set.\nThe @a channel should not be released.\n
+ *          When @a type is #WEBRTC_DATA_CHANNEL_TYPE_STRING, @a message should be casted to char pointer.\n
+ *          When @a type is #WEBRTC_DATA_CHANNEL_TYPE_BYTES, @a message should be casted to #webrtc_bytes_data_h.\n
+ *          In this case, webrtc_get_data() can be used to get the data and its size inside of this callback.
+ *          The @a message should not be released.
  * @param[in] channel    WebRTC data channel handle
  * @param[in] type       The data type
- * @param[in] message    The messsage from the remote peer
+ * @param[in] message    The message from the remote peer
  * @param[in] user_data  The user data passed from the callback registration function
  * @see webrtc_data_channel_create()
  * @see webrtc_data_channel_destroy()
  * @see webrtc_data_channel_set_message_cb()
  * @see webrtc_data_channel_unset_message_cb()
+ * @see webrtc_get_data()
  */
 typedef void (*webrtc_data_channel_message_cb)(webrtc_data_channel_h channel, webrtc_data_channel_type_e type, void *message, void *user_data);
 
@@ -851,9 +863,45 @@ int webrtc_data_channel_unset_close_cb(webrtc_data_channel_h channel);
  * @retval #WEBRTC_ERROR_INVALID_STATE Invalid state
  * @pre @a channel should be opened before calling this function.
  * @see webrtc_data_channel_open_cb()
+ * @see webrtc_data_channel_send_bytes()
  */
 int webrtc_data_channel_send_string(webrtc_data_channel_h channel, const char *string);
 
+/**
+ * @brief Sends byte data across the data channel to the remote peer.
+ * @since_tizen 6.5
+ * @param[in] channel     Data channel handle
+ * @param[in] data        Byte data to send
+ * @param[in] size        Size of the data
+ * @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 @a channel should be opened before calling this function.
+ * @see webrtc_data_channel_open_cb()
+ * @see webrtc_data_channel_send_string()
+ */
+int webrtc_data_channel_send_bytes(webrtc_data_channel_h channel, const char *data, unsigned int size);
+
+/**
+ * @brief Gets data pointer and its size.
+ * @since_tizen 6.5
+ * @remarks This function must be called inside of the webrtc_data_channel_message_cb().\n
+ *          @a bytes and @a data are managed by the platform and will be released when after the webrtc_data_channel_message_cb() is ended.
+ * @param[in] bytes       Bytes data handle
+ * @param[out] data       Data pointer
+ * @param[out] size       Size of the data
+ * @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_data_channel_message_cb()
+ */
+int webrtc_get_data(webrtc_bytes_data_h bytes, const char **data, unsigned int *size);
+
 /**
  * @}
  */
index 2ad2cd5e420b640f91c91ca458f4d5e65b2af698..de32b4ecf3c8853eb33c61040398e1b8ca73c4f2 100644 (file)
@@ -249,6 +249,11 @@ typedef struct _webrtc_data_channel_s {
        webrtc_callbacks_s close_cb;
 } webrtc_data_channel_s;
 
+typedef struct _webrtc_bytes_data_s {
+       void *data;
+       unsigned int size;
+} webrtc_bytes_data_s;
+
 typedef struct _element_info_s {
        const gchar *klass_name;
        GstCaps *src_caps;
@@ -298,6 +303,7 @@ void _destroy_data_channels(webrtc_s *webrtc);
 int _create_data_channel(webrtc_s *webrtc, const char *label, webrtc_data_channel_s **channel);
 int _destroy_data_channel(webrtc_data_channel_s *channel);
 int _data_channel_send_string(webrtc_data_channel_s *channel, const char *string);
+int _data_channel_send_bytes(webrtc_data_channel_s *channel, const char *data, unsigned int size);
 
 #ifdef __cplusplus
 }
index 0b0af48acb8c4837cac141fbff96beafdceaa485..f6a9b293a4ca289f2c42760b8d7f77e3a5c559a1 100644 (file)
@@ -1,6 +1,6 @@
 Name:       capi-media-webrtc
 Summary:    A WebRTC library in Tizen Native API
-Version:    0.1.53
+Version:    0.1.54
 Release:    0
 Group:      Multimedia/API
 License:    Apache-2.0
index 7af3d784f73ca4f883f5d30469be16375beee4bd..668eadc07fec28ae692a8c1f0d2fa08ba44d2ae1 100644 (file)
@@ -802,8 +802,8 @@ int webrtc_data_channel_unset_close_cb(webrtc_data_channel_h channel)
 
 int webrtc_data_channel_send_string(webrtc_data_channel_h channel, const char *string)
 {
-       webrtc_data_channel_s *_channel = (webrtc_data_channel_s*)channel;
        int ret = WEBRTC_ERROR_NONE;
+       webrtc_data_channel_s *_channel = (webrtc_data_channel_s*)channel;
 
        RET_VAL_IF(_channel == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "channel is NULL");
        RET_VAL_IF(string == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "string is NULL");
@@ -816,4 +816,39 @@ int webrtc_data_channel_send_string(webrtc_data_channel_h channel, const char *s
        g_mutex_unlock(&_channel->mutex);
 
        return ret;
+}
+
+int webrtc_data_channel_send_bytes(webrtc_data_channel_h channel, const char *data, unsigned int size)
+{
+       int ret = WEBRTC_ERROR_NONE;
+       webrtc_data_channel_s *_channel = (webrtc_data_channel_s*)channel;
+
+       RET_VAL_IF(_channel == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "channel is NULL");
+       RET_VAL_IF(data == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "data is NULL");
+       RET_VAL_IF(size == 0, WEBRTC_ERROR_INVALID_PARAMETER, "size is 0");
+       RET_VAL_IF(_channel->channel == NULL, WEBRTC_ERROR_INVALID_OPERATION, "data_channel is NULL");
+
+       g_mutex_lock(&_channel->mutex);
+
+       ret = _data_channel_send_bytes(channel, data, size);
+
+       g_mutex_unlock(&_channel->mutex);
+
+       return ret;
+}
+
+int webrtc_get_data(webrtc_bytes_data_h bytes, const char **data, unsigned int *size)
+{
+       webrtc_bytes_data_s *_bytes = (webrtc_bytes_data_s*)bytes;
+
+       RET_VAL_IF(bytes == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "bytes is NULL");
+       RET_VAL_IF(data == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "data is NULL");
+       RET_VAL_IF(size == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "size is NULL");
+
+       *data = (const char*)_bytes->data;
+       *size = _bytes->size;
+
+       LOG_INFO("data[%p] size[%u]", *data, *size);
+
+       return WEBRTC_ERROR_NONE;
 }
\ No newline at end of file
index be787df6191d877e077b1f547b37694cb5db8176..56cb9ede908ca896430e66f1242897ee7e4fe97f 100644 (file)
@@ -47,17 +47,20 @@ static void __data_channel_on_message_string_cb(GObject *data_channel, gchar *st
        }
 }
 
-static void __data_channel_on_message_data_cb(GObject *data_channel, GBytes *data, gpointer user_data)
+static void __data_channel_on_message_data_cb(GObject *data_channel, GBytes *bytes, gpointer user_data)
 {
        webrtc_data_channel_s *channel = (webrtc_data_channel_s *)user_data;
 
        RET_IF(channel == NULL, "channel is NULL");
 
-       LOG_DEBUG("data_channel[%s] data[%p, size:%u] user_data[%p]", GST_OBJECT_NAME(data_channel), data, g_bytes_get_size(data), user_data);
+       LOG_DEBUG("data_channel[%s] bytes[%p, size:%u] user_data[%p]", GST_OBJECT_NAME(data_channel), bytes, g_bytes_get_size(bytes), user_data);
 
        if (channel->message_cb.callback) {
+               webrtc_bytes_data_s data = { 0, };
+               data.data = (void*)g_bytes_get_data(bytes, &data.size);
+
                LOG_DEBUG(">>> callback[%p] user_data[%p]", channel->message_cb.callback, channel->message_cb.user_data);
-               ((webrtc_data_channel_message_cb)(channel->message_cb.callback))((webrtc_data_channel_h)channel, WEBRTC_DATA_CHANNEL_TYPE_BYTES, data, channel->message_cb.user_data);
+               ((webrtc_data_channel_message_cb)(channel->message_cb.callback))((webrtc_data_channel_h)channel, WEBRTC_DATA_CHANNEL_TYPE_BYTES, &data, channel->message_cb.user_data);
                LOG_DEBUG("<<< end of the callback");
        }
 }
@@ -255,3 +258,28 @@ int _data_channel_send_string(webrtc_data_channel_s *channel, const char *string
 
        return WEBRTC_ERROR_NONE;
 }
+
+int _data_channel_send_bytes(webrtc_data_channel_s *channel, const char *data, unsigned int size)
+{
+       GstWebRTCDataChannelState state;
+       GBytes *bytes;
+
+       RET_VAL_IF(channel == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "channel is NULL");
+       RET_VAL_IF(data == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "data is NULL");
+       RET_VAL_IF(size == 0, WEBRTC_ERROR_INVALID_PARAMETER, "size is 0");
+       RET_VAL_IF(channel->channel == NULL, WEBRTC_ERROR_INVALID_OPERATION, "data_channel is NULL");
+
+       g_object_get(channel->channel, "ready-state", &state, NULL);
+
+       RET_VAL_IF(state != GST_WEBRTC_DATA_CHANNEL_STATE_OPEN, WEBRTC_ERROR_INVALID_STATE, "channel is not opened");
+
+       bytes = g_bytes_new((gconstpointer)data, (gsize)size);
+
+       g_signal_emit_by_name(channel->channel, "send-data", bytes);
+
+       LOG_INFO("data_channel[%s] >>>>> [%p, size:%u]", GST_OBJECT_NAME(channel->channel), data, size);
+
+       g_bytes_unref(bytes);
+
+       return WEBRTC_ERROR_NONE;
+}
\ No newline at end of file
index 0b32f3c7bc43ab9698fa0743d00d4b4ab29166b2..7f2cffce5252cd67df55ea24b49d4b0f5c6453ea 100644 (file)
@@ -41,6 +41,7 @@ enum {
        CURRENT_STATUS_GET_TRANSCEIVER_DIRECTION,
        CURRENT_STATUS_SET_TRANSCEIVER_DIRECTION,
        CURRENT_STATUS_DATA_CHANNEL_SEND_STRING,
+       CURRENT_STATUS_DATA_CHANNEL_SEND_BYTES,
        CURRENT_STATUS_SET_STUN_SERVER,
        CURRENT_STATUS_SET_LOCAL_DESCRIPTION,
        CURRENT_STATUS_SET_REMOTE_DESCRIPTION,
@@ -398,16 +399,22 @@ static void _webrtc_data_channel_send_string(const char *string)
                else
                        g_print("webrtc_data_channel_send_string() success, string[%s]\n", string);
        }
+}
+
+static void _webrtc_data_channel_send_bytes(const char *string)
+{
+       int ret = WEBRTC_ERROR_NONE;
+       int i;
 
        for (i = 0; i < MAX_CHANNEL_LEN; i++) {
-               if (g_recv_channels[i] == NULL)
+               if (g_channels[i] == NULL)
                        continue;
-               g_print("received data_channel[%p], index[%d]: ", g_recv_channels[i], i);
-               ret = webrtc_data_channel_send_string(g_recv_channels[i], string);
+               g_print("data_channel[%p], index[%d]: ", g_channels[i], i);
+               ret = webrtc_data_channel_send_bytes(g_channels[i], (void*)string, strlen(string));
                if (ret != WEBRTC_ERROR_NONE)
-                       g_print("failed to webrtc_data_channel_send_string(), string[%s]\n", string);
+                       g_print("failed to webrtc_data_channel_send_bytes(), string[%s]\n", string);
                else
-                       g_print("webrtc_data_channel_send_string() success, string[%s]\n", string);
+                       g_print("webrtc_data_channel_send_bytes() success, string[%s]\n", string);
        }
 }
 
@@ -437,10 +444,19 @@ static void __data_channel_open_cb(webrtc_data_channel_h channel, void *user_dat
 static void __data_channel_message_cb(webrtc_data_channel_h channel, webrtc_data_channel_type_e type, void *message, void *user_data)
 {
        g_print("__data_channel_message_cb() is called, channel[%p], type[%d], ", channel, type);
-       if (type == WEBRTC_DATA_CHANNEL_TYPE_STRING)
+       if (type == WEBRTC_DATA_CHANNEL_TYPE_STRING) {
                g_print("string message[%s]\n", (char *)message);
-       else if (type == WEBRTC_DATA_CHANNEL_TYPE_BYTES)
-               g_print("bytes message[%p, size:%u]\n", message, g_bytes_get_size(message));
+       } else if (type == WEBRTC_DATA_CHANNEL_TYPE_BYTES) {
+               webrtc_bytes_data_h *data = message;
+               const char *data_p;
+               unsigned int size;
+               int i = 0;
+               webrtc_get_data(data, &data_p, &size);
+               g_print("bytes message[%p, size:%u]\n", data_p, size);
+               for (i = 0; i < size; i++)
+                       g_print("%c", data_p[i]);
+               g_print("\n");
+       }
 }
 
 static void __data_channel_error_cb(webrtc_data_channel_h channel, webrtc_error_e error, void *user_data)
@@ -726,7 +742,6 @@ static void _webrtc_create_data_channel(void)
        } else {
                g_print("webrtc_create_data_channel() success, channel[%p], index[%d]\n", g_channels[g_channel_index], g_channel_index);
                webrtc_data_channel_set_open_cb(g_channels[g_channel_index], __data_channel_open_cb, g_webrtc);
-               webrtc_data_channel_set_message_cb(g_channels[g_channel_index], __data_channel_message_cb, g_webrtc);
                webrtc_data_channel_set_error_cb(g_channels[g_channel_index], __data_channel_error_cb, g_webrtc);
                webrtc_data_channel_set_close_cb(g_channels[g_channel_index], __data_channel_close_cb, g_webrtc);
                g_channel_index++;
@@ -1041,6 +1056,9 @@ void _interpret_main_menu(char *cmd)
                } else if (strncmp(cmd, "zs", 2) == 0) {
                        g_menu_state = CURRENT_STATUS_DATA_CHANNEL_SEND_STRING;
 
+               } else if (strncmp(cmd, "zb", 2) == 0) {
+                       g_menu_state = CURRENT_STATUS_DATA_CHANNEL_SEND_BYTES;
+
                } else if (strncmp(cmd, "se", 2) == 0) {
                        _webrtc_set_error_cb();
 
@@ -1168,7 +1186,8 @@ void display_sub_basic()
        g_print("td. Set transceiver direction\n");
        g_print("cd. Create data channel\t");
        g_print("dd. Destroy data channel\n");
-       g_print("zs. Send string via data channel\n");
+       g_print("zs. Send string via data channel\t");
+       g_print("zb. Send bytes data via data channel\n");
        g_print("------------------------------------- Callbacks -----------------------------------------\n");
        g_print("se. Set error callback\t");
        g_print("ue. Unset error callback\n");
@@ -1228,6 +1247,9 @@ static void displaymenu()
        } else if (g_menu_state == CURRENT_STATUS_DATA_CHANNEL_SEND_STRING) {
                g_print("*** input string to send.\n");
 
+       } else if (g_menu_state == CURRENT_STATUS_DATA_CHANNEL_SEND_BYTES) {
+               g_print("*** input string to send.(it will be converted to bytes data)\n");
+
        } else if (g_menu_state == CURRENT_STATUS_SET_STUN_SERVER) {
                g_print("*** input STUN server address.\n");
 
@@ -1244,7 +1266,7 @@ static void displaymenu()
                g_print("*** input remote peer id.\n");
 
        } else if (g_menu_state == CURRENT_STATUS_SEND_LOCAL_DESCRIPTION) {
-               g_print("*** input type of local description to send to the sever.(1:offer, 2:answer)\n");
+               g_print("*** input type of local description to send to the server.(1:offer, 2:answer)\n");
 
        } else {
                g_print("*** unknown status.\n");
@@ -1341,6 +1363,11 @@ static void interpret(char *cmd)
                reset_menu_state();
                break;
        }
+       case CURRENT_STATUS_DATA_CHANNEL_SEND_BYTES: {
+               _webrtc_data_channel_send_bytes(cmd);
+               reset_menu_state();
+               break;
+       }
        case CURRENT_STATUS_SET_STUN_SERVER: {
                _webrtc_set_stun_server(cmd);
                reset_menu_state();