After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 87882 - state change in top-level thread not passed down to child bin
state change in top-level thread not passed down to child bin
Status: RESOLVED WONTFIX
Product: GStreamer
Classification: Platform
Component: gstreamer (core)
0.4.0
Other Linux
: Normal major
: 0.4.0
Assigned To: GStreamer Maintainers
Andy Wingo
Depends on:
Blocks:
 
 
Reported: 2002-07-11 00:12 UTC by matt romaine
Modified: 2004-12-22 21:47 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
main(....) part of test program (2.73 KB, text/plain)
2002-07-11 17:45 UTC, matt romaine
Details
mixer -- where pipelines are created (2.98 KB, text/plain)
2002-07-11 17:46 UTC, matt romaine
Details

Description matt romaine 2002-07-11 00:12:13 UTC
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
Comment 1 matt romaine 2002-07-11 17:45:50 UTC
Created attachment 9813 [details]
main(....) part of test program
Comment 2 matt romaine 2002-07-11 17:46:33 UTC
Created attachment 9814 [details]
mixer -- where pipelines are created
Comment 3 Wim Taymans 2002-10-25 17:45:46 UTC
doing state changes across threads is not yet supported, you could
however change the channel_bin state in the post/pre iterate callback.
You also have to make sure, the sinkpad of audiosink is made inactive
with gst_pad_set_active (pad, FALSE) so that osssink doesn't pull
anymore buffers from the disabled pipeline.

This cannot be improved without making a clear design doc about how we
do out of thread pipeline manipulation first.