mirror of
https://github.com/badaix/snapcast.git
synced 2025-05-21 21:16:15 +02:00
Send initial hardware mixer volume to the server
This commit is contained in:
parent
2217595c6b
commit
e8bb8ecdba
7 changed files with 116 additions and 96 deletions
|
@ -157,21 +157,33 @@ void Controller::getNextMessage()
|
||||||
throw SnapException("No audio player support");
|
throw SnapException("No audio player support");
|
||||||
|
|
||||||
player_->setVolumeCallback([this](double volume, bool muted) {
|
player_->setVolumeCallback([this](double volume, bool muted) {
|
||||||
auto settings = std::make_shared<msg::ClientSettings>();
|
static double last_volume(-1);
|
||||||
settings->setVolume(static_cast<uint16_t>(volume * 100.));
|
static bool last_muted(true);
|
||||||
settings->setMuted(muted);
|
if ((volume != last_volume) || (last_muted != muted))
|
||||||
clientConnection_->send(settings, [this](const boost::system::error_code& ec) {
|
{
|
||||||
if (ec)
|
last_volume = volume;
|
||||||
{
|
last_muted = muted;
|
||||||
LOG(ERROR, LOG_TAG) << "Failed to send client settings, error: " << ec.message() << "\n";
|
auto settings = std::make_shared<msg::ClientSettings>();
|
||||||
reconnect();
|
settings->setVolume(static_cast<uint16_t>(volume * 100.));
|
||||||
return;
|
settings->setMuted(muted);
|
||||||
}
|
clientConnection_->send(settings, [this](const boost::system::error_code& ec) {
|
||||||
});
|
if (ec)
|
||||||
|
{
|
||||||
|
LOG(ERROR, LOG_TAG) << "Failed to send client settings, error: " << ec.message() << "\n";
|
||||||
|
reconnect();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
player_->setVolume(serverSettings_->getVolume() / 100.);
|
|
||||||
player_->setMute(serverSettings_->isMuted());
|
|
||||||
player_->start();
|
player_->start();
|
||||||
|
// Don't change the initial hardware mixer volume on the user's device.
|
||||||
|
// The player class will send the device's volume to the server instead
|
||||||
|
if (settings_.player.mixer.mode != ClientSettings::Mixer::Mode::hardware)
|
||||||
|
{
|
||||||
|
player_->setVolume(serverSettings_->getVolume() / 100.);
|
||||||
|
player_->setMute(serverSettings_->isMuted());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (response->type == message_type::kStreamTags)
|
else if (response->type == message_type::kStreamTags)
|
||||||
{
|
{
|
||||||
|
@ -194,35 +206,34 @@ void Controller::getNextMessage()
|
||||||
void Controller::sendTimeSyncMessage(int quick_syncs)
|
void Controller::sendTimeSyncMessage(int quick_syncs)
|
||||||
{
|
{
|
||||||
auto timeReq = std::make_shared<msg::Time>();
|
auto timeReq = std::make_shared<msg::Time>();
|
||||||
clientConnection_->sendRequest<msg::Time>(
|
clientConnection_->sendRequest<msg::Time>(timeReq, 2s, [this, quick_syncs](const boost::system::error_code& ec,
|
||||||
timeReq, 2s, [this, quick_syncs](const boost::system::error_code& ec, const std::unique_ptr<msg::Time>& response) mutable {
|
const std::unique_ptr<msg::Time>& response) mutable {
|
||||||
if (ec)
|
if (ec)
|
||||||
{
|
{
|
||||||
LOG(ERROR, LOG_TAG) << "Time sync request failed: " << ec.message() << "\n";
|
LOG(ERROR, LOG_TAG) << "Time sync request failed: " << ec.message() << "\n";
|
||||||
reconnect();
|
reconnect();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
TimeProvider::getInstance().setDiff(response->latency, response->received - response->sent);
|
TimeProvider::getInstance().setDiff(response->latency, response->received - response->sent);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::chrono::microseconds next = 1s;
|
std::chrono::microseconds next = 1s;
|
||||||
if (quick_syncs > 0)
|
if (quick_syncs > 0)
|
||||||
|
{
|
||||||
|
if (--quick_syncs == 0)
|
||||||
|
LOG(INFO, LOG_TAG) << "diff to server [ms]: " << (float)TimeProvider::getInstance().getDiffToServer<chronos::usec>().count() / 1000.f << "\n";
|
||||||
|
next = 100us;
|
||||||
|
}
|
||||||
|
timer_.expires_after(next);
|
||||||
|
timer_.async_wait([this, quick_syncs](const boost::system::error_code& ec) {
|
||||||
|
if (!ec)
|
||||||
{
|
{
|
||||||
if (--quick_syncs == 0)
|
sendTimeSyncMessage(quick_syncs);
|
||||||
LOG(INFO, LOG_TAG) << "diff to server [ms]: " << (float)TimeProvider::getInstance().getDiffToServer<chronos::usec>().count() / 1000.f
|
|
||||||
<< "\n";
|
|
||||||
next = 100us;
|
|
||||||
}
|
}
|
||||||
timer_.expires_after(next);
|
|
||||||
timer_.async_wait([this, quick_syncs](const boost::system::error_code& ec) {
|
|
||||||
if (!ec)
|
|
||||||
{
|
|
||||||
sendTimeSyncMessage(quick_syncs);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Controller::browseMdns(const MdnsHandler& handler)
|
void Controller::browseMdns(const MdnsHandler& handler)
|
||||||
|
|
|
@ -29,7 +29,7 @@ using namespace std;
|
||||||
static constexpr auto LOG_TAG = "Alsa";
|
static constexpr auto LOG_TAG = "Alsa";
|
||||||
|
|
||||||
AlsaPlayer::AlsaPlayer(boost::asio::io_context& io_context, const ClientSettings::Player& settings, std::shared_ptr<Stream> stream)
|
AlsaPlayer::AlsaPlayer(boost::asio::io_context& io_context, const ClientSettings::Player& settings, std::shared_ptr<Stream> stream)
|
||||||
: Player(io_context, settings, stream), handle_(nullptr), ctl_(nullptr), sd_(io_context)
|
: Player(io_context, settings, stream), handle_(nullptr), ctl_(nullptr), mixer_(nullptr), elem_(nullptr), sd_(io_context)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,9 +37,6 @@ AlsaPlayer::AlsaPlayer(boost::asio::io_context& io_context, const ClientSettings
|
||||||
void AlsaPlayer::setVolume(double volume)
|
void AlsaPlayer::setVolume(double volume)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(mutex_);
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
int err = 0;
|
|
||||||
snd_mixer_elem_t* elem(nullptr);
|
|
||||||
snd_mixer_t* mixer(nullptr);
|
|
||||||
// boost::system::error_code ec;
|
// boost::system::error_code ec;
|
||||||
// sd_.cancel(ec);
|
// sd_.cancel(ec);
|
||||||
// if (ctl_)
|
// if (ctl_)
|
||||||
|
@ -48,23 +45,21 @@ void AlsaPlayer::setVolume(double volume)
|
||||||
last_change_ = std::chrono::steady_clock::now();
|
last_change_ = std::chrono::steady_clock::now();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
openMixer(&elem, &mixer);
|
int err = 0;
|
||||||
|
|
||||||
long minv, maxv;
|
long minv, maxv;
|
||||||
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)) < 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 * (maxv - minv) + minv;
|
auto mixer_volume = volume * (maxv - minv) + minv;
|
||||||
LOG(DEBUG, LOG_TAG) << "Mixer volume range [" << minv << ", " << maxv << "], volume: " << volume << ", mixer volume: " << mixer_volume << "\n";
|
LOG(DEBUG, LOG_TAG) << "Mixer volume range [" << minv << ", " << maxv << "], volume: " << volume << ", 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)) < 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));
|
||||||
}
|
}
|
||||||
catch (const std::exception& e)
|
catch (const std::exception& e)
|
||||||
{
|
{
|
||||||
LOG(ERROR, LOG_TAG) << "Exception: " << e.what() << "\n";
|
LOG(ERROR, LOG_TAG) << "Exception: " << e.what() << "\n";
|
||||||
}
|
}
|
||||||
if (mixer != nullptr)
|
|
||||||
snd_mixer_close(mixer);
|
|
||||||
// if (ctl_)
|
// if (ctl_)
|
||||||
// {
|
// {
|
||||||
// snd_ctl_subscribe_events(ctl_, 1);
|
// snd_ctl_subscribe_events(ctl_, 1);
|
||||||
|
@ -78,68 +73,35 @@ bool AlsaPlayer::getVolume(double& volume, bool& muted)
|
||||||
long vol;
|
long vol;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
snd_mixer_elem_t* elem(nullptr);
|
|
||||||
snd_mixer_t* mixer(nullptr);
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
openMixer(&elem, &mixer);
|
snd_mixer_handle_events(mixer_);
|
||||||
|
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)) < 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));
|
||||||
|
|
||||||
// make the value bound to 1
|
// make the value bound to 1
|
||||||
long minv, maxv;
|
long minv, maxv;
|
||||||
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)) < 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));
|
||||||
vol -= minv;
|
vol -= minv;
|
||||||
maxv = maxv - minv;
|
maxv = maxv - minv;
|
||||||
volume = static_cast<double>(vol) / static_cast<double>(maxv);
|
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)) < 0)
|
||||||
return false;
|
return false;
|
||||||
muted = (val == 0);
|
muted = (val == 0);
|
||||||
LOG(DEBUG, LOG_TAG) << "Get volume, mixer volume range [" << minv << ", " << maxv << "], volume: " << volume << ", muted: " << muted << "\n";
|
LOG(DEBUG, LOG_TAG) << "Get volume, mixer volume range [" << minv << ", " << maxv << "], volume: " << volume << ", muted: " << muted << "\n";
|
||||||
if (mixer != nullptr)
|
|
||||||
snd_mixer_close(mixer);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch (const std::exception& e)
|
catch (const std::exception& e)
|
||||||
{
|
{
|
||||||
if (mixer != nullptr)
|
|
||||||
snd_mixer_close(mixer);
|
|
||||||
LOG(ERROR, LOG_TAG) << "Exception: " << e.what() << "\n";
|
LOG(ERROR, LOG_TAG) << "Exception: " << e.what() << "\n";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void AlsaPlayer::openMixer(snd_mixer_elem_t** elem, snd_mixer_t** mixer)
|
|
||||||
{
|
|
||||||
snd_mixer_selem_id_t* sid;
|
|
||||||
|
|
||||||
snd_mixer_selem_id_alloca(&sid);
|
|
||||||
std::string mix_name = "Master";
|
|
||||||
int mix_index = 0;
|
|
||||||
// sets simple-mixer index and name
|
|
||||||
snd_mixer_selem_id_set_index(sid, mix_index);
|
|
||||||
snd_mixer_selem_id_set_name(sid, mix_name.c_str());
|
|
||||||
|
|
||||||
int err;
|
|
||||||
if ((err = snd_mixer_open(mixer, 0)) < 0)
|
|
||||||
throw SnapException(std::string("Failed to open mixer, error: ") + snd_strerror(err));
|
|
||||||
if ((err = snd_mixer_attach(*mixer, settings_.pcm_device.name.c_str())) < 0)
|
|
||||||
throw SnapException("Failed to attach mixer to " + settings_.pcm_device.name + ", error: " + snd_strerror(err));
|
|
||||||
if ((err = snd_mixer_selem_register(*mixer, NULL, NULL)) < 0)
|
|
||||||
throw SnapException(std::string("Failed to register selem, error: ") + snd_strerror(err));
|
|
||||||
if ((err = snd_mixer_load(*mixer)) < 0)
|
|
||||||
throw SnapException(std::string("Failed to load mixer, error: ") + snd_strerror(err));
|
|
||||||
*elem = snd_mixer_find_selem(*mixer, sid);
|
|
||||||
if (!elem)
|
|
||||||
throw SnapException(std::string("Failed to find selem, error: ") + snd_strerror(err));
|
|
||||||
}
|
|
||||||
|
|
||||||
void AlsaPlayer::waitForEvent()
|
void AlsaPlayer::waitForEvent()
|
||||||
{
|
{
|
||||||
sd_.async_wait(boost::asio::posix::stream_descriptor::wait_read, [this](const boost::system::error_code& ec) {
|
sd_.async_wait(boost::asio::posix::stream_descriptor::wait_read, [this](const boost::system::error_code& ec) {
|
||||||
|
@ -192,6 +154,26 @@ void AlsaPlayer::initMixer()
|
||||||
fd_ = std::make_unique<pollfd>();
|
fd_ = std::make_unique<pollfd>();
|
||||||
snd_ctl_poll_descriptors(ctl_, fd_.get(), 1);
|
snd_ctl_poll_descriptors(ctl_, fd_.get(), 1);
|
||||||
|
|
||||||
|
snd_mixer_selem_id_t* sid;
|
||||||
|
snd_mixer_selem_id_alloca(&sid);
|
||||||
|
std::string mix_name = "Master";
|
||||||
|
int mix_index = 0;
|
||||||
|
// sets simple-mixer index and name
|
||||||
|
snd_mixer_selem_id_set_index(sid, mix_index);
|
||||||
|
snd_mixer_selem_id_set_name(sid, mix_name.c_str());
|
||||||
|
|
||||||
|
if ((err = snd_mixer_open(&mixer_, 0)) < 0)
|
||||||
|
throw SnapException(std::string("Failed to open mixer, error: ") + snd_strerror(err));
|
||||||
|
if ((err = snd_mixer_attach(mixer_, settings_.pcm_device.name.c_str())) < 0)
|
||||||
|
throw SnapException("Failed to attach mixer to " + settings_.pcm_device.name + ", error: " + snd_strerror(err));
|
||||||
|
if ((err = snd_mixer_selem_register(mixer_, NULL, NULL)) < 0)
|
||||||
|
throw SnapException(std::string("Failed to register selem, error: ") + snd_strerror(err));
|
||||||
|
if ((err = snd_mixer_load(mixer_)) < 0)
|
||||||
|
throw SnapException(std::string("Failed to load mixer, error: ") + snd_strerror(err));
|
||||||
|
elem_ = snd_mixer_find_selem(mixer_, sid);
|
||||||
|
if (!elem_)
|
||||||
|
throw SnapException(std::string("Failed to find selem, error: ") + snd_strerror(err));
|
||||||
|
|
||||||
sd_ = boost::asio::posix::stream_descriptor(io_context_, fd_->fd);
|
sd_ = boost::asio::posix::stream_descriptor(io_context_, fd_->fd);
|
||||||
waitForEvent();
|
waitForEvent();
|
||||||
}
|
}
|
||||||
|
@ -315,7 +297,7 @@ void AlsaPlayer::initAlsa()
|
||||||
// snd_pcm_sw_params_set_stop_threshold(pcm_handle, swparams, frames_);
|
// snd_pcm_sw_params_set_stop_threshold(pcm_handle, swparams, frames_);
|
||||||
snd_pcm_sw_params(handle_, swparams);
|
snd_pcm_sw_params(handle_, swparams);
|
||||||
|
|
||||||
// initMixer();
|
initMixer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -49,13 +49,16 @@ private:
|
||||||
void initAlsa();
|
void initAlsa();
|
||||||
void uninitAlsa();
|
void uninitAlsa();
|
||||||
void initMixer();
|
void initMixer();
|
||||||
bool getVolume(double& volume, bool& muted);
|
|
||||||
void openMixer(snd_mixer_elem_t** elem, snd_mixer_t** mixer);
|
bool getVolume(double& volume, bool& muted) override;
|
||||||
void waitForEvent();
|
void waitForEvent();
|
||||||
|
|
||||||
snd_pcm_t* handle_;
|
snd_pcm_t* handle_;
|
||||||
snd_ctl_t* ctl_;
|
snd_ctl_t* ctl_;
|
||||||
|
|
||||||
|
snd_mixer_t* mixer_;
|
||||||
|
snd_mixer_elem_t* elem_;
|
||||||
|
|
||||||
std::unique_ptr<pollfd> fd_;
|
std::unique_ptr<pollfd> fd_;
|
||||||
std::vector<char> buffer_;
|
std::vector<char> buffer_;
|
||||||
snd_pcm_uframes_t frames_;
|
snd_pcm_uframes_t frames_;
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
static constexpr auto LOG_TAG = "Player";
|
||||||
|
|
||||||
Player::Player(boost::asio::io_context& io_context, const ClientSettings::Player& settings, std::shared_ptr<Stream> stream)
|
Player::Player(boost::asio::io_context& io_context, const ClientSettings::Player& settings, std::shared_ptr<Stream> stream)
|
||||||
: io_context_(io_context), active_(false), stream_(stream), settings_(settings), volume_(1.0), muted_(false), volCorrection_(1.0)
|
: io_context_(io_context), active_(false), stream_(stream), settings_(settings), volume_(1.0), muted_(false), volCorrection_(1.0)
|
||||||
|
@ -43,6 +44,19 @@ void Player::start()
|
||||||
active_ = true;
|
active_ = true;
|
||||||
if (needsThread())
|
if (needsThread())
|
||||||
playerThread_ = thread(&Player::worker, this);
|
playerThread_ = thread(&Player::worker, this);
|
||||||
|
|
||||||
|
// If hardware mixer is used, send the initial volume to the server, because this is
|
||||||
|
// the volume that is configured by the user on his local device
|
||||||
|
if (settings_.mixer.mode == ClientSettings::Mixer::Mode::hardware)
|
||||||
|
{
|
||||||
|
double volume;
|
||||||
|
bool muted;
|
||||||
|
if (getVolume(volume, muted))
|
||||||
|
{
|
||||||
|
LOG(DEBUG, LOG_TAG) << "Volume: " << volume << ", muted: " << muted << "\n";
|
||||||
|
notifyVolumeChange(volume, muted);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -62,6 +76,12 @@ void Player::worker()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Player::getVolume(double& volume, bool& muted)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Player::adjustVolume(char* buffer, size_t frames)
|
void Player::adjustVolume(char* buffer, size_t frames)
|
||||||
{
|
{
|
||||||
// if (settings_.mixer.mode != ClientSettings::Mixer::Mode::software)
|
// if (settings_.mixer.mode != ClientSettings::Mixer::Mode::software)
|
||||||
|
@ -92,7 +112,7 @@ void Player::adjustVolume(char* buffer, size_t frames)
|
||||||
void Player::setVolume_poly(double volume, double exp)
|
void Player::setVolume_poly(double volume, double exp)
|
||||||
{
|
{
|
||||||
volume_ = std::pow(volume, exp);
|
volume_ = std::pow(volume, exp);
|
||||||
LOG(DEBUG) << "setVolume poly: " << volume << " => " << volume_ << "\n";
|
LOG(DEBUG, LOG_TAG) << "setVolume poly: " << volume << " => " << volume_ << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -102,7 +122,7 @@ void Player::setVolume_exp(double volume, double base)
|
||||||
// double base = M_E;
|
// double base = M_E;
|
||||||
// double base = 10.;
|
// double base = 10.;
|
||||||
volume_ = (pow(base, volume) - 1) / (base - 1);
|
volume_ = (pow(base, volume) - 1) / (base - 1);
|
||||||
LOG(DEBUG) << "setVolume exp: " << volume << " => " << volume_ << "\n";
|
LOG(DEBUG, LOG_TAG) << "setVolume exp: " << volume << " => " << volume_ << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -62,6 +62,7 @@ protected:
|
||||||
void setVolume_poly(double volume, double exp);
|
void setVolume_poly(double volume, double exp);
|
||||||
void setVolume_exp(double volume, double base);
|
void setVolume_exp(double volume, double base);
|
||||||
|
|
||||||
|
virtual bool getVolume(double& volume, bool& muted);
|
||||||
void adjustVolume(char* buffer, size_t frames);
|
void adjustVolume(char* buffer, size_t frames);
|
||||||
void notifyVolumeChange(double volume, bool muted) const
|
void notifyVolumeChange(double volume, bool muted) const
|
||||||
{
|
{
|
||||||
|
|
|
@ -120,7 +120,7 @@ int main(int argc, char** argv)
|
||||||
"", "logfilter", "log filter <tag>:<level>[,<tag>:<level>]* with tag = * or <log tag> and level = [trace,debug,info,notice,warning,error,fatal]",
|
"", "logfilter", "log filter <tag>:<level>[,<tag>:<level>]* with tag = * or <log tag> and level = [trace,debug,info,notice,warning,error,fatal]",
|
||||||
settings.logging.filter);
|
settings.logging.filter);
|
||||||
auto versionSwitch = op.add<Switch>("v", "version", "show version number");
|
auto versionSwitch = op.add<Switch>("v", "version", "show version number");
|
||||||
#if defined(HAS_ALSA) || defined(WINDOWS)
|
#if defined(HAS_ALSA) || defined(HAS_WASAPI)
|
||||||
auto listSwitch = op.add<Switch>("l", "list", "list PCM devices");
|
auto listSwitch = op.add<Switch>("l", "list", "list PCM devices");
|
||||||
/*auto soundcardValue =*/op.add<Value<string>>("s", "soundcard", "index or name of the pcm device", "default", &pcm_device);
|
/*auto soundcardValue =*/op.add<Value<string>>("s", "soundcard", "index or name of the pcm device", "default", &pcm_device);
|
||||||
#endif
|
#endif
|
||||||
|
@ -135,16 +135,19 @@ int main(int argc, char** argv)
|
||||||
/*auto latencyValue =*/op.add<Value<int>>("", "latency", "latency of the PCM device", 0, &settings.player.latency);
|
/*auto latencyValue =*/op.add<Value<int>>("", "latency", "latency of the PCM device", 0, &settings.player.latency);
|
||||||
/*auto instanceValue =*/op.add<Value<size_t>>("i", "instance", "instance id", 1, &settings.instance);
|
/*auto instanceValue =*/op.add<Value<size_t>>("i", "instance", "instance id", 1, &settings.instance);
|
||||||
/*auto hostIdValue =*/op.add<Value<string>>("", "hostID", "unique host id", "", &settings.host_id);
|
/*auto hostIdValue =*/op.add<Value<string>>("", "hostID", "unique host id", "", &settings.host_id);
|
||||||
#ifdef ANDROID
|
#if defined(HAS_OBOE) && defined(HAS_OPENSL)
|
||||||
op.add<Value<string>>("", "player", "audio backend", "", &settings.player.player_name);
|
op.add<Value<string>>("", "player", "audio backend", "", &settings.player.player_name);
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAS_SOXR
|
#ifdef HAS_SOXR
|
||||||
auto sample_format = op.add<Value<string>>("", "sampleformat", "resample audio stream to <rate>:<bits>:<channels>", "");
|
auto sample_format = op.add<Value<string>>("", "sampleformat", "resample audio stream to <rate>:<bits>:<channels>", "");
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAS_WASAPI
|
#ifdef HAS_WASAPI
|
||||||
auto sharing_mode = op.add<Value<string>>("", "sharingmode", "audio mode to use [shared/exclusive]", "shared");
|
auto sharing_mode = op.add<Value<string>>("", "sharingmode", "audio mode to use [shared|exclusive]", "shared");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// TODO: hardcoded
|
||||||
|
settings.player.mixer.mode = ClientSettings::Mixer::Mode::hardware;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
op.parse(argc, argv);
|
op.parse(argc, argv);
|
||||||
|
|
|
@ -22,10 +22,10 @@
|
||||||
#include "client_settings.hpp"
|
#include "client_settings.hpp"
|
||||||
#include "codec_header.hpp"
|
#include "codec_header.hpp"
|
||||||
#include "hello.hpp"
|
#include "hello.hpp"
|
||||||
|
#include "pcm_chunk.hpp"
|
||||||
#include "server_settings.hpp"
|
#include "server_settings.hpp"
|
||||||
#include "stream_tags.hpp"
|
#include "stream_tags.hpp"
|
||||||
#include "time.hpp"
|
#include "time.hpp"
|
||||||
#include "pcm_chunk.hpp"
|
|
||||||
|
|
||||||
#include "common/str_compat.hpp"
|
#include "common/str_compat.hpp"
|
||||||
#include "common/utils.hpp"
|
#include "common/utils.hpp"
|
||||||
|
@ -79,8 +79,8 @@ static std::unique_ptr<BaseMessage> createMessage(const BaseMessage& base_messag
|
||||||
case kTime:
|
case kTime:
|
||||||
return createMessage<Time>(base_message, buffer);
|
return createMessage<Time>(base_message, buffer);
|
||||||
case kWireChunk:
|
case kWireChunk:
|
||||||
// this is kind of cheated to safe the convertion from WireChunk to PcmChunk
|
// this is kind of cheated to safe the convertion from WireChunk to PcmChunk
|
||||||
// the user of the factory must be aware that a PcmChunk will be created
|
// the user of the factory must be aware that a PcmChunk will be created
|
||||||
return createMessage<PcmChunk>(base_message, buffer);
|
return createMessage<PcmChunk>(base_message, buffer);
|
||||||
case kClientSettings:
|
case kClientSettings:
|
||||||
return createMessage<ClientSettings>(base_message, buffer);
|
return createMessage<ClientSettings>(base_message, buffer);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue