Output to multiple audio sinks does not work - modified AudioPlayerTutorial example

1,551 views
Skip to first unread message

greenender

unread,
Oct 15, 2010, 2:24:23 PM10/15/10
to gstreamer-java
Hi,

I have written a small program, which is a modification of
AudioPlayerTutorial example. The main goal was to play the same audio
to two different sound cards.

The only difference between the tutorial example and my program is
audioSink. Instead of using default audioSink, I created a a Bin
element, with Tee element and one or two "fakesink" elements,
depending how "multipleSinks" variable is set.

When only one "fakesink" element is used (multipleSinks =false),
everything works as expected. The program output is:
Pipeline state changed from NULL to READY
Pipeline state changed from READY to PAUSED
Pipeline state changed from PAUSED to PLAYING
Finished playing file

But if you use two "fakesink" elements (multipleSink = true), the
ouput you get is:
Pipeline state changed from NULL to READY

And that's it. I fought several hours with this, but the result is
always the same. Two "fakesink" elements - no way you can get the
PlayBin to play.

Here is the simplified source code:

public class AudioPlayerTest {

public static boolean multipleSinks = true;

public static void main(String[] args) {
args = Gst.init("AudioPlayerTest", args);
final PlayBin playbin = new PlayBin("AudioPlayer");
playbin.setInputFile(new File("D://intro.mp3"));
playbin.setVideoSink(ElementFactory.make("fakesink",
"videosink"));

Bin audioSinkBin = new Bin();
Element element1 = ElementFactory.make("fakesink",
"audiosink1");
Element element2 = ElementFactory.make("fakesink",
"audiosink2");
Element tee = ElementFactory.make("tee", "myTee");

audioSinkBin.add(tee);
audioSinkBin.add(element1);
if (multipleSinks) {
audioSinkBin.add(element2);
}
GhostPad gpad = new GhostPad("sink",PadDirection.SINK );
gpad.setTarget(tee.getPad("sink"));
audioSinkBin.addPad(gpad);

tee.link(element1);
if (multipleSinks) {
tee.link(element2);
}
playbin.setAudioSink(audioSinkBin);
playbin.getBus().connect(new Bus.EOS() {
public void endOfStream(GstObject source) {
System.out.println("Finished playing file");
Gst.quit();
}
});
playbin.getBus().connect(new Bus.STATE_CHANGED() {
public void stateChanged(GstObject source, State old,
State current, State pending) {
if (source == playbin) {
System.out.println("Pipeline state changed from "
+ old + " to " + current);
}
}
});

playbin.setState(State.PLAYING);
Gst.main();
}
}


Can you please help me out ? I'm totally stuck with this... :(((

Dave Liu

unread,
Oct 16, 2010, 3:16:46 AM10/16/10
to gstreamer-java
Try adding a queue element before each fakesink (after the tee). What
you have at the moment is equivalent to:

gst-launch filesrc location=foobar.mp3 ! decodebin ! tee name=a a. !
audioconvert ! audioresample ! autoaudiosink a. ! fakesink

but what you need is the following:

gst-launch filesrc location=foobar.mp3 ! decodebin ! tee name=a a. !
queue ! audioconvert ! audioresample ! autoaudiosink a. ! queue !
fakesink

Hope this helps!

greenender

unread,
Oct 16, 2010, 6:11:20 AM10/16/10
to gstreamer-java
That's it, thanks!

Following your suggestion, I added 2 queue elements:
Element queue1 = ElementFactory.make("queue", "queue1");
Element queue2 = ElementFactory.make("queue", "queue2");

And now it works :D Thank You!!!

greenender

unread,
Oct 19, 2010, 8:11:05 AM10/19/10
to gstreamer-java
There is still a small problem ...

I want to be able to disable a sink, on demand. In this example, we
have 2 audio sinks.
Is there a way to disable a chosen queue/sink? Or maybe there is
another element (on/off?),
which should be added in between ?

PS.
I had the idea to do it like this - first add all elements to the bin,
and then link only chosen queues to tee:

bin.add(tee);
Element element1 = ElementFactory.make("alsasink", "a1");
Element queue1 = ElementFactory.make("queue", "q1");
bin.add(element1);
bin.add(queue1);

Element element2 = ElementFactory.make("alsasink", "a2");
Element queue2 = ElementFactory.make("queue", "q2");
bin.add(element2);
bin.add(queue2);

tee.link(queue1);
queue1.link(element1);
playbin.setState(State.PLAYING);

But this solution does not work - playbin does not start at all
(when all queues/elements are linked - it works of course) :(

greenender

unread,
Oct 21, 2010, 10:51:18 AM10/21/10
to gstreamer-java
I found a solution (workaround?). To disable a sink, add an "identity"
element before sink,
with drop_probability set to 1.

Looks like a workaround - there probably should be another element
type for this ...

Nagy István

unread,
Oct 22, 2010, 4:00:04 AM10/22/10
to gstream...@googlegroups.com
Why don't you try to unlink the sink and it's queue? You can do this, by placing a block on the tee's source pad which provides the audio stream to the queue, set the queue's state to null, then unlink their pads.

I did it this way in my testing code. You have to get a request pad from the tee when connecting it to the sink, so you can block it later.

        // Add a Null audio output so pipeline can run without audio hardware
        Element fakeOutput = ElementFactory.make("fakesink", "FakeOutput");
        pipe.add(fakeOutput);
        fakeOutput.syncStateWithParent();
        Element fakeQueue = ElementFactory.make("queue","FakeQueue");
        pipe.add(fakeQueue);
        fakeOutput.set("sync", true); // run with realtime clock!
        fakeQueue.syncStateWithParent();
        fakeQueue.link(fakeOutput);
        Pad fakeSink = fakeQueue.getStaticPad("sink");
        Pad teeOutPadToFake = tee.getRequestPad("src%d");
        teeOutPadToFake.link(fakeSink);

Then you can remove fakesink later while the pipeline is running this way:

        teeOutPadToFake.setBlocked(true);
        fakeQueue.setState(State.NULL);
        teeOutPadToFake.unlink(fakeSink);
        tee.releaseRequestPad(teeOutPadToFake);

István

--
You received this message because you are subscribed to the Google Groups "gstreamer-java" group.
To post to this group, send email to gstream...@googlegroups.com.
To unsubscribe from this group, send email to gstreamer-jav...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/gstreamer-java?hl=en.


Wiktor Lisowicz

unread,
Oct 22, 2010, 4:15:33 AM10/22/10
to gstream...@googlegroups.com
Yes, i tried that. Worked well when the playbin was in state PLAYING. When I tried to do this in state NULL or READY, I was unable to change the playbin state to PLAYING - so I was unable to start playback. Maybe it had something to do with the fact, that i wasn't using the pads, but the methods element.link() and element.unlink() to link elements ...

I will give it a try one more time, thanks.
Reply all
Reply to author
Forward
0 new messages