/* * 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 #include #include #include #include #include "aaudio/AAudio.h" #include "core/AudioGlobal.h" #include #include #include #include #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); STATIC_ASSERT(AAUDIO_SYSTEM_USAGE_EMERGENCY == AUDIO_USAGE_EMERGENCY); STATIC_ASSERT(AAUDIO_SYSTEM_USAGE_SAFETY == AUDIO_USAGE_SAFETY); STATIC_ASSERT(AAUDIO_SYSTEM_USAGE_VEHICLE_STATUS == AUDIO_USAGE_VEHICLE_STATUS); STATIC_ASSERT(AAUDIO_SYSTEM_USAGE_ANNOUNCEMENT == AUDIO_USAGE_ANNOUNCEMENT); 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; // } } audio_flags_mask_t AAudioConvert_privacySensitiveToAudioFlagsMask( bool privacySensitive) { return privacySensitive ? AUDIO_FLAG_CAPTURE_PRIVATE : 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; } static int32_t AAudioProperty_getMMapOffsetMicros(const char *functionName, const char *propertyName) { const int32_t minMicros = -20000; // arbitrary const int32_t defaultMicros = 0; // arbitrary const int32_t maxMicros = 20000; // arbitrary int32_t prop = property_get_int32(propertyName, defaultMicros); if (prop < minMicros) { ALOGW("%s: clipped %d to %d", functionName, prop, minMicros); prop = minMicros; } else if (prop > maxMicros) { ALOGW("%s: clipped %d to %d", functionName, prop, minMicros); prop = maxMicros; } return prop; } int32_t AAudioProperty_getInputMMapOffsetMicros() { return AAudioProperty_getMMapOffsetMicros(__func__, AAUDIO_PROP_INPUT_MMAP_OFFSET_USEC); } int32_t AAudioProperty_getOutputMMapOffsetMicros() { return AAudioProperty_getMMapOffsetMicros(__func__, AAUDIO_PROP_OUTPUT_MMAP_OFFSET_USEC); } int32_t AAudioProperty_getLogMask() { return property_get_int32(AAUDIO_PROP_LOG_MASK, 0); } 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; }