blob: cdd02c036076ec9d92f5083381fa4661ac426e2f [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.
*/
#define LOG_TAG "AAudio"
//#define LOG_NDEBUG 0
#include <utils/Log.h>
#include <cutils/properties.h>
#include <stdint.h>
#include <sys/types.h>
#include <utils/Errors.h>
#include "aaudio/AAudio.h"
#include "core/AudioGlobal.h"
#include <aaudio/AAudioTesting.h>
#include <math.h>
#include <system/audio-base.h>
#include <assert.h>
#include "utility/AAudioUtilities.h"
using namespace android;
status_t AAudioConvert_aaudioToAndroidStatus(aaudio_result_t result) {
// This covers the case for AAUDIO_OK and for positive results.
if (result >= 0) {
return result;
}
status_t status;
switch (result) {
case AAUDIO_ERROR_DISCONNECTED:
case AAUDIO_ERROR_NO_SERVICE:
status = DEAD_OBJECT;
break;
case AAUDIO_ERROR_INVALID_HANDLE:
status = BAD_TYPE;
break;
case AAUDIO_ERROR_INVALID_STATE:
status = INVALID_OPERATION;
break;
case AAUDIO_ERROR_INVALID_RATE:
case AAUDIO_ERROR_INVALID_FORMAT:
case AAUDIO_ERROR_ILLEGAL_ARGUMENT:
case AAUDIO_ERROR_OUT_OF_RANGE:
status = BAD_VALUE;
break;
case AAUDIO_ERROR_WOULD_BLOCK:
status = WOULD_BLOCK;
break;
case AAUDIO_ERROR_NULL:
status = UNEXPECTED_NULL;
break;
case AAUDIO_ERROR_UNAVAILABLE:
status = NOT_ENOUGH_DATA;
break;
// TODO translate these result codes
case AAUDIO_ERROR_INTERNAL:
case AAUDIO_ERROR_UNIMPLEMENTED:
case AAUDIO_ERROR_NO_FREE_HANDLES:
case AAUDIO_ERROR_NO_MEMORY:
case AAUDIO_ERROR_TIMEOUT:
default:
status = UNKNOWN_ERROR;
break;
}
return status;
}
aaudio_result_t AAudioConvert_androidToAAudioResult(status_t status) {
// This covers the case for OK and for positive result.
if (status >= 0) {
return status;
}
aaudio_result_t result;
switch (status) {
case BAD_TYPE:
result = AAUDIO_ERROR_INVALID_HANDLE;
break;
case DEAD_OBJECT:
result = AAUDIO_ERROR_NO_SERVICE;
break;
case INVALID_OPERATION:
result = AAUDIO_ERROR_INVALID_STATE;
break;
case UNEXPECTED_NULL:
result = AAUDIO_ERROR_NULL;
break;
case BAD_VALUE:
result = AAUDIO_ERROR_ILLEGAL_ARGUMENT;
break;
case WOULD_BLOCK:
result = AAUDIO_ERROR_WOULD_BLOCK;
break;
case NOT_ENOUGH_DATA:
result = AAUDIO_ERROR_UNAVAILABLE;
break;
default:
result = AAUDIO_ERROR_INTERNAL;
break;
}
return result;
}
audio_session_t AAudioConvert_aaudioToAndroidSessionId(aaudio_session_id_t sessionId) {
// If not a regular sessionId then convert to a safe value of AUDIO_SESSION_ALLOCATE.
return (sessionId == AAUDIO_SESSION_ID_ALLOCATE || sessionId == AAUDIO_SESSION_ID_NONE)
? AUDIO_SESSION_ALLOCATE
: (audio_session_t) sessionId;
}
audio_format_t AAudioConvert_aaudioToAndroidDataFormat(aaudio_format_t aaudioFormat) {
audio_format_t androidFormat;
switch (aaudioFormat) {
case AAUDIO_FORMAT_UNSPECIFIED:
androidFormat = AUDIO_FORMAT_DEFAULT;
break;
case AAUDIO_FORMAT_PCM_I16:
androidFormat = AUDIO_FORMAT_PCM_16_BIT;
break;
case AAUDIO_FORMAT_PCM_FLOAT:
androidFormat = AUDIO_FORMAT_PCM_FLOAT;
break;
default:
androidFormat = AUDIO_FORMAT_INVALID;
ALOGE("%s() 0x%08X unrecognized", __func__, aaudioFormat);
break;
}
return androidFormat;
}
aaudio_format_t AAudioConvert_androidToAAudioDataFormat(audio_format_t androidFormat) {
aaudio_format_t aaudioFormat;
switch (androidFormat) {
case AUDIO_FORMAT_DEFAULT:
aaudioFormat = AAUDIO_FORMAT_UNSPECIFIED;
break;
case AUDIO_FORMAT_PCM_16_BIT:
aaudioFormat = AAUDIO_FORMAT_PCM_I16;
break;
case AUDIO_FORMAT_PCM_FLOAT:
aaudioFormat = AAUDIO_FORMAT_PCM_FLOAT;
break;
default:
aaudioFormat = AAUDIO_FORMAT_INVALID;
ALOGE("%s() 0x%08X unrecognized", __func__, androidFormat);
break;
}
return aaudioFormat;
}
// Make a message string from the condition.
#define STATIC_ASSERT(condition) static_assert(condition, #condition)
audio_usage_t AAudioConvert_usageToInternal(aaudio_usage_t usage) {
// The public aaudio_content_type_t constants are supposed to have the same
// values as the internal audio_content_type_t values.
STATIC_ASSERT(AAUDIO_USAGE_MEDIA == AUDIO_USAGE_MEDIA);
STATIC_ASSERT(AAUDIO_USAGE_VOICE_COMMUNICATION == AUDIO_USAGE_VOICE_COMMUNICATION);
STATIC_ASSERT(AAUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING
== AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING);
STATIC_ASSERT(AAUDIO_USAGE_ALARM == AUDIO_USAGE_ALARM);
STATIC_ASSERT(AAUDIO_USAGE_NOTIFICATION == AUDIO_USAGE_NOTIFICATION);
STATIC_ASSERT(AAUDIO_USAGE_NOTIFICATION_RINGTONE
== AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE);
STATIC_ASSERT(AAUDIO_USAGE_NOTIFICATION_EVENT == AUDIO_USAGE_NOTIFICATION_EVENT);
STATIC_ASSERT(AAUDIO_USAGE_ASSISTANCE_ACCESSIBILITY == AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY);
STATIC_ASSERT(AAUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE
== AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE);
STATIC_ASSERT(AAUDIO_USAGE_ASSISTANCE_SONIFICATION == AUDIO_USAGE_ASSISTANCE_SONIFICATION);
STATIC_ASSERT(AAUDIO_USAGE_GAME == AUDIO_USAGE_GAME);
STATIC_ASSERT(AAUDIO_USAGE_ASSISTANT == AUDIO_USAGE_ASSISTANT);
if (usage == AAUDIO_UNSPECIFIED) {
usage = AAUDIO_USAGE_MEDIA;
}
return (audio_usage_t) usage; // same value
}
audio_content_type_t AAudioConvert_contentTypeToInternal(aaudio_content_type_t contentType) {
// The public aaudio_content_type_t constants are supposed to have the same
// values as the internal audio_content_type_t values.
STATIC_ASSERT(AAUDIO_CONTENT_TYPE_MUSIC == AUDIO_CONTENT_TYPE_MUSIC);
STATIC_ASSERT(AAUDIO_CONTENT_TYPE_SPEECH == AUDIO_CONTENT_TYPE_SPEECH);
STATIC_ASSERT(AAUDIO_CONTENT_TYPE_SONIFICATION == AUDIO_CONTENT_TYPE_SONIFICATION);
STATIC_ASSERT(AAUDIO_CONTENT_TYPE_MOVIE == AUDIO_CONTENT_TYPE_MOVIE);
if (contentType == AAUDIO_UNSPECIFIED) {
contentType = AAUDIO_CONTENT_TYPE_MUSIC;
}
return (audio_content_type_t) contentType; // same value
}
audio_source_t AAudioConvert_inputPresetToAudioSource(aaudio_input_preset_t preset) {
// The public aaudio_input_preset_t constants are supposed to have the same
// values as the internal audio_source_t values.
STATIC_ASSERT(AAUDIO_UNSPECIFIED == AUDIO_SOURCE_DEFAULT);
STATIC_ASSERT(AAUDIO_INPUT_PRESET_GENERIC == AUDIO_SOURCE_MIC);
STATIC_ASSERT(AAUDIO_INPUT_PRESET_CAMCORDER == AUDIO_SOURCE_CAMCORDER);
STATIC_ASSERT(AAUDIO_INPUT_PRESET_VOICE_RECOGNITION == AUDIO_SOURCE_VOICE_RECOGNITION);
STATIC_ASSERT(AAUDIO_INPUT_PRESET_VOICE_COMMUNICATION == AUDIO_SOURCE_VOICE_COMMUNICATION);
STATIC_ASSERT(AAUDIO_INPUT_PRESET_UNPROCESSED == AUDIO_SOURCE_UNPROCESSED);
STATIC_ASSERT(AAUDIO_INPUT_PRESET_VOICE_PERFORMANCE == AUDIO_SOURCE_VOICE_PERFORMANCE);
if (preset == AAUDIO_UNSPECIFIED) {
preset = AAUDIO_INPUT_PRESET_VOICE_RECOGNITION;
}
return (audio_source_t) preset; // same value
}
audio_flags_mask_t AAudioConvert_allowCapturePolicyToAudioFlagsMask(
aaudio_allowed_capture_policy_t policy) {
switch (policy) {
case AAUDIO_UNSPECIFIED:
case AAUDIO_ALLOW_CAPTURE_BY_ALL:
return AUDIO_FLAG_NONE;
case AAUDIO_ALLOW_CAPTURE_BY_SYSTEM:
return AUDIO_FLAG_NO_MEDIA_PROJECTION;
case AAUDIO_ALLOW_CAPTURE_BY_NONE:
return AUDIO_FLAG_NO_MEDIA_PROJECTION | AUDIO_FLAG_NO_SYSTEM_CAPTURE;
default:
ALOGE("%s() 0x%08X unrecognized", __func__, policy);
return AUDIO_FLAG_NONE; //
}
}
int32_t AAudioConvert_framesToBytes(int32_t numFrames,
int32_t bytesPerFrame,
int32_t *sizeInBytes) {
*sizeInBytes = 0;
if (numFrames < 0 || bytesPerFrame < 0) {
ALOGE("negative size, numFrames = %d, frameSize = %d", numFrames, bytesPerFrame);
return AAUDIO_ERROR_OUT_OF_RANGE;
}
// Prevent numeric overflow.
if (numFrames > (INT32_MAX / bytesPerFrame)) {
ALOGE("size overflow, numFrames = %d, frameSize = %d", numFrames, bytesPerFrame);
return AAUDIO_ERROR_OUT_OF_RANGE;
}
*sizeInBytes = numFrames * bytesPerFrame;
return AAUDIO_OK;
}
static int32_t AAudioProperty_getMMapProperty(const char *propName,
int32_t defaultValue,
const char * caller) {
int32_t prop = property_get_int32(propName, defaultValue);
switch (prop) {
case AAUDIO_UNSPECIFIED:
case AAUDIO_POLICY_NEVER:
case AAUDIO_POLICY_ALWAYS:
case AAUDIO_POLICY_AUTO:
break;
default:
ALOGE("%s: invalid = %d", caller, prop);
prop = defaultValue;
break;
}
return prop;
}
int32_t AAudioProperty_getMMapPolicy() {
return AAudioProperty_getMMapProperty(AAUDIO_PROP_MMAP_POLICY,
AAUDIO_UNSPECIFIED, __func__);
}
int32_t AAudioProperty_getMMapExclusivePolicy() {
return AAudioProperty_getMMapProperty(AAUDIO_PROP_MMAP_EXCLUSIVE_POLICY,
AAUDIO_UNSPECIFIED, __func__);
}
int32_t AAudioProperty_getMixerBursts() {
const int32_t defaultBursts = 2; // arbitrary, use 2 for double buffered
const int32_t maxBursts = 1024; // arbitrary
int32_t prop = property_get_int32(AAUDIO_PROP_MIXER_BURSTS, defaultBursts);
if (prop < 1 || prop > maxBursts) {
ALOGE("AAudioProperty_getMixerBursts: invalid = %d", prop);
prop = defaultBursts;
}
return prop;
}
int32_t AAudioProperty_getWakeupDelayMicros() {
const int32_t minMicros = 0; // arbitrary
const int32_t defaultMicros = 200; // arbitrary, based on some observed jitter
const int32_t maxMicros = 5000; // arbitrary, probably don't want more than 500
int32_t prop = property_get_int32(AAUDIO_PROP_WAKEUP_DELAY_USEC, defaultMicros);
if (prop < minMicros) {
ALOGW("AAudioProperty_getWakeupDelayMicros: clipped %d to %d", prop, minMicros);
prop = minMicros;
} else if (prop > maxMicros) {
ALOGW("AAudioProperty_getWakeupDelayMicros: clipped %d to %d", prop, maxMicros);
prop = maxMicros;
}
return prop;
}
int32_t AAudioProperty_getMinimumSleepMicros() {
const int32_t minMicros = 20; // arbitrary
const int32_t defaultMicros = 200; // arbitrary
const int32_t maxMicros = 2000; // arbitrary
int32_t prop = property_get_int32(AAUDIO_PROP_MINIMUM_SLEEP_USEC, defaultMicros);
if (prop < minMicros) {
ALOGW("AAudioProperty_getMinimumSleepMicros: clipped %d to %d", prop, minMicros);
prop = minMicros;
} else if (prop > maxMicros) {
ALOGW("AAudioProperty_getMinimumSleepMicros: clipped %d to %d", prop, maxMicros);
prop = maxMicros;
}
return prop;
}
int32_t AAudioProperty_getHardwareBurstMinMicros() {
const int32_t defaultMicros = 1000; // arbitrary
const int32_t maxMicros = 1000 * 1000; // arbitrary
int32_t prop = property_get_int32(AAUDIO_PROP_HW_BURST_MIN_USEC, defaultMicros);
if (prop < 1 || prop > maxMicros) {
ALOGE("AAudioProperty_getHardwareBurstMinMicros: invalid = %d, use %d",
prop, defaultMicros);
prop = defaultMicros;
}
return prop;
}
aaudio_result_t AAudio_isFlushAllowed(aaudio_stream_state_t state) {
aaudio_result_t result = AAUDIO_OK;
switch (state) {
// Proceed with flushing.
case AAUDIO_STREAM_STATE_OPEN:
case AAUDIO_STREAM_STATE_PAUSED:
case AAUDIO_STREAM_STATE_STOPPED:
case AAUDIO_STREAM_STATE_FLUSHED:
break;
// Transition from one inactive state to another.
case AAUDIO_STREAM_STATE_STARTING:
case AAUDIO_STREAM_STATE_STARTED:
case AAUDIO_STREAM_STATE_STOPPING:
case AAUDIO_STREAM_STATE_PAUSING:
case AAUDIO_STREAM_STATE_FLUSHING:
case AAUDIO_STREAM_STATE_CLOSING:
case AAUDIO_STREAM_STATE_CLOSED:
case AAUDIO_STREAM_STATE_DISCONNECTED:
default:
ALOGE("can only flush stream when PAUSED, OPEN or STOPPED, state = %s",
aaudio::AudioGlobal_convertStreamStateToText(state));
result = AAUDIO_ERROR_INVALID_STATE;
break;
}
return result;
}