| /* | |
| * Copyright 2016 The Android Open Source Project | |
| * | |
| * 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 <stdint.h> | |
| #include "oboe/OboeUtilities.h" | |
| #include "common/OboeDebug.h" | |
| #include "aaudio/AAudioLoader.h" | |
| #include "aaudio/OboeStreamAAudio.h" | |
| AAudioLoader *OboeStreamAAudio::mLibLoader = nullptr; | |
| /* | |
| * Create a stream that uses Oboe Audio API. | |
| */ | |
| OboeStreamAAudio::OboeStreamAAudio(const OboeStreamBuilder &builder) | |
| : OboeStream(builder) | |
| , mFloatCallbackBuffer(nullptr) | |
| , mShortCallbackBuffer(nullptr) | |
| , mAAudioStream(nullptr) | |
| { | |
| mCallbackThreadEnabled.store(false); | |
| LOGD("OboeStreamAAudio() call isSupported()"); | |
| isSupported(); | |
| } | |
| OboeStreamAAudio::~OboeStreamAAudio() | |
| { | |
| delete[] mFloatCallbackBuffer; | |
| delete[] mShortCallbackBuffer; | |
| } | |
| bool OboeStreamAAudio::isSupported() { | |
| mLibLoader = AAudioLoader::getInstance(); | |
| int openResult = mLibLoader->open(); | |
| return openResult == 0; | |
| } | |
| // 'C' wrapper for the data callback method | |
| static aaudio_data_callback_result_t oboe_aaudio_data_callback_proc( | |
| AAudioStream *stream, | |
| void *userData, | |
| void *audioData, | |
| int32_t numFrames) { | |
| OboeStreamAAudio *oboeStream = (OboeStreamAAudio *)userData; | |
| if (oboeStream != NULL) { | |
| return oboeStream->callOnAudioReady(stream, audioData, numFrames); | |
| } else { | |
| return AAUDIO_CALLBACK_RESULT_STOP; | |
| } | |
| } | |
| // 'C' wrapper for the error callback method | |
| static void oboe_aaudio_error_callback_proc( | |
| AAudioStream *stream, | |
| void *userData, | |
| aaudio_result_t error) { | |
| OboeStreamAAudio *oboeStream = (OboeStreamAAudio *)userData; | |
| if (oboeStream != NULL) { | |
| oboeStream->callOnError(stream, error); | |
| } | |
| } | |
| oboe_result_t OboeStreamAAudio::open() { | |
| oboe_result_t result = AAUDIO_OK; | |
| if (mAAudioStream != nullptr) { | |
| return AAUDIO_ERROR_INVALID_STATE; | |
| } | |
| result = OboeStream::open(); | |
| if (result != AAUDIO_OK) { | |
| return result; | |
| } | |
| LOGD("OboeStreamAAudio(): AAudio_createStreamBuilder()"); | |
| AAudioStreamBuilder *aaudioBuilder; | |
| result = mLibLoader->createStreamBuilder(&aaudioBuilder); | |
| if (result != AAUDIO_OK) { | |
| return result; | |
| } | |
| LOGD("OboeStreamAAudio.open() try with deviceId = %d", (int) mDeviceId); | |
| mLibLoader->builder_setBufferCapacityInFrames(aaudioBuilder, mBufferCapacityInFrames); | |
| mLibLoader->builder_setChannelCount(aaudioBuilder, mChannelCount); | |
| mLibLoader->builder_setDeviceId(aaudioBuilder, mDeviceId); | |
| mLibLoader->builder_setDirection(aaudioBuilder, mDirection); | |
| mLibLoader->builder_setFormat(aaudioBuilder, mFormat); | |
| mLibLoader->builder_setSampleRate(aaudioBuilder, mSampleRate); | |
| mLibLoader->builder_setSharingMode(aaudioBuilder, mSharingMode); | |
| mLibLoader->builder_setPerformanceMode(aaudioBuilder, mPerformanceMode); | |
| // TODO get more parameters from the builder | |
| if (mStreamCallback != nullptr) { | |
| mLibLoader->builder_setDataCallback(aaudioBuilder, oboe_aaudio_data_callback_proc, this); | |
| mLibLoader->builder_setErrorCallback(aaudioBuilder, oboe_aaudio_error_callback_proc, this); | |
| mLibLoader->builder_setFramesPerDataCallback(aaudioBuilder, getFramesPerCallback()); | |
| } | |
| result = mLibLoader->builder_openStream(aaudioBuilder, &mAAudioStream); | |
| if (result != AAUDIO_OK) { | |
| goto error2; | |
| } | |
| mChannelCount = mLibLoader->stream_getChannelCount(mAAudioStream); | |
| mSampleRate = mLibLoader->stream_getSampleRate(mAAudioStream); | |
| mNativeFormat = mLibLoader->stream_getFormat(mAAudioStream); | |
| if (mFormat == OBOE_AUDIO_FORMAT_UNSPECIFIED) { | |
| mFormat = mNativeFormat; | |
| } | |
| mSharingMode = mLibLoader->stream_getSharingMode(mAAudioStream); | |
| mPerformanceMode = mLibLoader->stream_getPerformanceMode(mAAudioStream); | |
| LOGD("OboeStreamAAudio.open() app format = %d", (int) mFormat); | |
| LOGD("OboeStreamAAudio.open() native format = %d", (int) mNativeFormat); | |
| error2: | |
| mLibLoader->builder_delete(aaudioBuilder); | |
| LOGD("OboeStreamAAudio.open: AAudioStream_Open() returned %s, mAAudioStream = %p", | |
| mLibLoader->convertResultToText(result), mAAudioStream); | |
| return result; | |
| } | |
| oboe_result_t OboeStreamAAudio::close() | |
| { | |
| oboe_result_t result = mLibLoader->stream_close(mAAudioStream); | |
| mAAudioStream = nullptr; | |
| return result; | |
| } | |
| aaudio_data_callback_result_t OboeStreamAAudio::callOnAudioReady(AAudioStream *stream, | |
| void *audioData, | |
| int32_t numFrames) { | |
| return mStreamCallback->onAudioReady( | |
| this, | |
| audioData, | |
| numFrames); | |
| } | |
| void OboeStreamAAudio::callOnError(AAudioStream *stream, oboe_result_t error) { | |
| mStreamCallback->onError( this, error); | |
| } | |
| oboe_result_t OboeStreamAAudio::convertApplicationDataToNative(int32_t numFrames) { | |
| oboe_result_t result = OBOE_ERROR_UNIMPLEMENTED; | |
| int32_t numSamples = numFrames * getChannelCount(); | |
| if (mFormat == OBOE_AUDIO_FORMAT_PCM_FLOAT) { | |
| if (mNativeFormat == OBOE_AUDIO_FORMAT_PCM_I16) { | |
| Oboe_convertFloatToPcm16(mFloatCallbackBuffer, mShortCallbackBuffer, numSamples); | |
| result = AAUDIO_OK; | |
| } | |
| } else if (mFormat == OBOE_AUDIO_FORMAT_PCM_I16) { | |
| if (mNativeFormat == OBOE_AUDIO_FORMAT_PCM_FLOAT) { | |
| Oboe_convertPcm16ToFloat(mShortCallbackBuffer, mFloatCallbackBuffer, numSamples); | |
| result = AAUDIO_OK; | |
| } | |
| } | |
| return result; | |
| } | |
| oboe_result_t OboeStreamAAudio::requestStart() | |
| { | |
| return mLibLoader->stream_requestStart(mAAudioStream); | |
| } | |
| oboe_result_t OboeStreamAAudio::requestPause() | |
| { | |
| return mLibLoader->stream_requestPause(mAAudioStream); | |
| } | |
| oboe_result_t OboeStreamAAudio::requestFlush() { | |
| return mLibLoader->stream_requestFlush(mAAudioStream); | |
| } | |
| oboe_result_t OboeStreamAAudio::requestStop() | |
| { | |
| return mLibLoader->stream_requestStop(mAAudioStream); | |
| } | |
| oboe_result_t OboeStreamAAudio::write(const void *buffer, | |
| int32_t numFrames, | |
| int64_t timeoutNanoseconds) | |
| { | |
| return mLibLoader->stream_write(mAAudioStream, buffer, numFrames, timeoutNanoseconds); | |
| } | |
| oboe_result_t OboeStreamAAudio::waitForStateChange(oboe_stream_state_t currentState, | |
| oboe_stream_state_t *nextState, | |
| int64_t timeoutNanoseconds) | |
| { | |
| return mLibLoader->stream_waitForStateChange(mAAudioStream, currentState, | |
| nextState, timeoutNanoseconds); | |
| } | |
| oboe_result_t OboeStreamAAudio::setBufferSizeInFrames(int32_t requestedFrames) | |
| { | |
| return mLibLoader->stream_setBufferSize(mAAudioStream, requestedFrames); | |
| } | |
| oboe_stream_state_t OboeStreamAAudio::getState() | |
| { | |
| if (mAAudioStream == nullptr) { | |
| return OBOE_STREAM_STATE_CLOSED; | |
| } | |
| return mLibLoader->stream_getState(mAAudioStream); | |
| } | |
| int32_t OboeStreamAAudio::getBufferSizeInFrames() const { | |
| return mLibLoader->stream_getBufferSize(mAAudioStream); | |
| } | |
| int32_t OboeStreamAAudio::getBufferCapacityInFrames() const { | |
| return mLibLoader->stream_getBufferCapacity(mAAudioStream); | |
| } | |
| int32_t OboeStreamAAudio::getFramesPerBurst() | |
| { | |
| return mLibLoader->stream_getFramesPerBurst(mAAudioStream); | |
| } | |
| int64_t OboeStreamAAudio::getFramesRead() | |
| { | |
| return mLibLoader->stream_getFramesRead(mAAudioStream); | |
| } | |
| int64_t OboeStreamAAudio::getFramesWritten() | |
| { | |
| return mLibLoader->stream_getFramesWritten(mAAudioStream); | |
| } | |
| int32_t OboeStreamAAudio::getXRunCount() | |
| { | |
| return mLibLoader->stream_getXRunCount(mAAudioStream); | |
| } | |
| oboe_result_t OboeStreamAAudio::getTimestamp(clockid_t clockId, | |
| int64_t *framePosition, | |
| int64_t *timeNanoseconds) { | |
| return mLibLoader->stream_getTimestamp(mAAudioStream, clockId, | |
| framePosition, timeNanoseconds); | |
| } |