audio: Add tags changed event to audio.
Current version simply emits the keys of the changed tags to the audio listener. Following change will add support for storing the actual data.
This commit is contained in:
parent
de6bd63481
commit
6c62252919
@ -303,6 +303,8 @@ class _Handler(object):
|
||||
self.on_warning(*msg.parse_warning())
|
||||
elif msg.type == gst.MESSAGE_ASYNC_DONE:
|
||||
self.on_async_done()
|
||||
elif msg.type == gst.MESSAGE_TAG:
|
||||
self.on_tag(msg.parse_tag())
|
||||
elif msg.type == gst.MESSAGE_ELEMENT:
|
||||
if gst.pbutils.is_missing_plugin_message(msg):
|
||||
self.on_missing_plugin(_get_missing_description(msg),
|
||||
@ -387,6 +389,12 @@ class _Handler(object):
|
||||
def on_async_done(self):
|
||||
gst_logger.debug('Got async-done.')
|
||||
|
||||
def on_tag(self, taglist):
|
||||
# TODO: store current tags and reset on stream changes.
|
||||
tags = taglist.keys()
|
||||
logger.debug('Audio event: tags_changed(tags=%r)', tags)
|
||||
AudioListener.send('tags_changed', tags=tags)
|
||||
|
||||
def on_missing_plugin(self, msg):
|
||||
desc = gst.pbutils.missing_plugin_message_get_description(msg)
|
||||
debug = gst.pbutils.missing_plugin_message_get_installer_detail(msg)
|
||||
|
||||
@ -91,6 +91,9 @@ class DummyAudio(pykka.ThreadingActor):
|
||||
AudioListener.send('state_changed', old_state=old_state,
|
||||
new_state=new_state, target_state=None)
|
||||
|
||||
if new_state == PlaybackState.PLAYING:
|
||||
AudioListener.send('tags_changed', tags=[])
|
||||
|
||||
return self._state_change_result
|
||||
|
||||
def trigger_fake_playback_failure(self):
|
||||
|
||||
@ -75,3 +75,21 @@ class AudioListener(listener.Listener):
|
||||
field or :class:`None` if this is a final state.
|
||||
"""
|
||||
pass
|
||||
|
||||
def tags_changed(self, tags):
|
||||
"""
|
||||
Called whenever the current audio streams tags changes.
|
||||
|
||||
This event signals that some track metadata has been updated. This can
|
||||
be metadata such as artists, titles, organization, or details about the
|
||||
actual audio such as bit-rates, numbers of channels etc.
|
||||
|
||||
For the available tag keys please refer to GStreamer documenation for
|
||||
tags.
|
||||
|
||||
*MAY* be implemented by actor.
|
||||
|
||||
:param tags: The tags that have just been updated.
|
||||
:type tags: :class:`set` of strings
|
||||
"""
|
||||
pass
|
||||
|
||||
@ -42,7 +42,7 @@ class BaseTest(unittest.TestCase):
|
||||
|
||||
audio_class = audio.Audio
|
||||
|
||||
def setUp(self):
|
||||
def setUp(self): # noqa
|
||||
config = {
|
||||
'audio': {
|
||||
'mixer': 'foomixer',
|
||||
@ -57,7 +57,7 @@ class BaseTest(unittest.TestCase):
|
||||
self.song_uri = path_to_uri(path_to_data_dir('song1.wav'))
|
||||
self.audio = self.audio_class.start(config=config, mixer=None).proxy()
|
||||
|
||||
def tearDown(self):
|
||||
def tearDown(self): # noqa
|
||||
pykka.ActorRegistry.stop_all()
|
||||
|
||||
def possibly_trigger_fake_playback_error(self):
|
||||
@ -135,7 +135,7 @@ class AudioDummyTest(DummyMixin, AudioTest):
|
||||
|
||||
@mock.patch.object(audio.AudioListener, 'send')
|
||||
class AudioEventTest(BaseTest):
|
||||
def setUp(self):
|
||||
def setUp(self): # noqa
|
||||
super(AudioEventTest, self).setUp()
|
||||
self.audio.enable_sync_handler().get()
|
||||
|
||||
@ -292,6 +292,14 @@ class AudioEventTest(BaseTest):
|
||||
call = mock.call('position_changed', position=2000)
|
||||
self.assertIn(call, send_mock.call_args_list)
|
||||
|
||||
def test_tags_changed_on_playback(self, send_mock):
|
||||
self.audio.prepare_change()
|
||||
self.audio.set_uri(self.uris[0])
|
||||
self.audio.start_playback()
|
||||
self.audio.wait_for_state_change().get()
|
||||
|
||||
send_mock.assert_any_call('tags_changed', tags=mock.ANY)
|
||||
|
||||
# Unlike the other events, having the state changed done is not
|
||||
# enough to ensure our event is called. So we setup a threading
|
||||
# event that we can wait for with a timeout while the track playback
|
||||
@ -361,20 +369,20 @@ class AudioEventTest(BaseTest):
|
||||
if not done.wait(timeout=1.0):
|
||||
self.fail('EOS not received')
|
||||
|
||||
excepted = [
|
||||
('position_changed', {'position': 0}),
|
||||
('stream_changed', {'uri': self.uris[0]}),
|
||||
('state_changed', {'old_state': PlaybackState.STOPPED,
|
||||
'new_state': PlaybackState.PLAYING,
|
||||
'target_state': None}),
|
||||
('position_changed', {'position': 0}),
|
||||
('stream_changed', {'uri': self.uris[1]}),
|
||||
('reached_end_of_stream', {})]
|
||||
self.assertEqual(excepted, events)
|
||||
# Check that both uris got played
|
||||
self.assertIn(('stream_changed', {'uri': self.uris[0]}), events)
|
||||
self.assertIn(('stream_changed', {'uri': self.uris[1]}), events)
|
||||
|
||||
# Check that events counts check out.
|
||||
keys = [k for k, v in events]
|
||||
self.assertEqual(2, keys.count('stream_changed'))
|
||||
self.assertEqual(2, keys.count('position_changed'))
|
||||
self.assertEqual(1, keys.count('state_changed'))
|
||||
self.assertEqual(1, keys.count('reached_end_of_stream'))
|
||||
|
||||
|
||||
class AudioDummyEventTest(DummyMixin, AudioEventTest):
|
||||
pass
|
||||
"""Exercise the AudioEventTest against our mock audio classes."""
|
||||
|
||||
|
||||
# TODO: move to mixer tests...
|
||||
@ -399,7 +407,7 @@ class MixerTest(BaseTest):
|
||||
|
||||
|
||||
class AudioStateTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
def setUp(self): # noqa
|
||||
self.audio = audio.Audio(config=None, mixer=None)
|
||||
|
||||
def test_state_starts_as_stopped(self):
|
||||
@ -444,7 +452,7 @@ class AudioStateTest(unittest.TestCase):
|
||||
|
||||
|
||||
class AudioBufferingTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
def setUp(self): # noqa
|
||||
self.audio = audio.Audio(config=None, mixer=None)
|
||||
self.audio._playbin = mock.Mock(spec=['set_state'])
|
||||
|
||||
|
||||
@ -8,7 +8,7 @@ from mopidy import audio
|
||||
|
||||
|
||||
class AudioListenerTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
def setUp(self): # noqa
|
||||
self.listener = audio.AudioListener()
|
||||
|
||||
def test_on_event_forwards_to_specific_handler(self):
|
||||
@ -32,3 +32,6 @@ class AudioListenerTest(unittest.TestCase):
|
||||
|
||||
def test_listener_has_default_impl_for_position_changed(self):
|
||||
self.listener.position_changed(None)
|
||||
|
||||
def test_listener_has_default_impl_for_tags_changed(self):
|
||||
self.listener.tags_changed([])
|
||||
|
||||
Loading…
Reference in New Issue
Block a user