[gst-devel] [Bug 87882] New - state change in top-level thread not passed down to child bin

bugzilla-daemon at widget.gnome.org bugzilla-daemon at widget.gnome.org
Thu Jul 11 11:04:05 CEST 2002


Please do not reply to this email- if you want to comment on the bug, go to the
URL shown below and enter your comments there.

http://bugzilla.gnome.org/show_bug.cgi?id=87882

Changed by mromaine at parc.com.

--- shadow/87882	Wed Jul 10 20:12:14 2002
+++ shadow/87882.tmp.31684	Wed Jul 10 20:12:14 2002
@@ -0,0 +1,246 @@
+Bug#: 87882
+Product: GStreamer
+Version: 0.4.0
+OS: Linux
+OS Details: nothing special
+Status: NEW   
+Resolution: 
+Severity: major
+Priority: Normal
+Component: gstreamer (core)
+AssignedTo: gstreamer-maint at bugzilla.gnome.org                            
+ReportedBy: mromaine at parc.com               
+QAContact: gstreamer-maint at bugzilla.gnome.org
+TargetMilestone: 0.4.0
+URL: 
+Cc: 
+Summary: state change in top-level thread not passed down to child bin
+
+The following are two files to demonstrate that a bin (containing a
+filesrc, mad decoder, and volume filter) inside a thread which connects the
+bin to an osssink, does not stop when the bin is passed GST_STATE_PAUSED. 
+Essentially, it seems the thread's state override's the child's state. 
+Debugging output (and further gdb checking) verifies that the bin is
+receiving the correct state-change information, but the loop cycle does not
+seem to recognize this.
+
+This example uses gtk for a simple gui
+
+--------------------- file with main(...) -------------------------
+#include <gtk/gtk.h>
+#include "mixer.h"
+
+#ifndef EXIT_FAILURE
+#define EXIT_FAILURE -1
+#endif
+
+gint delete_event (GtkWidget *widget, GdkEvent *event, gpointer data)
+{
+    gtk_main_quit();
+    return FALSE;
+}
+
+static void play_src(GtkWidget *widget, gpointer data)
+{
+    start_channel ();
+}
+
+static void pause_src(GtkWidget *widget, gpointer data)
+{
+    pause_channel ();
+}
+
+static void quit(void)
+{
+    quit_everything();
+    gtk_main_quit();
+}
+
+int main( int argc, char *argv[])
+{
+    GtkWidget *window, *mainvbox;
+    GtkWidget *control_buttons_hbox;
+    GtkWidget *play_button, *pause_button;
+    GtkWidget *quit_button;
+
+    if (argc == 1)
+    {
+        g_print ("usage: %s <filename1> \n", argv[0]);
+        exit(EXIT_FAILURE);
+    }
+
+    gtk_init (&argc, &argv);
+
+    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+    gtk_window_set_title (GTK_WINDOW (window), "Tester");
+
+    /* When the window is given the "delete_event" signal (this is given
+     * by the window manager, usually by the "close" option, or on the
+     * titlebar), we ask it to call the delete_event () function
+     * as defined above. The data passed to the callback
+     * function is NULL and is ignored in the callback function. */
+    g_signal_connect (G_OBJECT (window), "delete_event",
+                      G_CALLBACK (delete_event), NULL); 
+
+    gtk_container_set_border_width (GTK_CONTAINER (window), 5);
+
+    /* main vbox that will hold main hbox (needed so that quit button appears
+     * below everything) */
+    mainvbox = gtk_vbox_new (FALSE, 5);
+    gtk_container_add (GTK_CONTAINER (window), mainvbox);
+
+    play_button = gtk_button_new_with_label("play");
+    g_signal_connect (G_OBJECT (play_button), "clicked",
+            G_CALLBACK (play_src), NULL);
+
+    pause_button = gtk_button_new_with_label("pause");
+    g_signal_connect (G_OBJECT (pause_button), "clicked",
+            G_CALLBACK (pause_src), NULL);
+
+    /* create container for control buttons */
+    control_buttons_hbox = gtk_hbox_new (TRUE, 5);
+    gtk_box_pack_start (GTK_BOX (mainvbox), control_buttons_hbox,
+            FALSE, FALSE, 5);
+
+    gtk_container_add (GTK_CONTAINER (control_buttons_hbox), play_button);
+    gtk_container_add (GTK_CONTAINER (control_buttons_hbox), pause_button);
+
+    gtk_widget_show (play_button);
+    gtk_widget_show (pause_button);
+    gtk_widget_show (control_buttons_hbox);
+
+    /* create quit button */
+    quit_button = gtk_button_new_with_label ("quit");
+    g_signal_connect (G_OBJECT (quit_button), "clicked",
+            G_CALLBACK (quit), NULL);
+    gtk_box_pack_start (GTK_BOX(mainvbox), quit_button, FALSE, FALSE, 5);
+
+    gtk_widget_show (quit_button);
+    gtk_widget_show (mainvbox);
+
+    gtk_window_set_default_size (GTK_WINDOW (window), 100, 100);
+    gtk_widget_show (window);
+
+    init_mixer (argc, argv);
+
+    gtk_main ();
+
+    return 0;
+}
+
+--------------------- mixer.c: where elements are created and stored -----
+
+#include <gst/gst.h>
+
+static GstElement *main_thread;
+static GstElement *channel_bin;
+static GstElement *audiosink;
+static GstElement *filesrc, *mad_decoder, *volume;
+
+init_mixer (int argc, char* argv[])
+{
+    GstPad *temp_pad; /* for connecting to adder */
+
+    gst_init (&argc, &argv);
+    gst_control_init (&argc, &argv);
+
+    /* create main thread to process everything.
+     * this thread will hold a bin and an osssink.
+     * the bin will hold a filesrc, mad, and volume.
+     * a ghost pad will connect the volume's output to
+     * the osssink. */
+    main_thread = gst_thread_new ("mixer_thread");
+    g_assert (main_thread != NULL);
+
+    /* create bin to hold filesrc, volume, and mad */
+    channel_bin = gst_bin_new ("channel_bin");
+    g_assert (channel_bin != NULL);
+
+    /* create a filesrc reader (goes into bin) */
+    filesrc = gst_element_factory_make ("filesrc", "filesrc");
+    g_assert (filesrc != NULL);
+    g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL);
+
+    /* create a decoder */
+    mad_decoder = gst_element_factory_make ("mad", "mpg123_decoder");
+    g_assert (mad_decoder != NULL);
+
+    /* create a volume controller */
+    volume = gst_element_factory_make ("volume", "volume");
+    g_assert (volume != NULL);
+
+    /* add main part of audio processing to the bin */
+    gst_bin_add_many (GST_BIN (channel_bin),
+                      filesrc,
+                      mad_decoder,
+                      volume,
+                      NULL);
+
+    /* actually connect the elements */
+    gst_element_connect_many (filesrc, mad_decoder, volume, NULL);
+
+    /* add ghost pad to connect bin to osssink which is held
+     * in mixer_thread */
+    gst_element_add_ghost_pad (channel_bin,
+                               gst_element_get_pad (volume, "src"),
+                               "channel_bin_output");
+
+    /* create our audio sink for final output */
+    audiosink = gst_element_factory_make ("osssink", "play_audio");
+    g_assert (audiosink != NULL);
+
+    temp_pad = gst_element_get_static_pad (audiosink, "sink");
+    g_assert (temp_pad != NULL);
+
+    /* try to connect the ghost pad from the channel bin to the
+     * audiosink intake pad */
+    if (!gst_pad_connect (gst_element_get_pad (channel_bin,
+                                               "channel_bin_output"),
+                                               temp_pad))
+    {
+        g_print ("error connecting pads!\n");
+    }
+
+    gst_bin_add (GST_BIN (main_thread), GST_ELEMENT (channel_bin));
+    gst_bin_add (GST_BIN (main_thread), GST_ELEMENT (audiosink));
+
+    /* we turn on all pipelines/bins/threads */
+    gst_element_set_state (main_thread, GST_STATE_PLAYING);
+    gst_element_set_state (channel_bin, GST_STATE_PLAYING);
+
+    /* print out the schedule? */
+    gst_scheduler_show (GST_ELEMENT_SCHED (main_thread));
+
+}
+
+void
+start_channel (void)
+{
+    g_print ("starting audio\n");
+    gst_element_set_state (GST_ELEMENT (channel_bin), GST_STATE_PLAYING);
+}
+
+void
+pause_channel (void)
+{
+    g_print ("pausing audio\n");
+    gst_element_set_state (GST_ELEMENT (channel_bin), GST_STATE_PAUSED);
+}
+
+void
+quit_everything(void)
+{
+
+    gst_object_destroy (GST_OBJECT (main_thread));
+
+    gst_main_quit();
+}
+
+------------- mixer.h, as needed by gainctl.c -------------
+#ifndef MIXER_HEADER_
+#define MIXER_HEADER_
+
+void start_channel (void);
+void pause_channel (void);
+
+#endif





More information about the gstreamer-devel mailing list