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