mirror of
https://github.com/badaix/snapcast.git
synced 2025-05-25 23:16:14 +02:00
Fix mixer script
This commit is contained in:
parent
9253b00bcc
commit
e57dc0888f
8 changed files with 51 additions and 50 deletions
|
@ -230,6 +230,7 @@ void Controller::getNextMessage()
|
||||||
player_->setVolumeCallback(
|
player_->setVolumeCallback(
|
||||||
[this](const Player::Volume& volume)
|
[this](const Player::Volume& volume)
|
||||||
{
|
{
|
||||||
|
// Cache the last volume and check if it really changed in the player's volume callback
|
||||||
static Player::Volume last_volume{-1, true};
|
static Player::Volume last_volume{-1, true};
|
||||||
if (volume != last_volume)
|
if (volume != last_volume)
|
||||||
{
|
{
|
||||||
|
|
|
@ -659,6 +659,7 @@ void AlsaPlayer::worker()
|
||||||
LOG(INFO, LOG_TAG) << "Failed to get chunk\n";
|
LOG(INFO, LOG_TAG) << "Failed to get chunk\n";
|
||||||
while (active_ && !stream_->waitForChunk(100ms))
|
while (active_ && !stream_->waitForChunk(100ms))
|
||||||
{
|
{
|
||||||
|
// Log "Waiting for chunk" only every second second
|
||||||
static utils::logging::TimeConditional cond(2s);
|
static utils::logging::TimeConditional cond(2s);
|
||||||
LOG(DEBUG, LOG_TAG) << cond << "Waiting for chunk\n";
|
LOG(DEBUG, LOG_TAG) << cond << "Waiting for chunk\n";
|
||||||
if ((handle_ != nullptr) && (chronos::getTickCount() - lastChunkTick > 5000))
|
if ((handle_ != nullptr) && (chronos::getTickCount() - lastChunkTick > 5000))
|
||||||
|
|
|
@ -240,38 +240,29 @@ void Player::setVolume(const Volume& volume)
|
||||||
else if (settings_.mixer.mode == ClientSettings::Mixer::Mode::script)
|
else if (settings_.mixer.mode == ClientSettings::Mixer::Mode::script)
|
||||||
{
|
{
|
||||||
#ifdef SUPPORTS_VOLUME_SCRIPT
|
#ifdef SUPPORTS_VOLUME_SCRIPT
|
||||||
static std::optional<Volume> pending_volume_setting;
|
static std::optional<Volume> pending_volume_change;
|
||||||
static bool script_running = false;
|
static boost::process::child mixer_script_process;
|
||||||
if (script_running)
|
if (mixer_script_process.running())
|
||||||
{
|
{
|
||||||
pending_volume_setting = volume;
|
pending_volume_change = volume;
|
||||||
LOG(DEBUG, LOG_TAG) << "Volume script still running, deferring this volume setting\n";
|
LOG(DEBUG, LOG_TAG) << "Volume mixer script still running, deferring this volume change\n";
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
static std::optional<Volume> pending_volume_setting;
|
|
||||||
static boost::process::child c;
|
|
||||||
if (c.running())
|
|
||||||
{
|
|
||||||
pending_volume_setting = volume;
|
|
||||||
LOG(DEBUG, LOG_TAG) << "Volume script still running, deferring this volume setting\n";
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
namespace bp = boost::process;
|
namespace bp = boost::process;
|
||||||
c = bp::child(bp::exe = settings_.mixer.parameter,
|
mixer_script_process = bp::child(bp::exe = settings_.mixer.parameter,
|
||||||
bp::args = {"--volume", cpt::to_string(volume.volume), "--mute", volume.mute ? "true" : "false"},
|
bp::args = {"--volume", cpt::to_string(volume.volume), "--mute", volume.mute ? "true" : "false"},
|
||||||
bp::on_exit(
|
bp::on_exit(
|
||||||
[&](int ret_val, std::error_code ec)
|
[&](int ret_val, std::error_code ec)
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lock(mutex_);
|
std::unique_lock<std::mutex> lock(mutex_);
|
||||||
LOG(DEBUG, LOG_TAG) << "Error code: " << ec.message() << ", i: " << ret_val << "\n";
|
LOG(DEBUG, LOG_TAG) << "Error code: " << ec.message() << ", i: " << ret_val << "\n";
|
||||||
if (pending_volume_setting.has_value())
|
if (pending_volume_change.has_value())
|
||||||
{
|
{
|
||||||
Volume v = pending_volume_setting.value();
|
Volume v = pending_volume_change.value();
|
||||||
pending_volume_setting = std::nullopt;
|
pending_volume_change = std::nullopt;
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
setVolume(v);
|
setVolume(v);
|
||||||
}
|
}
|
||||||
|
@ -280,9 +271,8 @@ void Player::setVolume(const Volume& volume)
|
||||||
}
|
}
|
||||||
catch (const std::exception& e)
|
catch (const std::exception& e)
|
||||||
{
|
{
|
||||||
script_running = false;
|
|
||||||
LOG(ERROR, LOG_TAG) << "Failed to run script '" + settings_.mixer.parameter + "', error: " << e.what() << "\n";
|
LOG(ERROR, LOG_TAG) << "Failed to run script '" + settings_.mixer.parameter + "', error: " << e.what() << "\n";
|
||||||
}
|
pending_volume_change = std::nullopt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
This file is part of snapcast
|
||||||
Copyright (C) 2014-2021 Johannes Pohl
|
Copyright (C) 2014-2024 Johannes Pohl
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
|
@ -20,12 +20,18 @@
|
||||||
#define NOMINMAX
|
#define NOMINMAX
|
||||||
#endif // NOMINMAX
|
#endif // NOMINMAX
|
||||||
|
|
||||||
|
// prototype/interface header file
|
||||||
#include "stream.hpp"
|
#include "stream.hpp"
|
||||||
|
|
||||||
|
// local headers
|
||||||
#include "common/aixlog.hpp"
|
#include "common/aixlog.hpp"
|
||||||
#include "common/snap_exception.hpp"
|
#include "common/snap_exception.hpp"
|
||||||
#include "common/str_compat.hpp"
|
#include "common/str_compat.hpp"
|
||||||
#include "common/utils/logging.hpp"
|
|
||||||
#include "time_provider.hpp"
|
#include "time_provider.hpp"
|
||||||
|
|
||||||
|
// 3rd party headers
|
||||||
|
|
||||||
|
// standard headers
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
@ -41,7 +47,7 @@ static constexpr auto kCorrectionBegin = 100us;
|
||||||
|
|
||||||
Stream::Stream(const SampleFormat& in_format, const SampleFormat& out_format)
|
Stream::Stream(const SampleFormat& in_format, const SampleFormat& out_format)
|
||||||
: in_format_(in_format), median_(0), shortMedian_(0), lastUpdate_(0), playedFrames_(0), correctAfterXFrames_(0), bufferMs_(cs::msec(500)), frame_delta_(0),
|
: in_format_(in_format), median_(0), shortMedian_(0), lastUpdate_(0), playedFrames_(0), correctAfterXFrames_(0), bufferMs_(cs::msec(500)), frame_delta_(0),
|
||||||
hard_sync_(true)
|
hard_sync_(true), time_cond_(1s)
|
||||||
{
|
{
|
||||||
buffer_.setSize(500);
|
buffer_.setSize(500);
|
||||||
shortBuffer_.setSize(100);
|
shortBuffer_.setSize(100);
|
||||||
|
@ -459,8 +465,7 @@ bool Stream::getPlayerChunkOrSilence(void* outputBuffer, const chronos::usec& ou
|
||||||
bool result = getPlayerChunk(outputBuffer, outputBufferDacTime, frames);
|
bool result = getPlayerChunk(outputBuffer, outputBufferDacTime, frames);
|
||||||
if (!result)
|
if (!result)
|
||||||
{
|
{
|
||||||
static utils::logging::TimeConditional cond(1s);
|
LOG(DEBUG, LOG_TAG) << time_cond_ << "Failed to get chunk, returning silence\n";
|
||||||
LOG(DEBUG, LOG_TAG) << cond << "Failed to get chunk, returning silence\n";
|
|
||||||
getSilentPlayerChunk(outputBuffer, frames);
|
getSilentPlayerChunk(outputBuffer, frames);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
This file is part of snapcast
|
||||||
Copyright (C) 2014-2023 Johannes Pohl
|
Copyright (C) 2014-2024 Johannes Pohl
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
|
@ -25,6 +25,7 @@
|
||||||
#include "common/queue.h"
|
#include "common/queue.h"
|
||||||
#include "common/resampler.hpp"
|
#include "common/resampler.hpp"
|
||||||
#include "common/sample_format.hpp"
|
#include "common/sample_format.hpp"
|
||||||
|
#include "common/utils/logging.hpp"
|
||||||
#include "double_buffer.hpp"
|
#include "double_buffer.hpp"
|
||||||
|
|
||||||
// 3rd party headers
|
// 3rd party headers
|
||||||
|
@ -134,6 +135,9 @@ private:
|
||||||
mutable std::mutex mutex_;
|
mutable std::mutex mutex_;
|
||||||
|
|
||||||
bool hard_sync_;
|
bool hard_sync_;
|
||||||
|
|
||||||
|
/// Log "failed to get chunk" only once per second
|
||||||
|
utils::logging::TimeConditional time_cond_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
This file is part of snapcast
|
||||||
Copyright (C) 2014-2023 Johannes Pohl
|
Copyright (C) 2014-2024 Johannes Pohl
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
|
@ -251,7 +251,7 @@ void ControlSessionHttp::handle_request(http::request<Body, http::basic_fields<A
|
||||||
if (target.empty() || target[0] != '/' || target.find("..") != beast::string_view::npos)
|
if (target.empty() || target[0] != '/' || target.find("..") != beast::string_view::npos)
|
||||||
return send(bad_request("Illegal request-target"));
|
return send(bad_request("Illegal request-target"));
|
||||||
|
|
||||||
static string image_cache_target = "/__image_cache?name=";
|
static const string image_cache_target = "/__image_cache?name=";
|
||||||
auto pos = target.find(image_cache_target);
|
auto pos = target.find(image_cache_target);
|
||||||
if (pos != std::string::npos)
|
if (pos != std::string::npos)
|
||||||
{
|
{
|
||||||
|
|
|
@ -23,9 +23,7 @@
|
||||||
#include "base64.h"
|
#include "base64.h"
|
||||||
#include "common/aixlog.hpp"
|
#include "common/aixlog.hpp"
|
||||||
#include "common/snap_exception.hpp"
|
#include "common/snap_exception.hpp"
|
||||||
#include "common/utils.hpp"
|
|
||||||
#include "common/utils/file_utils.hpp"
|
#include "common/utils/file_utils.hpp"
|
||||||
#include "common/utils/string_utils.hpp"
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
@ -248,7 +246,6 @@ void AirplayStream::pipeReadLine()
|
||||||
boost::asio::async_read_until(*pipe_fd_, streambuf_pipe_, delimiter,
|
boost::asio::async_read_until(*pipe_fd_, streambuf_pipe_, delimiter,
|
||||||
[this, delimiter](const std::error_code& ec, std::size_t bytes_transferred)
|
[this, delimiter](const std::error_code& ec, std::size_t bytes_transferred)
|
||||||
{
|
{
|
||||||
static AixLog::Severity logseverity = AixLog::Severity::info;
|
|
||||||
if (ec)
|
if (ec)
|
||||||
{
|
{
|
||||||
if ((ec.value() == boost::asio::error::eof) || (ec.value() == boost::asio::error::bad_descriptor))
|
if ((ec.value() == boost::asio::error::eof) || (ec.value() == boost::asio::error::bad_descriptor))
|
||||||
|
@ -256,8 +253,8 @@ void AirplayStream::pipeReadLine()
|
||||||
// For some reason, EOF is returned until the first metadata is written to the pipe.
|
// For some reason, EOF is returned until the first metadata is written to the pipe.
|
||||||
// If shairport-sync has not finished setting up the pipe, bad file descriptor is returned.
|
// If shairport-sync has not finished setting up the pipe, bad file descriptor is returned.
|
||||||
static constexpr auto retry_ms = 2500ms;
|
static constexpr auto retry_ms = 2500ms;
|
||||||
LOG(logseverity, LOG_TAG) << "Waiting for metadata, retrying in " << retry_ms.count() << "ms\n";
|
LOG(read_logseverity_, LOG_TAG) << "Waiting for metadata, retrying in " << retry_ms.count() << "ms\n";
|
||||||
logseverity = AixLog::Severity::debug;
|
read_logseverity_ = AixLog::Severity::debug;
|
||||||
wait(pipe_open_timer_, retry_ms, [this] { pipeReadLine(); });
|
wait(pipe_open_timer_, retry_ms, [this] { pipeReadLine(); });
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -266,7 +263,7 @@ void AirplayStream::pipeReadLine()
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
logseverity = AixLog::Severity::info;
|
read_logseverity_ = AixLog::Severity::info;
|
||||||
|
|
||||||
// Extract up to the first delimiter.
|
// Extract up to the first delimiter.
|
||||||
std::string line{buffers_begin(streambuf_pipe_.data()), buffers_begin(streambuf_pipe_.data()) + bytes_transferred - delimiter.length()};
|
std::string line{buffers_begin(streambuf_pipe_.data()), buffers_begin(streambuf_pipe_.data()) + bytes_transferred - delimiter.length()};
|
||||||
|
|
|
@ -101,6 +101,9 @@ protected:
|
||||||
static void XMLCALL element_end(void* userdata, const char* element_name);
|
static void XMLCALL element_end(void* userdata, const char* element_name);
|
||||||
static void XMLCALL data(void* userdata, const char* content, int length);
|
static void XMLCALL data(void* userdata, const char* content, int length);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
AixLog::Severity read_logseverity_{AixLog::Severity::info};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace streamreader
|
} // namespace streamreader
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue