From: Sangchul Lee Date: Tue, 27 Oct 2020 02:13:45 +0000 (+0900) Subject: Add API to send byte data via data channel X-Git-Tag: submit/tizen/20210729.023123~188 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=3969974e1074ec25f375a81ab1337f86b028ccc7;p=platform%2Fcore%2Fapi%2Fwebrtc.git Add API to send byte data via data channel 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 --- diff --git a/include/webrtc.h b/include/webrtc.h index 611dfe5b..a528383a 100644 --- a/include/webrtc.h +++ b/include/webrtc.h @@ -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); + /** * @} */ diff --git a/include/webrtc_private.h b/include/webrtc_private.h index 2ad2cd5e..de32b4ec 100644 --- a/include/webrtc_private.h +++ b/include/webrtc_private.h @@ -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 } diff --git a/packaging/capi-media-webrtc.spec b/packaging/capi-media-webrtc.spec index 0b0af48a..f6a9b293 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.1.53 +Version: 0.1.54 Release: 0 Group: Multimedia/API License: Apache-2.0 diff --git a/src/webrtc.c b/src/webrtc.c index 7af3d784..668eadc0 100644 --- a/src/webrtc.c +++ b/src/webrtc.c @@ -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 diff --git a/src/webrtc_data_channel.c b/src/webrtc_data_channel.c index be787df6..56cb9ede 100644 --- a/src/webrtc_data_channel.c +++ b/src/webrtc_data_channel.c @@ -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 diff --git a/test/webrtc_test.c b/test/webrtc_test.c index 0b32f3c7..7f2cffce 100644 --- a/test/webrtc_test.c +++ b/test/webrtc_test.c @@ -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();