mirror of
https://github.com/badaix/snapcast.git
synced 2025-07-16 16:15:40 +02:00
Fix linter warnings
This commit is contained in:
parent
66868e2501
commit
5c41afd9e3
31 changed files with 131 additions and 116 deletions
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
|
@ -56,7 +56,7 @@ jobs:
|
||||||
- name: evaluate
|
- name: evaluate
|
||||||
run: |
|
run: |
|
||||||
WARNINGS=$(cat build/analysis.log | sort | uniq | grep -e ": warning: " | wc -l)
|
WARNINGS=$(cat build/analysis.log | sort | uniq | grep -e ": warning: " | wc -l)
|
||||||
MAX_ALLOWED=431
|
MAX_ALLOWED=0
|
||||||
echo "Analysis finished with $WARNINGS warnings, max allowed: $MAX_ALLOWED"
|
echo "Analysis finished with $WARNINGS warnings, max allowed: $MAX_ALLOWED"
|
||||||
if [ "$WARNINGS" -gt "$MAX_ALLOWED" ]; then exit $WARNINGS; else exit 0; fi;
|
if [ "$WARNINGS" -gt "$MAX_ALLOWED" ]; then exit $WARNINGS; else exit 0; fi;
|
||||||
|
|
||||||
|
|
|
@ -300,7 +300,7 @@ ClientConnectionTcp::ClientConnectionTcp(boost::asio::io_context& io_context, Cl
|
||||||
|
|
||||||
ClientConnectionTcp::~ClientConnectionTcp()
|
ClientConnectionTcp::~ClientConnectionTcp()
|
||||||
{
|
{
|
||||||
disconnect();
|
disconnect(); // NOLINT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -421,7 +421,7 @@ ClientConnectionWs::ClientConnectionWs(boost::asio::io_context& io_context, Clie
|
||||||
|
|
||||||
ClientConnectionWs::~ClientConnectionWs()
|
ClientConnectionWs::~ClientConnectionWs()
|
||||||
{
|
{
|
||||||
disconnect();
|
disconnect(); // NOLINT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -539,7 +539,7 @@ boost::system::error_code ClientConnectionWs::doConnect(boost::asio::ip::basic_e
|
||||||
|
|
||||||
void ClientConnectionWs::write(boost::asio::streambuf& buffer, WriteHandler&& write_handler)
|
void ClientConnectionWs::write(boost::asio::streambuf& buffer, WriteHandler&& write_handler)
|
||||||
{
|
{
|
||||||
getWs().async_write(boost::asio::buffer(buffer.data()), write_handler);
|
getWs().async_write(boost::asio::buffer(buffer.data()), write_handler); // NOLINT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -592,7 +592,7 @@ ssl_websocket& ClientConnectionWss::getWs()
|
||||||
|
|
||||||
ClientConnectionWss::~ClientConnectionWss()
|
ClientConnectionWss::~ClientConnectionWss()
|
||||||
{
|
{
|
||||||
disconnect();
|
disconnect(); // NOLINT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
This file is part of snapcast
|
||||||
Copyright (C) 2014-2024 Johannes Pohl
|
Copyright (C) 2014-2025 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
|
||||||
|
@ -80,7 +80,7 @@ bool FlacDecoder::decode(msg::PcmChunk* chunk)
|
||||||
memcpy(flacChunk->payload, chunk->payload, chunk->payloadSize);
|
memcpy(flacChunk->payload, chunk->payload, chunk->payloadSize);
|
||||||
flacChunk->payloadSize = chunk->payloadSize;
|
flacChunk->payloadSize = chunk->payloadSize;
|
||||||
|
|
||||||
pcmChunk->payload = static_cast<char*>(realloc(pcmChunk->payload, 0));
|
pcmChunk->payload = static_cast<char*>(realloc(pcmChunk->payload, 0)); // NOLINT
|
||||||
pcmChunk->payloadSize = 0;
|
pcmChunk->payloadSize = 0;
|
||||||
while (flacChunk->payloadSize > 0)
|
while (flacChunk->payloadSize > 0)
|
||||||
{
|
{
|
||||||
|
@ -154,7 +154,7 @@ FLAC__StreamDecoderReadStatus read_callback(const FLAC__StreamDecoder* /*decoder
|
||||||
memcpy(buffer, flacChunk->payload, *bytes);
|
memcpy(buffer, flacChunk->payload, *bytes);
|
||||||
memmove(flacChunk->payload, flacChunk->payload + *bytes, flacChunk->payloadSize - *bytes);
|
memmove(flacChunk->payload, flacChunk->payload + *bytes, flacChunk->payloadSize - *bytes);
|
||||||
flacChunk->payloadSize = flacChunk->payloadSize - static_cast<uint32_t>(*bytes);
|
flacChunk->payloadSize = flacChunk->payloadSize - static_cast<uint32_t>(*bytes);
|
||||||
flacChunk->payload = static_cast<char*>(realloc(flacChunk->payload, flacChunk->payloadSize));
|
flacChunk->payload = static_cast<char*>(realloc(flacChunk->payload, flacChunk->payloadSize)); // NOLINT
|
||||||
}
|
}
|
||||||
return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
|
return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,25 +106,25 @@ void AlsaPlayer::setHardwareVolume(const Volume& volume)
|
||||||
LOG(ERROR, LOG_TAG) << "Failed to mute, error: " << snd_strerror(err) << "\n";
|
LOG(ERROR, LOG_TAG) << "Failed to mute, error: " << snd_strerror(err) << "\n";
|
||||||
|
|
||||||
long minv, maxv;
|
long minv, maxv;
|
||||||
if ((err = snd_mixer_selem_get_playback_dB_range(elem_, &minv, &maxv)) == 0)
|
if (err = snd_mixer_selem_get_playback_dB_range(elem_, &minv, &maxv); err == 0)
|
||||||
{
|
{
|
||||||
double min_norm = exp10((minv - maxv) / 6000.0);
|
double min_norm = exp10((minv - maxv) / 6000.0);
|
||||||
double vol = volume.volume * (1 - min_norm) + min_norm;
|
double vol = volume.volume * (1 - min_norm) + min_norm;
|
||||||
double mixer_volume = 6000.0 * log10(vol) + maxv;
|
double mixer_volume = 6000.0 * log10(vol) + maxv;
|
||||||
|
|
||||||
LOG(DEBUG, LOG_TAG) << "Mixer playback dB range [" << minv << ", " << maxv << "], volume: " << vol << ", mixer volume: " << mixer_volume << "\n";
|
LOG(DEBUG, LOG_TAG) << "Mixer playback dB range [" << minv << ", " << maxv << "], volume: " << vol << ", mixer volume: " << mixer_volume << "\n";
|
||||||
if ((err = snd_mixer_selem_set_playback_dB_all(elem_, mixer_volume, 0)) < 0)
|
if (err = snd_mixer_selem_set_playback_dB_all(elem_, mixer_volume, 0); err < 0)
|
||||||
throw SnapException(std::string("Failed to set playback volume, error: ") + snd_strerror(err));
|
throw SnapException(std::string("Failed to set playback volume, error: ") + snd_strerror(err));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ((err = snd_mixer_selem_get_playback_volume_range(elem_, &minv, &maxv)) < 0)
|
if (err = snd_mixer_selem_get_playback_volume_range(elem_, &minv, &maxv); err < 0)
|
||||||
throw SnapException(std::string("Failed to get playback volume range, error: ") + snd_strerror(err));
|
throw SnapException(std::string("Failed to get playback volume range, error: ") + snd_strerror(err));
|
||||||
|
|
||||||
auto mixer_volume = volume.volume * (maxv - minv) + minv;
|
auto mixer_volume = volume.volume * (maxv - minv) + minv;
|
||||||
LOG(DEBUG, LOG_TAG) << "Mixer playback volume range [" << minv << ", " << maxv << "], volume: " << volume.volume
|
LOG(DEBUG, LOG_TAG) << "Mixer playback volume range [" << minv << ", " << maxv << "], volume: " << volume.volume
|
||||||
<< ", mixer volume: " << mixer_volume << "\n";
|
<< ", mixer volume: " << mixer_volume << "\n";
|
||||||
if ((err = snd_mixer_selem_set_playback_volume_all(elem_, mixer_volume)) < 0)
|
if (err = snd_mixer_selem_set_playback_volume_all(elem_, mixer_volume); err < 0)
|
||||||
throw SnapException(std::string("Failed to set playback volume, error: ") + snd_strerror(err));
|
throw SnapException(std::string("Failed to set playback volume, error: ") + snd_strerror(err));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -149,9 +149,9 @@ bool AlsaPlayer::getHardwareVolume(Volume& volume)
|
||||||
while (snd_mixer_handle_events(mixer_) > 0)
|
while (snd_mixer_handle_events(mixer_) > 0)
|
||||||
this_thread::sleep_for(1us);
|
this_thread::sleep_for(1us);
|
||||||
long minv, maxv;
|
long minv, maxv;
|
||||||
if ((err = snd_mixer_selem_get_playback_dB_range(elem_, &minv, &maxv)) == 0)
|
if (err = snd_mixer_selem_get_playback_dB_range(elem_, &minv, &maxv); err == 0)
|
||||||
{
|
{
|
||||||
if ((err = snd_mixer_selem_get_playback_dB(elem_, SND_MIXER_SCHN_MONO, &vol)) < 0)
|
if (err = snd_mixer_selem_get_playback_dB(elem_, SND_MIXER_SCHN_MONO, &vol); err < 0)
|
||||||
throw SnapException(std::string("Failed to get playback volume, error: ") + snd_strerror(err));
|
throw SnapException(std::string("Failed to get playback volume, error: ") + snd_strerror(err));
|
||||||
|
|
||||||
volume.volume = pow(10, (vol - maxv) / 6000.0);
|
volume.volume = pow(10, (vol - maxv) / 6000.0);
|
||||||
|
@ -163,9 +163,9 @@ bool AlsaPlayer::getHardwareVolume(Volume& volume)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ((err = snd_mixer_selem_get_playback_volume_range(elem_, &minv, &maxv)) < 0)
|
if (err = snd_mixer_selem_get_playback_volume_range(elem_, &minv, &maxv); err < 0)
|
||||||
throw SnapException(std::string("Failed to get playback volume range, error: ") + snd_strerror(err));
|
throw SnapException(std::string("Failed to get playback volume range, error: ") + snd_strerror(err));
|
||||||
if ((err = snd_mixer_selem_get_playback_volume(elem_, SND_MIXER_SCHN_MONO, &vol)) < 0)
|
if (err = snd_mixer_selem_get_playback_volume(elem_, SND_MIXER_SCHN_MONO, &vol); err < 0)
|
||||||
throw SnapException(std::string("Failed to get playback volume, error: ") + snd_strerror(err));
|
throw SnapException(std::string("Failed to get playback volume, error: ") + snd_strerror(err));
|
||||||
|
|
||||||
vol -= minv;
|
vol -= minv;
|
||||||
|
@ -173,7 +173,7 @@ bool AlsaPlayer::getHardwareVolume(Volume& volume)
|
||||||
volume.volume = static_cast<double>(vol) / static_cast<double>(maxv);
|
volume.volume = static_cast<double>(vol) / static_cast<double>(maxv);
|
||||||
}
|
}
|
||||||
int val;
|
int val;
|
||||||
if ((err = snd_mixer_selem_get_playback_switch(elem_, SND_MIXER_SCHN_MONO, &val)) < 0)
|
if (err = snd_mixer_selem_get_playback_switch(elem_, SND_MIXER_SCHN_MONO, &val); err < 0)
|
||||||
throw SnapException(std::string("Failed to get mute state, error: ") + snd_strerror(err));
|
throw SnapException(std::string("Failed to get mute state, error: ") + snd_strerror(err));
|
||||||
volume.mute = (val == 0);
|
volume.mute = (val == 0);
|
||||||
LOG(DEBUG, LOG_TAG) << "Get volume, mixer volume range [" << minv << ", " << maxv << "], volume: " << volume.volume << ", muted: " << volume.mute
|
LOG(DEBUG, LOG_TAG) << "Get volume, mixer volume range [" << minv << ", " << maxv << "], volume: " << volume.volume << ", muted: " << volume.mute
|
||||||
|
@ -250,9 +250,9 @@ void AlsaPlayer::initMixer()
|
||||||
LOG(DEBUG, LOG_TAG) << "initMixer\n";
|
LOG(DEBUG, LOG_TAG) << "initMixer\n";
|
||||||
std::lock_guard<std::recursive_mutex> lock(rec_mutex_);
|
std::lock_guard<std::recursive_mutex> lock(rec_mutex_);
|
||||||
int err;
|
int err;
|
||||||
if ((err = snd_ctl_open(&ctl_, mixer_device_.c_str(), SND_CTL_READONLY)) < 0)
|
if (err = snd_ctl_open(&ctl_, mixer_device_.c_str(), SND_CTL_READONLY); err < 0)
|
||||||
throw SnapException("Can't open control for " + mixer_device_ + ", error: " + snd_strerror(err));
|
throw SnapException("Can't open control for " + mixer_device_ + ", error: " + snd_strerror(err));
|
||||||
if ((err = snd_ctl_subscribe_events(ctl_, 1)) < 0)
|
if (err = snd_ctl_subscribe_events(ctl_, 1); err < 0)
|
||||||
throw SnapException("Can't subscribe for events for " + mixer_device_ + ", error: " + snd_strerror(err));
|
throw SnapException("Can't subscribe for events for " + mixer_device_ + ", error: " + snd_strerror(err));
|
||||||
fd_ = std::unique_ptr<pollfd, std::function<void(pollfd*)>>(new pollfd(), [](pollfd* p)
|
fd_ = std::unique_ptr<pollfd, std::function<void(pollfd*)>>(new pollfd(), [](pollfd* p)
|
||||||
{
|
{
|
||||||
|
@ -270,13 +270,13 @@ void AlsaPlayer::initMixer()
|
||||||
snd_mixer_selem_id_set_index(sid, mix_index);
|
snd_mixer_selem_id_set_index(sid, mix_index);
|
||||||
snd_mixer_selem_id_set_name(sid, mixer_name_.c_str());
|
snd_mixer_selem_id_set_name(sid, mixer_name_.c_str());
|
||||||
|
|
||||||
if ((err = snd_mixer_open(&mixer_, 0)) < 0)
|
if (err = snd_mixer_open(&mixer_, 0); err < 0)
|
||||||
throw SnapException(std::string("Failed to open mixer, error: ") + snd_strerror(err));
|
throw SnapException(std::string("Failed to open mixer, error: ") + snd_strerror(err));
|
||||||
if ((err = snd_mixer_attach(mixer_, mixer_device_.c_str())) < 0)
|
if (err = snd_mixer_attach(mixer_, mixer_device_.c_str()); err < 0)
|
||||||
throw SnapException("Failed to attach mixer to " + mixer_device_ + ", error: " + snd_strerror(err));
|
throw SnapException("Failed to attach mixer to " + mixer_device_ + ", error: " + snd_strerror(err));
|
||||||
if ((err = snd_mixer_selem_register(mixer_, nullptr, nullptr)) < 0)
|
if (err = snd_mixer_selem_register(mixer_, nullptr, nullptr); err < 0)
|
||||||
throw SnapException(std::string("Failed to register selem, error: ") + snd_strerror(err));
|
throw SnapException(std::string("Failed to register selem, error: ") + snd_strerror(err));
|
||||||
if ((err = snd_mixer_load(mixer_)) < 0)
|
if (err = snd_mixer_load(mixer_); err < 0)
|
||||||
throw SnapException(std::string("Failed to load mixer, error: ") + snd_strerror(err));
|
throw SnapException(std::string("Failed to load mixer, error: ") + snd_strerror(err));
|
||||||
elem_ = snd_mixer_find_selem(mixer_, sid);
|
elem_ = snd_mixer_find_selem(mixer_, sid);
|
||||||
if (elem_ == nullptr)
|
if (elem_ == nullptr)
|
||||||
|
@ -297,7 +297,7 @@ void AlsaPlayer::initAlsa()
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
// Open the PCM device in playback mode
|
// Open the PCM device in playback mode
|
||||||
if ((err = snd_pcm_open(&handle_, settings_.pcm_device.name.c_str(), SND_PCM_STREAM_PLAYBACK, 0)) < 0)
|
if (err = snd_pcm_open(&handle_, settings_.pcm_device.name.c_str(), SND_PCM_STREAM_PLAYBACK, 0); err < 0)
|
||||||
throw SnapException("Can't open " + settings_.pcm_device.name + ", error: " + snd_strerror(err), err);
|
throw SnapException("Can't open " + settings_.pcm_device.name + ", error: " + snd_strerror(err), err);
|
||||||
|
|
||||||
// struct snd_pcm_playback_info_t pinfo;
|
// struct snd_pcm_playback_info_t pinfo;
|
||||||
|
@ -308,7 +308,7 @@ void AlsaPlayer::initAlsa()
|
||||||
// Allocate parameters object and fill it with default values
|
// Allocate parameters object and fill it with default values
|
||||||
snd_pcm_hw_params_t* params;
|
snd_pcm_hw_params_t* params;
|
||||||
snd_pcm_hw_params_alloca(¶ms);
|
snd_pcm_hw_params_alloca(¶ms);
|
||||||
if ((err = snd_pcm_hw_params_any(handle_, params)) < 0)
|
if (err = snd_pcm_hw_params_any(handle_, params); err < 0)
|
||||||
throw SnapException("Can't fill params: " + string(snd_strerror(err)));
|
throw SnapException("Can't fill params: " + string(snd_strerror(err)));
|
||||||
|
|
||||||
snd_output_t* output;
|
snd_output_t* output;
|
||||||
|
@ -324,7 +324,7 @@ void AlsaPlayer::initAlsa()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set parameters
|
// Set parameters
|
||||||
if ((err = snd_pcm_hw_params_set_access(handle_, params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
|
if (err = snd_pcm_hw_params_set_access(handle_, params, SND_PCM_ACCESS_RW_INTERLEAVED); err < 0)
|
||||||
throw SnapException("Can't set interleaved mode: " + string(snd_strerror(err)));
|
throw SnapException("Can't set interleaved mode: " + string(snd_strerror(err)));
|
||||||
|
|
||||||
snd_pcm_format_t snd_pcm_format;
|
snd_pcm_format_t snd_pcm_format;
|
||||||
|
@ -367,17 +367,17 @@ void AlsaPlayer::initAlsa()
|
||||||
throw SnapException(ss.str());
|
throw SnapException(ss.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((err = snd_pcm_hw_params_set_channels(handle_, params, channels)) < 0)
|
if (err = snd_pcm_hw_params_set_channels(handle_, params, channels); err < 0)
|
||||||
throw SnapException("Can't set channel count: " + string(snd_strerror(err)));
|
throw SnapException("Can't set channel count: " + string(snd_strerror(err)));
|
||||||
|
|
||||||
if ((err = snd_pcm_hw_params_set_rate_near(handle_, params, &rate, nullptr)) < 0)
|
if (err = snd_pcm_hw_params_set_rate_near(handle_, params, &rate, nullptr); err < 0)
|
||||||
throw SnapException("Can't set rate: " + string(snd_strerror(err)));
|
throw SnapException("Can't set rate: " + string(snd_strerror(err)));
|
||||||
if (rate != format.rate())
|
if (rate != format.rate())
|
||||||
LOG(WARNING, LOG_TAG) << "Could not set sample rate to " << format.rate() << " Hz, using: " << rate << " Hz\n";
|
LOG(WARNING, LOG_TAG) << "Could not set sample rate to " << format.rate() << " Hz, using: " << rate << " Hz\n";
|
||||||
|
|
||||||
uint32_t period_time = buffer_time_.value_or(BUFFER_TIME).count() / periods_.value_or(PERIODS);
|
uint32_t period_time = buffer_time_.value_or(BUFFER_TIME).count() / periods_.value_or(PERIODS);
|
||||||
uint32_t max_period_time = period_time;
|
uint32_t max_period_time = period_time;
|
||||||
if ((err = snd_pcm_hw_params_get_period_time_max(params, &max_period_time, nullptr)) < 0)
|
if (err = snd_pcm_hw_params_get_period_time_max(params, &max_period_time, nullptr); err < 0)
|
||||||
{
|
{
|
||||||
LOG(ERROR, LOG_TAG) << "Can't get max period time: " << snd_strerror(err) << "\n";
|
LOG(ERROR, LOG_TAG) << "Can't get max period time: " << snd_strerror(err) << "\n";
|
||||||
}
|
}
|
||||||
|
@ -390,7 +390,7 @@ void AlsaPlayer::initAlsa()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
uint32_t min_period_time = period_time;
|
uint32_t min_period_time = period_time;
|
||||||
if ((err = snd_pcm_hw_params_get_period_time_min(params, &min_period_time, nullptr)) < 0)
|
if (err = snd_pcm_hw_params_get_period_time_min(params, &min_period_time, nullptr); err < 0)
|
||||||
{
|
{
|
||||||
LOG(ERROR, LOG_TAG) << "Can't get min period time: " << snd_strerror(err) << "\n";
|
LOG(ERROR, LOG_TAG) << "Can't get min period time: " << snd_strerror(err) << "\n";
|
||||||
}
|
}
|
||||||
|
@ -403,7 +403,7 @@ void AlsaPlayer::initAlsa()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((err = snd_pcm_hw_params_set_period_time_near(handle_, params, &period_time, nullptr)) < 0)
|
if (err = snd_pcm_hw_params_set_period_time_near(handle_, params, &period_time, nullptr); err < 0)
|
||||||
throw SnapException("Can't set period time: " + string(snd_strerror(err)));
|
throw SnapException("Can't set period time: " + string(snd_strerror(err)));
|
||||||
|
|
||||||
uint32_t buffer_time = buffer_time_.value_or(BUFFER_TIME).count();
|
uint32_t buffer_time = buffer_time_.value_or(BUFFER_TIME).count();
|
||||||
|
@ -415,15 +415,15 @@ void AlsaPlayer::initAlsa()
|
||||||
buffer_time = period_time * periods;
|
buffer_time = period_time * periods;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((err = snd_pcm_hw_params_set_buffer_time_near(handle_, params, &buffer_time, nullptr)) < 0)
|
if (err = snd_pcm_hw_params_set_buffer_time_near(handle_, params, &buffer_time, nullptr); err < 0)
|
||||||
throw SnapException("Can't set buffer time to " + cpt::to_string(buffer_time) + " us : " + string(snd_strerror(err)));
|
throw SnapException("Can't set buffer time to " + cpt::to_string(buffer_time) + " us : " + string(snd_strerror(err)));
|
||||||
|
|
||||||
// unsigned int periods = periods_;
|
// unsigned int periods = periods_;
|
||||||
// if ((err = snd_pcm_hw_params_set_periods_near(handle_, params, &periods, 0)) < 0)
|
// if (err = snd_pcm_hw_params_set_periods_near(handle_, params, &periods, 0); err < 0)
|
||||||
// throw SnapException("Can't set periods: " + string(snd_strerror(err)));
|
// throw SnapException("Can't set periods: " + string(snd_strerror(err)));
|
||||||
|
|
||||||
// Write parameters
|
// Write parameters
|
||||||
if ((err = snd_pcm_hw_params(handle_, params)) < 0)
|
if (err = snd_pcm_hw_params(handle_, params); err < 0)
|
||||||
throw SnapException("Can't set hardware parameters: " + string(snd_strerror(err)));
|
throw SnapException("Can't set hardware parameters: " + string(snd_strerror(err)));
|
||||||
|
|
||||||
// Resume information
|
// Resume information
|
||||||
|
@ -447,7 +447,7 @@ void AlsaPlayer::initAlsa()
|
||||||
|
|
||||||
if (snd_pcm_state(handle_) == SND_PCM_STATE_PREPARED)
|
if (snd_pcm_state(handle_) == SND_PCM_STATE_PREPARED)
|
||||||
{
|
{
|
||||||
if ((err = snd_pcm_start(handle_)) < 0)
|
if (err = snd_pcm_start(handle_); err < 0)
|
||||||
LOG(DEBUG, LOG_TAG) << "Failed to start PCM: " << snd_strerror(err) << "\n";
|
LOG(DEBUG, LOG_TAG) << "Failed to start PCM: " << snd_strerror(err) << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -518,7 +518,7 @@ void AlsaPlayer::start()
|
||||||
|
|
||||||
AlsaPlayer::~AlsaPlayer()
|
AlsaPlayer::~AlsaPlayer()
|
||||||
{
|
{
|
||||||
stop();
|
stop(); // NOLINT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -86,7 +86,7 @@ FilePlayer::FilePlayer(boost::asio::io_context& io_context, const ClientSettings
|
||||||
FilePlayer::~FilePlayer()
|
FilePlayer::~FilePlayer()
|
||||||
{
|
{
|
||||||
LOG(DEBUG, LOG_TAG) << "Destructor\n";
|
LOG(DEBUG, LOG_TAG) << "Destructor\n";
|
||||||
stop();
|
stop(); // NOLINT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -96,7 +96,7 @@ Player::Player(boost::asio::io_context& io_context, const ClientSettings::Player
|
||||||
|
|
||||||
Player::~Player()
|
Player::~Player()
|
||||||
{
|
{
|
||||||
stop();
|
stop(); // NOLINT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -171,7 +171,7 @@ PulsePlayer::PulsePlayer(boost::asio::io_context& io_context, const ClientSettin
|
||||||
PulsePlayer::~PulsePlayer()
|
PulsePlayer::~PulsePlayer()
|
||||||
{
|
{
|
||||||
LOG(DEBUG, LOG_TAG) << "Destructor\n";
|
LOG(DEBUG, LOG_TAG) << "Destructor\n";
|
||||||
stop();
|
stop(); // NOLINT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -491,6 +491,7 @@ void PulsePlayer::connect()
|
||||||
if (settings_.pcm_device.name != DEFAULT_DEVICE)
|
if (settings_.pcm_device.name != DEFAULT_DEVICE)
|
||||||
device = settings_.pcm_device.name.c_str();
|
device = settings_.pcm_device.name.c_str();
|
||||||
|
|
||||||
|
// NOLINTBEGIN
|
||||||
int result = pa_stream_connect_playback(
|
int result = pa_stream_connect_playback(
|
||||||
playstream_, device, &bufattr_, static_cast<pa_stream_flags>(PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_ADJUST_LATENCY | PA_STREAM_AUTO_TIMING_UPDATE),
|
playstream_, device, &bufattr_, static_cast<pa_stream_flags>(PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_ADJUST_LATENCY | PA_STREAM_AUTO_TIMING_UPDATE),
|
||||||
nullptr, nullptr);
|
nullptr, nullptr);
|
||||||
|
@ -500,6 +501,7 @@ void PulsePlayer::connect()
|
||||||
result = pa_stream_connect_playback(playstream_, device, &bufattr_,
|
result = pa_stream_connect_playback(playstream_, device, &bufattr_,
|
||||||
static_cast<pa_stream_flags>(PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE), nullptr, nullptr);
|
static_cast<pa_stream_flags>(PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE), nullptr, nullptr);
|
||||||
}
|
}
|
||||||
|
// NOLINTEND
|
||||||
if (result < 0)
|
if (result < 0)
|
||||||
throw SnapException("Failed to connect PulseAudio playback stream");
|
throw SnapException("Failed to connect PulseAudio playback stream");
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
This file is part of snapcast
|
||||||
Copyright (C) 2014-2024 Johannes Pohl
|
Copyright (C) 2014-2025 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,8 +25,8 @@
|
||||||
#include "common/utils/file_utils.hpp"
|
#include "common/utils/file_utils.hpp"
|
||||||
|
|
||||||
// standard headers
|
// standard headers
|
||||||
|
#include <array>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <grp.h>
|
#include <grp.h>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
|
@ -36,11 +36,11 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
|
||||||
Daemon::Daemon(const std::string& user, const std::string& group, const std::string& pidfile)
|
Daemon::Daemon(std::string user, std::string group, std::string pidfile)
|
||||||
: pidFilehandle_(-1), user_(user), group_(group), pidfile_(pidfile)
|
: pidFilehandle_(-1), user_(std::move(user)), group_(std::move(group)), pidfile_(std::move(pidfile))
|
||||||
{
|
{
|
||||||
if (pidfile.empty() || pidfile.find('/') == std::string::npos)
|
if (pidfile_.empty() || pidfile_.find('/') == std::string::npos)
|
||||||
throw SnapException("invalid pid file \"" + pidfile + "\"");
|
throw SnapException("invalid pid file \"" + pidfile_ + "\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -152,12 +152,12 @@ void Daemon::daemonize()
|
||||||
if (lockf(pidFilehandle_, F_TLOCK, 0) == -1)
|
if (lockf(pidFilehandle_, F_TLOCK, 0) == -1)
|
||||||
throw SnapException("Could not lock PID lock file \"" + pidfile_ + "\". Is the daemon already running?");
|
throw SnapException("Could not lock PID lock file \"" + pidfile_ + "\". Is the daemon already running?");
|
||||||
|
|
||||||
char str[10];
|
std::array<char, 10> str;
|
||||||
/// Get and format PID
|
/// Get and format PID
|
||||||
sprintf(str, "%d\n", getpid());
|
sprintf(str.data(), "%d\n", getpid());
|
||||||
|
|
||||||
/// write pid to lockfile
|
/// write pid to lockfile
|
||||||
if (write(pidFilehandle_, str, strlen(str)) != static_cast<int>(strlen(str)))
|
if (write(pidFilehandle_, str.data(), str.size()) != static_cast<int>(str.size()))
|
||||||
throw SnapException("Could not write PID to lock file \"" + pidfile_ + "\"");
|
throw SnapException("Could not write PID to lock file \"" + pidfile_ + "\"");
|
||||||
|
|
||||||
/// Close out the standard file descriptors
|
/// Close out the standard file descriptors
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
This file is part of snapcast
|
||||||
Copyright (C) 2014-2024 Johannes Pohl
|
Copyright (C) 2014-2025 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
|
||||||
|
@ -22,13 +22,16 @@
|
||||||
// standard headers
|
// standard headers
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
/// Daemonize a process: run a fork as specified user/group
|
||||||
class Daemon
|
class Daemon
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Daemon(const std::string& user, const std::string& group, const std::string& pidfile);
|
/// c'tor
|
||||||
|
Daemon(std::string user, std::string group, std::string pidfile);
|
||||||
|
/// d'tor
|
||||||
virtual ~Daemon();
|
virtual ~Daemon();
|
||||||
|
|
||||||
|
/// daemonize the process
|
||||||
void daemonize();
|
void daemonize();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
This file is part of snapcast
|
||||||
Copyright (C) 2014-2024 Johannes Pohl
|
Copyright (C) 2014-2025 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
|
||||||
|
@ -112,9 +112,9 @@ struct ErrorOr
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @return the moved value
|
/// @return the moved value
|
||||||
T takeValue()
|
T&& takeValue()
|
||||||
{
|
{
|
||||||
return std::move(std::get<T>(var));
|
return std::get<T>(std::move(var));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @return the error
|
/// @return the error
|
||||||
|
@ -124,10 +124,9 @@ struct ErrorOr
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @return the moved error
|
/// @return the moved error
|
||||||
ErrorCode takeError()
|
ErrorCode&& takeError()
|
||||||
{
|
{
|
||||||
auto ec = std::move(std::get<ErrorCode>(var));
|
return std::get<ErrorCode>(std::move(var));
|
||||||
return ec;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -45,12 +45,13 @@ Config::~Config()
|
||||||
void Config::init(const std::string& root_directory, const std::string& user, const std::string& group)
|
void Config::init(const std::string& root_directory, const std::string& user, const std::string& group)
|
||||||
{
|
{
|
||||||
string dir;
|
string dir;
|
||||||
|
auto home = getenv("HOME");
|
||||||
if (!root_directory.empty())
|
if (!root_directory.empty())
|
||||||
dir = root_directory;
|
dir = root_directory;
|
||||||
else if (getenv("HOME") == nullptr)
|
else if (home == nullptr)
|
||||||
dir = "/var/lib/snapserver/";
|
dir = "/var/lib/snapserver/";
|
||||||
else
|
else
|
||||||
dir = string(getenv("HOME")) + "/.config/snapserver/";
|
dir = string{home} + "/.config/snapserver/";
|
||||||
|
|
||||||
if (!dir.empty() && (dir.back() != '/'))
|
if (!dir.empty() && (dir.back() != '/'))
|
||||||
dir += "/";
|
dir += "/";
|
||||||
|
|
|
@ -165,7 +165,7 @@ ControlSessionHttp::ControlSessionHttp(ControlMessageReceiver* receiver, tcp_soc
|
||||||
ControlSessionHttp::~ControlSessionHttp()
|
ControlSessionHttp::~ControlSessionHttp()
|
||||||
{
|
{
|
||||||
LOG(DEBUG, LOG_TAG) << "ControlSessionHttp::~ControlSessionHttp()\n";
|
LOG(DEBUG, LOG_TAG) << "ControlSessionHttp::~ControlSessionHttp()\n";
|
||||||
stop();
|
stop(); // NOLINT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -462,7 +462,7 @@ void ControlSessionHttp::on_read(beast::error_code ec, std::size_t bytes_transfe
|
||||||
// The lifetime of the message has to extend
|
// The lifetime of the message has to extend
|
||||||
// for the duration of the async operation so
|
// for the duration of the async operation so
|
||||||
// we use a shared_ptr to manage it.
|
// we use a shared_ptr to manage it.
|
||||||
using response_type = typename std::decay<decltype(response)>::type;
|
using response_type = typename std::decay<decltype(response)>::type; // NOLINT
|
||||||
auto sp = std::make_shared<response_type>(std::forward<decltype(response)>(response));
|
auto sp = std::make_shared<response_type>(std::forward<decltype(response)>(response));
|
||||||
|
|
||||||
// Write the response
|
// Write the response
|
||||||
|
|
|
@ -45,7 +45,7 @@ ControlSessionTcp::ControlSessionTcp(ControlMessageReceiver* receiver, tcp::sock
|
||||||
ControlSessionTcp::~ControlSessionTcp()
|
ControlSessionTcp::~ControlSessionTcp()
|
||||||
{
|
{
|
||||||
LOG(DEBUG, LOG_TAG) << "ControlSessionTcp::~ControlSessionTcp()\n";
|
LOG(DEBUG, LOG_TAG) << "ControlSessionTcp::~ControlSessionTcp()\n";
|
||||||
stop();
|
stop(); // NOLINT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,7 @@ ControlSessionWebsocket::ControlSessionWebsocket(ControlMessageReceiver* receive
|
||||||
ControlSessionWebsocket::~ControlSessionWebsocket()
|
ControlSessionWebsocket::~ControlSessionWebsocket()
|
||||||
{
|
{
|
||||||
LOG(DEBUG, LOG_TAG) << "ControlSessionWebsocket::~ControlSessionWebsocket()\n";
|
LOG(DEBUG, LOG_TAG) << "ControlSessionWebsocket::~ControlSessionWebsocket()\n";
|
||||||
stop();
|
stop(); // NOLINT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
|
|
||||||
// standard headers
|
// standard headers
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
@ -41,7 +42,7 @@ static constexpr auto LOG_TAG = "FlacEnc";
|
||||||
|
|
||||||
FlacEncoder::FlacEncoder(const std::string& codecOptions) : Encoder(codecOptions), encoder_(nullptr), pcmBufferSize_(0), encodedSamples_(0), flacChunk_(nullptr)
|
FlacEncoder::FlacEncoder(const std::string& codecOptions) : Encoder(codecOptions), encoder_(nullptr), pcmBufferSize_(0), encodedSamples_(0), flacChunk_(nullptr)
|
||||||
{
|
{
|
||||||
headerChunk_.reset(new msg::CodecHeader("flac"));
|
headerChunk_ = std::make_shared<msg::CodecHeader>("flac");
|
||||||
pcmBuffer_ = static_cast<FLAC__int32*>(malloc(pcmBufferSize_ * sizeof(FLAC__int32)));
|
pcmBuffer_ = static_cast<FLAC__int32*>(malloc(pcmBufferSize_ * sizeof(FLAC__int32)));
|
||||||
metadata_[0] = nullptr;
|
metadata_[0] = nullptr;
|
||||||
metadata_[1] = nullptr;
|
metadata_[1] = nullptr;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
This file is part of snapcast
|
||||||
Copyright (C) 2014-2024 Johannes Pohl
|
Copyright (C) 2014-2025 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
|
||||||
|
@ -22,6 +22,9 @@
|
||||||
// local headers
|
// local headers
|
||||||
#include "common/aixlog.hpp"
|
#include "common/aixlog.hpp"
|
||||||
|
|
||||||
|
// standard headers
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
|
||||||
namespace encoder
|
namespace encoder
|
||||||
{
|
{
|
||||||
|
@ -30,7 +33,7 @@ static constexpr auto LOG_TAG = "NullEnc";
|
||||||
|
|
||||||
NullEncoder::NullEncoder(const std::string& codecOptions) : Encoder(codecOptions)
|
NullEncoder::NullEncoder(const std::string& codecOptions) : Encoder(codecOptions)
|
||||||
{
|
{
|
||||||
headerChunk_.reset(new msg::CodecHeader("null"));
|
headerChunk_ = std::make_shared<msg::CodecHeader>("null");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
This file is part of snapcast
|
||||||
Copyright (C) 2014-2024 Johannes Pohl
|
Copyright (C) 2014-2025 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
|
||||||
|
@ -28,6 +28,7 @@
|
||||||
// standard headers
|
// standard headers
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
@ -238,8 +239,8 @@ void OggEncoder::initEncoder()
|
||||||
/* set up our packet->stream encoder */
|
/* set up our packet->stream encoder */
|
||||||
/* pick a random serial number; that way we can more likely build
|
/* pick a random serial number; that way we can more likely build
|
||||||
chained streams just by concatenation */
|
chained streams just by concatenation */
|
||||||
srand(time(nullptr));
|
srand(time(nullptr)); // NOLINT
|
||||||
ogg_stream_init(&os_, rand());
|
ogg_stream_init(&os_, rand()); // NOLINT
|
||||||
|
|
||||||
/* Vorbis streams begin with three headers; the initial header (with
|
/* Vorbis streams begin with three headers; the initial header (with
|
||||||
most of the codec setup parameters) which is mandated by the Ogg
|
most of the codec setup parameters) which is mandated by the Ogg
|
||||||
|
@ -261,7 +262,7 @@ void OggEncoder::initEncoder()
|
||||||
* audio data will start on a new page, as per spec
|
* audio data will start on a new page, as per spec
|
||||||
*/
|
*/
|
||||||
size_t pos(0);
|
size_t pos(0);
|
||||||
headerChunk_.reset(new msg::CodecHeader("ogg"));
|
headerChunk_ = std::make_shared<msg::CodecHeader>("ogg");
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
int result = ogg_stream_flush(&os_, &og_);
|
int result = ogg_stream_flush(&os_, &og_);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/***
|
/***
|
||||||
This file is part of snapcast
|
This file is part of snapcast
|
||||||
Copyright (C) 2014-2024 Johannes Pohl
|
Copyright (C) 2014-2025 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
|
||||||
|
@ -50,7 +50,7 @@ void assign(void* pointer, T val)
|
||||||
|
|
||||||
PcmEncoder::PcmEncoder(const std::string& codecOptions) : Encoder(codecOptions)
|
PcmEncoder::PcmEncoder(const std::string& codecOptions) : Encoder(codecOptions)
|
||||||
{
|
{
|
||||||
headerChunk_.reset(new msg::CodecHeader("pcm"));
|
headerChunk_ = std::make_shared<msg::CodecHeader>("pcm");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -45,18 +45,18 @@ void PublishAvahi::publish(const std::vector<mDNSService>& services)
|
||||||
{
|
{
|
||||||
services_ = services;
|
services_ = services;
|
||||||
|
|
||||||
/// Allocate main loop object
|
// Allocate main loop object
|
||||||
if ((simple_poll = avahi_simple_poll_new()) == nullptr)
|
if ((simple_poll = avahi_simple_poll_new()) == nullptr)
|
||||||
{
|
{
|
||||||
/// TODO: error handling
|
// TODO: error handling
|
||||||
LOG(ERROR, LOG_TAG) << "Failed to create simple poll object.\n";
|
LOG(ERROR, LOG_TAG) << "Failed to create simple poll object.\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Allocate a new client
|
// Allocate a new client
|
||||||
int error;
|
int error;
|
||||||
client_ = avahi_client_new(avahi_simple_poll_get(simple_poll), AVAHI_CLIENT_IGNORE_USER_CONFIG, client_callback, this, &error);
|
client_ = avahi_client_new(avahi_simple_poll_get(simple_poll), AVAHI_CLIENT_IGNORE_USER_CONFIG, client_callback, this, &error);
|
||||||
|
|
||||||
/// Check wether creating the client object succeeded
|
// Check wether creating the client object succeeded
|
||||||
if (client_ == nullptr)
|
if (client_ == nullptr)
|
||||||
{
|
{
|
||||||
LOG(ERROR, LOG_TAG) << "Failed to create client: " << avahi_strerror(error) << "\n";
|
LOG(ERROR, LOG_TAG) << "Failed to create client: " << avahi_strerror(error) << "\n";
|
||||||
|
@ -96,11 +96,11 @@ void PublishAvahi::entry_group_callback(AvahiEntryGroup* g, AvahiEntryGroupState
|
||||||
assert(g == group || group == nullptr);
|
assert(g == group || group == nullptr);
|
||||||
group = g;
|
group = g;
|
||||||
|
|
||||||
/// Called whenever the entry group state changes
|
// Called whenever the entry group state changes
|
||||||
switch (state)
|
switch (state)
|
||||||
{
|
{
|
||||||
case AVAHI_ENTRY_GROUP_ESTABLISHED:
|
case AVAHI_ENTRY_GROUP_ESTABLISHED:
|
||||||
/// The entry group has been established successfully
|
// The entry group has been established successfully
|
||||||
LOG(INFO, LOG_TAG) << "Service '" << name << "' successfully established.\n";
|
LOG(INFO, LOG_TAG) << "Service '" << name << "' successfully established.\n";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -108,14 +108,14 @@ void PublishAvahi::entry_group_callback(AvahiEntryGroup* g, AvahiEntryGroupState
|
||||||
{
|
{
|
||||||
char* n;
|
char* n;
|
||||||
|
|
||||||
/// A service name collision with a remote service happened. Let's pick a new name
|
// A service name collision with a remote service happened. Let's pick a new name
|
||||||
n = avahi_alternative_service_name(name);
|
n = avahi_alternative_service_name(name);
|
||||||
avahi_free(name);
|
avahi_free(name);
|
||||||
name = n;
|
name = n;
|
||||||
|
|
||||||
LOG(NOTICE, LOG_TAG) << "Service name collision, renaming service to '" << name << "'\n";
|
LOG(NOTICE, LOG_TAG) << "Service name collision, renaming service to '" << name << "'\n";
|
||||||
|
|
||||||
/// And recreate the services
|
// And recreate the services
|
||||||
static_cast<PublishAvahi*>(userdata)->create_services(avahi_entry_group_get_client(g));
|
static_cast<PublishAvahi*>(userdata)->create_services(avahi_entry_group_get_client(g));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -124,7 +124,7 @@ void PublishAvahi::entry_group_callback(AvahiEntryGroup* g, AvahiEntryGroupState
|
||||||
|
|
||||||
LOG(ERROR, LOG_TAG) << "Entry group failure: " << avahi_strerror(avahi_client_errno(avahi_entry_group_get_client(g))) << "\n";
|
LOG(ERROR, LOG_TAG) << "Entry group failure: " << avahi_strerror(avahi_client_errno(avahi_entry_group_get_client(g))) << "\n";
|
||||||
|
|
||||||
/// Some kind of failure happened while we were registering our services
|
// Some kind of failure happened while we were registering our services
|
||||||
avahi_simple_poll_quit(simple_poll);
|
avahi_simple_poll_quit(simple_poll);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -138,7 +138,7 @@ void PublishAvahi::create_services(AvahiClient* c)
|
||||||
assert(c);
|
assert(c);
|
||||||
char* n;
|
char* n;
|
||||||
|
|
||||||
/// If this is the first time we're called, let's create a new entry group if necessary
|
// If this is the first time we're called, let's create a new entry group if necessary
|
||||||
if (group == nullptr)
|
if (group == nullptr)
|
||||||
{
|
{
|
||||||
if ((group = avahi_entry_group_new(c, entry_group_callback, this)) == nullptr)
|
if ((group = avahi_entry_group_new(c, entry_group_callback, this)) == nullptr)
|
||||||
|
@ -148,15 +148,16 @@ void PublishAvahi::create_services(AvahiClient* c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If the group is empty (either because it was just created, or because it was reset previously, add our entries.
|
// If the group is empty (either because it was just created, or because it was reset previously, add our entries.
|
||||||
int ret;
|
int ret;
|
||||||
if (avahi_entry_group_is_empty(group) != 0)
|
if (avahi_entry_group_is_empty(group) != 0)
|
||||||
{
|
{
|
||||||
LOG(INFO, LOG_TAG) << "Adding service '" << name << "'\n";
|
LOG(INFO, LOG_TAG) << "Adding service '" << name << "'\n";
|
||||||
|
|
||||||
/// We will now add two services and one subtype to the entry group
|
// We will now add two services and one subtype to the entry group
|
||||||
for (const auto& service : services_)
|
for (const auto& service : services_)
|
||||||
{
|
{
|
||||||
|
// NOLINTNEXTLINE
|
||||||
if ((ret = avahi_entry_group_add_service(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, AvahiPublishFlags(0), name, service.name_.c_str(), nullptr,
|
if ((ret = avahi_entry_group_add_service(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, AvahiPublishFlags(0), name, service.name_.c_str(), nullptr,
|
||||||
nullptr, service.port_, static_cast<char*>(nullptr))) < 0)
|
nullptr, service.port_, static_cast<char*>(nullptr))) < 0)
|
||||||
{
|
{
|
||||||
|
@ -168,7 +169,7 @@ void PublishAvahi::create_services(AvahiClient* c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add an additional (hypothetic) subtype
|
// Add an additional (hypothetic) subtype
|
||||||
/* if ((ret = avahi_entry_group_add_service_subtype(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, AvahiPublishFlags(0), name,
|
/* if ((ret = avahi_entry_group_add_service_subtype(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, AvahiPublishFlags(0), name,
|
||||||
"_printer._tcp",
|
"_printer._tcp",
|
||||||
NULL, "_magic._sub._printer._tcp") < 0))
|
NULL, "_magic._sub._printer._tcp") < 0))
|
||||||
|
@ -177,7 +178,7 @@ void PublishAvahi::create_services(AvahiClient* c)
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
/// Tell the server to register the service
|
// Tell the server to register the service
|
||||||
if ((ret = avahi_entry_group_commit(group)) < 0)
|
if ((ret = avahi_entry_group_commit(group)) < 0)
|
||||||
{
|
{
|
||||||
LOG(ERROR, LOG_TAG) << "Failed to commit entry group: " << avahi_strerror(ret) << "\n";
|
LOG(ERROR, LOG_TAG) << "Failed to commit entry group: " << avahi_strerror(ret) << "\n";
|
||||||
|
@ -189,7 +190,7 @@ void PublishAvahi::create_services(AvahiClient* c)
|
||||||
|
|
||||||
collision:
|
collision:
|
||||||
|
|
||||||
/// A service name collision with a local service happened. Let's pick a new name
|
// A service name collision with a local service happened. Let's pick a new name
|
||||||
n = avahi_alternative_service_name(name);
|
n = avahi_alternative_service_name(name);
|
||||||
avahi_free(name);
|
avahi_free(name);
|
||||||
name = n;
|
name = n;
|
||||||
|
@ -210,12 +211,12 @@ void PublishAvahi::client_callback(AvahiClient* c, AvahiClientState state, AVAHI
|
||||||
{
|
{
|
||||||
assert(c);
|
assert(c);
|
||||||
|
|
||||||
/// Called whenever the client or server state changes
|
// Called whenever the client or server state changes
|
||||||
switch (state)
|
switch (state)
|
||||||
{
|
{
|
||||||
case AVAHI_CLIENT_S_RUNNING:
|
case AVAHI_CLIENT_S_RUNNING:
|
||||||
|
|
||||||
/// The server has startup successfully and registered its host name on the network, so it's time to create our services
|
// The server has startup successfully and registered its host name on the network, so it's time to create our services
|
||||||
static_cast<PublishAvahi*>(userdata)->create_services(c);
|
static_cast<PublishAvahi*>(userdata)->create_services(c);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -227,13 +228,13 @@ void PublishAvahi::client_callback(AvahiClient* c, AvahiClientState state, AVAHI
|
||||||
|
|
||||||
case AVAHI_CLIENT_S_COLLISION:
|
case AVAHI_CLIENT_S_COLLISION:
|
||||||
|
|
||||||
/// Let's drop our registered services. When the server is back
|
// Let's drop our registered services. When the server is back
|
||||||
/// in AVAHI_SERVER_RUNNING state we will register them again with the new host name.
|
// in AVAHI_SERVER_RUNNING state we will register them again with the new host name.
|
||||||
|
|
||||||
case AVAHI_CLIENT_S_REGISTERING:
|
case AVAHI_CLIENT_S_REGISTERING:
|
||||||
|
|
||||||
/// The server records are now being established. This might be caused by a host name change. We need to wait
|
// The server records are now being established. This might be caused by a host name change. We need to wait
|
||||||
/// for our own records to register until the host name is properly esatblished.
|
// for our own records to register until the host name is properly esatblished.
|
||||||
|
|
||||||
if (group != nullptr)
|
if (group != nullptr)
|
||||||
avahi_entry_group_reset(group);
|
avahi_entry_group_reset(group);
|
||||||
|
|
|
@ -55,7 +55,7 @@ Server::Server(boost::asio::io_context& io_context, ServerSettings serverSetting
|
||||||
void Server::onNewSession(std::shared_ptr<StreamSession> session)
|
void Server::onNewSession(std::shared_ptr<StreamSession> session)
|
||||||
{
|
{
|
||||||
LOG(DEBUG, LOG_TAG) << "onNewSession\n";
|
LOG(DEBUG, LOG_TAG) << "onNewSession\n";
|
||||||
streamServer_->addSession(std::move(session));
|
streamServer_->addSession(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -36,8 +36,8 @@ using json = nlohmann::json;
|
||||||
|
|
||||||
static constexpr auto LOG_TAG = "StreamServer";
|
static constexpr auto LOG_TAG = "StreamServer";
|
||||||
|
|
||||||
StreamServer::StreamServer(boost::asio::io_context& io_context, const ServerSettings& serverSettings, StreamMessageReceiver* messageReceiver)
|
StreamServer::StreamServer(boost::asio::io_context& io_context, ServerSettings serverSettings, StreamMessageReceiver* messageReceiver)
|
||||||
: io_context_(io_context), config_timer_(io_context), settings_(serverSettings), messageReceiver_(messageReceiver)
|
: io_context_(io_context), config_timer_(io_context), settings_(std::move(serverSettings)), messageReceiver_(messageReceiver)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,14 +57,14 @@ void StreamServer::cleanup()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void StreamServer::addSession(std::shared_ptr<StreamSession> session)
|
void StreamServer::addSession(const std::shared_ptr<StreamSession>& session)
|
||||||
{
|
{
|
||||||
session->setMessageReceiver(this);
|
session->setMessageReceiver(this);
|
||||||
session->setBufferMs(settings_.stream.bufferMs);
|
session->setBufferMs(settings_.stream.bufferMs);
|
||||||
session->start();
|
session->start();
|
||||||
|
|
||||||
std::lock_guard<std::recursive_mutex> mlock(sessionsMutex_);
|
std::lock_guard<std::recursive_mutex> mlock(sessionsMutex_);
|
||||||
sessions_.emplace_back(std::move(session));
|
sessions_.emplace_back(session);
|
||||||
cleanup();
|
cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,7 +210,7 @@ void StreamServer::handleAccept(tcp::socket socket)
|
||||||
|
|
||||||
LOG(NOTICE, LOG_TAG) << "StreamServer::NewConnection: " << socket.remote_endpoint().address().to_string() << "\n";
|
LOG(NOTICE, LOG_TAG) << "StreamServer::NewConnection: " << socket.remote_endpoint().address().to_string() << "\n";
|
||||||
shared_ptr<StreamSession> session = make_shared<StreamSessionTcp>(this, settings_, std::move(socket));
|
shared_ptr<StreamSession> session = make_shared<StreamSessionTcp>(this, settings_, std::move(socket));
|
||||||
addSession(std::move(session));
|
addSession(session);
|
||||||
}
|
}
|
||||||
catch (const std::exception& e)
|
catch (const std::exception& e)
|
||||||
{
|
{
|
||||||
|
|
|
@ -54,7 +54,7 @@ class StreamServer : public StreamMessageReceiver
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// c'tor
|
/// c'tor
|
||||||
StreamServer(boost::asio::io_context& io_context, const ServerSettings& serverSettings, StreamMessageReceiver* messageReceiver = nullptr);
|
StreamServer(boost::asio::io_context& io_context, ServerSettings serverSettings, StreamMessageReceiver* messageReceiver = nullptr);
|
||||||
/// d'tor
|
/// d'tor
|
||||||
virtual ~StreamServer();
|
virtual ~StreamServer();
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ public:
|
||||||
// void send(const msg::BaseMessage* message);
|
// void send(const msg::BaseMessage* message);
|
||||||
|
|
||||||
/// Add a new stream session
|
/// Add a new stream session
|
||||||
void addSession(std::shared_ptr<StreamSession> session);
|
void addSession(const std::shared_ptr<StreamSession>& session);
|
||||||
/// Callback for chunks that are ready to be sent
|
/// Callback for chunks that are ready to be sent
|
||||||
void onChunkEncoded(const PcmStream* pcmStream, bool isDefaultStream, const std::shared_ptr<msg::PcmChunk>& chunk, double duration);
|
void onChunkEncoded(const PcmStream* pcmStream, bool isDefaultStream, const std::shared_ptr<msg::PcmChunk>& chunk, double duration);
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,7 @@ StreamSessionTcp::StreamSessionTcp(StreamMessageReceiver* receiver, const Server
|
||||||
StreamSessionTcp::~StreamSessionTcp()
|
StreamSessionTcp::~StreamSessionTcp()
|
||||||
{
|
{
|
||||||
LOG(DEBUG, LOG_TAG) << "~StreamSessionTcp\n";
|
LOG(DEBUG, LOG_TAG) << "~StreamSessionTcp\n";
|
||||||
stop();
|
stop(); // NOLINT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,7 @@ StreamSessionWebsocket::StreamSessionWebsocket(StreamMessageReceiver* receiver,
|
||||||
StreamSessionWebsocket::~StreamSessionWebsocket()
|
StreamSessionWebsocket::~StreamSessionWebsocket()
|
||||||
{
|
{
|
||||||
LOG(DEBUG, LOG_TAG) << "~StreamSessionWS\n";
|
LOG(DEBUG, LOG_TAG) << "~StreamSessionWS\n";
|
||||||
stop();
|
stop(); // NOLINT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,10 @@
|
||||||
#include "common/snap_exception.hpp"
|
#include "common/snap_exception.hpp"
|
||||||
#include "common/utils/file_utils.hpp"
|
#include "common/utils/file_utils.hpp"
|
||||||
|
|
||||||
|
// standard headers
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
namespace streamreader
|
namespace streamreader
|
||||||
|
@ -38,8 +42,9 @@ string hex2str(const string& input)
|
||||||
{
|
{
|
||||||
using byte = unsigned char;
|
using byte = unsigned char;
|
||||||
unsigned long x = strtoul(input.c_str(), nullptr, 16);
|
unsigned long x = strtoul(input.c_str(), nullptr, 16);
|
||||||
|
// NOLINTNEXTLINE
|
||||||
byte a[] = {byte(x >> 24), byte(x >> 16), byte(x >> 8), byte(x), 0};
|
byte a[] = {byte(x >> 24), byte(x >> 16), byte(x >> 8), byte(x), 0};
|
||||||
return string(reinterpret_cast<char*>(a));
|
return reinterpret_cast<char*>(a);
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
@ -323,7 +328,7 @@ void XMLCALL AirplayStream::element_start(void* userdata, const char* element_na
|
||||||
|
|
||||||
self->buf_.assign("");
|
self->buf_.assign("");
|
||||||
if (name == "item")
|
if (name == "item")
|
||||||
self->entry_.reset(new TageEntry);
|
self->entry_ = std::make_unique<TageEntry>();
|
||||||
|
|
||||||
for (int i = 0; attr[i] != nullptr; i += 2)
|
for (int i = 0; attr[i] != nullptr; i += 2)
|
||||||
{
|
{
|
||||||
|
|
|
@ -220,7 +220,7 @@ void JackStream::tryConnect()
|
||||||
bool JackStream::openJackConnection()
|
bool JackStream::openJackConnection()
|
||||||
{
|
{
|
||||||
char* serverName = serverName_.data();
|
char* serverName = serverName_.data();
|
||||||
jack_options_t options = (jack_options_t)(JackNoStartServer | JackServerName);
|
auto options = static_cast<jack_options_t>(JackNoStartServer | JackServerName); // NOLINT
|
||||||
|
|
||||||
client_ = jack_client_open(name_.c_str(), options, nullptr, serverName);
|
client_ = jack_client_open(name_.c_str(), options, nullptr, serverName);
|
||||||
if (client_ == nullptr)
|
if (client_ == nullptr)
|
||||||
|
|
|
@ -69,7 +69,7 @@ MetaStream::MetaStream(PcmStream::Listener* pcmListener, const std::vector<std::
|
||||||
|
|
||||||
MetaStream::~MetaStream()
|
MetaStream::~MetaStream()
|
||||||
{
|
{
|
||||||
stop();
|
stop(); // NOLINT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -45,9 +45,9 @@ namespace streamreader
|
||||||
static constexpr auto LOG_TAG = "PcmStream";
|
static constexpr auto LOG_TAG = "PcmStream";
|
||||||
|
|
||||||
|
|
||||||
PcmStream::PcmStream(PcmStream::Listener* pcmListener, boost::asio::io_context& ioc, const ServerSettings& server_settings, const StreamUri& uri)
|
PcmStream::PcmStream(PcmStream::Listener* pcmListener, boost::asio::io_context& ioc, ServerSettings server_settings, StreamUri uri)
|
||||||
: active_(false), strand_(boost::asio::make_strand(ioc.get_executor())), pcmListeners_{pcmListener}, uri_(uri), chunk_ms_(20), state_(ReaderState::kIdle),
|
: active_(false), strand_(boost::asio::make_strand(ioc.get_executor())), pcmListeners_{pcmListener}, uri_(std::move(uri)), chunk_ms_(20),
|
||||||
server_settings_(server_settings), req_id_(0), property_timer_(strand_)
|
state_(ReaderState::kIdle), server_settings_(std::move(server_settings)), req_id_(0), property_timer_(strand_)
|
||||||
{
|
{
|
||||||
encoder::EncoderFactory encoderFactory;
|
encoder::EncoderFactory encoderFactory;
|
||||||
if (uri_.query.find(kUriCodec) == uri_.query.end())
|
if (uri_.query.find(kUriCodec) == uri_.query.end())
|
||||||
|
@ -94,7 +94,7 @@ PcmStream::PcmStream(PcmStream::Listener* pcmListener, boost::asio::io_context&
|
||||||
|
|
||||||
PcmStream::~PcmStream()
|
PcmStream::~PcmStream()
|
||||||
{
|
{
|
||||||
stop();
|
stop(); // NOLINT
|
||||||
property_timer_.cancel();
|
property_timer_.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -124,7 +124,7 @@ public:
|
||||||
using ResultHandler = std::function<void(const snapcast::ErrorCode& ec)>;
|
using ResultHandler = std::function<void(const snapcast::ErrorCode& ec)>;
|
||||||
|
|
||||||
/// c'tor. Encoded PCM data is passed to the PcmStream::Listener
|
/// c'tor. Encoded PCM data is passed to the PcmStream::Listener
|
||||||
PcmStream(PcmStream::Listener* pcmListener, boost::asio::io_context& ioc, const ServerSettings& server_settings, const StreamUri& uri);
|
PcmStream(PcmStream::Listener* pcmListener, boost::asio::io_context& ioc, ServerSettings server_settings, StreamUri uri);
|
||||||
/// d'tor
|
/// d'tor
|
||||||
virtual ~PcmStream();
|
virtual ~PcmStream();
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,7 @@ namespace streamreader
|
||||||
static constexpr auto LOG_TAG = "Script";
|
static constexpr auto LOG_TAG = "Script";
|
||||||
|
|
||||||
|
|
||||||
StreamControl::StreamControl(const boost::asio::any_io_executor& executor) : executor_(executor)
|
StreamControl::StreamControl(const boost::asio::any_io_executor& executor) : executor_(executor) // NOLINT
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -494,8 +494,7 @@ TEST_CASE("Librespot2")
|
||||||
}
|
}
|
||||||
|
|
||||||
line = "[2021-06-04T07:20:47Z INFO librespot_playback::player] metadata:{\"ARTIST\":\"artist\",\"TITLE\":\"title\"}";
|
line = "[2021-06-04T07:20:47Z INFO librespot_playback::player] metadata:{\"ARTIST\":\"artist\",\"TITLE\":\"title\"}";
|
||||||
n = 0;
|
if (n = line.find("metadata:"); n != std::string::npos)
|
||||||
if (((n = line.find("metadata:")) != std::string::npos))
|
|
||||||
{
|
{
|
||||||
std::string meta = line.substr(n + 9);
|
std::string meta = line.substr(n + 9);
|
||||||
REQUIRE(meta == "{\"ARTIST\":\"artist\",\"TITLE\":\"title\"}");
|
REQUIRE(meta == "{\"ARTIST\":\"artist\",\"TITLE\":\"title\"}");
|
||||||
|
@ -679,7 +678,7 @@ TEST_CASE("ErrorOr")
|
||||||
// Move value out
|
// Move value out
|
||||||
REQUIRE(error_or.takeValue() == "test");
|
REQUIRE(error_or.takeValue() == "test");
|
||||||
// Value has been moved out, get will return an empty string
|
// Value has been moved out, get will return an empty string
|
||||||
REQUIRE(error_or.getValue().empty());
|
// REQUIRE(error_or.getValue().empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue