#include #include #include #include /* these are the caps we are going to pass through the appsink and appsrc */ const gchar *audio_caps = "audio/x-raw,format=S16LE,channels=1,rate=8000, layout=interleaved"; typedef struct { GMainLoop *loop; GstElement *source; GstElement *sink; } ProgramData; /* called when the appsink notifies us that there is a new buffer ready for * processing */ static GstFlowReturn on_new_sample_from_sink (GstElement * elt, ProgramData * data) { GstSample *sample; GstBuffer *app_buffer, *buffer; GstElement *source; GstFlowReturn ret; /* get the sample from appsink */ sample = gst_app_sink_pull_sample (GST_APP_SINK (elt)); buffer = gst_sample_get_buffer (sample); /* make a copy */ app_buffer = gst_buffer_copy (buffer); /* we don't need the appsink sample anymore */ gst_sample_unref (sample); /* get source an push new buffer */ source = gst_bin_get_by_name (GST_BIN (data->sink), "testsource"); ret = gst_app_src_push_buffer (GST_APP_SRC (source), app_buffer); gst_object_unref (source); return ret; } /* called when we get a GstMessage from the source pipeline when we get EOS, we * notify the appsrc of it. */ static gboolean on_source_message (GstBus * bus, GstMessage * message, ProgramData * data) { GstElement *source; switch (GST_MESSAGE_TYPE (message)) { case GST_MESSAGE_EOS: g_print ("The source got dry\n"); source = gst_bin_get_by_name (GST_BIN (data->sink), "testsource"); gst_app_src_end_of_stream (GST_APP_SRC (source)); gst_object_unref (source); break; case GST_MESSAGE_ERROR: g_print ("Received error\n"); g_main_loop_quit (data->loop); break; default: break; } return TRUE; } /* called when we get a GstMessage from the sink pipeline when we get EOS, we * exit the mainloop and this testapp. */ static gboolean on_sink_message (GstBus * bus, GstMessage * message, ProgramData * data) { /* nil */ switch (GST_MESSAGE_TYPE (message)) { case GST_MESSAGE_EOS: g_print ("Finished playback\n"); g_main_loop_quit (data->loop); break; case GST_MESSAGE_ERROR: g_print ("Received error\n"); g_main_loop_quit (data->loop); break; default: break; } return TRUE; } int main (int argc, char *argv[]) { gchar *filename = NULL; ProgramData *data = NULL; gchar *string = NULL; GstBus *bus = NULL; GstElement *testsink = NULL; GstElement *testsource = NULL; gst_init (&argc, &argv); if (argc == 2) filename = g_strdup (argv[1]); else filename = g_strdup ("/usr/share/sounds/ekiga/ring.wav"); data = g_new0 (ProgramData, 1); data->loop = g_main_loop_new (NULL, FALSE); /* setting up source pipeline, we read from a file and convert to our desired * caps. */ string = g_strdup_printf ("filesrc location=\"%s\" ! wavparse ! audioconvert ! audioresample ! appsink caps=\"%s\" name=testsink", filename, audio_caps); g_free (filename); data->source = gst_parse_launch (string, NULL); g_free (string); if (data->source == NULL) { g_print ("Bad source\n"); return -1; } /* to be notified of messages from this pipeline, mostly EOS */ bus = gst_element_get_bus (data->source); gst_bus_add_watch (bus, (GstBusFunc) on_source_message, data); gst_object_unref (bus); /* we use appsink in push mode, it sends us a signal when data is available * and we pull out the data in the signal callback. We want the appsink to * push as fast as it can, hence the sync=false */ testsink = gst_bin_get_by_name (GST_BIN (data->source), "testsink"); g_object_set (G_OBJECT (testsink), "emit-signals", TRUE, "sync", FALSE, NULL); g_signal_connect (testsink, "new-sample", G_CALLBACK (on_new_sample_from_sink), data); gst_object_unref (testsink); /* setting up sink pipeline, we push audio data into this pipeline that will * then play it back using the default audio sink. We have no blocking * behaviour on the src which means that we will push the entire file into * memory. */ string = g_strdup_printf ("appsrc name=testsource caps=\"%s\" ! autoaudiosink", audio_caps); data->sink = gst_parse_launch (string, NULL); g_free (string); if (data->sink == NULL) { g_print ("Bad sink\n"); return -1; } testsource = gst_bin_get_by_name (GST_BIN (data->sink), "testsource"); /* configure for time-based format */ g_object_set (testsource, "format", GST_FORMAT_TIME, NULL); /* uncomment the next line to block when appsrc has buffered enough */ /* g_object_set (testsource, "block", TRUE, NULL); */ gst_object_unref (testsource); bus = gst_element_get_bus (data->sink); gst_bus_add_watch (bus, (GstBusFunc) on_sink_message, data); gst_object_unref (bus); /* launching things */ gst_element_set_state (data->sink, GST_STATE_PLAYING); gst_element_set_state (data->source, GST_STATE_PLAYING); /* let's run !, this loop will quit when the sink pipeline goes EOS or when an * error occurs in the source or sink pipelines. */ g_print ("Let's run!\n"); g_main_loop_run (data->loop); g_print ("Going out\n"); gst_element_set_state (data->source, GST_STATE_NULL); gst_element_set_state (data->sink, GST_STATE_NULL); gst_object_unref (data->source); gst_object_unref (data->sink); g_main_loop_unref (data->loop); g_free (data); return 0; }