动态添加和移除 GStreamer 管道中的音频源

117 阅读2分钟

在 GStreamer 中,将音频源添加到管道或从中移除是很有用的。例如,你可能希望将麦克风作为音频源添加,或在播放音乐时淡出/淡入背景音乐。

在本例中,有一个 GStreamer 管道,其中包含一个音频测试源(产生 1kHz 音调)和一个 Pulsesink 输出元素。当用户按 Enter 键时,应该将另一个 500Hz 测试音源添加到管道中,两者的音频应该同时播放。然而,当用户再次按 Enter 键时,1kHz 音源应该从混合中移除,只保留 500Hz 音源。

使用传统的链接和取消链接方法时,代码存在一个问题:当移除 1kHz 音源时,整个管道停止播放。这是因为 Pulsesink 输出元素期望始终接收音频数据,如果没有数据,它就会发出下溢错误并停止播放。

2、解决方案

要解决这个问题,可以使用 GStreamer 中的请求垫(request pad)和垫阻塞(pad blocking)功能。

使用请求垫,可以先在混音器元素上创建请求垫,然后将音源的输出垫连接到请求垫。这样,当音源被移除时,混音器元素不会立即停止播放,而是会等待下一个音源被连接到请求垫。

同时,使用垫阻塞功能,可以在移除音源之前阻塞混音器元素的输入垫,以防止状态更改。这样,就可以安全地移除音源,而不会导致管道停止播放。

以下是用 Python 编写的完整代码:

import gobject;
gobject.threads_init()
import gst;

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)

    # Gather a request sink pad on the mixer
    sinkpad1=adder.get_request_pad("sink%d")

    # Create the first buzzer..
    buzzer1 = gst.element_factory_make("audiotestsrc","buzzer1")
    buzzer1.set_property("freq",1000)
    pipe.add(buzzer1)
    # .. and connect it's source pad to the previously gathered request pad
    buzzersrc1=buzzer1.get_pad("src")
    buzzersrc1.link(sinkpad1)

    # 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 an another request sink pad on the mixer
    sinkpad2=adder.get_request_pad("sink%d")

    # Create an another buzzer and connect it the same way
    buzzer2 = gst.element_factory_make("audiotestsrc","buzzer2")
    buzzer2.set_property("freq",500)
    pipe.add(buzzer2)

    buzzersrc2=buzzer2.get_pad("src")
    buzzersrc2.link(sinkpad2)

    # 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(sinkpad1)
    # 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.")

按照以下步骤运行代码:

  1. 将代码保存为一个 Python 脚本文件(例如,mixer.py)。
  2. 打开终端窗口,导航到脚本文件所在的目录。
  3. 在终端窗口中输入以下命令:
python3 mixer.py
  1. 按照屏幕上的说明进行操作,按 Enter 键添加和移除音源。

你应该会听到 1kHz 音调,然后听到 1kHz + 500Hz 音调,最后听到 500Hz 音调。