blob: f709f4122c3f52e8a0bdd0a366b6bb31973dbb93 [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 Burkd04aeea2017-05-23 13:56:41 -070027#include <aaudio/AAudioTesting.h>
Phil Burkbba09002017-11-29 13:39:44 -080028#include <math.h>
Phil Burkd04aeea2017-05-23 13:56:41 -070029
30#include "utility/AAudioUtilities.h"
Phil Burk5ed503c2017-02-01 09:38:15 -080031
32using namespace android;
33
Phil Burke572f462017-04-20 13:03:19 -070034// This is 3 dB, (10^(3/20)), to match the maximum headroom in AudioTrack for float data.
35// It is designed to allow occasional transient peaks.
36#define MAX_HEADROOM (1.41253754f)
37#define MIN_HEADROOM (0 - MAX_HEADROOM)
38
Phil Burk9dca9822017-05-26 14:27:43 -070039int32_t AAudioConvert_formatToSizeInBytes(aaudio_format_t format) {
Phil Burk3316d5e2017-02-15 11:23:01 -080040 int32_t size = AAUDIO_ERROR_ILLEGAL_ARGUMENT;
Phil Burk5ed503c2017-02-01 09:38:15 -080041 switch (format) {
42 case AAUDIO_FORMAT_PCM_I16:
43 size = sizeof(int16_t);
44 break;
Phil Burk5ed503c2017-02-01 09:38:15 -080045 case AAUDIO_FORMAT_PCM_FLOAT:
46 size = sizeof(float);
47 break;
48 default:
49 break;
50 }
51 return size;
52}
53
Phil Burk5204d312017-05-04 17:16:13 -070054// TODO expose and call clamp16_from_float function in primitives.h
Phil Burke572f462017-04-20 13:03:19 -070055static inline int16_t clamp16_from_float(float f) {
Phil Burkbba09002017-11-29 13:39:44 -080056 static const float scale = 1 << 15;
57 return (int16_t) roundf(fmaxf(fminf(f * scale, scale - 1.f), -scale));
Phil Burke572f462017-04-20 13:03:19 -070058}
59
60static float clipAndClampFloatToPcm16(float sample, float scaler) {
61 // Clip to valid range of a float sample to prevent excessive volume.
62 if (sample > MAX_HEADROOM) sample = MAX_HEADROOM;
63 else if (sample < MIN_HEADROOM) sample = MIN_HEADROOM;
64
65 // Scale and convert to a short.
66 float fval = sample * scaler;
67 return clamp16_from_float(fval);
68}
69
70void AAudioConvert_floatToPcm16(const float *source,
71 int16_t *destination,
72 int32_t numSamples,
73 float amplitude) {
74 float scaler = amplitude;
Phil Burk5ed503c2017-02-01 09:38:15 -080075 for (int i = 0; i < numSamples; i++) {
Phil Burke572f462017-04-20 13:03:19 -070076 float sample = *source++;
77 *destination++ = clipAndClampFloatToPcm16(sample, scaler);
Phil Burk5ed503c2017-02-01 09:38:15 -080078 }
79}
80
Phil Burke572f462017-04-20 13:03:19 -070081void AAudioConvert_floatToPcm16(const float *source,
82 int16_t *destination,
83 int32_t numFrames,
84 int32_t samplesPerFrame,
85 float amplitude1,
86 float amplitude2) {
87 float scaler = amplitude1;
88 // divide by numFrames so that we almost reach amplitude2
89 float delta = (amplitude2 - amplitude1) / numFrames;
90 for (int frameIndex = 0; frameIndex < numFrames; frameIndex++) {
91 for (int sampleIndex = 0; sampleIndex < samplesPerFrame; sampleIndex++) {
92 float sample = *source++;
93 *destination++ = clipAndClampFloatToPcm16(sample, scaler);
94 }
95 scaler += delta;
96 }
97}
98
99#define SHORT_SCALE 32768
100
101void AAudioConvert_pcm16ToFloat(const int16_t *source,
102 float *destination,
103 int32_t numSamples,
104 float amplitude) {
105 float scaler = amplitude / SHORT_SCALE;
Phil Burk5ed503c2017-02-01 09:38:15 -0800106 for (int i = 0; i < numSamples; i++) {
Phil Burke572f462017-04-20 13:03:19 -0700107 destination[i] = source[i] * scaler;
108 }
109}
110
111// This code assumes amplitude1 and amplitude2 are between 0.0 and 1.0
112void AAudioConvert_pcm16ToFloat(const int16_t *source,
113 float *destination,
114 int32_t numFrames,
115 int32_t samplesPerFrame,
116 float amplitude1,
117 float amplitude2) {
118 float scaler = amplitude1 / SHORT_SCALE;
119 float delta = (amplitude2 - amplitude1) / (SHORT_SCALE * (float) numFrames);
120 for (int frameIndex = 0; frameIndex < numFrames; frameIndex++) {
121 for (int sampleIndex = 0; sampleIndex < samplesPerFrame; sampleIndex++) {
122 *destination++ = *source++ * scaler;
123 }
124 scaler += delta;
125 }
126}
127
128// This code assumes amplitude1 and amplitude2 are between 0.0 and 1.0
129void AAudio_linearRamp(const float *source,
130 float *destination,
131 int32_t numFrames,
132 int32_t samplesPerFrame,
133 float amplitude1,
134 float amplitude2) {
135 float scaler = amplitude1;
136 float delta = (amplitude2 - amplitude1) / numFrames;
137 for (int frameIndex = 0; frameIndex < numFrames; frameIndex++) {
138 for (int sampleIndex = 0; sampleIndex < samplesPerFrame; sampleIndex++) {
139 float sample = *source++;
140
141 // Clip to valid range of a float sample to prevent excessive volume.
142 if (sample > MAX_HEADROOM) sample = MAX_HEADROOM;
143 else if (sample < MIN_HEADROOM) sample = MIN_HEADROOM;
144
145 *destination++ = sample * scaler;
146 }
147 scaler += delta;
148 }
149}
150
151// This code assumes amplitude1 and amplitude2 are between 0.0 and 1.0
152void AAudio_linearRamp(const int16_t *source,
153 int16_t *destination,
154 int32_t numFrames,
155 int32_t samplesPerFrame,
156 float amplitude1,
157 float amplitude2) {
Phil Burkbba09002017-11-29 13:39:44 -0800158 // Because we are converting from int16 to 1nt16, we do not have to scale by 1/32768.
159 float scaler = amplitude1;
160 float delta = (amplitude2 - amplitude1) / numFrames;
Phil Burke572f462017-04-20 13:03:19 -0700161 for (int frameIndex = 0; frameIndex < numFrames; frameIndex++) {
162 for (int sampleIndex = 0; sampleIndex < samplesPerFrame; sampleIndex++) {
163 // No need to clip because int16_t range is inherently limited.
164 float sample = *source++ * scaler;
Phil Burkbba09002017-11-29 13:39:44 -0800165 *destination++ = (int16_t) roundf(sample);
Phil Burke572f462017-04-20 13:03:19 -0700166 }
167 scaler += delta;
Phil Burk5ed503c2017-02-01 09:38:15 -0800168 }
169}
170
171status_t AAudioConvert_aaudioToAndroidStatus(aaudio_result_t result) {
172 // This covers the case for AAUDIO_OK and for positive results.
173 if (result >= 0) {
174 return result;
175 }
176 status_t status;
177 switch (result) {
178 case AAUDIO_ERROR_DISCONNECTED:
Eric Laurenta2f296e2017-06-21 18:51:47 -0700179 case AAUDIO_ERROR_NO_SERVICE:
Phil Burk5ed503c2017-02-01 09:38:15 -0800180 status = DEAD_OBJECT;
181 break;
Eric Laurenta2f296e2017-06-21 18:51:47 -0700182 case AAUDIO_ERROR_INVALID_HANDLE:
183 status = BAD_TYPE;
184 break;
Phil Burk5ed503c2017-02-01 09:38:15 -0800185 case AAUDIO_ERROR_INVALID_STATE:
186 status = INVALID_OPERATION;
187 break;
Phil Burk71f35bb2017-04-13 16:05:07 -0700188 case AAUDIO_ERROR_INVALID_RATE:
189 case AAUDIO_ERROR_INVALID_FORMAT:
Phil Burk5ed503c2017-02-01 09:38:15 -0800190 case AAUDIO_ERROR_ILLEGAL_ARGUMENT:
Phil Burk5204d312017-05-04 17:16:13 -0700191 case AAUDIO_ERROR_OUT_OF_RANGE:
Phil Burk5ed503c2017-02-01 09:38:15 -0800192 status = BAD_VALUE;
193 break;
194 case AAUDIO_ERROR_WOULD_BLOCK:
195 status = WOULD_BLOCK;
196 break;
Phil Burk5204d312017-05-04 17:16:13 -0700197 case AAUDIO_ERROR_NULL:
198 status = UNEXPECTED_NULL;
199 break;
Phil Burk940083c2017-07-17 17:00:02 -0700200 case AAUDIO_ERROR_UNAVAILABLE:
201 status = NOT_ENOUGH_DATA;
202 break;
203
Phil Burk5204d312017-05-04 17:16:13 -0700204 // TODO translate these result codes
Phil Burk5204d312017-05-04 17:16:13 -0700205 case AAUDIO_ERROR_INTERNAL:
Phil Burk5204d312017-05-04 17:16:13 -0700206 case AAUDIO_ERROR_UNIMPLEMENTED:
Phil Burk5204d312017-05-04 17:16:13 -0700207 case AAUDIO_ERROR_NO_FREE_HANDLES:
208 case AAUDIO_ERROR_NO_MEMORY:
209 case AAUDIO_ERROR_TIMEOUT:
Phil Burk5ed503c2017-02-01 09:38:15 -0800210 default:
211 status = UNKNOWN_ERROR;
212 break;
213 }
214 return status;
215}
216
217aaudio_result_t AAudioConvert_androidToAAudioResult(status_t status) {
218 // This covers the case for OK and for positive result.
219 if (status >= 0) {
220 return status;
221 }
222 aaudio_result_t result;
223 switch (status) {
224 case BAD_TYPE:
225 result = AAUDIO_ERROR_INVALID_HANDLE;
226 break;
227 case DEAD_OBJECT:
Phil Burk71f35bb2017-04-13 16:05:07 -0700228 result = AAUDIO_ERROR_NO_SERVICE;
Phil Burk5ed503c2017-02-01 09:38:15 -0800229 break;
230 case INVALID_OPERATION:
231 result = AAUDIO_ERROR_INVALID_STATE;
232 break;
Eric Laurenta2f296e2017-06-21 18:51:47 -0700233 case UNEXPECTED_NULL:
234 result = AAUDIO_ERROR_NULL;
235 break;
236 case BAD_VALUE:
237 result = AAUDIO_ERROR_ILLEGAL_ARGUMENT;
238 break;
Phil Burk5ed503c2017-02-01 09:38:15 -0800239 case WOULD_BLOCK:
240 result = AAUDIO_ERROR_WOULD_BLOCK;
241 break;
Phil Burk940083c2017-07-17 17:00:02 -0700242 case NOT_ENOUGH_DATA:
243 result = AAUDIO_ERROR_UNAVAILABLE;
244 break;
Phil Burk5ed503c2017-02-01 09:38:15 -0800245 default:
246 result = AAUDIO_ERROR_INTERNAL;
247 break;
248 }
249 return result;
250}
251
Phil Burk9dca9822017-05-26 14:27:43 -0700252audio_format_t AAudioConvert_aaudioToAndroidDataFormat(aaudio_format_t aaudioFormat) {
Phil Burk5ed503c2017-02-01 09:38:15 -0800253 audio_format_t androidFormat;
254 switch (aaudioFormat) {
255 case AAUDIO_FORMAT_PCM_I16:
256 androidFormat = AUDIO_FORMAT_PCM_16_BIT;
257 break;
258 case AAUDIO_FORMAT_PCM_FLOAT:
259 androidFormat = AUDIO_FORMAT_PCM_FLOAT;
260 break;
Phil Burk5ed503c2017-02-01 09:38:15 -0800261 default:
262 androidFormat = AUDIO_FORMAT_DEFAULT;
263 ALOGE("AAudioConvert_aaudioToAndroidDataFormat 0x%08X unrecognized", aaudioFormat);
264 break;
265 }
266 return androidFormat;
267}
268
Phil Burk9dca9822017-05-26 14:27:43 -0700269aaudio_format_t AAudioConvert_androidToAAudioDataFormat(audio_format_t androidFormat) {
270 aaudio_format_t aaudioFormat = AAUDIO_FORMAT_INVALID;
Phil Burk5ed503c2017-02-01 09:38:15 -0800271 switch (androidFormat) {
272 case AUDIO_FORMAT_PCM_16_BIT:
273 aaudioFormat = AAUDIO_FORMAT_PCM_I16;
274 break;
275 case AUDIO_FORMAT_PCM_FLOAT:
276 aaudioFormat = AAUDIO_FORMAT_PCM_FLOAT;
277 break;
Phil Burk5ed503c2017-02-01 09:38:15 -0800278 default:
279 aaudioFormat = AAUDIO_FORMAT_INVALID;
280 ALOGE("AAudioConvert_androidToAAudioDataFormat 0x%08X unrecognized", androidFormat);
281 break;
282 }
283 return aaudioFormat;
284}
285
Phil Burk3316d5e2017-02-15 11:23:01 -0800286int32_t AAudioConvert_framesToBytes(int32_t numFrames,
287 int32_t bytesPerFrame,
288 int32_t *sizeInBytes) {
Phil Burk5ed503c2017-02-01 09:38:15 -0800289 // TODO implement more elegantly
290 const int32_t maxChannels = 256; // ridiculously large
Phil Burk3316d5e2017-02-15 11:23:01 -0800291 const int32_t maxBytesPerFrame = maxChannels * sizeof(float);
Phil Burk5ed503c2017-02-01 09:38:15 -0800292 // Prevent overflow by limiting multiplicands.
293 if (bytesPerFrame > maxBytesPerFrame || numFrames > (0x3FFFFFFF / maxBytesPerFrame)) {
Yi Kong0f414de2017-12-15 13:48:50 -0800294 ALOGE("size overflow, numFrames = %d, frameSize = %d", numFrames, bytesPerFrame);
Phil Burk5ed503c2017-02-01 09:38:15 -0800295 return AAUDIO_ERROR_OUT_OF_RANGE;
296 }
297 *sizeInBytes = numFrames * bytesPerFrame;
298 return AAUDIO_OK;
299}
Phil Burkc8f69a02017-05-11 15:53:06 -0700300
301static int32_t AAudioProperty_getMMapProperty(const char *propName,
302 int32_t defaultValue,
303 const char * caller) {
Phil Burk87c9f642017-05-17 07:22:39 -0700304 int32_t prop = property_get_int32(propName, defaultValue);
Phil Burkc8f69a02017-05-11 15:53:06 -0700305 switch (prop) {
Phil Burkd04aeea2017-05-23 13:56:41 -0700306 case AAUDIO_UNSPECIFIED:
307 case AAUDIO_POLICY_NEVER:
308 case AAUDIO_POLICY_ALWAYS:
309 case AAUDIO_POLICY_AUTO:
Phil Burkc8f69a02017-05-11 15:53:06 -0700310 break;
311 default:
312 ALOGE("%s: invalid = %d", caller, prop);
313 prop = defaultValue;
314 break;
315 }
316 return prop;
317}
318
Phil Burkd04aeea2017-05-23 13:56:41 -0700319int32_t AAudioProperty_getMMapPolicy() {
320 return AAudioProperty_getMMapProperty(AAUDIO_PROP_MMAP_POLICY,
321 AAUDIO_UNSPECIFIED, __func__);
Phil Burkc8f69a02017-05-11 15:53:06 -0700322}
323
Phil Burkd04aeea2017-05-23 13:56:41 -0700324int32_t AAudioProperty_getMMapExclusivePolicy() {
325 return AAudioProperty_getMMapProperty(AAUDIO_PROP_MMAP_EXCLUSIVE_POLICY,
326 AAUDIO_UNSPECIFIED, __func__);
Phil Burkc8f69a02017-05-11 15:53:06 -0700327}
328
329int32_t AAudioProperty_getMixerBursts() {
Phil Burk87c9f642017-05-17 07:22:39 -0700330 const int32_t defaultBursts = 2; // arbitrary, use 2 for double buffered
Phil Burkc8f69a02017-05-11 15:53:06 -0700331 const int32_t maxBursts = 1024; // arbitrary
Phil Burk87c9f642017-05-17 07:22:39 -0700332 int32_t prop = property_get_int32(AAUDIO_PROP_MIXER_BURSTS, defaultBursts);
Phil Burkc8f69a02017-05-11 15:53:06 -0700333 if (prop < 1 || prop > maxBursts) {
334 ALOGE("AAudioProperty_getMixerBursts: invalid = %d", prop);
335 prop = defaultBursts;
336 }
337 return prop;
338}
339
Phil Burkfd34a932017-07-19 07:03:52 -0700340int32_t AAudioProperty_getWakeupDelayMicros() {
341 const int32_t minMicros = 0; // arbitrary
342 const int32_t defaultMicros = 200; // arbitrary, based on some observed jitter
343 const int32_t maxMicros = 5000; // arbitrary, probably don't want more than 500
344 int32_t prop = property_get_int32(AAUDIO_PROP_WAKEUP_DELAY_USEC, defaultMicros);
345 if (prop < minMicros) {
346 ALOGW("AAudioProperty_getWakeupDelayMicros: clipped %d to %d", prop, minMicros);
347 prop = minMicros;
348 } else if (prop > maxMicros) {
349 ALOGW("AAudioProperty_getWakeupDelayMicros: clipped %d to %d", prop, maxMicros);
350 prop = maxMicros;
351 }
352 return prop;
353}
354
355int32_t AAudioProperty_getMinimumSleepMicros() {
356 const int32_t minMicros = 20; // arbitrary
357 const int32_t defaultMicros = 200; // arbitrary
358 const int32_t maxMicros = 2000; // arbitrary
359 int32_t prop = property_get_int32(AAUDIO_PROP_MINIMUM_SLEEP_USEC, defaultMicros);
360 if (prop < minMicros) {
361 ALOGW("AAudioProperty_getMinimumSleepMicros: clipped %d to %d", prop, minMicros);
362 prop = minMicros;
363 } else if (prop > maxMicros) {
364 ALOGW("AAudioProperty_getMinimumSleepMicros: clipped %d to %d", prop, maxMicros);
365 prop = maxMicros;
366 }
367 return prop;
368}
369
Phil Burkc8f69a02017-05-11 15:53:06 -0700370int32_t AAudioProperty_getHardwareBurstMinMicros() {
371 const int32_t defaultMicros = 1000; // arbitrary
372 const int32_t maxMicros = 1000 * 1000; // arbitrary
373 int32_t prop = property_get_int32(AAUDIO_PROP_HW_BURST_MIN_USEC, defaultMicros);
374 if (prop < 1 || prop > maxMicros) {
Phil Burkfd34a932017-07-19 07:03:52 -0700375 ALOGE("AAudioProperty_getHardwareBurstMinMicros: invalid = %d, use %d",
376 prop, defaultMicros);
Phil Burkc8f69a02017-05-11 15:53:06 -0700377 prop = defaultMicros;
378 }
379 return prop;
380}