song/DetachedSong: copy the AudioFormat from LightSong

Enables the "Format" row in "playlistinfo" responses.

https://github.com/MusicPlayerDaemon/MPD/issues/1094
This commit is contained in:
Max Kellermann 2021-02-18 21:59:47 +01:00
parent 81d0c04ed4
commit c729f16dcd
10 changed files with 40 additions and 18 deletions

1
NEWS
View File

@ -1,6 +1,7 @@
ver 0.23 (not yet released) ver 0.23 (not yet released)
* protocol * protocol
- new command "getvol" - new command "getvol"
- show the audio format in "playlistinfo"
* output * output
- snapcast: new plugin - snapcast: new plugin

View File

@ -111,6 +111,9 @@ song_print_info(Response &r, const DetachedSong &song, bool base) noexcept
if (!IsNegative(song.GetLastModified())) if (!IsNegative(song.GetLastModified()))
time_print(r, "Last-Modified", song.GetLastModified()); time_print(r, "Last-Modified", song.GetLastModified());
if (const auto &f = song.GetAudioFormat(); f.IsDefined())
r.Format("Format: %s\n", ToString(f).c_str());
tag_print_values(r, song.GetTag()); tag_print_values(r, song.GetTag());
const auto duration = song.GetDuration(); const auto duration = song.GetDuration();

View File

@ -86,8 +86,7 @@ song_save(BufferedOutputStream &os, const DetachedSong &song)
DetachedSong DetachedSong
song_load(TextFile &file, const char *uri, song_load(TextFile &file, const char *uri,
std::string *target_r, std::string *target_r)
AudioFormat *audio_format_r)
{ {
DetachedSong song(uri); DetachedSong song(uri);
@ -113,13 +112,11 @@ song_load(TextFile &file, const char *uri,
if (target_r != nullptr) if (target_r != nullptr)
*target_r = value; *target_r = value;
} else if (StringIsEqual(line, "Format")) { } else if (StringIsEqual(line, "Format")) {
if (audio_format_r != nullptr) { try {
try { song.SetAudioFormat(ParseAudioFormat(value,
*audio_format_r = false));
ParseAudioFormat(value, false); } catch (...) {
} catch (...) { /* ignore parser errors */
/* ignore parser errors */
}
} }
} else if (StringIsEqual(line, "Playlist")) { } else if (StringIsEqual(line, "Playlist")) {
tag.SetHasPlaylist(StringIsEqual(value, "yes")); tag.SetHasPlaylist(StringIsEqual(value, "yes"));

View File

@ -44,7 +44,6 @@ song_save(BufferedOutputStream &os, const DetachedSong &song);
*/ */
DetachedSong DetachedSong
song_load(TextFile &file, const char *uri, song_load(TextFile &file, const char *uri,
std::string *target_r=nullptr, std::string *target_r=nullptr);
AudioFormat *audio_format_r=nullptr);
#endif #endif

View File

@ -153,9 +153,10 @@ DetachedSong::LoadFile(Path path)
return false; return false;
TagBuilder tag_builder; TagBuilder tag_builder;
auto new_audio_format = AudioFormat::Undefined();
try { try {
if (!ScanFileTagsWithGeneric(path, tag_builder)) if (!ScanFileTagsWithGeneric(path, tag_builder, &new_audio_format))
return false; return false;
} catch (...) { } catch (...) {
// TODO: log or propagate I/O errors? // TODO: log or propagate I/O errors?
@ -163,6 +164,7 @@ DetachedSong::LoadFile(Path path)
} }
mtime = fi.GetModificationTime(); mtime = fi.GetModificationTime();
audio_format = new_audio_format;
tag_builder.Commit(tag); tag_builder.Commit(tag);
return true; return true;
} }
@ -177,9 +179,11 @@ DetachedSong::Update()
return LoadFile(path_fs); return LoadFile(path_fs);
} else if (IsRemote()) { } else if (IsRemote()) {
TagBuilder tag_builder; TagBuilder tag_builder;
auto new_audio_format = AudioFormat::Undefined();
try { try {
if (!tag_stream_scan(uri.c_str(), tag_builder)) if (!tag_stream_scan(uri.c_str(), tag_builder,
&new_audio_format))
return false; return false;
} catch (...) { } catch (...) {
// TODO: log or propagate I/O errors? // TODO: log or propagate I/O errors?
@ -187,6 +191,7 @@ DetachedSong::Update()
} }
mtime = std::chrono::system_clock::time_point::min(); mtime = std::chrono::system_clock::time_point::min();
audio_format = new_audio_format;
tag_builder.Commit(tag); tag_builder.Commit(tag);
return true; return true;
} else } else

