| /* GStreamer | |
| * | |
| * Copyright (C) 2010 Wim Taymans <wim.taymans@collabora.co.uk> | |
| * | |
| * 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 <string.h> | |
| #include <gst/gst.h> | |
| /* 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; | |
| } |