#include <cassert>
#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>
#include "common/OboeDebug.h"
#include "oboe/AudioStreamBuilder.h"
#include "AudioInputStreamOpenSLES.h"
#include "AudioStreamOpenSLES.h"
#include "OpenSLESUtilities.h"
using namespace oboe;
static SLuint32 OpenSLES_convertInputPreset(InputPreset oboePreset) {
SLuint32 openslPreset = SL_ANDROID_RECORDING_PRESET_NONE;
switch(oboePreset) {
case InputPreset::Generic:
openslPreset = SL_ANDROID_RECORDING_PRESET_GENERIC;
break;
case InputPreset::Camcorder:
openslPreset = SL_ANDROID_RECORDING_PRESET_CAMCORDER;
break;
case InputPreset::VoiceRecognition:
case InputPreset::VoicePerformance:
openslPreset = SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION;
break;
case InputPreset::VoiceCommunication:
openslPreset = SL_ANDROID_RECORDING_PRESET_VOICE_COMMUNICATION;
break;
case InputPreset::Unprocessed:
openslPreset = SL_ANDROID_RECORDING_PRESET_UNPROCESSED;
break;
default:
break;
}
return openslPreset;
}
AudioInputStreamOpenSLES::AudioInputStreamOpenSLES(const AudioStreamBuilder &builder)
: AudioStreamOpenSLES(builder) {
}
AudioInputStreamOpenSLES::~AudioInputStreamOpenSLES() {
}
SLuint32 AudioInputStreamOpenSLES::channelCountToChannelMask(int channelCount) const {
switch (channelCount) {
case 1:
return SL_SPEAKER_FRONT_LEFT;
case 2:
return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
default:
return channelCountToChannelMaskDefault(channelCount);
}
}
Result AudioInputStreamOpenSLES::open() {
logUnsupportedAttributes();
SLAndroidConfigurationItf configItf = nullptr;
if (getSdkVersion() < __ANDROID_API_M__ && mFormat == AudioFormat::Float){
return Result::ErrorInvalidFormat;
}
if (mFormat == AudioFormat::Unspecified){
mFormat = (getSdkVersion() < __ANDROID_API_M__) ?
AudioFormat::I16 : AudioFormat::Float;
}
Result oboeResult = AudioStreamOpenSLES::open();
if (Result::OK != oboeResult) return oboeResult;
SLuint32 bitsPerSample = static_cast<SLuint32>(getBytesPerSample() * kBitsPerByte);
mBufferQueueLength = calculateOptimalBufferQueueLength();
SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {
SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, static_cast<SLuint32>(mBufferQueueLength)};
SLDataFormat_PCM format_pcm = {
SL_DATAFORMAT_PCM, static_cast<SLuint32>(mChannelCount), static_cast<SLuint32>(mSampleRate * kMillisPerSecond), bitsPerSample, bitsPerSample, channelCountToChannelMask(mChannelCount), getDefaultByteOrder(),
};
SLDataSink audioSink = {&loc_bufq, &format_pcm};
SLAndroidDataFormat_PCM_EX format_pcm_ex;
if (getSdkVersion() >= __ANDROID_API_M__) {
SLuint32 representation = OpenSLES_ConvertFormatToRepresentation(getFormat());
format_pcm_ex = OpenSLES_createExtendedFormat(format_pcm, representation);
audioSink.pFormat = &format_pcm_ex;
}
SLDataLocator_IODevice loc_dev = {SL_DATALOCATOR_IODEVICE,
SL_IODEVICE_AUDIOINPUT,
SL_DEFAULTDEVICEID_AUDIOINPUT,
NULL};
SLDataSource audioSrc = {&loc_dev, NULL};
SLresult result = EngineOpenSLES::getInstance().createAudioRecorder(&mObjectInterface,
&audioSrc,
&audioSink);
if (SL_RESULT_SUCCESS != result) {
LOGE("createAudioRecorder() result:%s", getSLErrStr(result));
goto error;
}
result = (*mObjectInterface)->GetInterface(mObjectInterface,
SL_IID_ANDROIDCONFIGURATION,
&configItf);
if (SL_RESULT_SUCCESS != result) {
LOGW("%s() GetInterface(SL_IID_ANDROIDCONFIGURATION) failed with %s",
__func__, getSLErrStr(result));
} else {
if (getInputPreset() == InputPreset::VoicePerformance) {
LOGD("OpenSL ES does not support InputPreset::VoicePerformance. Use VoiceRecognition.");
mInputPreset = InputPreset::VoiceRecognition;
}
SLuint32 presetValue = OpenSLES_convertInputPreset(getInputPreset());
result = (*configItf)->SetConfiguration(configItf,
SL_ANDROID_KEY_RECORDING_PRESET,
&presetValue,
sizeof(SLuint32));
if (SL_RESULT_SUCCESS != result
&& presetValue != SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION) {
presetValue = SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION;
LOGD("Setting InputPreset %d failed. Using VoiceRecognition instead.", getInputPreset());
mInputPreset = InputPreset::VoiceRecognition;
(*configItf)->SetConfiguration(configItf,
SL_ANDROID_KEY_RECORDING_PRESET,
&presetValue,
sizeof(SLuint32));
}
result = configurePerformanceMode(configItf);
if (SL_RESULT_SUCCESS != result) {
goto error;
}
}
result = (*mObjectInterface)->Realize(mObjectInterface, SL_BOOLEAN_FALSE);
if (SL_RESULT_SUCCESS != result) {
LOGE("Realize recorder object result:%s", getSLErrStr(result));
goto error;
}
result = (*mObjectInterface)->GetInterface(mObjectInterface, SL_IID_RECORD, &mRecordInterface);
if (SL_RESULT_SUCCESS != result) {
LOGE("GetInterface RECORD result:%s", getSLErrStr(result));
goto error;
}
result = finishCommonOpen(configItf);
if (SL_RESULT_SUCCESS != result) {
goto error;
}
setState(StreamState::Open);
return Result::OK;
error:
close(); return Result::ErrorInternal; }
Result AudioInputStreamOpenSLES::close() {
LOGD("AudioInputStreamOpenSLES::%s()", __func__);
std::lock_guard<std::mutex> lock(mLock);
Result result = Result::OK;
if (getState() == StreamState::Closed){
result = Result::ErrorClosed;
} else {
(void) requestStop_l();
if (OboeGlobals::areWorkaroundsEnabled()) {
sleepBeforeClose();
}
mRecordInterface = nullptr;
result = AudioStreamOpenSLES::close_l();
}
return result;
}
Result AudioInputStreamOpenSLES::setRecordState_l(SLuint32 newState) {
LOGD("AudioInputStreamOpenSLES::%s(%u)", __func__, newState);
Result result = Result::OK;
if (mRecordInterface == nullptr) {
LOGW("AudioInputStreamOpenSLES::%s() mRecordInterface is null", __func__);
return Result::ErrorInvalidState;
}
SLresult slResult = (*mRecordInterface)->SetRecordState(mRecordInterface, newState);
if (SL_RESULT_SUCCESS != slResult) {
LOGE("AudioInputStreamOpenSLES::%s(%u) returned error %s",
__func__, newState, getSLErrStr(slResult));
result = Result::ErrorInternal; }
return result;
}
Result AudioInputStreamOpenSLES::requestStart() {
LOGD("AudioInputStreamOpenSLES(): %s() called", __func__);
std::lock_guard<std::mutex> lock(mLock);
StreamState initialState = getState();
switch (initialState) {
case StreamState::Starting:
case StreamState::Started:
return Result::OK;
case StreamState::Closed:
return Result::ErrorClosed;
default:
break;
}
setDataCallbackEnabled(true);
setState(StreamState::Starting);
closePerformanceHint();
if (getBufferDepth(mSimpleBufferQueueInterface) == 0) {
enqueueCallbackBuffer(mSimpleBufferQueueInterface);
}
Result result = setRecordState_l(SL_RECORDSTATE_RECORDING);
if (result == Result::OK) {
setState(StreamState::Started);
} else {
setState(initialState);
}
return result;
}
Result AudioInputStreamOpenSLES::requestPause() {
LOGW("AudioInputStreamOpenSLES::%s() is intentionally not implemented for input "
"streams", __func__);
return Result::ErrorUnimplemented; }
Result AudioInputStreamOpenSLES::requestFlush() {
LOGW("AudioInputStreamOpenSLES::%s() is intentionally not implemented for input "
"streams", __func__);
return Result::ErrorUnimplemented; }
Result AudioInputStreamOpenSLES::requestStop() {
LOGD("AudioInputStreamOpenSLES(): %s() called", __func__);
std::lock_guard<std::mutex> lock(mLock);
return requestStop_l();
}
Result AudioInputStreamOpenSLES::requestStop_l() {
StreamState initialState = getState();
switch (initialState) {
case StreamState::Stopping:
case StreamState::Stopped:
return Result::OK;
case StreamState::Uninitialized:
case StreamState::Closed:
return Result::ErrorClosed;
default:
break;
}
setState(StreamState::Stopping);
Result result = setRecordState_l(SL_RECORDSTATE_STOPPED);
if (result == Result::OK) {
mPositionMillis.reset32(); setState(StreamState::Stopped);
} else {
setState(initialState);
}
return result;
}
void AudioInputStreamOpenSLES::updateFramesWritten() {
if (usingFIFO()) {
AudioStreamBuffered::updateFramesWritten();
} else {
mFramesWritten = getFramesProcessedByServer();
}
}
Result AudioInputStreamOpenSLES::updateServiceFrameCounter() {
Result result = Result::OK;
if (mLock.try_lock()) {
if (mRecordInterface == nullptr) {
mLock.unlock();
return Result::ErrorNull;
}
SLmillisecond msec = 0;
SLresult slResult = (*mRecordInterface)->GetPosition(mRecordInterface, &msec);
if (SL_RESULT_SUCCESS != slResult) {
LOGW("%s(): GetPosition() returned %s", __func__, getSLErrStr(slResult));
result = Result::ErrorInternal;
} else {
mPositionMillis.update32(msec);
}
mLock.unlock();
}
return result;
}