Skip to content
Snippets Groups Projects
Commit ac9dcfad authored by Patrick Keroulas's avatar Patrick Keroulas Committed by Alexandre Lision
Browse files

alsa: decouple capture handle from playback handle

This allows for unidirectionnal sound transfert when one of the audio
direction can't be used. Plus refactoring.

Tuleap: #363
Change-Id: I3a9cbf5ef1ab9aba52ada8ce7554287e3c0a1b6e
parent 3677f3ad
No related branches found
No related tags found
No related merge requests found
......@@ -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,99 +726,35 @@ 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_)
return;
notifyIncomingCall();
snd_pcm_wait(playbackHandle_, 20);
int playbackAvailFrames = 0;
if (not safeUpdate(playbackHandle_, playbackAvailFrames))
if (!ringtoneHandle_)
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;
......@@ -829,11 +773,6 @@ void AlsaLayer::audioCallback()
write(playbackIBuff_.data(), ringtoneAvailFrames, ringtoneHandle_);
}
// Additionally handle the mic's audio stream
if (is_capture_running_)
capture();
}
void AlsaLayer::updatePreference(AudioPreference &preference, int index, DeviceType type)
{
switch (type) {
......
......@@ -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
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment