/**
* @brief Find Udp elements into rtp container by name.
- *
+ * It returns elements with increased ref count.
* @since_tizen 3.0
*/
gboolean __ms_get_rtp_elements(media_streamer_node_s *ms_node, GstElement **rtp_elem,
GHashTable *nodes_table;
GMutex mutex_lock;
+ GList *autoplug_sig_list;
GstBus *bus;
guint bus_watcher;
gboolean linked_by_user;
+ GList *sig_list;
+
ms_node_set_param set_param;
void *callbacks_structure;
} media_streamer_node_s;
#include <stdlib.h>
#include <glib.h>
+#include <gst/gst.h>
#include <dlog.h>
#include <iniparser.h>
} media_streamer_ini_t;
+/**
+ * @brief Media Streamer signal structure.
+ *
+ * @since_tizen 3.0
+ */
+typedef struct {
+ GObject* obj;
+ gulong signal_id;
+} media_streamer_signal_s;
/*Test elements*/
#define DEFAULT_VIDEO_TEST_SOURCE "videotestsrc"
*/
media_format_mimetype_e __ms_convert_string_format_to_mime(const char *format_type);
+/**
+ * @brief Creates Media streamer signal structure,
+ * connects it to object and appends it to signal list.
+ *
+ * @since_tizen 3.0
+ */
+void __ms_signal_create(GList **sig_list, GstElement *obj, const char *sig_name, GCallback cb, gpointer user_data);
+
+/**
+ * @brief Disconnects signal from object and
+ * destroys Media streamer signal object.
+ *
+ * @since_tizen 3.0
+ */
+void __ms_signal_destroy(void *data);
+
#ifdef __cplusplus
}
#endif
return ret;
}
-static int __ms_add_ghostpad(GstElement * gst_element, const char *pad_name, GstElement * gst_bin, const char *ghost_pad_name)
+static gboolean __ms_add_ghostpad(GstElement * gst_element, const char *pad_name, GstElement * gst_bin, const char *ghost_pad_name)
{
- ms_retvm_if(!gst_element || !pad_name || !ghost_pad_name || !gst_bin, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL");
+ ms_retvm_if(!gst_element || !pad_name || !ghost_pad_name || !gst_bin, FALSE, "Handle is NULL");
- int ret = MEDIA_STREAMER_ERROR_NONE;
+ gboolean ret = FALSE;
GstPad *ghost_pad = NULL;
- gchar *bin_name = gst_element_get_name(gst_bin);
-
- gchar *element_name = gst_element_get_name(gst_element);
GstPad *element_pad = gst_element_get_static_pad(gst_element, pad_name);
- if (!element_pad) {
- /*maybe it is request pad */
+
+ if (element_pad == NULL) {
+ /* maybe it is request pad */
element_pad = gst_element_get_request_pad(gst_element, pad_name);
}
- if (element_pad != NULL) {
- ghost_pad = gst_ghost_pad_new(ghost_pad_name, element_pad);
- gst_pad_set_active(ghost_pad, TRUE);
- gst_element_add_pad(GST_ELEMENT(gst_bin), ghost_pad);
- ms_info("Added %s ghostpad from [%s] into [%s]", pad_name, element_name, bin_name);
- MS_SAFE_UNREF(element_pad);
- MS_SAFE_GFREE(element_name);
+ ghost_pad = gst_ghost_pad_new(ghost_pad_name, element_pad);
+ gst_pad_set_active(ghost_pad, TRUE);
+
+ ret = gst_element_add_pad(GST_ELEMENT(gst_bin), ghost_pad);
- ret = MEDIA_STREAMER_ERROR_NONE;
+ if (ret) {
+ ms_info("Added %s ghostpad from [%s] into [%s]", pad_name,
+ GST_ELEMENT_NAME(gst_element), GST_ELEMENT_NAME(gst_bin));
} else {
- ms_error("Error: element [%s] does not have valid [%s] pad for adding into [%s] bin", element_name, pad_name, bin_name);
- ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION;
+ ms_error("Error: element [%s] does not have valid [%s] pad for adding into [%s] bin",
+ GST_ELEMENT_NAME(gst_element), pad_name, GST_ELEMENT_NAME(gst_bin));
}
- MS_SAFE_GFREE(bin_name);
+ MS_SAFE_UNREF(element_pad);
return ret;
}
static GObject *__ms_get_property_owner(GstElement * element, const gchar * key, GValue * value)
{
- GParamSpec *param;
+ GParamSpec *param = NULL;
GObject *obj = NULL;
if (GST_IS_CHILD_PROXY(element)) {
int i;
int childs_count = gst_child_proxy_get_children_count(GST_CHILD_PROXY(element));
- param = NULL;
for (i = 0; (i < childs_count) && (param == NULL); ++i) {
obj = gst_child_proxy_get_child_by_index(GST_CHILD_PROXY(element), i);
param = g_object_class_find_property(G_OBJECT_GET_CLASS(obj), key);
gboolean __ms_element_set_property(GstElement * element, const char *key, const gchar * param_value)
{
- gchar *element_name = gst_element_get_name(element);
- GValue value = G_VALUE_INIT;
-
char *init_name = NULL;
int pint = 0;
- gboolean bool_val = false;
+ gboolean bool_val = FALSE;
+ gboolean ret = FALSE;
__ms_node_check_param_name(element, TRUE, key, &init_name);
if (init_name) {
+ GValue value = G_VALUE_INIT;
GObject *obj = __ms_get_property_owner(element, init_name, &value);
if (obj == NULL) {
- ms_debug("Element [%s] does not have property [%s].", element_name, init_name);
- MS_SAFE_GFREE(element_name);
+ ms_debug("Element [%s] does not have property [%s].", GST_ELEMENT_NAME(element), init_name);
return FALSE;
}
ms_info("Set string value: [%s]", g_value_get_string(&value));
} else {
ms_info("Got unknown type with param->value_type [%lu]", G_VALUE_TYPE(&value));
- return FALSE;
+ ret = FALSE;
}
+ g_value_unset(&value);
} else {
- ms_info("Can not set parameter [%s] in the node [%s]\n", key, gst_element_get_name(element));
+ ms_info("Can not set parameter [%s] in the node [%s]", key, GST_ELEMENT_NAME(element));
}
- MS_SAFE_GFREE(element_name);
-
- return TRUE;
+ return ret;
}
/* This unlinks from its peer and ghostpads on its way */
GstElement *__ms_create_element_by_registry(GstPad * src_pad, const gchar * klass_name)
{
- GList *factories;
const GList *pads;
GstElement *next_element = NULL;
GstCaps *new_pad_caps = gst_pad_query_caps(src_pad, NULL);
- factories = gst_registry_feature_filter(gst_registry_get(), (GstPluginFeatureFilter) __ms_feature_filter, FALSE, NULL);
- factories = g_list_sort(factories, (GCompareFunc) __ms_factory_rank_compare);
-
- for (; factories != NULL; factories = factories->next) {
- GstElementFactory *factory = GST_ELEMENT_FACTORY(factories->data);
+ GList *factories = gst_registry_feature_filter(gst_registry_get(),
+ (GstPluginFeatureFilter)__ms_feature_filter, FALSE, NULL);
+ factories = g_list_sort(factories, (GCompareFunc)__ms_factory_rank_compare);
+ GList *factories_iter = factories;
+ for (; factories_iter != NULL ; factories_iter = factories_iter->next) {
+ GstElementFactory *factory = GST_ELEMENT_FACTORY(factories_iter->data);
if (g_strrstr(gst_element_factory_get_klass(GST_ELEMENT_FACTORY(factory)), klass_name)) {
for (pads = gst_element_factory_get_static_pad_templates(factory); pads != NULL; pads = pads->next) {
if (!gst_pad_is_linked(sink_pad)) {
if (!strncmp(new_pad_type, GST_PAD_NAME(sink_pad), 5)) {
if (gst_element_link_pads_filtered(previous_element, "src", new_element, GST_PAD_NAME(sink_pad), NULL))
- ms_info("Succeeded to link [%s] -> [%s]\n", GST_ELEMENT_NAME(previous_element), GST_ELEMENT_NAME(new_element));
+ ms_info("Succeeded to link [%s] -> [%s]", GST_ELEMENT_NAME(previous_element), GST_ELEMENT_NAME(new_element));
else
- ms_error("Failed to link [%s] -> [%s]\n", GST_ELEMENT_NAME(previous_element), GST_ELEMENT_NAME(new_element));
+ ms_error("Failed to link [%s] -> [%s]", GST_ELEMENT_NAME(previous_element), GST_ELEMENT_NAME(new_element));
}
}
MS_SAFE_UNREF(prev_elem_sink_pad);
gboolean ret = gst_element_link_pads_filtered(previous_element, NULL, new_element, NULL, NULL);
if (ret)
- ms_info("Succeeded to link [%s] -> [%s]\n", GST_ELEMENT_NAME(previous_element), GST_ELEMENT_NAME(new_element));
+ ms_info("Succeeded to link [%s] -> [%s]", GST_ELEMENT_NAME(previous_element), GST_ELEMENT_NAME(new_element));
else
- ms_error("Failed to link [%s] and [%s] \n", GST_ELEMENT_NAME(previous_element), GST_ELEMENT_NAME(new_element));
+ ms_error("Failed to link [%s] and [%s]", GST_ELEMENT_NAME(previous_element), GST_ELEMENT_NAME(new_element));
}
return new_element;
}
factory_name = GST_OBJECT_NAME(factory);
klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
- ms_debug("Decodebin: found new element [%s] to link [%s]\n\n", factory_name, klass);
+ ms_debug("Decodebin: found new element [%s] to link [%s]", factory_name, klass);
if ((g_strrstr(klass, "Codec/Decoder/Video"))) {
/* Skip Video4Linux decoders */
if (g_strrstr(factory_name, "v4l2video")) {
- ms_debug("Decodebin: skipping [%s] by not required\n", factory_name);
+ ms_debug("Decodebin: skipping [%s] by not required", factory_name);
return GST_AUTOPLUG_SELECT_SKIP;
}
GstStructure *new_pad_struct = NULL;
const gchar *new_pad_type = NULL;
- ms_info("Received new pad '%s' from [%s]\n", GST_PAD_NAME(new_pad), GST_ELEMENT_NAME(decodebin));
+ ms_info("Received new pad '%s' from [%s]", GST_PAD_NAME(new_pad), GST_ELEMENT_NAME(decodebin));
/* Check the new pad's type */
new_pad_caps = gst_pad_query_caps(new_pad, 0);
found_element = __ms_combine_next_element(found_element, MEDIA_STREAMER_SINK_KLASS, NULL, NULL);
if (!found_element)
- ms_error("Could not link to sink element \n");
+ ms_error("Could not link to sink element");
}
gst_caps_unref(new_pad_caps);
found_element = __ms_combine_next_element(found_element, MEDIA_STREAMER_SINK_KLASS, NULL, NULL);
if (!found_element)
- ms_error("Could not link to sink element \n");
+ ms_error("Could not link to sink element");
gst_caps_unref(new_pad_caps);
}
if (!found_element) {
if (decodebin_usage) {
-
found_element = __ms_element_create("decodebin", NULL);
- gst_bin_add_many((GstBin *) sink_bin, found_element, NULL);
+ __ms_bin_add_element(sink_bin, found_element, FALSE);
gst_element_sync_state_with_parent(found_element);
- g_signal_connect(found_element, "pad-added", G_CALLBACK(__decodebin_newpad_client_cb), (gpointer) ms_node);
- g_signal_connect(found_element, "autoplug-select", G_CALLBACK(__ms_decodebin_autoplug_select), NULL);
+
+ __ms_signal_create(&ms_node->parent_streamer->autoplug_sig_list, found_element, "pad-added",
+ G_CALLBACK(__decodebin_newpad_client_cb), (gpointer)ms_node);
+ __ms_signal_create(&ms_node->parent_streamer->autoplug_sig_list, found_element, "autoplug-select",
+ G_CALLBACK(__ms_decodebin_autoplug_select), NULL);
+
previous_element = __ms_link_with_new_element(previous_element, found_element, NULL);
__ms_element_set_state(found_element, GST_STATE_PLAYING);
static void __ms_rtpbin_pad_added_cb(GstElement * src, GstPad * new_pad, gpointer user_data)
{
- gchar *new_pad_name = NULL;
- gchar *src_element_name = NULL;
+ ms_debug("Pad [%s] added on [%s]", GST_PAD_NAME(new_pad), GST_ELEMENT_NAME(src));
media_streamer_node_s *ms_node = (media_streamer_node_s *) user_data;
ms_retm_if(ms_node == NULL, "Handle is NULL");
- new_pad_name = gst_pad_get_name(new_pad);
- src_element_name = gst_element_get_name(src);
- ms_debug("Pad [%s] added on [%s]\n", new_pad_name, src_element_name);
+ if (g_str_has_prefix(GST_PAD_NAME(new_pad), "recv_rtp_src")) {
+ media_streamer_s *ms_streamer = ms_node->parent_streamer;
+ ms_retm_if(ms_streamer == NULL, "Node's parent streamer handle is NULL");
- GstPad *target_pad = gst_ghost_pad_get_target(GST_GHOST_PAD(new_pad));
- GstCaps *src_pad_caps = gst_pad_query_caps(target_pad, NULL);
-
- if (ms_node->parent_streamer && !gst_caps_is_any(src_pad_caps)) {
+ GstPad *target_pad = gst_ghost_pad_get_target(GST_GHOST_PAD(new_pad));
+ GstCaps *src_pad_caps = gst_pad_query_caps(target_pad, NULL);
g_mutex_lock(&ms_node->parent_streamer->mutex_lock);
GstPad *source_pad = gst_element_get_static_pad(ms_node->gst_element, source_pad_name);
gst_ghost_pad_set_target(GST_GHOST_PAD(source_pad), new_pad);
- if (__ms_sink_bin_prepare(ms_node, sink_bin, source_pad)) {
-
- if (__ms_bin_add_element(ms_node->parent_streamer->pipeline, sink_bin, TRUE)) {
- gst_element_sync_state_with_parent(sink_bin);
+ if (__ms_sink_bin_prepare(ms_node, sink_bin, source_pad) &&
+ __ms_bin_add_element(ms_node->parent_streamer->pipeline, sink_bin, TRUE)) {
+ gst_element_sync_state_with_parent(sink_bin);
- if (gst_element_link_pads(ms_node->gst_element, source_pad_name, sink_bin, "sink")) {
- __ms_element_set_state(ms_node->gst_element, GST_STATE_PLAYING);
- __ms_generate_dots(ms_node->parent_streamer->pipeline, "playing");
- } else {
- ms_error("Failed to link [rtp_containeer].[%s] and [sink_bin].[sink]\n", source_pad_name);
- }
+ if (gst_element_link_pads(ms_node->gst_element, source_pad_name, sink_bin, "sink")) {
+ __ms_element_set_state(ms_node->gst_element, GST_STATE_PLAYING);
+ __ms_generate_dots(ms_node->parent_streamer->pipeline, "rtpbin_playing");
+ } else {
+ ms_error("Failed to link [rtp_containeer].[%s] and [sink_bin].[sink]", source_pad_name);
}
} else {
- ms_error("Failed to prepare sink_bin for pad type [%s]\n", src_pad_type);
+ ms_error("Failed to prepare sink_bin for pad type [%s]", src_pad_type);
}
MS_SAFE_UNREF(source_pad);
}
g_mutex_unlock(&ms_node->parent_streamer->mutex_lock);
- } else {
- ms_debug("Node doesn`t have parent streamer or caps media type\n");
+ gst_caps_unref(src_pad_caps);
+ MS_SAFE_UNREF(target_pad);
}
-
- gst_caps_unref(src_pad_caps);
- MS_SAFE_UNREF(target_pad);
- MS_SAFE_GFREE(new_pad_name);
- MS_SAFE_GFREE(src_element_name);
}
int __ms_element_set_state(GstElement * gst_element, GstState gst_state)
return NULL;
}
- g_signal_connect(rtp_elem, "pad-added", G_CALLBACK(__ms_rtpbin_pad_added_cb), ms_node);
-
+ __ms_signal_create(&ms_node->sig_list, rtp_elem, "pad-added", G_CALLBACK(__ms_rtpbin_pad_added_cb), ms_node);
return rtp_container;
}
gboolean __ms_get_rtp_elements(media_streamer_node_s * ms_node, GstElement ** rtp_elem, GstElement ** rtcp_elem, const gchar * elem_name, const gchar * direction, gboolean auto_create)
{
- gboolean ret = TRUE;
- gchar *rtp_elem_name = NULL;
- gchar *rtcp_elem_name = NULL;
- gchar *plugin_name = NULL;
+ ms_retvm_if(!elem_name || !direction, FALSE, "Empty rtp element name or direction.");
GstElement *rtpbin = gst_bin_get_by_name(GST_BIN(ms_node->gst_element), "rtpbin");
- ms_retvm_if(!elem_name || !direction, FALSE, "Empty rtp element name or direction.");
-
+ gboolean ret = TRUE;
+ gchar *plugin_name = NULL;
if (MS_ELEMENT_IS_INPUT(direction)) {
plugin_name = g_strdup(DEFAULT_UDP_SOURCE);
} else if (MS_ELEMENT_IS_OUTPUT(direction)) {
plugin_name = g_strdup(DEFAULT_UDP_SINK);
} else {
- ms_error("Error: invalid parameter name [%s]", elem_name);
+ ms_error("Error: invalid RTP pad direction [%s]", direction);
+ MS_SAFE_UNREF(rtpbin);
return FALSE;
}
- rtp_elem_name = g_strdup_printf("%s_%s_rtp", elem_name, direction);
- rtcp_elem_name = g_strdup_printf("%s_%s_rtcp", elem_name, direction);
+ gchar *rtp_elem_name = g_strdup_printf("%s_%s_rtp", elem_name, direction);
+ gchar *rtcp_elem_name = g_strdup_printf("%s_%s_rtcp", elem_name, direction);
/* Find video udp rtp/rtcp element if it present. */
*rtp_elem = gst_bin_get_by_name(GST_BIN(ms_node->gst_element), rtp_elem_name);
*rtp_elem = __ms_element_create(plugin_name, rtp_elem_name);
*rtcp_elem = __ms_element_create(plugin_name, rtcp_elem_name);
gst_bin_add_many(GST_BIN(ms_node->gst_element), *rtp_elem, *rtcp_elem, NULL);
+ gst_object_ref(*rtp_elem);
+ gst_object_ref(*rtcp_elem);
} else {
/*rtp/rtcp elements already into rtp bin. */
+ MS_SAFE_UNREF(rtpbin);
MS_SAFE_GFREE(rtp_elem_name);
MS_SAFE_GFREE(rtcp_elem_name);
MS_SAFE_GFREE(plugin_name);
if (!ret) {
ms_error("Can not link [rtpbin] pad to [%s] pad", rtp_elem_name);
+ MS_SAFE_UNREF(*rtp_elem);
+ MS_SAFE_UNREF(*rtcp_elem);
ret = FALSE;
+ __ms_generate_dots(ms_node->gst_element, "rtp_fail");
}
__ms_generate_dots(ms_node->gst_element, "rtp");
+ MS_SAFE_UNREF(rtpbin);
MS_SAFE_GFREE(rtp_elem_name);
MS_SAFE_GFREE(rtcp_elem_name);
MS_SAFE_GFREE(plugin_name);
gst_message_parse_state_changed(message, &state_old, &state_new, &state_pending);
state_transition_name = g_strdup_printf("%s_%s", gst_element_state_get_name(state_old), gst_element_state_get_name(state_new));
- ms_info("GST_MESSAGE_STATE_CHANGED: [%s] %s", gst_object_get_name(GST_MESSAGE_SRC(message)), state_transition_name);
+ ms_info("GST_MESSAGE_STATE_CHANGED: [%s] %s", GST_OBJECT_NAME(GST_MESSAGE_SRC(message)), state_transition_name);
__ms_generate_dots(ms_streamer->pipeline, state_transition_name);
MS_SAFE_GFREE(state_transition_name);
{
ms_retvm_if(ms_streamer == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL");
- gst_init(NULL, NULL);
+ GError *err = NULL;
+ if (!gst_init_check(NULL, NULL, &err)) {
+ ms_error("Error: Failed to initialize GStreamer [%s].", err->message);
+ g_clear_error(&err);
+ return MEDIA_STREAMER_ERROR_INVALID_OPERATION;
+ }
ms_streamer->pipeline = gst_pipeline_new(MEDIA_STREAMER_PIPELINE_NAME);
ms_retvm_if(ms_streamer->pipeline == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Error creating pipeline");
GValue value = G_VALUE_INIT;
if (node->type == MEDIA_STREAMER_NODE_TYPE_RTP) {
- /* It is needed to set 'application/x-rtp' for audio and video udpsrc */
+ /* Check if it is a valid pad */
+ GstPad *pad = gst_element_get_static_pad(node->gst_element, pad_name);
+ ms_retvm_if(!pad, MEDIA_STREAMER_ERROR_INVALID_PARAMETER,
+ "Error: Failed set format to pad [%s].[%s].", node->name, pad_name);
+ MS_SAFE_UNREF(pad);
+
+ /* It is needed to set 'application/x-rtp' for audio and video udpsrc*/
media_format_mimetype_e mime;
int audio_channels, audio_samplerate;
GstElement *rtp_elem, *rtcp_elem;
gchar *rtp_caps_str = NULL;
- /*Check if it is a valid pad */
- GstPad *pad = gst_element_get_static_pad(node->gst_element, pad_name);
- if (!pad) {
- ms_error("Error: Failed set format to pad [%s].[%s].", node->name, pad_name);
- return MEDIA_STREAMER_ERROR_INVALID_PARAMETER;
- }
-
if (MEDIA_FORMAT_ERROR_NONE == media_format_get_video_info(fmt, &mime, NULL, NULL, NULL, NULL)) {
+ rtp_caps_str = g_strdup_printf("application/x-rtp,media=video,clock-rate=90000,encoding-name=%s",
+ __ms_convert_mime_to_rtp_format(mime));
__ms_get_rtp_elements(node, &rtp_elem, &rtcp_elem, "video", "in", FALSE);
- rtp_caps_str = g_strdup_printf("application/x-rtp,media=video,clock-rate=90000,encoding-name=%s", __ms_convert_mime_to_rtp_format(mime));
- caps = gst_caps_from_string(rtp_caps_str);
- ms_retvm_if(caps == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Fail creating caps from fmt.");
-
- obj = __ms_get_property_owner(rtp_elem, "caps", &value);
} else if (MEDIA_FORMAT_ERROR_NONE == media_format_get_audio_info(fmt, &mime, &audio_channels, &audio_samplerate, NULL, NULL)) {
+ rtp_caps_str = g_strdup_printf("application/x-rtp,media=audio,clock-rate=%d,encoding-name=%s,channels=%d,payload=96",
+ audio_samplerate, __ms_convert_mime_to_rtp_format(mime), audio_channels);
__ms_get_rtp_elements(node, &rtp_elem, &rtcp_elem, "audio", "in", FALSE);
-
- rtp_caps_str = g_strdup_printf("application/x-rtp,media=audio,clock-rate=%d,encoding-name=%s,channels=%d,payload=96", audio_samplerate, __ms_convert_mime_to_rtp_format(mime), audio_channels);
- caps = gst_caps_from_string(rtp_caps_str);
- ms_retvm_if(caps == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Fail creating caps from fmt.");
-
- obj = __ms_get_property_owner(rtp_elem, "caps", &value);
} else {
ms_error("Failed getting media info from fmt.");
return MEDIA_STREAMER_ERROR_INVALID_PARAMETER;
}
+ caps = gst_caps_from_string(rtp_caps_str);
+ obj = __ms_get_property_owner(rtp_elem, "caps", &value);
+ MS_SAFE_UNREF(rtp_elem);
+ MS_SAFE_UNREF(rtcp_elem);
MS_SAFE_GFREE(rtp_caps_str);
- MS_SAFE_UNREF(pad);
} else {
caps = __ms_create_caps_from_fmt(fmt);
ms_retvm_if(caps == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Fail creating caps from fmt.");
gst_value_set_caps(&value, caps);
g_object_set_property(obj, "caps", &value);
+ g_value_unset(&value);
gst_caps_unref(caps);
return MEDIA_STREAMER_ERROR_NONE;
if (rtp_elem && rtcp_elem) {
__ms_element_set_property(rtp_elem, param, param_value);
__ms_element_set_property(rtcp_elem, param, param_value);
+ MS_SAFE_UNREF(rtp_elem);
+ MS_SAFE_UNREF(rtcp_elem);
}
__ms_get_rtp_elements(ms_node, &rtp_elem, &rtcp_elem, "video", "out", FALSE);
if (rtp_elem && rtcp_elem) {
__ms_element_set_property(rtp_elem, param, param_value);
__ms_element_set_property(rtcp_elem, param, param_value);
+ MS_SAFE_UNREF(rtp_elem);
+ MS_SAFE_UNREF(rtcp_elem);
}
} else {
ms_error("Error: Unsupported parameter [%s] for rtp node.", param);
}
g_strfreev(tokens);
+ MS_SAFE_UNREF(rtp_elem);
+ MS_SAFE_UNREF(rtcp_elem);
return MEDIA_STREAMER_ERROR_NONE;
} else {
ms_error("Invalid rtp parameter name.");
dec_use = iniparser_getboolean(dict, "general:use decodebin", DEFAULT_USE_DECODEBIN);
if (dec_use) {
node->gst_element = __ms_element_create("decodebin", NULL);
- g_signal_connect(node->gst_element, "pad-added", G_CALLBACK(__decodebin_newpad_client_cb), (gpointer) node);
- g_signal_connect(node->gst_element, "autoplug-select", G_CALLBACK(__ms_decodebin_autoplug_select), NULL);
+ __ms_signal_create(&node->sig_list, node->gst_element, "pad-added", G_CALLBACK(__decodebin_newpad_client_cb), node);
+ __ms_signal_create(&node->sig_list, node->gst_element, "autoplug-select", G_CALLBACK(__ms_decodebin_autoplug_select), NULL);
} else {
format_prefix = g_strdup_printf("%s:decoder", __ms_convert_mime_to_string(mime));
plugin_name = __ms_ini_get_string(dict, format_prefix, DEFAULT_VIDEO_DECODER);
break;
case MEDIA_STREAMER_NODE_SRC_TYPE_CUSTOM:
node->gst_element = __ms_element_create(DEFAULT_APP_SOURCE, NULL);
- g_signal_connect(node->gst_element, "need-data", G_CALLBACK(__ms_src_start_feed_cb), (gpointer) node);
- g_signal_connect(node->gst_element, "enough-data", G_CALLBACK(__ms_src_stop_feed_cb), (gpointer) node);
+ __ms_signal_create(&node->sig_list, node->gst_element, "need-data", G_CALLBACK(__ms_src_start_feed_cb), node);
+ __ms_signal_create(&node->sig_list, node->gst_element, "enough-data", G_CALLBACK(__ms_src_stop_feed_cb), node);
break;
default:
ms_error("Error: invalid Src node Type [%d]", node->subtype);
case MEDIA_STREAMER_NODE_SINK_TYPE_CUSTOM:
node->gst_element = __ms_element_create(DEFAULT_APP_SINK, NULL);
g_object_set(G_OBJECT(node->gst_element), "emit-signals", TRUE, NULL);
- g_signal_connect(node->gst_element, "new-sample", G_CALLBACK(__ms_sink_new_buffer_cb), (gpointer) node);
- g_signal_connect(node->gst_element, "eos", G_CALLBACK(sink_eos), (gpointer) node);
+ __ms_signal_create(&node->sig_list, node->gst_element, "new-sample", G_CALLBACK(__ms_sink_new_buffer_cb), node);
+ __ms_signal_create(&node->sig_list, node->gst_element, "eos", G_CALLBACK(sink_eos), node);
break;
default:
ms_error("Error: invalid Sink node Type [%d]", node->subtype);
void __ms_node_destroy(media_streamer_node_s * node)
{
- char *node_name = NULL;
+ gchar *node_name = g_strdup(node->name);
+
+ /* Disconnects and clean all node signals */
+ g_list_free_full(node->sig_list, __ms_signal_destroy);
- node_name = g_strdup(node->name);
MS_SAFE_UNREF(node->gst_element);
MS_SAFE_FREE(node->name);
MS_SAFE_FREE(node->callbacks_structure);
int __ms_pipeline_prepare(media_streamer_s * ms_streamer)
{
- GstElement *unlinked_element = NULL;
- GstPad *unlinked_pad = NULL;
-
- GstElement *parent;
GstElement *found_element;
GstCaps *new_pad_caps = NULL;
ms_retvm_if(ms_streamer == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL");
/* Find unlinked element in src_bin */
- unlinked_pad = gst_bin_find_unlinked_pad(GST_BIN(ms_streamer->src_bin), GST_PAD_SRC);
+ GstPad *unlinked_pad = gst_bin_find_unlinked_pad(GST_BIN(ms_streamer->src_bin), GST_PAD_SRC);
+ GstElement *unlinked_element = NULL;
while (unlinked_pad) {
unlinked_element = gst_pad_get_parent_element(unlinked_pad);
ms_debug("Autoplug: found unlinked element [%s]", GST_ELEMENT_NAME(unlinked_element));
- parent = (GstElement *) gst_element_get_parent(GST_OBJECT_CAST(unlinked_element));
- ms_info("Received new pad '%s' from [%s]", GST_PAD_NAME(unlinked_pad), GST_ELEMENT_NAME(unlinked_element));
-
/* If element in src bin is filesrc */
if (__ms_src_need_typefind(unlinked_element)) {
found_element = __ms_element_create("decodebin", NULL);
- gst_bin_add_many((GstBin *) ms_streamer->topology_bin, found_element, NULL);
-
+ __ms_bin_add_element(ms_streamer->topology_bin, found_element, FALSE);
gst_element_sync_state_with_parent(found_element);
- if (__ms_bin_find_element_by_klass(ms_streamer->topology_bin, found_element, MEDIA_STREAMER_BIN_KLASS, "rtp_container"))
+ if (__ms_bin_find_element_by_klass(ms_streamer->topology_bin, found_element, MEDIA_STREAMER_BIN_KLASS, "rtp_container")) {
+ __ms_signal_create(&ms_streamer->autoplug_sig_list, found_element, "pad-added", G_CALLBACK(__decodebin_newpad_streamer_cb), ms_streamer);
g_signal_connect(found_element, "pad-added", G_CALLBACK(__decodebin_newpad_streamer_cb), ms_streamer);
- else
+ } else {
+ __ms_signal_create(&ms_streamer->autoplug_sig_list, found_element, "pad-added", G_CALLBACK(__decodebin_newpad_cb), ms_streamer);
g_signal_connect(found_element, "pad-added", G_CALLBACK(__decodebin_newpad_cb), ms_streamer);
-
- g_signal_connect(found_element, "autoplug-select", G_CALLBACK(__ms_decodebin_autoplug_select), NULL);
+ }
+ __ms_signal_create(&ms_streamer->autoplug_sig_list, found_element, "autoplug-select", G_CALLBACK(__ms_decodebin_autoplug_select), NULL);
found_element = __ms_link_with_new_element(unlinked_element, found_element, NULL);
__ms_generate_dots(ms_streamer->pipeline, GST_ELEMENT_NAME(found_element));
- MS_SAFE_UNREF(unlinked_pad);
-
} else {
found_element = __ms_element_create(DEFAULT_QUEUE, NULL);
- gst_bin_add_many((GstBin *) ms_streamer->topology_bin, found_element, NULL);
-
+ __ms_bin_add_element(ms_streamer->topology_bin, found_element, FALSE);
gst_element_sync_state_with_parent(found_element);
found_element = __ms_link_with_new_element(unlinked_element, found_element, NULL);
- __ms_generate_dots(parent, DEFAULT_QUEUE);
/* Check the new pad's type */
new_pad_caps = gst_pad_query_caps(unlinked_pad, 0);
found_element = __ms_combine_next_element(found_element, MEDIA_STREAMER_PAYLOADER_KLASS, NULL, NULL);
found_element = __ms_combine_next_element(found_element, MEDIA_STREAMER_BIN_KLASS, "rtp_container", NULL);
}
- __ms_generate_dots(parent, GST_ELEMENT_NAME(found_element));
+ __ms_generate_dots(ms_streamer->pipeline, GST_ELEMENT_NAME(found_element));
+ gst_caps_unref(new_pad_caps);
}
+ MS_SAFE_UNREF(unlinked_pad);
+ MS_SAFE_UNREF(unlinked_element);
unlinked_pad = gst_bin_find_unlinked_pad(GST_BIN(ms_streamer->src_bin), GST_PAD_SRC);
}
ms_debug("Got a few errors during unprepare [%s] bin.", GST_ELEMENT_NAME(bin));\
ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION;\
}
+ /* Disconnects and clean all autoplug signals */
+ g_list_free_full(ms_streamer->autoplug_sig_list, __ms_signal_destroy);
+ ms_streamer->autoplug_sig_list = NULL;
MS_BIN_UNPREPARE(ms_streamer->src_bin);
MS_BIN_UNPREPARE(ms_streamer->topology_bin);
MS_SAFE_UNREF(ms_streamer->bus);
MS_SAFE_UNREF(ms_streamer->pipeline);
+ MS_SAFE_UNREF(ms_streamer->sink_video_bin);
+ MS_SAFE_UNREF(ms_streamer->sink_audio_bin);
g_mutex_unlock(&ms_streamer->mutex_lock);
g_mutex_clear(&ms_streamer->mutex_lock);
MS_SAFE_FREE(ms_streamer);
- /* gst_deinit(); */
return ret;
}
* limitations under the License.
*/
-#ifndef __MEDIA_STREAMER_UTIL_C__
-#define __MEDIA_STREAMER_UTIL_C__
-
#include <glib/gstdio.h>
#include <media_streamer.h>
__ms_destroy_ini_dictionary(dict);
/* general */
- ms_debug("Media Streamer param [generate_dot] : %d\n", ini->generate_dot);
- ms_debug("Media Streamer param [use_decodebin] : %d\n", ini->use_decodebin);
+ ms_debug("Media Streamer param [generate_dot] : %d", ini->generate_dot);
+ ms_debug("Media Streamer param [use_decodebin] : %d", ini->use_decodebin);
}
static void __ms_check_ini_status(void)
}
}
-#endif
+void __ms_signal_create(GList **sig_list, GstElement *obj, const char *sig_name, GCallback cb, gpointer user_data)
+{
+ ms_retm_if(!sig_list || !obj || !sig_name, "Empty signal data!");
+
+ media_streamer_signal_s *sig_data = (media_streamer_signal_s*) g_try_malloc(sizeof(media_streamer_signal_s));
+ if (!sig_data) {
+ ms_error("Failed to create signal [%s] for object [%s]", sig_name, GST_OBJECT_NAME(obj));
+ return;
+ }
+
+ sig_data->obj = G_OBJECT(obj);
+ sig_data->signal_id = g_signal_connect(sig_data->obj, sig_name, cb, user_data);
+
+ if (sig_data->signal_id > 0) {
+ *sig_list = g_list_append(*sig_list, sig_data);
+ ms_debug("Signal [%s] with id[%lu] connected to object [%s].",
+ sig_name, sig_data->signal_id, GST_OBJECT_NAME(sig_data->obj));
+ } else {
+ ms_error("Failed to connect signal [%s] for object [%s]", sig_name, GST_OBJECT_NAME(obj));
+ }
+}
+
+void __ms_signal_destroy(void *data)
+{
+ media_streamer_signal_s *sig_data = (media_streamer_signal_s *) data;
+ ms_retm_if(!sig_data, "Empty signal data!");
+
+ if (sig_data->obj && GST_IS_ELEMENT(sig_data->obj)) {
+ if (g_signal_handler_is_connected(sig_data->obj, sig_data->signal_id)) {
+ g_signal_handler_disconnect(sig_data->obj, sig_data->signal_id);
+ ms_debug("Signal with id[%lu] disconnected from object [%s].",
+ sig_data->signal_id, GST_OBJECT_NAME(sig_data->obj));
+ }
+ }
+
+ MS_SAFE_GFREE(sig_data);
+}
* limitations under the License.
*/
-#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define DEFAULT_IP_ADDR "127.0.0.1"
#define DEFAULT_SEEK_POS 0
#define MSEC_MULTIPLIER 1000
+#define MAX_NODES_COUNT 50
#define VIDEO_PORT 5000
#define AUDIO_PORT 6000
static media_streamer_h g_media_streamer_2;
static media_streamer_h current_media_streamer = &g_media_streamer;
+media_streamer_node_h g_nodes[MAX_NODES_COUNT] = {0,};
+int g_node_counter = 0;
+#define APPEND_NODE(x) {g_nodes[g_node_counter++] = x; }
+
GMainLoop *g_loop;
gchar *g_broadcast_address = NULL;
media_streamer_node_create_src(MEDIA_STREAMER_NODE_SRC_TYPE_FILE, &file_src);
media_streamer_node_set_param(file_src, MEDIA_STREAMER_PARAM_URI, g_uri);
media_streamer_node_add(current_media_streamer, file_src);
+ APPEND_NODE(file_src);
/*********************** videosink *********************************** */
media_streamer_node_h video_sink = NULL;
media_streamer_node_create_sink(MEDIA_STREAMER_NODE_SINK_TYPE_SCREEN, &video_sink);
media_streamer_node_add(current_media_streamer, video_sink);
+ APPEND_NODE(video_sink);
/*********************** audiosink *********************************** */
media_streamer_node_h audio_sink = NULL;
media_streamer_node_create_sink(MEDIA_STREAMER_NODE_SINK_TYPE_AUDIO, &audio_sink);
media_streamer_node_add(current_media_streamer, audio_sink);
+ APPEND_NODE(audio_sink);
}
static void _create_file_sub_playing()
media_streamer_node_create_src(MEDIA_STREAMER_NODE_SRC_TYPE_FILE, &file_sub_src);
media_streamer_node_set_param(file_sub_src, MEDIA_STREAMER_PARAM_URI, g_uri);
media_streamer_node_add(current_media_streamer, file_sub_src);
+ APPEND_NODE(file_sub_src);
media_streamer_node_h txt_src = NULL;
media_streamer_node_create_src(MEDIA_STREAMER_NODE_SRC_TYPE_FILE, &txt_src);
media_streamer_node_set_param(txt_src, MEDIA_STREAMER_PARAM_URI, g_sub_uri);
media_streamer_node_add(current_media_streamer, txt_src);
+ APPEND_NODE(txt_src);
/*********************** videosink *********************************** */
media_streamer_node_h video_sink = NULL;
media_streamer_node_create_sink(MEDIA_STREAMER_NODE_SINK_TYPE_SCREEN, &video_sink);
media_streamer_node_add(current_media_streamer, video_sink);
+ APPEND_NODE(video_sink);
/*********************** audiosink *********************************** */
media_streamer_node_h audio_sink = NULL;
media_streamer_node_create_sink(MEDIA_STREAMER_NODE_SINK_TYPE_AUDIO, &audio_sink);
media_streamer_node_add(current_media_streamer, audio_sink);
+ APPEND_NODE(audio_sink);
}
static void _create_file_streaming()
media_streamer_node_create_src(MEDIA_STREAMER_NODE_SRC_TYPE_FILE, &file_src);
media_streamer_node_set_param(file_src, MEDIA_STREAMER_PARAM_URI, g_uri);
media_streamer_node_add(current_media_streamer, file_src);
+ APPEND_NODE(file_src);
}
static void _create_http_playing()
media_streamer_node_create_src(MEDIA_STREAMER_NODE_SRC_TYPE_HTTP, &http_src);
media_streamer_node_set_param(http_src, MEDIA_STREAMER_PARAM_URI, g_uri);
media_streamer_node_add(current_media_streamer, http_src);
+ APPEND_NODE(http_src);
/*********************** videosink *********************************** */
media_streamer_node_h video_sink = NULL;
media_streamer_node_create_sink(MEDIA_STREAMER_NODE_SINK_TYPE_SCREEN, &video_sink);
media_streamer_node_add(current_media_streamer, video_sink);
+ APPEND_NODE(video_sink);
/*********************** audiosink *********************************** */
media_streamer_node_h audio_sink = NULL;
media_streamer_node_create_sink(MEDIA_STREAMER_NODE_SINK_TYPE_AUDIO, &audio_sink);
media_streamer_node_add(current_media_streamer, audio_sink);
+ APPEND_NODE(audio_sink);
}
static void _create_rtp_streamer(media_streamer_node_h rtp_bin)
}
media_streamer_node_add(current_media_streamer, video_src);
+ APPEND_NODE(video_src);
/*********************** encoder **************************************** */
media_streamer_node_h video_enc = NULL;
media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_VIDEO_ENCODER, NULL, vfmt_encoded, &video_enc);
media_streamer_node_add(current_media_streamer, video_enc);
+ APPEND_NODE(video_enc);
/*********************** videopay *************************************** */
media_streamer_node_h video_pay = NULL;
media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_VIDEO_PAY, NULL, vfmt_encoded, &video_pay);
media_streamer_node_add(current_media_streamer, video_pay);
+ APPEND_NODE(video_pay);
/*====================Linking Video Streamer=========================== */
media_streamer_node_link(video_src, "src", video_enc, "sink");
}
media_streamer_node_add(current_media_streamer, audio_src);
+ APPEND_NODE(audio_src);
/*********************** audioencoder *********************************** */
media_streamer_node_h audio_enc = NULL;
media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_AUDIO_ENCODER, NULL, NULL, &audio_enc);
media_streamer_node_add(current_media_streamer, audio_enc);
+ APPEND_NODE(audio_enc);
/*********************** rtpL16pay *********************************** */
media_streamer_node_h audio_pay = NULL;
media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_AUDIO_PAY, NULL, NULL, &audio_pay);
media_streamer_node_add(current_media_streamer, audio_pay);
+ APPEND_NODE(audio_pay);
/*====================Linking Audio Streamer========================== */
media_streamer_node_link(audio_src, "src", audio_enc, "sink");
}
media_streamer_node_add(current_media_streamer, video_src);
+ APPEND_NODE(video_src);
g_print("== success streamer_autoplug video part \n");
}
}
media_streamer_node_add(current_media_streamer, audio_src);
+ APPEND_NODE(audio_src);
g_print("== success streamer_autoplug audio part \n");
}
media_streamer_node_h video_depay = NULL;
media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_VIDEO_DEPAY, NULL, vfmt_encoded, &video_depay);
media_streamer_node_add(current_media_streamer, video_depay);
+ APPEND_NODE(video_depay);
/*********************** videodec *********************************** */
media_streamer_node_h video_dec = NULL;
media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_VIDEO_DECODER, NULL, vfmt_encoded, &video_dec);
media_streamer_node_add(current_media_streamer, video_dec);
+ APPEND_NODE(video_dec);
/*********************** videoconvertor *********************************** */
media_streamer_node_h video_conv = NULL;
media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_VIDEO_CONVERTER, NULL, vfmt_encoded, &video_conv);
media_streamer_node_add(current_media_streamer, video_conv);
+ APPEND_NODE(video_conv);
/*********************** videosink *********************************** */
media_streamer_node_h video_sink = NULL;
media_streamer_node_create_sink(MEDIA_STREAMER_NODE_SINK_TYPE_SCREEN, &video_sink);
media_streamer_node_add(current_media_streamer, video_sink);
+ APPEND_NODE(video_sink);
/*====================Linking Video Client=========================== */
media_streamer_node_link(video_depay, "src", video_dec, "sink");
media_streamer_node_h audio_depay = NULL;
media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_AUDIO_DEPAY, NULL, NULL, &audio_depay);
media_streamer_node_add(current_media_streamer, audio_depay);
+ APPEND_NODE(audio_depay);
/*********************** audiodecoder *********************************** */
media_streamer_node_h audio_dec = NULL;
media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_AUDIO_DECODER, NULL, NULL, &audio_dec);
media_streamer_node_add(current_media_streamer, audio_dec);
+ APPEND_NODE(audio_dec);
/*********************** audioconverter *********************************** */
media_streamer_node_h audio_conv = NULL;
media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_AUDIO_CONVERTER, NULL, NULL, &audio_conv);
media_streamer_node_add(current_media_streamer, audio_conv);
+ APPEND_NODE(audio_conv);
/*********************** audiosink *********************************** */
media_streamer_node_h audio_sink = NULL;
media_streamer_node_create_sink(MEDIA_STREAMER_NODE_SINK_TYPE_AUDIO, &audio_sink);
media_streamer_node_add(current_media_streamer, audio_sink);
+ APPEND_NODE(audio_sink);
/*====================Linking Audio Client=========================== */
media_streamer_node_link(audio_depay, "src", audio_dec, "sink");
media_streamer_node_h video_sink = NULL;
media_streamer_node_create_sink(MEDIA_STREAMER_NODE_SINK_TYPE_SCREEN, &video_sink);
media_streamer_node_add(current_media_streamer, video_sink);
+ APPEND_NODE(video_sink);
g_print("== success client_autoplug video part \n");
}
media_streamer_node_h audio_sink = NULL;
media_streamer_node_create_sink(MEDIA_STREAMER_NODE_SINK_TYPE_AUDIO, &audio_sink);
media_streamer_node_add(current_media_streamer, audio_sink);
+ APPEND_NODE(audio_sink);
g_print("== success client_autoplug audio part \n");
}
media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_RTP, NULL, NULL, &rtp_bin);
set_rtp_params(rtp_bin, g_broadcast_address, video_port, audio_port, second_client);
media_streamer_node_add(current_media_streamer, rtp_bin);
+ APPEND_NODE(rtp_bin);
return rtp_bin;
}
media_streamer_node_h app_src = NULL;
media_streamer_node_create_src(MEDIA_STREAMER_NODE_SRC_TYPE_CUSTOM, &app_src);
media_streamer_node_add(current_media_streamer, app_src);
+ APPEND_NODE(app_src);
/*********************** app_sink *********************************** */
media_streamer_node_h app_sink = NULL;
media_streamer_node_create_sink(MEDIA_STREAMER_NODE_SINK_TYPE_CUSTOM, &app_sink);
media_streamer_node_set_pad_format(app_sink, "sink", vfmt_raw);
media_streamer_node_add(current_media_streamer, app_sink);
+ APPEND_NODE(app_sink);
/*====================Linking ======================================== */
media_streamer_node_link(app_src, "src", app_sink, "sink");
g_free(g_sub_uri);
g_sub_uri = NULL;
}
+
+ /* Clean Up Nodes */
+ int i = g_node_counter-1;
+ for (; i >= 0; --i) {
+ media_streamer_node_destroy(g_nodes[i]);
+ g_nodes[i] = NULL;
+ }
+ g_node_counter = 0;
}
void quit()
_create_rtp_client_autoplug(rtp_bin);
else
_create_rtp_client(rtp_bin);
-
break;
case PRESET_VOIP:
rtp_bin = _create_rtp(VIDEO_PORT, AUDIO_PORT, FALSE);
- _create_rtp_streamer(rtp_bin);
- _create_rtp_client(rtp_bin);
+ if (g_autoplug_mode) {
+ _create_rtp_streamer_autoplug(rtp_bin);
+ _create_rtp_client_autoplug(rtp_bin);
+ } else {
+ _create_rtp_streamer(rtp_bin);
+ _create_rtp_client(rtp_bin);
+ }
break;
case PRESET_VOIP_2:
rtp_bin = _create_rtp(VIDEO_PORT, AUDIO_PORT, TRUE);
- _create_rtp_streamer(rtp_bin);
- _create_rtp_client(rtp_bin);
+ if (g_autoplug_mode) {
+ _create_rtp_streamer_autoplug(rtp_bin);
+ _create_rtp_client_autoplug(rtp_bin);
+ } else {
+ _create_rtp_streamer(rtp_bin);
+ _create_rtp_client(rtp_bin);
+ }
break;
case PRESET_DOUBLE_VOIP_SERVER:
rtp_bin = _create_rtp(VIDEO_PORT, AUDIO_PORT, FALSE);
g_loop = g_main_loop_new(NULL, FALSE);
g_main_loop_run(g_loop);
+
+ g_main_loop_unref(g_loop);
+ g_io_channel_unref(stdin_channel);
return 0;
}