/* GStreamer * * Copyright (C) 2010 Wim Taymans * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library 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. */ /* An example of synchronized playback and recording. * The trick is to wait for the playback pipeline to preroll before starting * playback and recording. */ #include #include /* Define to run the asynchronous version, which has the benefit that it doesn't * block the main thread but it produces slightly less clear code. */ #define ASYNC_VERSION static GMainLoop *loop; static GstElement *pipeline = NULL; static GstElement *play_bin, *play_source, *play_sink; static GstElement *rec_bin, *rec_source, *rec_sink; static gboolean message_handler (GstBus * bus, GstMessage * message, gpointer user_data) { switch (GST_MESSAGE_TYPE (message)) { #ifdef ASYNC_VERSION case GST_MESSAGE_ELEMENT:{ const GstStructure *str; str = gst_message_get_structure (message); if (gst_structure_has_name (str, "GstBinForwarded")) { GstMessage *orig; /* unwrap the element message */ gst_structure_get (str, "message", GST_TYPE_MESSAGE, &orig, NULL); g_assert (orig); switch (GST_MESSAGE_TYPE (orig)) { case GST_MESSAGE_ASYNC_DONE: g_print ("ASYNC done %s\n", GST_MESSAGE_SRC_NAME (orig)); if (GST_MESSAGE_SRC (orig) == GST_OBJECT_CAST (play_bin)) { g_print ("prerolled, starting synchronized playback and recording\n"); /* returns ASYNC because the sink linked to the live source is not * prerolled */ if (gst_element_set_state (pipeline, GST_STATE_PLAYING) != GST_STATE_CHANGE_ASYNC) { g_warning ("State change failed"); } } break; default: break; } } break; } #endif case GST_MESSAGE_EOS: g_print ("EOS\n"); g_main_loop_quit (loop); break; case GST_MESSAGE_ERROR:{ GError *err = NULL; gst_message_parse_error (message, &err, NULL); g_print ("error: %s\n", err->message); g_clear_error (&err); g_main_loop_quit (loop); break; } default: break; } return TRUE; } int main (int argc, char *argv[]) { GstBus *bus; gint watch_id; gst_init (NULL, NULL); loop = g_main_loop_new (NULL, TRUE); pipeline = gst_pipeline_new ("pipeline"); #ifdef ASYNC_VERSION /* this enables messages of individual elements inside the pipeline */ g_object_set (pipeline, "message-forward", TRUE, NULL); #endif /* make a bin with the playback elements this is a non-live pipeline */ play_bin = gst_bin_new ("play_bin"); play_source = gst_element_factory_make ("audiotestsrc", "play_source"); play_sink = gst_element_factory_make ("autoaudiosink", "play_sink"); gst_bin_add (GST_BIN (play_bin), play_source); gst_bin_add (GST_BIN (play_bin), play_sink); gst_element_link (play_source, play_sink); /* make bin with the record elements, this is a live pipeline */ rec_bin = gst_bin_new ("rec_bin"); rec_source = gst_element_factory_make ("autoaudiosrc", "rec_source"); rec_sink = gst_element_factory_make ("fakesink", "rec_sink"); gst_bin_add (GST_BIN (rec_bin), rec_source); gst_bin_add (GST_BIN (rec_bin), rec_sink); gst_element_link (rec_source, rec_sink); gst_bin_add (GST_BIN (pipeline), play_bin); gst_bin_add (GST_BIN (pipeline), rec_bin); bus = gst_element_get_bus (pipeline); watch_id = gst_bus_add_watch (bus, message_handler, NULL); gst_object_unref (bus); g_print ("going to PAUSED\n"); /* returns NO_PREROLL because we have a live element */ if (gst_element_set_state (pipeline, GST_STATE_PAUSED) != GST_STATE_CHANGE_NO_PREROLL) { g_warning ("Expected state change NO_PREROLL result"); } g_print ("waiting for playback preroll\n"); #ifndef ASYNC_VERSION /* sync wait for preroll on the playback bin and then go to PLAYING */ if (gst_element_get_state (play_bin, NULL, NULL, GST_CLOCK_TIME_NONE) != GST_STATE_CHANGE_SUCCESS) { g_warning ("Error while waiting for state change"); } g_print ("prerolled, starting synchronized playback and recording\n"); /* returns ASYNC because the sink linked to the live source is not * prerolled */ if (gst_element_set_state (pipeline, GST_STATE_PLAYING) != GST_STATE_CHANGE_ASYNC) { g_warning ("Expected state change NO_PREROLL result"); } #endif g_main_loop_run (loop); g_source_remove (watch_id); gst_element_set_state (pipeline, GST_STATE_NULL); gst_object_unref (pipeline); g_main_loop_unref (loop); return 0; }