Commit 2a4ae6aa authored by Adrien Béraud's avatar Adrien Béraud

android audio refactoring

* better abstraction of player/recorder
* extract higher-level logic to AudioLayer

Tuleap: #102
Change-Id: I1e81ecb220b7e01907154188ced531eb368b3311
parent 3364bd33
......@@ -109,4 +109,101 @@ void AudioLayer::notifyIncomingCall()
putUrgent(buf);
}
const AudioBuffer& AudioLayer::getToRing(AudioFormat format, size_t writableSamples)
{
ringtoneBuffer_.resize(0);
AudioLoop *fileToPlay = Manager::instance().getTelephoneFile();
if (fileToPlay) {
auto fileformat = fileToPlay->getFormat();
bool resample = format.sample_rate != fileformat.sample_rate;
size_t readableSamples = resample
? fileformat.sample_rate * (double) writableSamples / (double) audioFormat_.sample_rate
: writableSamples;
ringtoneBuffer_.setFormat(fileformat);
ringtoneBuffer_.resize(readableSamples);
fileToPlay->getNext(ringtoneBuffer_, 1.0);
ringtoneBuffer_.setChannelNum(format.nb_channels, true);
AudioBuffer* out;
if (resample) {
ringtoneResampleBuffer_.setSampleRate(format.sample_rate);
resampler_->resample(ringtoneBuffer_, ringtoneResampleBuffer_);
out = &ringtoneResampleBuffer_;
} else {
out = &ringtoneBuffer_;
}
return *out;
}
return ringtoneBuffer_;
}
const AudioBuffer& AudioLayer::getToPlay(AudioFormat format, size_t writableSamples)
{
playbackBuffer_.resize(0);
playbackResampleBuffer_.resize(0);
notifyIncomingCall();
size_t urgentSamples = std::min(urgentRingBuffer_.availableForGet(RingBufferPool::DEFAULT_ID), writableSamples);
if (urgentSamples) {
playbackBuffer_.setFormat(format);
playbackBuffer_.resize(urgentSamples);
urgentRingBuffer_.get(playbackBuffer_, RingBufferPool::DEFAULT_ID); // retrive only the first sample_spec->channels channels
playbackBuffer_.applyGain(isPlaybackMuted_ ? 0.0 : playbackGain_);
// Consume the regular one as well (same amount of samples)
Manager::instance().getRingBufferPool().discard(urgentSamples, RingBufferPool::DEFAULT_ID);
return playbackBuffer_;
}
// 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
if (AudioLoop* toneToPlay = Manager::instance().getTelephoneTone()) {
playbackBuffer_.setFormat(format);
playbackBuffer_.resize(writableSamples);
toneToPlay->getNext(playbackBuffer_, playbackGain_); // retrive only n_channels
return playbackBuffer_;
}
flushUrgent(); // flush remaining samples in _urgentRingBuffer
size_t availSamples = Manager::instance().getRingBufferPool().availableForGet(RingBufferPool::DEFAULT_ID);
if (not availSamples)
return playbackBuffer_;
// how many samples we want to read from the buffer
size_t readableSamples = writableSamples;
AudioFormat mainBufferAudioFormat = Manager::instance().getRingBufferPool().getInternalAudioFormat();
bool resample = audioFormat_.sample_rate != mainBufferAudioFormat.sample_rate;
double resampleFactor = 1.;
if (resample) {
resampleFactor = (double) audioFormat_.sample_rate / mainBufferAudioFormat.sample_rate;
readableSamples = (double) readableSamples / resampleFactor;
}
readableSamples = std::min(readableSamples, availSamples);
size_t nResampled = (double) readableSamples * resampleFactor;
playbackBuffer_.setFormat(mainBufferAudioFormat);
playbackBuffer_.resize(readableSamples);
Manager::instance().getRingBufferPool().getData(playbackBuffer_, RingBufferPool::DEFAULT_ID);
playbackBuffer_.setChannelNum(format.nb_channels, true);
if (resample) {
playbackResampleBuffer_.setFormat(format);
playbackResampleBuffer_.resize(nResampled);
resampler_->resample(playbackBuffer_, playbackResampleBuffer_);
playbackResampleBuffer_.applyGain(isPlaybackMuted_ ? 0.0 : playbackGain_);
return playbackResampleBuffer_;
} else {
playbackBuffer_.applyGain(isPlaybackMuted_ ? 0.0 : playbackGain_);
return playbackBuffer_;
}
}
} // namespace ring
......@@ -219,6 +219,11 @@ class AudioLayer {
*/
void hardwareInputFormatAvailable(AudioFormat capture);
const AudioBuffer& getToPlay(AudioFormat format, size_t writableSamples);
const AudioBuffer& getToRing(AudioFormat format, size_t writableSamples);
/**
* True if capture is not to be used
*/
......@@ -239,6 +244,14 @@ class AudioLayer {
*/
double playbackGain_;
/**
* Buffers for audio processing
*/
AudioBuffer playbackBuffer_;
AudioBuffer playbackResampleBuffer_;
AudioBuffer ringtoneBuffer_;
AudioBuffer ringtoneResampleBuffer_;
/**
* Whether or not the audio layer stream is started
*/
......
......@@ -4,8 +4,8 @@ if BUILD_OPENSL
noinst_LTLIBRARIES = libopensl.la
libopensl_la_SOURCES = opensllayer.cpp
libopensl_la_SOURCES = opensllayer.cpp audio_player.cpp audio_recorder.cpp
noinst_HEADERS = opensllayer.h
noinst_HEADERS = opensllayer.h audio_common.h audio_player.h audio_recorder.h buf_manager.h
endif
/*
* Copyright 2015 The Android Open Source Project
* Copyright 2015 Savoir-faire Linux Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <SLES/OpenSLES_Android.h>
#include "buf_manager.h"
namespace ring {
namespace opensl {
/*
* Sample Buffer Controls...
*/
#define RECORD_DEVICE_KICKSTART_BUF_COUNT 2
#define PLAY_KICKSTART_BUFFER_COUNT 8
#define DEVICE_SHADOW_BUFFER_QUEUE_LEN 4
#define BUF_COUNT 16
inline SLDataFormat_PCM convertToSLSampleFormat(const ring::AudioFormat& infos)
{
return SLDataFormat_PCM {
.formatType = SL_DATAFORMAT_PCM,
.numChannels = infos.nb_channels <= 1 ? 1u : 2u,
.samplesPerSec = infos.sample_rate * 1000,
.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16,
.containerSize = SL_PCMSAMPLEFORMAT_FIXED_16,
.channelMask = infos.nb_channels <= 1 ? SL_SPEAKER_FRONT_CENTER : SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT,
.endianness = SL_BYTEORDER_LITTLEENDIAN,
};
}
#define SLASSERT(x) { \
if(SL_RESULT_SUCCESS != (x))\
throw std::runtime_error("OpenSLES error");\
}
/*
* Interface for player and recorder to communicate with engine
*/
#define ENGINE_SERVICE_MSG_KICKSTART_PLAYER 1
#define ENGINE_SERVICE_MSG_RETRIEVE_DUMP_BUFS 2
using EngineCallback = std::function<void(bool waiting)>;
}}
/*
* Copyright 2015 The Android Open Source Project
* Copyright 2015 Savoir-faire Linux Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "audio_player.h"
#include "logger.h"
#include <SLES/OpenSLES_AndroidConfiguration.h>
#include <cstdlib>
namespace ring {
namespace opensl {
/*
* Called by OpenSL SimpleBufferQueue for every audio buffer played
* directly pass thru to our handler.
* The regularity of this callback from openSL/Android System affects
* playback continuity. If it does not callback in the regular time
* slot, you are under big pressure for audio processing[here we do
* not do any filtering/mixing]. Callback from fast audio path are
* much more regular than other audio paths by my observation. If it
* very regular, you could buffer much less audio samples between
* recorder and player, hence lower latency.
*/
void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *ctx) {
(static_cast<AudioPlayer *>(ctx))->processSLCallback(bq);
}
void AudioPlayer::processSLCallback(SLAndroidSimpleBufferQueueItf bq) {
std::lock_guard<std::mutex> lk(m_);
// retrieve the finished device buf and put onto the free queue
// so recorder could re-use it
sample_buf *buf;
if(!devShadowQueue_.front(&buf)) {
RING_ERR("AudioPlayer buffer lost");
/*
* This should not happen: we got a callback,
* but we have no buffer in deviceShadowedQueue
* we lost buffers this way...(ERROR)
*/
callback_(true);
return;
}
devShadowQueue_.pop();
buf->size_ = 0;
if (!freeQueue_->push(buf)) {
RING_ERR("buffer lost");
}
callback_(false);
while(playQueue_->front(&buf) && devShadowQueue_.push(buf)) {
if ((*bq)->Enqueue(bq, buf->buf_, buf->size_) != SL_RESULT_SUCCESS) {
devShadowQueue_.pop();
RING_ERR("enqueue failed %zu %zu %zu %zu", buf->size_, freeQueue_->size(), playQueue_->size(), devShadowQueue_.size());
break;
} else
playQueue_->pop();
}
if (devShadowQueue_.size() == 0) {
RING_ERR("AudioPlayer: nothing to play %zu %zu %zu", freeQueue_->size(), playQueue_->size(), devShadowQueue_.size());
waiting_ = true;
callback_(true);
}
}
AudioPlayer::AudioPlayer(ring::AudioFormat sampleFormat, SLEngineItf slEngine, SLint32 streamType) :
sampleInfo_(sampleFormat)
{
SLresult result;
result = (*slEngine)->CreateOutputMix(slEngine, &outputMixObjectItf_, 0, nullptr, nullptr);
SLASSERT(result);
// realize the output mix
result = (*outputMixObjectItf_)->Realize(outputMixObjectItf_, SL_BOOLEAN_FALSE);
SLASSERT(result);
// configure audio source
SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {
SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
DEVICE_SHADOW_BUFFER_QUEUE_LEN };
auto format_pcm = convertToSLSampleFormat(sampleInfo_);
SLDataSource audioSrc = {&loc_bufq, &format_pcm};
// configure audio sink
SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObjectItf_};
SLDataSink audioSnk = {&loc_outmix, nullptr};
/*
* create fast path audio player: SL_IID_BUFFERQUEUE and SL_IID_VOLUME interfaces ok,
* NO others!
*/
SLInterfaceID ids[3] = { SL_IID_BUFFERQUEUE, SL_IID_VOLUME, SL_IID_ANDROIDCONFIGURATION};
SLboolean req[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
result = (*slEngine)->CreateAudioPlayer(slEngine, &playerObjectItf_, &audioSrc, &audioSnk,
sizeof(ids)/sizeof(ids[0]), ids, req);
SLASSERT(result);
SLAndroidConfigurationItf playerConfig;
result = (*playerObjectItf_)->GetInterface(playerObjectItf_, SL_IID_ANDROIDCONFIGURATION, &playerConfig);
result = (*playerConfig)->SetConfiguration(playerConfig, SL_ANDROID_KEY_STREAM_TYPE, &streamType, sizeof(SLint32));
// realize the player
result = (*playerObjectItf_)->Realize(playerObjectItf_, SL_BOOLEAN_FALSE);
SLASSERT(result);
// get the play interface
result = (*playerObjectItf_)->GetInterface(playerObjectItf_, SL_IID_PLAY, &playItf_);
SLASSERT(result);
// get the buffer queue interface
result = (*playerObjectItf_)->GetInterface(playerObjectItf_, SL_IID_BUFFERQUEUE, &playBufferQueueItf_);
SLASSERT(result);
// register callback on the buffer queue
result = (*playBufferQueueItf_)->RegisterCallback(playBufferQueueItf_, bqPlayerCallback, this);
SLASSERT(result);
result = (*playItf_)->SetPlayState(playItf_, SL_PLAYSTATE_STOPPED);
SLASSERT(result);
}
AudioPlayer::~AudioPlayer() {
// destroy buffer queue audio player object, and invalidate all associated interfaces
if (playerObjectItf_) {
(*playerObjectItf_)->Destroy(playerObjectItf_);
}
// destroy output mix object, and invalidate all associated interfaces
if (outputMixObjectItf_) {
(*outputMixObjectItf_)->Destroy(outputMixObjectItf_);
}
}
void AudioPlayer::setBufQueue(AudioQueue *playQ, AudioQueue *freeQ) {
playQueue_ = playQ;
freeQueue_ = freeQ;
}
bool AudioPlayer::start() {
SLuint32 state;
SLresult result = (*playItf_)->GetPlayState(playItf_, &state);
if (result != SL_RESULT_SUCCESS)
return false;
if(state == SL_PLAYSTATE_PLAYING)
return true;
result = (*playItf_)->SetPlayState(playItf_, SL_PLAYSTATE_STOPPED);
SLASSERT(result);
result = (*playItf_)->SetPlayState(playItf_, SL_PLAYSTATE_PLAYING);
SLASSERT(result);
// send pre-defined audio buffers to device
int i = PLAY_KICKSTART_BUFFER_COUNT;
while(i--) {
sample_buf *buf;
if(!playQueue_->front(&buf)) //we have buffers for sure
break;
if(SL_RESULT_SUCCESS !=
(*playBufferQueueItf_)->Enqueue(playBufferQueueItf_, buf, buf->size_))
{
RING_ERR("====failed to enqueue (%d) in %s", i, __FUNCTION__);
return false;
} else {
playQueue_->pop();
devShadowQueue_.push(buf);
}
}
waiting_ = devShadowQueue_.size() == 0;
return true;
}
bool AudioPlayer::started() const
{
if (!playItf_)
return false;
SLuint32 state;
SLresult result = (*playItf_)->GetPlayState(playItf_, &state);
return result == SL_RESULT_SUCCESS && state == SL_PLAYSTATE_PLAYING;
}
void AudioPlayer::stop() {
SLuint32 state;
SLresult result = (*playItf_)->GetPlayState(playItf_, &state);
SLASSERT(result);
if(state == SL_PLAYSTATE_STOPPED)
return;
result = (*playItf_)->SetPlayState(playItf_, SL_PLAYSTATE_STOPPED);
SLASSERT(result);
waiting_ = false;
// Consume all non-completed audio buffers
sample_buf *buf = nullptr;
while(devShadowQueue_.front(&buf)) {
buf->size_ = 0;
devShadowQueue_.pop();
freeQueue_->push(buf);
}
while(playQueue_->front(&buf)) {
buf->size_ = 0;
playQueue_->pop();
freeQueue_->push(buf);
}
}
void AudioPlayer::playAudioBuffers(unsigned count) {
while (count--) {
sample_buf *buf = nullptr;
if(!playQueue_->front(&buf)) {
RING_ERR("====Run out of buffers in %s @(count = %d)", __FUNCTION__, count);
break;
}
if(!devShadowQueue_.push(buf)) {
break; // PlayerBufferQueue is full!!!
}
SLresult result = (*playBufferQueueItf_)->Enqueue(playBufferQueueItf_,
buf->buf_, buf->size_);
if(result != SL_RESULT_SUCCESS) {
RING_ERR("%s Error @( %p, %d ), result = %d", __FUNCTION__, (void*)buf->buf_, buf->size_, result);
/*
* when this happens, a buffer is lost. Need to remove the buffer
* from top of the devShadowQueue. Since I do not have it now,
* just pop out the one that is being played right now. Afer a
* cycle it will be normal.
*/
devShadowQueue_.front(&buf), devShadowQueue_.pop();
freeQueue_->push(buf);
break;
}
playQueue_->pop(); // really pop out the buffer
}
waiting_ = devShadowQueue_.size() == 0;
}
size_t AudioPlayer::dbgGetDevBufCount(void) {
return devShadowQueue_.size();
}
}}
/*
* Copyright 2015 The Android Open Source Project
* Copyright 2015 Savoir-faire Linux Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "audio_common.h"
#include "buf_manager.h"
#include <sys/types.h>
#include <SLES/OpenSLES_Android.h>
#include <mutex>
namespace ring {
namespace opensl {
class AudioPlayer {
// buffer queue player interfaces
SLObjectItf outputMixObjectItf_;
SLObjectItf playerObjectItf_;
SLPlayItf playItf_;
SLAndroidSimpleBufferQueueItf playBufferQueueItf_;
ring::AudioFormat sampleInfo_;
AudioQueue *freeQueue_ {nullptr}; // user
AudioQueue *playQueue_ {nullptr}; // user
AudioQueue devShadowQueue_ {DEVICE_SHADOW_BUFFER_QUEUE_LEN}; // owner
EngineCallback callback_ {};
public:
explicit AudioPlayer(ring::AudioFormat sampleFormat, SLEngineItf engine, SLint32 streamType);
~AudioPlayer();
bool start();
void stop();
bool started() const;
void setBufQueue(AudioQueue *playQ, AudioQueue *freeQ);
void processSLCallback(SLAndroidSimpleBufferQueueItf bq);
void playAudioBuffers(unsigned count);
void registerCallback(EngineCallback cb) {callback_ = cb;}
size_t dbgGetDevBufCount();
std::mutex m_;
std::atomic_bool waiting_ {false};
};
}}
/*
* Copyright 2015 The Android Open Source Project
* Copyright 2015 Savoir-faire Linux Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <cstring>
#include <cstdlib>
#include "audio_recorder.h"
namespace ring {
namespace opensl {
/*
* bqRecorderCallback(): called for every buffer is full;
* pass directly to handler
*/
void bqRecorderCallback(SLAndroidSimpleBufferQueueItf bq, void *rec) {
(static_cast<AudioRecorder *>(rec))->processSLCallback(bq);
}
void AudioRecorder::processSLCallback(SLAndroidSimpleBufferQueueItf bq) {
assert(bq == recBufQueueItf_);
sample_buf *dataBuf {nullptr};
devShadowQueue_.front(&dataBuf);
devShadowQueue_.pop();
dataBuf->size_ = dataBuf->cap_; //device only calls us when it is really full
recQueue_->push(dataBuf);
sample_buf* freeBuf;
while (freeQueue_->front(&freeBuf) && devShadowQueue_.push(freeBuf)) {
freeQueue_->pop();
SLresult result = (*bq)->Enqueue(bq, freeBuf->buf_, freeBuf->cap_);
SLASSERT(result);
}
// should leave the device to sleep to save power if no buffers
if (devShadowQueue_.size() == 0) {
(*recItf_)->SetRecordState(recItf_, SL_RECORDSTATE_STOPPED);
}
callback_(false);
}
AudioRecorder::AudioRecorder(ring::AudioFormat sampleFormat, SLEngineItf slEngine) :
sampleInfo_(sampleFormat)
{
// configure audio source
SLDataLocator_IODevice loc_dev = {SL_DATALOCATOR_IODEVICE,
SL_IODEVICE_AUDIOINPUT,
SL_DEFAULTDEVICEID_AUDIOINPUT,
nullptr };
SLDataSource audioSrc = {&loc_dev, nullptr };
// configure audio sink
SLDataLocator_AndroidSimpleBufferQueue loc_bq = {
SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
DEVICE_SHADOW_BUFFER_QUEUE_LEN };
auto format_pcm = convertToSLSampleFormat(sampleInfo_);
SLDataSink audioSnk = {&loc_bq, &format_pcm};
// create audio recorder
// (requires the RECORD_AUDIO permission)
const SLInterfaceID id[1] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE};
const SLboolean req[1] = {SL_BOOLEAN_TRUE};
SLresult result;
result = (*slEngine)->CreateAudioRecorder(slEngine,
&recObjectItf_,
&audioSrc,
&audioSnk,
1, id, req);
SLASSERT(result);
result = (*recObjectItf_)->Realize(recObjectItf_, SL_BOOLEAN_FALSE);
SLASSERT(result);
result = (*recObjectItf_)->GetInterface(recObjectItf_, SL_IID_RECORD, &recItf_);
SLASSERT(result);
result = (*recObjectItf_)->GetInterface(recObjectItf_, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &recBufQueueItf_);
SLASSERT(result);
result = (*recBufQueueItf_)->RegisterCallback(recBufQueueItf_, bqRecorderCallback, this);
SLASSERT(result);
}
bool
AudioRecorder::start()
{
if(!freeQueue_ || !recQueue_) {
RING_ERR("====NULL pointer to Start(%p, %p)", freeQueue_, recQueue_);
return false;
}
audioBufCount = 0;
SLresult result;
// in case already recording, stop recording and clear buffer queue
result = (*recItf_)->SetRecordState(recItf_, SL_RECORDSTATE_STOPPED);
SLASSERT(result);
result = (*recBufQueueItf_)->Clear(recBufQueueItf_);
SLASSERT(result);
for(int i =0; i < RECORD_DEVICE_KICKSTART_BUF_COUNT; i++ ) {
sample_buf *buf = NULL;
if(!freeQueue_->front(&buf)) {
RING_ERR("=====OutOfFreeBuffers @ startingRecording @ (%d)", i);
break;
}
freeQueue_->pop();
assert(buf->buf_ && buf->cap_ && !buf->size_);
result = (*recBufQueueItf_)->Enqueue(recBufQueueItf_, buf->buf_,
buf->cap_);
SLASSERT(result);
devShadowQueue_.push(buf);
}
result = (*recItf_)->SetRecordState(recItf_, SL_RECORDSTATE_RECORDING);
SLASSERT(result);
return result == SL_RESULT_SUCCESS;
}
bool
AudioRecorder::stop()
{
// in case already recording, stop recording and clear buffer queue
SLuint32 curState;
SLresult result = (*recItf_)->GetRecordState(recItf_, &curState);
SLASSERT(result);
if (curState == SL_RECORDSTATE_STOPPED)
return true;
result = (*recItf_)->SetRecordState(recItf_, SL_RECORDSTATE_STOPPED);
SLASSERT(result);
result = (*recBufQueueItf_)->Clear(recBufQueueItf_);
SLASSERT(result);
sample_buf *buf {nullptr};
while(devShadowQueue_.front(&buf)) {
devShadowQueue_.pop();
freeQueue_->push(buf);
}
return true;
}
AudioRecorder::~AudioRecorder() {
// destroy audio recorder object, and invalidate all associated interfaces
if (recObjectItf_) {
(*recObjectItf_)->Destroy(recObjectItf_);
}
}
void AudioRecorder::setBufQueues(AudioQueue *freeQ, AudioQueue *recQ) {
assert(freeQ && recQ);
freeQueue_ = freeQ;
recQueue_ = recQ;
}
size_t AudioRecorder::dbgGetDevBufCount() {
return devShadowQueue_.size();
}
}}
/*
* Copyright 2015 The Android Open Source Project
* Copyright 2015 Savoir-faire Linux Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.