View File

@ -168,15 +168,12 @@ directory_load(TextFile &file, Directory &directory)
throw FormatRuntimeError("Duplicate song '%s'", name); throw FormatRuntimeError("Duplicate song '%s'", name);
std::string target; std::string target;
auto audio_format = AudioFormat::Undefined();
auto detached_song = song_load(file, name, auto detached_song = song_load(file, name,
&target, &target);
&audio_format);
auto song = std::make_unique<Song>(std::move(detached_song), auto song = std::make_unique<Song>(std::move(detached_song),
directory); directory);
song->target = std::move(target); song->target = std::move(target);
song->audio_format = audio_format;
directory.AddSong(std::move(song)); directory.AddSong(std::move(song));
} else if ((p = StringAfterPrefix(line, PLAYLIST_META_BEGIN))) { } else if ((p = StringAfterPrefix(line, PLAYLIST_META_BEGIN))) {

View File

@ -34,6 +34,7 @@ Song::Song(DetachedSong &&other, Directory &_parent) noexcept
mtime(other.GetLastModified()), mtime(other.GetLastModified()),
start_time(other.GetStartTime()), start_time(other.GetStartTime()),
end_time(other.GetEndTime()), end_time(other.GetEndTime()),
audio_format(other.GetAudioFormat()),
filename(other.GetURI()) filename(other.GetURI())
{ {
} }

View File

@ -47,6 +47,9 @@ merge_song_metadata(DetachedSong &add, const DetachedSong &base) noexcept
if (add.GetEndTime().IsZero()) { if (add.GetEndTime().IsZero()) {
add.SetEndTime(base.GetEndTime()); add.SetEndTime(base.GetEndTime());
} }
if (!add.GetAudioFormat().IsDefined())
add.SetAudioFormat(base.GetAudioFormat());
} }
static bool static bool

View File

@ -28,7 +28,8 @@ DetachedSong::DetachedSong(const LightSong &other) noexcept
tag(other.tag), tag(other.tag),
mtime(other.mtime), mtime(other.mtime),
start_time(other.start_time), start_time(other.start_time),
end_time(other.end_time) {} end_time(other.end_time),
audio_format(other.audio_format) {}
DetachedSong::operator LightSong() const noexcept DetachedSong::operator LightSong() const noexcept
{ {

View File

@ -21,6 +21,7 @@
#define MPD_DETACHED_SONG_HXX #define MPD_DETACHED_SONG_HXX
#include "tag/Tag.hxx" #include "tag/Tag.hxx"
#include "pcm/AudioFormat.hxx"
#include "Chrono.hxx" #include "Chrono.hxx"
#include "util/Compiler.h" #include "util/Compiler.h"
@ -79,6 +80,12 @@ class DetachedSong {
*/ */
SongTime end_time = SongTime::zero(); SongTime end_time = SongTime::zero();
/**
* The audio format of the song, if given by the decoder
* plugin. May be undefined if unknown.
*/
AudioFormat audio_format = AudioFormat::Undefined();
public: public:
explicit DetachedSong(const char *_uri) noexcept explicit DetachedSong(const char *_uri) noexcept
:uri(_uri) {} :uri(_uri) {}
@ -231,6 +238,14 @@ public:
gcc_pure gcc_pure
SignedSongTime GetDuration() const noexcept; SignedSongTime GetDuration() const noexcept;
const AudioFormat &GetAudioFormat() const noexcept {
return audio_format;
}
void SetAudioFormat(const AudioFormat &src) noexcept {
audio_format = src;
}
/** /**
* Update the #tag and #mtime. * Update the #tag and #mtime.
* *