gst1: Update imports to use PyGI

This commit is contained in:
Stein Magnus Jodal 2015-09-02 00:24:02 +02:00
parent d046974aaf
commit 8c82f4773f
14 changed files with 263 additions and 275 deletions

View File

@ -7,12 +7,12 @@ import sys
import textwrap import textwrap
try: try:
import gobject # noqa from gi.repository import GObject, Gst
except ImportError: except ImportError:
print(textwrap.dedent(""" print(textwrap.dedent("""
ERROR: The gobject Python package was not found. ERROR: The GObject and Gst Python packages were not found.
Mopidy requires GStreamer (and GObject) to work. These are C libraries Mopidy requires GStreamer and GObject to work. These are C libraries
with a number of dependencies themselves, and cannot be installed with with a number of dependencies themselves, and cannot be installed with
the regular Python tools like pip. the regular Python tools like pip.
@ -21,7 +21,7 @@ except ImportError:
""")) """))
raise raise
gobject.threads_init() GObject.threads_init()
try: try:
# Make GObject's mainloop the event loop for python-dbus # Make GObject's mainloop the event loop for python-dbus

View File

@ -4,12 +4,9 @@ import logging
import os import os
import threading import threading
import gobject import gi
gi.require_version('Gst', '1.0')
import pygst from gi.repository import GObject, Gst
pygst.require('0.10')
import gst # noqa
import gst.pbutils # noqa
import pykka import pykka
@ -28,9 +25,9 @@ logger = logging.getLogger(__name__)
gst_logger = logging.getLogger('mopidy.audio.gst') gst_logger = logging.getLogger('mopidy.audio.gst')
_GST_STATE_MAPPING = { _GST_STATE_MAPPING = {
gst.STATE_PLAYING: PlaybackState.PLAYING, Gst.STATE_PLAYING: PlaybackState.PLAYING,
gst.STATE_PAUSED: PlaybackState.PAUSED, Gst.STATE_PAUSED: PlaybackState.PAUSED,
gst.STATE_NULL: PlaybackState.STOPPED} Gst.STATE_NULL: PlaybackState.STOPPED}
class _Signals(object): class _Signals(object):
@ -118,9 +115,9 @@ class _Appsrc(object):
if buffer_ is None: if buffer_ is None:
gst_logger.debug('Sending appsrc end-of-stream event.') gst_logger.debug('Sending appsrc end-of-stream event.')
return self._source.emit('end-of-stream') == gst.FLOW_OK return self._source.emit('end-of-stream') == Gst.FLOW_OK
else: else:
return self._source.emit('push-buffer', buffer_) == gst.FLOW_OK return self._source.emit('push-buffer', buffer_) == Gst.FLOW_OK
def _on_signal(self, element, clocktime, func): def _on_signal(self, element, clocktime, func):
# This shim is used to ensure we always return true, and also handles # This shim is used to ensure we always return true, and also handles
@ -133,29 +130,29 @@ class _Appsrc(object):
# TODO: expose this as a property on audio when #790 gets further along. # TODO: expose this as a property on audio when #790 gets further along.
class _Outputs(gst.Bin): class _Outputs(Gst.Bin):
def __init__(self): def __init__(self):
gst.Bin.__init__(self, 'outputs') Gst.Bin.__init__(self, 'outputs')
self._tee = gst.element_factory_make('tee') self._tee = Gst.element_factory_make('tee')
self.add(self._tee) self.add(self._tee)
ghost_pad = gst.GhostPad('sink', self._tee.get_pad('sink')) ghost_pad = Gst.GhostPad('sink', self._tee.get_pad('sink'))
self.add_pad(ghost_pad) self.add_pad(ghost_pad)
# Add an always connected fakesink which respects the clock so the tee # Add an always connected fakesink which respects the clock so the tee
# doesn't fail even if we don't have any outputs. # doesn't fail even if we don't have any outputs.
fakesink = gst.element_factory_make('fakesink') fakesink = Gst.element_factory_make('fakesink')
fakesink.set_property('sync', True) fakesink.set_property('sync', True)
self._add(fakesink) self._add(fakesink)
def add_output(self, description): def add_output(self, description):
# XXX This only works for pipelines not in use until #790 gets done. # XXX This only works for pipelines not in use until #790 gets done.
try: try:
output = gst.parse_bin_from_description( output = Gst.parse_bin_from_description(
description, ghost_unconnected_pads=True) description, ghost_unconnected_pads=True)
except gobject.GError as ex: except GObject.GError as ex:
logger.error( logger.error(
'Failed to create audio output "%s": %s', description, ex) 'Failed to create audio output "%s": %s', description, ex)
raise exceptions.AudioException(bytes(ex)) raise exceptions.AudioException(bytes(ex))
@ -164,7 +161,7 @@ class _Outputs(gst.Bin):
logger.info('Audio output set to "%s"', description) logger.info('Audio output set to "%s"', description)
def _add(self, element): def _add(self, element):
queue = gst.element_factory_make('queue') queue = Gst.element_factory_make('queue')
self.add(element) self.add(element)
self.add(queue) self.add(queue)
queue.link(element) queue.link(element)
@ -234,28 +231,28 @@ class _Handler(object):
self._event_handler_id = None self._event_handler_id = None
def on_message(self, bus, msg): def on_message(self, bus, msg):
if msg.type == gst.MESSAGE_STATE_CHANGED and msg.src == self._element: if msg.type == Gst.MESSAGE_STATE_CHANGED and msg.src == self._element:
self.on_playbin_state_changed(*msg.parse_state_changed()) self.on_playbin_state_changed(*msg.parse_state_changed())
elif msg.type == gst.MESSAGE_BUFFERING: elif msg.type == Gst.MESSAGE_BUFFERING:
self.on_buffering(msg.parse_buffering(), msg.structure) self.on_buffering(msg.parse_buffering(), msg.structure)
elif msg.type == gst.MESSAGE_EOS: elif msg.type == Gst.MESSAGE_EOS:
self.on_end_of_stream() self.on_end_of_stream()
elif msg.type == gst.MESSAGE_ERROR: elif msg.type == Gst.MESSAGE_ERROR:
self.on_error(*msg.parse_error()) self.on_error(*msg.parse_error())
elif msg.type == gst.MESSAGE_WARNING: elif msg.type == Gst.MESSAGE_WARNING:
self.on_warning(*msg.parse_warning()) self.on_warning(*msg.parse_warning())
elif msg.type == gst.MESSAGE_ASYNC_DONE: elif msg.type == Gst.MESSAGE_ASYNC_DONE:
self.on_async_done() self.on_async_done()
elif msg.type == gst.MESSAGE_TAG: elif msg.type == Gst.MESSAGE_TAG:
self.on_tag(msg.parse_tag()) self.on_tag(msg.parse_tag())
elif msg.type == gst.MESSAGE_ELEMENT: elif msg.type == Gst.MESSAGE_ELEMENT:
if gst.pbutils.is_missing_plugin_message(msg): if Gst.pbutils.is_missing_plugin_message(msg):
self.on_missing_plugin(msg) self.on_missing_plugin(msg)
def on_event(self, pad, event): def on_event(self, pad, event):
if event.type == gst.EVENT_NEWSEGMENT: if event.type == Gst.EVENT_NEWSEGMENT:
self.on_new_segment(*event.parse_new_segment()) self.on_new_segment(*event.parse_new_segment())
elif event.type == gst.EVENT_SINK_MESSAGE: elif event.type == Gst.EVENT_SINK_MESSAGE:
# Handle stream changed messages when they reach our output bin. # Handle stream changed messages when they reach our output bin.
# If we listen for it on the bus we get one per tee branch. # If we listen for it on the bus we get one per tee branch.
msg = event.parse_sink_message() msg = event.parse_sink_message()
@ -268,17 +265,17 @@ class _Handler(object):
old_state.value_name, new_state.value_name, old_state.value_name, new_state.value_name,
pending_state.value_name) pending_state.value_name)
if new_state == gst.STATE_READY and pending_state == gst.STATE_NULL: if new_state == Gst.STATE_READY and pending_state == Gst.STATE_NULL:
# XXX: We're not called on the last state change when going down to # XXX: We're not called on the last state change when going down to
# NULL, so we rewrite the second to last call to get the expected # NULL, so we rewrite the second to last call to get the expected
# behavior. # behavior.
new_state = gst.STATE_NULL new_state = Gst.STATE_NULL
pending_state = gst.STATE_VOID_PENDING pending_state = Gst.STATE_VOID_PENDING
if pending_state != gst.STATE_VOID_PENDING: if pending_state != Gst.STATE_VOID_PENDING:
return # Ignore intermediate state changes return # Ignore intermediate state changes
if new_state == gst.STATE_READY: if new_state == Gst.STATE_READY:
return # Ignore READY state as it's GStreamer specific return # Ignore READY state as it's GStreamer specific
new_state = _GST_STATE_MAPPING[new_state] new_state = _GST_STATE_MAPPING[new_state]
@ -297,23 +294,23 @@ class _Handler(object):
AudioListener.send('stream_changed', uri=None) AudioListener.send('stream_changed', uri=None)
if 'GST_DEBUG_DUMP_DOT_DIR' in os.environ: if 'GST_DEBUG_DUMP_DOT_DIR' in os.environ:
gst.DEBUG_BIN_TO_DOT_FILE( Gst.DEBUG_BIN_TO_DOT_FILE(
self._audio._playbin, gst.DEBUG_GRAPH_SHOW_ALL, 'mopidy') self._audio._playbin, Gst.DEBUG_GRAPH_SHOW_ALL, 'mopidy')
def on_buffering(self, percent, structure=None): def on_buffering(self, percent, structure=None):
if structure and structure.has_field('buffering-mode'): if structure and structure.has_field('buffering-mode'):
if structure['buffering-mode'] == gst.BUFFERING_LIVE: if structure['buffering-mode'] == Gst.BUFFERING_LIVE:
return # Live sources stall in paused. return # Live sources stall in paused.
level = logging.getLevelName('TRACE') level = logging.getLevelName('TRACE')
if percent < 10 and not self._audio._buffering: if percent < 10 and not self._audio._buffering:
self._audio._playbin.set_state(gst.STATE_PAUSED) self._audio._playbin.set_state(Gst.STATE_PAUSED)
self._audio._buffering = True self._audio._buffering = True
level = logging.DEBUG level = logging.DEBUG
if percent == 100: if percent == 100:
self._audio._buffering = False self._audio._buffering = False
if self._audio._target_state == gst.STATE_PLAYING: if self._audio._target_state == Gst.STATE_PLAYING:
self._audio._playbin.set_state(gst.STATE_PLAYING) self._audio._playbin.set_state(Gst.STATE_PLAYING)
level = logging.DEBUG level = logging.DEBUG
gst_logger.log(level, 'Got buffering message: percent=%d%%', percent) gst_logger.log(level, 'Got buffering message: percent=%d%%', percent)
@ -346,12 +343,12 @@ class _Handler(object):
AudioListener.send('tags_changed', tags=tags.keys()) AudioListener.send('tags_changed', tags=tags.keys())
def on_missing_plugin(self, msg): def on_missing_plugin(self, msg):
desc = gst.pbutils.missing_plugin_message_get_description(msg) desc = Gst.pbutils.missing_plugin_message_get_description(msg)
debug = gst.pbutils.missing_plugin_message_get_installer_detail(msg) debug = Gst.pbutils.missing_plugin_message_get_installer_detail(msg)
gst_logger.debug('Got missing-plugin message: description:%s', desc) gst_logger.debug('Got missing-plugin message: description:%s', desc)
logger.warning('Could not find a %s to handle media.', desc) logger.warning('Could not find a %s to handle media.', desc)
if gst.pbutils.install_plugins_supported(): if Gst.pbutils.install_plugins_supported():
logger.info('You might be able to fix this by running: ' logger.info('You might be able to fix this by running: '
'gst-installer "%s"', debug) 'gst-installer "%s"', debug)
# TODO: store the missing plugins installer info in a file so we can # TODO: store the missing plugins installer info in a file so we can
@ -362,7 +359,7 @@ class _Handler(object):
gst_logger.debug('Got new-segment event: update=%s rate=%s format=%s ' gst_logger.debug('Got new-segment event: update=%s rate=%s format=%s '
'start=%s stop=%s position=%s', update, rate, 'start=%s stop=%s position=%s', update, rate,
format_.value_name, start, stop, position) format_.value_name, start, stop, position)
position_ms = position // gst.MSECOND position_ms = position // Gst.MSECOND
logger.debug('Audio event: position_changed(position=%s)', position_ms) logger.debug('Audio event: position_changed(position=%s)', position_ms)
AudioListener.send('position_changed', position=position_ms) AudioListener.send('position_changed', position=position_ms)
@ -389,7 +386,7 @@ class Audio(pykka.ThreadingActor):
super(Audio, self).__init__() super(Audio, self).__init__()
self._config = config self._config = config
self._target_state = gst.STATE_NULL self._target_state = Gst.STATE_NULL
self._buffering = False self._buffering = False
self._tags = {} self._tags = {}
@ -411,7 +408,7 @@ class Audio(pykka.ThreadingActor):
self._setup_playbin() self._setup_playbin()
self._setup_outputs() self._setup_outputs()
self._setup_audio_sink() self._setup_audio_sink()
except gobject.GError as ex: except GObject.GError as ex:
logger.exception(ex) logger.exception(ex)
process.exit_process() process.exit_process()
@ -422,19 +419,19 @@ class Audio(pykka.ThreadingActor):
def _setup_preferences(self): def _setup_preferences(self):
# TODO: move out of audio actor? # TODO: move out of audio actor?
# Fix for https://github.com/mopidy/mopidy/issues/604 # Fix for https://github.com/mopidy/mopidy/issues/604
registry = gst.registry_get_default() registry = Gst.registry_get_default()
jacksink = registry.find_feature( jacksink = registry.find_feature(
'jackaudiosink', gst.TYPE_ELEMENT_FACTORY) 'jackaudiosink', Gst.TYPE_ELEMENT_FACTORY)
if jacksink: if jacksink:
jacksink.set_rank(gst.RANK_SECONDARY) jacksink.set_rank(Gst.RANK_SECONDARY)
def _setup_playbin(self): def _setup_playbin(self):
playbin = gst.element_factory_make('playbin2') playbin = Gst.element_factory_make('playbin2')
playbin.set_property('flags', 2) # GST_PLAY_FLAG_AUDIO playbin.set_property('flags', 2) # GST_PLAY_FLAG_AUDIO
# TODO: turn into config values... # TODO: turn into config values...
playbin.set_property('buffer-size', 5 << 20) # 5MB playbin.set_property('buffer-size', 5 << 20) # 5MB
playbin.set_property('buffer-duration', 5 * gst.SECOND) playbin.set_property('buffer-duration', 5 * Gst.SECOND)
self._signals.connect(playbin, 'source-setup', self._on_source_setup) self._signals.connect(playbin, 'source-setup', self._on_source_setup)
self._signals.connect(playbin, 'about-to-finish', self._signals.connect(playbin, 'about-to-finish',
@ -448,13 +445,13 @@ class Audio(pykka.ThreadingActor):
self._handler.teardown_event_handling() self._handler.teardown_event_handling()
self._signals.disconnect(self._playbin, 'about-to-finish') self._signals.disconnect(self._playbin, 'about-to-finish')
self._signals.disconnect(self._playbin, 'source-setup') self._signals.disconnect(self._playbin, 'source-setup')
self._playbin.set_state(gst.STATE_NULL) self._playbin.set_state(Gst.STATE_NULL)
def _setup_outputs(self): def _setup_outputs(self):
# We don't want to use outputs for regular testing, so just install # We don't want to use outputs for regular testing, so just install
# an unsynced fakesink when someone asks for a 'testoutput'. # an unsynced fakesink when someone asks for a 'testoutput'.
if self._config['audio']['output'] == 'testoutput': if self._config['audio']['output'] == 'testoutput':
self._outputs = gst.element_factory_make('fakesink') self._outputs = Gst.element_factory_make('fakesink')
else: else:
self._outputs = _Outputs() self._outputs = _Outputs()
try: try:
@ -465,23 +462,23 @@ class Audio(pykka.ThreadingActor):
self._handler.setup_event_handling(self._outputs.get_pad('sink')) self._handler.setup_event_handling(self._outputs.get_pad('sink'))
def _setup_audio_sink(self): def _setup_audio_sink(self):
audio_sink = gst.Bin('audio-sink') audio_sink = Gst.Bin('audio-sink')
# Queue element to buy us time between the about to finish event and # Queue element to buy us time between the about to finish event and
# the actual switch, i.e. about to switch can block for longer thanks # the actual switch, i.e. about to switch can block for longer thanks
# to this queue. # to this queue.
# TODO: make the min-max values a setting? # TODO: make the min-max values a setting?
queue = gst.element_factory_make('queue') queue = Gst.element_factory_make('queue')
queue.set_property('max-size-buffers', 0) queue.set_property('max-size-buffers', 0)
queue.set_property('max-size-bytes', 0) queue.set_property('max-size-bytes', 0)
queue.set_property('max-size-time', 3 * gst.SECOND) queue.set_property('max-size-time', 3 * Gst.SECOND)
queue.set_property('min-threshold-time', 1 * gst.SECOND) queue.set_property('min-threshold-time', 1 * Gst.SECOND)
audio_sink.add(queue) audio_sink.add(queue)
audio_sink.add(self._outputs) audio_sink.add(self._outputs)
if self.mixer: if self.mixer:
volume = gst.element_factory_make('volume') volume = Gst.element_factory_make('volume')
audio_sink.add(volume) audio_sink.add(volume)
queue.link(volume) queue.link(volume)
volume.link(self._outputs) volume.link(self._outputs)
@ -489,7 +486,7 @@ class Audio(pykka.ThreadingActor):
else: else:
queue.link(self._outputs) queue.link(self._outputs)
ghost_pad = gst.GhostPad('sink', queue.get_pad('sink')) ghost_pad = Gst.GhostPad('sink', queue.get_pad('sink'))
audio_sink.add_pad(ghost_pad) audio_sink.add_pad(ghost_pad)
self._playbin.set_property('audio-sink', audio_sink) self._playbin.set_property('audio-sink', audio_sink)
@ -561,7 +558,7 @@ class Audio(pykka.ThreadingActor):
:type seek_data: callable which takes time position in ms :type seek_data: callable which takes time position in ms
""" """
self._appsrc.prepare( self._appsrc.prepare(
gst.Caps(bytes(caps)), need_data, enough_data, seek_data) Gst.Caps(bytes(caps)), need_data, enough_data, seek_data)
self._playbin.set_property('uri', 'appsrc://') self._playbin.set_property('uri', 'appsrc://')
def emit_data(self, buffer_): def emit_data(self, buffer_):
@ -577,7 +574,7 @@ class Audio(pykka.ThreadingActor):
Returns :class:`True` if data was delivered. Returns :class:`True` if data was delivered.
:param buffer_: buffer to pass to appsrc :param buffer_: buffer to pass to appsrc
:type buffer_: :class:`gst.Buffer` or :class:`None` :type buffer_: :class:`Gst.Buffer` or :class:`None`
:rtype: boolean :rtype: boolean
""" """
return self._appsrc.push(buffer_) return self._appsrc.push(buffer_)
@ -616,9 +613,9 @@ class Audio(pykka.ThreadingActor):
:rtype: int :rtype: int
""" """
try: try:
gst_position = self._playbin.query_position(gst.FORMAT_TIME)[0] gst_position = self._playbin.query_position(Gst.FORMAT_TIME)[0]
return utils.clocktime_to_millisecond(gst_position) return utils.clocktime_to_millisecond(gst_position)
except gst.QueryError: except Gst.QueryError:
# TODO: take state into account for this and possibly also return # TODO: take state into account for this and possibly also return
# None as the unknown value instead of zero? # None as the unknown value instead of zero?
logger.debug('Position query failed') logger.debug('Position query failed')
@ -635,7 +632,7 @@ class Audio(pykka.ThreadingActor):
# TODO: double check seek flags in use. # TODO: double check seek flags in use.
gst_position = utils.millisecond_to_clocktime(position) gst_position = utils.millisecond_to_clocktime(position)
result = self._playbin.seek_simple( result = self._playbin.seek_simple(
gst.Format(gst.FORMAT_TIME), gst.SEEK_FLAG_FLUSH, gst_position) Gst.Format(Gst.FORMAT_TIME), Gst.SEEK_FLAG_FLUSH, gst_position)
gst_logger.debug('Sent flushing seek: position=%s', gst_position) gst_logger.debug('Sent flushing seek: position=%s', gst_position)
return result return result
@ -645,7 +642,7 @@ class Audio(pykka.ThreadingActor):
:rtype: :class:`True` if successfull, else :class:`False` :rtype: :class:`True` if successfull, else :class:`False`
""" """
return self._set_state(gst.STATE_PLAYING) return self._set_state(Gst.STATE_PLAYING)
def pause_playback(self): def pause_playback(self):
""" """
@ -653,7 +650,7 @@ class Audio(pykka.ThreadingActor):
:rtype: :class:`True` if successfull, else :class:`False` :rtype: :class:`True` if successfull, else :class:`False`
""" """
return self._set_state(gst.STATE_PAUSED) return self._set_state(Gst.STATE_PAUSED)
def prepare_change(self): def prepare_change(self):
""" """
@ -664,7 +661,7 @@ class Audio(pykka.ThreadingActor):
is that GStreamer will reset all its state when it changes to is that GStreamer will reset all its state when it changes to
:attr:`gst.STATE_READY`. :attr:`gst.STATE_READY`.
""" """
return self._set_state(gst.STATE_READY) return self._set_state(Gst.STATE_READY)
def stop_playback(self): def stop_playback(self):
""" """
@ -673,7 +670,7 @@ class Audio(pykka.ThreadingActor):
:rtype: :class:`True` if successfull, else :class:`False` :rtype: :class:`True` if successfull, else :class:`False`
""" """
self._buffering = False self._buffering = False
return self._set_state(gst.STATE_NULL) return self._set_state(Gst.STATE_NULL)
def wait_for_state_change(self): def wait_for_state_change(self):
"""Block until any pending state changes are complete. """Block until any pending state changes are complete.
@ -689,7 +686,7 @@ class Audio(pykka.ThreadingActor):
""" """
def sync_handler(bus, message): def sync_handler(bus, message):
self._handler.on_message(bus, message) self._handler.on_message(bus, message)
return gst.BUS_DROP return Gst.BUS_DROP
bus = self._playbin.get_bus() bus = self._playbin.get_bus()
bus.set_sync_handler(sync_handler) bus.set_sync_handler(sync_handler)
@ -710,9 +707,9 @@ class Audio(pykka.ThreadingActor):
"READY" -> "NULL" "READY" -> "NULL"
"READY" -> "PAUSED" "READY" -> "PAUSED"
:param state: State to set playbin to. One of: `gst.STATE_NULL`, :param state: State to set playbin to. One of: `Gst.STATE_NULL`,
`gst.STATE_READY`, `gst.STATE_PAUSED` and `gst.STATE_PLAYING`. `Gst.STATE_READY`, `Gst.STATE_PAUSED` and `Gst.STATE_PLAYING`.
:type state: :class:`gst.State` :type state: :class:`Gst.State`
:rtype: :class:`True` if successfull, else :class:`False` :rtype: :class:`True` if successfull, else :class:`False`
""" """
self._target_state = state self._target_state = state
@ -720,7 +717,7 @@ class Audio(pykka.ThreadingActor):
gst_logger.debug('State change to %s: result=%s', state.value_name, gst_logger.debug('State change to %s: result=%s', state.value_name,
result.value_name) result.value_name)
if result == gst.STATE_CHANGE_FAILURE: if result == Gst.STATE_CHANGE_FAILURE:
logger.warning( logger.warning(
'Setting GStreamer state to %s failed', state.value_name) 'Setting GStreamer state to %s failed', state.value_name)
return False return False
@ -740,25 +737,25 @@ class Audio(pykka.ThreadingActor):
:param track: the current track :param track: the current track
:type track: :class:`mopidy.models.Track` :type track: :class:`mopidy.models.Track`
""" """
taglist = gst.TagList() taglist = Gst.TagList()
artists = [a for a in (track.artists or []) if a.name] artists = [a for a in (track.artists or []) if a.name]
# Default to blank data to trick shoutcast into clearing any previous # Default to blank data to trick shoutcast into clearing any previous
# values it might have. # values it might have.
taglist[gst.TAG_ARTIST] = ' ' taglist[Gst.TAG_ARTIST] = ' '
taglist[gst.TAG_TITLE] = ' ' taglist[Gst.TAG_TITLE] = ' '
taglist[gst.TAG_ALBUM] = ' ' taglist[Gst.TAG_ALBUM] = ' '
if artists: if artists:
taglist[gst.TAG_ARTIST] = ', '.join([a.name for a in artists]) taglist[Gst.TAG_ARTIST] = ', '.join([a.name for a in artists])
if track.name: if track.name:
taglist[gst.TAG_TITLE] = track.name taglist[Gst.TAG_TITLE] = track.name
if track.album and track.album.name: if track.album and track.album.name:
taglist[gst.TAG_ALBUM] = track.album.name taglist[Gst.TAG_ALBUM] = track.album.name
event = gst.event_new_tag(taglist) event = Gst.event_new_tag(taglist)
# TODO: check if we get this back on our own bus? # TODO: check if we get this back on our own bus?
self._playbin.send_event(event) self._playbin.send_event(event)
gst_logger.debug('Sent tag event: track=%s', track.uri) gst_logger.debug('Sent tag event: track=%s', track.uri)

View File

@ -3,10 +3,9 @@ from __future__ import (
import collections import collections
import pygst import gi
pygst.require('0.10') gi.require_version('Gst', '1.0')
import gst # noqa from gi.repository import GObject, Gst, GstPbutils
import gst.pbutils # noqa
from mopidy import exceptions from mopidy import exceptions
from mopidy.audio import utils from mopidy.audio import utils
@ -15,7 +14,7 @@ from mopidy.internal import encoding
_Result = collections.namedtuple( _Result = collections.namedtuple(
'Result', ('uri', 'tags', 'duration', 'seekable', 'mime', 'playable')) 'Result', ('uri', 'tags', 'duration', 'seekable', 'mime', 'playable'))
_RAW_AUDIO = gst.Caps(b'audio/x-raw-int; audio/x-raw-float') _RAW_AUDIO = Gst.Caps(b'audio/x-raw-int; audio/x-raw-float')
# TODO: replace with a scan(uri, timeout=1000, proxy_config=None)? # TODO: replace with a scan(uri, timeout=1000, proxy_config=None)?
@ -59,7 +58,7 @@ class Scanner(object):
duration = _query_duration(pipeline) duration = _query_duration(pipeline)
seekable = _query_seekable(pipeline) seekable = _query_seekable(pipeline)
finally: finally:
pipeline.set_state(gst.STATE_NULL) pipeline.set_state(Gst.STATE_NULL)
del pipeline del pipeline
return _Result(uri, tags, duration, seekable, mime, have_audio) return _Result(uri, tags, duration, seekable, mime, have_audio)
@ -68,17 +67,17 @@ class Scanner(object):
# Turns out it's _much_ faster to just create a new pipeline for every as # Turns out it's _much_ faster to just create a new pipeline for every as
# decodebins and other elements don't seem to take well to being reused. # decodebins and other elements don't seem to take well to being reused.
def _setup_pipeline(uri, proxy_config=None): def _setup_pipeline(uri, proxy_config=None):
src = gst.element_make_from_uri(gst.URI_SRC, uri) src = Gst.element_make_from_uri(Gst.URI_SRC, uri)
if not src: if not src:
raise exceptions.ScannerError('GStreamer can not open: %s' % uri) raise exceptions.ScannerError('GStreamer can not open: %s' % uri)
typefind = gst.element_factory_make('typefind') typefind = Gst.element_factory_make('typefind')
decodebin = gst.element_factory_make('decodebin2') decodebin = Gst.element_factory_make('decodebin2')
pipeline = gst.element_factory_make('pipeline') pipeline = Gst.element_factory_make('pipeline')
for e in (src, typefind, decodebin): for e in (src, typefind, decodebin):
pipeline.add(e) pipeline.add(e)
gst.element_link_many(src, typefind, decodebin) Gst.element_link_many(src, typefind, decodebin)
if proxy_config: if proxy_config:
utils.setup_proxy(src, proxy_config) utils.setup_proxy(src, proxy_config)
@ -91,13 +90,13 @@ def _setup_pipeline(uri, proxy_config=None):
def _have_type(element, probability, caps, decodebin): def _have_type(element, probability, caps, decodebin):
decodebin.set_property('sink-caps', caps) decodebin.set_property('sink-caps', caps)
struct = gst.Structure('have-type') struct = Gst.Structure('have-type')
struct['caps'] = caps.get_structure(0) struct['caps'] = caps.get_structure(0)
element.get_bus().post(gst.message_new_application(element, struct)) element.get_bus().post(Gst.message_new_application(element, struct))
def _pad_added(element, pad, pipeline): def _pad_added(element, pad, pipeline):
sink = gst.element_factory_make('fakesink') sink = Gst.element_factory_make('fakesink')
sink.set_property('sync', False) sink.set_property('sync', False)
pipeline.add(sink) pipeline.add(sink)
@ -105,29 +104,29 @@ def _pad_added(element, pad, pipeline):
pad.link(sink.get_pad('sink')) pad.link(sink.get_pad('sink'))
if pad.get_caps().is_subset(_RAW_AUDIO): if pad.get_caps().is_subset(_RAW_AUDIO):
struct = gst.Structure('have-audio') struct = Gst.Structure('have-audio')
element.get_bus().post(gst.message_new_application(element, struct)) element.get_bus().post(Gst.message_new_application(element, struct))
def _start_pipeline(pipeline): def _start_pipeline(pipeline):
if pipeline.set_state(gst.STATE_PAUSED) == gst.STATE_CHANGE_NO_PREROLL: if pipeline.set_state(Gst.STATE_PAUSED) == Gst.STATE_CHANGE_NO_PREROLL:
pipeline.set_state(gst.STATE_PLAYING) pipeline.set_state(Gst.STATE_PLAYING)
def _query_duration(pipeline): def _query_duration(pipeline):
try: try:
duration = pipeline.query_duration(gst.FORMAT_TIME, None)[0] duration = pipeline.query_duration(Gst.FORMAT_TIME, None)[0]
except gst.QueryError: except Gst.QueryError:
return None return None
if duration < 0: if duration < 0:
return None return None
else: else:
return duration // gst.MSECOND return duration // Gst.MSECOND
def _query_seekable(pipeline): def _query_seekable(pipeline):
query = gst.query_new_seeking(gst.FORMAT_TIME) query = Gst.query_new_seeking(Gst.FORMAT_TIME)
pipeline.query(query) pipeline.query(query)
return query.parse_seeking()[1] return query.parse_seeking()[1]
@ -135,15 +134,15 @@ def _query_seekable(pipeline):
def _process(pipeline, timeout_ms): def _process(pipeline, timeout_ms):
clock = pipeline.get_clock() clock = pipeline.get_clock()
bus = pipeline.get_bus() bus = pipeline.get_bus()
timeout = timeout_ms * gst.MSECOND timeout = timeout_ms * Gst.MSECOND
tags = {} tags = {}
mime = None mime = None
have_audio = False have_audio = False
missing_message = None missing_message = None
types = ( types = (
gst.MESSAGE_ELEMENT | gst.MESSAGE_APPLICATION | gst.MESSAGE_ERROR | Gst.MESSAGE_ELEMENT | Gst.MESSAGE_APPLICATION | Gst.MESSAGE_ERROR |
gst.MESSAGE_EOS | gst.MESSAGE_ASYNC_DONE | gst.MESSAGE_TAG) Gst.MESSAGE_EOS | Gst.MESSAGE_ASYNC_DONE | Gst.MESSAGE_TAG)
previous = clock.get_time() previous = clock.get_time()
while timeout > 0: while timeout > 0:
@ -151,29 +150,29 @@ def _process(pipeline, timeout_ms):
if message is None: if message is None:
break break
elif message.type == gst.MESSAGE_ELEMENT: elif message.type == Gst.MESSAGE_ELEMENT:
if gst.pbutils.is_missing_plugin_message(message): if GstPbutils.is_missing_plugin_message(message):
missing_message = message missing_message = message
elif message.type == gst.MESSAGE_APPLICATION: elif message.type == Gst.MESSAGE_APPLICATION:
if message.structure.get_name() == 'have-type': if message.structure.get_name() == 'have-type':
mime = message.structure['caps'].get_name() mime = message.structure['caps'].get_name()
if mime.startswith('text/') or mime == 'application/xml': if mime.startswith('text/') or mime == 'application/xml':
return tags, mime, have_audio return tags, mime, have_audio
elif message.structure.get_name() == 'have-audio': elif message.structure.get_name() == 'have-audio':
have_audio = True have_audio = True
elif message.type == gst.MESSAGE_ERROR: elif message.type == Gst.MESSAGE_ERROR:
error = encoding.locale_decode(message.parse_error()[0]) error = encoding.locale_decode(message.parse_error()[0])
if missing_message and not mime: if missing_message and not mime:
caps = missing_message.structure['detail'] caps = missing_message.structure['detail']
mime = caps.get_structure(0).get_name() mime = caps.get_structure(0).get_name()
return tags, mime, have_audio return tags, mime, have_audio
raise exceptions.ScannerError(error) raise exceptions.ScannerError(error)
elif message.type == gst.MESSAGE_EOS: elif message.type == Gst.MESSAGE_EOS:
return tags, mime, have_audio return tags, mime, have_audio
elif message.type == gst.MESSAGE_ASYNC_DONE: elif message.type == Gst.MESSAGE_ASYNC_DONE:
if message.src == pipeline: if message.src == pipeline:
return tags, mime, have_audio return tags, mime, have_audio
elif message.type == gst.MESSAGE_TAG: elif message.type == Gst.MESSAGE_TAG:
taglist = message.parse_tag() taglist = message.parse_tag()
# Note that this will only keep the last tag. # Note that this will only keep the last tag.
tags.update(utils.convert_taglist(taglist)) tags.update(utils.convert_taglist(taglist))
@ -189,15 +188,13 @@ if __name__ == '__main__':
import os import os
import sys import sys
import gobject
from mopidy.internal import path from mopidy.internal import path
gobject.threads_init() GObject.threads_init()
scanner = Scanner(5000) scanner = Scanner(5000)
for uri in sys.argv[1:]: for uri in sys.argv[1:]:
if not gst.uri_is_valid(uri): if not Gst.uri_is_valid(uri):
uri = path.path_to_uri(os.path.abspath(uri)) uri = path.path_to_uri(os.path.abspath(uri))
try: try:
result = scanner.scan(uri) result = scanner.scan(uri)

View File

@ -4,9 +4,9 @@ import datetime
import logging import logging
import numbers import numbers
import pygst import gi
pygst.require('0.10') gi.require_version('Gst', '1.0')
import gst # noqa from gi.repository import Gst
from mopidy import compat, httpclient from mopidy import compat, httpclient
from mopidy.models import Album, Artist, Track from mopidy.models import Album, Artist, Track
@ -17,7 +17,7 @@ logger = logging.getLogger(__name__)
def calculate_duration(num_samples, sample_rate): def calculate_duration(num_samples, sample_rate):
"""Determine duration of samples using GStreamer helper for precise """Determine duration of samples using GStreamer helper for precise
math.""" math."""
return gst.util_uint64_scale(num_samples, gst.SECOND, sample_rate) return Gst.util_uint64_scale(num_samples, Gst.SECOND, sample_rate)
def create_buffer(data, capabilites=None, timestamp=None, duration=None): def create_buffer(data, capabilites=None, timestamp=None, duration=None):
@ -25,10 +25,10 @@ def create_buffer(data, capabilites=None, timestamp=None, duration=None):
Mainly intended to keep gst imports out of non-audio modules. Mainly intended to keep gst imports out of non-audio modules.
""" """
buffer_ = gst.Buffer(data) buffer_ = Gst.Buffer(data)
if capabilites: if capabilites:
if isinstance(capabilites, compat.string_types): if isinstance(capabilites, compat.string_types):
capabilites = gst.caps_from_string(capabilites) capabilites = Gst.caps_from_string(capabilites)
buffer_.set_caps(capabilites) buffer_.set_caps(capabilites)
if timestamp: if timestamp:
buffer_.timestamp = timestamp buffer_.timestamp = timestamp
@ -39,12 +39,12 @@ def create_buffer(data, capabilites=None, timestamp=None, duration=None):
def millisecond_to_clocktime(value): def millisecond_to_clocktime(value):
"""Convert a millisecond time to internal GStreamer time.""" """Convert a millisecond time to internal GStreamer time."""
return value * gst.MSECOND return value * Gst.MSECOND
def clocktime_to_millisecond(value): def clocktime_to_millisecond(value):
"""Convert an internal GStreamer time to millisecond time.""" """Convert an internal GStreamer time to millisecond time."""
return value // gst.MSECOND return value // Gst.MSECOND
def supported_uri_schemes(uri_schemes): def supported_uri_schemes(uri_schemes):
@ -55,9 +55,9 @@ def supported_uri_schemes(uri_schemes):
:rtype: set of URI schemes we can support via this GStreamer install. :rtype: set of URI schemes we can support via this GStreamer install.
""" """
supported_schemes = set() supported_schemes = set()
registry = gst.registry_get_default() registry = Gst.registry_get_default()
for factory in registry.get_feature_list(gst.TYPE_ELEMENT_FACTORY): for factory in registry.get_feature_list(Gst.TYPE_ELEMENT_FACTORY):
for uri in factory.get_uri_protocols(): for uri in factory.get_uri_protocols():
if uri in uri_schemes: if uri in uri_schemes:
supported_schemes.add(uri) supported_schemes.add(uri)
@ -95,37 +95,37 @@ def convert_tags_to_track(tags):
album_kwargs = {} album_kwargs = {}
track_kwargs = {} track_kwargs = {}
track_kwargs['composers'] = _artists(tags, gst.TAG_COMPOSER) track_kwargs['composers'] = _artists(tags, Gst.TAG_COMPOSER)
track_kwargs['performers'] = _artists(tags, gst.TAG_PERFORMER) track_kwargs['performers'] = _artists(tags, Gst.TAG_PERFORMER)
track_kwargs['artists'] = _artists(tags, gst.TAG_ARTIST, track_kwargs['artists'] = _artists(tags, Gst.TAG_ARTIST,
'musicbrainz-artistid', 'musicbrainz-artistid',
'musicbrainz-sortname') 'musicbrainz-sortname')
album_kwargs['artists'] = _artists( album_kwargs['artists'] = _artists(
tags, gst.TAG_ALBUM_ARTIST, 'musicbrainz-albumartistid') tags, Gst.TAG_ALBUM_ARTIST, 'musicbrainz-albumartistid')
track_kwargs['genre'] = '; '.join(tags.get(gst.TAG_GENRE, [])) track_kwargs['genre'] = '; '.join(tags.get(Gst.TAG_GENRE, []))
track_kwargs['name'] = '; '.join(tags.get(gst.TAG_TITLE, [])) track_kwargs['name'] = '; '.join(tags.get(Gst.TAG_TITLE, []))
if not track_kwargs['name']: if not track_kwargs['name']:
track_kwargs['name'] = '; '.join(tags.get(gst.TAG_ORGANIZATION, [])) track_kwargs['name'] = '; '.join(tags.get(Gst.TAG_ORGANIZATION, []))
track_kwargs['comment'] = '; '.join(tags.get('comment', [])) track_kwargs['comment'] = '; '.join(tags.get('comment', []))
if not track_kwargs['comment']: if not track_kwargs['comment']:
track_kwargs['comment'] = '; '.join(tags.get(gst.TAG_LOCATION, [])) track_kwargs['comment'] = '; '.join(tags.get(Gst.TAG_LOCATION, []))
if not track_kwargs['comment']: if not track_kwargs['comment']:
track_kwargs['comment'] = '; '.join(tags.get(gst.TAG_COPYRIGHT, [])) track_kwargs['comment'] = '; '.join(tags.get(Gst.TAG_COPYRIGHT, []))
track_kwargs['track_no'] = tags.get(gst.TAG_TRACK_NUMBER, [None])[0] track_kwargs['track_no'] = tags.get(Gst.TAG_TRACK_NUMBER, [None])[0]
track_kwargs['disc_no'] = tags.get(gst.TAG_ALBUM_VOLUME_NUMBER, [None])[0] track_kwargs['disc_no'] = tags.get(Gst.TAG_ALBUM_VOLUME_NUMBER, [None])[0]
track_kwargs['bitrate'] = tags.get(gst.TAG_BITRATE, [None])[0] track_kwargs['bitrate'] = tags.get(Gst.TAG_BITRATE, [None])[0]
track_kwargs['musicbrainz_id'] = tags.get('musicbrainz-trackid', [None])[0] track_kwargs['musicbrainz_id'] = tags.get('musicbrainz-trackid', [None])[0]
album_kwargs['name'] = tags.get(gst.TAG_ALBUM, [None])[0] album_kwargs['name'] = tags.get(Gst.TAG_ALBUM, [None])[0]
album_kwargs['num_tracks'] = tags.get(gst.TAG_TRACK_COUNT, [None])[0] album_kwargs['num_tracks'] = tags.get(Gst.TAG_TRACK_COUNT, [None])[0]
album_kwargs['num_discs'] = tags.get(gst.TAG_ALBUM_VOLUME_COUNT, [None])[0] album_kwargs['num_discs'] = tags.get(Gst.TAG_ALBUM_VOLUME_COUNT, [None])[0]
album_kwargs['musicbrainz_id'] = tags.get('musicbrainz-albumid', [None])[0] album_kwargs['musicbrainz_id'] = tags.get('musicbrainz-albumid', [None])[0]
if tags.get(gst.TAG_DATE) and tags.get(gst.TAG_DATE)[0]: if tags.get(Gst.TAG_DATE) and tags.get(Gst.TAG_DATE)[0]:
track_kwargs['date'] = tags[gst.TAG_DATE][0].isoformat() track_kwargs['date'] = tags[Gst.TAG_DATE][0].isoformat()
# Clear out any empty values we found # Clear out any empty values we found
track_kwargs = {k: v for k, v in track_kwargs.items() if v} track_kwargs = {k: v for k, v in track_kwargs.items() if v}
@ -142,7 +142,7 @@ def setup_proxy(element, config):
"""Configure a GStreamer element with proxy settings. """Configure a GStreamer element with proxy settings.
:param element: element to setup proxy in. :param element: element to setup proxy in.
:type element: :class:`gst.GstElement` :type element: :class:`Gst.GstElement`
:param config: proxy settings to use. :param config: proxy settings to use.
:type config: :class:`dict` :type config: :class:`dict`
""" """
@ -155,7 +155,7 @@ def setup_proxy(element, config):
def convert_taglist(taglist): def convert_taglist(taglist):
"""Convert a :class:`gst.Taglist` to plain Python types. """Convert a :class:`Gst.Taglist` to plain Python types.
Knows how to convert: Knows how to convert:
@ -172,7 +172,7 @@ def convert_taglist(taglist):
0.10.36/gstreamer/html/gstreamer-GstTagList.html 0.10.36/gstreamer/html/gstreamer-GstTagList.html
:param taglist: A GStreamer taglist to be converted. :param taglist: A GStreamer taglist to be converted.
:type taglist: :class:`gst.Taglist` :type taglist: :class:`Gst.Taglist`
:rtype: dictionary of tag keys with a list of values. :rtype: dictionary of tag keys with a list of values.
""" """
result = {} result = {}
@ -187,13 +187,13 @@ def convert_taglist(taglist):
values = [values] values = [values]
for value in values: for value in values:
if isinstance(value, gst.Date): if isinstance(value, Gst.Date):
try: try:
date = datetime.date(value.year, value.month, value.day) date = datetime.date(value.year, value.month, value.day)
result[key].append(date) result[key].append(date)
except ValueError: except ValueError:
logger.debug('Ignoring invalid date: %r = %r', key, value) logger.debug('Ignoring invalid date: %r = %r', key, value)
elif isinstance(value, gst.Buffer): elif isinstance(value, Gst.Buffer):
result[key].append(bytes(value)) result[key].append(bytes(value))
elif isinstance( elif isinstance(
value, (compat.string_types, bool, numbers.Number)): value, (compat.string_types, bool, numbers.Number)):

View File

@ -7,9 +7,7 @@ import logging
import os import os
import sys import sys
import glib from gi.repository import GLib, GObject
import gobject
import pykka import pykka
@ -21,7 +19,7 @@ from mopidy.internal import deps, process, timer, versioning
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
_default_config = [] _default_config = []
for base in glib.get_system_config_dirs() + (glib.get_user_config_dir(),): for base in GLib.get_system_config_dirs() + (GLib.get_user_config_dir(),):
_default_config.append(os.path.join(base, b'mopidy', b'mopidy.conf')) _default_config.append(os.path.join(base, b'mopidy', b'mopidy.conf'))
DEFAULT_CONFIG = b':'.join(_default_config) DEFAULT_CONFIG = b':'.join(_default_config)
@ -286,7 +284,7 @@ class RootCommand(Command):
help='`section/key=value` values to override config options') help='`section/key=value` values to override config options')
def run(self, args, config): def run(self, args, config):
loop = gobject.MainLoop() loop = GObject.MainLoop()
mixer_class = self.get_mixer_class(config, args.registry['mixer']) mixer_class = self.get_mixer_class(config, args.registry['mixer'])
backend_classes = args.registry['backend'] backend_classes = args.registry['backend']

View File

@ -5,11 +5,11 @@ import os
import platform import platform
import sys import sys
import pkg_resources import gi
gi.require_version('Gst', '1.0')
from gi.repository import Gst
import pygst import pkg_resources
pygst.require('0.10')
import gst # noqa
from mopidy.internal import formatting from mopidy.internal import formatting
@ -110,8 +110,7 @@ def pkg_info(project_name=None, include_extras=False):
def gstreamer_info(): def gstreamer_info():
other = [] other = []
other.append('Python wrapper: gst-python %s' % ( other.append('Python wrapper: python-gi %s' % gi.__version__)
'.'.join(map(str, gst.get_pygst_version()))))
found_elements = [] found_elements = []
missing_elements = [] missing_elements = []
@ -135,8 +134,8 @@ def gstreamer_info():
return { return {
'name': 'GStreamer', 'name': 'GStreamer',
'version': '.'.join(map(str, gst.get_gst_version())), 'version': '.'.join(map(str, Gst.version())),
'path': os.path.dirname(gst.__file__), 'path': os.path.dirname(gi.__file__),
'other': '\n'.join(other), 'other': '\n'.join(other),
} }
@ -187,6 +186,6 @@ def _gstreamer_check_elements():
] ]
known_elements = [ known_elements = [
factory.get_name() for factory in factory.get_name() for factory in
gst.registry_get_default().get_feature_list(gst.TYPE_ELEMENT_FACTORY)] Gst.registry_get_default().get_feature_list(Gst.TYPE_ELEMENT_FACTORY)]
return [ return [
(element, element in known_elements) for element in elements_to_check] (element, element in known_elements) for element in elements_to_check]

