Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ classifiers = [
]
dynamic = ["version"]
dependencies = [
"mopidy >= 4.0.0a7",
"mopidy >= 4.0.0a8",
"pygobject >= 3.50",
"pykka >= 4.1",
]
Expand Down
3 changes: 1 addition & 2 deletions src/mopidy_mpd/protocol/playback.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@

from typing import TYPE_CHECKING, Never

from mopidy.core import PlaybackState
from mopidy.types import DurationMs, Percentage
from mopidy.types import DurationMs, Percentage, PlaybackState

from mopidy_mpd import exceptions, protocol

Expand Down
2 changes: 1 addition & 1 deletion src/mopidy_mpd/protocol/status.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from typing import TYPE_CHECKING

from mopidy.core import PlaybackState
from mopidy.types import PlaybackState

from mopidy_mpd import exceptions, protocol, translator

Expand Down
86 changes: 26 additions & 60 deletions tests/dummy_audio.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,23 @@
tests of the core and backends.
"""

from typing import override

import pykka
from mopidy import audio
from mopidy.types import DurationMs, PlaybackState


def create_proxy(config=None, mixer=None):
return DummyAudio.start(config, mixer).proxy()


# TODO: reset position on track change?
class DummyAudio(pykka.ThreadingActor):
class DummyAudio(audio.Audio, pykka.ThreadingActor):
def __init__(self, config=None, mixer=None):
super().__init__()
self.state = audio.PlaybackState.STOPPED
self._volume = 0
self._position = 0
self.state = PlaybackState.STOPPED
self._position = DurationMs(0)
self._source_setup_callback = None
self._about_to_finish_callback = None
self._uri = None
Expand All @@ -27,72 +29,60 @@ def __init__(self, config=None, mixer=None):
self._tags = {}
self._bad_uris = set()

@override
def set_uri(self, uri, live_stream=False, download=False):
assert self._uri is None, "prepare change not called before set"
self._position = 0
self._position = DurationMs(0)
self._uri = uri
self._stream_changed = True
self._live_stream = live_stream
self._tags = {}

def set_appsrc(self, *args, **kwargs):
pass
@override
def set_source_setup_callback(self, callback):
self._source_setup_callback = callback

def emit_data(self, buffer_):
pass
@override
def set_about_to_finish_callback(self, callback):
self._about_to_finish_callback = callback

@override
def get_position(self):
return self._position

@override
def set_position(self, position):
self._position = position
audio.AudioListener.send("position_changed", position=position)
return True

@override
def start_playback(self):
return self._change_state(audio.PlaybackState.PLAYING)
return self._change_state(PlaybackState.PLAYING)

@override
def pause_playback(self):
return self._change_state(audio.PlaybackState.PAUSED)
return self._change_state(PlaybackState.PAUSED)

@override
def prepare_change(self):
self._uri = None
self._source_setup_callback = None
return True

@override
def stop_playback(self):
return self._change_state(audio.PlaybackState.STOPPED)

def get_volume(self):
return self._volume

def set_volume(self, volume):
self._volume = volume
return True

def set_metadata(self, track):
pass
return self._change_state(PlaybackState.STOPPED)

@override
def get_current_tags(self):
return self._tags

def set_source_setup_callback(self, callback):
self._source_setup_callback = callback

def set_about_to_finish_callback(self, callback):
self._about_to_finish_callback = callback

def enable_sync_handler(self):
pass

def wait_for_state_change(self):
pass

def _change_state(self, new_state):
if not self._uri:
return False

if new_state == audio.PlaybackState.STOPPED and self._uri:
if new_state == PlaybackState.STOPPED and self._uri:
self._stream_changed = True
self._uri = None

Expand All @@ -111,7 +101,7 @@ def _change_state(self, new_state):
target_state=None,
)

if new_state == audio.PlaybackState.PLAYING:
if new_state == PlaybackState.PLAYING:
self._tags["audio-codec"] = ["fake info..."]
audio.AudioListener.send("tags_changed", tags=["audio-codec"])

Expand All @@ -123,27 +113,3 @@ def trigger_fake_playback_failure(self, uri):
def trigger_fake_tags_changed(self, tags):
self._tags.update(tags)
audio.AudioListener.send("tags_changed", tags=self._tags.keys())

def get_source_setup_callback(self):
# This needs to be called from outside the actor or we lock up.
def wrapper():
if self._source_setup_callback:
self._source_setup_callback()

return wrapper

def get_about_to_finish_callback(self):
# This needs to be called from outside the actor or we lock up.
def wrapper():
if self._about_to_finish_callback:
self.prepare_change()
self._about_to_finish_callback()

if not self._uri or not self._about_to_finish_callback:
self._tags = {}
audio.AudioListener.send("reached_end_of_stream")
else:
audio.AudioListener.send("position_changed", position=0)
audio.AudioListener.send("stream_changed", uri=self._uri)

return wrapper
2 changes: 1 addition & 1 deletion tests/protocol/test_playback.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import unittest

from mopidy.core import PlaybackState
from mopidy.models import Track
from mopidy.types import PlaybackState

from tests import protocol

Expand Down
12 changes: 8 additions & 4 deletions tests/protocol/test_regression.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ class IssueGH17RegressionTest(protocol.BaseTestCase):
- Press next until you get to the unplayable track
"""

@mock.patch.object(protocol.core.tracklist.random, "shuffle", mock_shuffle)
def test(self):
random.seed(1)
tracks = [
Track(uri="dummy:a"),
Track(uri="dummy:b"),
Expand All @@ -42,14 +42,18 @@ def test(self):
assert self.core.playback.get_current_track().get().uri == "dummy:a"
self.send_request('random "1"')
self.send_request("next")
assert self.core.playback.get_current_track().get().uri == "dummy:b"
assert self.core.playback.get_current_track().get().uri == "dummy:d"
self.send_request("next")
# Should now be at track 'c', but playback fails and it skips ahead
assert self.core.playback.get_current_track().get().uri == "dummy:f"
self.send_request("next")
assert self.core.playback.get_current_track().get().uri == "dummy:d"
assert self.core.playback.get_current_track().get().uri == "dummy:a"
self.send_request("next")
assert self.core.playback.get_current_track().get().uri == "dummy:e"
self.send_request("next")
assert self.core.playback.get_current_track().get().uri == "dummy:b"
self.send_request("next")
# All tracks have been played, including the error one, which we skipped.
assert self.core.playback.get_current_track().get() is None


class IssueGH18RegressionTest(protocol.BaseTestCase):
Expand Down
2 changes: 1 addition & 1 deletion tests/test_status.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@

import pykka
from mopidy import core
from mopidy.core import PlaybackState
from mopidy.models import Track
from mopidy.types import PlaybackState

from mopidy_mpd import dispatcher, uri_mapper
from mopidy_mpd.protocol import status
Expand Down