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
|
||||
_target_state = gst.STATE_NULL
|
||||
|
||||
def __init__(self, config):
|
||||
def __init__(self, config, mixer):
|
||||
super(Audio, self).__init__()
|
||||
|
||||
self._config = config
|
||||
self._mixer = mixer
|
||||
|
||||
self._playbin = None
|
||||
self._signal_ids = {} # {(element, event): signal_id}
|
||||
@ -68,6 +69,7 @@ class Audio(pykka.ThreadingActor):
|
||||
try:
|
||||
self._setup_playbin()
|
||||
self._setup_output()
|
||||
self._setup_mixer()
|
||||
self._setup_visualizer()
|
||||
self._setup_message_processor()
|
||||
except gobject.GError as ex:
|
||||
@ -76,6 +78,7 @@ class Audio(pykka.ThreadingActor):
|
||||
|
||||
def on_stop(self):
|
||||
self._teardown_message_processor()
|
||||
self._teardown_mixer()
|
||||
self._teardown_playbin()
|
||||
|
||||
def _connect(self, element, event, *args):
|
||||
@ -180,6 +183,16 @@ class Audio(pykka.ThreadingActor):
|
||||
'Failed to create audio output "%s": %s', output_desc, ex)
|
||||
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):
|
||||
visualizer_element = self._config['audio']['visualizer']
|
||||
if not visualizer_element:
|
||||
|
||||
@ -266,8 +266,8 @@ class RootCommand(Command):
|
||||
frontend_classes = args.registry['frontend']
|
||||
|
||||
try:
|
||||
audio = self.start_audio(config)
|
||||
mixer = self.start_mixer(config, mixer_class, audio)
|
||||
mixer = self.start_mixer(config, mixer_class)
|
||||
audio = self.start_audio(config, mixer)
|
||||
backends = self.start_backends(config, backend_classes, audio)
|
||||
core = self.start_core(mixer, backends)
|
||||
self.start_frontends(config, frontend_classes, core)
|
||||
@ -282,9 +282,9 @@ class RootCommand(Command):
|
||||
loop.quit()
|
||||
self.stop_frontends(frontend_classes)
|
||||
self.stop_core()
|
||||
self.stop_mixer(mixer_class)
|
||||
self.stop_backends(backend_classes)
|
||||
self.stop_audio()
|
||||
self.stop_mixer(mixer_class)
|
||||
process.stop_remaining_actors()
|
||||
|
||||
def get_mixer_class(self, config, mixer_classes):
|
||||
@ -302,9 +302,29 @@ class RootCommand(Command):
|
||||
process.exit_process()
|
||||
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')
|
||||
return Audio.start(config=config).proxy()
|
||||
return Audio.start(config=config, mixer=mixer).proxy()
|
||||
|
||||
def start_backends(self, config, backend_classes, audio):
|
||||
logger.info(
|
||||
@ -325,26 +345,6 @@ class RootCommand(Command):
|
||||
|
||||
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):
|
||||
logger.info('Starting Mopidy core')
|
||||
return Core.start(mixer=mixer, backends=backends).proxy()
|
||||
@ -372,10 +372,6 @@ class RootCommand(Command):
|
||||
logger.info('Stopping Mopidy 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):
|
||||
logger.info('Stopping Mopidy backends')
|
||||
for backend_class in backend_classes:
|
||||
@ -385,6 +381,10 @@ class RootCommand(Command):
|
||||
logger.info('Stopping Mopidy 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):
|
||||
help = 'Show currently active configuration.'
|
||||
|
||||
@ -19,8 +19,6 @@ class Mixer(object):
|
||||
|
||||
:param config: the entire Mopidy configuration
|
||||
:type config: dict
|
||||
:param audio: actor proxy for the audio subsystem
|
||||
:type audio: :class:`pykka.ActorProxy` for :class:`mopidy.audio.Audio`
|
||||
"""
|
||||
|
||||
name = None
|
||||
@ -122,7 +120,7 @@ class MixerListener(listener.Listener):
|
||||
|
||||
@staticmethod
|
||||
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)
|
||||
|
||||
def volume_changed(self, volume):
|
||||
|
||||
@ -14,22 +14,33 @@ class SoftwareMixer(pykka.ThreadingActor, mixer.Mixer):
|
||||
|
||||
name = 'software'
|
||||
|
||||
def __init__(self, config, audio):
|
||||
def __init__(self, config):
|
||||
super(SoftwareMixer, self).__init__()
|
||||
self.audio = audio
|
||||
|
||||
self.audio = None
|
||||
|
||||
logger.info('Mixing using GStreamer software mixing')
|
||||
|
||||
def get_volume(self):
|
||||
if self.audio is None:
|
||||
return None
|
||||
return self.audio.get_volume().get()
|
||||
|
||||
def set_volume(self, volume):
|
||||
if self.audio is None:
|
||||
return False
|
||||
self.audio.set_volume(volume)
|
||||
self.trigger_volume_changed(volume)
|
||||
return True
|
||||
|
||||
def get_mute(self):
|
||||
if self.audio is None:
|
||||
return None
|
||||
return self.audio.get_mute().get()
|
||||
|
||||
def set_mute(self, muted):
|
||||
if self.audio is None:
|
||||
return False
|
||||
self.audio.set_mute(muted)
|
||||
self.trigger_mute_changed(muted)
|
||||
return True
|
||||
|
||||
Loading…
Reference in New Issue
Block a user