forked from platypush/platypush
Initial support for playing multiple sounds to the same stream
This commit is contained in:
parent
3d2636b09c
commit
3baf0b1589
1 changed files with 32 additions and 16 deletions
|
@ -172,7 +172,8 @@ class SoundPlugin(Plugin):
|
||||||
|
|
||||||
@action
|
@action
|
||||||
def play(self, file=None, sound=None, device=None, blocksize=None,
|
def play(self, file=None, sound=None, device=None, blocksize=None,
|
||||||
bufsize=Sound._DEFAULT_BUFSIZE, samplerate=None, channels=None):
|
bufsize=Sound._DEFAULT_BUFSIZE, samplerate=None, channels=None,
|
||||||
|
stream_index=None):
|
||||||
"""
|
"""
|
||||||
Plays a sound file (support formats: wav, raw) or a synthetic sound.
|
Plays a sound file (support formats: wav, raw) or a synthetic sound.
|
||||||
|
|
||||||
|
@ -209,6 +210,11 @@ class SoundPlugin(Plugin):
|
||||||
:param channels: Number of audio channels. Default: number of channels
|
:param channels: Number of audio channels. Default: number of channels
|
||||||
in the audio file in file mode, 1 if in synth mode
|
in the audio file in file mode, 1 if in synth mode
|
||||||
:type channels: int
|
:type channels: int
|
||||||
|
|
||||||
|
:param stream_index: If specified, play to an already active stream
|
||||||
|
index (you can get them through
|
||||||
|
:method:`platypush.plugins.sound.query_active_streams`). Default:
|
||||||
|
creates a new audio stream through PortAudio.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if not file and not sound:
|
if not file and not sound:
|
||||||
|
@ -222,7 +228,6 @@ class SoundPlugin(Plugin):
|
||||||
|
|
||||||
self.playback_paused_changed.clear()
|
self.playback_paused_changed.clear()
|
||||||
|
|
||||||
stream_index = None
|
|
||||||
q = queue.Queue(maxsize=bufsize)
|
q = queue.Queue(maxsize=bufsize)
|
||||||
f = None
|
f = None
|
||||||
t = 0.
|
t = 0.
|
||||||
|
@ -273,17 +278,23 @@ class SoundPlugin(Plugin):
|
||||||
|
|
||||||
q.put_nowait(data) # Pre-fill the audio queue
|
q.put_nowait(data) # Pre-fill the audio queue
|
||||||
|
|
||||||
streamtype = sd.RawOutputStream if file else sd.OutputStream
|
|
||||||
completed_callback_event = Event()
|
|
||||||
stream = streamtype(samplerate=samplerate, blocksize=blocksize,
|
|
||||||
device=device, channels=channels,
|
|
||||||
dtype='float32',
|
|
||||||
callback=self._play_audio_callback(
|
|
||||||
q=q, blocksize=blocksize,
|
|
||||||
streamtype=streamtype),
|
|
||||||
finished_callback=completed_callback_event.set)
|
|
||||||
|
|
||||||
stream_index = self.start_playback(stream, completed_callback_event)
|
if stream_index is None:
|
||||||
|
completed_callback_event = Event()
|
||||||
|
streamtype = sd.RawOutputStream if file else sd.OutputStream
|
||||||
|
stream = streamtype(samplerate=samplerate, blocksize=blocksize,
|
||||||
|
device=device, channels=channels,
|
||||||
|
dtype='float32',
|
||||||
|
callback=self._play_audio_callback(
|
||||||
|
q=q, blocksize=blocksize,
|
||||||
|
streamtype=streamtype),
|
||||||
|
finished_callback=completed_callback_event.set)
|
||||||
|
|
||||||
|
stream_index = self.start_playback(stream,
|
||||||
|
completed_callback_event)
|
||||||
|
else:
|
||||||
|
stream = self.active_streams[stream_index]
|
||||||
|
completed_callback_event = self.completed_callback_events[stream_index]
|
||||||
|
|
||||||
with stream:
|
with stream:
|
||||||
# Timeout set until we expect all the buffered blocks to
|
# Timeout set until we expect all the buffered blocks to
|
||||||
|
@ -327,7 +338,7 @@ class SoundPlugin(Plugin):
|
||||||
f.close()
|
f.close()
|
||||||
f = None
|
f = None
|
||||||
|
|
||||||
self.stop_playback(stream_index)
|
self.stop_playback([stream_index])
|
||||||
|
|
||||||
|
|
||||||
@action
|
@action
|
||||||
|
@ -533,12 +544,12 @@ class SoundPlugin(Plugin):
|
||||||
except queue.Empty as e:
|
except queue.Empty as e:
|
||||||
self.logger.warning('Recording timeout: audio callback failed?')
|
self.logger.warning('Recording timeout: audio callback failed?')
|
||||||
finally:
|
finally:
|
||||||
self.stop_playback(stream_index)
|
self.stop_playback([stream_index])
|
||||||
self.stop_recording()
|
self.stop_recording()
|
||||||
|
|
||||||
|
|
||||||
@action
|
@action
|
||||||
def get_active_streams(self):
|
def query_active_streams(self):
|
||||||
"""
|
"""
|
||||||
:returns: A list of active players
|
:returns: A list of active players
|
||||||
"""
|
"""
|
||||||
|
@ -572,7 +583,12 @@ class SoundPlugin(Plugin):
|
||||||
return stream_index
|
return stream_index
|
||||||
|
|
||||||
@action
|
@action
|
||||||
def stop_playback(self, *streams):
|
def stop_playback(self, streams=None):
|
||||||
|
"""
|
||||||
|
:param streams: Stream to stop by index (default: all)
|
||||||
|
:type streams: list[int]
|
||||||
|
"""
|
||||||
|
|
||||||
with self.playback_state_lock:
|
with self.playback_state_lock:
|
||||||
if not streams:
|
if not streams:
|
||||||
streams = self.active_streams.keys()
|
streams = self.active_streams.keys()
|
||||||
|
|
Loading…
Reference in a new issue