AAudioUtilities.cpp revision 5204d315c6c6f53188f8d1414dd1b55b6c90142b
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 expose and 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 case AAUDIO_ERROR_UNEXPECTED_STATE: 213 status = INVALID_OPERATION; 214 break; 215 case AAUDIO_ERROR_UNEXPECTED_VALUE: 216 case AAUDIO_ERROR_INVALID_RATE: 217 case AAUDIO_ERROR_INVALID_FORMAT: 218 case AAUDIO_ERROR_ILLEGAL_ARGUMENT: 219 case AAUDIO_ERROR_OUT_OF_RANGE: 220 status = BAD_VALUE; 221 break; 222 case AAUDIO_ERROR_WOULD_BLOCK: 223 status = WOULD_BLOCK; 224 break; 225 case AAUDIO_ERROR_NULL: 226 status = UNEXPECTED_NULL; 227 break; 228 // TODO translate these result codes 229 case AAUDIO_ERROR_INCOMPATIBLE: 230 case AAUDIO_ERROR_INTERNAL: 231 case AAUDIO_ERROR_INVALID_QUERY: 232 case AAUDIO_ERROR_UNIMPLEMENTED: 233 case AAUDIO_ERROR_UNAVAILABLE: 234 case AAUDIO_ERROR_NO_FREE_HANDLES: 235 case AAUDIO_ERROR_NO_MEMORY: 236 case AAUDIO_ERROR_TIMEOUT: 237 case AAUDIO_ERROR_NO_SERVICE: 238 default: 239 status = UNKNOWN_ERROR; 240 break; 241 } 242 return status; 243} 244 245aaudio_result_t AAudioConvert_androidToAAudioResult(status_t status) { 246 // This covers the case for OK and for positive result. 247 if (status >= 0) { 248 return status; 249 } 250 aaudio_result_t result; 251 switch (status) { 252 case BAD_TYPE: 253 result = AAUDIO_ERROR_INVALID_HANDLE; 254 break; 255 case DEAD_OBJECT: 256 result = AAUDIO_ERROR_NO_SERVICE; 257 break; 258 case INVALID_OPERATION: 259 result = AAUDIO_ERROR_INVALID_STATE; 260 break; 261 case UNEXPECTED_NULL: 262 result = AAUDIO_ERROR_NULL; 263 break; 264 case BAD_VALUE: 265 result = AAUDIO_ERROR_UNEXPECTED_VALUE; 266 break; 267 case WOULD_BLOCK: 268 result = AAUDIO_ERROR_WOULD_BLOCK; 269 break; 270 default: 271 result = AAUDIO_ERROR_INTERNAL; 272 break; 273 } 274 return result; 275} 276 277audio_format_t AAudioConvert_aaudioToAndroidDataFormat(aaudio_audio_format_t aaudioFormat) { 278 audio_format_t androidFormat; 279 switch (aaudioFormat) { 280 case AAUDIO_FORMAT_PCM_I16: 281 androidFormat = AUDIO_FORMAT_PCM_16_BIT; 282 break; 283 case AAUDIO_FORMAT_PCM_FLOAT: 284 androidFormat = AUDIO_FORMAT_PCM_FLOAT; 285 break; 286 default: 287 androidFormat = AUDIO_FORMAT_DEFAULT; 288 ALOGE("AAudioConvert_aaudioToAndroidDataFormat 0x%08X unrecognized", aaudioFormat); 289 break; 290 } 291 return androidFormat; 292} 293 294aaudio_audio_format_t AAudioConvert_androidToAAudioDataFormat(audio_format_t androidFormat) { 295 aaudio_audio_format_t aaudioFormat = AAUDIO_FORMAT_INVALID; 296 switch (androidFormat) { 297 case AUDIO_FORMAT_PCM_16_BIT: 298 aaudioFormat = AAUDIO_FORMAT_PCM_I16; 299 break; 300 case AUDIO_FORMAT_PCM_FLOAT: 301 aaudioFormat = AAUDIO_FORMAT_PCM_FLOAT; 302 break; 303 default: 304 aaudioFormat = AAUDIO_FORMAT_INVALID; 305 ALOGE("AAudioConvert_androidToAAudioDataFormat 0x%08X unrecognized", androidFormat); 306 break; 307 } 308 return aaudioFormat; 309} 310 311int32_t AAudioConvert_framesToBytes(int32_t numFrames, 312 int32_t bytesPerFrame, 313 int32_t *sizeInBytes) { 314 // TODO implement more elegantly 315 const int32_t maxChannels = 256; // ridiculously large 316 const int32_t maxBytesPerFrame = maxChannels * sizeof(float); 317 // Prevent overflow by limiting multiplicands. 318 if (bytesPerFrame > maxBytesPerFrame || numFrames > (0x3FFFFFFF / maxBytesPerFrame)) { 319 ALOGE("size overflow, numFrames = %d, frameSize = %zd", numFrames, bytesPerFrame); 320 return AAUDIO_ERROR_OUT_OF_RANGE; 321 } 322 *sizeInBytes = numFrames * bytesPerFrame; 323 return AAUDIO_OK; 324} 325