Commit 52305113 authored by Max Kellermann's avatar Max Kellermann

Merge branch 'v0.20.x'

parents 55e6629f b111a8fe
...@@ -14,6 +14,16 @@ ver 0.21 (not yet released) ...@@ -14,6 +14,16 @@ ver 0.21 (not yet released)
* mixer * mixer
- sndio: new mixer plugin - sndio: new mixer plugin
ver 0.20.12 (not yet released)
* input
- curl: fix seeking
* decoder
- vorbis: fix Tremor support
* player
- log message when decoder is too slow
* output
- fix hanging playback with soxr resampler
ver 0.20.11 (2017/10/18) ver 0.20.11 (2017/10/18)
* storage * storage
- curl: support Content-Type application/xml - curl: support Content-Type application/xml
......
...@@ -178,6 +178,20 @@ VorbisDecoder::SubmitInit() ...@@ -178,6 +178,20 @@ VorbisDecoder::SubmitInit()
client.Ready(audio_format, eos_granulepos > 0, duration); 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 bool
VorbisDecoder::SubmitSomePcm() VorbisDecoder::SubmitSomePcm()
{ {
...@@ -197,7 +211,7 @@ VorbisDecoder::SubmitSomePcm() ...@@ -197,7 +211,7 @@ VorbisDecoder::SubmitSomePcm()
auto *dest = &buffer[c]; auto *dest = &buffer[c];
for (size_t i = 0; i < n_frames; ++i) { for (size_t i = 0; i < n_frames; ++i) {
*dest = *src++; *dest = tremor_clip_sample(*src++);
dest += channels; dest += channels;
} }
} }
......
...@@ -66,7 +66,6 @@ static const size_t CURL_RESUME_AT = 384 * 1024; ...@@ -66,7 +66,6 @@ static const size_t CURL_RESUME_AT = 384 * 1024;
struct CurlInputStream final : public AsyncInputStream, CurlResponseHandler { struct CurlInputStream final : public AsyncInputStream, CurlResponseHandler {
/* some buffers which were passed to libcurl, which we have /* some buffers which were passed to libcurl, which we have
too free */ too free */
char range[32];
CurlSlist request_headers; CurlSlist request_headers;
CurlRequest *request = nullptr; CurlRequest *request = nullptr;
...@@ -89,9 +88,20 @@ struct CurlInputStream final : public AsyncInputStream, CurlResponseHandler { ...@@ -89,9 +88,20 @@ struct CurlInputStream final : public AsyncInputStream, CurlResponseHandler {
static InputStream *Open(const char *url, Mutex &mutex, Cond &cond); 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(); 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 * Frees the current "libcurl easy" handle, and everything
* associated with it. * associated with it.
* *
...@@ -365,6 +375,11 @@ CurlInputStream::InitEasy() ...@@ -365,6 +375,11 @@ CurlInputStream::InitEasy()
request_headers.Clear(); request_headers.Clear();
request_headers.Append("Icy-Metadata: 1"); request_headers.Append("Icy-Metadata: 1");
}
void
CurlInputStream::StartRequest()
{
request->SetOption(CURLOPT_HTTPHEADER, request_headers.Get()); request->SetOption(CURLOPT_HTTPHEADER, request_headers.Get());
request->Start(); request->Start();
...@@ -391,6 +406,7 @@ CurlInputStream::SeekInternal(offset_type new_offset) ...@@ -391,6 +406,7 @@ CurlInputStream::SeekInternal(offset_type new_offset)
/* send the "Range" header */ /* send the "Range" header */
if (offset > 0) { if (offset > 0) {
char range[32];
#ifdef WIN32 #ifdef WIN32
// TODO: what can we use on Windows to format 64 bit? // TODO: what can we use on Windows to format 64 bit?
sprintf(range, "%lu-", (long)offset); sprintf(range, "%lu-", (long)offset);
...@@ -399,6 +415,8 @@ CurlInputStream::SeekInternal(offset_type new_offset) ...@@ -399,6 +415,8 @@ CurlInputStream::SeekInternal(offset_type new_offset)
#endif #endif
request->SetOption(CURLOPT_RANGE, range); request->SetOption(CURLOPT_RANGE, range);
} }
StartRequest();
} }
void void
...@@ -422,6 +440,7 @@ CurlInputStream::Open(const char *url, Mutex &mutex, Cond &cond) ...@@ -422,6 +440,7 @@ CurlInputStream::Open(const char *url, Mutex &mutex, Cond &cond)
try { try {
BlockingCall(c->GetEventLoop(), [c](){ BlockingCall(c->GetEventLoop(), [c](){
c->InitEasy(); c->InitEasy();
c->StartRequest();
}); });
} catch (...) { } catch (...) {
delete c; delete c;
......
...@@ -245,16 +245,15 @@ try { ...@@ -245,16 +245,15 @@ try {
inline bool inline bool
AudioOutputControl::PlayChunk() noexcept AudioOutputControl::PlayChunk() noexcept
{ {
if (tags) { // ensure pending tags are flushed in all cases
const auto *tag = source.ReadTag(); const auto *tag = source.ReadTag();
if (tag != nullptr) { if (tags && tag != nullptr) {
const ScopeUnlock unlock(mutex); const ScopeUnlock unlock(mutex);
try { try {
output->SendTag(*tag); output->SendTag(*tag);
} catch (const std::runtime_error &e) { } catch (const std::runtime_error &e) {
FormatError(e, "Failed to send tag to %s", FormatError(e, "Failed to send tag to %s",
GetLogName()); GetLogName());
}
} }
} }
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include "output/MultipleOutputs.hxx" #include "output/MultipleOutputs.hxx"
#include "tag/Tag.hxx" #include "tag/Tag.hxx"
#include "Idle.hxx" #include "Idle.hxx"
#include "system/PeriodClock.hxx"
#include "util/Domain.hxx" #include "util/Domain.hxx"
#include "thread/Name.hxx" #include "thread/Name.hxx"
#include "Log.hxx" #include "Log.hxx"
...@@ -146,6 +147,8 @@ class Player { ...@@ -146,6 +147,8 @@ class Player {
*/ */
SongTime elapsed_time; SongTime elapsed_time;
PeriodClock throttle_silence_log;
public: public:
Player(PlayerControl &_pc, DecoderControl &_dc, Player(PlayerControl &_pc, DecoderControl &_dc,
MusicBuffer &_buffer) MusicBuffer &_buffer)
...@@ -934,6 +937,8 @@ Player::SongBorder() ...@@ -934,6 +937,8 @@ Player::SongBorder()
{ {
FormatDefault(player_domain, "played \"%s\"", song->GetURI()); FormatDefault(player_domain, "played \"%s\"", song->GetURI());
throttle_silence_log.Reset();
ReplacePipe(dc.pipe); ReplacePipe(dc.pipe);
pc.outputs.SongBorder(); pc.outputs.SongBorder();
...@@ -1095,6 +1100,10 @@ Player::Run() ...@@ -1095,6 +1100,10 @@ Player::Run()
/* the decoder is too busy and hasn't provided /* the decoder is too busy and hasn't provided
new PCM data in time: send silence (if the new PCM data in time: send silence (if the
output pipe is empty) */ 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()) if (!SendSilence())
break; break;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment