diff options
author | Max Kellermann <max@duempel.org> | 2013-10-21 23:22:16 +0200 |
---|---|---|
committer | Max Kellermann <max@duempel.org> | 2013-10-22 00:02:21 +0200 |
commit | 2f43e4bc668f04a222500ab34536ef00149e209f (patch) | |
tree | 260593ec865b3f13b8cb11f86a86d23bb10ad2ad | |
parent | f8c23488c942a89df74b231307281cf1919fab61 (diff) | |
download | mpd-2f43e4bc668f04a222500ab34536ef00149e209f.tar.gz mpd-2f43e4bc668f04a222500ab34536ef00149e209f.tar.xz mpd-2f43e4bc668f04a222500ab34536ef00149e209f.zip |
Playlist: copy stream tags from the PlayerThread
Finally restores an important feature that has been broken for several
months when the PlayerThread started working with Song copies instead
of pointers to the Queue's Song instances (commit e96779d).
-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(); |