From dcdbe199fc85f798863a534aa9040741c0f92dec Mon Sep 17 00:00:00 2001 From: Sjoerd Simons Date: Thu, 10 Feb 2011 13:24:34 +0000 Subject: Add a C example of tp-farstream usage --- examples/Makefile.am | 20 +++ examples/call-handler.c | 325 ++++++++++++++++++++++++++++++++++++++++++++ examples/codec-preferences | 50 +++++++ examples/element-properties | 62 +++++++++ 4 files changed, 457 insertions(+) create mode 100644 examples/Makefile.am create mode 100644 examples/call-handler.c create mode 100644 examples/codec-preferences create mode 100644 examples/element-properties (limited to 'examples') diff --git a/examples/Makefile.am b/examples/Makefile.am new file mode 100644 index 0000000..eba7bb7 --- /dev/null +++ b/examples/Makefile.am @@ -0,0 +1,20 @@ +noinst_PROGRAMS = call-handler + +LDADD = \ + $(GLIB_LIBS) \ + $(DBUS_LIBS) \ + $(GST_LIBS) \ + $(FARSIGHT2_LIBS) \ + $(TELEPATHY_LIBS) \ + ../telepathy-farstream/libtelepathy-farstream.la \ + ../extensions/libfuture-extensions.la + +AM_CFLAGS = \ + $(ERROR_CFLAGS) \ + $(GLIB_CFLAGS) \ + $(DBUS_CFLAGS) \ + $(GST_CFLAGS) \ + $(FARSIGHT2_CFLAGS) \ + $(TELEPATHY_CFLAGS) \ + -I$(top_srcdir) \ + -I$(top_builddir) diff --git a/examples/call-handler.c b/examples/call-handler.c new file mode 100644 index 0000000..4f9a636 --- /dev/null +++ b/examples/call-handler.c @@ -0,0 +1,325 @@ +/* + * call-handler.c + * Copyright (C) 2011 Collabora Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include + +typedef struct { + GstElement *pipeline; + guint buswatch; + TpChannel *proxy; + TfChannel *channel; + FsElementAddedNotifier *notifier; +} ChannelContext; + +GMainLoop *loop; + +static gboolean +bus_watch_cb (GstBus *bus, + GstMessage *message, + gpointer user_data) +{ + ChannelContext *context = user_data; + + if (context->channel != NULL) + tf_channel_bus_message (context->channel, message); + + return TRUE; +} + +static void +src_pad_added_cb (TfContent *content, + TpHandle handle, + FsStream *stream, + GstPad *pad, + FsCodec *codec, + gpointer user_data) +{ + ChannelContext *context = user_data; + gchar *cstr = fs_codec_to_string (codec); + FsMediaType mtype; + GstPad *sinkpad; + GstElement *element; + + g_debug ("New src pad: %s", cstr); + g_object_get (content, "media-type", &mtype, NULL); + + switch (mtype) + { + case FS_MEDIA_TYPE_AUDIO: + element = gst_parse_bin_from_description ( + "audioconvert ! audioresample ! audioconvert ! autoaudiosink", + TRUE, NULL); + break; + case FS_MEDIA_TYPE_VIDEO: + element = gst_parse_bin_from_description ( + "ffmpegcolorspace ! videoscale ! autovideosink", + TRUE, NULL); + break; + default: + g_warning ("Unknown media type"); + return; + } + + gst_bin_add (GST_BIN (context->pipeline), element); + sinkpad = gst_element_get_pad (element, "sink"); + gst_element_set_state (element, GST_STATE_PLAYING); + gst_pad_link (pad, sinkpad); + + g_object_unref (sinkpad); +} + + +static void +content_added_cb (TfChannel *channel, + TfContent *content, + gpointer user_data) +{ + GstPad *srcpad, *sinkpad; + FsMediaType mtype; + GstElement *element; + GList *codecs; + ChannelContext *context = user_data; + + g_debug ("Content added"); + + codecs = fs_codec_list_from_keyfile ("codec-preferences", NULL); + + tf_content_set_codec_preferences (content, codecs, NULL); + + g_object_get (content, + "sink-pad", &sinkpad, + "media-type", &mtype, + NULL); + + switch (mtype) + { + case FS_MEDIA_TYPE_AUDIO: + element = gst_parse_bin_from_description ( + "audiotestsrc is-live=1 ! audio/x-raw-int,rate=8000 ! queue", + TRUE, NULL); + break; + case FS_MEDIA_TYPE_VIDEO: + element = gst_parse_bin_from_description ( + "videotestsrc is-live=1 ! " \ + "video/x-raw-yuv,width=640, height=480 ! queue", + TRUE, NULL); + break; + default: + g_warning ("Unknown media type"); + goto out; + } + + g_signal_connect (content, "src-pad-added", + G_CALLBACK (src_pad_added_cb), context); + + gst_bin_add (GST_BIN (context->pipeline), element); + srcpad = gst_element_get_pad (element, "src"); + gst_pad_link (srcpad, sinkpad); + + gst_element_set_state (element, GST_STATE_PLAYING); + + g_object_unref (srcpad); +out: + g_object_unref (sinkpad); +} + +static void +conference_added_cb (TfChannel *channel, + GstElement *conference, + gpointer user_data) +{ + ChannelContext *context = user_data; + + g_debug ("Conference added"); + + gst_bin_add (GST_BIN (context->pipeline), conference); + gst_element_set_state (conference, GST_STATE_PLAYING); +} + +static gboolean +dump_pipeline_cb (gpointer data) +{ + ChannelContext *context = data; + + GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (context->pipeline), + GST_DEBUG_GRAPH_SHOW_ALL, + "call-handler"); + + return TRUE; +} + +static void +new_tf_channel_cb (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + ChannelContext *context = user_data; + + g_debug ("New TfChannel"); + + context->channel = TF_CHANNEL (g_async_initable_new_finish ( + G_ASYNC_INITABLE (source), result, NULL)); + + + if (context->channel == NULL) + { + g_warning ("Failed to create channel"); + return; + } + + g_debug ("Adding timeout"); + g_timeout_add_seconds (5, dump_pipeline_cb, context); + + g_signal_connect (context->channel, "fs-conference-added", + G_CALLBACK (conference_added_cb), context); + + g_signal_connect (context->channel, "content-added", + G_CALLBACK (content_added_cb), context); +} + +static void +proxy_invalidated_cb (TpProxy *proxy, + guint domain, + gint code, + gchar *message, + gpointer user_data) +{ + ChannelContext *context = user_data; + + g_debug ("Channel closed"); + if (context->pipeline != NULL) + { + gst_element_set_state (context->pipeline, GST_STATE_NULL); + g_object_unref (context->pipeline); + } + + if (context->channel != NULL) + g_object_unref (context->channel); + + if (context->notifier != NULL) + g_object_unref (context->notifier); + + g_object_unref (context->proxy); + + g_slice_free (ChannelContext, context); + + g_main_loop_quit (loop); +} + +static void +new_call_channel_cb (TpSimpleHandler *handler, + TpAccount *account, + TpConnection *connection, + GList *channels, + GList *requests_satisfied, + gint64 user_action_time, + TpHandleChannelsContext *handler_context, + gpointer user_data) +{ + ChannelContext *context = g_slice_new0 (ChannelContext); + TpChannel *proxy; + + g_debug ("New channel"); + + proxy = channels->data; + + context->pipeline = gst_pipeline_new (NULL); + context->buswatch = gst_bus_add_watch ( + gst_pipeline_get_bus (GST_PIPELINE (context->pipeline)), + bus_watch_cb, + context); + context->notifier = fs_element_added_notifier_new (); + + fs_element_added_notifier_set_properties_from_file (context->notifier, + "element-properties", NULL); + fs_element_added_notifier_add (context->notifier, + GST_BIN (context->pipeline)); + + gst_element_set_state (context->pipeline, GST_STATE_PLAYING); + + tf_channel_new_async (proxy, new_tf_channel_cb, context); + + tp_handle_channels_context_accept (handler_context); + + tf_future_cli_channel_type_call_call_accept (proxy, -1, + NULL, NULL, NULL, NULL); + + context->proxy = g_object_ref (proxy); + g_signal_connect (proxy, "invalidated", + G_CALLBACK (proxy_invalidated_cb), + context); +} + +int +main (int argc, char **argv) +{ + TpBaseClient *client; + TpDBusDaemon *bus; + + g_type_init (); + tf_init (); + gst_init (&argc, &argv); + + loop = g_main_loop_new (NULL, FALSE); + + bus = tp_dbus_daemon_dup (NULL); + + client = tp_simple_handler_new (bus, + FALSE, + FALSE, + "TpFsCallHandlerDemo", + TRUE, + new_call_channel_cb, + NULL, + NULL); + + tp_base_client_take_handler_filter (client, + tp_asv_new ( + TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, + TF_FUTURE_IFACE_CHANNEL_TYPE_CALL, + TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, + TP_HANDLE_TYPE_CONTACT, + TF_FUTURE_PROP_CHANNEL_TYPE_CALL_INITIAL_AUDIO, G_TYPE_BOOLEAN, + TRUE, + NULL)); + + tp_base_client_take_handler_filter (client, + tp_asv_new ( + TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, + TF_FUTURE_IFACE_CHANNEL_TYPE_CALL, + TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, + TP_HANDLE_TYPE_CONTACT, + TF_FUTURE_PROP_CHANNEL_TYPE_CALL_INITIAL_VIDEO, G_TYPE_BOOLEAN, + TRUE, + NULL)); + + tp_base_client_register (client, NULL); + + g_main_loop_run (loop); + + g_object_unref (bus); + g_object_unref (client); + g_main_loop_unref (loop); + + return 0; +} diff --git a/examples/codec-preferences b/examples/codec-preferences new file mode 100644 index 0000000..fbd8ad5 --- /dev/null +++ b/examples/codec-preferences @@ -0,0 +1,50 @@ +# Favorite audio codecs + +[audio/SPEEX:8000] +clock-rate=8000 + +[audio/SPEEX:16000] +clock-rate=16000 + +[audio/AMR] + +[audio/G729] + +[audio/ILBC] + +# Disabled audio codecs + +[audio/DV] +id=-1 + +[audio/MPA] +id=-1 + +[audio/VORBIS] +id=-1 + +[audio/MP3] +id=-1 + + +# Favorite video codecs + +# We like freedom and the future (proof of concept VP8 payloading) +[video/X-VP8-GST] + +# but keep an eye on people living in the past +[video/H264] + +[video/H263] + +[video/THEORA] + +# Disable the ones we don't want +[video/JPEG] +id=-1 + +[video/DV] +id=-1 + +[video/MPV] +id=-1 diff --git a/examples/element-properties b/examples/element-properties new file mode 100644 index 0000000..40f706d --- /dev/null +++ b/examples/element-properties @@ -0,0 +1,62 @@ +# Put the desired properties in the style of +# +# [element name] +# prop1=val1 + +[gstrtpbin] +latency=100 + +[x264enc] +byte-stream=1 +bframes=0 +b-adapt=0 +cabac=0 +dct8x8=0 +bitrate=256 +# tuned for zero latency +tune=0x4 +profile=1 +speed-preset=3 +sliced-threads=false + +[ffenc_h263] +rtp-payload-size=1 + +[theoraenc] +bitrate=256 + +[vp8enc] +bitrate=256000 +max-latency=1 +speed=2 +error-resilient=true + +# Work around bug in the re-timestamp slaving method in +# GStreamer (2 is skew) +[alsasrc] +slave-method=2 + +[osssrc] +slave-method=2 + +[oss4src] +slave-method=2 + +[sunaudiosrc] +slave-method=2 + +[rtph264pay] +config-interval=5 + +[rtppcmupay] +ptime-multiple=20000000 + +[rtppcmapay] +ptime-multiple=20000000 + +[gstrtpjitterbuffer] +do-lost=1 + +[ewh264enc] +profile=baseline +quality=5 -- cgit v1.2.1