blob: ef7b4444104d7cdb934289e6ffbfbca8860a153a [file] [log] [blame]
Phil Burk5ed503c2017-02-01 09:38:15 -08001/*
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
Phil Burkc8f69a02017-05-11 15:53:06 -070021#include <cutils/properties.h>
Phil Burk5ed503c2017-02-01 09:38:15 -080022#include <stdint.h>
23#include <sys/types.h>
24#include <utils/Errors.h>
25
Phil Burka4eb0d82017-04-12 15:44:06 -070026#include "aaudio/AAudio.h"
Phil Burk5ed503c2017-02-01 09:38:15 -080027#include "AAudioUtilities.h"
28
29using namespace android;
30
Phil Burke572f462017-04-20 13:03:19 -070031// This is 3 dB, (10^(3/20)), to match the maximum headroom in AudioTrack for float data.
32// It is designed to allow occasional transient peaks.
33#define MAX_HEADROOM (1.41253754f)
34#define MIN_HEADROOM (0 - MAX_HEADROOM)
35
Phil Burk3316d5e2017-02-15 11:23:01 -080036int32_t AAudioConvert_formatToSizeInBytes(aaudio_audio_format_t format) {
37 int32_t size = AAUDIO_ERROR_ILLEGAL_ARGUMENT;
Phil Burk5ed503c2017-02-01 09:38:15 -080038 switch (format) {
39 case AAUDIO_FORMAT_PCM_I16:
40 size = sizeof(int16_t);
41 break;
Phil Burk5ed503c2017-02-01 09:38:15 -080042 case AAUDIO_FORMAT_PCM_FLOAT:
43 size = sizeof(float);
44 break;
45 default:
46 break;
47 }
48 return size;
49}
50
Phil Burke572f462017-04-20 13:03:19 -070051
Phil Burk5204d312017-05-04 17:16:13 -070052// TODO expose and call clamp16_from_float function in primitives.h
Phil Burke572f462017-04-20 13:03:19 -070053static inline int16_t clamp16_from_float(float f) {
54 /* Offset is used to expand the valid range of [-1.0, 1.0) into the 16 lsbs of the
55 * floating point significand. The normal shift is 3<<22, but the -15 offset
56 * is used to multiply by 32768.
57 */
58 static const float offset = (float)(3 << (22 - 15));
59 /* zero = (0x10f << 22) = 0x43c00000 (not directly used) */
60 static const int32_t limneg = (0x10f << 22) /*zero*/ - 32768; /* 0x43bf8000 */
61 static const int32_t limpos = (0x10f << 22) /*zero*/ + 32767; /* 0x43c07fff */
62
63 union {
64 float f;
65 int32_t i;
66 } u;
67
68 u.f = f + offset; /* recenter valid range */
69 /* Now the valid range is represented as integers between [limneg, limpos].
70 * Clamp using the fact that float representation (as an integer) is an ordered set.
71 */
72 if (u.i < limneg)
73 u.i = -32768;
74 else if (u.i > limpos)
75 u.i = 32767;
76 return u.i; /* Return lower 16 bits, the part of interest in the significand. */
77}
78
79// Same but without clipping.
80// Convert -1.0f to +1.0f to -32768 to +32767
81static inline int16_t floatToInt16(float f) {
82 static const float offset = (float)(3 << (22 - 15));
83 union {
84 float f;
85 int32_t i;
86 } u;
87 u.f = f + offset; /* recenter valid range */
88 return u.i; /* Return lower 16 bits, the part of interest in the significand. */
89}
90
91static float clipAndClampFloatToPcm16(float sample, float scaler) {
92 // Clip to valid range of a float sample to prevent excessive volume.
93 if (sample > MAX_HEADROOM) sample = MAX_HEADROOM;
94 else if (sample < MIN_HEADROOM) sample = MIN_HEADROOM;
95
96 // Scale and convert to a short.
97 float fval = sample * scaler;
98 return clamp16_from_float(fval);
99}
100
101void AAudioConvert_floatToPcm16(const float *source,
102 int16_t *destination,
103 int32_t numSamples,
104 float amplitude) {
105 float scaler = amplitude;
Phil Burk5ed503c2017-02-01 09:38:15 -0800106 for (int i = 0; i < numSamples; i++) {
Phil Burke572f462017-04-20 13:03:19 -0700107 float sample = *source++;
108 *destination++ = clipAndClampFloatToPcm16(sample, scaler);
Phil Burk5ed503c2017-02-01 09:38:15 -0800109 }
110}
111
Phil Burke572f462017-04-20 13:03:19 -0700112void AAudioConvert_floatToPcm16(const float *source,
113 int16_t *destination,
114 int32_t numFrames,
115 int32_t samplesPerFrame,
116 float amplitude1,
117 float amplitude2) {
118 float scaler = amplitude1;
119 // divide by numFrames so that we almost reach amplitude2
120 float delta = (amplitude2 - amplitude1) / numFrames;
121 for (int frameIndex = 0; frameIndex < numFrames; frameIndex++) {
122 for (int sampleIndex = 0; sampleIndex < samplesPerFrame; sampleIndex++) {
123 float sample = *source++;
124 *destination++ = clipAndClampFloatToPcm16(sample, scaler);
125 }
126 scaler += delta;
127 }
128}
129
130#define SHORT_SCALE 32768
131
132void AAudioConvert_pcm16ToFloat(const int16_t *source,
133 float *destination,
134 int32_t numSamples,
135 float amplitude) {
136 float scaler = amplitude / SHORT_SCALE;
Phil Burk5ed503c2017-02-01 09:38:15 -0800137 for (int i = 0; i < numSamples; i++) {
Phil Burke572f462017-04-20 13:03:19 -0700138 destination[i] = source[i] * scaler;
139 }
140}
141
142// This code assumes amplitude1 and amplitude2 are between 0.0 and 1.0
143void AAudioConvert_pcm16ToFloat(const int16_t *source,
144 float *destination,
145 int32_t numFrames,
146 int32_t samplesPerFrame,
147 float amplitude1,
148 float amplitude2) {
149 float scaler = amplitude1 / SHORT_SCALE;
150 float delta = (amplitude2 - amplitude1) / (SHORT_SCALE * (float) numFrames);
151 for (int frameIndex = 0; frameIndex < numFrames; frameIndex++) {
152 for (int sampleIndex = 0; sampleIndex < samplesPerFrame; sampleIndex++) {
153 *destination++ = *source++ * scaler;
154 }
155 scaler += delta;
156 }
157}
158
159// This code assumes amplitude1 and amplitude2 are between 0.0 and 1.0
160void AAudio_linearRamp(const float *source,
161 float *destination,
162 int32_t numFrames,
163 int32_t samplesPerFrame,
164 float amplitude1,
165 float amplitude2) {
166 float scaler = amplitude1;
167 float delta = (amplitude2 - amplitude1) / numFrames;
168 for (int frameIndex = 0; frameIndex < numFrames; frameIndex++) {
169 for (int sampleIndex = 0; sampleIndex < samplesPerFrame; sampleIndex++) {
170 float sample = *source++;
171
172 // Clip to valid range of a float sample to prevent excessive volume.
173 if (sample > MAX_HEADROOM) sample = MAX_HEADROOM;
174 else if (sample < MIN_HEADROOM) sample = MIN_HEADROOM;
175
176 *destination++ = sample * scaler;
177 }
178 scaler += delta;
179 }
180}
181
182// This code assumes amplitude1 and amplitude2 are between 0.0 and 1.0
183void AAudio_linearRamp(const int16_t *source,
184 int16_t *destination,
185 int32_t numFrames,
186 int32_t samplesPerFrame,
187 float amplitude1,
188 float amplitude2) {
189 float scaler = amplitude1 / SHORT_SCALE;
190 float delta = (amplitude2 - amplitude1) / (SHORT_SCALE * (float) numFrames);
191 for (int frameIndex = 0; frameIndex < numFrames; frameIndex++) {
192 for (int sampleIndex = 0; sampleIndex < samplesPerFrame; sampleIndex++) {
193 // No need to clip because int16_t range is inherently limited.
194 float sample = *source++ * scaler;
195 *destination++ = floatToInt16(sample);
196 }
197 scaler += delta;
Phil Burk5ed503c2017-02-01 09:38:15 -0800198 }
199}
200
201status_t AAudioConvert_aaudioToAndroidStatus(aaudio_result_t result) {
202 // This covers the case for AAUDIO_OK and for positive results.
203 if (result >= 0) {
204 return result;
205 }
206 status_t status;
207 switch (result) {
208 case AAUDIO_ERROR_DISCONNECTED:
209 case AAUDIO_ERROR_INVALID_HANDLE:
210 status = DEAD_OBJECT;
211 break;
212 case AAUDIO_ERROR_INVALID_STATE:
213 status = INVALID_OPERATION;
214 break;
Phil Burk71f35bb2017-04-13 16:05:07 -0700215 case AAUDIO_ERROR_INVALID_RATE:
216 case AAUDIO_ERROR_INVALID_FORMAT:
Phil Burk5ed503c2017-02-01 09:38:15 -0800217 case AAUDIO_ERROR_ILLEGAL_ARGUMENT:
Phil Burk5204d312017-05-04 17:16:13 -0700218 case AAUDIO_ERROR_OUT_OF_RANGE:
Phil Burk5ed503c2017-02-01 09:38:15 -0800219 status = BAD_VALUE;
220 break;
221 case AAUDIO_ERROR_WOULD_BLOCK:
222 status = WOULD_BLOCK;
223 break;
Phil Burk5204d312017-05-04 17:16:13 -0700224 case AAUDIO_ERROR_NULL:
225 status = UNEXPECTED_NULL;
226 break;
227 // TODO translate these result codes
Phil Burk5204d312017-05-04 17:16:13 -0700228 case AAUDIO_ERROR_INTERNAL:
Phil Burk5204d312017-05-04 17:16:13 -0700229 case AAUDIO_ERROR_UNIMPLEMENTED:
230 case AAUDIO_ERROR_UNAVAILABLE:
231 case AAUDIO_ERROR_NO_FREE_HANDLES:
232 case AAUDIO_ERROR_NO_MEMORY:
233 case AAUDIO_ERROR_TIMEOUT:
234 case AAUDIO_ERROR_NO_SERVICE:
Phil Burk5ed503c2017-02-01 09:38:15 -0800235 default:
236 status = UNKNOWN_ERROR;
237 break;
238 }
239 return status;
240}
241
242aaudio_result_t AAudioConvert_androidToAAudioResult(status_t status) {
243 // This covers the case for OK and for positive result.
244 if (status >= 0) {
245 return status;
246 }
247 aaudio_result_t result;
248 switch (status) {
249 case BAD_TYPE:
250 result = AAUDIO_ERROR_INVALID_HANDLE;
251 break;
252 case DEAD_OBJECT:
Phil Burk71f35bb2017-04-13 16:05:07 -0700253 result = AAUDIO_ERROR_NO_SERVICE;
Phil Burk5ed503c2017-02-01 09:38:15 -0800254 break;
255 case INVALID_OPERATION:
256 result = AAUDIO_ERROR_INVALID_STATE;
257 break;
Phil Burk5204d312017-05-04 17:16:13 -0700258 case UNEXPECTED_NULL:
259 result = AAUDIO_ERROR_NULL;
260 break;
261 case BAD_VALUE:
Phil Burk17fff382017-05-16 14:06:45 -0700262 result = AAUDIO_ERROR_ILLEGAL_ARGUMENT;
Phil Burk5204d312017-05-04 17:16:13 -0700263 break;
Phil Burk5ed503c2017-02-01 09:38:15 -0800264 case WOULD_BLOCK:
265 result = AAUDIO_ERROR_WOULD_BLOCK;
266 break;
Phil Burk5ed503c2017-02-01 09:38:15 -0800267 default:
268 result = AAUDIO_ERROR_INTERNAL;
269 break;
270 }
271 return result;
272}
273
274audio_format_t AAudioConvert_aaudioToAndroidDataFormat(aaudio_audio_format_t aaudioFormat) {
275 audio_format_t androidFormat;
276 switch (aaudioFormat) {
277 case AAUDIO_FORMAT_PCM_I16:
278 androidFormat = AUDIO_FORMAT_PCM_16_BIT;
279 break;
280 case AAUDIO_FORMAT_PCM_FLOAT:
281 androidFormat = AUDIO_FORMAT_PCM_FLOAT;
282 break;
Phil Burk5ed503c2017-02-01 09:38:15 -0800283 default:
284 androidFormat = AUDIO_FORMAT_DEFAULT;
285 ALOGE("AAudioConvert_aaudioToAndroidDataFormat 0x%08X unrecognized", aaudioFormat);
286 break;
287 }
288 return androidFormat;
289}
290
291aaudio_audio_format_t AAudioConvert_androidToAAudioDataFormat(audio_format_t androidFormat) {
292 aaudio_audio_format_t aaudioFormat = AAUDIO_FORMAT_INVALID;
293 switch (androidFormat) {
294 case AUDIO_FORMAT_PCM_16_BIT:
295 aaudioFormat = AAUDIO_FORMAT_PCM_I16;
296 break;
297 case AUDIO_FORMAT_PCM_FLOAT:
298 aaudioFormat = AAUDIO_FORMAT_PCM_FLOAT;
299 break;
Phil Burk5ed503c2017-02-01 09:38:15 -0800300 default:
301 aaudioFormat = AAUDIO_FORMAT_INVALID;
302 ALOGE("AAudioConvert_androidToAAudioDataFormat 0x%08X unrecognized", androidFormat);
303 break;
304 }
305 return aaudioFormat;
306}
307
Phil Burk3316d5e2017-02-15 11:23:01 -0800308int32_t AAudioConvert_framesToBytes(int32_t numFrames,
309 int32_t bytesPerFrame,
310 int32_t *sizeInBytes) {
Phil Burk5ed503c2017-02-01 09:38:15 -0800311 // TODO implement more elegantly
312 const int32_t maxChannels = 256; // ridiculously large
Phil Burk3316d5e2017-02-15 11:23:01 -0800313 const int32_t maxBytesPerFrame = maxChannels * sizeof(float);
Phil Burk5ed503c2017-02-01 09:38:15 -0800314 // Prevent overflow by limiting multiplicands.
315 if (bytesPerFrame > maxBytesPerFrame || numFrames > (0x3FFFFFFF / maxBytesPerFrame)) {
316 ALOGE("size overflow, numFrames = %d, frameSize = %zd", numFrames, bytesPerFrame);
317 return AAUDIO_ERROR_OUT_OF_RANGE;
318 }
319 *sizeInBytes = numFrames * bytesPerFrame;
320 return AAUDIO_OK;
321}
Phil Burkc8f69a02017-05-11 15:53:06 -0700322
323static int32_t AAudioProperty_getMMapProperty(const char *propName,
324 int32_t defaultValue,
325 const char * caller) {
Phil Burk87c9f642017-05-17 07:22:39 -0700326 int32_t prop = property_get_int32(propName, defaultValue);
Phil Burkc8f69a02017-05-11 15:53:06 -0700327 switch (prop) {
328 case AAUDIO_USE_NEVER:
329 case AAUDIO_USE_ALWAYS:
330 case AAUDIO_USE_AUTO:
331 break;
332 default:
333 ALOGE("%s: invalid = %d", caller, prop);
334 prop = defaultValue;
335 break;
336 }
337 return prop;
338}
339
340int32_t AAudioProperty_getMMapEnabled() {
341 return AAudioProperty_getMMapProperty(AAUDIO_PROP_MMAP_ENABLED,
342 AAUDIO_USE_NEVER, __func__);
343}
344
345int32_t AAudioProperty_getMMapExclusiveEnabled() {
346 return AAudioProperty_getMMapProperty(AAUDIO_PROP_MMAP_EXCLUSIVE_ENABLED,
347 AAUDIO_USE_NEVER, __func__);
348}
349
350int32_t AAudioProperty_getMixerBursts() {
Phil Burk87c9f642017-05-17 07:22:39 -0700351 const int32_t defaultBursts = 2; // arbitrary, use 2 for double buffered
Phil Burkc8f69a02017-05-11 15:53:06 -0700352 const int32_t maxBursts = 1024; // arbitrary
Phil Burk87c9f642017-05-17 07:22:39 -0700353 int32_t prop = property_get_int32(AAUDIO_PROP_MIXER_BURSTS, defaultBursts);
Phil Burkc8f69a02017-05-11 15:53:06 -0700354 if (prop < 1 || prop > maxBursts) {
355 ALOGE("AAudioProperty_getMixerBursts: invalid = %d", prop);
356 prop = defaultBursts;
357 }
358 return prop;
359}
360
361int32_t AAudioProperty_getHardwareBurstMinMicros() {
362 const int32_t defaultMicros = 1000; // arbitrary
363 const int32_t maxMicros = 1000 * 1000; // arbitrary
364 int32_t prop = property_get_int32(AAUDIO_PROP_HW_BURST_MIN_USEC, defaultMicros);
365 if (prop < 1 || prop > maxMicros) {
366 ALOGE("AAudioProperty_getHardwareBurstMinMicros: invalid = %d", prop);
367 prop = defaultMicros;
368 }
369 return prop;
370}