gst1: Update imports to use PyGI
This commit is contained in:
parent
d046974aaf
commit
8c82f4773f
@ -7,12 +7,12 @@ import sys
|
||||
import textwrap
|
||||
|
||||
try:
|
||||
import gobject # noqa
|
||||
from gi.repository import GObject, Gst
|
||||
except ImportError:
|
||||
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
|
||||
the regular Python tools like pip.
|
||||
|
||||
@ -21,7 +21,7 @@ except ImportError:
|
||||
"""))
|
||||
raise
|
||||
|
||||
gobject.threads_init()
|
||||
GObject.threads_init()
|
||||
|
||||
try:
|
||||
# Make GObject's mainloop the event loop for python-dbus
|
||||
|
||||
@ -4,12 +4,9 @@ import logging
|
||||
import os
|
||||
import threading
|
||||
|
||||
import gobject
|
||||
|
||||
import pygst
|
||||
pygst.require('0.10')
|
||||
import gst # noqa
|
||||
import gst.pbutils # noqa
|
||||
import gi
|
||||
gi.require_version('Gst', '1.0')
|
||||
from gi.repository import GObject, Gst
|
||||
|
||||
import pykka
|
||||
|
||||
@ -28,9 +25,9 @@ logger = logging.getLogger(__name__)
|
||||
gst_logger = logging.getLogger('mopidy.audio.gst')
|
||||
|
||||
_GST_STATE_MAPPING = {
|
||||
gst.STATE_PLAYING: PlaybackState.PLAYING,
|
||||
gst.STATE_PAUSED: PlaybackState.PAUSED,
|
||||
gst.STATE_NULL: PlaybackState.STOPPED}
|
||||
Gst.STATE_PLAYING: PlaybackState.PLAYING,
|
||||
Gst.STATE_PAUSED: PlaybackState.PAUSED,
|
||||
Gst.STATE_NULL: PlaybackState.STOPPED}
|
||||
|
||||
|
||||
class _Signals(object):
|
||||
@ -118,9 +115,9 @@ class _Appsrc(object):
|
||||
|
||||
if buffer_ is None:
|
||||
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:
|
||||
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):
|
||||
# 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.
|
||||
class _Outputs(gst.Bin):
|
||||
class _Outputs(Gst.Bin):
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
# Add an always connected fakesink which respects the clock so the tee
|
||||
# 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)
|
||||
self._add(fakesink)
|
||||
|
||||
def add_output(self, description):
|
||||
# XXX This only works for pipelines not in use until #790 gets done.
|
||||
try:
|
||||
output = gst.parse_bin_from_description(
|
||||
output = Gst.parse_bin_from_description(
|
||||
description, ghost_unconnected_pads=True)
|
||||
except gobject.GError as ex:
|
||||
except GObject.GError as ex:
|
||||
logger.error(
|
||||
'Failed to create audio output "%s": %s', description, ex)
|
||||
raise exceptions.AudioException(bytes(ex))
|
||||
@ -164,7 +161,7 @@ class _Outputs(gst.Bin):
|
||||
logger.info('Audio output set to "%s"', description)
|
||||
|
||||
def _add(self, element):
|
||||
queue = gst.element_factory_make('queue')
|
||||
queue = Gst.element_factory_make('queue')
|
||||
self.add(element)
|
||||
self.add(queue)
|
||||
queue.link(element)
|
||||
@ -234,28 +231,28 @@ class _Handler(object):
|
||||
self._event_handler_id = None
|
||||
|
||||
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())
|
||||
elif msg.type == gst.MESSAGE_BUFFERING:
|
||||
elif msg.type == Gst.MESSAGE_BUFFERING:
|
||||
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()
|
||||
elif msg.type == gst.MESSAGE_ERROR:
|
||||
elif msg.type == Gst.MESSAGE_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())
|
||||
elif msg.type == gst.MESSAGE_ASYNC_DONE:
|
||||
elif msg.type == Gst.MESSAGE_ASYNC_DONE:
|
||||
self.on_async_done()
|
||||
elif msg.type == gst.MESSAGE_TAG:
|
||||
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):
|
||||
elif msg.type == Gst.MESSAGE_ELEMENT:
|
||||
if Gst.pbutils.is_missing_plugin_message(msg):
|
||||
self.on_missing_plugin(msg)
|
||||
|
||||
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())
|
||||
elif event.type == gst.EVENT_SINK_MESSAGE:
|
||||
elif event.type == Gst.EVENT_SINK_MESSAGE:
|
||||
# Handle stream changed messages when they reach our output bin.
|
||||
# If we listen for it on the bus we get one per tee branch.
|
||||
msg = event.parse_sink_message()
|
||||
@ -268,17 +265,17 @@ class _Handler(object):
|
||||
old_state.value_name, new_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
|
||||
# NULL, so we rewrite the second to last call to get the expected
|
||||
# behavior.
|
||||
new_state = gst.STATE_NULL
|
||||
pending_state = gst.STATE_VOID_PENDING
|
||||
new_state = Gst.STATE_NULL
|
||||
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
|
||||
|
||||
if new_state == gst.STATE_READY:
|
||||
if new_state == Gst.STATE_READY:
|
||||
return # Ignore READY state as it's GStreamer specific
|
||||
|
||||
new_state = _GST_STATE_MAPPING[new_state]
|
||||
@ -297,23 +294,23 @@ class _Handler(object):
|
||||
AudioListener.send('stream_changed', uri=None)
|
||||
|
||||
if 'GST_DEBUG_DUMP_DOT_DIR' in os.environ:
|
||||
gst.DEBUG_BIN_TO_DOT_FILE(
|
||||
self._audio._playbin, gst.DEBUG_GRAPH_SHOW_ALL, 'mopidy')
|
||||
Gst.DEBUG_BIN_TO_DOT_FILE(
|
||||
self._audio._playbin, Gst.DEBUG_GRAPH_SHOW_ALL, 'mopidy')
|
||||
|
||||
def on_buffering(self, percent, structure=None):
|
||||
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.
|
||||
|
||||
level = logging.getLevelName('TRACE')
|
||||
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
|
||||
level = logging.DEBUG
|
||||
if percent == 100:
|
||||
self._audio._buffering = False
|
||||
if self._audio._target_state == gst.STATE_PLAYING:
|
||||
self._audio._playbin.set_state(gst.STATE_PLAYING)
|
||||
if self._audio._target_state == Gst.STATE_PLAYING:
|
||||
self._audio._playbin.set_state(Gst.STATE_PLAYING)
|
||||
level = logging.DEBUG
|
||||
|
||||
gst_logger.log(level, 'Got buffering message: percent=%d%%', percent)
|
||||
@ -346,12 +343,12 @@ class _Handler(object):
|
||||
AudioListener.send('tags_changed', tags=tags.keys())
|
||||
|
||||
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)
|
||||
desc = Gst.pbutils.missing_plugin_message_get_description(msg)
|
||||
debug = Gst.pbutils.missing_plugin_message_get_installer_detail(msg)
|
||||
|
||||
gst_logger.debug('Got missing-plugin message: description:%s', 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: '
|
||||
'gst-installer "%s"', debug)
|
||||
# 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 '
|
||||
'start=%s stop=%s position=%s', update, rate,
|
||||
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)
|
||||
AudioListener.send('position_changed', position=position_ms)
|
||||
|
||||
@ -389,7 +386,7 @@ class Audio(pykka.ThreadingActor):
|
||||
super(Audio, self).__init__()
|
||||
|
||||
self._config = config
|
||||
self._target_state = gst.STATE_NULL
|
||||
self._target_state = Gst.STATE_NULL
|
||||
self._buffering = False
|
||||
self._tags = {}
|
||||
|
||||
@ -411,7 +408,7 @@ class Audio(pykka.ThreadingActor):
|
||||
self._setup_playbin()
|
||||
self._setup_outputs()
|
||||
self._setup_audio_sink()
|
||||
except gobject.GError as ex:
|
||||
except GObject.GError as ex:
|
||||
logger.exception(ex)
|
||||
process.exit_process()
|
||||
|
||||
@ -422,19 +419,19 @@ class Audio(pykka.ThreadingActor):
|
||||
def _setup_preferences(self):
|
||||
# TODO: move out of audio actor?
|
||||
# Fix for https://github.com/mopidy/mopidy/issues/604
|
||||
registry = gst.registry_get_default()
|
||||
registry = Gst.registry_get_default()
|
||||
jacksink = registry.find_feature(
|
||||
'jackaudiosink', gst.TYPE_ELEMENT_FACTORY)
|
||||
'jackaudiosink', Gst.TYPE_ELEMENT_FACTORY)
|
||||
if jacksink:
|
||||
jacksink.set_rank(gst.RANK_SECONDARY)
|
||||
jacksink.set_rank(Gst.RANK_SECONDARY)
|
||||
|
||||
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
|
||||
|
||||
# TODO: turn into config values...
|
||||
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, 'about-to-finish',
|
||||
@ -448,13 +445,13 @@ class Audio(pykka.ThreadingActor):
|
||||
self._handler.teardown_event_handling()
|
||||
self._signals.disconnect(self._playbin, 'about-to-finish')
|
||||
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):
|
||||
# We don't want to use outputs for regular testing, so just install
|
||||
# an unsynced fakesink when someone asks for a 'testoutput'.
|
||||
if self._config['audio']['output'] == 'testoutput':
|
||||
self._outputs = gst.element_factory_make('fakesink')
|
||||
self._outputs = Gst.element_factory_make('fakesink')
|
||||
else:
|
||||
self._outputs = _Outputs()
|
||||
try:
|
||||
@ -465,23 +462,23 @@ class Audio(pykka.ThreadingActor):
|
||||
self._handler.setup_event_handling(self._outputs.get_pad('sink'))
|
||||
|
||||
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
|
||||
# the actual switch, i.e. about to switch can block for longer thanks
|
||||
# to this queue.
|
||||
# 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-bytes', 0)
|
||||
queue.set_property('max-size-time', 3 * gst.SECOND)
|
||||
queue.set_property('min-threshold-time', 1 * gst.SECOND)
|
||||
queue.set_property('max-size-time', 3 * Gst.SECOND)
|
||||
queue.set_property('min-threshold-time', 1 * Gst.SECOND)
|
||||
|
||||
audio_sink.add(queue)
|
||||
audio_sink.add(self._outputs)
|
||||
|
||||
if self.mixer:
|
||||
volume = gst.element_factory_make('volume')
|
||||
volume = Gst.element_factory_make('volume')
|
||||
audio_sink.add(volume)
|
||||
queue.link(volume)
|
||||
volume.link(self._outputs)
|
||||
@ -489,7 +486,7 @@ class Audio(pykka.ThreadingActor):
|
||||
else:
|
||||
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)
|
||||
|
||||
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
|
||||
"""
|
||||
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://')
|
||||
|
||||
def emit_data(self, buffer_):
|
||||
@ -577,7 +574,7 @@ class Audio(pykka.ThreadingActor):
|
||||
Returns :class:`True` if data was delivered.
|
||||
|
||||
: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
|
||||
"""
|
||||
return self._appsrc.push(buffer_)
|
||||
@ -616,9 +613,9 @@ class Audio(pykka.ThreadingActor):
|
||||
:rtype: int
|
||||
"""
|
||||
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)
|
||||
except gst.QueryError:
|
||||
except Gst.QueryError:
|
||||
# TODO: take state into account for this and possibly also return
|
||||
# None as the unknown value instead of zero?
|
||||
logger.debug('Position query failed')
|
||||
@ -635,7 +632,7 @@ class Audio(pykka.ThreadingActor):
|
||||
# TODO: double check seek flags in use.
|
||||
gst_position = utils.millisecond_to_clocktime(position)
|
||||
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)
|
||||
return result
|
||||
|
||||
@ -645,7 +642,7 @@ class Audio(pykka.ThreadingActor):
|
||||
|
||||
: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):
|
||||
"""
|
||||
@ -653,7 +650,7 @@ class Audio(pykka.ThreadingActor):
|
||||
|
||||
: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):
|
||||
"""
|
||||
@ -664,7 +661,7 @@ class Audio(pykka.ThreadingActor):
|
||||
is that GStreamer will reset all its state when it changes to
|
||||
:attr:`gst.STATE_READY`.
|
||||
"""
|
||||
return self._set_state(gst.STATE_READY)
|
||||
return self._set_state(Gst.STATE_READY)
|
||||
|
||||
def stop_playback(self):
|
||||
"""
|
||||
@ -673,7 +670,7 @@ class Audio(pykka.ThreadingActor):
|
||||
:rtype: :class:`True` if successfull, else :class:`False`
|
||||
"""
|
||||
self._buffering = False
|
||||
return self._set_state(gst.STATE_NULL)
|
||||
return self._set_state(Gst.STATE_NULL)
|
||||
|
||||
def wait_for_state_change(self):
|
||||
"""Block until any pending state changes are complete.
|
||||
@ -689,7 +686,7 @@ class Audio(pykka.ThreadingActor):
|
||||
"""
|
||||
def sync_handler(bus, message):
|
||||
self._handler.on_message(bus, message)
|
||||
return gst.BUS_DROP
|
||||
return Gst.BUS_DROP
|
||||
|
||||
bus = self._playbin.get_bus()
|
||||
bus.set_sync_handler(sync_handler)
|
||||
@ -710,9 +707,9 @@ class Audio(pykka.ThreadingActor):
|
||||
"READY" -> "NULL"
|
||||
"READY" -> "PAUSED"
|
||||
|
||||
:param state: State to set playbin to. One of: `gst.STATE_NULL`,
|
||||
`gst.STATE_READY`, `gst.STATE_PAUSED` and `gst.STATE_PLAYING`.
|
||||
:type state: :class:`gst.State`
|
||||
:param state: State to set playbin to. One of: `Gst.STATE_NULL`,
|
||||
`Gst.STATE_READY`, `Gst.STATE_PAUSED` and `Gst.STATE_PLAYING`.
|
||||
:type state: :class:`Gst.State`
|
||||
:rtype: :class:`True` if successfull, else :class:`False`
|
||||
"""
|
||||
self._target_state = state
|
||||
@ -720,7 +717,7 @@ class Audio(pykka.ThreadingActor):
|
||||
gst_logger.debug('State change to %s: result=%s', state.value_name,
|
||||
result.value_name)
|
||||
|
||||
if result == gst.STATE_CHANGE_FAILURE:
|
||||
if result == Gst.STATE_CHANGE_FAILURE:
|
||||
logger.warning(
|
||||
'Setting GStreamer state to %s failed', state.value_name)
|
||||
return False
|
||||
@ -740,25 +737,25 @@ class Audio(pykka.ThreadingActor):
|
||||
:param track: the current track
|
||||
:type track: :class:`mopidy.models.Track`
|
||||
"""
|
||||
taglist = gst.TagList()
|
||||
taglist = Gst.TagList()
|
||||
artists = [a for a in (track.artists or []) if a.name]
|
||||
|
||||
# Default to blank data to trick shoutcast into clearing any previous
|
||||
# values it might have.
|
||||
taglist[gst.TAG_ARTIST] = ' '
|
||||
taglist[gst.TAG_TITLE] = ' '
|
||||
taglist[gst.TAG_ALBUM] = ' '
|
||||
taglist[Gst.TAG_ARTIST] = ' '
|
||||
taglist[Gst.TAG_TITLE] = ' '
|
||||
taglist[Gst.TAG_ALBUM] = ' '
|
||||
|
||||
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:
|
||||
taglist[gst.TAG_TITLE] = track.name
|
||||
taglist[Gst.TAG_TITLE] = track.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?
|
||||
self._playbin.send_event(event)
|
||||
gst_logger.debug('Sent tag event: track=%s', track.uri)
|
||||
|
||||
@ -3,10 +3,9 @@ from __future__ import (
|
||||
|
||||
import collections
|
||||
|
||||
import pygst
|
||||
pygst.require('0.10')
|
||||
import gst # noqa
|
||||
import gst.pbutils # noqa
|
||||
import gi
|
||||
gi.require_version('Gst', '1.0')
|
||||
from gi.repository import GObject, Gst, GstPbutils
|
||||
|
||||
from mopidy import exceptions
|
||||
from mopidy.audio import utils
|
||||
@ -15,7 +14,7 @@ from mopidy.internal import encoding
|
||||
_Result = collections.namedtuple(
|
||||
'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)?
|
||||
@ -59,7 +58,7 @@ class Scanner(object):
|
||||
duration = _query_duration(pipeline)
|
||||
seekable = _query_seekable(pipeline)
|
||||
finally:
|
||||
pipeline.set_state(gst.STATE_NULL)
|
||||
pipeline.set_state(Gst.STATE_NULL)
|
||||
del pipeline
|
||||
|
||||
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
|
||||
# decodebins and other elements don't seem to take well to being reused.
|
||||
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:
|
||||
raise exceptions.ScannerError('GStreamer can not open: %s' % uri)
|
||||
|
||||
typefind = gst.element_factory_make('typefind')
|
||||
decodebin = gst.element_factory_make('decodebin2')
|
||||
typefind = Gst.element_factory_make('typefind')
|
||||
decodebin = Gst.element_factory_make('decodebin2')
|
||||
|
||||
pipeline = gst.element_factory_make('pipeline')
|
||||
pipeline = Gst.element_factory_make('pipeline')
|
||||
for e in (src, typefind, decodebin):
|
||||
pipeline.add(e)
|
||||
gst.element_link_many(src, typefind, decodebin)
|
||||
Gst.element_link_many(src, typefind, decodebin)
|
||||
|
||||
if 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):
|
||||
decodebin.set_property('sink-caps', caps)
|
||||
struct = gst.Structure('have-type')
|
||||
struct = Gst.Structure('have-type')
|
||||
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):
|
||||
sink = gst.element_factory_make('fakesink')
|
||||
sink = Gst.element_factory_make('fakesink')
|
||||
sink.set_property('sync', False)
|
||||
|
||||
pipeline.add(sink)
|
||||
@ -105,29 +104,29 @@ def _pad_added(element, pad, pipeline):
|
||||
pad.link(sink.get_pad('sink'))
|
||||
|
||||
if pad.get_caps().is_subset(_RAW_AUDIO):
|
||||
struct = gst.Structure('have-audio')
|
||||
element.get_bus().post(gst.message_new_application(element, struct))
|
||||
struct = Gst.Structure('have-audio')
|
||||
element.get_bus().post(Gst.message_new_application(element, struct))
|
||||
|
||||
|
||||
def _start_pipeline(pipeline):
|
||||
if pipeline.set_state(gst.STATE_PAUSED) == gst.STATE_CHANGE_NO_PREROLL:
|
||||
pipeline.set_state(gst.STATE_PLAYING)
|
||||
if pipeline.set_state(Gst.STATE_PAUSED) == Gst.STATE_CHANGE_NO_PREROLL:
|
||||
pipeline.set_state(Gst.STATE_PLAYING)
|
||||
|
||||
|
||||
def _query_duration(pipeline):
|
||||
try:
|
||||
duration = pipeline.query_duration(gst.FORMAT_TIME, None)[0]
|
||||
except gst.QueryError:
|
||||
duration = pipeline.query_duration(Gst.FORMAT_TIME, None)[0]
|
||||
except Gst.QueryError:
|
||||
return None
|
||||
|
||||
if duration < 0:
|
||||
return None
|
||||
else:
|
||||
return duration // gst.MSECOND
|
||||
return duration // Gst.MSECOND
|
||||
|
||||
|
||||
def _query_seekable(pipeline):
|
||||
query = gst.query_new_seeking(gst.FORMAT_TIME)
|
||||
query = Gst.query_new_seeking(Gst.FORMAT_TIME)
|
||||
pipeline.query(query)
|
||||
return query.parse_seeking()[1]
|
||||
|
||||
@ -135,15 +134,15 @@ def _query_seekable(pipeline):
|
||||
def _process(pipeline, timeout_ms):
|
||||
clock = pipeline.get_clock()
|
||||
bus = pipeline.get_bus()
|
||||
timeout = timeout_ms * gst.MSECOND
|
||||
timeout = timeout_ms * Gst.MSECOND
|
||||
tags = {}
|
||||
mime = None
|
||||
have_audio = False
|
||||
missing_message = None
|
||||
|
||||
types = (
|
||||
gst.MESSAGE_ELEMENT | gst.MESSAGE_APPLICATION | gst.MESSAGE_ERROR |
|
||||
gst.MESSAGE_EOS | gst.MESSAGE_ASYNC_DONE | gst.MESSAGE_TAG)
|
||||
Gst.MESSAGE_ELEMENT | Gst.MESSAGE_APPLICATION | Gst.MESSAGE_ERROR |
|
||||
Gst.MESSAGE_EOS | Gst.MESSAGE_ASYNC_DONE | Gst.MESSAGE_TAG)
|
||||
|
||||
previous = clock.get_time()
|
||||
while timeout > 0:
|
||||
@ -151,29 +150,29 @@ def _process(pipeline, timeout_ms):
|
||||
|
||||
if message is None:
|
||||
break
|
||||
elif message.type == gst.MESSAGE_ELEMENT:
|
||||
if gst.pbutils.is_missing_plugin_message(message):
|
||||
elif message.type == Gst.MESSAGE_ELEMENT:
|
||||
if GstPbutils.is_missing_plugin_message(message):
|
||||
missing_message = message
|
||||
elif message.type == gst.MESSAGE_APPLICATION:
|
||||
elif message.type == Gst.MESSAGE_APPLICATION:
|
||||
if message.structure.get_name() == 'have-type':
|
||||
mime = message.structure['caps'].get_name()
|
||||
if mime.startswith('text/') or mime == 'application/xml':
|
||||
return tags, mime, have_audio
|
||||
elif message.structure.get_name() == 'have-audio':
|
||||
have_audio = True
|
||||
elif message.type == gst.MESSAGE_ERROR:
|
||||
elif message.type == Gst.MESSAGE_ERROR:
|
||||
error = encoding.locale_decode(message.parse_error()[0])
|
||||
if missing_message and not mime:
|
||||
caps = missing_message.structure['detail']
|
||||
mime = caps.get_structure(0).get_name()
|
||||
return tags, mime, have_audio
|
||||
raise exceptions.ScannerError(error)
|
||||
elif message.type == gst.MESSAGE_EOS:
|
||||
elif message.type == Gst.MESSAGE_EOS:
|
||||
return tags, mime, have_audio
|
||||
elif message.type == gst.MESSAGE_ASYNC_DONE:
|
||||
elif message.type == Gst.MESSAGE_ASYNC_DONE:
|
||||
if message.src == pipeline:
|
||||
return tags, mime, have_audio
|
||||
elif message.type == gst.MESSAGE_TAG:
|
||||
elif message.type == Gst.MESSAGE_TAG:
|
||||
taglist = message.parse_tag()
|
||||
# Note that this will only keep the last tag.
|
||||
tags.update(utils.convert_taglist(taglist))
|
||||
@ -189,15 +188,13 @@ if __name__ == '__main__':
|
||||
import os
|
||||
import sys
|
||||
|
||||
import gobject
|
||||
|
||||
from mopidy.internal import path
|
||||
|
||||
gobject.threads_init()
|
||||
GObject.threads_init()
|
||||
|
||||
scanner = Scanner(5000)
|
||||
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))
|
||||
try:
|
||||
result = scanner.scan(uri)
|
||||
|
||||
@ -4,9 +4,9 @@ import datetime
|
||||
import logging
|
||||
import numbers
|
||||
|
||||
import pygst
|
||||
pygst.require('0.10')
|
||||
import gst # noqa
|
||||
import gi
|
||||
gi.require_version('Gst', '1.0')
|
||||
from gi.repository import Gst
|
||||
|
||||
from mopidy import compat, httpclient
|
||||
from mopidy.models import Album, Artist, Track
|
||||
@ -17,7 +17,7 @@ logger = logging.getLogger(__name__)
|
||||
def calculate_duration(num_samples, sample_rate):
|
||||
"""Determine duration of samples using GStreamer helper for precise
|
||||
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):
|
||||
@ -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.
|
||||
"""
|
||||
buffer_ = gst.Buffer(data)
|
||||
buffer_ = Gst.Buffer(data)
|
||||
if capabilites:
|
||||
if isinstance(capabilites, compat.string_types):
|
||||
capabilites = gst.caps_from_string(capabilites)
|
||||
capabilites = Gst.caps_from_string(capabilites)
|
||||
buffer_.set_caps(capabilites)
|
||||
if timestamp:
|
||||
buffer_.timestamp = timestamp
|
||||
@ -39,12 +39,12 @@ def create_buffer(data, capabilites=None, timestamp=None, duration=None):
|
||||
|
||||
def millisecond_to_clocktime(value):
|
||||
"""Convert a millisecond time to internal GStreamer time."""
|
||||
return value * gst.MSECOND
|
||||
return value * Gst.MSECOND
|
||||
|
||||
|
||||
def clocktime_to_millisecond(value):
|
||||
"""Convert an internal GStreamer time to millisecond time."""
|
||||
return value // gst.MSECOND
|
||||
return value // Gst.MSECOND
|
||||
|
||||
|
||||
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.
|
||||
"""
|
||||
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():
|
||||
if uri in uri_schemes:
|
||||
supported_schemes.add(uri)
|
||||
@ -95,37 +95,37 @@ def convert_tags_to_track(tags):
|
||||
album_kwargs = {}
|
||||
track_kwargs = {}
|
||||
|
||||
track_kwargs['composers'] = _artists(tags, gst.TAG_COMPOSER)
|
||||
track_kwargs['performers'] = _artists(tags, gst.TAG_PERFORMER)
|
||||
track_kwargs['artists'] = _artists(tags, gst.TAG_ARTIST,
|
||||
track_kwargs['composers'] = _artists(tags, Gst.TAG_COMPOSER)
|
||||
track_kwargs['performers'] = _artists(tags, Gst.TAG_PERFORMER)
|
||||
track_kwargs['artists'] = _artists(tags, Gst.TAG_ARTIST,
|
||||
'musicbrainz-artistid',
|
||||
'musicbrainz-sortname')
|
||||
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['name'] = '; '.join(tags.get(gst.TAG_TITLE, []))
|
||||
track_kwargs['genre'] = '; '.join(tags.get(Gst.TAG_GENRE, []))
|
||||
track_kwargs['name'] = '; '.join(tags.get(Gst.TAG_TITLE, []))
|
||||
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', []))
|
||||
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']:
|
||||
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['disc_no'] = tags.get(gst.TAG_ALBUM_VOLUME_NUMBER, [None])[0]
|
||||
track_kwargs['bitrate'] = tags.get(gst.TAG_BITRATE, [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['bitrate'] = tags.get(Gst.TAG_BITRATE, [None])[0]
|
||||
track_kwargs['musicbrainz_id'] = tags.get('musicbrainz-trackid', [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_discs'] = tags.get(gst.TAG_ALBUM_VOLUME_COUNT, [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_discs'] = tags.get(Gst.TAG_ALBUM_VOLUME_COUNT, [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]:
|
||||
track_kwargs['date'] = tags[gst.TAG_DATE][0].isoformat()
|
||||
if tags.get(Gst.TAG_DATE) and tags.get(Gst.TAG_DATE)[0]:
|
||||
track_kwargs['date'] = tags[Gst.TAG_DATE][0].isoformat()
|
||||
|
||||
# Clear out any empty values we found
|
||||
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.
|
||||
|
||||
:param element: element to setup proxy in.
|
||||
:type element: :class:`gst.GstElement`
|
||||
:type element: :class:`Gst.GstElement`
|
||||
:param config: proxy settings to use.
|
||||
:type config: :class:`dict`
|
||||
"""
|
||||
@ -155,7 +155,7 @@ def setup_proxy(element, config):
|
||||
|
||||
|
||||
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:
|
||||
|
||||
@ -172,7 +172,7 @@ def convert_taglist(taglist):
|
||||
0.10.36/gstreamer/html/gstreamer-GstTagList.html
|
||||
|
||||
: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.
|
||||
"""
|
||||
result = {}
|
||||
@ -187,13 +187,13 @@ def convert_taglist(taglist):
|
||||
values = [values]
|
||||
|
||||
for value in values:
|
||||
if isinstance(value, gst.Date):
|
||||
if isinstance(value, Gst.Date):
|
||||
try:
|
||||
date = datetime.date(value.year, value.month, value.day)
|
||||
result[key].append(date)
|
||||
except ValueError:
|
||||
logger.debug('Ignoring invalid date: %r = %r', key, value)
|
||||
elif isinstance(value, gst.Buffer):
|
||||
elif isinstance(value, Gst.Buffer):
|
||||
result[key].append(bytes(value))
|
||||
elif isinstance(
|
||||
value, (compat.string_types, bool, numbers.Number)):
|
||||
|
||||
@ -7,9 +7,7 @@ import logging
|
||||
import os
|
||||
import sys
|
||||
|
||||
import glib
|
||||
|
||||
import gobject
|
||||
from gi.repository import GLib, GObject
|
||||
|
||||
import pykka
|
||||
|
||||
@ -21,7 +19,7 @@ from mopidy.internal import deps, process, timer, versioning
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
_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 = b':'.join(_default_config)
|
||||
|
||||
@ -286,7 +284,7 @@ class RootCommand(Command):
|
||||
help='`section/key=value` values to override config options')
|
||||
|
||||
def run(self, args, config):
|
||||
loop = gobject.MainLoop()
|
||||
loop = GObject.MainLoop()
|
||||
|
||||
mixer_class = self.get_mixer_class(config, args.registry['mixer'])
|
||||
backend_classes = args.registry['backend']
|
||||
|
||||
@ -5,11 +5,11 @@ import os
|
||||
import platform
|
||||
import sys
|
||||
|
||||
import pkg_resources
|
||||
import gi
|
||||
gi.require_version('Gst', '1.0')
|
||||
from gi.repository import Gst
|
||||
|
||||
import pygst
|
||||
pygst.require('0.10')
|
||||
import gst # noqa
|
||||
import pkg_resources
|
||||
|
||||
from mopidy.internal import formatting
|
||||
|
||||
@ -110,8 +110,7 @@ def pkg_info(project_name=None, include_extras=False):
|
||||
|
||||
def gstreamer_info():
|
||||
other = []
|
||||
other.append('Python wrapper: gst-python %s' % (
|
||||
'.'.join(map(str, gst.get_pygst_version()))))
|
||||
other.append('Python wrapper: python-gi %s' % gi.__version__)
|
||||
|
||||
found_elements = []
|
||||
missing_elements = []
|
||||
@ -135,8 +134,8 @@ def gstreamer_info():
|
||||
|
||||
return {
|
||||
'name': 'GStreamer',
|
||||
'version': '.'.join(map(str, gst.get_gst_version())),
|
||||
'path': os.path.dirname(gst.__file__),
|
||||
'version': '.'.join(map(str, Gst.version())),
|
||||
'path': os.path.dirname(gi.__file__),
|
||||
'other': '\n'.join(other),
|
||||
}
|
||||
|
||||
@ -187,6 +186,6 @@ def _gstreamer_check_elements():
|
||||
]
|
||||
known_elements = [
|
||||
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 [
|
||||
(element, element in known_elements) for element in elements_to_check]
|
||||
|
||||
@ -7,7 +7,7 @@ import socket
|
||||
import sys
|
||||
import threading
|
||||
|
||||
import gobject
|
||||
from gi.repository import GObject
|
||||
|
||||
import pykka
|
||||
|
||||
@ -67,7 +67,7 @@ def format_hostname(hostname):
|
||||
|
||||
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,
|
||||
max_connections=5, timeout=30):
|
||||
@ -87,7 +87,7 @@ class Server(object):
|
||||
return sock
|
||||
|
||||
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):
|
||||
try:
|
||||
@ -132,7 +132,7 @@ class Server(object):
|
||||
class Connection(object):
|
||||
# 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
|
||||
# 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
|
||||
# false return value would only tell us that what we thought was registered
|
||||
@ -211,14 +211,14 @@ class Connection(object):
|
||||
return
|
||||
|
||||
self.disable_timeout()
|
||||
self.timeout_id = gobject.timeout_add_seconds(
|
||||
self.timeout_id = GObject.timeout_add_seconds(
|
||||
self.timeout, self.timeout_callback)
|
||||
|
||||
def disable_timeout(self):
|
||||
"""Deactivate timeout mechanism."""
|
||||
if self.timeout_id is None:
|
||||
return
|
||||
gobject.source_remove(self.timeout_id)
|
||||
GObject.source_remove(self.timeout_id)
|
||||
self.timeout_id = None
|
||||
|
||||
def enable_recv(self):
|
||||
@ -226,9 +226,9 @@ class Connection(object):
|
||||
return
|
||||
|
||||
try:
|
||||
self.recv_id = gobject.io_add_watch(
|
||||
self.recv_id = GObject.io_add_watch(
|
||||
self.sock.fileno(),
|
||||
gobject.IO_IN | gobject.IO_ERR | gobject.IO_HUP,
|
||||
GObject.IO_IN | GObject.IO_ERR | GObject.IO_HUP,
|
||||
self.recv_callback)
|
||||
except socket.error as e:
|
||||
self.stop('Problem with connection: %s' % e)
|
||||
@ -236,7 +236,7 @@ class Connection(object):
|
||||
def disable_recv(self):
|
||||
if self.recv_id is None:
|
||||
return
|
||||
gobject.source_remove(self.recv_id)
|
||||
GObject.source_remove(self.recv_id)
|
||||
self.recv_id = None
|
||||
|
||||
def enable_send(self):
|
||||
@ -244,9 +244,9 @@ class Connection(object):
|
||||
return
|
||||
|
||||
try:
|
||||
self.send_id = gobject.io_add_watch(
|
||||
self.send_id = GObject.io_add_watch(
|
||||
self.sock.fileno(),
|
||||
gobject.IO_OUT | gobject.IO_ERR | gobject.IO_HUP,
|
||||
GObject.IO_OUT | GObject.IO_ERR | GObject.IO_HUP,
|
||||
self.send_callback)
|
||||
except socket.error as e:
|
||||
self.stop('Problem with connection: %s' % e)
|
||||
@ -255,11 +255,11 @@ class Connection(object):
|
||||
if self.send_id is None:
|
||||
return
|
||||
|
||||
gobject.source_remove(self.send_id)
|
||||
GObject.source_remove(self.send_id)
|
||||
self.send_id = None
|
||||
|
||||
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)
|
||||
return True
|
||||
|
||||
@ -283,7 +283,7 @@ class Connection(object):
|
||||
return True
|
||||
|
||||
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)
|
||||
return True
|
||||
|
||||
|
||||
@ -2,10 +2,6 @@ from __future__ import absolute_import, unicode_literals
|
||||
|
||||
import io
|
||||
|
||||
import pygst
|
||||
pygst.require('0.10')
|
||||
import gst # noqa
|
||||
|
||||
from mopidy.compat import configparser
|
||||
from mopidy.internal import validation
|
||||
|
||||
|
||||
@ -3,15 +3,13 @@ from __future__ import absolute_import, unicode_literals
|
||||
import threading
|
||||
import unittest
|
||||
|
||||
import gobject
|
||||
gobject.threads_init()
|
||||
import gi
|
||||
gi.require_version('Gst', '1.0')
|
||||
from gi.repository import GObject, Gst
|
||||
GObject.threads_init()
|
||||
|
||||
import mock
|
||||
|
||||
import pygst
|
||||
pygst.require('0.10')
|
||||
import gst # noqa
|
||||
|
||||
import pykka
|
||||
|
||||
from mopidy import audio
|
||||
@ -520,17 +518,17 @@ class AudioStateTest(unittest.TestCase):
|
||||
|
||||
def test_state_does_not_change_when_in_gst_ready_state(self):
|
||||
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)
|
||||
|
||||
def test_state_changes_from_stopped_to_playing_on_play(self):
|
||||
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(
|
||||
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(
|
||||
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)
|
||||
|
||||
@ -538,7 +536,7 @@ class AudioStateTest(unittest.TestCase):
|
||||
self.audio.state = audio.PlaybackState.PLAYING
|
||||
|
||||
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)
|
||||
|
||||
@ -546,12 +544,12 @@ class AudioStateTest(unittest.TestCase):
|
||||
self.audio.state = audio.PlaybackState.PLAYING
|
||||
|
||||
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(
|
||||
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
|
||||
# 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)
|
||||
|
||||
@ -565,17 +563,17 @@ class AudioBufferingTest(unittest.TestCase):
|
||||
def test_pause_when_buffer_empty(self):
|
||||
playbin = self.audio._playbin
|
||||
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()
|
||||
|
||||
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)
|
||||
|
||||
def test_stay_paused_when_buffering_finished(self):
|
||||
playbin = self.audio._playbin
|
||||
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()
|
||||
|
||||
self.audio._handler.on_buffering(100)
|
||||
@ -585,11 +583,11 @@ class AudioBufferingTest(unittest.TestCase):
|
||||
def test_change_to_paused_while_buffering(self):
|
||||
playbin = self.audio._playbin
|
||||
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()
|
||||
|
||||
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()
|
||||
playbin.set_state.reset_mock()
|
||||
|
||||
@ -600,13 +598,13 @@ class AudioBufferingTest(unittest.TestCase):
|
||||
def test_change_to_stopped_while_buffering(self):
|
||||
playbin = self.audio._playbin
|
||||
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()
|
||||
|
||||
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()
|
||||
|
||||
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)
|
||||
|
||||
@ -3,8 +3,12 @@ from __future__ import absolute_import, unicode_literals
|
||||
import os
|
||||
import unittest
|
||||
|
||||
import gobject
|
||||
gobject.threads_init()
|
||||
import gi
|
||||
gi.require_version('Gst', '1.0')
|
||||
from gi.repository import GObject, Gst
|
||||
|
||||
GObject.threads_init()
|
||||
Gst.init(None)
|
||||
|
||||
from mopidy import exceptions
|
||||
from mopidy.audio import scan
|
||||
|
||||
@ -5,7 +5,7 @@ import logging
|
||||
import socket
|
||||
import unittest
|
||||
|
||||
import gobject
|
||||
from gi.repository import GObject
|
||||
|
||||
from mock import Mock, call, patch, sentinel
|
||||
|
||||
@ -162,27 +162,27 @@ class ConnectionTest(unittest.TestCase):
|
||||
network.Connection.stop(self.mock, sentinel.reason)
|
||||
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):
|
||||
self.mock.recv_id = None
|
||||
self.mock.sock = Mock(spec=socket.SocketType)
|
||||
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)
|
||||
gobject.io_add_watch.assert_called_once_with(
|
||||
GObject.io_add_watch.assert_called_once_with(
|
||||
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.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):
|
||||
self.mock.sock = Mock(spec=socket.SocketType)
|
||||
self.mock.recv_id = sentinel.tag
|
||||
|
||||
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):
|
||||
self.mock.recv_id = sentinel.tag
|
||||
@ -191,20 +191,20 @@ class ConnectionTest(unittest.TestCase):
|
||||
network.Connection.enable_recv(self.mock)
|
||||
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):
|
||||
self.mock.recv_id = sentinel.tag
|
||||
|
||||
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)
|
||||
|
||||
@patch.object(gobject, 'source_remove', new=Mock())
|
||||
@patch.object(GObject, 'source_remove', new=Mock())
|
||||
def test_disable_recv_already_deregistered(self):
|
||||
self.mock.recv_id = None
|
||||
|
||||
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)
|
||||
|
||||
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.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):
|
||||
self.mock.send_id = None
|
||||
self.mock.sock = Mock(spec=socket.SocketType)
|
||||
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)
|
||||
gobject.io_add_watch.assert_called_once_with(
|
||||
GObject.io_add_watch.assert_called_once_with(
|
||||
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.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):
|
||||
self.mock.sock = Mock(spec=socket.SocketType)
|
||||
self.mock.send_id = sentinel.tag
|
||||
|
||||
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):
|
||||
self.mock.send_id = sentinel.tag
|
||||
@ -245,20 +245,20 @@ class ConnectionTest(unittest.TestCase):
|
||||
network.Connection.enable_send(self.mock)
|
||||
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):
|
||||
self.mock.send_id = sentinel.tag
|
||||
|
||||
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)
|
||||
|
||||
@patch.object(gobject, 'source_remove', new=Mock())
|
||||
@patch.object(GObject, 'source_remove', new=Mock())
|
||||
def test_disable_send_already_deregistered(self):
|
||||
self.mock.send_id = None
|
||||
|
||||
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)
|
||||
|
||||
def test_enable_send_on_closed_socket(self):
|
||||
@ -269,36 +269,36 @@ class ConnectionTest(unittest.TestCase):
|
||||
network.Connection.enable_send(self.mock)
|
||||
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):
|
||||
self.mock.timeout = 10
|
||||
|
||||
network.Connection.enable_timeout(self.mock)
|
||||
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):
|
||||
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)
|
||||
gobject.timeout_add_seconds.assert_called_once_with(
|
||||
GObject.timeout_add_seconds.assert_called_once_with(
|
||||
10, self.mock.timeout_callback)
|
||||
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):
|
||||
self.mock.timeout = 0
|
||||
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
|
||||
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
|
||||
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):
|
||||
self.mock.timeout = 0
|
||||
@ -313,20 +313,20 @@ class ConnectionTest(unittest.TestCase):
|
||||
network.Connection.enable_timeout(self.mock)
|
||||
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):
|
||||
self.mock.timeout_id = sentinel.tag
|
||||
|
||||
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)
|
||||
|
||||
@patch.object(gobject, 'source_remove', new=Mock())
|
||||
@patch.object(GObject, 'source_remove', new=Mock())
|
||||
def test_disable_timeout_already_deregistered(self):
|
||||
self.mock.timeout_id = None
|
||||
|
||||
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)
|
||||
|
||||
def test_queue_send_acquires_and_releases_lock(self):
|
||||
@ -372,7 +372,7 @@ class ConnectionTest(unittest.TestCase):
|
||||
self.mock.actor_ref = Mock()
|
||||
|
||||
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)
|
||||
|
||||
def test_recv_callback_respects_io_hup(self):
|
||||
@ -380,7 +380,7 @@ class ConnectionTest(unittest.TestCase):
|
||||
self.mock.actor_ref = Mock()
|
||||
|
||||
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)
|
||||
|
||||
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.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)
|
||||
|
||||
def test_recv_callback_sends_data_to_actor(self):
|
||||
@ -398,7 +398,7 @@ class ConnectionTest(unittest.TestCase):
|
||||
self.mock.actor_ref = Mock()
|
||||
|
||||
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(
|
||||
{'received': 'data'})
|
||||
|
||||
@ -409,7 +409,7 @@ class ConnectionTest(unittest.TestCase):
|
||||
self.mock.actor_ref.tell.side_effect = pykka.ActorDeadError()
|
||||
|
||||
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)
|
||||
|
||||
def test_recv_callback_gets_no_data(self):
|
||||
@ -418,7 +418,7 @@ class ConnectionTest(unittest.TestCase):
|
||||
self.mock.actor_ref = Mock()
|
||||
|
||||
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, [
|
||||
call.sock.recv(any_int),
|
||||
call.disable_recv(),
|
||||
@ -431,7 +431,7 @@ class ConnectionTest(unittest.TestCase):
|
||||
for error in (errno.EWOULDBLOCK, errno.EINTR):
|
||||
self.mock.sock.recv.side_effect = socket.error(error, '')
|
||||
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)
|
||||
|
||||
def test_recv_callback_unrecoverable_error(self):
|
||||
@ -439,7 +439,7 @@ class ConnectionTest(unittest.TestCase):
|
||||
self.mock.sock.recv.side_effect = socket.error
|
||||
|
||||
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)
|
||||
|
||||
def test_send_callback_respects_io_err(self):
|
||||
@ -450,7 +450,7 @@ class ConnectionTest(unittest.TestCase):
|
||||
self.mock.send_buffer = ''
|
||||
|
||||
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)
|
||||
|
||||
def test_send_callback_respects_io_hup(self):
|
||||
@ -461,7 +461,7 @@ class ConnectionTest(unittest.TestCase):
|
||||
self.mock.send_buffer = ''
|
||||
|
||||
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)
|
||||
|
||||
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.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)
|
||||
|
||||
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.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.release.assert_called_once_with()
|
||||
|
||||
@ -496,7 +496,7 @@ class ConnectionTest(unittest.TestCase):
|
||||
self.mock.sock.send.return_value = 0
|
||||
|
||||
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.assertEqual(0, self.mock.sock.send.call_count)
|
||||
|
||||
@ -507,7 +507,7 @@ class ConnectionTest(unittest.TestCase):
|
||||
self.mock.send.return_value = ''
|
||||
|
||||
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.send.assert_called_once_with('data')
|
||||
self.assertEqual('', self.mock.send_buffer)
|
||||
@ -519,7 +519,7 @@ class ConnectionTest(unittest.TestCase):
|
||||
self.mock.send.return_value = 'ta'
|
||||
|
||||
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.assertEqual('ta', self.mock.send_buffer)
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@ import errno
|
||||
import socket
|
||||
import unittest
|
||||
|
||||
import gobject
|
||||
from gi.repository import GObject
|
||||
|
||||
from mock import Mock, patch, sentinel
|
||||
|
||||
@ -91,11 +91,11 @@ class ServerTest(unittest.TestCase):
|
||||
network.Server.create_server_socket(
|
||||
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):
|
||||
network.Server.register_server_socket(self.mock, sentinel.fileno)
|
||||
gobject.io_add_watch.assert_called_once_with(
|
||||
sentinel.fileno, gobject.IO_IN, self.mock.handle_connection)
|
||||
GObject.io_add_watch.assert_called_once_with(
|
||||
sentinel.fileno, GObject.IO_IN, self.mock.handle_connection)
|
||||
|
||||
def test_handle_connection(self):
|
||||
self.mock.accept_connection.return_value = (
|
||||
@ -103,7 +103,7 @@ class ServerTest(unittest.TestCase):
|
||||
self.mock.maximum_connections_exceeded.return_value = False
|
||||
|
||||
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.maximum_connections_exceeded.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.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.maximum_connections_exceeded.assert_called_once_with()
|
||||
self.mock.reject_connection.assert_called_once_with(
|
||||
|
||||
@ -4,14 +4,14 @@ import platform
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
import gi
|
||||
gi.require_version('Gst', '1.0')
|
||||
from gi.repository import Gst
|
||||
|
||||
import mock
|
||||
|
||||
import pkg_resources
|
||||
|
||||
import pygst
|
||||
pygst.require('0.10')
|
||||
import gst # noqa
|
||||
|
||||
from mopidy.internal import deps
|
||||
|
||||
|
||||
@ -74,12 +74,11 @@ class DepsTest(unittest.TestCase):
|
||||
|
||||
self.assertEqual('GStreamer', result['name'])
|
||||
self.assertEqual(
|
||||
'.'.join(map(str, gst.get_gst_version())), result['version'])
|
||||
self.assertIn('gst', result['path'])
|
||||
'.'.join(map(str, Gst.version())), result['version'])
|
||||
self.assertIn('gi', result['path'])
|
||||
self.assertNotIn('__init__.py', result['path'])
|
||||
self.assertIn('Python wrapper: gst-python', result['other'])
|
||||
self.assertIn(
|
||||
'.'.join(map(str, gst.get_pygst_version())), result['other'])
|
||||
self.assertIn('Python wrapper: python-gi', result['other'])
|
||||
self.assertIn(gi.__version__, result['other'])
|
||||
self.assertIn('Relevant elements:', result['other'])
|
||||
|
||||
@mock.patch('pkg_resources.get_distribution')
|
||||
|
||||
@ -7,7 +7,7 @@ import shutil
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
import glib
|
||||
from gi.repository import GLib
|
||||
|
||||
from mopidy import compat, exceptions
|
||||
from mopidy.internal import path
|
||||
@ -215,7 +215,7 @@ class ExpandPathTest(unittest.TestCase):
|
||||
|
||||
def test_xdg_subsititution(self):
|
||||
self.assertEqual(
|
||||
glib.get_user_data_dir() + b'/foo',
|
||||
GLib.get_user_data_dir() + b'/foo',
|
||||
path.expand_path(b'$XDG_DATA_DIR/foo'))
|
||||
|
||||
def test_xdg_subsititution_unknown(self):
|
||||
|
||||
Loading…
Reference in New Issue
Block a user