AAudioUtilities.cpp revision e572f469de5dca1078a79d3d80e5b04f96ae7505
1/* 2 * Copyright 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#define LOG_TAG "AAudio" 18//#define LOG_NDEBUG 0 19#include <utils/Log.h> 20 21#include <stdint.h> 22#include <sys/types.h> 23#include <utils/Errors.h> 24 25#include "aaudio/AAudio.h" 26#include "AAudioUtilities.h" 27 28using namespace android; 29 30// This is 3 dB, (10^(3/20)), to match the maximum headroom in AudioTrack for float data. 31// It is designed to allow occasional transient peaks. 32#define MAX_HEADROOM (1.41253754f) 33#define MIN_HEADROOM (0 - MAX_HEADROOM) 34 35int32_t AAudioConvert_formatToSizeInBytes(aaudio_audio_format_t format) { 36 int32_t size = AAUDIO_ERROR_ILLEGAL_ARGUMENT; 37 switch (format) { 38 case AAUDIO_FORMAT_PCM_I16: 39 size = sizeof(int16_t); 40 break; 41 case AAUDIO_FORMAT_PCM_FLOAT: 42 size = sizeof(float); 43 break; 44 default: 45 break; 46 } 47 return size; 48} 49 50 51// TODO call clamp16_from_float function in primitives.h 52static inline int16_t clamp16_from_float(float f) { 53 /* Offset is used to expand the valid range of [-1.0, 1.0) into the 16 lsbs of the 54 * floating point significand. The normal shift is 3<<22, but the -15 offset 55 * is used to multiply by 32768. 56 */ 57 static const float offset = (float)(3 << (22 - 15)); 58 /* zero = (0x10f << 22) = 0x43c00000 (not directly used) */ 59 static const int32_t limneg = (0x10f << 22) /*zero*/ - 32768; /* 0x43bf8000 */ 60 static const int32_t limpos = (0x10f << 22) /*zero*/ + 32767; /* 0x43c07fff */ 61 62 union { 63 float f; 64 int32_t i; 65 } u; 66 67 u.f = f + offset; /* recenter valid range */ 68 /* Now the valid range is represented as integers between [limneg, limpos]. 69 * Clamp using the fact that float representation (as an integer) is an ordered set. 70 */ 71 if (u.i < limneg) 72 u.i = -32768; 73 else if (u.i > limpos) 74 u.i = 32767; 75 return u.i; /* Return lower 16 bits, the part of interest in the significand. */ 76} 77 78// Same but without clipping. 79// Convert -1.0f to +1.0f to -32768 to +32767 80static inline int16_t floatToInt16(float f) { 81 static const float offset = (float)(3 << (22 - 15)); 82 union { 83 float f; 84 int32_t i; 85 } u; 86 u.f = f + offset; /* recenter valid range */ 87 return u.i; /* Return lower 16 bits, the part of interest in the significand. */ 88} 89 90static float clipAndClampFloatToPcm16(float sample, float scaler) { 91 // Clip to valid range of a float sample to prevent excessive volume. 92 if (sample > MAX_HEADROOM) sample = MAX_HEADROOM; 93 else if (sample < MIN_HEADROOM) sample = MIN_HEADROOM; 94 95 // Scale and convert to a short. 96 float fval = sample * scaler; 97 return clamp16_from_float(fval); 98} 99 100void AAudioConvert_floatToPcm16(const float *source, 101 int16_t *destination, 102 int32_t numSamples, 103 float amplitude) { 104 float scaler = amplitude; 105 for (int i = 0; i < numSamples; i++) { 106 float sample = *source++; 107 *destination++ = clipAndClampFloatToPcm16(sample, scaler); 108 } 109} 110 111void AAudioConvert_floatToPcm16(const float *source, 112 int16_t *destination, 113 int32_t numFrames, 114 int32_t samplesPerFrame, 115 float amplitude1, 116 float amplitude2) { 117 float scaler = amplitude1; 118 // divide by numFrames so that we almost reach amplitude2 119 float delta = (amplitude2 - amplitude1) / numFrames; 120 for (int frameIndex = 0; frameIndex < numFrames; frameIndex++) { 121 for (int sampleIndex = 0; sampleIndex < samplesPerFrame; sampleIndex++) { 122 float sample = *source++; 123 *destination++ = clipAndClampFloatToPcm16(sample, scaler); 124 } 125 scaler += delta; 126 } 127} 128 129#define SHORT_SCALE 32768 130 131void AAudioConvert_pcm16ToFloat(const int16_t *source, 132 float *destination, 133 int32_t numSamples, 134 float amplitude) { 135 float scaler = amplitude / SHORT_SCALE; 136 for (int i = 0; i < numSamples; i++) { 137 destination[i] = source[i] * scaler; 138 } 139} 140 141// This code assumes amplitude1 and amplitude2 are between 0.0 and 1.0 142void AAudioConvert_pcm16ToFloat(const int16_t *source, 143 float *destination, 144 int32_t numFrames, 145 int32_t samplesPerFrame, 146 float amplitude1, 147 float amplitude2) { 148 float scaler = amplitude1 / SHORT_SCALE; 149 float delta = (amplitude2 - amplitude1) / (SHORT_SCALE * (float) numFrames); 150 for (int frameIndex = 0; frameIndex < numFrames; frameIndex++) { 151 for (int sampleIndex = 0; sampleIndex < samplesPerFrame; sampleIndex++) { 152 *destination++ = *source++ * scaler; 153 } 154 scaler += delta; 155 } 156} 157 158// This code assumes amplitude1 and amplitude2 are between 0.0 and 1.0 159void AAudio_linearRamp(const float *source, 160 float *destination, 161 int32_t numFrames, 162 int32_t samplesPerFrame, 163 float amplitude1, 164 float amplitude2) { 165 float scaler = amplitude1; 166 float delta = (amplitude2 - amplitude1) / numFrames; 167 for (int frameIndex = 0; frameIndex < numFrames; frameIndex++) { 168 for (int sampleIndex = 0; sampleIndex < samplesPerFrame; sampleIndex++) { 169 float sample = *source++; 170 171 // Clip to valid range of a float sample to prevent excessive volume. 172 if (sample > MAX_HEADROOM) sample = MAX_HEADROOM; 173 else if (sample < MIN_HEADROOM) sample = MIN_HEADROOM; 174 175 *destination++ = sample * scaler; 176 } 177 scaler += delta; 178 } 179} 180 181// This code assumes amplitude1 and amplitude2 are between 0.0 and 1.0 182void AAudio_linearRamp(const int16_t *source, 183 int16_t *destination, 184 int32_t numFrames, 185 int32_t samplesPerFrame, 186 float amplitude1, 187 float amplitude2) { 188 float scaler = amplitude1 / SHORT_SCALE; 189 float delta = (amplitude2 - amplitude1) / (SHORT_SCALE * (float) numFrames); 190 for (int frameIndex = 0; frameIndex < numFrames; frameIndex++) { 191 for (int sampleIndex = 0; sampleIndex < samplesPerFrame; sampleIndex++) { 192 // No need to clip because int16_t range is inherently limited. 193 float sample = *source++ * scaler; 194 *destination++ = floatToInt16(sample); 195 } 196 scaler += delta; 197 } 198} 199 200status_t AAudioConvert_aaudioToAndroidStatus(aaudio_result_t result) { 201 // This covers the case for AAUDIO_OK and for positive results. 202 if (result >= 0) { 203 return result; 204 } 205 status_t status; 206 switch (result) { 207 case AAUDIO_ERROR_DISCONNECTED: 208 case AAUDIO_ERROR_INVALID_HANDLE: 209 status = DEAD_OBJECT; 210 break; 211 case AAUDIO_ERROR_INVALID_STATE: 212 status = INVALID_OPERATION; 213 break; 214 case AAUDIO_ERROR_UNEXPECTED_VALUE: // TODO redundant? 215 case AAUDIO_ERROR_INVALID_RATE: 216 case AAUDIO_ERROR_INVALID_FORMAT: 217 case AAUDIO_ERROR_ILLEGAL_ARGUMENT: 218 status = BAD_VALUE; 219 break; 220 case AAUDIO_ERROR_WOULD_BLOCK: 221 status = WOULD_BLOCK; 222 break; 223 // TODO add more result codes 224 default: 225 status = UNKNOWN_ERROR; 226 break; 227 } 228 return status; 229} 230 231aaudio_result_t AAudioConvert_androidToAAudioResult(status_t status) { 232 // This covers the case for OK and for positive result. 233 if (status >= 0) { 234 return status; 235 } 236 aaudio_result_t result; 237 switch (status) { 238 case BAD_TYPE: 239 result = AAUDIO_ERROR_INVALID_HANDLE; 240 break; 241 case DEAD_OBJECT: 242 result = AAUDIO_ERROR_NO_SERVICE; 243 break; 244 case INVALID_OPERATION: 245 result = AAUDIO_ERROR_INVALID_STATE; 246 break; 247 case BAD_VALUE: 248 result = AAUDIO_ERROR_UNEXPECTED_VALUE; 249 break; 250 case WOULD_BLOCK: 251 result = AAUDIO_ERROR_WOULD_BLOCK; 252 break; 253 // TODO add more status codes 254 default: 255 result = AAUDIO_ERROR_INTERNAL; 256 break; 257 } 258 return result; 259} 260 261audio_format_t AAudioConvert_aaudioToAndroidDataFormat(aaudio_audio_format_t aaudioFormat) { 262 audio_format_t androidFormat; 263 switch (aaudioFormat) { 264 case AAUDIO_FORMAT_PCM_I16: 265 androidFormat = AUDIO_FORMAT_PCM_16_BIT; 266 break; 267 case AAUDIO_FORMAT_PCM_FLOAT: 268 androidFormat = AUDIO_FORMAT_PCM_FLOAT; 269 break; 270 default: 271 androidFormat = AUDIO_FORMAT_DEFAULT; 272 ALOGE("AAudioConvert_aaudioToAndroidDataFormat 0x%08X unrecognized", aaudioFormat); 273 break; 274 } 275 return androidFormat; 276} 277 278aaudio_audio_format_t AAudioConvert_androidToAAudioDataFormat(audio_format_t androidFormat) { 279 aaudio_audio_format_t aaudioFormat = AAUDIO_FORMAT_INVALID; 280 switch (androidFormat) { 281 case AUDIO_FORMAT_PCM_16_BIT: 282 aaudioFormat = AAUDIO_FORMAT_PCM_I16; 283 break; 284 case AUDIO_FORMAT_PCM_FLOAT: 285 aaudioFormat = AAUDIO_FORMAT_PCM_FLOAT; 286 break; 287 default: 288 aaudioFormat = AAUDIO_FORMAT_INVALID; 289 ALOGE("AAudioConvert_androidToAAudioDataFormat 0x%08X unrecognized", androidFormat); 290 break; 291 } 292 return aaudioFormat; 293} 294 295int32_t AAudioConvert_framesToBytes(int32_t numFrames, 296 int32_t bytesPerFrame, 297 int32_t *sizeInBytes) { 298 // TODO implement more elegantly 299 const int32_t maxChannels = 256; // ridiculously large 300 const int32_t maxBytesPerFrame = maxChannels * sizeof(float); 301 // Prevent overflow by limiting multiplicands. 302 if (bytesPerFrame > maxBytesPerFrame || numFrames > (0x3FFFFFFF / maxBytesPerFrame)) { 303 ALOGE("size overflow, numFrames = %d, frameSize = %zd", numFrames, bytesPerFrame); 304 return AAUDIO_ERROR_OUT_OF_RANGE; 305 } 306 *sizeInBytes = numFrames * bytesPerFrame; 307 return AAUDIO_OK; 308} 309