diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Instance.hxx | 4 | ||||
-rw-r--r-- | src/Partition.cxx | 7 | ||||
-rw-r--r-- | src/Partition.hxx | 4 | ||||
-rw-r--r-- | src/PlayerControl.cxx | 22 | ||||
-rw-r--r-- | src/PlayerControl.hxx | 43 | ||||
-rw-r--r-- | src/PlayerThread.cxx | 10 | ||||
-rw-r--r-- | src/Playlist.cxx | 9 | ||||
-rw-r--r-- | src/Playlist.hxx | 7 |
8 files changed, 95 insertions, 11 deletions
diff --git a/src/Instance.hxx b/src/Instance.hxx index 896656b10..a0dfd1b94 100644 --- a/src/Instance.hxx +++ b/src/Instance.hxx @@ -40,8 +40,8 @@ struct Instance { void DatabaseModified(); /** - * A tag in the play queue has been modified. Propagate the - * change to all subsystems. + * A tag in the play queue has been modified by the player + * thread. Propagate the change to all subsystems. */ void TagModified(); diff --git a/src/Partition.cxx b/src/Partition.cxx index e2bbe19d8..3619ff7f0 100644 --- a/src/Partition.cxx +++ b/src/Partition.cxx @@ -19,11 +19,16 @@ #include "config.h" #include "Partition.hxx" +#include "Song.hxx" void Partition::TagModified() { - playlist.TagChanged(); + Song *song = pc.LockReadTaggedSong(); + if (song != nullptr) { + playlist.TagModified(std::move(*song)); + song->Free(); + } } void diff --git a/src/Partition.hxx b/src/Partition.hxx index 23c5745ec..1d326b147 100644 --- a/src/Partition.hxx +++ b/src/Partition.hxx @@ -167,8 +167,8 @@ struct Partition { } /** - * A tag in the play queue has been modified. Propagate the - * change to all subsystems. + * A tag in the play queue has been modified by the player + * thread. Propagate the change to all subsystems. */ void TagModified(); diff --git a/src/PlayerControl.cxx b/src/PlayerControl.cxx index 96a221f6d..9ba77b32c 100644 --- a/src/PlayerControl.cxx +++ b/src/PlayerControl.cxx @@ -53,6 +53,9 @@ player_control::~player_control() { if (next_song != nullptr) next_song->Free(); + + if (tagged_song != nullptr) + tagged_song->Free(); } void @@ -201,6 +204,25 @@ player_control::ClearError() } void +player_control::LockSetTaggedSong(const Song &song) +{ + Lock(); + if (tagged_song != nullptr) + tagged_song->Free(); + tagged_song = song.DupDetached(); + Unlock(); +} + +void +player_control::ClearTaggedSong() +{ + if (tagged_song != nullptr) { + tagged_song->Free(); + tagged_song = nullptr; + } +} + +void player_control::EnqueueSong(Song *song) { assert(song != nullptr); diff --git a/src/PlayerControl.hxx b/src/PlayerControl.hxx index b2b2087e2..bdfc10fec 100644 --- a/src/PlayerControl.hxx +++ b/src/PlayerControl.hxx @@ -100,7 +100,7 @@ struct player_control { Thread thread; /** - * This lock protects #command, #state, #error. + * This lock protects #command, #state, #error, #tagged_song. */ mutable Mutex mutex; @@ -129,6 +129,18 @@ struct player_control { */ Error error; + /** + * A copy of the current #Song after its tags have been + * updated by the decoder (for example, a radio stream that + * has sent a new tag after switching to the next song). This + * shall be used by the GlobalEvents::TAG handler to update + * the current #Song in the queue. + * + * Protected by #mutex. Set by the PlayerThread and consumed + * by the main thread. + */ + Song *tagged_song; + uint16_t bit_rate; AudioFormat audio_format; float total_time; @@ -356,6 +368,35 @@ public: return error_type; } + /** + * Set the #tagged_song attribute to a newly allocated copy of + * the given #Song. Locks and unlocks the object. + */ + void LockSetTaggedSong(const Song &song); + + void ClearTaggedSong(); + + /** + * Read and clear the #tagged_song attribute. + * + * Caller must lock the object. + */ + Song *ReadTaggedSong() { + Song *result = tagged_song; + tagged_song = nullptr; + return result; + } + + /** + * Like ReadTaggedSong(), but locks and unlocks the object. + */ + Song *LockReadTaggedSong() { + Lock(); + Song *result = ReadTaggedSong(); + Unlock(); + return result; + } + void Stop(); void UpdateAudio(); diff --git a/src/PlayerThread.cxx b/src/PlayerThread.cxx index 4f5b15bba..35f697c45 100644 --- a/src/PlayerThread.cxx +++ b/src/PlayerThread.cxx @@ -335,6 +335,8 @@ Player::WaitForDecoder() return false; } + pc.ClearTaggedSong(); + if (song != nullptr) song->Free(); @@ -684,7 +686,7 @@ Player::ProcessCommand() } static void -update_song_tag(Song *song, const Tag &new_tag) +update_song_tag(player_control &pc, Song *song, const Tag &new_tag) { if (song->IsFile()) /* don't update tags of local files, only remote @@ -696,6 +698,8 @@ update_song_tag(Song *song, const Tag &new_tag) delete old_tag; + pc.LockSetTaggedSong(*song); + /* the main thread will update the playlist version when he receives this event */ GlobalEvents::Emit(GlobalEvents::TAG); @@ -722,7 +726,7 @@ play_chunk(player_control &pc, assert(chunk->CheckFormat(format)); if (chunk->tag != nullptr) - update_song_tag(song, *chunk->tag); + update_song_tag(pc, song, *chunk->tag); if (chunk->IsEmpty()) { buffer.Return(chunk); @@ -1077,6 +1081,8 @@ Player::Run() pc.Lock(); + pc.ClearTaggedSong(); + if (queued) { assert(pc.next_song != nullptr); pc.next_song->Free(); diff --git a/src/Playlist.cxx b/src/Playlist.cxx index 570d64b19..296b52769 100644 --- a/src/Playlist.cxx +++ b/src/Playlist.cxx @@ -22,6 +22,7 @@ #include "PlaylistError.hxx" #include "PlayerControl.hxx" #include "Song.hxx" +#include "tag/Tag.hxx" #include "Idle.hxx" #include "Log.hxx" @@ -35,13 +36,17 @@ playlist::FullIncrementVersions() } void -playlist::TagChanged() +playlist::TagModified(Song &&song) { - if (!playing) + if (!playing || song.tag == nullptr) return; assert(current >= 0); + Song ¤t_song = queue.GetOrder(current); + if (SongEquals(song, current_song)) + current_song.ReplaceTag(std::move(*song.tag)); + queue.ModifyAtOrder(current); idle_add(IDLE_PLAYLIST); } diff --git a/src/Playlist.hxx b/src/Playlist.hxx index 866fd9a2d..88ea099c5 100644 --- a/src/Playlist.hxx +++ b/src/Playlist.hxx @@ -128,7 +128,12 @@ protected: public: void Clear(player_control &pc); - void TagChanged(); + /** + * A tag in the play queue has been modified by the player + * thread. Apply the given song's tag to the current song if + * the song matches. + */ + void TagModified(Song &&song); void FullIncrementVersions(); |