From 0169ce7cad2d462988a32808c874bb3fb3545017 Mon Sep 17 00:00:00 2001 From: Thomas Adamcik Date: Tue, 6 Oct 2015 22:45:06 +0200 Subject: [PATCH] core: Make sure the about-to-finish callback gets run in the actor. When about to finish gets called we are running in some GStreamer thread. Our audio code then calls the shim core callback which is responsible for transferring our execution to the core actor thread and waiting for the response. From this point we do normal actor calls to the backend(s) which in turn call into the audio actor. Since the initial audio code that was called is outside the actor this should never deadlock due to this loop. --- mopidy/core/playback.py | 16 +++++++++++++++- tests/core/test_playback.py | 4 ++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/mopidy/core/playback.py b/mopidy/core/playback.py index a8afebd3..4216f349 100644 --- a/mopidy/core/playback.py +++ b/mopidy/core/playback.py @@ -27,7 +27,8 @@ class PlaybackController(object): self._pending_tl_track = None if self._audio: - self._audio.set_about_to_finish_callback(self._on_about_to_finish) + self._audio.set_about_to_finish_callback( + self._on_about_to_finish_callback) def _get_backend(self, tl_track): if tl_track is None: @@ -206,6 +207,19 @@ class PlaybackController(object): self._pending_tl_track = None self._trigger_track_playback_started() + def _on_about_to_finish_callback(self): + """Callback that performs a blocking actor call to the real callback. + + This is passed to audio, which is allowed to call this code from the + audio thread. We pass execution into the core actor to ensure that + there is no unsafe access of state in core. This must block until + we get a response. + """ + self.core.actor_ref.ask({ + 'command': 'pykka_call', 'args': tuple(), 'kwargs': {}, + 'attr_path': ('playback', '_on_about_to_finish'), + }) + def _on_about_to_finish(self): self._trigger_track_playback_ended(self.get_time_position()) diff --git a/tests/core/test_playback.py b/tests/core/test_playback.py index 60a3f612..0869b3ec 100644 --- a/tests/core/test_playback.py +++ b/tests/core/test_playback.py @@ -40,6 +40,10 @@ class BaseTest(unittest.TestCase): audio=self.audio, backends=[self.backend], config=self.config) self.playback = self.core.playback + # We don't have a core actor running, so call about to finish directly. + self.audio.set_about_to_finish_callback( + self.playback._on_about_to_finish) + with deprecation.ignore('core.tracklist.add:tracks_arg'): self.core.tracklist.add(self.tracks)