View File

@ -7,7 +7,7 @@ import socket
import sys import sys
import threading import threading
import gobject from gi.repository import GObject
import pykka import pykka
@ -67,7 +67,7 @@ def format_hostname(hostname):
class Server(object): class Server(object):
"""Setup listener and register it with gobject's event loop.""" """Setup listener and register it with GObject's event loop."""
def __init__(self, host, port, protocol, protocol_kwargs=None, def __init__(self, host, port, protocol, protocol_kwargs=None,
max_connections=5, timeout=30): max_connections=5, timeout=30):
@ -87,7 +87,7 @@ class Server(object):
return sock return sock
def register_server_socket(self, fileno): def register_server_socket(self, fileno):
gobject.io_add_watch(fileno, gobject.IO_IN, self.handle_connection) GObject.io_add_watch(fileno, GObject.IO_IN, self.handle_connection)
def handle_connection(self, fd, flags): def handle_connection(self, fd, flags):
try: try:
@ -132,7 +132,7 @@ class Server(object):
class Connection(object): class Connection(object):
# NOTE: the callback code is _not_ run in the actor's thread, but in the # NOTE: the callback code is _not_ run in the actor's thread, but in the
# same one as the event loop. If code in the callbacks blocks, the rest of # same one as the event loop. If code in the callbacks blocks, the rest of
# gobject code will likely be blocked as well... # GObject code will likely be blocked as well...
# #
# Also note that source_remove() return values are ignored on purpose, a # Also note that source_remove() return values are ignored on purpose, a
# false return value would only tell us that what we thought was registered # false return value would only tell us that what we thought was registered
@ -211,14 +211,14 @@ class Connection(object):
return return
self.disable_timeout() self.disable_timeout()
self.timeout_id = gobject.timeout_add_seconds( self.timeout_id = GObject.timeout_add_seconds(
self.timeout, self.timeout_callback) self.timeout, self.timeout_callback)
def disable_timeout(self): def disable_timeout(self):
"""Deactivate timeout mechanism.""" """Deactivate timeout mechanism."""
if self.timeout_id is None: if self.timeout_id is None:
return return
gobject.source_remove(self.timeout_id) GObject.source_remove(self.timeout_id)
self.timeout_id = None self.timeout_id = None
def enable_recv(self): def enable_recv(self):
@ -226,9 +226,9 @@ class Connection(object):
return return
try: try:
self.recv_id = gobject.io_add_watch( self.recv_id = GObject.io_add_watch(
self.sock.fileno(), self.sock.fileno(),
gobject.IO_IN | gobject.IO_ERR | gobject.IO_HUP, GObject.IO_IN | GObject.IO_ERR | GObject.IO_HUP,
self.recv_callback) self.recv_callback)
except socket.error as e: except socket.error as e:
self.stop('Problem with connection: %s' % e) self.stop('Problem with connection: %s' % e)
@ -236,7 +236,7 @@ class Connection(object):
def disable_recv(self): def disable_recv(self):
if self.recv_id is None: if self.recv_id is None:
return return
gobject.source_remove(self.recv_id) GObject.source_remove(self.recv_id)
self.recv_id = None self.recv_id = None
def enable_send(self): def enable_send(self):
@ -244,9 +244,9 @@ class Connection(object):
return return
try: try:
self.send_id = gobject.io_add_watch( self.send_id = GObject.io_add_watch(
self.sock.fileno(), self.sock.fileno(),
gobject.IO_OUT | gobject.IO_ERR | gobject.IO_HUP, GObject.IO_OUT | GObject.IO_ERR | GObject.IO_HUP,
self.send_callback) self.send_callback)
except socket.error as e: except socket.error as e:
self.stop('Problem with connection: %s' % e) self.stop('Problem with connection: %s' % e)
@ -255,11 +255,11 @@ class Connection(object):
if self.send_id is None: if self.send_id is None:
return return
gobject.source_remove(self.send_id) GObject.source_remove(self.send_id)
self.send_id = None self.send_id = None
def recv_callback(self, fd, flags): def recv_callback(self, fd, flags):
if flags & (gobject.IO_ERR | gobject.IO_HUP): if flags & (GObject.IO_ERR | GObject.IO_HUP):
self.stop('Bad client flags: %s' % flags) self.stop('Bad client flags: %s' % flags)
return True return True
@ -283,7 +283,7 @@ class Connection(object):
return True return True
def send_callback(self, fd, flags): def send_callback(self, fd, flags):
if flags & (gobject.IO_ERR | gobject.IO_HUP): if flags & (GObject.IO_ERR | GObject.IO_HUP):
self.stop('Bad client flags: %s' % flags) self.stop('Bad client flags: %s' % flags)
return True return True

