[WIP] Add GStreamerOutput
This commit is contained in:
parent
ded033fd4c
commit
6e5e5a8930
0
mopidy/outputs/__init__.py
Normal file
0
mopidy/outputs/__init__.py
Normal file
130
mopidy/outputs/gstreamer.py
Normal file
130
mopidy/outputs/gstreamer.py
Normal file
@ -0,0 +1,130 @@
|
||||
import gobject
|
||||
|
||||
import pygst
|
||||
pygst.require('0.10')
|
||||
|
||||
import gst
|
||||
import logging
|
||||
|
||||
from mopidy.process import BaseProcess
|
||||
|
||||
logger = logging.getLogger('mopidy.outputs.gstreamer')
|
||||
|
||||
class GStreamerOutput(object):
|
||||
"""
|
||||
Audio output through GStreamer.
|
||||
|
||||
Starts the :class:`GStreamerProcess`.
|
||||
"""
|
||||
|
||||
def __init__(self, core_queue):
|
||||
process = GStreamerProcess(core_queue)
|
||||
process.start()
|
||||
|
||||
class GStreamerProcess(BaseProcess):
|
||||
"""
|
||||
A process for all work related to GStreamer.
|
||||
|
||||
The main loop polls for events from both Mopidy and GStreamer.
|
||||
"""
|
||||
|
||||
def __init__(self, core_queue):
|
||||
self.core_queue = core_queue
|
||||
|
||||
# See http://www.jejik.com/articles/2007/01/
|
||||
# python-gstreamer_threading_and_the_main_loop/ for details.
|
||||
gobject.threads_init()
|
||||
self.gobject_context = gobject.MainLoop().get_context()
|
||||
|
||||
# A pipeline consisting of many elements
|
||||
self.gst_pipeline = gst.Pipeline("pipeline")
|
||||
|
||||
# Setup bus and message processor
|
||||
self.gst_bus = self.gst_pipeline.get_bus()
|
||||
self.gst_bus.add_signal_watch()
|
||||
self.gst_bus_id = self.gst_bus.connect('message', self.process_message)
|
||||
|
||||
# Bin for playing audio URIs
|
||||
self.gst_uri_src = gst.element_factory_make('uridecodebin', 'uri_src')
|
||||
self.gst_pipeline.add(self.gst_uri_src)
|
||||
|
||||
# Bin for playing audio data
|
||||
self.gst_data_src = gst.element_factory_make('appsrc', 'data_src')
|
||||
self.gst_pipeline.add(self.gst_data_src)
|
||||
|
||||
# Volume filter
|
||||
self.gst_volume = gst.element_factory_make('volume', 'volume')
|
||||
self.gst_pipeline.add(self.gst_volume)
|
||||
|
||||
# Audio output sink
|
||||
self.gst_sink = gst.element_factory_make('autoaudiosink', 'sink')
|
||||
self.gst_pipeline.add(self.gst_sink)
|
||||
|
||||
# The audio URI chain
|
||||
gst.element_link_many(self.gst_uri_src, self.gst_volume, self.gst_sink)
|
||||
|
||||
# The audio data chain
|
||||
gst.element_link_many(self.gst_data_src, self.gst_volume,
|
||||
self.gst_sink)
|
||||
|
||||
def _run(self):
|
||||
while True:
|
||||
# TODO Handle commands
|
||||
self.gobject_context.iteration(True)
|
||||
|
||||
def process_message(self, bus, message):
|
||||
if message.type == gst.MESSAGE_EOS:
|
||||
pass # TODO Handle end of track/stream
|
||||
elif message.type == gst.MESSAGE_ERROR:
|
||||
self.gst_bin.set_state(gst.STATE_NULL)
|
||||
error, debug = message.parse_error()
|
||||
logger.error(u'%s %s', error, debug)
|
||||
|
||||
def deliver_data(self, caps_string, data):
|
||||
"""Deliver audio data to be played"""
|
||||
caps = gst.caps_from_string(caps_string)
|
||||
buffer_ = gst.Buffer(data)
|
||||
buffer_.set_caps(caps)
|
||||
self.gst_data_src.emit('push-buffer', buffer_)
|
||||
|
||||
def play_uri(self, uri):
|
||||
"""Play audio at URI"""
|
||||
self.gst_uri_src.set_state(gst.STATE_READY)
|
||||
self.gst_uri_src.set_property('uri', uri)
|
||||
self.gst_uri_src.set_state(gst.STATE_PLAYING)
|
||||
# TODO Return status
|
||||
|
||||
def state_playing(self):
|
||||
"""
|
||||
Set the state to PLAYING.
|
||||
|
||||
Previous state should be READY or PAUSED.
|
||||
"""
|
||||
result = self.gst_uri_src.set_state(gst.STATE_PLAYING)
|
||||
return result == gst.STATE_CHANGE_SUCCESS
|
||||
|
||||
def state_paused(self):
|
||||
"""
|
||||
Set the state to PAUSED.
|
||||
|
||||
Previous state should be PLAYING.
|
||||
"""
|
||||
result = self.gst_uri_src.set_state(gst.STATE_PAUSED)
|
||||
return result == gst.STATE_CHANGE_SUCCESS
|
||||
|
||||
def state_ready(self):
|
||||
"""
|
||||
Set the state to READY.
|
||||
"""
|
||||
result = self.gst_uri_src.set_state(gst.STATE_READY)
|
||||
return result == gst.STATE_CHANGE_SUCCESS
|
||||
|
||||
def get_volume(self):
|
||||
"""Get volume in range [0..100]"""
|
||||
gst_volume = self.gst_volume.get_property('volume')
|
||||
return int(gst_volume * 100)
|
||||
|
||||
def set_volume(self, volume):
|
||||
"""Set volume in range [0..100]"""
|
||||
gst_volume = volume / 100.0
|
||||
self.gst_volume.set_property('volume', gst_volume)
|
||||
Loading…
Reference in New Issue
Block a user