summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMax Kellermann <max@musicpd.org>2017-11-05 17:48:41 +0100
committerMax Kellermann <max@musicpd.org>2017-11-05 17:48:41 +0100
commit523051132d77cb5da01847592c4c1e1faae93c6a (patch)
treeb82c42d2638eb9e83715cac0ea9dc77c7797e798 /src
parent55e6629fb49187f90e3c8357cee16ab393f5667d (diff)
parentb111a8fe8d64ee9584ffc63f648dc1bce7c670d6 (diff)
Merge branch 'v0.20.x'
Diffstat (limited to 'src')
-rw-r--r--src/decoder/plugins/VorbisDecoderPlugin.cxx16
-rw-r--r--src/input/plugins/CurlInputPlugin.cxx21
-rw-r--r--src/output/Thread.cxx19
-rw-r--r--src/player/Thread.cxx9
4 files changed, 53 insertions, 12 deletions
diff --git a/src/decoder/plugins/VorbisDecoderPlugin.cxx b/src/decoder/plugins/VorbisDecoderPlugin.cxx
index be557a353..fbbc0264a 100644
--- a/src/decoder/plugins/VorbisDecoderPlugin.cxx
+++ b/src/decoder/plugins/VorbisDecoderPlugin.cxx
@@ -178,6 +178,20 @@ VorbisDecoder::SubmitInit()
client.Ready(audio_format, eos_granulepos > 0, duration);
}
+#ifdef HAVE_TREMOR
+static inline int16_t tremor_clip_sample(int32_t x)
+{
+ x >>= 9;
+
+ if (x < INT16_MIN)
+ return INT16_MIN;
+ if (x > INT16_MAX)
+ return INT16_MAX;
+
+ return x;
+}
+#endif
+
bool
VorbisDecoder::SubmitSomePcm()
{
@@ -197,7 +211,7 @@ VorbisDecoder::SubmitSomePcm()
auto *dest = &buffer[c];
for (size_t i = 0; i < n_frames; ++i) {
- *dest = *src++;
+ *dest = tremor_clip_sample(*src++);
dest += channels;
}
}
diff --git a/src/input/plugins/CurlInputPlugin.cxx b/src/input/plugins/CurlInputPlugin.cxx
index a1be25d90..6ab7e34ee 100644
--- a/src/input/plugins/CurlInputPlugin.cxx
+++ b/src/input/plugins/CurlInputPlugin.cxx
@@ -66,7 +66,6 @@ static const size_t CURL_RESUME_AT = 384 * 1024;
struct CurlInputStream final : public AsyncInputStream, CurlResponseHandler {
/* some buffers which were passed to libcurl, which we have
too free */
- char range[32];
CurlSlist request_headers;
CurlRequest *request = nullptr;
@@ -89,9 +88,20 @@ struct CurlInputStream final : public AsyncInputStream, CurlResponseHandler {
static InputStream *Open(const char *url, Mutex &mutex, Cond &cond);
+ /**
+ * Create and initialize a new #CurlRequest instance. After
+ * this, you may add more request headers and set options. To
+ * actually start the request, call StartRequest().
+ */
void InitEasy();
/**
+ * Start the request after having called InitEasy(). After
+ * this, you must not set any CURL options.
+ */
+ void StartRequest();
+
+ /**
* Frees the current "libcurl easy" handle, and everything
* associated with it.
*
@@ -365,6 +375,11 @@ CurlInputStream::InitEasy()
request_headers.Clear();
request_headers.Append("Icy-Metadata: 1");
+}
+
+void
+CurlInputStream::StartRequest()
+{
request->SetOption(CURLOPT_HTTPHEADER, request_headers.Get());
request->Start();
@@ -391,6 +406,7 @@ CurlInputStream::SeekInternal(offset_type new_offset)
/* send the "Range" header */
if (offset > 0) {
+ char range[32];
#ifdef WIN32
// TODO: what can we use on Windows to format 64 bit?
sprintf(range, "%lu-", (long)offset);
@@ -399,6 +415,8 @@ CurlInputStream::SeekInternal(offset_type new_offset)
#endif
request->SetOption(CURLOPT_RANGE, range);
}
+
+ StartRequest();
}
void
@@ -422,6 +440,7 @@ CurlInputStream::Open(const char *url, Mutex &mutex, Cond &cond)
try {
BlockingCall(c->GetEventLoop(), [c](){
c->InitEasy();
+ c->StartRequest();
});
} catch (...) {
delete c;
diff --git a/src/output/Thread.cxx b/src/output/Thread.cxx
index 5acf0da0b..ed2feac82 100644
--- a/src/output/Thread.cxx
+++ b/src/output/Thread.cxx
@@ -245,16 +245,15 @@ try {
inline bool
AudioOutputControl::PlayChunk() noexcept
{
- if (tags) {
- const auto *tag = source.ReadTag();
- if (tag != nullptr) {
- const ScopeUnlock unlock(mutex);
- try {
- output->SendTag(*tag);
- } catch (const std::runtime_error &e) {
- FormatError(e, "Failed to send tag to %s",
- GetLogName());
- }
+ // ensure pending tags are flushed in all cases
+ const auto *tag = source.ReadTag();
+ if (tags && tag != nullptr) {
+ const ScopeUnlock unlock(mutex);
+ try {
+ output->SendTag(*tag);
+ } catch (const std::runtime_error &e) {
+ FormatError(e, "Failed to send tag to %s",
+ GetLogName());
}
}
diff --git a/src/player/Thread.cxx b/src/player/Thread.cxx
index a6d2b3d4b..90431ef90 100644
--- a/src/player/Thread.cxx
+++ b/src/player/Thread.cxx
@@ -32,6 +32,7 @@
#include "output/MultipleOutputs.hxx"
#include "tag/Tag.hxx"
#include "Idle.hxx"
+#include "system/PeriodClock.hxx"
#include "util/Domain.hxx"
#include "thread/Name.hxx"
#include "Log.hxx"
@@ -146,6 +147,8 @@ class Player {
*/
SongTime elapsed_time;
+ PeriodClock throttle_silence_log;
+
public:
Player(PlayerControl &_pc, DecoderControl &_dc,
MusicBuffer &_buffer)
@@ -934,6 +937,8 @@ Player::SongBorder()
{
FormatDefault(player_domain, "played \"%s\"", song->GetURI());
+ throttle_silence_log.Reset();
+
ReplacePipe(dc.pipe);
pc.outputs.SongBorder();
@@ -1095,6 +1100,10 @@ Player::Run()
/* the decoder is too busy and hasn't provided
new PCM data in time: send silence (if the
output pipe is empty) */
+
+ if (throttle_silence_log.CheckUpdate(std::chrono::seconds(5)))
+ FormatWarning(player_domain, "Decoder is too slow; playing silence to avoid xrun");
+
if (!SendSilence())
break;
}