aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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();