mixer: Inject audio into software mixer
Instead of giving all mixers access to the audio actor.
This commit is contained in:
parent
a3dc763b29
commit
5f091c10c2
@ -50,10 +50,11 @@ class Audio(pykka.ThreadingActor):
|
|||||||
state = PlaybackState.STOPPED
|
state = PlaybackState.STOPPED
|
||||||
_target_state = gst.STATE_NULL
|
_target_state = gst.STATE_NULL
|
||||||
|
|
||||||
def __init__(self, config):
|
def __init__(self, config, mixer):
|
||||||
super(Audio, self).__init__()
|
super(Audio, self).__init__()
|
||||||
|
|
||||||
self._config = config
|
self._config = config
|
||||||
|
self._mixer = mixer
|
||||||
|
|
||||||
self._playbin = None
|
self._playbin = None
|
||||||
self._signal_ids = {} # {(element, event): signal_id}
|
self._signal_ids = {} # {(element, event): signal_id}
|
||||||
@ -68,6 +69,7 @@ class Audio(pykka.ThreadingActor):
|
|||||||
try:
|
try:
|
||||||
self._setup_playbin()
|
self._setup_playbin()
|
||||||
self._setup_output()
|
self._setup_output()
|
||||||
|
self._setup_mixer()
|
||||||
self._setup_visualizer()
|
self._setup_visualizer()
|
||||||
self._setup_message_processor()
|
self._setup_message_processor()
|
||||||
except gobject.GError as ex:
|
except gobject.GError as ex:
|
||||||
@ -76,6 +78,7 @@ class Audio(pykka.ThreadingActor):
|
|||||||
|
|
||||||
def on_stop(self):
|
def on_stop(self):
|
||||||
self._teardown_message_processor()
|
self._teardown_message_processor()
|
||||||
|
self._teardown_mixer()
|
||||||
self._teardown_playbin()
|
self._teardown_playbin()
|
||||||
|
|
||||||
def _connect(self, element, event, *args):
|
def _connect(self, element, event, *args):
|
||||||
@ -180,6 +183,16 @@ class Audio(pykka.ThreadingActor):
|
|||||||
'Failed to create audio output "%s": %s', output_desc, ex)
|
'Failed to create audio output "%s": %s', output_desc, ex)
|
||||||
process.exit_process()
|
process.exit_process()
|
||||||
|
|
||||||
|
def _setup_mixer(self):
|
||||||
|
if self._config['audio']['mixer'] != 'software':
|
||||||
|
return
|
||||||
|
self._mixer.audio = self.actor_ref.proxy()
|
||||||
|
|
||||||
|
def _teardown_mixer(self):
|
||||||
|
if self._config['audio']['mixer'] != 'software':
|
||||||
|
return
|
||||||
|
self._mixer.audio = None
|
||||||
|
|
||||||
def _setup_visualizer(self):
|
def _setup_visualizer(self):
|
||||||
visualizer_element = self._config['audio']['visualizer']
|
visualizer_element = self._config['audio']['visualizer']
|
||||||
if not visualizer_element:
|
if not visualizer_element:
|
||||||
|
|||||||
@ -266,8 +266,8 @@ class RootCommand(Command):
|
|||||||
frontend_classes = args.registry['frontend']
|
frontend_classes = args.registry['frontend']
|
||||||
|
|
||||||
try:
|
try:
|
||||||
audio = self.start_audio(config)
|
mixer = self.start_mixer(config, mixer_class)
|
||||||
mixer = self.start_mixer(config, mixer_class, audio)
|
audio = self.start_audio(config, mixer)
|
||||||
backends = self.start_backends(config, backend_classes, audio)
|
backends = self.start_backends(config, backend_classes, audio)
|
||||||
core = self.start_core(mixer, backends)
|
core = self.start_core(mixer, backends)
|
||||||
self.start_frontends(config, frontend_classes, core)
|
self.start_frontends(config, frontend_classes, core)
|
||||||
@ -282,9 +282,9 @@ class RootCommand(Command):
|
|||||||
loop.quit()
|
loop.quit()
|
||||||
self.stop_frontends(frontend_classes)
|
self.stop_frontends(frontend_classes)
|
||||||
self.stop_core()
|
self.stop_core()
|
||||||
self.stop_mixer(mixer_class)
|
|
||||||
self.stop_backends(backend_classes)
|
self.stop_backends(backend_classes)
|
||||||
self.stop_audio()
|
self.stop_audio()
|
||||||
|
self.stop_mixer(mixer_class)
|
||||||
process.stop_remaining_actors()
|
process.stop_remaining_actors()
|
||||||
|
|
||||||
def get_mixer_class(self, config, mixer_classes):
|
def get_mixer_class(self, config, mixer_classes):
|
||||||
@ -302,9 +302,29 @@ class RootCommand(Command):
|
|||||||
process.exit_process()
|
process.exit_process()
|
||||||
return selected_mixers[0]
|
return selected_mixers[0]
|
||||||
|
|
||||||
def start_audio(self, config):
|
def start_mixer(self, config, mixer_class):
|
||||||
|
try:
|
||||||
|
logger.info('Starting Mopidy mixer: %s', mixer_class.__name__)
|
||||||
|
mixer = mixer_class.start(config=config).proxy()
|
||||||
|
self.configure_mixer(config, mixer)
|
||||||
|
return mixer
|
||||||
|
except exceptions.MixerError as exc:
|
||||||
|
logger.error(
|
||||||
|
'Mixer (%s) initialization error: %s',
|
||||||
|
mixer_class.__name__, exc.message)
|
||||||
|
raise
|
||||||
|
|
||||||
|
def configure_mixer(self, config, mixer):
|
||||||
|
volume = config['audio']['mixer_volume']
|
||||||
|
if volume is not None:
|
||||||
|
mixer.set_volume(volume)
|
||||||
|
logger.info('Mixer volume set to %d', volume)
|
||||||
|
else:
|
||||||
|
logger.debug('Mixer volume left unchanged')
|
||||||
|
|
||||||
|
def start_audio(self, config, mixer):
|
||||||
logger.info('Starting Mopidy audio')
|
logger.info('Starting Mopidy audio')
|
||||||
return Audio.start(config=config).proxy()
|
return Audio.start(config=config, mixer=mixer).proxy()
|
||||||
|
|
||||||
def start_backends(self, config, backend_classes, audio):
|
def start_backends(self, config, backend_classes, audio):
|
||||||
logger.info(
|
logger.info(
|
||||||
@ -325,26 +345,6 @@ class RootCommand(Command):
|
|||||||
|
|
||||||
return backends
|
return backends
|
||||||
|
|
||||||
def start_mixer(self, config, mixer_class, audio):
|
|
||||||
try:
|
|
||||||
logger.info('Starting Mopidy mixer: %s', mixer_class.__name__)
|
|
||||||
mixer = mixer_class.start(config=config, audio=audio).proxy()
|
|
||||||
self.configure_mixer(config, mixer)
|
|
||||||
return mixer
|
|
||||||
except exceptions.MixerError as exc:
|
|
||||||
logger.error(
|
|
||||||
'Mixer (%s) initialization error: %s',
|
|
||||||
mixer_class.__name__, exc.message)
|
|
||||||
raise
|
|
||||||
|
|
||||||
def configure_mixer(self, config, mixer):
|
|
||||||
volume = config['audio']['mixer_volume']
|
|
||||||
if volume is not None:
|
|
||||||
mixer.set_volume(volume)
|
|
||||||
logger.info('Mixer volume set to %d', volume)
|
|
||||||
else:
|
|
||||||
logger.debug('Mixer volume left unchanged')
|
|
||||||
|
|
||||||
def start_core(self, mixer, backends):
|
def start_core(self, mixer, backends):
|
||||||
logger.info('Starting Mopidy core')
|
logger.info('Starting Mopidy core')
|
||||||
return Core.start(mixer=mixer, backends=backends).proxy()
|
return Core.start(mixer=mixer, backends=backends).proxy()
|
||||||
@ -372,10 +372,6 @@ class RootCommand(Command):
|
|||||||
logger.info('Stopping Mopidy core')
|
logger.info('Stopping Mopidy core')
|
||||||
process.stop_actors_by_class(Core)
|
process.stop_actors_by_class(Core)
|
||||||
|
|
||||||
def stop_mixer(self, mixer_class):
|
|
||||||
logger.info('Stopping Mopidy mixer')
|
|
||||||
process.stop_actors_by_class(mixer_class)
|
|
||||||
|
|
||||||
def stop_backends(self, backend_classes):
|
def stop_backends(self, backend_classes):
|
||||||
logger.info('Stopping Mopidy backends')
|
logger.info('Stopping Mopidy backends')
|
||||||
for backend_class in backend_classes:
|
for backend_class in backend_classes:
|
||||||
@ -385,6 +381,10 @@ class RootCommand(Command):
|
|||||||
logger.info('Stopping Mopidy audio')
|
logger.info('Stopping Mopidy audio')
|
||||||
process.stop_actors_by_class(Audio)
|
process.stop_actors_by_class(Audio)
|
||||||
|
|
||||||
|
def stop_mixer(self, mixer_class):
|
||||||
|
logger.info('Stopping Mopidy mixer')
|
||||||
|
process.stop_actors_by_class(mixer_class)
|
||||||
|
|
||||||
|
|
||||||
class ConfigCommand(Command):
|
class ConfigCommand(Command):
|
||||||
help = 'Show currently active configuration.'
|
help = 'Show currently active configuration.'
|
||||||
|
|||||||
@ -19,8 +19,6 @@ class Mixer(object):
|
|||||||
|
|
||||||
:param config: the entire Mopidy configuration
|
:param config: the entire Mopidy configuration
|
||||||
:type config: dict
|
:type config: dict
|
||||||
:param audio: actor proxy for the audio subsystem
|
|
||||||
:type audio: :class:`pykka.ActorProxy` for :class:`mopidy.audio.Audio`
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = None
|
name = None
|
||||||
@ -122,7 +120,7 @@ class MixerListener(listener.Listener):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def send(event, **kwargs):
|
def send(event, **kwargs):
|
||||||
"""Helper to allow calling of audio listener events"""
|
"""Helper to allow calling of mixer listener events"""
|
||||||
listener.send_async(MixerListener, event, **kwargs)
|
listener.send_async(MixerListener, event, **kwargs)
|
||||||
|
|
||||||
def volume_changed(self, volume):
|
def volume_changed(self, volume):
|
||||||
|
|||||||
@ -14,22 +14,33 @@ class SoftwareMixer(pykka.ThreadingActor, mixer.Mixer):
|
|||||||
|
|
||||||
name = 'software'
|
name = 'software'
|
||||||
|
|
||||||
def __init__(self, config, audio):
|
def __init__(self, config):
|
||||||
super(SoftwareMixer, self).__init__()
|
super(SoftwareMixer, self).__init__()
|
||||||
self.audio = audio
|
|
||||||
|
self.audio = None
|
||||||
|
|
||||||
logger.info('Mixing using GStreamer software mixing')
|
logger.info('Mixing using GStreamer software mixing')
|
||||||
|
|
||||||
def get_volume(self):
|
def get_volume(self):
|
||||||
|
if self.audio is None:
|
||||||
|
return None
|
||||||
return self.audio.get_volume().get()
|
return self.audio.get_volume().get()
|
||||||
|
|
||||||
def set_volume(self, volume):
|
def set_volume(self, volume):
|
||||||
|
if self.audio is None:
|
||||||
|
return False
|
||||||
self.audio.set_volume(volume)
|
self.audio.set_volume(volume)
|
||||||
self.trigger_volume_changed(volume)
|
self.trigger_volume_changed(volume)
|
||||||
|
return True
|
||||||
|
|
||||||
def get_mute(self):
|
def get_mute(self):
|
||||||
|
if self.audio is None:
|
||||||
|
return None
|
||||||
return self.audio.get_mute().get()
|
return self.audio.get_mute().get()
|
||||||
|
|
||||||
def set_mute(self, muted):
|
def set_mute(self, muted):
|
||||||
|
if self.audio is None:
|
||||||
|
return False
|
||||||
self.audio.set_mute(muted)
|
self.audio.set_mute(muted)
|
||||||
self.trigger_mute_changed(muted)
|
self.trigger_mute_changed(muted)
|
||||||
|
return True
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user