Hello everyone,
I’ve noticed that when a USB audio speaker is disconnected while a pipeline is running, it results in increased CPU and memory usage.
With GST_DEBUG=3, I can see the following error that can be caught in a bus error handler:
alsa gstalsasink.c:1112_alsasink_write:<alsasink0> error: Error outputting to audio device. The device has been disconnected.
However, if I don’t stop the program at this point, the CPU and memory usage continue to increase. Assuming that I also have video content to display, I don’t want the program to stop if the USB speaker is disconnected. Instead, should I explicitly discard the audio samples in some way, or is there a memory leak that needs to be addressed?
Here’s the Python code I’m using to reproduce this issue. Run it and unplug your USB speaker to see the problem in action
import gi
gi.require_version("Gst", "1.0")
from gi.repository import Gst
def main() -> None:
Gst.init(None)
pipeline = Gst.Pipeline.new()
audio = Gst.ElementFactory.make("audiotestsrc")
audio_sink = Gst.ElementFactory.make("alsasink")
# change with your device id
audio_sink.set_property("device", "hw:2,0")
video = Gst.ElementFactory.make("videotestsrc")
video_sink = Gst.ElementFactory.make("autovideosink")
if not pipeline or not audio or not audio_sink or not video or not video_sink:
print("Not all elements could be created.")
exit(-1)
pipeline.add(audio)
pipeline.add(audio_sink)
audio.link(audio_sink)
pipeline.add(video)
pipeline.add(video_sink)
video.link(video_sink)
ret = pipeline.set_state(Gst.State.PLAYING)
if ret == Gst.StateChangeReturn.FAILURE:
print("Error starting playback.")
exit(-1)
# Wait until error or EOS
bus = pipeline.get_bus()
try:
while True:
msg = bus.timed_pop_filtered(10 * Gst.MSECOND, Gst.MessageType.ANY)
if msg:
if msg.type == Gst.MessageType.ERROR:
err, debug = msg.parse_error()
if "The device has been disconnected" in str(err):
# print("device disconnected")
pass
else:
print(f"Error: {err}, {debug}")
break
elif msg.type == Gst.MessageType.EOS:
print("End-Of-Stream reached.")
break
# else:
# print(f"Message: {msg.type}")
except KeyboardInterrupt:
print("User exit")
finally:
pipeline.set_state(Gst.State.NULL)
Gst.deinit()
if __name__ == "__main__":
main()