diff --git a/src/media/audio/alsa/alsalayer.cpp b/src/media/audio/alsa/alsalayer.cpp index 3de960930d47beeb205735e316d9bbfd036f9486..b8f91d75ef0e3708268140ee2bc8e1c7f36ce7cc 100644 --- a/src/media/audio/alsa/alsalayer.cpp +++ b/src/media/audio/alsa/alsalayer.cpp @@ -132,7 +132,9 @@ void AlsaThread::run() alsa_->startedCv_.notify_all(); while (alsa_->status_ == AudioLayer::Status::Started and running_) { - alsa_->audioCallback(); + alsa_->playback(); + alsa_->ringtone(); + alsa_->capture(); } } @@ -188,7 +190,10 @@ bool AlsaLayer::openDevice(snd_pcm_t **pcm, const std::string &dev, snd_pcm_stre } while (err == -EBUSY and ++tries <= MAX_RETRIES); if (err < 0) { - RING_ERR("Alsa: couldn't open device %s : %s", dev.c_str(), + RING_ERR("Alsa: couldn't open %s device %s : %s", + (stream == SND_PCM_STREAM_CAPTURE)? "capture" : + (stream == SND_PCM_STREAM_PLAYBACK)? "playback" : "ringtone", + dev.c_str(), snd_strerror(err)); return false; } @@ -681,6 +686,9 @@ AlsaLayer::getAudioDeviceName(int index, DeviceType type) const void AlsaLayer::capture() { + if (!captureHandle_ or !is_capture_running_) + return; + AudioFormat mainBufferFormat = Manager::instance().getRingBufferPool().getInternalAudioFormat(); int toGetFrames = snd_pcm_avail_update(captureHandle_); @@ -718,120 +726,51 @@ void AlsaLayer::capture() } } -void AlsaLayer::playback(int maxFrames) +void AlsaLayer::playback() { - unsigned framesToGet = Manager::instance().getRingBufferPool().availableForGet(RingBufferPool::DEFAULT_ID); - - // no audio available, play tone or silence - if (framesToGet <= 0) { - // FIXME: not thread safe! we only lock the mutex when we get the - // pointer, we have no guarantee that it will stay safe to use - AudioLoop *tone = Manager::instance().getTelephoneTone(); - AudioLoop *file_tone = Manager::instance().getTelephoneFile(); - - playbackBuff_.setFormat(audioFormat_); - playbackBuff_.resize(maxFrames); - if (tone) - tone->getNext(playbackBuff_, playbackGain_); - else if (file_tone && !ringtoneHandle_) - file_tone->getNext(playbackBuff_, playbackGain_); - else - playbackBuff_.reset(); - - playbackBuff_.interleave(playbackIBuff_); - write(playbackIBuff_.data(), playbackBuff_.frames(), playbackHandle_); - } else { - // play the regular sound samples - const AudioFormat mainBufferFormat = Manager::instance().getRingBufferPool().getInternalAudioFormat(); - const bool resample = audioFormat_.sample_rate != mainBufferFormat.sample_rate; + if (!playbackHandle_) + return; - double resampleFactor = 1.0; - unsigned maxNbFramesToGet = maxFrames; + snd_pcm_wait(playbackHandle_, 20); - if (resample) { - resampleFactor = static_cast<double>(audioFormat_.sample_rate) / mainBufferFormat.sample_rate; - maxNbFramesToGet = maxFrames / resampleFactor; - } + int maxFrames = 0; - framesToGet = std::min(framesToGet, maxNbFramesToGet); + if (not safeUpdate(playbackHandle_, maxFrames)) + return; - playbackBuff_.setFormat(mainBufferFormat); - playbackBuff_.resize(framesToGet); + auto& ringBuff = getToRing(audioFormat_, maxFrames); + auto& playBuff = getToPlay(audioFormat_, maxFrames); + auto& toPlay = ringBuff.frames() > 0 ? ringBuff : playBuff; - Manager::instance().getRingBufferPool().getData(playbackBuff_, RingBufferPool::DEFAULT_ID); - playbackBuff_.applyGain(isPlaybackMuted_ ? 0.0 : playbackGain_); + if (!toPlay.frames() > 0) + return; - if (audioFormat_.nb_channels != mainBufferFormat.nb_channels) { - playbackBuff_.setChannelNum(audioFormat_.nb_channels, true); - } - if (resample) { - const size_t outFrames = framesToGet * resampleFactor; - AudioBuffer rsmpl_out(outFrames, audioFormat_); - resampler_->resample(playbackBuff_, rsmpl_out); - rsmpl_out.interleave(playbackIBuff_); - write(playbackIBuff_.data(), outFrames, playbackHandle_); - } else { - playbackBuff_.interleave(playbackIBuff_); - write(playbackIBuff_.data(), framesToGet, playbackHandle_); - } - } + toPlay.interleave(playbackIBuff_); + write(playbackIBuff_.data(), toPlay.frames(), playbackHandle_); } -void AlsaLayer::audioCallback() +void AlsaLayer::ringtone() { - if (!playbackHandle_ or !captureHandle_) + if (!ringtoneHandle_) return; - notifyIncomingCall(); - - snd_pcm_wait(playbackHandle_, 20); - - int playbackAvailFrames = 0; + AudioLoop *file_tone = Manager::instance().getTelephoneFile(); + int ringtoneAvailFrames = 0; - if (not safeUpdate(playbackHandle_, playbackAvailFrames)) + if (not safeUpdate(ringtoneHandle_, ringtoneAvailFrames)) return; - unsigned framesToGet = urgentRingBuffer_.availableForGet(RingBufferPool::DEFAULT_ID); - - if (framesToGet > 0) { - // Urgent data (dtmf, incoming call signal) come first. - framesToGet = std::min(framesToGet, (unsigned)playbackAvailFrames); - playbackBuff_.setFormat(audioFormat_); - playbackBuff_.resize(framesToGet); - urgentRingBuffer_.get(playbackBuff_, RingBufferPool::DEFAULT_ID); - playbackBuff_.applyGain(isPlaybackMuted_ ? 0.0 : playbackGain_); - playbackBuff_.interleave(playbackIBuff_); - write(playbackIBuff_.data(), framesToGet, playbackHandle_); - // Consume the regular one as well (same amount of frames) - Manager::instance().getRingBufferPool().discard(framesToGet, RingBufferPool::DEFAULT_ID); - } else { - // regular audio data - playback(playbackAvailFrames); - } - - if (ringtoneHandle_) { - AudioLoop *file_tone = Manager::instance().getTelephoneFile(); - int ringtoneAvailFrames = 0; - - if (not safeUpdate(ringtoneHandle_, ringtoneAvailFrames)) - return; - - playbackBuff_.setFormat(audioFormat_); - playbackBuff_.resize(ringtoneAvailFrames); - - if (file_tone) { - RING_DBG("playback gain %.3f", playbackGain_); - file_tone->getNext(playbackBuff_, playbackGain_); - } + playbackBuff_.setFormat(audioFormat_); + playbackBuff_.resize(ringtoneAvailFrames); - playbackBuff_.interleave(playbackIBuff_); - write(playbackIBuff_.data(), ringtoneAvailFrames, ringtoneHandle_); + if (file_tone) { + RING_DBG("playback gain %.3f", playbackGain_); + file_tone->getNext(playbackBuff_, playbackGain_); } - // Additionally handle the mic's audio stream - if (is_capture_running_) - capture(); + playbackBuff_.interleave(playbackIBuff_); + write(playbackIBuff_.data(), ringtoneAvailFrames, ringtoneHandle_); } void AlsaLayer::updatePreference(AudioPreference &preference, int index, DeviceType type) diff --git a/src/media/audio/alsa/alsalayer.h b/src/media/audio/alsa/alsalayer.h index 57203c50c50c740b9f4a6e4cf4a70206540d6284..c408b612a8f3caa798e704a25353d50ef7d6b2f9 100644 --- a/src/media/audio/alsa/alsalayer.h +++ b/src/media/audio/alsa/alsalayer.h @@ -111,11 +111,10 @@ class AlsaLayer : public AudioLayer { int getAudioDeviceIndex(const std::string &description, DeviceType type) const; std::string getAudioDeviceName(int index, DeviceType type) const; - void playback(int maxSamples); + void playback(); + void ringtone(); void capture(); - void audioCallback(); - /** * Get the index of the audio card for capture * @return int The index of the card used for capture