Extend output API with all methods needed for GStreamerOutput
This commit is contained in:
parent
9fe5874069
commit
abce165aa3
@ -17,3 +17,72 @@ class BaseOutput(object):
|
||||
def process_message(self, message):
|
||||
"""Process messages with the output as destination."""
|
||||
raise NotImplementedError
|
||||
|
||||
def play_uri(self, uri):
|
||||
"""
|
||||
Play URI.
|
||||
|
||||
:param uri: the URI to play
|
||||
:type uri: string
|
||||
:rtype: :class:`True` if successful, else :class:`False`
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def deliver_data(self, capabilities, data):
|
||||
"""
|
||||
Deliver audio data to be played.
|
||||
|
||||
:param capabilities: a GStreamer capabilities string
|
||||
:type capabilities: string
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def end_of_data_stream(self):
|
||||
"""Signal that the last audio data has been delivered."""
|
||||
raise NotImplementedError
|
||||
|
||||
def get_position(self):
|
||||
"""
|
||||
Get position in milliseconds.
|
||||
|
||||
:rtype: int
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def set_position(self, position):
|
||||
"""
|
||||
Set position in milliseconds.
|
||||
|
||||
:param position: the position in milliseconds
|
||||
:type volume: int
|
||||
:rtype: :class:`True` if successful, else :class:`False`
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def set_state(self, state):
|
||||
"""
|
||||
Set playback state.
|
||||
|
||||
:param state: the state
|
||||
:type state: string
|
||||
:rtype: :class:`True` if successful, else :class:`False`
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def get_volume(self):
|
||||
"""
|
||||
Get volume level for software mixer.
|
||||
|
||||
:rtype: int in range [0..100]
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def set_volume(self, volume):
|
||||
"""
|
||||
Set volume level for software mixer.
|
||||
|
||||
:param volume: the volume in the range [0..100]
|
||||
:type volume: int
|
||||
:rtype: :class:`True` if successful, else :class:`False`
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@ -15,6 +15,29 @@ class DummyOutput(BaseOutput):
|
||||
#: For testing. Contains all messages :meth:`process_message` has received.
|
||||
messages = []
|
||||
|
||||
#: For testing. Contains the last URI passed to :meth:`play_uri`.
|
||||
uri = None
|
||||
|
||||
#: For testing. Contains the last capabilities passed to
|
||||
#: :meth:`deliver_data`.
|
||||
capabilities = None
|
||||
|
||||
#: For testing. Contains the last data passed to :meth:`deliver_data`.
|
||||
data = None
|
||||
|
||||
#: For testing. :class:`True` if :meth:`end_of_data_stream` has been
|
||||
#: called.
|
||||
end_of_data_stream_called = False
|
||||
|
||||
#: For testing. Contains the current position.
|
||||
position = 0
|
||||
|
||||
#: For testing. Contains the current state.
|
||||
state = 'NULL'
|
||||
|
||||
#: For testing. Contains the current volume.
|
||||
volume = 100
|
||||
|
||||
def start(self):
|
||||
self.start_called = True
|
||||
|
||||
@ -23,7 +46,32 @@ class DummyOutput(BaseOutput):
|
||||
|
||||
def process_message(self, message):
|
||||
self.messages.append(message)
|
||||
if 'reply_to' in message:
|
||||
connection = unpickle_connection(message['reply_to'])
|
||||
# FIXME This is too simple. Some callers expect something else.
|
||||
connection.send(True)
|
||||
|
||||
def play_uri(self, uri):
|
||||
self.uri = uri
|
||||
return True
|
||||
|
||||
def deliver_data(self, capabilities, data):
|
||||
self.capabilities = capabilities
|
||||
self.data = data
|
||||
|
||||
def end_of_data_stream(self):
|
||||
self.end_of_data_stream_called = True
|
||||
|
||||
def get_position(self):
|
||||
return self.position
|
||||
|
||||
def set_position(self, position):
|
||||
self.position = position
|
||||
return True
|
||||
|
||||
def set_state(self, state):
|
||||
self.state = state
|
||||
return True
|
||||
|
||||
def get_volume(self):
|
||||
return self.volume
|
||||
|
||||
def set_volume(self, volume):
|
||||
self.volume = volume
|
||||
return True
|
||||
|
||||
@ -11,7 +11,8 @@ import threading
|
||||
|
||||
from mopidy import settings
|
||||
from mopidy.outputs.base import BaseOutput
|
||||
from mopidy.utils.process import BaseProcess, unpickle_connection
|
||||
from mopidy.utils.process import (BaseProcess, pickle_connection,
|
||||
unpickle_connection)
|
||||
|
||||
logger = logging.getLogger('mopidy.outputs.gstreamer')
|
||||
|
||||
@ -38,17 +39,56 @@ class GStreamerOutput(BaseOutput):
|
||||
self.process.terminate()
|
||||
|
||||
def process_message(self, message):
|
||||
"""
|
||||
Processes messages with the GStreamer output as destination.
|
||||
"""
|
||||
assert message['to'] == 'output', \
|
||||
u'Message recipient must be "output".'
|
||||
self.output_queue.put(message)
|
||||
|
||||
def _send_recv(self, message):
|
||||
(my_end, other_end) = multiprocessing.Pipe()
|
||||
message['to'] = 'output'
|
||||
message['reply_to'] = pickle_connection(other_end)
|
||||
self.process_message(message)
|
||||
my_end.poll(None)
|
||||
return my_end.recv()
|
||||
|
||||
def _send(self, message):
|
||||
message['to'] = 'output'
|
||||
self.process_message(message)
|
||||
|
||||
def play_uri(self, uri):
|
||||
return self._send_recv({'command': 'play_uri', 'uri': uri})
|
||||
|
||||
def deliver_data(self, capabilities, data):
|
||||
return self._send({
|
||||
'command': 'deliver_data',
|
||||
'caps': capabilities,
|
||||
'data': data,
|
||||
})
|
||||
|
||||
def end_of_data_stream(self):
|
||||
return self._send({'command': 'end_of_data_stream'})
|
||||
|
||||
def get_position(self):
|
||||
return self._send_recv({'command': 'get_position'})
|
||||
|
||||
def set_position(self, position):
|
||||
return self._send_recv({'command': 'set_position'})
|
||||
|
||||
def set_state(self, state):
|
||||
return self._send_recv({'command': 'set_state', 'state': state})
|
||||
|
||||
def get_volume(self):
|
||||
return self._send_recv({'command': 'get_volume'})
|
||||
|
||||
def set_volume(self, volume):
|
||||
return self._send_recv({'command': 'set_volume', 'volume': volume})
|
||||
|
||||
|
||||
class GStreamerMessagesThread(threading.Thread):
|
||||
def run(self):
|
||||
gobject.MainLoop().run()
|
||||
|
||||
|
||||
class GStreamerProcess(BaseProcess):
|
||||
"""
|
||||
A process for all work related to GStreamer.
|
||||
|
||||
@ -28,44 +28,39 @@ class GStreamerOutputTest(unittest.TestCase):
|
||||
self.output.destroy()
|
||||
settings.BACKENDS = settings.original_backends
|
||||
|
||||
def send_recv(self, message):
|
||||
(my_end, other_end) = multiprocessing.Pipe()
|
||||
message.update({
|
||||
'to': 'output',
|
||||
'reply_to': pickle_connection(other_end),
|
||||
})
|
||||
self.output.process_message(message)
|
||||
my_end.poll(None)
|
||||
return my_end.recv()
|
||||
|
||||
def send(self, message):
|
||||
message.update({'to': 'output'})
|
||||
self.output.process_message(message)
|
||||
|
||||
def test_play_uri_existing_file(self):
|
||||
message = {'command': 'play_uri', 'uri': self.song_uri}
|
||||
self.assertEqual(True, self.send_recv(message))
|
||||
self.assertTrue(self.output.play_uri(self.song_uri))
|
||||
|
||||
def test_play_uri_non_existing_file(self):
|
||||
message = {'command': 'play_uri', 'uri': self.song_uri + 'bogus'}
|
||||
self.assertEqual(False, self.send_recv(message))
|
||||
self.assertFalse(self.output.play_uri(self.song_uri + 'bogus'))
|
||||
|
||||
@SkipTest
|
||||
def test_deliver_data(self):
|
||||
pass # TODO
|
||||
|
||||
@SkipTest
|
||||
def test_end_of_data_stream(self):
|
||||
pass # TODO
|
||||
|
||||
def test_default_get_volume_result(self):
|
||||
message = {'command': 'get_volume'}
|
||||
self.assertEqual(100, self.send_recv(message))
|
||||
self.assertEqual(100, self.output.get_volume())
|
||||
|
||||
def test_set_volume(self):
|
||||
self.send({'command': 'set_volume', 'volume': 50})
|
||||
self.assertEqual(50, self.send_recv({'command': 'get_volume'}))
|
||||
self.assertTrue(self.output.set_volume(50))
|
||||
self.assertEqual(50, self.output.get_volume())
|
||||
|
||||
def test_set_volume_to_zero(self):
|
||||
self.send({'command': 'set_volume', 'volume': 0})
|
||||
self.assertEqual(0, self.send_recv({'command': 'get_volume'}))
|
||||
self.assertTrue(self.output.set_volume(0))
|
||||
self.assertEqual(0, self.output.get_volume())
|
||||
|
||||
def test_set_volume_to_one_hundred(self):
|
||||
self.send({'command': 'set_volume', 'volume': 100})
|
||||
self.assertEqual(100, self.send_recv({'command': 'get_volume'}))
|
||||
self.assertTrue(self.output.set_volume(100))
|
||||
self.assertEqual(100, self.output.get_volume())
|
||||
|
||||
@SkipTest
|
||||
def test_set_state(self):
|
||||
raise NotImplementedError
|
||||
pass # TODO
|
||||
|
||||
@SkipTest
|
||||
def test_set_position(self):
|
||||
pass # TODO
|
||||
|
||||
Loading…
Reference in New Issue
Block a user