blob: 8040e6a40e84ba5dce7ee1f78dc3970224dd64d4 [file] [log] [blame]
/*
* Copyright (C) 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.
*/
#define LOG_TAG "AAudio"
//#define LOG_NDEBUG 0
#include <utils/Log.h>
#include <inttypes.h>
#include <mutex>
#include <time.h>
#include <pthread.h>
#include <aaudio/AAudio.h>
#include <aaudio/AAudioTesting.h>
#include "AudioClock.h"
#include "AudioGlobal.h"
#include "AudioStreamBuilder.h"
#include "AudioStream.h"
#include "binding/AAudioCommon.h"
#include "client/AudioStreamInternal.h"
using namespace aaudio;
// Macros for common code that includes a return.
// TODO Consider using do{}while(0) construct. I tried but it hung AndroidStudio
#define CONVERT_BUILDER_HANDLE_OR_RETURN() \
convertAAudioBuilderToStreamBuilder(builder);
#define COMMON_GET_FROM_BUILDER_OR_RETURN(resultPtr) \
CONVERT_BUILDER_HANDLE_OR_RETURN() \
if ((resultPtr) == nullptr) { \
return AAUDIO_ERROR_NULL; \
}
AAUDIO_API const char * AAudio_convertResultToText(aaudio_result_t returnCode) {
return AudioGlobal_convertResultToText(returnCode);
}
AAUDIO_API const char * AAudio_convertStreamStateToText(aaudio_stream_state_t state) {
return AudioGlobal_convertStreamStateToText(state);
}
static AudioStream *convertAAudioStreamToAudioStream(AAudioStream* stream)
{
return (AudioStream*) stream;
}
static AudioStreamBuilder *convertAAudioBuilderToStreamBuilder(AAudioStreamBuilder* builder)
{
return (AudioStreamBuilder*) builder;
}
AAUDIO_API aaudio_result_t AAudio_createStreamBuilder(AAudioStreamBuilder** builder)
{
AudioStreamBuilder *audioStreamBuilder = new(std::nothrow) AudioStreamBuilder();
if (audioStreamBuilder == nullptr) {
return AAUDIO_ERROR_NO_MEMORY;
}
*builder = (AAudioStreamBuilder*) audioStreamBuilder;
return AAUDIO_OK;
}
AAUDIO_API void AAudioStreamBuilder_setPerformanceMode(AAudioStreamBuilder* builder,
aaudio_performance_mode_t mode)
{
AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
streamBuilder->setPerformanceMode(mode);
}
AAUDIO_API void AAudioStreamBuilder_setDeviceId(AAudioStreamBuilder* builder,
int32_t deviceId)
{
AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
streamBuilder->setDeviceId(deviceId);
}
AAUDIO_API void AAudioStreamBuilder_setSampleRate(AAudioStreamBuilder* builder,
int32_t sampleRate)
{
AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
streamBuilder->setSampleRate(sampleRate);
}
AAUDIO_API void AAudioStreamBuilder_setChannelCount(AAudioStreamBuilder* builder,
int32_t channelCount)
{
AAudioStreamBuilder_setSamplesPerFrame(builder, channelCount);
}
AAUDIO_API void AAudioStreamBuilder_setSamplesPerFrame(AAudioStreamBuilder* builder,
int32_t samplesPerFrame)
{
AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
streamBuilder->setSamplesPerFrame(samplesPerFrame);
}
AAUDIO_API void AAudioStreamBuilder_setDirection(AAudioStreamBuilder* builder,
aaudio_direction_t direction)
{
AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
streamBuilder->setDirection(direction);
}
AAUDIO_API void AAudioStreamBuilder_setFormat(AAudioStreamBuilder* builder,
aaudio_format_t format)
{
AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
// Use audio_format_t everywhere internally.
const audio_format_t internalFormat = AAudioConvert_aaudioToAndroidDataFormat(format);
streamBuilder->setFormat(internalFormat);
}
AAUDIO_API void AAudioStreamBuilder_setSharingMode(AAudioStreamBuilder* builder,
aaudio_sharing_mode_t sharingMode)
{
AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
streamBuilder->setSharingMode(sharingMode);
}
AAUDIO_API void AAudioStreamBuilder_setUsage(AAudioStreamBuilder* builder,
aaudio_usage_t usage) {
AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
streamBuilder->setUsage(usage);
}
AAUDIO_API void AAudioStreamBuilder_setContentType(AAudioStreamBuilder* builder,
aaudio_content_type_t contentType) {
AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
streamBuilder->setContentType(contentType);
}
AAUDIO_API void AAudioStreamBuilder_setInputPreset(AAudioStreamBuilder* builder,
aaudio_input_preset_t inputPreset) {
AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
streamBuilder->setInputPreset(inputPreset);
}
AAUDIO_API void AAudioStreamBuilder_setBufferCapacityInFrames(AAudioStreamBuilder* builder,
int32_t frames)
{
AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
streamBuilder->setBufferCapacity(frames);
}
AAUDIO_API void AAudioStreamBuilder_setAllowedCapturePolicy(
AAudioStreamBuilder* builder, aaudio_allowed_capture_policy_t policy) {
AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
streamBuilder->setAllowedCapturePolicy(policy);
}
AAUDIO_API void AAudioStreamBuilder_setSessionId(AAudioStreamBuilder* builder,
aaudio_session_id_t sessionId)
{
AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
streamBuilder->setSessionId(sessionId);
}
AAUDIO_API void AAudioStreamBuilder_setDataCallback(AAudioStreamBuilder* builder,
AAudioStream_dataCallback callback,
void *userData)
{
AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
streamBuilder->setDataCallbackProc(callback);
streamBuilder->setDataCallbackUserData(userData);
}
AAUDIO_API void AAudioStreamBuilder_setErrorCallback(AAudioStreamBuilder* builder,
AAudioStream_errorCallback callback,
void *userData)
{
AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
streamBuilder->setErrorCallbackProc(callback);
streamBuilder->setErrorCallbackUserData(userData);
}
AAUDIO_API void AAudioStreamBuilder_setFramesPerDataCallback(AAudioStreamBuilder* builder,
int32_t frames)
{
AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
streamBuilder->setFramesPerDataCallback(frames);
}
AAUDIO_API aaudio_result_t AAudioStreamBuilder_openStream(AAudioStreamBuilder* builder,
AAudioStream** streamPtr)
{
AudioStream *audioStream = nullptr;
aaudio_stream_id_t id = 0;
// Please leave these logs because they are very helpful when debugging.
ALOGI("%s() called ----------------------------------------", __func__);
AudioStreamBuilder *streamBuilder = COMMON_GET_FROM_BUILDER_OR_RETURN(streamPtr);
aaudio_result_t result = streamBuilder->build(&audioStream);
if (result == AAUDIO_OK) {
audioStream->registerPlayerBase();
*streamPtr = (AAudioStream*) audioStream;
id = audioStream->getId();
} else {
*streamPtr = nullptr;
}
ALOGI("%s() returns %d = %s for s#%u ----------------",
__func__, result, AAudio_convertResultToText(result), id);
return result;
}
AAUDIO_API aaudio_result_t AAudioStreamBuilder_delete(AAudioStreamBuilder* builder)
{
AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
if (streamBuilder != nullptr) {
delete streamBuilder;
return AAUDIO_OK;
}
return AAUDIO_ERROR_NULL;
}
AAUDIO_API aaudio_result_t AAudioStream_close(AAudioStream* stream)
{
aaudio_result_t result = AAUDIO_ERROR_NULL;
AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
if (audioStream != nullptr) {
aaudio_stream_id_t id = audioStream->getId();
ALOGD("%s(s#%u) called ---------------", __func__, id);
result = audioStream->safeClose();
// Close will only fail if called illegally, for example, from a callback.
// That would result in deleting an active stream, which would cause a crash.
if (result == AAUDIO_OK) {
audioStream->unregisterPlayerBase();
delete audioStream;
} else {
ALOGW("%s attempt to close failed. Close it from another thread.", __func__);
}
ALOGD("%s(s#%u) returned %d ---------", __func__, id, result);
}
return result;
}
AAUDIO_API aaudio_result_t AAudioStream_requestStart(AAudioStream* stream)
{
AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
aaudio_stream_id_t id = audioStream->getId();
ALOGD("%s(s#%u) called --------------", __func__, id);
aaudio_result_t result = audioStream->systemStart();
ALOGD("%s(s#%u) returned %d ---------", __func__, id, result);
return result;
}
AAUDIO_API aaudio_result_t AAudioStream_requestPause(AAudioStream* stream)
{
AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
ALOGD("%s(s#%u) called", __func__, audioStream->getId());
return audioStream->systemPause();
}
AAUDIO_API aaudio_result_t AAudioStream_requestFlush(AAudioStream* stream)
{
AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
ALOGD("%s(s#%u) called", __func__, audioStream->getId());
return audioStream->safeFlush();
}
AAUDIO_API aaudio_result_t AAudioStream_requestStop(AAudioStream* stream)
{
AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
ALOGD("%s(s#%u) called", __func__, audioStream->getId());
return audioStream->systemStopFromApp();
}
AAUDIO_API aaudio_result_t AAudioStream_waitForStateChange(AAudioStream* stream,
aaudio_stream_state_t inputState,
aaudio_stream_state_t *nextState,
int64_t timeoutNanoseconds)
{
AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
return audioStream->waitForStateChange(inputState, nextState, timeoutNanoseconds);
}
// ============================================================
// Stream - non-blocking I/O
// ============================================================
AAUDIO_API aaudio_result_t AAudioStream_read(AAudioStream* stream,
void *buffer,
int32_t numFrames,
int64_t timeoutNanoseconds)
{
AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
if (buffer == nullptr) {
return AAUDIO_ERROR_NULL;
}
if (numFrames < 0) {
return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
} else if (numFrames == 0) {
return 0;
}
aaudio_result_t result = audioStream->read(buffer, numFrames, timeoutNanoseconds);
return result;
}
AAUDIO_API aaudio_result_t AAudioStream_write(AAudioStream* stream,
const void *buffer,
int32_t numFrames,
int64_t timeoutNanoseconds)
{
AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
if (buffer == nullptr) {
return AAUDIO_ERROR_NULL;
}
// Don't allow writes when playing with a callback.
if (audioStream->isDataCallbackActive()) {
ALOGD("Cannot write to a callback stream when running.");
return AAUDIO_ERROR_INVALID_STATE;
}
if (numFrames < 0) {
return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
} else if (numFrames == 0) {
return 0;
}
aaudio_result_t result = audioStream->write(buffer, numFrames, timeoutNanoseconds);
return result;
}
// ============================================================
// Stream - queries
// ============================================================
AAUDIO_API int32_t AAudioStream_getSampleRate(AAudioStream* stream)
{
AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
return audioStream->getSampleRate();
}
AAUDIO_API int32_t AAudioStream_getChannelCount(AAudioStream* stream)
{
AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
return audioStream->getSamplesPerFrame();
}
AAUDIO_API int32_t AAudioStream_getSamplesPerFrame(AAudioStream* stream)
{
return AAudioStream_getChannelCount(stream);
}
AAUDIO_API aaudio_stream_state_t AAudioStream_getState(AAudioStream* stream)
{
AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
return audioStream->getState();
}
AAUDIO_API aaudio_format_t AAudioStream_getFormat(AAudioStream* stream)
{
AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
// Use audio_format_t internally.
audio_format_t internalFormat = audioStream->getFormat();
return AAudioConvert_androidToAAudioDataFormat(internalFormat);
}
AAUDIO_API aaudio_result_t AAudioStream_setBufferSizeInFrames(AAudioStream* stream,
int32_t requestedFrames)
{
AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
return audioStream->setBufferSize(requestedFrames);
}
AAUDIO_API int32_t AAudioStream_getBufferSizeInFrames(AAudioStream* stream)
{
AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
return audioStream->getBufferSize();
}
AAUDIO_API aaudio_direction_t AAudioStream_getDirection(AAudioStream* stream)
{
AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
return audioStream->getDirection();
}
AAUDIO_API int32_t AAudioStream_getFramesPerBurst(AAudioStream* stream)
{
AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
return audioStream->getFramesPerBurst();
}
AAUDIO_API int32_t AAudioStream_getFramesPerDataCallback(AAudioStream* stream)
{
AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
return audioStream->getFramesPerDataCallback();
}
AAUDIO_API int32_t AAudioStream_getBufferCapacityInFrames(AAudioStream* stream)
{
AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
return audioStream->getBufferCapacity();
}
AAUDIO_API int32_t AAudioStream_getXRunCount(AAudioStream* stream)
{
AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
return audioStream->getXRunCount();
}
AAUDIO_API aaudio_performance_mode_t AAudioStream_getPerformanceMode(AAudioStream* stream)
{
AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
return audioStream->getPerformanceMode();
}
AAUDIO_API int32_t AAudioStream_getDeviceId(AAudioStream* stream)
{
AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
return audioStream->getDeviceId();
}
AAUDIO_API aaudio_sharing_mode_t AAudioStream_getSharingMode(AAudioStream* stream)
{
AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
return audioStream->getSharingMode();
}
AAUDIO_API aaudio_usage_t AAudioStream_getUsage(AAudioStream* stream)
{
AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
return audioStream->getUsage();
}
AAUDIO_API aaudio_content_type_t AAudioStream_getContentType(AAudioStream* stream)
{
AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
return audioStream->getContentType();
}
AAUDIO_API aaudio_input_preset_t AAudioStream_getInputPreset(AAudioStream* stream)
{
AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
return audioStream->getInputPreset();
}
AAUDIO_API aaudio_allowed_capture_policy_t AAudioStream_getAllowedCapturePolicy(
AAudioStream* stream)
{
AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
return audioStream->getAllowedCapturePolicy();
}
AAUDIO_API int32_t AAudioStream_getSessionId(AAudioStream* stream)
{
AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
return audioStream->getSessionId();
}
AAUDIO_API int64_t AAudioStream_getFramesWritten(AAudioStream* stream)
{
AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
return audioStream->getFramesWritten();
}
AAUDIO_API int64_t AAudioStream_getFramesRead(AAudioStream* stream)
{
AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
return audioStream->getFramesRead();
}
AAUDIO_API aaudio_result_t AAudioStream_getTimestamp(AAudioStream* stream,
clockid_t clockid,
int64_t *framePosition,
int64_t *timeNanoseconds)
{
AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
if (framePosition == nullptr) {
return AAUDIO_ERROR_NULL;
} else if (timeNanoseconds == nullptr) {
return AAUDIO_ERROR_NULL;
} else if (clockid != CLOCK_MONOTONIC && clockid != CLOCK_BOOTTIME) {
return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
}
return audioStream->getTimestamp(clockid, framePosition, timeNanoseconds);
}
AAUDIO_API aaudio_policy_t AAudio_getMMapPolicy() {
return AudioGlobal_getMMapPolicy();
}
AAUDIO_API aaudio_result_t AAudio_setMMapPolicy(aaudio_policy_t policy) {
return AudioGlobal_setMMapPolicy(policy);
}
AAUDIO_API bool AAudioStream_isMMapUsed(AAudioStream* stream)
{
AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
return audioStream->isMMap();
}