View File

@ -2,10 +2,6 @@ from __future__ import absolute_import, unicode_literals
import io import io
import pygst
pygst.require('0.10')
import gst # noqa
from mopidy.compat import configparser from mopidy.compat import configparser
from mopidy.internal import validation from mopidy.internal import validation

View File

@ -3,15 +3,13 @@ from __future__ import absolute_import, unicode_literals
import threading import threading
import unittest import unittest
import gobject import gi
gobject.threads_init() gi.require_version('Gst', '1.0')
from gi.repository import GObject, Gst
GObject.threads_init()
import mock import mock
import pygst
pygst.require('0.10')
import gst # noqa
import pykka import pykka
from mopidy import audio from mopidy import audio
@ -520,17 +518,17 @@ class AudioStateTest(unittest.TestCase):
def test_state_does_not_change_when_in_gst_ready_state(self): def test_state_does_not_change_when_in_gst_ready_state(self):
self.audio._handler.on_playbin_state_changed( self.audio._handler.on_playbin_state_changed(
gst.STATE_NULL, gst.STATE_READY, gst.STATE_VOID_PENDING) Gst.STATE_NULL, Gst.STATE_READY, Gst.STATE_VOID_PENDING)
self.assertEqual(audio.PlaybackState.STOPPED, self.audio.state) self.assertEqual(audio.PlaybackState.STOPPED, self.audio.state)
def test_state_changes_from_stopped_to_playing_on_play(self): def test_state_changes_from_stopped_to_playing_on_play(self):
self.audio._handler.on_playbin_state_changed( self.audio._handler.on_playbin_state_changed(
gst.STATE_NULL, gst.STATE_READY, gst.STATE_PLAYING) Gst.STATE_NULL, Gst.STATE_READY, Gst.STATE_PLAYING)
self.audio._handler.on_playbin_state_changed( self.audio._handler.on_playbin_state_changed(
gst.STATE_READY, gst.STATE_PAUSED, gst.STATE_PLAYING) Gst.STATE_READY, Gst.STATE_PAUSED, Gst.STATE_PLAYING)
self.audio._handler.on_playbin_state_changed( self.audio._handler.on_playbin_state_changed(
gst.STATE_PAUSED, gst.STATE_PLAYING, gst.STATE_VOID_PENDING) Gst.STATE_PAUSED, Gst.STATE_PLAYING, Gst.STATE_VOID_PENDING)
self.assertEqual(audio.PlaybackState.PLAYING, self.audio.state) self.assertEqual(audio.PlaybackState.PLAYING, self.audio.state)
@ -538,7 +536,7 @@ class AudioStateTest(unittest.TestCase):
self.audio.state = audio.PlaybackState.PLAYING self.audio.state = audio.PlaybackState.PLAYING
self.audio._handler.on_playbin_state_changed( self.audio._handler.on_playbin_state_changed(
gst.STATE_PLAYING, gst.STATE_PAUSED, gst.STATE_VOID_PENDING) Gst.STATE_PLAYING, Gst.STATE_PAUSED, Gst.STATE_VOID_PENDING)
self.assertEqual(audio.PlaybackState.PAUSED, self.audio.state) self.assertEqual(audio.PlaybackState.PAUSED, self.audio.state)
@ -546,12 +544,12 @@ class AudioStateTest(unittest.TestCase):
self.audio.state = audio.PlaybackState.PLAYING self.audio.state = audio.PlaybackState.PLAYING
self.audio._handler.on_playbin_state_changed( self.audio._handler.on_playbin_state_changed(
gst.STATE_PLAYING, gst.STATE_PAUSED, gst.STATE_NULL) Gst.STATE_PLAYING, Gst.STATE_PAUSED, Gst.STATE_NULL)
self.audio._handler.on_playbin_state_changed( self.audio._handler.on_playbin_state_changed(
gst.STATE_PAUSED, gst.STATE_READY, gst.STATE_NULL) Gst.STATE_PAUSED, Gst.STATE_READY, Gst.STATE_NULL)
# We never get the following call, so the logic must work without it # We never get the following call, so the logic must work without it
# self.audio._handler.on_playbin_state_changed( # self.audio._handler.on_playbin_state_changed(
# gst.STATE_READY, gst.STATE_NULL, gst.STATE_VOID_PENDING) # Gst.STATE_READY, Gst.STATE_NULL, Gst.STATE_VOID_PENDING)
self.assertEqual(audio.PlaybackState.STOPPED, self.audio.state) self.assertEqual(audio.PlaybackState.STOPPED, self.audio.state)
@ -565,17 +563,17 @@ class AudioBufferingTest(unittest.TestCase):
def test_pause_when_buffer_empty(self): def test_pause_when_buffer_empty(self):
playbin = self.audio._playbin playbin = self.audio._playbin
self.audio.start_playback() self.audio.start_playback()
playbin.set_state.assert_called_with(gst.STATE_PLAYING) playbin.set_state.assert_called_with(Gst.STATE_PLAYING)
playbin.set_state.reset_mock() playbin.set_state.reset_mock()
self.audio._handler.on_buffering(0) self.audio._handler.on_buffering(0)
playbin.set_state.assert_called_with(gst.STATE_PAUSED) playbin.set_state.assert_called_with(Gst.STATE_PAUSED)
self.assertTrue(self.audio._buffering) self.assertTrue(self.audio._buffering)
def test_stay_paused_when_buffering_finished(self): def test_stay_paused_when_buffering_finished(self):
playbin = self.audio._playbin playbin = self.audio._playbin
self.audio.pause_playback() self.audio.pause_playback()
playbin.set_state.assert_called_with(gst.STATE_PAUSED) playbin.set_state.assert_called_with(Gst.STATE_PAUSED)
playbin.set_state.reset_mock() playbin.set_state.reset_mock()
self.audio._handler.on_buffering(100) self.audio._handler.on_buffering(100)
@ -585,11 +583,11 @@ class AudioBufferingTest(unittest.TestCase):
def test_change_to_paused_while_buffering(self): def test_change_to_paused_while_buffering(self):
playbin = self.audio._playbin playbin = self.audio._playbin
self.audio.start_playback() self.audio.start_playback()
playbin.set_state.assert_called_with(gst.STATE_PLAYING) playbin.set_state.assert_called_with(Gst.STATE_PLAYING)
playbin.set_state.reset_mock() playbin.set_state.reset_mock()
self.audio._handler.on_buffering(0) self.audio._handler.on_buffering(0)
playbin.set_state.assert_called_with(gst.STATE_PAUSED) playbin.set_state.assert_called_with(Gst.STATE_PAUSED)
self.audio.pause_playback() self.audio.pause_playback()
playbin.set_state.reset_mock() playbin.set_state.reset_mock()
@ -600,13 +598,13 @@ class AudioBufferingTest(unittest.TestCase):
def test_change_to_stopped_while_buffering(self): def test_change_to_stopped_while_buffering(self):
playbin = self.audio._playbin playbin = self.audio._playbin
self.audio.start_playback() self.audio.start_playback()
playbin.set_state.assert_called_with(gst.STATE_PLAYING) playbin.set_state.assert_called_with(Gst.STATE_PLAYING)
playbin.set_state.reset_mock() playbin.set_state.reset_mock()
self.audio._handler.on_buffering(0) self.audio._handler.on_buffering(0)
playbin.set_state.assert_called_with(gst.STATE_PAUSED) playbin.set_state.assert_called_with(Gst.STATE_PAUSED)
playbin.set_state.reset_mock() playbin.set_state.reset_mock()
self.audio.stop_playback() self.audio.stop_playback()
playbin.set_state.assert_called_with(gst.STATE_NULL) playbin.set_state.assert_called_with(Gst.STATE_NULL)
self.assertFalse(self.audio._buffering) self.assertFalse(self.audio._buffering)

