Move mixers out of gstreamer module.

Mixers now live in mopidy.mixers.<shortname>. Futhermore mopidy.mixers should
now import each of the mixers so that doing import mopidy.mixers is enough to
install the gstreamer elements.
This commit is contained in:
Thomas Adamcik 2012-09-04 01:04:59 +02:00
parent c71202c2be
commit 8281128a2e
4 changed files with 155 additions and 142 deletions

View File

@ -1,6 +1,5 @@
import pygst
pygst.require('0.10')
import gobject
import gst
import logging
@ -10,151 +9,11 @@ from pykka.registry import ActorRegistry
from mopidy import settings, utils
from mopidy.backends.base import Backend
from mopidy import mixers # Trigger install of gst mixer plugins.
logger = logging.getLogger('mopidy.gstreamer')
# TODO: we might want to add some ranking to the mixers we know about?
# TODO: move to mixers module and do from mopidy.mixers import * to install
# elements.
class AutoAudioMixer(gst.Bin):
__gstdetails__ = ('AutoAudioMixer',
'Mixer',
'Element automatically selects a mixer.',
'Thomas Adamcik')
def __init__(self):
gst.Bin.__init__(self)
mixer = self._find_mixer()
if mixer:
self.add(mixer)
logger.debug('AutoAudioMixer chose: %s', mixer.get_name())
else:
logger.debug('AutoAudioMixer did not find any usable mixers')
def _find_mixer(self):
registry = gst.registry_get_default()
factories = registry.get_feature_list(gst.TYPE_ELEMENT_FACTORY)
factories.sort(key=lambda f: (-f.get_rank(), f.get_name()))
for factory in factories:
# Avoid sink/srcs that implment mixing.
if factory.get_klass() != 'Generic/Audio':
continue
# Avoid anything that doesn't implment mixing.
elif not factory.has_interface('GstMixer'):
continue
if self._test_mixer(factory):
return factory.create()
return None
def _test_mixer(self, factory):
element = factory.create()
if not element:
return False
try:
result = element.set_state(gst.STATE_READY)
if result != gst.STATE_CHANGE_SUCCESS:
return False
# Trust that the default device is sane and just check tracks.
return self._test_tracks(element)
finally:
element.set_state(gst.STATE_NULL)
def _test_tracks(self, element):
# Only allow elements that have a least one output track.
flags = gst.interfaces.MIXER_TRACK_OUTPUT
for track in element.list_tracks():
if track.flags & flags:
return True
return False
gobject.type_register(AutoAudioMixer)
gst.element_register (AutoAudioMixer, 'autoaudiomixer', gst.RANK_MARGINAL)
def create_fake_track(label, intial_volume, min_volume, max_volume,
num_channels, flags):
class Track(gst.interfaces.MixerTrack):
def __init__(self):
super(Track, self).__init__()
self.volumes = (intial_volume,) * self.num_channels
@gobject.property
def label(self):
return label
@gobject.property
def min_volume(self):
return min_volume
@gobject.property
def max_volume(self):
return max_volume
@gobject.property
def num_channels(self):
return num_channels
@gobject.property
def flags(self):
return flags
return Track()
class FakeMixer(gst.Element, gst.ImplementsInterface, gst.interfaces.Mixer):
__gstdetails__ = ('FakeMixer',
'Mixer',
'Fake mixer for use in tests.',
'Thomas Adamcik')
track_label = gobject.property(type=str, default='Master')
track_initial_volume = gobject.property(type=int, default=0)
track_min_volume = gobject.property(type=int, default=0)
track_max_volume = gobject.property(type=int, default=100)
track_num_channels = gobject.property(type=int, default=2)
track_flags = gobject.property(type=int,
default=(gst.interfaces.MIXER_TRACK_MASTER |
gst.interfaces.MIXER_TRACK_OUTPUT))
def __init__(self):
gst.Element.__init__(self)
def list_tracks(self):
track = create_fake_track(self.track_label,
self.track_initial_volume,
self.track_min_volume,
self.track_max_volume,
self.track_num_channels,
self.track_flags)
return [track]
def get_volume(self, track):
return track.volumes
def set_volume(self, track, volumes):
track.volumes = volumes
def set_record(self, track, record):
pass
gobject.type_register(FakeMixer)
gst.element_register (FakeMixer, 'fakemixer', gst.RANK_MARGINAL)
class GStreamer(ThreadingActor):
"""
Audio output through `GStreamer <http://gstreamer.freedesktop.org/>`_.

View File

@ -0,0 +1,2 @@
from mopidy.mixers.auto import AutoAudioMixer
from mopidy.mixers.fake import FakeMixer

72
mopidy/mixers/auto.py Normal file
View File

@ -0,0 +1,72 @@
import pygst
pygst.require('0.10')
import gobject
import gst
import logging
logger = logging.getLogger('mopidy.mixers.auto')
# TODO: we might want to add some ranking to the mixers we know about?
class AutoAudioMixer(gst.Bin):
__gstdetails__ = ('AutoAudioMixer',
'Mixer',
'Element automatically selects a mixer.',
'Thomas Adamcik')
def __init__(self):
gst.Bin.__init__(self)
mixer = self._find_mixer()
if mixer:
self.add(mixer)
logger.debug('AutoAudioMixer chose: %s', mixer.get_name())
else:
logger.debug('AutoAudioMixer did not find any usable mixers')
def _find_mixer(self):
registry = gst.registry_get_default()
factories = registry.get_feature_list(gst.TYPE_ELEMENT_FACTORY)
factories.sort(key=lambda f: (-f.get_rank(), f.get_name()))
for factory in factories:
# Avoid sink/srcs that implment mixing.
if factory.get_klass() != 'Generic/Audio':
continue
# Avoid anything that doesn't implment mixing.
elif not factory.has_interface('GstMixer'):
continue
if self._test_mixer(factory):
return factory.create()
return None
def _test_mixer(self, factory):
element = factory.create()
if not element:
return False
try:
result = element.set_state(gst.STATE_READY)
if result != gst.STATE_CHANGE_SUCCESS:
return False
# Trust that the default device is sane and just check tracks.
return self._test_tracks(element)
finally:
element.set_state(gst.STATE_NULL)
def _test_tracks(self, element):
# Only allow elements that have a least one output track.
flags = gst.interfaces.MIXER_TRACK_OUTPUT
for track in element.list_tracks():
if track.flags & flags:
return True
return False
gobject.type_register(AutoAudioMixer)
gst.element_register (AutoAudioMixer, 'autoaudiomixer', gst.RANK_MARGINAL)

80
mopidy/mixers/fake.py Normal file
View File

@ -0,0 +1,80 @@
import pygst
pygst.require('0.10')
import gobject
import gst
def create_fake_track(label, intial_volume, min_volume, max_volume,
num_channels, flags):
class Track(gst.interfaces.MixerTrack):
def __init__(self):
super(Track, self).__init__()
self.volumes = (intial_volume,) * self.num_channels
@gobject.property
def label(self):
return label
@gobject.property
def min_volume(self):
return min_volume
@gobject.property
def max_volume(self):
return max_volume
@gobject.property
def num_channels(self):
return num_channels
@gobject.property
def flags(self):
return flags
return Track()
class FakeMixer(gst.Element, gst.ImplementsInterface, gst.interfaces.Mixer):
__gstdetails__ = ('FakeMixer',
'Mixer',
'Fake mixer for use in tests.',
'Thomas Adamcik')
track_label = gobject.property(type=str, default='Master')
track_initial_volume = gobject.property(type=int, default=0)
track_min_volume = gobject.property(type=int, default=0)
track_max_volume = gobject.property(type=int, default=100)
track_num_channels = gobject.property(type=int, default=2)
track_flags = gobject.property(type=int,
default=(gst.interfaces.MIXER_TRACK_MASTER |
gst.interfaces.MIXER_TRACK_OUTPUT))
def __init__(self):
gst.Element.__init__(self)
def list_tracks(self):
track = create_fake_track(self.track_label,
self.track_initial_volume,
self.track_min_volume,
self.track_max_volume,
self.track_num_channels,
self.track_flags)
return [track]
def get_volume(self, track):
return track.volumes
def set_volume(self, track, volumes):
track.volumes = volumes
def set_record(self, track, record):
pass
gobject.type_register(FakeMixer)
gst.element_register (FakeMixer, 'fakemixer', gst.RANK_MARGINAL)