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)
* protocol
- new command "getvol"
- show the audio format in "playlistinfo"
* output
- snapcast: new plugin

View File

@ -111,6 +111,9 @@ song_print_info(Response &r, const DetachedSong &song, bool base) noexcept
if (!IsNegative(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());
const auto duration = song.GetDuration();

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -28,7 +28,8 @@ DetachedSong::DetachedSong(const LightSong &other) noexcept
tag(other.tag),
mtime(other.mtime),
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
{

View File

@ -21,6 +21,7 @@
#define MPD_DETACHED_SONG_HXX
#include "tag/Tag.hxx"
#include "pcm/AudioFormat.hxx"
#include "Chrono.hxx"
#include "util/Compiler.h"
@ -79,6 +80,12 @@ class DetachedSong {
*/
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:
explicit DetachedSong(const char *_uri) noexcept
:uri(_uri) {}
@ -231,6 +238,14 @@ public:
gcc_pure
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.
*