View File

@ -3,8 +3,12 @@ from __future__ import absolute_import, unicode_literals
import os import os
import unittest import unittest
import gobject import gi
gobject.threads_init() gi.require_version('Gst', '1.0')
from gi.repository import GObject, Gst
GObject.threads_init()
Gst.init(None)
from mopidy import exceptions from mopidy import exceptions
from mopidy.audio import scan from mopidy.audio import scan

View File

@ -5,7 +5,7 @@ import logging
import socket import socket
import unittest import unittest
import gobject from gi.repository import GObject
from mock import Mock, call, patch, sentinel from mock import Mock, call, patch, sentinel
@ -162,27 +162,27 @@ class ConnectionTest(unittest.TestCase):
network.Connection.stop(self.mock, sentinel.reason) network.Connection.stop(self.mock, sentinel.reason)
network.logger.log(any_int, any_unicode) network.logger.log(any_int, any_unicode)
@patch.object(gobject, 'io_add_watch', new=Mock()) @patch.object(GObject, 'io_add_watch', new=Mock())
def test_enable_recv_registers_with_gobject(self): def test_enable_recv_registers_with_gobject(self):
self.mock.recv_id = None self.mock.recv_id = None
self.mock.sock = Mock(spec=socket.SocketType) self.mock.sock = Mock(spec=socket.SocketType)
self.mock.sock.fileno.return_value = sentinel.fileno self.mock.sock.fileno.return_value = sentinel.fileno
gobject.io_add_watch.return_value = sentinel.tag GObject.io_add_watch.return_value = sentinel.tag
network.Connection.enable_recv(self.mock) network.Connection.enable_recv(self.mock)
gobject.io_add_watch.assert_called_once_with( GObject.io_add_watch.assert_called_once_with(
sentinel.fileno, sentinel.fileno,
gobject.IO_IN | gobject.IO_ERR | gobject.IO_HUP, GObject.IO_IN | GObject.IO_ERR | GObject.IO_HUP,
self.mock.recv_callback) self.mock.recv_callback)
self.assertEqual(sentinel.tag, self.mock.recv_id) self.assertEqual(sentinel.tag, self.mock.recv_id)
@patch.object(gobject, 'io_add_watch', new=Mock()) @patch.object(GObject, 'io_add_watch', new=Mock())
def test_enable_recv_already_registered(self): def test_enable_recv_already_registered(self):
self.mock.sock = Mock(spec=socket.SocketType) self.mock.sock = Mock(spec=socket.SocketType)
self.mock.recv_id = sentinel.tag self.mock.recv_id = sentinel.tag
network.Connection.enable_recv(self.mock) network.Connection.enable_recv(self.mock)
self.assertEqual(0, gobject.io_add_watch.call_count) self.assertEqual(0, GObject.io_add_watch.call_count)
def test_enable_recv_does_not_change_tag(self): def test_enable_recv_does_not_change_tag(self):
self.mock.recv_id = sentinel.tag self.mock.recv_id = sentinel.tag
@ -191,20 +191,20 @@ class ConnectionTest(unittest.TestCase):
network.Connection.enable_recv(self.mock) network.Connection.enable_recv(self.mock)
self.assertEqual(sentinel.tag, self.mock.recv_id) self.assertEqual(sentinel.tag, self.mock.recv_id)
@patch.object(gobject, 'source_remove', new=Mock()) @patch.object(GObject, 'source_remove', new=Mock())
def test_disable_recv_deregisters(self): def test_disable_recv_deregisters(self):
self.mock.recv_id = sentinel.tag self.mock.recv_id = sentinel.tag
network.Connection.disable_recv(self.mock) network.Connection.disable_recv(self.mock)
gobject.source_remove.assert_called_once_with(sentinel.tag) GObject.source_remove.assert_called_once_with(sentinel.tag)
self.assertEqual(None, self.mock.recv_id) self.assertEqual(None, self.mock.recv_id)
@patch.object(gobject, 'source_remove', new=Mock()) @patch.object(GObject, 'source_remove', new=Mock())
def test_disable_recv_already_deregistered(self): def test_disable_recv_already_deregistered(self):
self.mock.recv_id = None self.mock.recv_id = None
network.Connection.disable_recv(self.mock) network.Connection.disable_recv(self.mock)
self.assertEqual(0, gobject.source_remove.call_count) self.assertEqual(0, GObject.source_remove.call_count)
self.assertEqual(None, self.mock.recv_id) self.assertEqual(None, self.mock.recv_id)
def test_enable_recv_on_closed_socket(self): def test_enable_recv_on_closed_socket(self):
@ -216,27 +216,27 @@ class ConnectionTest(unittest.TestCase):
self.mock.stop.assert_called_once_with(any_unicode) self.mock.stop.assert_called_once_with(any_unicode)
self.assertEqual(None, self.mock.recv_id) self.assertEqual(None, self.mock.recv_id)
@patch.object(gobject, 'io_add_watch', new=Mock()) @patch.object(GObject, 'io_add_watch', new=Mock())
def test_enable_send_registers_with_gobject(self): def test_enable_send_registers_with_gobject(self):
self.mock.send_id = None self.mock.send_id = None
self.mock.sock = Mock(spec=socket.SocketType) self.mock.sock = Mock(spec=socket.SocketType)
self.mock.sock.fileno.return_value = sentinel.fileno self.mock.sock.fileno.return_value = sentinel.fileno
gobject.io_add_watch.return_value = sentinel.tag GObject.io_add_watch.return_value = sentinel.tag
network.Connection.enable_send(self.mock) network.Connection.enable_send(self.mock)
gobject.io_add_watch.assert_called_once_with( GObject.io_add_watch.assert_called_once_with(
sentinel.fileno, sentinel.fileno,
gobject.IO_OUT | gobject.IO_ERR | gobject.IO_HUP, GObject.IO_OUT | GObject.IO_ERR | GObject.IO_HUP,
self.mock.send_callback) self.mock.send_callback)
self.assertEqual(sentinel.tag, self.mock.send_id) self.assertEqual(sentinel.tag, self.mock.send_id)
@patch.object(gobject, 'io_add_watch', new=Mock()) @patch.object(GObject, 'io_add_watch', new=Mock())
def test_enable_send_already_registered(self): def test_enable_send_already_registered(self):
self.mock.sock = Mock(spec=socket.SocketType) self.mock.sock = Mock(spec=socket.SocketType)
self.mock.send_id = sentinel.tag self.mock.send_id = sentinel.tag
network.Connection.enable_send(self.mock) network.Connection.enable_send(self.mock)
self.assertEqual(0, gobject.io_add_watch.call_count) self.assertEqual(0, GObject.io_add_watch.call_count)
def test_enable_send_does_not_change_tag(self): def test_enable_send_does_not_change_tag(self):
self.mock.send_id = sentinel.tag self.mock.send_id = sentinel.tag
@ -245,20 +245,20 @@ class ConnectionTest(unittest.TestCase):
network.Connection.enable_send(self.mock) network.Connection.enable_send(self.mock)
self.assertEqual(sentinel.tag, self.mock.send_id) self.assertEqual(sentinel.tag, self.mock.send_id)
@patch.object(gobject, 'source_remove', new=Mock()) @patch.object(GObject, 'source_remove', new=Mock())
def test_disable_send_deregisters(self): def test_disable_send_deregisters(self):
self.mock.send_id = sentinel.tag self.mock.send_id = sentinel.tag
network.Connection.disable_send(self.mock) network.Connection.disable_send(self.mock)
gobject.source_remove.assert_called_once_with(sentinel.tag) GObject.source_remove.assert_called_once_with(sentinel.tag)
self.assertEqual(None, self.mock.send_id) self.assertEqual(None, self.mock.send_id)
@patch.object(gobject, 'source_remove', new=Mock()) @patch.object(GObject, 'source_remove', new=Mock())
def test_disable_send_already_deregistered(self): def test_disable_send_already_deregistered(self):
self.mock.send_id = None self.mock.send_id = None
network.Connection.disable_send(self.mock) network.Connection.disable_send(self.mock)
self.assertEqual(0, gobject.source_remove.call_count) self.assertEqual(0, GObject.source_remove.call_count)
self.assertEqual(None, self.mock.send_id) self.assertEqual(None, self.mock.send_id)
def test_enable_send_on_closed_socket(self): def test_enable_send_on_closed_socket(self):
@ -269,36 +269,36 @@ class ConnectionTest(unittest.TestCase):
network.Connection.enable_send(self.mock) network.Connection.enable_send(self.mock)
self.assertEqual(None, self.mock.send_id) self.assertEqual(None, self.mock.send_id)
@patch.object(gobject, 'timeout_add_seconds', new=Mock()) @patch.object(GObject, 'timeout_add_seconds', new=Mock())
def test_enable_timeout_clears_existing_timeouts(self): def test_enable_timeout_clears_existing_timeouts(self):
self.mock.timeout = 10 self.mock.timeout = 10
network.Connection.enable_timeout(self.mock) network.Connection.enable_timeout(self.mock)
self.mock.disable_timeout.assert_called_once_with() self.mock.disable_timeout.assert_called_once_with()
@patch.object(gobject, 'timeout_add_seconds', new=Mock()) @patch.object(GObject, 'timeout_add_seconds', new=Mock())
def test_enable_timeout_add_gobject_timeout(self): def test_enable_timeout_add_gobject_timeout(self):
self.mock.timeout = 10 self.mock.timeout = 10
gobject.timeout_add_seconds.return_value = sentinel.tag GObject.timeout_add_seconds.return_value = sentinel.tag
network.Connection.enable_timeout(self.mock) network.Connection.enable_timeout(self.mock)
gobject.timeout_add_seconds.assert_called_once_with( GObject.timeout_add_seconds.assert_called_once_with(
10, self.mock.timeout_callback) 10, self.mock.timeout_callback)
self.assertEqual(sentinel.tag, self.mock.timeout_id) self.assertEqual(sentinel.tag, self.mock.timeout_id)
@patch.object(gobject, 'timeout_add_seconds', new=Mock()) @patch.object(GObject, 'timeout_add_seconds', new=Mock())
def test_enable_timeout_does_not_add_timeout(self): def test_enable_timeout_does_not_add_timeout(self):
self.mock.timeout = 0 self.mock.timeout = 0
network.Connection.enable_timeout(self.mock) network.Connection.enable_timeout(self.mock)
self.assertEqual(0, gobject.timeout_add_seconds.call_count) self.assertEqual(0, GObject.timeout_add_seconds.call_count)
self.mock.timeout = -1 self.mock.timeout = -1
network.Connection.enable_timeout(self.mock) network.Connection.enable_timeout(self.mock)
self.assertEqual(0, gobject.timeout_add_seconds.call_count) self.assertEqual(0, GObject.timeout_add_seconds.call_count)
self.mock.timeout = None self.mock.timeout = None
network.Connection.enable_timeout(self.mock) network.Connection.enable_timeout(self.mock)
self.assertEqual(0, gobject.timeout_add_seconds.call_count) self.assertEqual(0, GObject.timeout_add_seconds.call_count)
def test_enable_timeout_does_not_call_disable_for_invalid_timeout(self): def test_enable_timeout_does_not_call_disable_for_invalid_timeout(self):
self.mock.timeout = 0 self.mock.timeout = 0
@ -313,20 +313,20 @@ class ConnectionTest(unittest.TestCase):
network.Connection.enable_timeout(self.mock) network.Connection.enable_timeout(self.mock)
self.assertEqual(0, self.mock.disable_timeout.call_count) self.assertEqual(0, self.mock.disable_timeout.call_count)
@patch.object(gobject, 'source_remove', new=Mock()) @patch.object(GObject, 'source_remove', new=Mock())
def test_disable_timeout_deregisters(self): def test_disable_timeout_deregisters(self):
self.mock.timeout_id = sentinel.tag self.mock.timeout_id = sentinel.tag
network.Connection.disable_timeout(self.mock) network.Connection.disable_timeout(self.mock)
gobject.source_remove.assert_called_once_with(sentinel.tag) GObject.source_remove.assert_called_once_with(sentinel.tag)
self.assertEqual(None, self.mock.timeout_id) self.assertEqual(None, self.mock.timeout_id)
@patch.object(gobject, 'source_remove', new=Mock()) @patch.object(GObject, 'source_remove', new=Mock())
def test_disable_timeout_already_deregistered(self): def test_disable_timeout_already_deregistered(self):
self.mock.timeout_id = None self.mock.timeout_id = None
network.Connection.disable_timeout(self.mock) network.Connection.disable_timeout(self.mock)
self.assertEqual(0, gobject.source_remove.call_count) self.assertEqual(0, GObject.source_remove.call_count)
self.assertEqual(None, self.mock.timeout_id) self.assertEqual(None, self.mock.timeout_id)
def test_queue_send_acquires_and_releases_lock(self): def test_queue_send_acquires_and_releases_lock(self):
@ -372,7 +372,7 @@ class ConnectionTest(unittest.TestCase):
self.mock.actor_ref = Mock() self.mock.actor_ref = Mock()
self.assertTrue(network.Connection.recv_callback( self.assertTrue(network.Connection.recv_callback(
self.mock, sentinel.fd, gobject.IO_IN | gobject.IO_ERR)) self.mock, sentinel.fd, GObject.IO_IN | GObject.IO_ERR))
self.mock.stop.assert_called_once_with(any_unicode) self.mock.stop.assert_called_once_with(any_unicode)
def test_recv_callback_respects_io_hup(self): def test_recv_callback_respects_io_hup(self):
@ -380,7 +380,7 @@ class ConnectionTest(unittest.TestCase):
self.mock.actor_ref = Mock() self.mock.actor_ref = Mock()
self.assertTrue(network.Connection.recv_callback( self.assertTrue(network.Connection.recv_callback(
self.mock, sentinel.fd, gobject.IO_IN | gobject.IO_HUP)) self.mock, sentinel.fd, GObject.IO_IN | GObject.IO_HUP))
self.mock.stop.assert_called_once_with(any_unicode) self.mock.stop.assert_called_once_with(any_unicode)
def test_recv_callback_respects_io_hup_and_io_err(self): def test_recv_callback_respects_io_hup_and_io_err(self):
@ -389,7 +389,7 @@ class ConnectionTest(unittest.TestCase):
self.assertTrue(network.Connection.recv_callback( self.assertTrue(network.Connection.recv_callback(
self.mock, sentinel.fd, self.mock, sentinel.fd,
gobject.IO_IN | gobject.IO_HUP | gobject.IO_ERR)) GObject.IO_IN | GObject.IO_HUP | GObject.IO_ERR))
self.mock.stop.assert_called_once_with(any_unicode) self.mock.stop.assert_called_once_with(any_unicode)
def test_recv_callback_sends_data_to_actor(self): def test_recv_callback_sends_data_to_actor(self):
@ -398,7 +398,7 @@ class ConnectionTest(unittest.TestCase):
self.mock.actor_ref = Mock() self.mock.actor_ref = Mock()
self.assertTrue(network.Connection.recv_callback( self.assertTrue(network.Connection.recv_callback(
self.mock, sentinel.fd, gobject.IO_IN)) self.mock, sentinel.fd, GObject.IO_IN))
self.mock.actor_ref.tell.assert_called_once_with( self.mock.actor_ref.tell.assert_called_once_with(
{'received': 'data'}) {'received': 'data'})
@ -409,7 +409,7 @@ class ConnectionTest(unittest.TestCase):
self.mock.actor_ref.tell.side_effect = pykka.ActorDeadError() self.mock.actor_ref.tell.side_effect = pykka.ActorDeadError()
self.assertTrue(network.Connection.recv_callback( self.assertTrue(network.Connection.recv_callback(
self.mock, sentinel.fd, gobject.IO_IN)) self.mock, sentinel.fd, GObject.IO_IN))
self.mock.stop.assert_called_once_with(any_unicode) self.mock.stop.assert_called_once_with(any_unicode)
def test_recv_callback_gets_no_data(self): def test_recv_callback_gets_no_data(self):
@ -418,7 +418,7 @@ class ConnectionTest(unittest.TestCase):
self.mock.actor_ref = Mock() self.mock.actor_ref = Mock()
self.assertTrue(network.Connection.recv_callback( self.assertTrue(network.Connection.recv_callback(
self.mock, sentinel.fd, gobject.IO_IN)) self.mock, sentinel.fd, GObject.IO_IN))
self.assertEqual(self.mock.mock_calls, [ self.assertEqual(self.mock.mock_calls, [
call.sock.recv(any_int), call.sock.recv(any_int),
call.disable_recv(), call.disable_recv(),
@ -431,7 +431,7 @@ class ConnectionTest(unittest.TestCase):
for error in (errno.EWOULDBLOCK, errno.EINTR): for error in (errno.EWOULDBLOCK, errno.EINTR):
self.mock.sock.recv.side_effect = socket.error(error, '') self.mock.sock.recv.side_effect = socket.error(error, '')
self.assertTrue(network.Connection.recv_callback( self.assertTrue(network.Connection.recv_callback(
self.mock, sentinel.fd, gobject.IO_IN)) self.mock, sentinel.fd, GObject.IO_IN))
self.assertEqual(0, self.mock.stop.call_count) self.assertEqual(0, self.mock.stop.call_count)
def test_recv_callback_unrecoverable_error(self): def test_recv_callback_unrecoverable_error(self):
@ -439,7 +439,7 @@ class ConnectionTest(unittest.TestCase):
self.mock.sock.recv.side_effect = socket.error self.mock.sock.recv.side_effect = socket.error
self.assertTrue(network.Connection.recv_callback( self.assertTrue(network.Connection.recv_callback(
self.mock, sentinel.fd, gobject.IO_IN)) self.mock, sentinel.fd, GObject.IO_IN))
self.mock.stop.assert_called_once_with(any_unicode) self.mock.stop.assert_called_once_with(any_unicode)
def test_send_callback_respects_io_err(self): def test_send_callback_respects_io_err(self):
@ -450,7 +450,7 @@ class ConnectionTest(unittest.TestCase):
self.mock.send_buffer = '' self.mock.send_buffer = ''
self.assertTrue(network.Connection.send_callback( self.assertTrue(network.Connection.send_callback(
self.mock, sentinel.fd, gobject.IO_IN | gobject.IO_ERR)) self.mock, sentinel.fd, GObject.IO_IN | GObject.IO_ERR))
self.mock.stop.assert_called_once_with(any_unicode) self.mock.stop.assert_called_once_with(any_unicode)
def test_send_callback_respects_io_hup(self): def test_send_callback_respects_io_hup(self):
@ -461,7 +461,7 @@ class ConnectionTest(unittest.TestCase):
self.mock.send_buffer = '' self.mock.send_buffer = ''
self.assertTrue(network.Connection.send_callback( self.assertTrue(network.Connection.send_callback(
self.mock, sentinel.fd, gobject.IO_IN | gobject.IO_HUP)) self.mock, sentinel.fd, GObject.IO_IN | GObject.IO_HUP))
self.mock.stop.assert_called_once_with(any_unicode) self.mock.stop.assert_called_once_with(any_unicode)
def test_send_callback_respects_io_hup_and_io_err(self): def test_send_callback_respects_io_hup_and_io_err(self):
@ -473,7 +473,7 @@ class ConnectionTest(unittest.TestCase):
self.assertTrue(network.Connection.send_callback( self.assertTrue(network.Connection.send_callback(
self.mock, sentinel.fd, self.mock, sentinel.fd,
gobject.IO_IN | gobject.IO_HUP | gobject.IO_ERR)) GObject.IO_IN | GObject.IO_HUP | GObject.IO_ERR))
self.mock.stop.assert_called_once_with(any_unicode) self.mock.stop.assert_called_once_with(any_unicode)
def test_send_callback_acquires_and_releases_lock(self): def test_send_callback_acquires_and_releases_lock(self):
@ -484,7 +484,7 @@ class ConnectionTest(unittest.TestCase):
self.mock.sock.send.return_value = 0 self.mock.sock.send.return_value = 0
self.assertTrue(network.Connection.send_callback( self.assertTrue(network.Connection.send_callback(
self.mock, sentinel.fd, gobject.IO_IN)) self.mock, sentinel.fd, GObject.IO_IN))
self.mock.send_lock.acquire.assert_called_once_with(False) self.mock.send_lock.acquire.assert_called_once_with(False)
self.mock.send_lock.release.assert_called_once_with() self.mock.send_lock.release.assert_called_once_with()
@ -496,7 +496,7 @@ class ConnectionTest(unittest.TestCase):
self.mock.sock.send.return_value = 0 self.mock.sock.send.return_value = 0
self.assertTrue(network.Connection.send_callback( self.assertTrue(network.Connection.send_callback(
self.mock, sentinel.fd, gobject.IO_IN)) self.mock, sentinel.fd, GObject.IO_IN))
self.mock.send_lock.acquire.assert_called_once_with(False) self.mock.send_lock.acquire.assert_called_once_with(False)
self.assertEqual(0, self.mock.sock.send.call_count) self.assertEqual(0, self.mock.sock.send.call_count)
@ -507,7 +507,7 @@ class ConnectionTest(unittest.TestCase):
self.mock.send.return_value = '' self.mock.send.return_value = ''
self.assertTrue(network.Connection.send_callback( self.assertTrue(network.Connection.send_callback(
self.mock, sentinel.fd, gobject.IO_IN)) self.mock, sentinel.fd, GObject.IO_IN))
self.mock.disable_send.assert_called_once_with() self.mock.disable_send.assert_called_once_with()
self.mock.send.assert_called_once_with('data') self.mock.send.assert_called_once_with('data')
self.assertEqual('', self.mock.send_buffer) self.assertEqual('', self.mock.send_buffer)
@ -519,7 +519,7 @@ class ConnectionTest(unittest.TestCase):
self.mock.send.return_value = 'ta' self.mock.send.return_value = 'ta'
self.assertTrue(network.Connection.send_callback( self.assertTrue(network.Connection.send_callback(
self.mock, sentinel.fd, gobject.IO_IN)) self.mock, sentinel.fd, GObject.IO_IN))
self.mock.send.assert_called_once_with('data') self.mock.send.assert_called_once_with('data')
self.assertEqual('ta', self.mock.send_buffer) self.assertEqual('ta', self.mock.send_buffer)

View File

@ -4,7 +4,7 @@ import errno
import socket import socket
import unittest import unittest
import gobject from gi.repository import GObject
from mock import Mock, patch, sentinel from mock import Mock, patch, sentinel
@ -91,11 +91,11 @@ class ServerTest(unittest.TestCase):
network.Server.create_server_socket( network.Server.create_server_socket(
self.mock, sentinel.host, sentinel.port) self.mock, sentinel.host, sentinel.port)
@patch.object(gobject, 'io_add_watch', new=Mock()) @patch.object(GObject, 'io_add_watch', new=Mock())
def test_register_server_socket_sets_up_io_watch(self): def test_register_server_socket_sets_up_io_watch(self):
network.Server.register_server_socket(self.mock, sentinel.fileno) network.Server.register_server_socket(self.mock, sentinel.fileno)
gobject.io_add_watch.assert_called_once_with( GObject.io_add_watch.assert_called_once_with(
sentinel.fileno, gobject.IO_IN, self.mock.handle_connection) sentinel.fileno, GObject.IO_IN, self.mock.handle_connection)
def test_handle_connection(self): def test_handle_connection(self):
self.mock.accept_connection.return_value = ( self.mock.accept_connection.return_value = (
@ -103,7 +103,7 @@ class ServerTest(unittest.TestCase):
self.mock.maximum_connections_exceeded.return_value = False self.mock.maximum_connections_exceeded.return_value = False
self.assertTrue(network.Server.handle_connection( self.assertTrue(network.Server.handle_connection(
self.mock, sentinel.fileno, gobject.IO_IN)) self.mock, sentinel.fileno, GObject.IO_IN))
self.mock.accept_connection.assert_called_once_with() self.mock.accept_connection.assert_called_once_with()
self.mock.maximum_connections_exceeded.assert_called_once_with() self.mock.maximum_connections_exceeded.assert_called_once_with()
self.mock.init_connection.assert_called_once_with( self.mock.init_connection.assert_called_once_with(
@ -116,7 +116,7 @@ class ServerTest(unittest.TestCase):
self.mock.maximum_connections_exceeded.return_value = True self.mock.maximum_connections_exceeded.return_value = True
self.assertTrue(network.Server.handle_connection( self.assertTrue(network.Server.handle_connection(
self.mock, sentinel.fileno, gobject.IO_IN)) self.mock, sentinel.fileno, GObject.IO_IN))
self.mock.accept_connection.assert_called_once_with() self.mock.accept_connection.assert_called_once_with()
self.mock.maximum_connections_exceeded.assert_called_once_with() self.mock.maximum_connections_exceeded.assert_called_once_with()
self.mock.reject_connection.assert_called_once_with( self.mock.reject_connection.assert_called_once_with(

View File

@ -4,14 +4,14 @@ import platform
import sys import sys
import unittest import unittest
import gi
gi.require_version('Gst', '1.0')
from gi.repository import Gst
import mock import mock
import pkg_resources import pkg_resources
import pygst
pygst.require('0.10')
import gst # noqa
from mopidy.internal import deps from mopidy.internal import deps
@ -74,12 +74,11 @@ class DepsTest(unittest.TestCase):
self.assertEqual('GStreamer', result['name']) self.assertEqual('GStreamer', result['name'])
self.assertEqual( self.assertEqual(
'.'.join(map(str, gst.get_gst_version())), result['version']) '.'.join(map(str, Gst.version())), result['version'])
self.assertIn('gst', result['path']) self.assertIn('gi', result['path'])
self.assertNotIn('__init__.py', result['path']) self.assertNotIn('__init__.py', result['path'])
self.assertIn('Python wrapper: gst-python', result['other']) self.assertIn('Python wrapper: python-gi', result['other'])
self.assertIn( self.assertIn(gi.__version__, result['other'])
'.'.join(map(str, gst.get_pygst_version())), result['other'])
self.assertIn('Relevant elements:', result['other']) self.assertIn('Relevant elements:', result['other'])
@mock.patch('pkg_resources.get_distribution') @mock.patch('pkg_resources.get_distribution')

View File

@ -7,7 +7,7 @@ import shutil
import tempfile import tempfile
import unittest import unittest
import glib from gi.repository import GLib
from mopidy import compat, exceptions from mopidy import compat, exceptions
from mopidy.internal import path from mopidy.internal import path
@ -215,7 +215,7 @@ class ExpandPathTest(unittest.TestCase):
def test_xdg_subsititution(self): def test_xdg_subsititution(self):
self.assertEqual( self.assertEqual(
glib.get_user_data_dir() + b'/foo', GLib.get_user_data_dir() + b'/foo',
path.expand_path(b'$XDG_DATA_DIR/foo')) path.expand_path(b'$XDG_DATA_DIR/foo'))
def test_xdg_subsititution_unknown(self): def test_xdg_subsititution_unknown(self):