The gstreamer pipeline state is changed to NULL when after webrtc_stop().
In this situation, webrtc state is IDLE in which a media source can be added
or removed. This change intends to be sure to release all the resources
inside of the webrtcbin as well as avoid warning message when calling the
gst_bin_remove() within gstreamer READY state.
Release missing sink slots which have been created after finishing
negotiation APIs.
[Version] 0.1.39
[Issue Type] Improvement
Change-Id: Ia51d8f98d8e778619e20c36c6a87ed56721065db
Signed-off-by: Sangchul Lee <sc11.lee@samsung.com>
} \
} while (0)
-#define MALLOC_AND_INIT_SLOT(x_slot, x_id, x_bin_name) \
+#define MALLOC_AND_INIT_SLOT(x_slot, x_id, x_bin_name, x_webrtcbin) \
do { \
x_slot = g_new0(webrtc_gst_slot_s, 1); \
x_slot->id = x_id; \
x_slot->bin = gst_bin_new(x_bin_name); \
x_slot->mlines[MLINES_IDX_AUDIO] = -1; \
x_slot->mlines[MLINES_IDX_VIDEO] = -1; \
+ x_slot->webrtcbin = x_webrtcbin; \
} while (0)
#define GENERATE_DOT(x_webrtc, x_fmt, x_arg...) \
GstElement *bin;
int media_types; /* values of media_type_e combined with bitwise 'or' */
int mlines[2]; /* index 0 for audio, 1 for video */
+ GstElement *webrtcbin;
} webrtc_gst_slot_s;
typedef struct _webrtc_gst_s {
int _add_no_target_ghostpad_to_slot(webrtc_gst_slot_s *slot, gboolean is_src, GstPad **new_pad);
int _set_ghost_pad_target(GstPad *ghost_pad, GstElement *target_element, gboolean is_src);
int _add_rendering_sink_bin(webrtc_s *webrtc, GstPad *src_pad);
+void _sink_slot_destroy_cb(gpointer data);
+void _source_slot_destroy_cb(gpointer data);
void _generate_dot(webrtc_s *webrtc, const gchar *name);
int _webrtcbin_create_offer(webrtc_s *webrtc, char **offer);
Name: capi-media-webrtc
Summary: A WebRTC library in Tizen Native API
-Version: 0.1.38
+Version: 0.1.39
Release: 0
Group: Multimedia/API
License: Apache-2.0
RET_VAL_WITH_UNLOCK_IF(_webrtc->state == WEBRTC_STATE_IDLE, WEBRTC_ERROR_INVALID_STATE, &_webrtc->mutex, "the state should not be IDLE");
- _gst_pipeline_set_state(_webrtc, GST_STATE_READY);
+ _gst_pipeline_set_state(_webrtc, GST_STATE_NULL);
_post_state_in_idle(_webrtc, WEBRTC_STATE_IDLE);
LOG_INFO("webrtc[%p] is stopping", webrtc);
+ g_hash_table_remove_all(_webrtc->gst.sink_slots);
+
g_mutex_unlock(&_webrtc->mutex);
return WEBRTC_ERROR_NONE;
__invoke_state_changed_cb(webrtc, old_state, webrtc->state);
- return FALSE;
+ return G_SOURCE_REMOVE;
}
void _post_state_in_idle(webrtc_s *webrtc, webrtc_state_e new_state)
return element;
}
-static void __value_destroy_cb(gpointer data)
-{
- webrtc_gst_slot_s *source = (webrtc_gst_slot_s *)data;
-
- RET_IF(data == NULL, "data is NULL");
-
- LOG_DEBUG("[%s, id:%u, media_types:0x%x, mlines[AUDIO]:%d, mlines[VIDEO]:%d] is removed",
- GST_ELEMENT_NAME(source->bin), source->id, source->media_types, source->mlines[MLINES_IDX_AUDIO], source->mlines[MLINES_IDX_VIDEO]);
-
- /* FIXME: do unlink */
-
- gst_bin_remove(GST_BIN(gst_element_get_parent(source->bin)), source->bin);
-
- g_free(source);
-}
-
int _ini_load(webrtc_s *webrtc)
{
RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
{
webrtc_signal_s *sig_data = (webrtc_signal_s *)data;
- RET_IF(data == NULL, "data is NULL");
+ RET_IF(sig_data == NULL, "sig_data is NULL");
if (GST_IS_ELEMENT(sig_data->obj)) {
if (g_signal_handler_is_connected(sig_data->obj, sig_data->signal_id)) {
goto error;
}
- webrtc->gst.source_slots = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, __value_destroy_cb);
- webrtc->gst.sink_slots = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, __value_destroy_cb);
+ webrtc->gst.source_slots = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, _source_slot_destroy_cb);
+ webrtc->gst.sink_slots = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, _sink_slot_destroy_cb);
return WEBRTC_ERROR_NONE;
return (unsigned int)id;
}
+void _sink_slot_destroy_cb(gpointer data)
+{
+ webrtc_gst_slot_s *sink = (webrtc_gst_slot_s *)data;
+
+ RET_IF(sink == NULL, "sink is NULL");
+
+ LOG_DEBUG("[%s, id:%u, media_types:0x%x] is removed",
+ GST_ELEMENT_NAME(sink->bin), sink->id, sink->media_types);
+
+ gst_bin_remove(GST_BIN(gst_element_get_parent(sink->bin)), sink->bin);
+
+ g_free(sink);
+}
+
int _add_rendering_sink_bin(webrtc_s *webrtc, GstPad *src_pad)
{
int ret = WEBRTC_ERROR_NONE;
bin_name = g_strdup_printf("rendering_sink_%u", id);
decodebin_name = g_strdup_printf("%s_decodebin", bin_name);
- MALLOC_AND_INIT_SLOT(sink, id, bin_name);
+ MALLOC_AND_INIT_SLOT(sink, id, bin_name, webrtc->gst.webrtcbin);
g_free(bin_name);
return 0;
}
+static gboolean __foreach_src_pad_cb(GstElement *element, GstPad *pad, gpointer user_data)
+{
+ webrtc_gst_slot_s *source = (webrtc_gst_slot_s *)user_data;
+ GstPad *peer = gst_pad_get_peer(pad);
+
+ RET_VAL_IF(source == NULL, FALSE, "source is NULL");
+ RET_VAL_IF(peer == NULL, TRUE, "peer pad is NULL");
+
+ LOG_DEBUG("about to release request pad[%s]", GST_PAD_NAME(peer));
+
+ gst_element_release_request_pad(source->webrtcbin, peer);
+
+ /* Two unrefing here, one for getting request pad, another one for getting peer pad */
+ gst_object_unref(peer);
+ gst_object_unref(peer);
+
+ return TRUE;
+}
+
+void _source_slot_destroy_cb(gpointer data)
+{
+ webrtc_gst_slot_s *source = (webrtc_gst_slot_s *)data;
+
+ RET_IF(source == NULL, "source is NULL");
+
+ LOG_DEBUG("[%s, id:%u, media_types:0x%x, mlines[AUDIO]:%d, mlines[VIDEO]:%d] is removed",
+ GST_ELEMENT_NAME(source->bin), source->id, source->media_types, source->mlines[MLINES_IDX_AUDIO], source->mlines[MLINES_IDX_VIDEO]);
+
+ gst_element_foreach_src_pad(source->bin, __foreach_src_pad_cb, source);
+
+ gst_bin_remove(GST_BIN(gst_element_get_parent(source->bin)), source->bin);
+
+ g_free(source);
+}
+
int _add_media_source(webrtc_s *webrtc, webrtc_media_source_type_e type, unsigned int *source_id)
{
int ret = WEBRTC_ERROR_NONE;
bin_name = g_strdup_printf("media_source_%u", id);
- MALLOC_AND_INIT_SLOT(source, id, bin_name);
+ MALLOC_AND_INIT_SLOT(source, id, bin_name, webrtc->gst.webrtcbin);
ret = __build_source_bin(source, type);
if (ret != WEBRTC_ERROR_NONE) {