Add new data channel buffered amount APIs 13/269013/13
authorbackto.kim <backto.kim@samsung.com>
Thu, 6 Jan 2022 07:38:57 +0000 (16:38 +0900)
committerbackto.kim <backto.kim@samsung.com>
Fri, 14 Jan 2022 02:18:20 +0000 (11:18 +0900)
Functions are added as below.
 - typedef void (*webrtc_data_channel_buffered_amount_low_cb)()
 - webrtc_data_channel_get_buffered_amount()
 - webrtc_data_channel_set_buffered_amount_low_cb()
 - webrtc_data_channel_get_buffered_amount_low_threshold()
 - webrtc_data_channel_unset_buffered_amount_low_cb()

[Version] 0.3.40
[Issue Type] API

Change-Id: I3279925a1508955eded709927639ca2249c20137

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 573c035f148dc25a95406e7147fcb3ec0e7dee8f..ff66f6455a3c077b4adf6bd3587bd47a56cc2a40 100644 (file)
@@ -564,6 +564,19 @@ typedef void (*webrtc_data_channel_error_cb)(webrtc_data_channel_h channel, webr
  */
 typedef void (*webrtc_data_channel_close_cb)(webrtc_data_channel_h channel, void *user_data);
 
+/**
+ * @brief Called when the number of bytes of data currently queued to be sent over the data channel falls below the threshold.
+ * @since_tizen 7.0
+ * @remarks The @a channel is the same object for which the callback was set.\n
+ *          The @a channel should not be released.
+ * @param[in] channel    WebRTC data channel handle
+ * @param[in] user_data  The user data passed from the callback registration function
+ * @see webrtc_create_data_channel()
+ * @see webrtc_destroy_data_channel()
+ * @see webrtc_data_channel_set_buffered_amount_low_cb()
+ * @see webrtc_data_channel_unset_buffered_amount_low_cb()
+ */
+typedef void (*webrtc_data_channel_buffered_amount_low_cb)(webrtc_data_channel_h channel, void *user_data);
 /**
  * @}
  */
@@ -2202,6 +2215,69 @@ int webrtc_data_channel_get_label(webrtc_data_channel_h channel, char **label);
  */
 int webrtc_get_data(webrtc_bytes_data_h bytes, const char **data, unsigned long *size);
 
+/**
+ * @brief Gets the number of bytes of data currently queued to be sent over the data channel.
+ * @since_tizen 7.0
+ * @param[in] channel             Data channel handle
+ * @param[out] buffered_amount    The number of bytes of 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_create_data_channel()
+ */
+int webrtc_data_channel_get_buffered_amount(webrtc_data_channel_h channel, unsigned int *buffered_amount);
+
+/**
+ * @brief Sets the threshold at which the buffered amount is considered low and callback function.
+ * @since_tizen 7.0
+ * @remarks The registered callback will be invoked in an internal thread of the webrtc.\n
+            Callback function will be invoked when the number of bytes currently queued falls below the @a threshold.
+ * @param[in] channel     Data channel handle
+ * @param[in] threshold   The threshold
+ * @param[in] callback    Callback function pointer
+ * @param[in] user_data   The user data to be passed to the callback function
+ * @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
+ * @post webrtc_data_channel_buffered_amount_low_cb() will be invoked.
+ * @see webrtc_data_channel_buffered_amount_low_cb()
+ * @see webrtc_data_channel_get_buffered_amount_low_threshold()
+ * @see webrtc_data_channel_unset_buffered_amount_low_cb()
+ */
+int webrtc_data_channel_set_buffered_amount_low_cb(webrtc_data_channel_h channel, unsigned int threshold, webrtc_data_channel_buffered_amount_low_cb callback, void *user_data);
+
+/**
+ * @brief Gets the threshold at which the buffered amount is considered low.
+ * @since_tizen 7.0
+ * @remarks The default value is 0.
+ * @param[in] channel     Data channel handle
+ * @param[out] threshold  The threshold
+ * @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_set_buffered_amount_low_cb()
+ */
+int webrtc_data_channel_get_buffered_amount_low_threshold(webrtc_data_channel_h channel, unsigned int *threshold);
+
+/**
+ * @brief Unsets the data channel buffered amount low callback function.
+ * @since_tizen 7.0
+ * @param[in] channel     Data channel 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_data_channel_set_buffered_amount_low_cb()
+ */
+int webrtc_data_channel_unset_buffered_amount_low_cb(webrtc_data_channel_h channel);
+
 /**
  * @}
  */
index b6f3e210f1bfd2c76b1558a41235f587e047acf6..cc8893882bff3830f2e761507a49de476ce2ad62 100644 (file)
@@ -547,6 +547,7 @@ typedef struct _webrtc_data_channel_s {
        webrtc_callbacks_s message_cb;
        webrtc_callbacks_s error_cb;
        webrtc_callbacks_s close_cb;
+       webrtc_callbacks_s buffered_amount_low_cb;
 } webrtc_data_channel_s;
 
 typedef struct _webrtc_bytes_data_s {
index 98901a362ab516f0b9f9653a3ce7086c7b90e81e..6b71615f5a1afb23ef62f3e8ff5f8a046c097030 100644 (file)
@@ -1,6 +1,6 @@
 Name:       capi-media-webrtc
 Summary:    A WebRTC library in Tizen Native API
-Version:    0.3.39
+Version:    0.3.40
 Release:    0
 Group:      Multimedia/API
 License:    Apache-2.0
index 436f9ee934df4cd88596c9504a5e831e4316516a..28d038fb65b30eaec3de9360f0b3f18838ed7b93 100644 (file)
@@ -1850,3 +1850,89 @@ int webrtc_get_data(webrtc_bytes_data_h bytes, const char **data, unsigned long
 
        return WEBRTC_ERROR_NONE;
 }
+
+int webrtc_data_channel_set_buffered_amount_low_cb(webrtc_data_channel_h channel, unsigned int threshold, webrtc_data_channel_buffered_amount_low_cb callback, void *user_data)
+{
+       g_autoptr(GMutexLocker) locker = NULL;
+       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(_channel->channel == NULL, WEBRTC_ERROR_INVALID_OPERATION, "data_channel is NULL");
+
+       locker = g_mutex_locker_new(&_channel->mutex);
+
+       g_object_set(_channel->channel, "buffered-amount-low-threshold", (guint64)threshold, NULL);
+
+       LOG_WARNING_IF_CALLBACK_EXISTS(_channel->buffered_amount_low_cb);
+
+       _channel->buffered_amount_low_cb.callback = callback;
+       _channel->buffered_amount_low_cb.user_data = user_data;
+
+       LOG_INFO("channel[%p] threshold[%u] callback[%p] user_data[%p]", _channel, threshold, callback, user_data);
+
+       return WEBRTC_ERROR_NONE;
+}
+
+int webrtc_data_channel_get_buffered_amount_low_threshold(webrtc_data_channel_h channel, unsigned int *threshold)
+{
+       g_autoptr(GMutexLocker) locker = NULL;
+       webrtc_data_channel_s *_channel = (webrtc_data_channel_s*)channel;
+       guint64 _threshold;
+
+       RET_VAL_IF(_channel == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "channel is NULL");
+       RET_VAL_IF(threshold == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "threshold is NULL");
+       RET_VAL_IF(_channel->channel == NULL, WEBRTC_ERROR_INVALID_OPERATION, "data_channel is NULL");
+
+       locker = g_mutex_locker_new(&_channel->mutex);
+
+       g_object_get(_channel->channel, "buffered-amount-low-threshold", &_threshold, NULL);
+
+       *threshold = (unsigned int)_threshold;
+
+       LOG_INFO("channel[%p] threshold[%u]", _channel, *threshold);
+
+       return WEBRTC_ERROR_NONE;
+}
+
+int webrtc_data_channel_get_buffered_amount(webrtc_data_channel_h channel, unsigned int *buffered_amount)
+{
+       g_autoptr(GMutexLocker) locker = NULL;
+       webrtc_data_channel_s *_channel = (webrtc_data_channel_s*)channel;
+       guint64 _buffered_amount;
+
+       RET_VAL_IF(_channel == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "channel is NULL");
+       RET_VAL_IF(buffered_amount == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "buffered_amount is NULL");
+       RET_VAL_IF(_channel->channel == NULL, WEBRTC_ERROR_INVALID_OPERATION, "data_channel is NULL");
+
+       locker = g_mutex_locker_new(&_channel->mutex);
+
+       g_object_get(_channel->channel, "buffered-amount", &_buffered_amount, NULL);
+
+       *buffered_amount = _buffered_amount;
+
+       LOG_INFO("channel[%p] buffered_amount[%u]", _channel, *buffered_amount);
+
+       return WEBRTC_ERROR_NONE;
+}
+
+int webrtc_data_channel_unset_buffered_amount_low_cb(webrtc_data_channel_h channel)
+{
+       g_autoptr(GMutexLocker) locker = NULL;
+       webrtc_data_channel_s *_channel = (webrtc_data_channel_s*)channel;
+
+       RET_VAL_IF(_channel == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "channel is NULL");
+
+       locker = g_mutex_locker_new(&_channel->mutex);
+
+       RET_VAL_IF(_channel->buffered_amount_low_cb.callback == NULL, WEBRTC_ERROR_INVALID_OPERATION, "callback was not set");
+
+       LOG_INFO("channel[%p] callback[%p] user_data[%p] is reset to NULL",
+               _channel, _channel->buffered_amount_low_cb.callback, _channel->buffered_amount_low_cb.user_data);
+
+       g_object_set(_channel->channel, "buffered-amount-low-threshold", 0, NULL);
+
+       _channel->buffered_amount_low_cb.callback = NULL;
+       _channel->buffered_amount_low_cb.user_data = NULL;
+
+       return WEBRTC_ERROR_NONE;
+}
index 7812b13402b1023ffdd3cdc2cb9f005818b16e91..9d3a9468b3567611f5ce13c595cb233b38fdbaf6 100644 (file)
@@ -119,6 +119,23 @@ static void __invoke_data_channel_cb(webrtc_s *webrtc, webrtc_data_channel_s *ch
        }
 }
 
+static void __data_channel_on_buffered_amount_low_cb(GObject *data_channel, gpointer user_data)
+{
+       webrtc_data_channel_s *channel = (webrtc_data_channel_s *)user_data;
+       guint64 threshold;
+
+       RET_IF(channel == NULL, "channel is NULL");
+
+       g_object_get(data_channel, "buffered-amount-low-threshold", &threshold, NULL);
+       LOG_DEBUG("channel[%p, %s] user_data[%p] threshold[%"G_GUINT64_FORMAT"]", channel, GST_OBJECT_NAME(data_channel), user_data, threshold);
+
+       if (channel->buffered_amount_low_cb.callback) {
+               LOG_DEBUG(">>> callback[%p] user_data[%p]", channel->buffered_amount_low_cb.callback, channel->buffered_amount_low_cb.user_data);
+               ((webrtc_data_channel_buffered_amount_low_cb)(channel->buffered_amount_low_cb.callback))((webrtc_data_channel_h)channel, channel->buffered_amount_low_cb.user_data);
+               LOG_DEBUG("<<< end of the callback");
+       }
+}
+
 void _webrtcbin_on_data_channel_cb(GstElement *webrtcbin, GObject *data_channel, gpointer user_data)
 {
        webrtc_s *webrtc = (webrtc_s *)user_data;
@@ -191,6 +208,7 @@ int _create_data_channel(webrtc_s *webrtc, const char *label, bundle *options, w
        _connect_and_append_signal(&_channel->signals, data_channel, "on-message-data", G_CALLBACK(__data_channel_on_message_data_cb), _channel);
        _connect_and_append_signal(&_channel->signals, data_channel, "on-error", G_CALLBACK(__data_channel_on_error_cb), _channel);
        _connect_and_append_signal(&_channel->signals, data_channel, "on-close", G_CALLBACK(__data_channel_on_close_cb), _channel);
+       _connect_and_append_signal(&_channel->signals, data_channel, "on-buffered-amount-low", G_CALLBACK(__data_channel_on_buffered_amount_low_cb), _channel);
 
        *channel = _channel;
 
index 23984cfdb2ca11a5883d5d94bf97734dd9571aaa..2bef9453e80aa98d07467617210ade38d28033cb 100644 (file)
@@ -86,6 +86,7 @@ enum {
        CURRENT_STATUS_DATA_CHANNEL_SEND_STRING,
        CURRENT_STATUS_DATA_CHANNEL_SEND_STRING_AS_BYTES,
        CURRENT_STATUS_DATA_CHANNEL_SEND_FILE,
+       CURRENT_STATUS_DATA_CHANNEL_SET_BUFFERED_AMOUNT_LOW_CB,
        CURRENT_STATUS_SET_STUN_SERVER,
        CURRENT_STATUS_ADD_TURN_SERVER,
        CURRENT_STATUS_SET_ICE_TRANSPORT_POLICY,
@@ -1168,6 +1169,7 @@ static void _webrtc_data_channel_send_file(int index, const char *file_path)
        ssize_t sum_size;
        char buffer[BUFFER_SIZE] = {0, };
        int fd;
+       unsigned int buffered_amount;
 
        for (i = 0; i < MAX_CHANNEL_LEN; i++) {
                if (g_conns[index].channels[i] == NULL)
@@ -1208,13 +1210,18 @@ static void _webrtc_data_channel_send_file(int index, const char *file_path)
                sum_size = 0;
                while((read_size = read(fd, buffer, BUFFER_SIZE)) > 0) {
                        sum_size += read_size;
-                       g_print("[%zd / %llu]bytes is read", sum_size, (unsigned long long)st.st_size);
+                       g_print("%s : [%zd / %llu]bytes is read.", file_path, sum_size, (unsigned long long)st.st_size);
 
                        ret = webrtc_data_channel_send_bytes(g_conns[index].channels[i], buffer, (unsigned int)read_size);
                        if (ret != WEBRTC_ERROR_NONE)
                                g_print("failed to webrtc_data_channel_send_bytes(), file_path[%s], size[%zd]\n", file_path, read_size);
-                       else
-                               g_print("webrtc_data_channel_send_bytes() success, file_path[%s], size[%zd]\n", file_path, read_size);
+
+                       ret = webrtc_data_channel_get_buffered_amount(g_conns[index].channels[i], &buffered_amount);
+                       if (ret != WEBRTC_ERROR_NONE)
+                               g_print("failed to webrtc_data_channel_get_buffered_amount()\n");
+                       if (buffered_amount > 0)
+                               g_print(" buffered_amount [%u]", buffered_amount);
+                       g_print("\n");
                }
 
                close(fd);
@@ -1650,6 +1657,17 @@ static void __data_channel_close_cb(webrtc_data_channel_h channel, void *user_da
                free(label);
 }
 
+static void __data_channel_buffered_amount_low_cb(webrtc_data_channel_h channel, void *user_data)
+{
+       connection_s *conn = (connection_s*)user_data;
+       char *label = __get_channel_label(channel);
+
+       g_print("__data_channel_buffered_amount_low_cb() is called, channel[%p], conn[%p] label[%s]\n", channel, conn, label);
+
+       if (label)
+               free(label);
+}
+
 static void __data_channel_cb(webrtc_h webrtc, webrtc_data_channel_h channel, void *user_data)
 {
        int i;
@@ -1699,6 +1717,76 @@ static void _webrtc_unset_data_channel_cb(int index)
        g_print("webrtc_unset_data_channel_cb() success\n");
 }
 
+static void _webrtc_data_channel_set_buffered_amount_low_cb(int index, unsigned int threshold)
+{
+       int ret = WEBRTC_ERROR_NONE;
+       int i;
+
+       for (i = 0; i < MAX_CHANNEL_LEN; i++) {
+               if (g_conns[index].channels[i] == NULL)
+                       continue;
+
+               ret = webrtc_data_channel_set_buffered_amount_low_cb(g_conns[index].channels[i], threshold, __data_channel_buffered_amount_low_cb, &g_conns[index]);
+               if (ret != WEBRTC_ERROR_NONE)
+                       g_print("failed to webrtc_data_channel_set_buffered_amount_low_cb(), index[%d]\n", i);
+               else
+                       g_print("webrtc_data_channel_set_buffered_amount_low_cb() success, index[%d] threshold[%u]\n", i, threshold);
+       }
+}
+
+static void _webrtc_data_channel_get_buffered_amount_low_threshold(int index)
+{
+       int ret = WEBRTC_ERROR_NONE;
+       int i;
+       unsigned int threshold;
+
+       for (i = 0; i < MAX_CHANNEL_LEN; i++) {
+               if (g_conns[index].channels[i] == NULL)
+                       continue;
+
+               ret = webrtc_data_channel_get_buffered_amount_low_threshold(g_conns[index].channels[i], &threshold);
+               if (ret != WEBRTC_ERROR_NONE)
+                       g_print("failed to webrtc_data_channel_get_buffered_amount_low_threshold(), index[%d]\n", i);
+               else
+                       g_print("webrtc_data_channel_get_buffered_amount_low_threshold() success, index[%d] threshold[%u]\n", i, threshold);
+       }
+}
+
+static void _webrtc_data_channel_unset_buffered_amount_low_cb(int index)
+{
+       int ret = WEBRTC_ERROR_NONE;
+       int i;
+
+       for (i = 0; i < MAX_CHANNEL_LEN; i++) {
+               if (g_conns[index].channels[i] == NULL)
+                       continue;
+
+               ret = webrtc_data_channel_unset_buffered_amount_low_cb(g_conns[index].channels[i]);
+               if (ret != WEBRTC_ERROR_NONE)
+                       g_print("failed to webrtc_data_channel_unset_buffered_amount_low_cb(), index[%d]\n", i);
+               else
+                       g_print("webrtc_data_channel_unset_buffered_amount_low_cb() success, index[%d]\n", i);
+       }
+}
+
+static void _webrtc_data_channel_get_buffered_amount(int index)
+{
+       int ret = WEBRTC_ERROR_NONE;
+       int i;
+       unsigned int buffered_amount;
+
+       for (i = 0; i < MAX_CHANNEL_LEN; i++) {
+               if (g_conns[index].channels[i] == NULL)
+                       continue;
+
+               ret = webrtc_data_channel_get_buffered_amount(g_conns[index].channels[i], &buffered_amount);
+               if (ret != WEBRTC_ERROR_NONE)
+                       g_print("failed to webrtc_data_channel_get_buffered_amount(), index[%d]\n", i);
+               else
+                       g_print("webrtc_data_channel_get_buffered_amount() success, index[%d] buffered_amount[%u]\n", i, buffered_amount);
+       }
+}
+
 static void __error_cb(webrtc_h webrtc, webrtc_error_e error, webrtc_state_e state, void *user_data)
 {
        g_print("__error_cb() is invoked, webrtc[%p], error[0x%x], state[%d], user_data[%p]\n",
@@ -4123,6 +4211,9 @@ void _interpret_main_menu(char *cmd)
                } else if (strncmp(cmd, "zf", 2) == 0) {
                        g_menu_state = CURRENT_STATUS_DATA_CHANNEL_SEND_FILE;
 
+               } else if (strncmp(cmd, "ba", 2) == 0) {
+                       _webrtc_data_channel_get_buffered_amount(0);
+
                } else if (strncmp(cmd, "mu", 2) == 0) {
                        g_menu_state = CURRENT_STATUS_MUTE_MEDIA_SOURCE;
 
@@ -4312,6 +4403,15 @@ void _interpret_main_menu(char *cmd)
                } else if (strncmp(cmd, "gfl", 3) == 0) {
                        g_menu_state = CURRENT_STATUS_MEDIA_SOURCE_GET_FILE_LOOPING;
 
+               } else if (strncmp(cmd, "sbc", 3) == 0) {
+                       g_menu_state = CURRENT_STATUS_DATA_CHANNEL_SET_BUFFERED_AMOUNT_LOW_CB;
+
+               } else if (strncmp(cmd, "gbt", 3) == 0) {
+                       _webrtc_data_channel_get_buffered_amount_low_threshold(0);
+
+               } else if (strncmp(cmd, "ubc", 3) == 0) {
+                       _webrtc_data_channel_unset_buffered_amount_low_cb(0);
+
                } else {
                        g_print("unknown menu \n");
                }
@@ -4416,6 +4516,10 @@ void display_sub_basic()
        g_print("zs. Send string via data channel\n");
        g_print("zb. Send string as bytes data via data channel\t");
        g_print("zf. Send file via data channel\n");
+       g_print("ba. Get buffered amount\n");
+       g_print("sbc. Set buffered amount low callback\n");
+       g_print("gbt. Get buffered amount low threshold\n");
+       g_print("ubc. Unset buffered amount low callback\n");
        g_print("------------------------------------- Callbacks -----------------------------------------\n");
        g_print("sac. Set all callbacks below (except for the encoded frame callbacks)\n");
        g_print("san. Set all the negotiation state change callbacks\t");
@@ -4588,7 +4692,11 @@ static void displaymenu()
        } else if (g_menu_state == CURRENT_STATUS_DATA_CHANNEL_SEND_FILE) {
                g_print("*** input file path to send.\n");
 
-       } else if (g_menu_state == CURRENT_STATUS_MUTE_MEDIA_SOURCE) {
+       } else if (g_menu_state == CURRENT_STATUS_DATA_CHANNEL_SET_BUFFERED_AMOUNT_LOW_CB) {
+               g_print("*** input data channel buffered amount low threshold.\n");
+
+       }
+       else if (g_menu_state == CURRENT_STATUS_MUTE_MEDIA_SOURCE) {
                if (g_cnt == 0)
                        g_print("*** input source id.\n");
                else if (g_cnt == 1)
@@ -4962,6 +5070,11 @@ static void interpret(char *cmd)
                reset_menu_state();
                break;
        }
+       case CURRENT_STATUS_DATA_CHANNEL_SET_BUFFERED_AMOUNT_LOW_CB: {
+               _webrtc_data_channel_set_buffered_amount_low_cb(0, (unsigned int)atoi(cmd));
+               reset_menu_state();
+               break;
+       }
        case CURRENT_STATUS_SET_STUN_SERVER: {
                _webrtc_set_stun_server(0, cmd);
                reset_menu_state();