Skip to content

Commit

Permalink
Merge pull request #3222 from arcresu/bpd-decoders
Browse files Browse the repository at this point in the history
bpd: support decoders command
  • Loading branch information
arcresu authored Apr 20, 2019
2 parents 0f8a748 + c932751 commit 063e4f2
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 4 deletions.
10 changes: 10 additions & 0 deletions beetsplug/bpd/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1321,6 +1321,16 @@ def cmd_stats(self, conn):
u'db_update: ' + six.text_type(int(self.updated_time)),
)

def cmd_decoders(self, conn):
"""Send list of supported decoders and formats."""
decoders = self.player.get_decoders()
for name, (mimes, exts) in decoders.items():
yield u'plugin: {}'.format(name)
for ext in exts:
yield u'suffix: {}'.format(ext)
for mime in mimes:
yield u'mime_type: {}'.format(mime)

# Searching.

tagtype_map = {
Expand Down
53 changes: 53 additions & 0 deletions beetsplug/bpd/gstplayer.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,59 @@ def block(self):
while self.playing:
time.sleep(1)

def get_decoders(self):
return get_decoders()


def get_decoders():
"""Get supported audio decoders from GStreamer.
Returns a dict mapping decoder element names to the associated media types
and file extensions.
"""
# We only care about audio decoder elements.
filt = (Gst.ELEMENT_FACTORY_TYPE_DEPAYLOADER |
Gst.ELEMENT_FACTORY_TYPE_DEMUXER |
Gst.ELEMENT_FACTORY_TYPE_PARSER |
Gst.ELEMENT_FACTORY_TYPE_DECODER |
Gst.ELEMENT_FACTORY_TYPE_MEDIA_AUDIO)

decoders = {}
mime_types = set()
for f in Gst.ElementFactory.list_get_elements(filt, Gst.Rank.NONE):
for pad in f.get_static_pad_templates():
if pad.direction == Gst.PadDirection.SINK:
caps = pad.static_caps.get()
mimes = set()
for i in range(caps.get_size()):
struct = caps.get_structure(i)
mime = struct.get_name()
if mime == 'unknown/unknown':
continue
mimes.add(mime)
mime_types.add(mime)
if mimes:
decoders[f.get_name()] = (mimes, set())

# Check all the TypeFindFactory plugin features form the registry. If they
# are associated with an audio media type that we found above, get the list
# of corresponding file extensions.
mime_extensions = {mime: set() for mime in mime_types}
for feat in Gst.Registry.get().get_feature_list(Gst.TypeFindFactory):
caps = feat.get_caps()
if caps:
for i in range(caps.get_size()):
struct = caps.get_structure(i)
mime = struct.get_name()
if mime in mime_types:
mime_extensions[mime].update(feat.get_extensions())

# Fill in the slot we left for file extensions.
for name, (mimes, exts) in decoders.items():
for mime in mimes:
exts.update(mime_extensions[mime])

return decoders


def play_simple(paths):
"""Play the files in paths in a straightforward way, without
Expand Down
2 changes: 2 additions & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ New features:
* :doc:`/plugins/bpd`: MPD protocol command ``idle`` is now supported, allowing
the MPD version to be bumped to 0.14.
:bug:`3205` :bug:`800`
* :doc:`/plugins/bpd`: MPD protocol command ``decoders`` is now supported.
:bug:`3222`

Changes:

Expand Down
16 changes: 12 additions & 4 deletions test/test_player.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,14 @@ def _gstplayer_play(*_): # noqa: 42
gstplayer._GstPlayer = mock.MagicMock(
spec_set=[
"time", "volume", "playing", "run", "play_file", "pause", "stop",
"seek", "play"
"seek", "play", "get_decoders",
], **{
'playing': False,
'volume': 0,
'time.return_value': (0, 0),
'play_file.side_effect': _gstplayer_play,
'play.side_effect': _gstplayer_play,
'get_decoders.return_value': {'default': ({'audio/mpeg'}, {'mp3'})},
})
gstplayer.GstPlayer = lambda _: gstplayer._GstPlayer
sys.modules["beetsplug.bpd.gstplayer"] = gstplayer
Expand Down Expand Up @@ -879,9 +880,16 @@ class BPDDeviceTest(BPDTestHelper):

class BPDReflectionTest(BPDTestHelper):
test_implements_reflection = implements({
'config', 'commands', 'notcommands', 'urlhandlers',
'decoders',
}, expectedFailure=True)
'config', 'commands', 'notcommands', 'urlhandlers',
}, expectedFailure=True)

def test_cmd_decoders(self):
with self.run_bpd() as client:
response = client.send_command('decoders')
self._assert_ok(response)
self.assertEqual('default', response.data['plugin'])
self.assertEqual('mp3', response.data['suffix'])
self.assertEqual('audio/mpeg', response.data['mime_type'])


class BPDPeersTest(BPDTestHelper):
Expand Down

0 comments on commit 063e4f2

Please sign in to comment.