diff --git a/client/alsaPlayer.cpp b/client/alsaPlayer.cpp index e6b71c99..9f766756 100644 --- a/client/alsaPlayer.cpp +++ b/client/alsaPlayer.cpp @@ -27,7 +27,14 @@ using namespace std; -Player::Player(const PcmDevice& pcmDevice, Stream* stream) : handle_(NULL), buff_(NULL), active_(false), stream_(stream), pcmDevice_(pcmDevice) +Player::Player(const PcmDevice& pcmDevice, Stream* stream) : + handle_(NULL), + buff_(NULL), + active_(false), + stream_(stream), + pcmDevice_(pcmDevice), + volume_(1.0), + muted_(false) { } @@ -184,9 +191,22 @@ void Player::worker() snd_pcm_delay(handle_, &framesDelay); chronos::usec delay((chronos::usec::rep) (1000 * (double) framesDelay / stream_->getFormat().msRate())); // logO << "delay: " << framesDelay << ", delay[ms]: " << delay.count() / 1000 << "\n"; + double volume = volume_; + if (muted_) + volume = 0.; + const msg::SampleFormat& sampleFormat = stream_->getFormat(); if (stream_->getPlayerChunk(buff_, delay, frames_)) { + if (volume < 1.0) + { + if (sampleFormat.bits == 8) + adjustVolume(buff_, frames_*sampleFormat.channels, volume); + else if (sampleFormat.bits == 16) + adjustVolume(buff_, frames_*sampleFormat.channels, volume); + else if (sampleFormat.bits == 32) + adjustVolume(buff_, frames_*sampleFormat.channels, volume); + } if ((pcm = snd_pcm_writei(handle_, buff_, frames_)) == -EPIPE) { logE << "XRUN\n"; @@ -211,49 +231,14 @@ void Player::worker() void Player::setVolume(double volume) { - long min, max; - snd_mixer_t *handle; - snd_mixer_selem_id_t *sid; - const char *selem_name = "Master"; - - snd_mixer_open(&handle, 0); - snd_mixer_attach(handle, pcmDevice_.name.c_str()); - snd_mixer_selem_register(handle, NULL, NULL); - snd_mixer_load(handle); - - snd_mixer_selem_id_alloca(&sid); - snd_mixer_selem_id_set_index(sid, 0); - snd_mixer_selem_id_set_name(sid, selem_name); - snd_mixer_elem_t* elem = snd_mixer_find_selem(handle, sid); - - snd_mixer_selem_get_playback_volume_range(elem, &min, &max); - snd_mixer_selem_set_playback_volume_all(elem, volume * max); - - snd_mixer_close(handle); + volume_ = volume; } void Player::setMute(bool mute) { - snd_mixer_t *handle; - snd_mixer_selem_id_t *sid; - const char *selem_name = "Master"; - - snd_mixer_open(&handle, 0); - snd_mixer_attach(handle, pcmDevice_.name.c_str()); - snd_mixer_selem_register(handle, NULL, NULL); - snd_mixer_load(handle); - - snd_mixer_selem_id_alloca(&sid); - snd_mixer_selem_id_set_index(sid, 0); - snd_mixer_selem_id_set_name(sid, selem_name); - snd_mixer_elem_t* elem = snd_mixer_find_selem(handle, sid); - - if (snd_mixer_selem_has_playback_switch(elem)) - snd_mixer_selem_set_playback_switch_all(elem, mute?0:1); - - snd_mixer_close(handle); + muted_ = mute; } diff --git a/client/alsaPlayer.h b/client/alsaPlayer.h index 82c9904b..5e6ad085 100644 --- a/client/alsaPlayer.h +++ b/client/alsaPlayer.h @@ -28,15 +28,23 @@ #include "pcmDevice.h" +/// Audio Player +/** + * Audio player implementation using Alsa + */ class Player { public: Player(const PcmDevice& pcmDevice, Stream* stream); virtual ~Player(); + + /// Set audio volume in range [0..1] void setVolume(double volume); void setMute(bool mute); void start(); void stop(); + + /// List the system's audio output devices static std::vector pcm_list(void); private: @@ -44,6 +52,14 @@ private: void uninitAlsa(); void worker(); + template + void adjustVolume(char *buffer, size_t count, double volume) + { + T* bufferT = (T*)buffer; + for (size_t n=0; nsetBufferLen(serverSettings->bufferMs - latency_); player_.reset(new Player(pcmDevice_, stream_)); - player_->setVolume(serverSettings->volume); + player_->setVolume(serverSettings->volume / 100.); player_->start(); msg::Command startStream("startStream");