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 <cutils/properties.h>
22#include <stdint.h>
23#include <sys/types.h>
24#include <utils/Errors.h>
25
26#include "aaudio/AAudio.h"
27#include <aaudio/AAudioTesting.h>
28
29#include "utility/AAudioUtilities.h"
30
31using namespace android;
32
33// This is 3 dB, (10^(3/20)), to match the maximum headroom in AudioTrack for float data.
34// It is designed to allow occasional transient peaks.
35#define MAX_HEADROOM (1.41253754f)
36#define MIN_HEADROOM (0 - MAX_HEADROOM)
37
38int32_t AAudioConvert_formatToSizeInBytes(aaudio_format_t format) {
39    int32_t size = AAUDIO_ERROR_ILLEGAL_ARGUMENT;
40    switch (format) {
41        case AAUDIO_FORMAT_PCM_I16:
42            size = sizeof(int16_t);
43            break;
44        case AAUDIO_FORMAT_PCM_FLOAT:
45            size = sizeof(float);
46            break;
47        default:
48            break;
49    }
50    return size;
51}
52
53
54// TODO expose and call clamp16_from_float function in primitives.h
55static inline int16_t clamp16_from_float(float f) {
56    /* Offset is used to expand the valid range of [-1.0, 1.0) into the 16 lsbs of the
57     * floating point significand. The normal shift is 3<<22, but the -15 offset
58     * is used to multiply by 32768.
59     */
60    static const float offset = (float)(3 << (22 - 15));
61    /* zero = (0x10f << 22) =  0x43c00000 (not directly used) */
62    static const int32_t limneg = (0x10f << 22) /*zero*/ - 32768; /* 0x43bf8000 */
63    static const int32_t limpos = (0x10f << 22) /*zero*/ + 32767; /* 0x43c07fff */
64
65    union {
66        float f;
67        int32_t i;
68    } u;
69
70    u.f = f + offset; /* recenter valid range */
71    /* Now the valid range is represented as integers between [limneg, limpos].
72     * Clamp using the fact that float representation (as an integer) is an ordered set.
73     */
74    if (u.i < limneg)
75        u.i = -32768;
76    else if (u.i > limpos)
77        u.i = 32767;
78    return u.i; /* Return lower 16 bits, the part of interest in the significand. */
79}
80
81// Same but without clipping.
82// Convert -1.0f to +1.0f to -32768 to +32767
83static inline int16_t floatToInt16(float f) {
84    static const float offset = (float)(3 << (22 - 15));
85    union {
86        float f;
87        int32_t i;
88    } u;
89    u.f = f + offset; /* recenter valid range */
90    return u.i; /* Return lower 16 bits, the part of interest in the significand. */
91}
92
93static float clipAndClampFloatToPcm16(float sample, float scaler) {
94    // Clip to valid range of a float sample to prevent excessive volume.
95    if (sample > MAX_HEADROOM) sample = MAX_HEADROOM;
96    else if (sample < MIN_HEADROOM) sample = MIN_HEADROOM;
97
98    // Scale and convert to a short.
99    float fval = sample * scaler;
100    return clamp16_from_float(fval);
101}
102
103void AAudioConvert_floatToPcm16(const float *source,
104                                int16_t *destination,
105                                int32_t numSamples,
106                                float amplitude) {
107    float scaler = amplitude;
108    for (int i = 0; i < numSamples; i++) {
109        float sample = *source++;
110        *destination++ = clipAndClampFloatToPcm16(sample, scaler);
111    }
112}
113
114void AAudioConvert_floatToPcm16(const float *source,
115                                int16_t *destination,
116                                int32_t numFrames,
117                                int32_t samplesPerFrame,
118                                float amplitude1,
119                                float amplitude2) {
120    float scaler = amplitude1;
121    // divide by numFrames so that we almost reach amplitude2
122    float delta = (amplitude2 - amplitude1) / numFrames;
123    for (int frameIndex = 0; frameIndex < numFrames; frameIndex++) {
124        for (int sampleIndex = 0; sampleIndex < samplesPerFrame; sampleIndex++) {
125            float sample = *source++;
126            *destination++ = clipAndClampFloatToPcm16(sample, scaler);
127        }
128        scaler += delta;
129    }
130}
131
132#define SHORT_SCALE  32768
133
134void AAudioConvert_pcm16ToFloat(const int16_t *source,
135                                float *destination,
136                                int32_t numSamples,
137                                float amplitude) {
138    float scaler = amplitude / SHORT_SCALE;
139    for (int i = 0; i < numSamples; i++) {
140        destination[i] = source[i] * scaler;
141    }
142}
143
144// This code assumes amplitude1 and amplitude2 are between 0.0 and 1.0
145void AAudioConvert_pcm16ToFloat(const int16_t *source,
146                                float *destination,
147                                int32_t numFrames,
148                                int32_t samplesPerFrame,
149                                float amplitude1,
150                                float amplitude2) {
151    float scaler = amplitude1 / SHORT_SCALE;
152    float delta = (amplitude2 - amplitude1) / (SHORT_SCALE * (float) numFrames);
153    for (int frameIndex = 0; frameIndex < numFrames; frameIndex++) {
154        for (int sampleIndex = 0; sampleIndex < samplesPerFrame; sampleIndex++) {
155            *destination++ = *source++ * scaler;
156        }
157        scaler += delta;
158    }
159}
160
161// This code assumes amplitude1 and amplitude2 are between 0.0 and 1.0
162void AAudio_linearRamp(const float *source,
163                       float *destination,
164                       int32_t numFrames,
165                       int32_t samplesPerFrame,
166                       float amplitude1,
167                       float amplitude2) {
168    float scaler = amplitude1;
169    float delta = (amplitude2 - amplitude1) / numFrames;
170    for (int frameIndex = 0; frameIndex < numFrames; frameIndex++) {
171        for (int sampleIndex = 0; sampleIndex < samplesPerFrame; sampleIndex++) {
172            float sample = *source++;
173
174            // Clip to valid range of a float sample to prevent excessive volume.
175            if (sample > MAX_HEADROOM) sample = MAX_HEADROOM;
176            else if (sample < MIN_HEADROOM) sample = MIN_HEADROOM;
177
178            *destination++ = sample * scaler;
179        }
180        scaler += delta;
181    }
182}
183
184// This code assumes amplitude1 and amplitude2 are between 0.0 and 1.0
185void AAudio_linearRamp(const int16_t *source,
186                       int16_t *destination,
187                       int32_t numFrames,
188                       int32_t samplesPerFrame,
189                       float amplitude1,
190                       float amplitude2) {
191    float scaler = amplitude1 / SHORT_SCALE;
192    float delta = (amplitude2 - amplitude1) / (SHORT_SCALE * (float) numFrames);
193    for (int frameIndex = 0; frameIndex < numFrames; frameIndex++) {
194        for (int sampleIndex = 0; sampleIndex < samplesPerFrame; sampleIndex++) {
195            // No need to clip because int16_t range is inherently limited.
196            float sample =  *source++ * scaler;
197            *destination++ =  floatToInt16(sample);
198        }
199        scaler += delta;
200    }
201}
202
203status_t AAudioConvert_aaudioToAndroidStatus(aaudio_result_t result) {
204    // This covers the case for AAUDIO_OK and for positive results.
205    if (result >= 0) {
206        return result;
207    }
208    status_t status;
209    switch (result) {
210    case AAUDIO_ERROR_DISCONNECTED:
211    case AAUDIO_ERROR_NO_SERVICE:
212        status = DEAD_OBJECT;
213        break;
214    case AAUDIO_ERROR_INVALID_HANDLE:
215        status = BAD_TYPE;
216        break;
217    case AAUDIO_ERROR_INVALID_STATE:
218        status = INVALID_OPERATION;
219        break;
220    case AAUDIO_ERROR_INVALID_RATE:
221    case AAUDIO_ERROR_INVALID_FORMAT:
222    case AAUDIO_ERROR_ILLEGAL_ARGUMENT:
223    case AAUDIO_ERROR_OUT_OF_RANGE:
224        status = BAD_VALUE;
225        break;
226    case AAUDIO_ERROR_WOULD_BLOCK:
227        status = WOULD_BLOCK;
228        break;
229    case AAUDIO_ERROR_NULL:
230        status = UNEXPECTED_NULL;
231        break;
232    case AAUDIO_ERROR_UNAVAILABLE:
233        status = NOT_ENOUGH_DATA;
234        break;
235
236    // TODO translate these result codes
237    case AAUDIO_ERROR_INTERNAL:
238    case AAUDIO_ERROR_UNIMPLEMENTED:
239    case AAUDIO_ERROR_NO_FREE_HANDLES:
240    case AAUDIO_ERROR_NO_MEMORY:
241    case AAUDIO_ERROR_TIMEOUT:
242    default:
243        status = UNKNOWN_ERROR;
244        break;
245    }
246    return status;
247}
248
249aaudio_result_t AAudioConvert_androidToAAudioResult(status_t status) {
250    // This covers the case for OK and for positive result.
251    if (status >= 0) {
252        return status;
253    }
254    aaudio_result_t result;
255    switch (status) {
256    case BAD_TYPE:
257        result = AAUDIO_ERROR_INVALID_HANDLE;
258        break;
259    case DEAD_OBJECT:
260        result = AAUDIO_ERROR_NO_SERVICE;
261        break;
262    case INVALID_OPERATION:
263        result = AAUDIO_ERROR_INVALID_STATE;
264        break;
265    case UNEXPECTED_NULL:
266        result = AAUDIO_ERROR_NULL;
267        break;
268    case BAD_VALUE:
269        result = AAUDIO_ERROR_ILLEGAL_ARGUMENT;
270        break;
271    case WOULD_BLOCK:
272        result = AAUDIO_ERROR_WOULD_BLOCK;
273        break;
274    case NOT_ENOUGH_DATA:
275        result = AAUDIO_ERROR_UNAVAILABLE;
276        break;
277    default:
278        result = AAUDIO_ERROR_INTERNAL;
279        break;
280    }
281    return result;
282}
283
284audio_format_t AAudioConvert_aaudioToAndroidDataFormat(aaudio_format_t aaudioFormat) {
285    audio_format_t androidFormat;
286    switch (aaudioFormat) {
287    case AAUDIO_FORMAT_PCM_I16:
288        androidFormat = AUDIO_FORMAT_PCM_16_BIT;
289        break;
290    case AAUDIO_FORMAT_PCM_FLOAT:
291        androidFormat = AUDIO_FORMAT_PCM_FLOAT;
292        break;
293    default:
294        androidFormat = AUDIO_FORMAT_DEFAULT;
295        ALOGE("AAudioConvert_aaudioToAndroidDataFormat 0x%08X unrecognized", aaudioFormat);
296        break;
297    }
298    return androidFormat;
299}
300
301aaudio_format_t AAudioConvert_androidToAAudioDataFormat(audio_format_t androidFormat) {
302    aaudio_format_t aaudioFormat = AAUDIO_FORMAT_INVALID;
303    switch (androidFormat) {
304    case AUDIO_FORMAT_PCM_16_BIT:
305        aaudioFormat = AAUDIO_FORMAT_PCM_I16;
306        break;
307    case AUDIO_FORMAT_PCM_FLOAT:
308        aaudioFormat = AAUDIO_FORMAT_PCM_FLOAT;
309        break;
310    default:
311        aaudioFormat = AAUDIO_FORMAT_INVALID;
312        ALOGE("AAudioConvert_androidToAAudioDataFormat 0x%08X unrecognized", androidFormat);
313        break;
314    }
315    return aaudioFormat;
316}
317
318int32_t AAudioConvert_framesToBytes(int32_t numFrames,
319                                            int32_t bytesPerFrame,
320                                            int32_t *sizeInBytes) {
321    // TODO implement more elegantly
322    const int32_t maxChannels = 256; // ridiculously large
323    const int32_t maxBytesPerFrame = maxChannels * sizeof(float);
324    // Prevent overflow by limiting multiplicands.
325    if (bytesPerFrame > maxBytesPerFrame || numFrames > (0x3FFFFFFF / maxBytesPerFrame)) {
326        ALOGE("size overflow, numFrames = %d, frameSize = %zd", numFrames, bytesPerFrame);
327        return AAUDIO_ERROR_OUT_OF_RANGE;
328    }
329    *sizeInBytes = numFrames * bytesPerFrame;
330    return AAUDIO_OK;
331}
332
333static int32_t AAudioProperty_getMMapProperty(const char *propName,
334                                              int32_t defaultValue,
335                                              const char * caller) {
336    int32_t prop = property_get_int32(propName, defaultValue);
337    switch (prop) {
338        case AAUDIO_UNSPECIFIED:
339        case AAUDIO_POLICY_NEVER:
340        case AAUDIO_POLICY_ALWAYS:
341        case AAUDIO_POLICY_AUTO:
342            break;
343        default:
344            ALOGE("%s: invalid = %d", caller, prop);
345            prop = defaultValue;
346            break;
347    }
348    return prop;
349}
350
351int32_t AAudioProperty_getMMapPolicy() {
352    return AAudioProperty_getMMapProperty(AAUDIO_PROP_MMAP_POLICY,
353                                          AAUDIO_UNSPECIFIED, __func__);
354}
355
356int32_t AAudioProperty_getMMapExclusivePolicy() {
357    return AAudioProperty_getMMapProperty(AAUDIO_PROP_MMAP_EXCLUSIVE_POLICY,
358                                          AAUDIO_UNSPECIFIED, __func__);
359}
360
361int32_t AAudioProperty_getMixerBursts() {
362    const int32_t defaultBursts = 2; // arbitrary, use 2 for double buffered
363    const int32_t maxBursts = 1024; // arbitrary
364    int32_t prop = property_get_int32(AAUDIO_PROP_MIXER_BURSTS, defaultBursts);
365    if (prop < 1 || prop > maxBursts) {
366        ALOGE("AAudioProperty_getMixerBursts: invalid = %d", prop);
367        prop = defaultBursts;
368    }
369    return prop;
370}
371
372int32_t AAudioProperty_getWakeupDelayMicros() {
373    const int32_t minMicros = 0; // arbitrary
374    const int32_t defaultMicros = 200; // arbitrary, based on some observed jitter
375    const int32_t maxMicros = 5000; // arbitrary, probably don't want more than 500
376    int32_t prop = property_get_int32(AAUDIO_PROP_WAKEUP_DELAY_USEC, defaultMicros);
377    if (prop < minMicros) {
378        ALOGW("AAudioProperty_getWakeupDelayMicros: clipped %d to %d", prop, minMicros);
379        prop = minMicros;
380    } else if (prop > maxMicros) {
381        ALOGW("AAudioProperty_getWakeupDelayMicros: clipped %d to %d", prop, maxMicros);
382        prop = maxMicros;
383    }
384    return prop;
385}
386
387int32_t AAudioProperty_getMinimumSleepMicros() {
388    const int32_t minMicros = 20; // arbitrary
389    const int32_t defaultMicros = 200; // arbitrary
390    const int32_t maxMicros = 2000; // arbitrary
391    int32_t prop = property_get_int32(AAUDIO_PROP_MINIMUM_SLEEP_USEC, defaultMicros);
392    if (prop < minMicros) {
393        ALOGW("AAudioProperty_getMinimumSleepMicros: clipped %d to %d", prop, minMicros);
394        prop = minMicros;
395    } else if (prop > maxMicros) {
396        ALOGW("AAudioProperty_getMinimumSleepMicros: clipped %d to %d", prop, maxMicros);
397        prop = maxMicros;
398    }
399    return prop;
400}
401
402int32_t AAudioProperty_getHardwareBurstMinMicros() {
403    const int32_t defaultMicros = 1000; // arbitrary
404    const int32_t maxMicros = 1000 * 1000; // arbitrary
405    int32_t prop = property_get_int32(AAUDIO_PROP_HW_BURST_MIN_USEC, defaultMicros);
406    if (prop < 1 || prop > maxMicros) {
407        ALOGE("AAudioProperty_getHardwareBurstMinMicros: invalid = %d, use %d",
408              prop, defaultMicros);
409        prop = defaultMicros;
410    }
411    return prop;
412}
413