user1048335
user1048335

Reputation: 61

Gstreamer+python: adding and removing audio sources while pipeline is running

I'm working on a sample python script, originally found here: Adding and removing audio sources to/from GStreamer pipeline on-the-go. The aim is to make a script such as the one above, able to insert and remove audio sources while the pipeline is running but with an audioconvert element between the source and the adder. This is because in a more general case Adder wants the incoming streams to be of the same format.

So here's the code; we create 2 generators (buzzers). The first emits a 1000Hz tone and waits for a return key. The second is a 500Hz tone, which is summed to the first one after the key press. Again, by pressing the return key, only the second generator is heard.

#!/usr/bin/python

import gobject;
gobject.threads_init()
import gst

# THE FOLLOWING FUNCTION IS A REWORK OF THE ORIGINAL, STILL DOING THE JOB

def create_raw_audiotest_signal(pipe, freq, adder):
  # create buzzer of a given freq
  buzzer = gst.element_factory_make("audiotestsrc","buzzer%d" % freq)
  buzzer.set_property("freq",freq)
  pipe.add(buzzer)
  buzzersrc=buzzer.get_pad("src")
  # Gather a request sink pad on the mixer
  sinkpad=adder.get_request_pad("sink%d")
  # .. and connect it to the buzzer
  buzzersrc.link(sinkpad)
  return buzzer, buzzersrc, sinkpad

# THIS IS A MODIFIED VERSION, NOT WORKING, THAT JUST PUTS AN AUDIOCONVERT
# ELEMENT BETWEEN THE GENERATOR AND THE ADDER.

def create_audiotest_signal_with_converter(pipe, freq, adder):
    # create buzzer of a given freq
    buzzer = gst.element_factory_make("audiotestsrc","buzzer%d" % freq)
    buzzer.set_property("freq",freq)
    # add a converter because adder wants inputs with the same format.
    ac = gst.element_factory_make("audioconvert", "ac%d" % freq)
    pipe.add(buzzer, ac)
    # link the buzzer with the converter ...
    buzzer.link(ac)
    buzzersrc=buzzer.get_pad("src")
    # Gather a request sink pad on the mixer
    sinkpad=adder.get_request_pad("sink%d")
    # and then the converter to the adder
    ac.get_pad('src').link(sinkpad)
    return buzzer, buzzersrc, sinkpad

if __name__ == "__main__":
  # First create our pipeline
  pipe = gst.Pipeline("mypipe")

  # Create a software mixer with "Adder"
  adder = gst.element_factory_make("adder","audiomixer")
  pipe.add(adder)

  # Create the first buzzer..
  #buzzer1, buzzersrc1, sinkpad1 = create_raw_audiotest_signal(pipe, 1000, adder)
  buzzer1, buzzersrc1, sinkpad1 = create_audiotest_signal_with_converter(pipe, 1000, adder)

  # Add some output
  output = gst.element_factory_make("autoaudiosink", "audio_out")
  pipe.add(output)
  adder.link(output)

  # Start the playback
  pipe.set_state(gst.STATE_PLAYING)

  raw_input("1kHz test sound. Press <ENTER> to continue.")

  # Get another generator
  #buzzer2, buzzersrc2, sinkpad2 = create_raw_audiotest_signal(pipe, 500, adder)
  buzzer2, buzzersrc2, sinkpad2 = create_audiotest_signal_with_converter(pipe, 500, adder)

  # Start the second buzzer (other ways streaming stops because of starvation)
  buzzer2.set_state(gst.STATE_PLAYING)

  raw_input("1kHz + 500Hz test sound playing simoultenously. Press <ENTER> to continue.")

  # Before removing a source, we must use pad blocking to prevent state changes
  buzzersrc1.set_blocked(True)
  # Stop the first buzzer
  buzzer1.set_state(gst.STATE_NULL)
  # Unlink from the mixer
  buzzersrc1.unlink(sinkpad2)
  # Release the mixers first sink pad
  adder.release_request_pad(sinkpad1)
  # Because here none of the Adder's sink pads block, streaming continues

  raw_input("Only 500Hz test sound. Press <ENTER> to stop.")

If you use create_raw_audiotest_signal in place of create_audiotest_signal_with_converter in both the calls of course it works. If you use a mixture of the two, it works, but with an unwanted extra delay inbetween. The most interesting case is when you use the audioconvert in both the calls, but gtk blocks at the first return key.

Does anybody have any suggestion? What am I doing wrong? Thank you in advance.

Upvotes: 4

Views: 3057

Answers (1)

user1048335
user1048335

Reputation: 61

I found the answer myself, it was simple indeed... I added other components, but they live in the pipeline and keep having an independent play status. So the solution is set all the pipeline to playing, which in turn sets the status to all the children.

pipe.set_state(gst.STATE_PLAYING)

instead of:

buzzer2.set_state(gst.STATE_PLAYING)

and it works again.

Upvotes: 2

Related Questions