aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMax Kellermann <max@duempel.org>2013-10-21 23:22:16 +0200
committerMax Kellermann <max@duempel.org>2013-10-22 00:02:21 +0200
commit2f43e4bc668f04a222500ab34536ef00149e209f (patch)
tree260593ec865b3f13b8cb11f86a86d23bb10ad2ad
parentf8c23488c942a89df74b231307281cf1919fab61 (diff)
downloadmpd-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.hxx4
-rw-r--r--src/Partition.cxx7
-rw-r--r--src/Partition.hxx4
-rw-r--r--src/PlayerControl.cxx22
-rw-r--r--src/PlayerControl.hxx43
-rw-r--r--src/PlayerThread.cxx10
-rw-r--r--src/Playlist.cxx9
-rw-r--r--src/Playlist.hxx7
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 &current_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();