From a06d6f28d156489715d4f84fa6d30582bea8881b Mon Sep 17 00:00:00 2001 From: casey langen Date: Fri, 30 Oct 2020 16:47:57 -0700 Subject: [PATCH] Added track fetching timeouts to PlaybackService. This should skirt a couple edge cases and possibly allow us to not immediately stop playback when reconnecting. --- src/musikcore/audio/PlaybackService.cpp | 41 +++++++++++--------- src/musikcore/library/track/TrackList.cpp | 16 ++++++++ src/musikcore/library/track/TrackList.h | 3 +- src/musikcube/app/layout/MainLayout.cpp | 5 --- src/musikcube/app/window/TrackListView.cpp | 1 + src/musikcube/app/window/TransportWindow.cpp | 1 + 6 files changed, 42 insertions(+), 25 deletions(-) diff --git a/src/musikcore/audio/PlaybackService.cpp b/src/musikcore/audio/PlaybackService.cpp index de29e52d0..0a1d43a20 100755 --- a/src/musikcore/audio/PlaybackService.cpp +++ b/src/musikcore/audio/PlaybackService.cpp @@ -60,6 +60,12 @@ using musik::core::ILibraryPtr; using musik::core::audio::ITransport; using Editor = PlaybackService::Editor; +/* internally PlaybackService leverages a message queue for synchronization; +tracks are a special in that they are heavy-weight so aggressively exjected +from caches... sometimes we may have to query for them. if they take more than +the specified timeout we consider it a failure and stop playback. */ +static const size_t kTrackTimeoutMs = 3000; + #define NO_POSITION (size_t) -1 #define START_OVER (size_t) -2 @@ -332,13 +338,17 @@ void PlaybackService::ProcessMessage(IMessage &message) { } if (this->index != NO_POSITION) { - track = this->playlist.Get(this->index); + track = this->playlist.GetWithTimeout(this->index, kTrackTimeoutMs); } } if (track) { this->OnTrackChanged(this->index, track); } + else { + this->Stop(); + return; + } if (eventType == StreamPlaying) { this->PrepareNextTrack(); @@ -365,10 +375,13 @@ void PlaybackService::ProcessMessage(IMessage &message) { /* notify track change as soon as we're prepared. if we wait until we start playing, it may be a while until the UI knows to redraw! */ if (this->UriAtIndex(this->index) == transport->Uri()) { - auto track = this->playlist.Get(this->index); + auto track = this->playlist.GetWithTimeout(this->index, kTrackTimeoutMs); if (track) { this->OnTrackChanged(this->index, track); } + else { + this->Stop(); + } } } @@ -589,26 +602,18 @@ bool PlaybackService::HotSwap(const TrackList& tracks, size_t index) { bool found = false; auto playingTrack = this->GetPlaying(); if (playingTrack && tracks.Count() > index) { - auto supplantTrack = tracks.Get(index); - auto supplantLibrary = supplantTrack->Library(); auto supplantId = tracks.GetId(index); - - auto playingId = playingTrack->GetId(); - auto playingLibrary = playingTrack->Library(); + const auto playingId = playingTrack->GetId(); /* look at the index hint, see if we can find a matching track without iteration. */ - if (supplantId == playingId && supplantLibrary == playingLibrary) { + if (supplantId == playingId) { found = true; } /* otherwise search the input */ else { for (size_t i = 0; i < tracks.Count(); i++) { - supplantTrack = tracks.Get(i); - auto supplantLibrary = supplantTrack->Library(); - auto supplantId = supplantTrack->GetId(); - - if (supplantId == playingId && supplantLibrary == playingLibrary) { + if (tracks.GetId(i) == playingId) { index = i; found = true; } @@ -828,7 +833,7 @@ double PlaybackService::GetDuration() { size_t index = this->index; if (index < this->playlist.Count()) { - track = this->playlist.Get(index); + track = this->playlist.GetWithTimeout(index, kTrackTimeoutMs); } } @@ -845,7 +850,7 @@ ITrack* PlaybackService::GetTrack(size_t index) { const size_t count = this->playlist.Count(); if (count && index < this->playlist.Count()) { - auto track = this->playlist.Get(index); + auto track = this->playlist.GetWithTimeout(index, kTrackTimeoutMs * 10); if (track) { return track->GetSdkValue(); } @@ -876,7 +881,7 @@ TrackPtr PlaybackService::GetTrackAtIndex(size_t index) { return TrackPtr(); } - return this->playlist.Get(index); + return this->playlist.GetWithTimeout(index, kTrackTimeoutMs); } Editor PlaybackService::Edit() { @@ -1101,7 +1106,7 @@ void PlaybackService::Editor::Release() { std::string PlaybackService::UriAtIndex(size_t index) { if (index < this->playlist.Count()) { - auto track = this->playlist.Get(index); + auto track = this->playlist.GetWithTimeout(index, kTrackTimeoutMs); if (track) { return this->library->GetResourceLocator().GetTrackUri(track.get()); } @@ -1128,7 +1133,7 @@ ITransport::Gain PlaybackService::GainAtIndex(size_t index) { Mode mode = (Mode)playbackPrefs->GetInt(keys::ReplayGainMode.c_str(), (int) Mode::Disabled); if (mode != Mode::Disabled && index < this->playlist.Count()) { - auto track = this->playlist.Get(index); + auto track = this->playlist.GetWithTimeout(index, kTrackTimeoutMs); if (track) { auto rg = track->GetReplayGain(); float gain = (mode == Mode::Album) ? rg.albumGain : rg.trackGain; diff --git a/src/musikcore/library/track/TrackList.cpp b/src/musikcore/library/track/TrackList.cpp index 387d5add6..306fc0c82 100755 --- a/src/musikcore/library/track/TrackList.cpp +++ b/src/musikcore/library/track/TrackList.cpp @@ -172,6 +172,22 @@ TrackPtr TrackList::Get(size_t index, bool async) const { #endif } +TrackPtr TrackList::GetWithTimeout(size_t index, size_t timeoutMs) const { + auto id = this->ids.at(index); + auto cached = this->GetFromCache(id); + if (cached) { return cached; } + + auto target = std::make_shared(id, this->library); + auto query = std::make_shared(target, this->library); + this->library->EnqueueAndWait(query, timeoutMs); + if (query->GetStatus() == IQuery::Finished) { + this->AddToCache(id, query->Result()); + return query->Result(); + } + + return TrackPtr(); +} + ITrack* TrackList::GetTrack(size_t index) const { return this->Get(index)->GetSdkValue(); } diff --git a/src/musikcore/library/track/TrackList.h b/src/musikcore/library/track/TrackList.h index 62aed46ed..d8cec5010 100755 --- a/src/musikcore/library/track/TrackList.h +++ b/src/musikcore/library/track/TrackList.h @@ -79,8 +79,7 @@ namespace musik { namespace core { /* implementation specific */ TrackPtr Get(size_t index, bool async = false) const; - TrackPtr GetSync(size_t index) const { return this->Get(index, false); } - TrackPtr GetAsync(size_t index) const { return this->Get(index, true); } + TrackPtr GetWithTimeout(size_t index, size_t timeoutMs) const; void ClearCache(); void Swap(TrackList& list); void CopyFrom(const TrackList& from); diff --git a/src/musikcube/app/layout/MainLayout.cpp b/src/musikcube/app/layout/MainLayout.cpp index e2f13a923..9c1ec3a17 100755 --- a/src/musikcube/app/layout/MainLayout.cpp +++ b/src/musikcube/app/layout/MainLayout.cpp @@ -292,16 +292,11 @@ void MainLayout::SwitchToLibraryLayout() { void MainLayout::OnLibraryConnectionStateChanged(ILibrary::ConnectionState state) { auto currentLayout = this->GetLayout(); - if (currentLayout == this->libraryLayout || currentLayout == this->libraryNotConnectedLayout) { this->SwitchToLibraryLayout(); } - - if (state == ILibrary::ConnectionState::Disconnected) { - this->playback.Stop(); - } } void MainLayout::OnLibraryChanged(musik::core::ILibraryPtr prev, musik::core::ILibraryPtr curr) { diff --git a/src/musikcube/app/window/TrackListView.cpp b/src/musikcube/app/window/TrackListView.cpp index c23bfb424..bff05442e 100755 --- a/src/musikcube/app/window/TrackListView.cpp +++ b/src/musikcube/app/window/TrackListView.cpp @@ -93,6 +93,7 @@ TrackListView::TrackListView( this->decorator = decorator; this->trackNumType = TrackRowRenderers::TrackNumType::Metadata; this->renderer = TrackRowRenderers::Get(TrackRowRenderers::Type::AlbumSort); + this->playing = playback.GetPlaying(); } TrackListView::~TrackListView() { diff --git a/src/musikcube/app/window/TransportWindow.cpp b/src/musikcube/app/window/TransportWindow.cpp index 6f4713c1b..91c2168a1 100755 --- a/src/musikcube/app/window/TransportWindow.cpp +++ b/src/musikcube/app/window/TransportWindow.cpp @@ -373,6 +373,7 @@ TransportWindow::TransportWindow( this->repeatPos.y = 1; this->volumePos.y = 1; this->timePos.y = 1; + this->currentTrack = playback.GetPlaying(); this->UpdateReplayGainState(); }