From: backto.kim Date: Thu, 6 Jan 2022 07:38:57 +0000 (+0900) Subject: Add new data channel buffered amount APIs X-Git-Tag: submit/tizen/20220118.012546~1 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=d9cf362451a2c1ebbe681dc740bcf8eb3843f865;p=platform%2Fcore%2Fapi%2Fwebrtc.git Add new data channel buffered amount APIs 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 --- diff --git a/include/webrtc.h b/include/webrtc.h index 573c035f..ff66f645 100644 --- a/include/webrtc.h +++ b/include/webrtc.h @@ -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); + /** * @} */ diff --git a/include/webrtc_private.h b/include/webrtc_private.h index b6f3e210..cc889388 100644 --- a/include/webrtc_private.h +++ b/include/webrtc_private.h @@ -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 { diff --git a/packaging/capi-media-webrtc.spec b/packaging/capi-media-webrtc.spec index 98901a36..6b71615f 100644 --- a/packaging/capi-media-webrtc.spec +++ b/packaging/capi-media-webrtc.spec @@ -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 diff --git a/src/webrtc.c b/src/webrtc.c index 436f9ee9..28d038fb 100644 --- a/src/webrtc.c +++ b/src/webrtc.c @@ -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; +} diff --git a/src/webrtc_data_channel.c b/src/webrtc_data_channel.c index 7812b134..9d3a9468 100644 --- a/src/webrtc_data_channel.c +++ b/src/webrtc_data_channel.c @@ -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; diff --git a/test/webrtc_test.c b/test/webrtc_test.c index 23984cfd..2bef9453 100644 --- a/test/webrtc_test.c +++ b/test/webrtc_test.c @@ -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();