blob: 719a3bff5a685b8b1fa524ba5af6c7671e1e8c3c [file] [log] [blame]
/*
* 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);
}