typedef void (*media_streamer_interrupted_cb)(media_streamer_interrupted_code_e code, void *user_data);
/**
+ * @brief Called when the media streamer node is ready for decoded data.
+ * @since_tizen 6.0
+ * @param[in] webrtc Media streamer node handle
+ * @param[in] src_pad_name The source pad name that can give decoded data to another one
+ * @param[in] media_type The media type of the data from the given source pad such as 'video/x-raw', 'audio/x-raw', and so on
+ * @param[in] user_data The user data passed from the callback registration function
+ * @see media_streamer_node_set_decoded_ready_cb()
+ * @see media_streamer_node_link()
+ * @see media_streamer_node_unset_decoded_ready_cb()
+ */
+typedef void (*media_streamer_node_decoded_ready_cb)(media_streamer_node_h node, const char *src_pad_name, const char *media_type, void *user_data);
+
+/**
* @brief Called when the media streamer WebRTC node needs to send the message to the remote peer of WebRTC connection.
* @since_tizen 6.0
* @remarks Two types will be delivered with @ message which is JSON string.
const char *param_name, char **param_value);
/**
+ * @brief Sets a callback function to be invoked when a source pad of @ node is ready to give decoded data.
+ * @remarks The available type of @a node for this function is #MEDIA_STREAMER_NODE_TYPE_WEBRTC.
+ * @since_tizen 6.0
+ * @param[in] node Media streamer node handle
+ * @param[in] callback The decoded ready callback function to register
+ * @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 #MEDIA_STREAMER_ERROR_NONE Successful
+ * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation
+ * @pre Create a media streamer node handle by calling media_streamer_node_create().
+ * @post media_streamer_node_decoded_ready_cb() will be invoked.
+ * @see media_streamer_node_unset_decoded_ready_cb()
+ * @see media_streamer_node_decoded_ready_cb()
+ */
+int media_streamer_node_set_decoded_ready_cb(media_streamer_node_h node, media_streamer_node_decoded_ready_cb callback, void *user_data);
+
+/**
+ * @brief Unsets the decoded ready callback function.
+ * @since_tizen 6.0
+ * @param[in] node Media streamer node handle
+ * @return @c 0 on success,
+ * otherwise a negative error value
+ * @retval #MEDIA_STREAMER_ERROR_NONE Successful
+ * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter
+ * @see media_streamer_node_set_decoded_ready_cb()
+ */
+int media_streamer_node_unset_decoded_ready_cb(media_streamer_node_h node);
+
+/**
* @brief Sets a callback function to be invoked when WebRTC node needs to send the message to the remote peer of WebRTC connection.
* @details This function can be called only for #MEDIA_STREAMER_NODE_TYPE_WEBRTC type.
* @since_tizen 6.0
} media_streamer_sink_callbacks_s;
/**
+ * @brief Media Streamer webrtc node callbacks structure.
+ */
+typedef struct {
+ media_streamer_callback_s message_cb;
+ media_streamer_callback_s decoded_ready_cb;
+} media_streamer_webrtc_callbacks_s;
+
+/**
* @brief Media Streamer param type handle.
*/
typedef struct {
mm_resource_manager_res_h resource;
device_policy_manager_h dpm_handle;
int policy_changed_cb_id;
-
- media_streamer_callback_s user_cb;
} media_streamer_node_s;
/**
return MEDIA_STREAMER_ERROR_NONE;
}
+int media_streamer_node_set_decoded_ready_cb(media_streamer_node_h node, media_streamer_node_decoded_ready_cb callback, void *user_data)
+{
+ media_streamer_node_s *ms_node = (media_streamer_node_s *) node;
+
+ ms_debug_fenter();
+
+ ms_retvm_if(ms_node == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "node is NULL");
+ ms_retvm_if(callback == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "callback is NULL");
+
+ if (ms_node->type == MEDIA_STREAMER_NODE_TYPE_WEBRTC) {
+ media_streamer_webrtc_callbacks_s **_callbacks = (media_streamer_webrtc_callbacks_s **)&(ms_node->callbacks_structure);
+
+ if (!*_callbacks) {
+ *_callbacks = (media_streamer_webrtc_callbacks_s *) calloc(1, sizeof(media_streamer_webrtc_callbacks_s));
+ ms_retvm_if(*_callbacks == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Error allocation memory");
+ }
+ (*_callbacks)->decoded_ready_cb.callback = callback;
+ (*_callbacks)->decoded_ready_cb.user_data = user_data;
+ } else {
+ /* It can be accepted other types in the future. */
+ ms_error("Not supported node type[%d]", ms_node->type);
+ return MEDIA_STREAMER_ERROR_INVALID_PARAMETER;
+ }
+
+ ms_debug_fleave();
+
+ return MEDIA_STREAMER_ERROR_NONE;
+}
+
+int media_streamer_node_unset_decoded_ready_cb(media_streamer_node_h node)
+{
+ media_streamer_node_s *ms_node = (media_streamer_node_s *) node;
+
+ ms_debug_fenter();
+
+ ms_retvm_if(ms_node == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "node is NULL");
+
+ if (ms_node->type == MEDIA_STREAMER_NODE_TYPE_WEBRTC) {
+ media_streamer_webrtc_callbacks_s **_callbacks = (media_streamer_webrtc_callbacks_s **)&(ms_node->callbacks_structure);
+
+ ms_retvm_if(*_callbacks == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "callbacks is NULL");
+ ms_retvm_if((*_callbacks)->decoded_ready_cb.callback == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER,
+ "decoded_ready_cb.callback is NULL");
+
+ (*_callbacks)->decoded_ready_cb.callback = NULL;
+ (*_callbacks)->decoded_ready_cb.user_data = NULL;
+
+ if (!(*_callbacks)->message_cb.callback) {
+ free(ms_node->callbacks_structure);
+ ms_node->callbacks_structure = NULL;
+ }
+ } else {
+ /* It can be accepted other types in the future. */
+ ms_error("Not supported node type[%d]", ms_node->type);
+ return MEDIA_STREAMER_ERROR_INVALID_PARAMETER;
+ }
+
+ ms_debug_fleave();
+
+ return MEDIA_STREAMER_ERROR_NONE;
+}
+
int media_streamer_webrtc_node_set_message_cb(media_streamer_node_h webrtc, media_streamer_webrtc_message_cb callback, void *user_data)
{
media_streamer_node_s *ms_node = (media_streamer_node_s *) webrtc;
+ media_streamer_webrtc_callbacks_s **_callbacks;
ms_retvm_if(ms_node == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "node is NULL");
+ ms_retvm_if(callback == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "callback is NULL");
ms_retvm_if(ms_node->type != MEDIA_STREAMER_NODE_TYPE_WEBRTC, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "node is not for WebRTC");
ms_debug_fenter();
- ms_node->user_cb.callback = callback;
- ms_node->user_cb.user_data = user_data;
+ _callbacks = (media_streamer_webrtc_callbacks_s **)&(ms_node->callbacks_structure);
+ if (!*_callbacks) {
+ *_callbacks = (media_streamer_webrtc_callbacks_s *) calloc(1, sizeof(media_streamer_webrtc_callbacks_s));
+ ms_retvm_if(*_callbacks == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Error allocation memory");
+ }
+
+ (*_callbacks)->message_cb.callback = callback;
+ (*_callbacks)->message_cb.user_data = user_data;
ms_debug_fleave();
int media_streamer_webrtc_node_unset_message_cb(media_streamer_node_h webrtc)
{
media_streamer_node_s *ms_node = (media_streamer_node_s *) webrtc;
+ media_streamer_webrtc_callbacks_s **_callbacks;
+
+ ms_debug_fenter();
ms_retvm_if(ms_node == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "node is NULL");
ms_retvm_if(ms_node->type != MEDIA_STREAMER_NODE_TYPE_WEBRTC, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "node is not for WebRTC");
- ms_debug_fenter();
+ _callbacks = (media_streamer_webrtc_callbacks_s **)&(ms_node->callbacks_structure);
+
+ ms_retvm_if(*_callbacks == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "callbacks is NULL");
+ ms_retvm_if((*_callbacks)->message_cb.callback == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "message_cb.callback is NULL");
- ms_node->user_cb.callback = NULL;
- ms_node->user_cb.user_data = NULL;
+ (*_callbacks)->message_cb.callback = NULL;
+ (*_callbacks)->message_cb.user_data = NULL;
+
+ if (!(*_callbacks)->decoded_ready_cb.callback) {
+ free(ms_node->callbacks_structure);
+ ms_node->callbacks_structure = NULL;
+ }
ms_debug_fleave();
return MEDIA_STREAMER_ERROR_NONE;
-}
\ No newline at end of file
+}
static void __trigger_message_callback(media_streamer_node_s *webrtc_node, gchar *message)
{
+ media_streamer_webrtc_callbacks_s *_callbacks;
+
ms_retm_if(webrtc_node == NULL, "webrtc_node is NULL");
+ ms_retm_if(message == NULL, "message is NULL");
ms_debug("message is : \n%s", message);
- if (webrtc_node->user_cb.callback) {
- ms_debug("=====> Now trigger user callback(%p)", webrtc_node->user_cb.callback);
- ((media_streamer_webrtc_message_cb)(webrtc_node->user_cb.callback))(webrtc_node, message, webrtc_node->user_cb.user_data);
- ms_debug("<===== End of the callback");
+ _callbacks = (media_streamer_webrtc_callbacks_s *) webrtc_node->callbacks_structure;
+ if (_callbacks->message_cb.callback) {
+ ms_debug("=====> invoke message callback(%p)", _callbacks->message_cb.callback);
+ ((media_streamer_webrtc_message_cb)(_callbacks->message_cb.callback))(webrtc_node, message, _callbacks->message_cb.user_data);
+ ms_debug("<===== end of the callback");
} else {
ms_warning("message callback is NULL");
}
ms_debug_fleave();
}
+static void __trigger_decoded_ready_callback(media_streamer_node_s *webrtc_node, const gchar *new_pad_name, const gchar *media_type)
+{
+ media_streamer_webrtc_callbacks_s *_callbacks;
+
+ ms_retm_if(webrtc_node == NULL, "webrtc_node is NULL");
+ ms_retm_if(new_pad_name == NULL, "new_pad_name is NULL");
+ ms_retm_if(media_type == NULL, "media_type is NULL");
+
+ _callbacks = (media_streamer_webrtc_callbacks_s *) webrtc_node->callbacks_structure;
+ if (!_callbacks->decoded_ready_cb.callback) {
+ ms_warning("decoded_ready_cb.callback is NULL");
+ return;
+ }
+
+ ms_debug("=====> invoke decoded ready callback(%p)", _callbacks->decoded_ready_cb.callback);
+ ((media_streamer_node_decoded_ready_cb)(_callbacks->decoded_ready_cb.callback))(webrtc_node,
+ (const char *)new_pad_name,
+ (const char *)media_type,
+ _callbacks->decoded_ready_cb.user_data);
+ ms_debug("<===== end of the callback");
+}
+
+static void __decodebin_pad_added_cb(GstElement *decodebin, GstPad *new_pad, gpointer user_data)
+{
+ media_streamer_node_s *webrtc_node = (media_streamer_node_s *)user_data;
+ const gchar *new_pad_name;
+ const gchar *media_type;
+
+ ms_retm_if(decodebin == NULL, "decodebin is NULL");
+ ms_retm_if(new_pad == NULL, "new_pad is NULL");
+ ms_retm_if(webrtc_node == NULL, "webrtc_node is NULL");
+ ms_retm_if(GST_PAD_DIRECTION(new_pad) != GST_PAD_SRC, "new_pad is not for source");
+ ms_retm_if(gst_pad_has_current_caps(new_pad) == FALSE, "new_pad does not have caps");
+
+ new_pad_name = GST_PAD_NAME(new_pad);
+ media_type = gst_structure_get_name(gst_caps_get_structure(gst_pad_get_current_caps(new_pad), 0));
+
+ ms_debug("new_pad_name[%s], media_type[%s]", new_pad_name, media_type);
+
+ __trigger_decoded_ready_callback(webrtc_node, new_pad_name, media_type);
+}
+
void ms_webrtcbin_pad_added_cb(GstElement *webrtcbin, GstPad *new_pad, gpointer user_data)
{
- media_streamer_s *ms_streamer = (media_streamer_s *)user_data;
+ media_streamer_node_s *webrtc_node = (media_streamer_node_s *)user_data;
+ media_streamer_webrtc_callbacks_s *_callbacks;
+ GstPad *sink_pad;
+ GstElement *decodebin;
ms_retm_if(new_pad == NULL, "new_pad is NULL");
- ms_retm_if(ms_streamer == NULL, "ms_streamer is NULL");
+ ms_retm_if(webrtc_node == NULL, "webrtc_node is NULL");
+ ms_retm_if(webrtc_node->callbacks_structure == NULL, "callbacks_structure is NULL");
ms_retm_if(GST_PAD_DIRECTION(new_pad) != GST_PAD_SRC, "new_pad is not for source");
ms_debug_fenter();
ms_debug("Pad [%s] added on [%s]", GST_PAD_NAME(new_pad), GST_ELEMENT_NAME(webrtcbin));
+ _callbacks = (media_streamer_webrtc_callbacks_s *) webrtc_node->callbacks_structure;
+ if (!_callbacks->decoded_ready_cb.callback) {
+ ms_warning("decoded_ready_cb.callback is null, skip it");
+ return;
+ }
+
+ decodebin = ms_element_create(DEFAULT_DECODEBIN, NULL);
+ ms_retm_if(decodebin == NULL, "decodebin is NULL");
+
+ ms_retm_if(webrtc_node->parent_streamer == NULL, "parent_streamer is NULL");
+ ms_retm_if(webrtc_node->parent_streamer->pipeline == NULL, "pipeline is NULL");
+ gst_bin_add(GST_BIN(webrtc_node->parent_streamer->pipeline), decodebin);
+
+ gst_element_sync_state_with_parent(decodebin);
+
+ g_signal_connect(decodebin, "pad-added", G_CALLBACK(__decodebin_pad_added_cb), webrtc_node);
+
+ sink_pad = gst_element_get_static_pad(decodebin, "sink");
+ ms_retm_if(sink_pad == NULL, "sink_pad is NULL");
+
+ gst_pad_link(new_pad, sink_pad);
+ gst_object_unref(sink_pad);
+
ms_debug_fleave();
}
node_info_s *node_klass_type = NULL;
GObject *send_channel = NULL;
gboolean is_offerer = FALSE;
+ media_streamer_webrtc_callbacks_s *_callbacks = NULL;
ms_debug_fenter();
return MEDIA_STREAMER_ERROR_INVALID_OPERATION;
}
- if (!node->user_cb.callback) {
+ _callbacks = (media_streamer_webrtc_callbacks_s *) node->callbacks_structure;
+ if (!_callbacks || !(_callbacks->message_cb.callback)) {
ms_error("message callback should be set before preparing");
return MEDIA_STREAMER_ERROR_INVALID_OPERATION;
}
}
g_signal_emit_by_name (webrtcbin, "create-data-channel", "channel", NULL, &send_channel);
- if (send_channel) {
+ if (send_channel)
ms_info("data channel(%p) for sending is created", send_channel);
- } else {
- ms_warning("Failed to create data channel, is usrsctp available?");
- }
+ else
+ ms_warning("Failed to create data channel");
ms_signal_create(&node->sig_list, webrtcbin, "on-data-channel", G_CALLBACK(ms_webrtcbin_on_data_channel_cb), ms_streamer);
- ms_signal_create(&node->sig_list, webrtcbin, "pad-added", G_CALLBACK(ms_webrtcbin_pad_added_cb), ms_streamer);
+ ms_signal_create(&node->sig_list, webrtcbin, "pad-added", G_CALLBACK(ms_webrtcbin_pad_added_cb), node);
ms_generate_dots(node->gst_element, "webrtc_prepared");