blob: 5fa228ac58a19d0c0a5065c5ec02d221b9b23229 [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
21#include <stdint.h>
22#include <sys/types.h>
23#include <utils/Errors.h>
24
Phil Burka4eb0d82017-04-12 15:44:06 -070025#include "aaudio/AAudio.h"
Phil Burk5ed503c2017-02-01 09:38:15 -080026#include "AAudioUtilities.h"
27
28using namespace android;
29
Phil Burke572f462017-04-20 13:03:19 -070030// 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
Phil Burk3316d5e2017-02-15 11:23:01 -080035int32_t AAudioConvert_formatToSizeInBytes(aaudio_audio_format_t format) {
36 int32_t size = AAUDIO_ERROR_ILLEGAL_ARGUMENT;
Phil Burk5ed503c2017-02-01 09:38:15 -080037 switch (format) {
38 case AAUDIO_FORMAT_PCM_I16:
39 size = sizeof(int16_t);
40 break;
Phil Burk5ed503c2017-02-01 09:38:15 -080041 case AAUDIO_FORMAT_PCM_FLOAT:
42 size = sizeof(float);
43 break;
44 default:
45 break;
46 }
47 return size;
48}
49
Phil Burke572f462017-04-20 13:03:19 -070050
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;
Phil Burk5ed503c2017-02-01 09:38:15 -0800105 for (int i = 0; i < numSamples; i++) {
Phil Burke572f462017-04-20 13:03:19 -0700106 float sample = *source++;
107 *destination++ = clipAndClampFloatToPcm16(sample, scaler);
Phil Burk5ed503c2017-02-01 09:38:15 -0800108 }
109}
110
Phil Burke572f462017-04-20 13:03:19 -0700111void 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;
Phil Burk5ed503c2017-02-01 09:38:15 -0800136 for (int i = 0; i < numSamples; i++) {
Phil Burke572f462017-04-20 13:03:19 -0700137 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;
Phil Burk5ed503c2017-02-01 09:38:15 -0800197 }
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?
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:
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:
Phil Burk71f35bb2017-04-13 16:05:07 -0700242 result = AAUDIO_ERROR_NO_SERVICE;
Phil Burk5ed503c2017-02-01 09:38:15 -0800243 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;
Phil Burk5ed503c2017-02-01 09:38:15 -0800270 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;
Phil Burk5ed503c2017-02-01 09:38:15 -0800287 default:
288 aaudioFormat = AAUDIO_FORMAT_INVALID;
289 ALOGE("AAudioConvert_androidToAAudioDataFormat 0x%08X unrecognized", androidFormat);
290 break;
291 }
292 return aaudioFormat;
293}
294
Phil Burk3316d5e2017-02-15 11:23:01 -0800295int32_t AAudioConvert_framesToBytes(int32_t numFrames,
296 int32_t bytesPerFrame,
297 int32_t *sizeInBytes) {
Phil Burk5ed503c2017-02-01 09:38:15 -0800298 // TODO implement more elegantly
299 const int32_t maxChannels = 256; // ridiculously large
Phil Burk3316d5e2017-02-15 11:23:01 -0800300 const int32_t maxBytesPerFrame = maxChannels * sizeof(float);
Phil Burk5ed503c2017-02-01 09:38:15 -0800301 // 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}