diff --git a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/AudioConfig.cxx b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/AudioConfig.cxx index d54f59e..25b9b2f 100644 --- a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/AudioConfig.cxx +++ b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/AudioConfig.cxx @@ -29,11 +29,102 @@ static AudioFormat configured_audio_format; +#ifdef USE_EXTEND_AUDIO_FORMAT +#include "util/Domain.hxx" +#include "Log.hxx" +#include +#include + +static constexpr Domain audio_config("audio_config"); + +struct SampleRateSpec { + bool enable; + bool dsdenable; + uint32_t oversamples; + uint32_t limit; +}; + +static SampleRateSpec configured_sampleratespec = { false, false,0, 0 }; + +#define BASE_FREQ(f) (((f) % 44100) == 0 ? 44100 : 48000) +#define ISPOWEROF2(f) ((f) != 0) && (((f) & ((f) - 1)) == 0) + +static uint32_t oversampled_freq(uint32_t input_freq) { + if ( !configured_sampleratespec.enable ) { + return configured_audio_format.sample_rate; + } + + uint32_t osample = input_freq * configured_sampleratespec.oversamples; + uint32_t lsample = BASE_FREQ(input_freq) * configured_sampleratespec.limit; + + FormatDebug(audio_config,"input_freq %d oversamples %d limit %d osample %d lsample %d", + input_freq, configured_sampleratespec.oversamples,configured_sampleratespec.limit,osample,lsample); + + return (osample <= lsample) ? osample : lsample; +} + +static char* getnumparam(char *ptr,uint32_t *num) { + char *endptr; + + long l = strtol(ptr,&endptr,10); + *num = l; + return endptr; +} + + +static char* extend_format_parse(char *confstr) { + + configured_sampleratespec.enable = false; + if ( (*confstr != 'X') && (*confstr != 'x') ) { + return confstr; + } + + configured_sampleratespec.dsdenable = (*confstr == 'x') ? true : false; + + confstr++; + + uint32_t num; + confstr = getnumparam(confstr,&num); + if ( !ISPOWEROF2(num) ) { + return NULL; + } + configured_sampleratespec.oversamples = num; + + if ( *confstr != 'L' ) { + return NULL; + } + confstr++; + + confstr = getnumparam(confstr,&num); + if ( !ISPOWEROF2(num) ) { + return NULL; + } + configured_sampleratespec.limit = num; + confstr--; + *confstr = '*'; + + configured_sampleratespec.enable = 1; + return confstr; +} +#endif + AudioFormat getOutputAudioFormat(AudioFormat inAudioFormat) { AudioFormat out_audio_format = inAudioFormat; +#ifdef USE_EXTEND_AUDIO_FORMAT + if ((out_audio_format.format != SampleFormat::DSD) || configured_sampleratespec.dsdenable) { + AudioFormat extend_audio_format = configured_audio_format; + extend_audio_format.sample_rate = oversampled_freq(out_audio_format.sample_rate); + + FormatDebug(audio_config,"oversampled_freq %d intput freq %d", + extend_audio_format.sample_rate,out_audio_format.sample_rate); + + out_audio_format.ApplyMask(extend_audio_format); + } +#else out_audio_format.ApplyMask(configured_audio_format); +#endif return out_audio_format; } @@ -45,8 +136,25 @@ void initAudioConfig(void) return; Error error; +#ifdef USE_EXTEND_AUDIO_FORMAT + FormatDebug(audio_config,"extend parse start"); + FormatDebug(audio_config,"value.c_str %s",param->value.c_str()); + FormatDebug(audio_config,"value.c_str length %ld",strlen(param->value.c_str())); + char *confstr = (char *)alloca(strlen(param->value.c_str()) + 1); + strcpy(confstr,param->value.c_str()); + confstr = extend_format_parse(confstr); + if ( confstr == NULL ) { + FormatFatalError("error parsing line %i: %s",param->line,"Extend sample rate error"); + } + FormatDebug(audio_config,"extend_format_parse ret '%s'",confstr); + if (!audio_format_parse(configured_audio_format, confstr, +#else if (!audio_format_parse(configured_audio_format, param->value.c_str(), +#endif true, error)) FormatFatalError("error parsing line %i: %s", param->line, error.GetMessage()); +#ifdef USE_EXTEND_AUDIO_FORMAT + FormatDebug(audio_config,"oversampled_freq %d",configured_audio_format.sample_rate); +#endif } diff --git a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/AudioFormat.cxx b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/AudioFormat.cxx index edfb9d8..deeb0b9 100644 --- a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/AudioFormat.cxx +++ b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/AudioFormat.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -48,6 +48,7 @@ sample_format_to_string(SampleFormat format) return "?"; case SampleFormat::S8: + case SampleFormat::DSD_U8: return "8"; case SampleFormat::S16: @@ -57,6 +58,8 @@ sample_format_to_string(SampleFormat format) return "24"; case SampleFormat::S32: + case SampleFormat::DSD_U32_BE: + case SampleFormat::DSD_U32_LE: return "32"; case SampleFormat::FLOAT: diff --git a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/AudioFormat.hxx b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/AudioFormat.hxx index 0937ab8..ea93b2f 100644 --- a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/AudioFormat.hxx +++ b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/AudioFormat.hxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -56,6 +56,24 @@ enum class SampleFormat : uint8_t { * byte (8 samples) per channel. */ DSD, + + /** + * DSD native output, 1 bit samples. Each frame carries 1 byte + * per channel + */ + DSD_U8, + + /** + * DSD native output, 1 bit samples. Each frames carries 4 DSD + * 1 byte samples, Big Endian + */ + DSD_U32_BE, + + /* + * DSD native output, 1 bit samples. Each frame carries 4 DSD + * 1 byte samples, Little Endian + */ + DSD_U32_LE, }; #if defined(WIN32) && GCC_CHECK_VERSION(4,6) @@ -198,6 +216,9 @@ audio_valid_sample_format(SampleFormat format) case SampleFormat::S32: case SampleFormat::FLOAT: case SampleFormat::DSD: + case SampleFormat::DSD_U8: + case SampleFormat::DSD_U32_BE: + case SampleFormat::DSD_U32_LE: return true; case SampleFormat::UNDEFINED: @@ -256,9 +277,12 @@ sample_format_size(SampleFormat format) case SampleFormat::S24_P32: case SampleFormat::S32: case SampleFormat::FLOAT: + case SampleFormat::DSD_U32_BE: + case SampleFormat::DSD_U32_LE: return 4; case SampleFormat::DSD: + case SampleFormat::DSD_U8: /* each frame has 8 samples per channel */ return 1; diff --git a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/IOThread.cxx b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/IOThread.cxx index e21ede4..aa662df 100644 --- a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/IOThread.cxx +++ b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/IOThread.cxx @@ -27,6 +27,10 @@ #include "system/FatalError.hxx" #include "util/Error.hxx" +#ifdef ENABLE_RTOPT +#include "rt_opt.hxx" +#endif + #include static struct { @@ -51,6 +55,10 @@ io_thread_func(gcc_unused void *arg) { SetThreadName("io"); +#ifdef ENABLE_RTOPT + rtopt_change_priority(RTOPT_IO_PRIORITY_NAME); +#endif + /* lock+unlock to synchronize with io_thread_start(), to be sure that io.thread is set */ io.mutex.lock(); diff --git a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/Main.cxx b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/Main.cxx index d646573..9013b6e 100644 --- a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/Main.cxx +++ b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/Main.cxx @@ -63,7 +63,9 @@ #include "config/ConfigOption.hxx" #include "config/ConfigError.hxx" #include "Stats.hxx" - +#ifdef ENABLE_RTOPT +#include "rt_opt.hxx" +#endif #ifdef ENABLE_DATABASE #include "db/update/Service.hxx" #include "db/Configured.hxx" @@ -509,6 +511,11 @@ int mpd_main(int argc, char *argv[]) return EXIT_FAILURE; } +#ifdef ENABLE_RTOPT + rtopt_init(); + rtopt_change_priority(RTOPT_MAIN_PRIORITY_NAME); +#endif + #ifndef ANDROID daemonize_set_user(); daemonize_begin(options.daemon); @@ -565,6 +572,9 @@ static int mpd_main_after_fork(struct options options) #ifdef ENABLE_DATABASE const bool create_db = InitDatabaseAndStorage(); #endif +#ifdef ENABLE_RTOPT + rtopt_memlock(); +#endif glue_sticker_init(); diff --git a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/PlayerThread.cxx b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/PlayerThread.cxx index 69bd088..8e74538 100644 --- a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/PlayerThread.cxx +++ b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/PlayerThread.cxx @@ -37,6 +37,10 @@ #include "thread/Name.hxx" #include "Log.hxx" +#ifdef ENABLE_RTOPT +#include "rt_opt.hxx" +#endif + #include static constexpr Domain player_domain("player"); @@ -1121,6 +1125,10 @@ player_task(void *arg) SetThreadName("player"); +#ifdef ENABLE_RTOPT + rtopt_change_priority(RTOPT_PLAYER_PRIORITY_NAME); +#endif + DecoderControl dc(pc.mutex, pc.cond); decoder_thread_start(dc); diff --git a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/SongUpdate.cxx b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/SongUpdate.cxx index 0245b91..1210e7d 100644 --- a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/SongUpdate.cxx +++ b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/SongUpdate.cxx @@ -122,9 +122,13 @@ Song::UpdateFileInArchive(const Storage &storage) if (suffix == nullptr) return false; +#ifdef HAVE_DECODER_SELECTOR + if (!decoder_scan_plugins_supports_suffix(suffix)) + return false; +#else if (!decoder_plugins_supports_suffix(suffix)) return false; - +#endif const auto path_fs = parent->IsRoot() ? storage.MapFS(uri) : storage.MapChildFS(parent->GetPath(), uri); @@ -138,7 +142,6 @@ Song::UpdateFileInArchive(const Storage &storage) tag_builder.Commit(tag); return true; } - #endif bool diff --git a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/TagFile.cxx b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/TagFile.cxx index 7655b96..8f6f0fd 100644 --- a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/TagFile.cxx +++ b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/TagFile.cxx @@ -92,6 +92,12 @@ tag_file_scan(Path path_fs, const tag_handler &handler, void *handler_ctx) return false; TagFileScan tfs(path_fs, suffix, handler, handler_ctx); +#ifdef HAVE_DECODER_SELECTOR + const DecoderPlugin *plugin_ptr = decoder_scan_plugin_selector(suffix); + if ( (plugin_ptr != nullptr) && tfs.Scan(*plugin_ptr) ) { + return true; + } +#endif return decoder_plugins_try([&](const DecoderPlugin &plugin){ return tfs.Scan(plugin); }); diff --git a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/TagStream.cxx b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/TagStream.cxx index 6201028..e7ede9c 100644 --- a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/TagStream.cxx +++ b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/TagStream.cxx @@ -52,7 +52,21 @@ tag_stream_scan(InputStream &is, const tag_handler &handler, void *ctx) if (suffix == nullptr && mime == nullptr) return false; +#ifdef HAVE_DECODER_SELECTOR + is.LockRewind(IgnoreError()); + const DecoderPlugin *plugin_ptr = decoder_scan_plugin_selector(suffix); + if ( (plugin_ptr != nullptr) && + CheckDecoderPlugin(*plugin_ptr, suffix, mime) && + plugin_ptr->ScanStream(is, handler, ctx) ) { + return true; + } + return decoder_plugins_try([suffix, mime, &is, + &handler, ctx](const DecoderPlugin &plugin){ + return CheckDecoderPlugin(plugin, suffix, mime) && + plugin.ScanStream(is, handler, ctx); + }); +#else return decoder_plugins_try([suffix, mime, &is, &handler, ctx](const DecoderPlugin &plugin){ is.LockRewind(IgnoreError()); @@ -60,6 +74,7 @@ tag_stream_scan(InputStream &is, const tag_handler &handler, void *ctx) return CheckDecoderPlugin(plugin, suffix, mime) && plugin.ScanStream(is, handler, ctx); }); +#endif } bool diff --git a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/config/ConfigOption.hxx b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/config/ConfigOption.hxx index 8eb4c7e..e7e9a9e 100644 --- a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/config/ConfigOption.hxx +++ b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/config/ConfigOption.hxx @@ -20,6 +20,7 @@ #ifndef MPD_CONFIG_OPTION_HXX #define MPD_CONFIG_OPTION_HXX +#include #include "Compiler.h" enum ConfigOption { @@ -69,6 +70,9 @@ enum ConfigOption { CONF_SAVE_ABSOLUTE_PATHS, CONF_DECODER, CONF_INPUT, +#ifdef HAVE_DECODER_SELECTOR + CONF_DECODER_SELECTOR, +#endif CONF_GAPLESS_MP3_PLAYBACK, CONF_PLAYLIST_PLUGIN, CONF_AUTO_UPDATE, @@ -78,6 +82,9 @@ enum ConfigOption { CONF_DESPOTIFY_HIGH_BITRATE, CONF_AUDIO_FILTER, CONF_DATABASE, +#ifdef ENABLE_RTOPT + CONF_RTOPT, +#endif CONF_NEIGHBORS, CONF_MAX }; diff --git a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/config/ConfigTemplates.cxx b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/config/ConfigTemplates.cxx index 58ee564..fa20ec7 100644 --- a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/config/ConfigTemplates.cxx +++ b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/config/ConfigTemplates.cxx @@ -20,6 +20,7 @@ #include "ConfigTemplates.hxx" #include "ConfigOption.hxx" +#include #include const ConfigTemplate config_templates[] = { @@ -69,6 +70,9 @@ const ConfigTemplate config_templates[] = { { "save_absolute_paths_in_playlists", false, false }, { "decoder", true, true }, { "input", true, true }, +#ifdef HAVE_DECODER_SELECTOR + { "decoder_selector", true, true }, +#endif { "gapless_mp3_playback", false, false }, { "playlist_plugin", true, true }, { "auto_update", false, false }, @@ -78,6 +82,9 @@ const ConfigTemplate config_templates[] = { { "despotify_high_bitrate", false, false }, { "filter", true, true }, { "database", false, true }, +#ifdef ENABLE_RTOPT + { "realtime_option", false, true }, +#endif { "neighbors", true, true }, }; diff --git a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/db/update/Container.cxx b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/db/update/Container.cxx index 1c420fa..357fc11 100644 --- a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/db/update/Container.cxx +++ b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/db/update/Container.cxx @@ -62,8 +62,14 @@ UpdateWalk::MakeDirectoryIfModified(Directory &parent, const char *name, static bool SupportsContainerSuffix(const DecoderPlugin &plugin, const char *suffix) { +#ifdef HAVE_DECODER_SELECTOR + return plugin.container_scan != nullptr && + plugin.SupportsSuffix(suffix) && + &plugin == decoder_scan_plugin_selector(suffix); +#else return plugin.container_scan != nullptr && plugin.SupportsSuffix(suffix); +#endif } bool diff --git a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/db/update/Service.cxx b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/db/update/Service.cxx index e8a1f6b..3ab34d3 100644 --- a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/db/update/Service.cxx +++ b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/db/update/Service.cxx @@ -34,6 +34,9 @@ #include "thread/Id.hxx" #include "thread/Thread.hxx" #include "thread/Util.hxx" +#ifdef ENABLE_RTOPT +#include "rt_opt.hxx" +#endif #ifndef NDEBUG #include "event/Loop.hxx" @@ -121,7 +124,11 @@ UpdateService::Task() else LogDebug(update_domain, "starting"); +#ifdef ENABLE_RTOPT + rtopt_change_priority(RTOPT_UPDATE_PRIORITY_NAME); +#else SetThreadIdlePriority(); +#endif modified = walk->Walk(next.db->GetRoot(), next.path_utf8.c_str(), next.discard); diff --git a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/db/update/UpdateSong.cxx b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/db/update/UpdateSong.cxx index 005bf89..6ca743f 100644 --- a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/db/update/UpdateSong.cxx +++ b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/db/update/UpdateSong.cxx @@ -95,8 +95,13 @@ UpdateWalk::UpdateSongFile(Directory &directory, const char *name, const char *suffix, const FileInfo &info) { +#ifdef HAVE_DECODER_SELECTOR + if (!decoder_scan_plugins_supports_suffix(suffix)) + return false; +#else if (!decoder_plugins_supports_suffix(suffix)) return false; +#endif UpdateSongFile2(directory, name, suffix, info); return true; diff --git a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/decoder/DecoderList.cxx b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/decoder/DecoderList.cxx index cd6881c..126677e 100644 --- a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/decoder/DecoderList.cxx +++ b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/decoder/DecoderList.cxx @@ -47,6 +47,15 @@ #include +#ifdef HAVE_DECODER_SELECTOR +#include "config/ConfigOption.hxx" +#include "system/FatalError.hxx" +#include "Log.hxx" +#include "util/Domain.hxx" + +static constexpr Domain decoderlist_domain("DecoderList"); +#endif + const struct DecoderPlugin *const decoder_plugins[] = { #ifdef HAVE_MAD &mad_decoder_plugin, @@ -119,6 +128,140 @@ static constexpr unsigned num_decoder_plugins = /** which plugins have been initialized successfully? */ bool decoder_plugins_enabled[num_decoder_plugins]; +#ifdef HAVE_DECODER_SELECTOR +struct decoder_selector_table { + const char *attr; + const struct DecoderPlugin *plugin; + const struct DecoderPlugin *scan_plugin; +}; + +static unsigned ds_count = 0; +static struct decoder_selector_table *ds_table = nullptr; + +static unsigned +decoder_selector_config_count(void) +{ + unsigned int nr = 0; + const struct config_param *param = config_get_param(CONF_DECODER_SELECTOR); + + while (param != nullptr) { + nr++; + param = param->next; + } + return nr; +} + +static unsigned int decoder_selector_entry(const struct config_param *param, + const struct DecoderPlugin *plugin, + const struct DecoderPlugin *scan_plugin, + const char *attrname, + unsigned int index) +{ + const char *attr = param->GetBlockValue(attrname); + if (attr == nullptr) { + return index; + } + + if ((plugin == nullptr) && (scan_plugin == nullptr)) { + return index; + } + + const struct DecoderPlugin *p = nullptr; + const struct DecoderPlugin *sp = nullptr; + + if ( strcmp("suffix",attrname) == 0 ) { + if ( plugin != nullptr ) { + p = plugin->SupportsSuffix(attr) ? plugin : nullptr; + } else { + p = nullptr; + } + if ( scan_plugin != nullptr ) { + sp = scan_plugin->SupportsSuffix(attr) ? scan_plugin : nullptr; + } else { + sp = nullptr; + } + if ( (p != nullptr) && (sp == nullptr) ) { + sp = p; + } + } else if ( strcmp("mimetype",attrname) == 0 ) { + if ( plugin != nullptr ) { + p = plugin->SupportsMimeType(attr) ? plugin : nullptr; + } else { + p = nullptr; + } + sp = nullptr; + } + + if ((p != nullptr) || (sp != nullptr)) { + ds_table[index].attr = attr; + ds_table[index].plugin = p; + ds_table[index].scan_plugin = sp; + index++; + } + return index; +} + +const struct DecoderPlugin *decoder_plugin_selector(const char *attr) +{ + if ( attr != nullptr ) { + for ( unsigned int i = 0; i < ds_count; i++ ) { + if ( strcmp(ds_table[i].attr,attr) == 0 ) { + return ds_table[i].plugin; + } + } + } + return nullptr; +} + +const struct DecoderPlugin *decoder_scan_plugin_selector(const char *attr) +{ + if ( attr != nullptr ) { + for ( unsigned int i = 0; i < ds_count; i++ ) { + if ( strcmp(ds_table[i].attr,attr) == 0 ) { + return ds_table[i].scan_plugin; + } + } + } + return nullptr; +} + +static void dump_ds_table(void) +{ + for ( unsigned int i = 0; i < ds_count; i++ ) { + FormatDebug(decoderlist_domain, + "attr: %-20s plugin: %-20s scan_plugin: %s ",ds_table[i].attr, + ds_table[i].plugin? ds_table[i].plugin->name : "", + ds_table[i].scan_plugin? ds_table[i].scan_plugin->name : ""); + } +} + +static void decoder_selector_init(void) +{ + ds_count = decoder_selector_config_count(); + if (ds_count == 0) { + return; + } + + ds_table = (struct decoder_selector_table *)malloc(sizeof(struct decoder_selector_table) * ds_count * 2); + + unsigned int i = 0; + const struct config_param *param = config_get_param(CONF_DECODER_SELECTOR); + + // while ((param = config_get_next_param(CONF_DECODER_SELECTOR, param))) { + while ( param != nullptr ) { + const char *plugin_name = param->GetBlockValue("plugin"); + const struct DecoderPlugin *plugin = (plugin_name != nullptr) ? decoder_plugin_from_name(plugin_name) : nullptr; + const char *scan_plugin_name = param->GetBlockValue("scan_plugin"); + const struct DecoderPlugin *scan_plugin = (scan_plugin_name != nullptr) ? decoder_plugin_from_name(scan_plugin_name) :nullptr; + i = decoder_selector_entry(param,plugin,scan_plugin,"suffix",i); + i = decoder_selector_entry(param,plugin,scan_plugin,"mimetype",i); + param = param->next; + } + ds_count = i; + dump_ds_table(); +} +#endif + const struct DecoderPlugin * decoder_plugin_from_name(const char *name) { @@ -145,6 +288,9 @@ void decoder_plugin_init_all(void) if (plugin.Init(*param)) decoder_plugins_enabled[i] = true; } +#ifdef HAVE_DECODER_SELECTOR + decoder_selector_init(); +#endif } void decoder_plugin_deinit_all(void) @@ -157,7 +303,27 @@ void decoder_plugin_deinit_all(void) bool decoder_plugins_supports_suffix(const char *suffix) { +#ifdef HAVE_DECODER_SELECTOR + const DecoderPlugin *plugin_ptr = decoder_plugin_selector(suffix); + if ( (plugin_ptr != nullptr) && plugin_ptr->SupportsSuffix(suffix) ) { + return true; + } +#endif return decoder_plugins_try([suffix](const DecoderPlugin &plugin){ return plugin.SupportsSuffix(suffix); }); } + +#ifdef HAVE_DECODER_SELECTOR +bool +decoder_scan_plugins_supports_suffix(const char *suffix) +{ + const DecoderPlugin *plugin_ptr = decoder_scan_plugin_selector(suffix); + if ( (plugin_ptr != nullptr) && plugin_ptr->SupportsSuffix(suffix) ) { + return true; + } + return decoder_plugins_try([suffix](const DecoderPlugin &plugin){ + return plugin.SupportsSuffix(suffix); + }); +} +#endif diff --git a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/decoder/DecoderList.hxx b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/decoder/DecoderList.hxx index 47085d4..d29097e 100644 --- a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/decoder/DecoderList.hxx +++ b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/decoder/DecoderList.hxx @@ -86,4 +86,12 @@ gcc_pure gcc_nonnull_all bool decoder_plugins_supports_suffix(const char *suffix); +#ifdef HAVE_DECODER_SELECTOR +gcc_pure gcc_nonnull_all +bool +decoder_scan_plugins_supports_suffix(const char *suffix); + +const struct DecoderPlugin *decoder_plugin_selector(const char *attr); +const struct DecoderPlugin *decoder_scan_plugin_selector(const char *attr); +#endif #endif diff --git a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/decoder/DecoderThread.cxx b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/decoder/DecoderThread.cxx index 2e407e6..d3dca47 100644 --- a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/decoder/DecoderThread.cxx +++ b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/decoder/DecoderThread.cxx @@ -39,6 +39,10 @@ #include "tag/ApeReplayGain.hxx" #include "Log.hxx" +#ifdef ENABLE_RTOPT +#include "rt_opt.hxx" +#endif + #include static constexpr Domain decoder_thread_domain("decoder_thread"); @@ -245,6 +249,12 @@ decoder_run_stream_locked(Decoder &decoder, InputStream &is, const auto f = std::bind(decoder_run_stream_plugin, std::ref(decoder), std::ref(is), suffix, _1, std::ref(tried_r)); +#ifdef HAVE_DECODER_SELECTOR + const DecoderPlugin *plugin = decoder_plugin_selector(suffix); + if ( (plugin != nullptr) && f(*plugin) ) { + return true; + } +#endif return decoder_plugins_try(f); } @@ -368,6 +378,12 @@ decoder_run_file(Decoder &decoder, const char *uri_utf8, Path path_fs) decoder_load_replay_gain(decoder, path_fs); +#ifdef HAVE_DECODER_SELECTOR + const DecoderPlugin *plugin_ptr = decoder_plugin_selector(suffix); + if ( (plugin_ptr != nullptr) && TryDecoderFile(decoder,path_fs,suffix,*plugin_ptr) ) { + return true; + } +#endif if (decoder_plugins_try([&decoder, path_fs, suffix](const DecoderPlugin &plugin){ return TryDecoderFile(decoder, @@ -462,6 +478,9 @@ static void decoder_task(void *arg) { DecoderControl &dc = *(DecoderControl *)arg; +#ifdef ENABLE_RTOPT + rtopt_change_priority(RTOPT_DECODER_PRIORITY_NAME); +#endif SetThreadName("decoder"); diff --git a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/decoder/plugins/AudiofileDecoderPlugin.cxx b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/decoder/plugins/AudiofileDecoderPlugin.cxx index a0ef71e..6bade64 100644 --- a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/decoder/plugins/AudiofileDecoderPlugin.cxx +++ b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/decoder/plugins/AudiofileDecoderPlugin.cxx @@ -274,12 +274,24 @@ audiofile_scan_stream(InputStream &is, } static const char *const audiofile_suffixes[] = { +#ifdef HAVE_DECODER_SELECTOR + "wav", "au", "aiff", "aif", "m4a", "mp4", "flac", nullptr +#else "wav", "au", "aiff", "aif", nullptr +#endif }; static const char *const audiofile_mime_types[] = { "audio/x-wav", "audio/x-aiff", +#ifdef HAVE_DECODER_SELECTOR + "audio/mp4", + "audio/m4a", + "application/flac", + "application/x-flac", + "audio/flac", + "audio/x-flac", +#endif nullptr }; diff --git a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/decoder/plugins/FlacPcm.cxx b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/decoder/plugins/FlacPcm.cxx index 311500f..2353781 100644 --- a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/decoder/plugins/FlacPcm.cxx +++ b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/decoder/plugins/FlacPcm.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -104,6 +104,9 @@ flac_convert(void *dest, case SampleFormat::FLOAT: case SampleFormat::DSD: case SampleFormat::UNDEFINED: + case SampleFormat::DSD_U8: + case SampleFormat::DSD_U32_BE: + case SampleFormat::DSD_U32_LE: assert(false); gcc_unreachable(); } diff --git a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/output/OutputThread.cxx b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/output/OutputThread.cxx index 2ec0670..206edac 100644 --- a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/output/OutputThread.cxx +++ b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/output/OutputThread.cxx @@ -38,6 +38,9 @@ #include "util/ConstBuffer.hxx" #include "Log.hxx" #include "Compiler.h" +#ifdef ENABLE_RTOPT +#include "rt_opt.hxx" +#endif #include #include @@ -587,8 +590,13 @@ AudioOutput::Task() { FormatThreadName("output:%s", name); +#ifdef ENABLE_RTOPT + rtopt_change_output_priority(name); + rtopt_change_output_timerslack(name); +#else SetThreadRealtime(); SetThreadTimerSlackUS(100); +#endif mutex.lock(); diff --git a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/output/plugins/AlsaOutputPlugin.cxx b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/output/plugins/AlsaOutputPlugin.cxx index 14eaeeb..eb007c5 100644 --- a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/output/plugins/AlsaOutputPlugin.cxx +++ b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/output/plugins/AlsaOutputPlugin.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -68,6 +68,17 @@ struct AlsaOutput { */ bool dop; + /** + * Enable native DSD playback (requires ALSA driver support) + */ + bool dsd_native; + + /** + * dsd_native_type + * 0 = regular, uses DSD_U8, 1 = reserved, 2 uses DSD_U32_BE, 3 uses DSD_U32_LE + */ + unsigned int dsd_native_type; + /** libasound's buffer_time setting (in microseconds) */ unsigned int buffer_time; @@ -156,6 +167,28 @@ AlsaOutput::Configure(const config_param ¶m, Error &error) /* legacy name from MPD 0.18 and older: */ param.GetBlockValue("dsd_usb", false); + dsd_native = param.GetBlockValue("dsd_native", false); + + + /* If native DSD is enabled check for requested output type */ + if (dsd_native) { + dsd_native_type = param.GetBlockValue("dsd_native_type", 255); + switch(dsd_native_type) { + case 0: + case 2: + case 3: + break; + case 1: + dsd_native = false; + default: + dsd_native = false; + } + } + + /* If both dop and dsd_native are enabled, fall back to dop */ + if (dop && dsd_native) + dsd_native = false; + buffer_time = param.GetBlockValue("buffer_time", MPD_ALSA_BUFFER_TIME_US); period_time = param.GetBlockValue("period_time", 0u); @@ -270,6 +303,15 @@ get_bitformat(SampleFormat sample_format) case SampleFormat::FLOAT: return SND_PCM_FORMAT_FLOAT; + + case SampleFormat::DSD_U8: + return SND_PCM_FORMAT_DSD_U8; + + case SampleFormat::DSD_U32_BE: + return SND_PCM_FORMAT_DSD_U32_BE; + + case SampleFormat::DSD_U32_LE: + return SND_PCM_FORMAT_DSD_U32_LE; } assert(false); @@ -643,9 +685,32 @@ alsa_setup_dop(AlsaOutput *ad, const AudioFormat audio_format, assert(ad->dop); assert(audio_format.format == SampleFormat::DSD); + AudioFormat dop_format = audio_format; + + /* DSD native type 0 -> DSD_U8 */ + if (ad->dsd_native && ad->dsd_native_type == 0) { + + dop_format.format = SampleFormat::DSD_U8; + if (!alsa_setup(ad, dop_format, packed_r, + reverse_endian_r, error)) + return false; + return true; + } + + /* DSD native type 2 -> DSD_U32_BE , 3 -> DSD_U32_LE */ + if (ad->dsd_native && ((ad->dsd_native_type == 2) || (ad->dsd_native_type == 3))) { + + dop_format.format = ad->dsd_native_type == 2 ? SampleFormat::DSD_U32_BE : SampleFormat::DSD_U32_LE; + dop_format.sample_rate /= 4; + if (!alsa_setup(ad, dop_format, packed_r, + reverse_endian_r, error)) + return false; + return true; + } + + /* pass 24 bit to alsa_setup() */ - AudioFormat dop_format = audio_format; dop_format.format = SampleFormat::S24_P32; dop_format.sample_rate /= 2; @@ -684,7 +749,13 @@ alsa_setup_or_dop(AlsaOutput *ad, AudioFormat &audio_format, const bool dop = ad->dop && audio_format.format == SampleFormat::DSD; - const bool success = dop + + const bool dsd_native = ad->dsd_native && + audio_format.format == SampleFormat::DSD; + + const bool dsd_enabled = dop || dsd_native; + + const bool success = dsd_enabled ? alsa_setup_dop(ad, audio_format, &shift8, &packed, &reverse_endian, error) @@ -695,7 +766,8 @@ alsa_setup_or_dop(AlsaOutput *ad, AudioFormat &audio_format, ad->pcm_export->Open(audio_format.format, audio_format.channels, - dop, shift8, packed, reverse_endian); + dop, shift8, packed, reverse_endian, + dsd_native, ad->dsd_native_type); return true; } diff --git a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/output/plugins/OssOutputPlugin.cxx b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/output/plugins/OssOutputPlugin.cxx index 39d87fc..52b2637 100644 --- a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/output/plugins/OssOutputPlugin.cxx +++ b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/output/plugins/OssOutputPlugin.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -419,6 +419,9 @@ sample_format_to_oss(SampleFormat format) case SampleFormat::UNDEFINED: case SampleFormat::FLOAT: case SampleFormat::DSD: + case SampleFormat::DSD_U8: + case SampleFormat::DSD_U32_BE: + case SampleFormat::DSD_U32_LE: return AFMT_QUERY; case SampleFormat::S8: diff --git a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/pcm/ChannelsConverter.cxx b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/pcm/ChannelsConverter.cxx index 7146137..099ad7d 100644 --- a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/pcm/ChannelsConverter.cxx +++ b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/pcm/ChannelsConverter.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -68,6 +68,9 @@ PcmChannelsConverter::Convert(ConstBuffer src, gcc_unused Error &error) case SampleFormat::UNDEFINED: case SampleFormat::S8: case SampleFormat::DSD: + case SampleFormat::DSD_U8: + case SampleFormat::DSD_U32_BE: + case SampleFormat::DSD_U32_LE: assert(false); gcc_unreachable(); diff --git a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/pcm/FallbackResampler.cxx b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/pcm/FallbackResampler.cxx index bd3f20d..b575a87 100644 --- a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/pcm/FallbackResampler.cxx +++ b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/pcm/FallbackResampler.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -31,6 +31,9 @@ FallbackPcmResampler::Open(AudioFormat &af, unsigned new_sample_rate, switch (af.format) { case SampleFormat::UNDEFINED: + case SampleFormat::DSD_U8: + case SampleFormat::DSD_U32_BE: + case SampleFormat::DSD_U32_LE: assert(false); gcc_unreachable(); @@ -122,6 +125,9 @@ FallbackPcmResampler::Resample(ConstBuffer src, gcc_unused Error &error) case SampleFormat::UNDEFINED: case SampleFormat::S8: case SampleFormat::DSD: + case SampleFormat::DSD_U8: + case SampleFormat::DSD_U32_BE: + case SampleFormat::DSD_U32_LE: assert(false); gcc_unreachable(); diff --git a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/pcm/FormatConverter.cxx b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/pcm/FormatConverter.cxx index 8874e1b..510aeea 100644 --- a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/pcm/FormatConverter.cxx +++ b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/pcm/FormatConverter.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -40,6 +40,9 @@ PcmFormatConverter::Open(SampleFormat _src_format, SampleFormat _dest_format, case SampleFormat::S8: case SampleFormat::DSD: + case SampleFormat::DSD_U8: + case SampleFormat::DSD_U32_BE: + case SampleFormat::DSD_U32_LE: error.Format(pcm_domain, "PCM conversion from %s to %s is not implemented", sample_format_to_string(_src_format), @@ -74,6 +77,9 @@ PcmFormatConverter::Convert(ConstBuffer src, gcc_unused Error &error) case SampleFormat::UNDEFINED: case SampleFormat::S8: case SampleFormat::DSD: + case SampleFormat::DSD_U8: + case SampleFormat::DSD_U32_BE: + case SampleFormat::DSD_U32_LE: assert(false); gcc_unreachable(); diff --git a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/pcm/PcmDsd.cxx b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/pcm/PcmDsd.cxx index 53d26d4..9a20a00 100644 --- a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/pcm/PcmDsd.cxx +++ b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/pcm/PcmDsd.cxx @@ -68,11 +68,14 @@ PcmDsd::ToFloat(unsigned channels, ConstBuffer src) if (dsd2pcm[c] == nullptr) return nullptr; } - - dsd2pcm_translate(dsd2pcm[c], num_frames, - src.data + c, channels, - false, dest + c, channels); } +#ifdef _OPENMP + for (unsigned i = 0; i < channels; ++i) { + dsd2pcm_translate(dsd2pcm[i], num_frames, + src.data + i, channels, + false, dest + i, channels); + } +#endif return { dest, num_samples }; } diff --git a/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/pcm/PcmDsdNative.cxx b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/pcm/PcmDsdNative.cxx new file mode 100644 index 0000000..4a034c7 --- /dev/null +++ b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/pcm/PcmDsdNative.cxx @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2014-2015 Jurgen Kramer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" +#include "PcmDsdNative.hxx" +#include "PcmBuffer.hxx" +#include "AudioFormat.hxx" +#include "util/ConstBuffer.hxx" + +/* JK For debug info */ +#include "util/Domain.hxx" +#include "Log.hxx" + +static constexpr Domain dsdn_dom("dsd_native"); + +constexpr +static inline uint32_t +pcm_two_dsd_native(uint8_t a, uint8_t b, uint8_t c, uint8_t d) +{ + return 0x00000000 | (a << 24 ) | (b << 16) | (c << 8) | d; +} + +ConstBuffer +pcm_dsd_native(PcmBuffer &buffer, unsigned channels, + ConstBuffer _src,unsigned dsd_native_type) +{ + assert(audio_valid_channel_count(channels)); + assert(!_src.isNull()); + assert(_src_size > 0); + assert(_src_size % channels == 0); + + const unsigned num_src_samples = _src.size; + const unsigned num_src_frames = num_src_samples / channels; + + const unsigned num_frames = num_src_frames / sizeof(uint32_t); + unsigned num_samples = num_frames * channels; + + uint32_t *const dest0 = (uint32_t *)buffer.GetT(num_samples), + *dest = dest0; + + auto src = _src.data; + + for (unsigned i = num_frames ; i > 0 ; --i) { + for (unsigned c = 0; c < channels; c++) { + if ( dsd_native_type == 2 ) { + *dest++ = pcm_two_dsd_native(src[channels * 3 + c], + src[channels * 2 + c], + src[channels * 1 + c], + src[channels * 0 + c]); + } else { + *dest++ = pcm_two_dsd_native(src[channels * 0 + c], + src[channels * 1 + c], + src[channels * 2 + c], + src[channels * 3 + c]); + } + } + src += (sizeof(uint32_t) * channels); + } + + return { dest0, num_samples }; +} diff --git a/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/pcm/PcmDsdNative.hxx b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/pcm/PcmDsdNative.hxx new file mode 100644 index 0000000..9340da8 --- /dev/null +++ b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/pcm/PcmDsdNative.hxx @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2014-2015 Jurgen Kramer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_PCM_DSD_NATIVE_HXX +#define MPD_PCM_DSD_NATIVE_HXX + +#include "check.h" + +#include +#include + +class PcmBuffer; +template struct ConstBuffer; + +/** + * Pack DSD 1 bit samples into DSD_U32_LE samples for + * native DSD playback + */ +ConstBuffer +pcm_dsd_native(PcmBuffer &buffer, unsigned channels, + ConstBuffer src,unsigned dsd_native_type); + +#endif diff --git a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/pcm/PcmExport.cxx b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/pcm/PcmExport.cxx index ef099ba..23fba66 100644 --- a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/pcm/PcmExport.cxx +++ b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/pcm/PcmExport.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -20,6 +20,7 @@ #include "config.h" #include "PcmExport.hxx" #include "PcmDop.hxx" +#include "PcmDsdNative.hxx" #include "PcmPack.hxx" #include "util/ByteReverse.hxx" #include "util/ConstBuffer.hxx" @@ -28,18 +29,26 @@ void PcmExport::Open(SampleFormat sample_format, unsigned _channels, - bool _dop, bool _shift8, bool _pack, bool _reverse_endian) + bool _dop, bool _shift8, bool _pack, bool _reverse_endian, + bool _dsd_native, unsigned _dsd_native_type) { assert(audio_valid_sample_format(sample_format)); assert(!_dop || audio_valid_channel_count(_channels)); channels = _channels; dop = _dop && sample_format == SampleFormat::DSD; + + dsd_native = _dsd_native; + dsd_native_type = _dsd_native_type; + if (dop) /* after the conversion to DoP, the DSD samples are stuffed inside fake 24 bit samples */ sample_format = SampleFormat::S24_P32; + if (dsd_native && ((dsd_native_type == 2) || (dsd_native_type == 3))) + sample_format = SampleFormat::S32; + shift8 = _shift8 && sample_format == SampleFormat::S24_P32; pack24 = _pack && sample_format == SampleFormat::S24_P32; @@ -71,6 +80,9 @@ PcmExport::GetFrameSize(const AudioFormat &audio_format) const bytes per sample) */ return channels * 4; + if (dsd_native && ((dsd_native_type == 2) || (dsd_native_type == 3))) + return channels * 4; + return audio_format.GetFrameSize(); } @@ -82,6 +94,11 @@ PcmExport::Export(ConstBuffer data) ConstBuffer::FromVoid(data)) .ToVoid(); + if (dsd_native && ((dsd_native_type == 2) || (dsd_native_type == 3))) + data = pcm_dsd_native(dop_buffer, channels, + ConstBuffer::FromVoid(data), dsd_native_type) + .ToVoid(); + if (pack24) { const auto src = ConstBuffer::FromVoid(data); const size_t num_samples = src.size; diff --git a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/pcm/PcmExport.hxx b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/pcm/PcmExport.hxx index b99a358..6048505 100644 --- a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/pcm/PcmExport.hxx +++ b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/pcm/PcmExport.hxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -67,6 +67,22 @@ struct PcmExport { */ bool dop; + /** + * Output native DSD? + * dsd_native_type contains requested output type + */ + + bool dsd_native; + + /** + * DSD native output type + * 0 = DSD_U8, no export needed + * 1 = DSD_U16_BE, reserved. Not supported yet + * 2 = DSD_U32_BE, e.g. XMOS based USB DACs + */ + + unsigned dsd_native_type; + /** * Convert (padded) 24 bit samples to 32 bit by shifting 8 * bits to the left? @@ -96,7 +112,8 @@ struct PcmExport { * @param channels the number of channels; ignored unless dop is set */ void Open(SampleFormat sample_format, unsigned channels, - bool dop, bool shift8, bool pack, bool reverse_endian); + bool dop, bool shift8, bool pack, bool reverse_endian, + bool dsd_native, unsigned dsd_native_type); /** * Calculate the size of one output frame. diff --git a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/pcm/PcmFormat.cxx b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/pcm/PcmFormat.cxx index 4cabc05..5d5bdf9 100644 --- a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/pcm/PcmFormat.cxx +++ b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/pcm/PcmFormat.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -166,6 +166,9 @@ pcm_convert_to_16(PcmBuffer &buffer, PcmDither &dither, switch (src_format) { case SampleFormat::UNDEFINED: case SampleFormat::DSD: + case SampleFormat::DSD_U8: + case SampleFormat::DSD_U32_BE: + case SampleFormat::DSD_U32_LE: break; case SampleFormat::S8: @@ -234,6 +237,9 @@ pcm_convert_to_24(PcmBuffer &buffer, switch (src_format) { case SampleFormat::UNDEFINED: case SampleFormat::DSD: + case SampleFormat::DSD_U8: + case SampleFormat::DSD_U32_BE: + case SampleFormat::DSD_U32_LE: break; case SampleFormat::S8: @@ -302,6 +308,9 @@ pcm_convert_to_32(PcmBuffer &buffer, switch (src_format) { case SampleFormat::UNDEFINED: case SampleFormat::DSD: + case SampleFormat::DSD_U8: + case SampleFormat::DSD_U32_BE: + case SampleFormat::DSD_U32_LE: break; case SampleFormat::S8: @@ -370,6 +379,9 @@ pcm_convert_to_float(PcmBuffer &buffer, switch (src_format) { case SampleFormat::UNDEFINED: case SampleFormat::DSD: + case SampleFormat::DSD_U8: + case SampleFormat::DSD_U32_BE: + case SampleFormat::DSD_U32_LE: break; case SampleFormat::S8: diff --git a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/pcm/PcmMix.cxx b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/pcm/PcmMix.cxx index d21b5f0..c59f9fd 100644 --- a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/pcm/PcmMix.cxx +++ b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/pcm/PcmMix.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -93,6 +93,9 @@ pcm_add_vol(PcmDither &dither, void *buffer1, const void *buffer2, size_t size, switch (format) { case SampleFormat::UNDEFINED: case SampleFormat::DSD: + case SampleFormat::DSD_U8: + case SampleFormat::DSD_U32_BE: + case SampleFormat::DSD_U32_LE: /* not implemented */ return false; @@ -181,6 +184,9 @@ pcm_add(void *buffer1, const void *buffer2, size_t size, switch (format) { case SampleFormat::UNDEFINED: case SampleFormat::DSD: + case SampleFormat::DSD_U8: + case SampleFormat::DSD_U32_BE: + case SampleFormat::DSD_U32_LE: /* not implemented */ return false; diff --git a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/pcm/SoxrResampler.cxx b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/pcm/SoxrResampler.cxx index b9d6fc0..f1019aa 100644 --- a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/pcm/SoxrResampler.cxx +++ b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/pcm/SoxrResampler.cxx @@ -33,10 +33,29 @@ static constexpr Domain soxr_domain("soxr"); static unsigned long soxr_quality_recipe = SOXR_HQ; +#ifdef _OPENMP +static bool use_openmp = false; +#endif static const char * soxr_quality_name(unsigned long recipe) { +#ifdef _OPENMP + if ( use_openmp ) { + switch (recipe) { + case SOXR_VHQ: + return "Very High Quality openmp"; + case SOXR_HQ: + return "High Quality openmp"; + case SOXR_MQ: + return "Medium Quality openmp"; + case SOXR_LQ: + return "Low Quality openmp"; + case SOXR_QQ: + return "Quick openmp"; + } + } +#endif switch (recipe) { case SOXR_VHQ: return "Very High Quality"; @@ -76,6 +95,24 @@ soxr_parse_converter(const char *converter) soxr_quality_recipe = SOXR_LQ; else if (strcmp(quality, "quick") == 0) soxr_quality_recipe = SOXR_QQ; +#ifdef _OPENMP + else if (strcmp(quality, "very high openmp") == 0) { + soxr_quality_recipe = SOXR_VHQ; + use_openmp = true; + } else if (strcmp(quality, "high opnemp") == 0) { + soxr_quality_recipe = SOXR_HQ; + use_openmp = true; + } else if (strcmp(quality, "medium openmp") == 0) { + soxr_quality_recipe = SOXR_MQ; + use_openmp = true; + } else if (strcmp(quality, "low openmp") == 0) { + soxr_quality_recipe = SOXR_LQ; + use_openmp = true; + } else if (strcmp(quality, "quick openmp") == 0) { + soxr_quality_recipe = SOXR_QQ; + use_openmp = true; + } +#endif else return false; @@ -107,9 +144,14 @@ SoxrPcmResampler::Open(AudioFormat &af, unsigned new_sample_rate, soxr_error_t e; soxr_quality_spec_t quality = soxr_quality_spec(soxr_quality_recipe, 0); + soxr_runtime_spec_t *runtime_p = nullptr; +#ifdef _OPENMP + soxr_runtime_spec_t runtime = soxr_runtime_spec(0); + runtime_p = use_openmp ? &runtime : nullptr; +#endif soxr = soxr_create(af.sample_rate, new_sample_rate, af.channels, &e, - nullptr, &quality, nullptr); + nullptr, &quality, runtime_p); if (soxr == nullptr) { error.Format(soxr_domain, "soxr initialization has failed: %s", e); diff --git a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/pcm/Volume.cxx b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/pcm/Volume.cxx index 6d28a9b..9730d42 100644 --- a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/pcm/Volume.cxx +++ b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/pcm/Volume.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -118,6 +118,9 @@ PcmVolume::Open(SampleFormat _format, Error &error) break; case SampleFormat::DSD: + case SampleFormat::DSD_U8: + case SampleFormat::DSD_U32_BE: + case SampleFormat::DSD_U32_LE: // TODO: implement this; currently, it's a no-op break; } @@ -181,6 +184,9 @@ PcmVolume::Apply(ConstBuffer src) break; case SampleFormat::DSD: + case SampleFormat::DSD_U8: + case SampleFormat::DSD_U32_BE: + case SampleFormat::DSD_U32_LE: // TODO: implement this; currently, it's a no-op return src; } diff --git a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/pcm/dsd2pcm/dsd2pcm.c b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/pcm/dsd2pcm/dsd2pcm.c index f089102..7b2d26a 100644 --- a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/pcm/dsd2pcm/dsd2pcm.c +++ b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/pcm/dsd2pcm/dsd2pcm.c @@ -115,7 +115,7 @@ static const double htaps[HTAPS] = { 3.130441005359396e-08 }; -static float ctables[CTABLES][256]; +static double ctables[CTABLES][256]; static int precalculated = 0; static void precalc(void) @@ -131,7 +131,7 @@ static void precalc(void) for (m=0; m> (7-m)) & 1)*2-1) * htaps[t*8+m]; } - ctables[CTABLES-1-t][e] = (float)acc; + ctables[CTABLES-1-t][e] = acc; } } precalculated = 1; diff --git a/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/rt_opt.cxx b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/rt_opt.cxx new file mode 100644 index 0000000..ecb7071 --- /dev/null +++ b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/rt_opt.cxx @@ -0,0 +1,510 @@ +/* + * Copyright (C) 2003-2010 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" +#include "config/ConfigOption.hxx" + +#include "system/FatalError.hxx" +#include "Log.hxx" +#include "util/Domain.hxx" + + +#include "config/ConfigData.hxx" +#include "config/ConfigGlobal.hxx" +#include "config/ConfigOption.hxx" + +#include "thread/Util.hxx" +#include "thread/Slack.hxx" + +#include "rt_opt.hxx" + +#include + +#include +#include +#include +#include + +static constexpr Domain rt_opt_domain("rt_opt"); + +#define IS_ENABLE_RTOPT enable_rtopt +#define IS_ENABLE_MEMLOCK enable_memlock +#define IS_ENABLE_PRIORITY(p) ( (p) != RTOPT_DISABLE ) + +#define AUDIO_OUTPUT_PRIORITY ((const char *)"priority") +#define AUDIO_OUTPUT_NAME ((const char *)"name") +#define AUDIO_OUTPUT_TIMERSLACK ((const char *)"timerslack") +#define DEFAULT_TIMERSLACK ((const unsigned)100) + +#define IS_EQUAL_PRIORITY(p1,p2) (((p1)->policy == (p2)->policy) && \ + ((p1)->priority == (p2)->priority)) + +#define MIN_PRIORITY 1 +#define MAX_PRIORITY 99 + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) + +struct policy_info { + const char* name; + const int policy; +}; + +static struct policy_info policy_tab[] = { + { RTOPT_SCHED_OTHER, SCHED_OTHER }, + { RTOPT_SCHED_FIFO, SCHED_FIFO }, + { RTOPT_SCHED_RR, SCHED_RR }, + { RTOPT_SCHED_BATCH, SCHED_BATCH }, +#ifdef SCHED_IDLE + { RTOPT_SCHED_IDLE, SCHED_IDLE } +#endif +}; + +static const char* priority_keys[] = { + RTOPT_MAIN_PRIORITY_NAME, + RTOPT_IO_PRIORITY_NAME, + RTOPT_PLAYER_PRIORITY_NAME, + RTOPT_DECODER_PRIORITY_NAME, + RTOPT_UPDATE_PRIORITY_NAME +}; + + +static struct rtopt_priority priority_tab[ARRAY_SIZE(priority_keys)]; + +static struct rtopt_priority **output_priority_tab = NULL; +static unsigned output_count = 0; + +static bool enable_rtopt = false; +static bool enable_memlock = false; +static unsigned stack_reserve = RTOPT_DEFAULT_STACK_RESERVE; +static unsigned heap_reserve = RTOPT_DEFAULT_HEAP_RESERVE; + + +static void setUnlimited( const int target, const char *target_name); +static int get_policy(char *name); +static void init_priority_tab(void); +static unsigned audio_output_config_count(void); +static unsigned init_output_priority_tab(void); +static int strtointeger(char *str, int *ival); +static void parse_priority(const char *paramstr, struct rtopt_priority *priority); +static void set_parameter(void); +static const struct rtopt_priority *get_priority_param(const char *key); +static const struct rtopt_priority *get_output_priority_param(const char *key); +static void reset_limit(void); +static int get_current_priority(struct rtopt_priority *priority); +static int change_priority(const struct rtopt_priority *priority); + + +static void +setUnlimited( const int target, const char *target_name) { + const struct rlimit unlimited = { + RLIM_INFINITY, + RLIM_INFINITY + }; + const int res = setrlimit(target,&unlimited); + if ( res < 0 ) { + FormatFatalError("setrlimit %s error %d(%s)\n",target_name,errno,strerror(errno)); + } +} + +static int +get_policy(char *name) { + for (unsigned i = 0; i < ARRAY_SIZE(policy_tab); i++ ) { + if (strcmp(name,policy_tab[i].name) == 0) { + return policy_tab[i].policy; + } + } + return RTOPT_DISABLE; +} + +static void +init_priority_tab(void) { + for (unsigned i = 0; i < ARRAY_SIZE(priority_tab); i++) { + priority_tab[i].name = priority_keys[i]; + priority_tab[i].policy = RTOPT_DISABLE; + priority_tab[i].priority = 0; +/* + priority_tab[i].policy = SCHED_OTHER; + priority_tab[i].priority = 0; +*/ + } +} + +/* from output_all.c */ +static unsigned +audio_output_config_count(void) +{ + unsigned int nr = 0; + const struct config_param *param = config_get_param(CONF_AUDIO_OUTPUT); + + while (param != nullptr) { + nr++; + param = param->next; + } + + +// if (!nr) +// nr = 1; /* we'll always have at least one device */ + return nr; +} + +static unsigned +init_output_priority_tab(void) { + const char *p = NULL; + const char *name = NULL; + struct rtopt_priority *pri = NULL; + + unsigned cnt = audio_output_config_count(); + if ( cnt == 0 ) { + return 0; + } + + output_priority_tab = (struct rtopt_priority **)malloc(sizeof(struct rtopt_priority *) * cnt); + for ( unsigned i = 0; i < cnt; i++ ) { + output_priority_tab[i] = NULL; + } + + unsigned idx = 0; + const struct config_param *param = config_get_param(CONF_AUDIO_OUTPUT); + for ( unsigned i = 0; i < cnt; i++) { + assert(param); + + name = param->GetBlockValue(AUDIO_OUTPUT_NAME); + if ( name != NULL ) { + pri = (struct rtopt_priority *)malloc(sizeof( struct rtopt_priority )); + pri->name = name; + p = param->GetBlockValue(AUDIO_OUTPUT_PRIORITY); + + parse_priority(p, pri); + pri->timerslack = param->GetBlockValue(AUDIO_OUTPUT_TIMERSLACK,DEFAULT_TIMERSLACK); + FormatDebug(rt_opt_domain, + "realtime_option(init_output_priority_tab): output priority name %s policy %d priority %d timerslack %lu\n", + pri->name,pri->policy,pri->priority,pri->timerslack); + output_priority_tab[idx++] = pri; + } else { + FormatWarning(rt_opt_domain, + "realtime_option(init_output_priority_tab): Missing \"name\" configuration\n"); + } + param = param->next; + } + return idx; +} + + +static int +strtointeger(char *str, int *ival) { + char *endptr = NULL; + + *ival = strtol(str, &endptr, 10); + return (*endptr == '\0') ? 0 : -1; +} + +static void +parse_priority(const char *paramstr, struct rtopt_priority *priority) { + char *policyname = NULL; + char *pstr = NULL; + int priority_val; + int policy_val; + + priority->policy = RTOPT_DISABLE; + priority->priority = 0; + + if ( paramstr == NULL ) { + return; + } + priority->policy = SCHED_OTHER; + + policyname = (char *)alloca(strlen(paramstr) + 1); + strcpy(policyname,paramstr); + pstr = strchr(policyname,':'); + + if ( pstr != NULL ) { + *pstr++ = '\0'; + } + + if ( strcmp(policyname,RTOPT_SCHED_OTHER) == 0 ) { + return; + } else if ( (policy_val = get_policy(policyname)) < 0 ) { + FormatWarning(rt_opt_domain, + "realtime_option(parse_priority): illegal policy name = '%s' priority = '%s'\n", + priority->name,paramstr); + return; + } + + if ( pstr == NULL ) { + FormatWarning(rt_opt_domain, + "realtime_option(parse_priority): undefined priority name = '%s' priority = '%s'\n", + priority->name,paramstr); + return; + } + if ( strtointeger(pstr, &priority_val) != 0 ) { + FormatWarning(rt_opt_domain, + "realtime_option(parse_priority): priority isn't number name = '%s' priority = '%s'\n", + priority->name,paramstr); + return; + } + + if ( (priority_val < MIN_PRIORITY) || + (priority_val > MAX_PRIORITY) ) { + FormatWarning(rt_opt_domain, + "realtime_option(parse_priority): illegal priority name = '%s' priority = '%s'\n", + priority->name,paramstr); + return; + } + + priority->policy = policy_val; + priority->priority = priority_val; +} + + +static void +set_parameter(void) { + const struct config_param *param = NULL; + struct rtopt_priority *pri = NULL; + const char *pstr; + + init_priority_tab(); + + enable_rtopt = false; + param = config_get_param(CONF_RTOPT); + if ( param == NULL ) { + return; + } + enable_rtopt = true; + + enable_memlock = param->GetBlockValue(RTOPT_MEMLOCK_NAME,false); + + stack_reserve = param->GetBlockValue(RTOPT_STACKRESERVE_NAME,RTOPT_DEFAULT_STACK_RESERVE) * 1024; + + heap_reserve = param->GetBlockValue(RTOPT_HEAPRESERVE_NAME,RTOPT_DEFAULT_HEAP_RESERVE) * 1024; + + if ( enable_memlock ) { + FormatDebug(rt_opt_domain, + "realtime_option(set_parameter): memlock enable stack_reserve : %d heap_reserve : %d\n", + stack_reserve,heap_reserve); + } + + for (unsigned i = 0; i < ARRAY_SIZE(priority_tab); i++ ) { + pri = priority_tab + i; + pstr = param->GetBlockValue(pri->name); + parse_priority(pstr, pri); + FormatDebug(rt_opt_domain, + "realtime_option(set_parameter): %s policy %d priority %d\n", + pri->name,pri->policy,pri->priority); + } + output_count = init_output_priority_tab(); +} + +static const struct rtopt_priority +*get_priority_param(const char *key) { + for (unsigned i = 0; i < ARRAY_SIZE(priority_keys); i++) { + if ( strcmp(key,priority_keys[i]) == 0 ) { + return priority_tab + i; + } + } + return NULL; +} + +static const struct rtopt_priority +*get_output_priority_param(const char *key) { + for ( unsigned i = 0; i < output_count; i++ ) { + if ( output_priority_tab[i] == NULL ) { + return NULL; + } + if ( strcmp(key,output_priority_tab[i]->name) == 0 ) { + return output_priority_tab[i]; + } + } + return NULL; +} + +static void +reset_limit() { + setUnlimited(RLIMIT_MEMLOCK,"memlock"); + setUnlimited(RLIMIT_RTPRIO, "rtprio"); +} + +static int get_current_priority(struct rtopt_priority *priority) { + struct sched_param param; + int res; + + res = sched_getparam(0,¶m); + if ( res < 0 ) { + FormatWarning(rt_opt_domain, + "realtime_option(get_current_priority): sched_getparm error errno = %s(%d)\n", + strerror(errno),errno); + return -1; + } + + res = sched_getscheduler(0); + if ( res < 0 ) { + FormatWarning(rt_opt_domain, + "realtime_option(get_current_priority): sched_getscheduler error errno = %s(%d)\n", + strerror(errno),errno); + return -1; + } + priority->policy = res; + priority->priority = param.sched_priority; + return 0; +} + +static int change_priority(const struct rtopt_priority *priority) { + struct sched_param param = { priority->priority }; + + int res = sched_setscheduler(0,priority->policy,¶m); + if ( res < 0 ) { + FormatWarning(rt_opt_domain, + "realtime_option(change_priority): sched_setscheduler error errno = %s(%d)\n", + strerror(errno),errno); + } + FormatDebug(rt_opt_domain, + "realtime_option(change_priority): name %s policy %d priority %d\n", + priority->name,priority->policy,param.sched_priority); + return res; +} + +static unsigned long get_output_timerslack(const char *name) { + const struct rtopt_priority *param = get_output_priority_param(name); + if ( param == NULL ) { + FormatDebug(rt_opt_domain, + "realtime_option(rtopt_get_output_timerslack): name not found name = '%s'\n",name); + return DEFAULT_TIMERSLACK; + } + FormatDebug(rt_opt_domain, + "realtime_option(rtopt_get_output_timerslack): name %s policy %d timerslack %lu\n", + param->name,param->policy,param->timerslack); + return param->timerslack; +} + + +void rtopt_init() { + set_parameter(); + if ( !IS_ENABLE_RTOPT ) { + return; + } + reset_limit(); +} + + +void rtopt_memlock() { + void *ptr = NULL; + + if ( !IS_ENABLE_RTOPT ) { + FormatDebug(rt_opt_domain, + "realtime_option(rtopt_memlock): realtime_option disabled\n"); + return; + } + + if ( stack_reserve != (size_t)0 ) { + FormatDebug(rt_opt_domain, + "realtime_option(rtopt_memlock): stack_reserve %d",stack_reserve); + bzero(alloca(stack_reserve), stack_reserve); + } + + if ( heap_reserve != (size_t)0 ) { + FormatDebug(rt_opt_domain, + "realtime_option(rtopt_memlock): heap_reserve %d",heap_reserve); + ptr = malloc(heap_reserve); + if ( ptr != NULL ) { + bzero(ptr, heap_reserve); + free(ptr); + } else { + FormatFatalError("realtime_option(rtopt_memlock): heap allocate error reserved size = %d\n", + heap_reserve); + } + } + + if ( !IS_ENABLE_MEMLOCK ) { + FormatDebug(rt_opt_domain, + "realtime_option(rtopt_memlock): memlock disabled\n"); + return; + } + + int stat = mlockall(MCL_CURRENT); + if ( stat < 0 ) { + FormatFatalError("realtime_option(rtopt_memlock): mlockall error errno = %d(%s)\n", + errno,strerror(errno)); + } +} + +int rtopt_change_priority(const char *name) { + const struct rtopt_priority *param = get_priority_param(name); + if ( param == NULL ) { + FormatDebug(rt_opt_domain, + "realtime_option(rtopt_change_priority): name not found name = '%s'\n",name); + return -1; + } + + if ( !IS_ENABLE_PRIORITY(param->policy) ) { + if ( strcmp(name,RTOPT_UPDATE_PRIORITY_NAME) == 0 ) { + SetThreadIdlePriority(); + FormatDebug(rt_opt_domain, + "realtime_option(rtopt_change_priority): name %s SCHED_IDLE",name); + } + return 1; + } + FormatDebug(rt_opt_domain, + "realtime_option(rtopt_change_priority): name %s policy %d priority %d\n", + param->name,param->policy,param->priority); + return rtopt_change_thread_priority(param); +} + +int rtopt_change_output_priority(const char *name) { + const struct rtopt_priority *param = get_output_priority_param(name); + if ( param == NULL ) { + FormatDebug(rt_opt_domain, + "realtime_option(rtopt_change_output_priority): name not found name = '%s'\n",name); + return -1; + } + FormatDebug(rt_opt_domain, + "realtime_option(rtopt_change_output_priority): name %s policy %d priority %d\n", + param->name,param->policy,param->priority); + return rtopt_change_thread_priority(param); +} + + +int rtopt_change_thread_priority(const struct rtopt_priority *new_priority) { + struct rtopt_priority save; + + if ( !IS_ENABLE_RTOPT ) { + return 1; + } + if ( !IS_ENABLE_PRIORITY(new_priority->policy) ) { + return 1; + } + + if ( get_current_priority(&save) < 0 ) { + return 1; + } + + if ( IS_EQUAL_PRIORITY(new_priority, &save) ) { + FormatDebug(rt_opt_domain, + "realtime_option(rtopt_change_thread_priority): name %s not changed", + new_priority->name); + return 1; + } + + return change_priority(new_priority); +} + +void rtopt_change_output_timerslack(const char *name) { + unsigned long t = get_output_timerslack(name); + + SetThreadTimerSlackUS(t); + FormatDebug(rt_opt_domain,"output:%s timerslack %lu", name,t); +} diff --git a/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/rt_opt.hxx b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/rt_opt.hxx new file mode 100644 index 0000000..5afedda --- /dev/null +++ b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/rt_opt.hxx @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2003-2010 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +// +// mpd.conf +// +// realtime_option { +// main_priority "POLICY:PRIORITY" +// io_priority "POLICY:PRIORITY" +// decorder_priority "POLICY:PRIORITY" +// player_priority "POLICY:PRIORITY" +// update_priority "POLICY:PRIORITY" +// +// memlock "yes" or "no" +// stackreserve "1024" +// heapreserve "10240" +// +// } +// +// POLICY "OTHER" | "FIFO" | "RR" | "BATCH" | "IDLE" +// PRIORITY +// OTHER,BATCH,IDLE 0 +// FIFO, RR 1 - 99 +// +// audio_output { +// .... +// .... +// priority "POLICY:PRIORITY" +// timerslack unsigned long(default value = 100) +// } +// + +#ifndef RT_OPT_H_ +#define RT_OPT_H_ + +#include +#include +#include +#include +#include +#include + +#ifdef ENABLE_RTOPT +#define RTOPT_MAIN_PRIORITY_NAME ((const char *)"main_priority") +#define RTOPT_IO_PRIORITY_NAME ((const char *)"io_priority") +#define RTOPT_DECODER_PRIORITY_NAME ((const char *)"decoder_priority") +#define RTOPT_PLAYER_PRIORITY_NAME ((const char *)"player_priority") +#define RTOPT_UPDATE_PRIORITY_NAME ((const char *)"update_priority") +#define RTOPT_MEMLOCK_NAME ((const char *)"memlock") +#define RTOPT_STACKRESERVE_NAME ((const char *)"stack_reserve") +#define RTOPT_HEAPRESERVE_NAME ((const char *)"heap_reserve") + + +#define RTOPT_MAIL_PRIORITY 0 +#define RTOPT_DECODER_PRIORITY 1 +#define RTOPT_PLAYER_PRIORITY 2 + +#define RTOPT_DEFAULT_STACK_RESERVE ((unsigned)0) +#define RTOPT_DEFAULT_HEAP_RESERVE ((unsigned)0) + + +#define RTOPT_SCHED_OTHER "OTHER" +#define RTOPT_SCHED_FIFO "FIFO" +#define RTOPT_SCHED_RR "RR" +#define RTOPT_SCHED_BATCH "BATCH" +#define RTOPT_SCHED_IDLE "IDLE" + +#define RTOPT_DISABLE (-1) + +struct rtopt_priority { + const char *name; + int policy; + int priority; + unsigned long timerslack; +}; + +void rtopt_init(void); +void rtopt_memlock(void); +int rtopt_change_priority(const char *name); +int rtopt_change_output_priority(const char *name); +int rtopt_change_thread_priority(const struct rtopt_priority *new_priority); +void rtopt_change_output_timerslack(const char *name); + +#endif /* ENABLE_RTOPT */ + +#endif /* RT_OPT_H_ */ diff --git a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/thread/Name.hxx b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/thread/Name.hxx index a99208d..8f9d7d3 100644 --- a/home/yasuaki/MPD-V19.21-DIFFS/mpd-0.19.21/src/thread/Name.hxx +++ b/home/yasuaki/MPD-V19.21-DIFFS/mpd-native-dsd-0.19.21/src/thread/Name.hxx @@ -25,6 +25,7 @@ # include #elif defined(HAVE_PRCTL) # include +# include # ifdef PR_SET_NAME # define HAVE_THREAD_NAME # endif