1/*
2 * Copyright (C) 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
18// cribbed from samples/native-audio
19
20#include "audioplay.h"
21
22#define CHATTY ALOGD
23#define LOG_TAG "audioplay"
24
25#include <string.h>
26
27#include <utils/Log.h>
28
29// for native audio
30#include <SLES/OpenSLES.h>
31#include <SLES/OpenSLES_Android.h>
32
33namespace audioplay {
34namespace {
35
36// engine interfaces
37static SLObjectItf engineObject = NULL;
38static SLEngineItf engineEngine;
39
40// output mix interfaces
41static SLObjectItf outputMixObject = NULL;
42
43// buffer queue player interfaces
44static SLObjectItf bqPlayerObject = NULL;
45static SLPlayItf bqPlayerPlay;
46static SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue;
47static SLMuteSoloItf bqPlayerMuteSolo;
48static SLVolumeItf bqPlayerVolume;
49
50// pointer and size of the next player buffer to enqueue, and number of remaining buffers
51static const uint8_t* nextBuffer;
52static unsigned nextSize;
53
54static const uint32_t ID_RIFF = 0x46464952;
55static const uint32_t ID_WAVE = 0x45564157;
56static const uint32_t ID_FMT  = 0x20746d66;
57static const uint32_t ID_DATA = 0x61746164;
58
59struct RiffWaveHeader {
60    uint32_t riff_id;
61    uint32_t riff_sz;
62    uint32_t wave_id;
63};
64
65struct ChunkHeader {
66    uint32_t id;
67    uint32_t sz;
68};
69
70struct ChunkFormat {
71    uint16_t audio_format;
72    uint16_t num_channels;
73    uint32_t sample_rate;
74    uint32_t byte_rate;
75    uint16_t block_align;
76    uint16_t bits_per_sample;
77};
78
79// this callback handler is called every time a buffer finishes playing
80void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context) {
81    (void)bq;
82    (void)context;
83    audioplay::setPlaying(false);
84}
85
86bool hasPlayer() {
87    return (engineObject != NULL && bqPlayerObject != NULL);
88}
89
90// create the engine and output mix objects
91bool createEngine() {
92    SLresult result;
93
94    // create engine
95    result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
96    if (result != SL_RESULT_SUCCESS) {
97        ALOGE("slCreateEngine failed with result %d", result);
98        return false;
99    }
100    (void)result;
101
102    // realize the engine
103    result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
104    if (result != SL_RESULT_SUCCESS) {
105        ALOGE("sl engine Realize failed with result %d", result);
106        return false;
107    }
108    (void)result;
109
110    // get the engine interface, which is needed in order to create other objects
111    result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
112    if (result != SL_RESULT_SUCCESS) {
113        ALOGE("sl engine GetInterface failed with result %d", result);
114        return false;
115    }
116    (void)result;
117
118    // create output mix
119    result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, NULL, NULL);
120    if (result != SL_RESULT_SUCCESS) {
121        ALOGE("sl engine CreateOutputMix failed with result %d", result);
122        return false;
123    }
124    (void)result;
125
126    // realize the output mix
127    result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
128    if (result != SL_RESULT_SUCCESS) {
129        ALOGE("sl outputMix Realize failed with result %d", result);
130        return false;
131    }
132    (void)result;
133
134    return true;
135}
136
137// create buffer queue audio player
138bool createBufferQueueAudioPlayer(const ChunkFormat* chunkFormat) {
139    SLresult result;
140
141    // configure audio source
142    SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 1};
143
144    // Determine channelMask from num_channels
145    SLuint32 channelMask;
146    switch (chunkFormat->num_channels) {
147        case 1:
148            channelMask = SL_SPEAKER_FRONT_CENTER;
149            break;
150        case 2:
151            channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
152            break;
153        default:
154            // Default of 0 will derive mask from num_channels and log a warning.
155            channelMask = 0;
156    }
157
158    SLDataFormat_PCM format_pcm = {
159        SL_DATAFORMAT_PCM,
160        chunkFormat->num_channels,
161        chunkFormat->sample_rate * 1000,  // convert to milliHz
162        chunkFormat->bits_per_sample,
163        16,
164        channelMask,
165        SL_BYTEORDER_LITTLEENDIAN
166    };
167    SLDataSource audioSrc = {&loc_bufq, &format_pcm};
168
169    // configure audio sink
170    SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};
171    SLDataSink audioSnk = {&loc_outmix, NULL};
172
173    // create audio player
174    const SLInterfaceID ids[3] = {SL_IID_BUFFERQUEUE, SL_IID_VOLUME, SL_IID_ANDROIDCONFIGURATION};
175    const SLboolean req[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
176    result = (*engineEngine)->CreateAudioPlayer(engineEngine, &bqPlayerObject, &audioSrc, &audioSnk,
177            3, ids, req);
178    if (result != SL_RESULT_SUCCESS) {
179        ALOGE("sl CreateAudioPlayer failed with result %d", result);
180        return false;
181    }
182    (void)result;
183
184    // Use the System stream for boot sound playback.
185    SLAndroidConfigurationItf playerConfig;
186    result = (*bqPlayerObject)->GetInterface(bqPlayerObject,
187        SL_IID_ANDROIDCONFIGURATION, &playerConfig);
188    if (result != SL_RESULT_SUCCESS) {
189        ALOGE("config GetInterface failed with result %d", result);
190        return false;
191    }
192    SLint32 streamType = SL_ANDROID_STREAM_SYSTEM;
193    result = (*playerConfig)->SetConfiguration(playerConfig,
194        SL_ANDROID_KEY_STREAM_TYPE, &streamType, sizeof(SLint32));
195    if (result != SL_RESULT_SUCCESS) {
196        ALOGE("SetConfiguration failed with result %d", result);
197        return false;
198    }
199    // use normal performance mode as low latency is not needed. This is not mandatory so
200    // do not bail if we fail
201    SLuint32 performanceMode = SL_ANDROID_PERFORMANCE_NONE;
202    result = (*playerConfig)->SetConfiguration(
203           playerConfig, SL_ANDROID_KEY_PERFORMANCE_MODE, &performanceMode, sizeof(SLuint32));
204    ALOGW_IF(result != SL_RESULT_SUCCESS,
205            "could not set performance mode on player, error %d", result);
206    (void)result;
207
208    // realize the player
209    result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE);
210    if (result != SL_RESULT_SUCCESS) {
211        ALOGE("sl player Realize failed with result %d", result);
212        return false;
213    }
214    (void)result;
215
216    // get the play interface
217    result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay);
218    if (result != SL_RESULT_SUCCESS) {
219        ALOGE("sl player GetInterface failed with result %d", result);
220        return false;
221    }
222    (void)result;
223
224    // get the buffer queue interface
225    result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_BUFFERQUEUE,
226            &bqPlayerBufferQueue);
227    if (result != SL_RESULT_SUCCESS) {
228        ALOGE("sl playberBufferQueue GetInterface failed with result %d", result);
229        return false;
230    }
231    (void)result;
232
233    // register callback on the buffer queue
234    result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, NULL);
235    if (result != SL_RESULT_SUCCESS) {
236        ALOGE("sl bqPlayerBufferQueue RegisterCallback failed with result %d", result);
237        return false;
238    }
239    (void)result;
240
241    // get the volume interface
242    result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_VOLUME, &bqPlayerVolume);
243    if (result != SL_RESULT_SUCCESS) {
244        ALOGE("sl volume GetInterface failed with result %d", result);
245        return false;
246    }
247    (void)result;
248
249    // set the player's state to playing
250    audioplay::setPlaying(true);
251    CHATTY("Created buffer queue player: %p", bqPlayerBufferQueue);
252    return true;
253}
254
255bool parseClipBuf(const uint8_t* clipBuf, int clipBufSize, const ChunkFormat** oChunkFormat,
256                  const uint8_t** oSoundBuf, unsigned* oSoundBufSize) {
257    *oSoundBuf = clipBuf;
258    *oSoundBufSize = clipBufSize;
259    *oChunkFormat = NULL;
260    const RiffWaveHeader* wavHeader = (const RiffWaveHeader*)*oSoundBuf;
261    if (*oSoundBufSize < sizeof(*wavHeader) || (wavHeader->riff_id != ID_RIFF) ||
262        (wavHeader->wave_id != ID_WAVE)) {
263        ALOGE("Error: audio file is not a riff/wave file\n");
264        return false;
265    }
266    *oSoundBuf += sizeof(*wavHeader);
267    *oSoundBufSize -= sizeof(*wavHeader);
268
269    while (true) {
270        const ChunkHeader* chunkHeader = (const ChunkHeader*)*oSoundBuf;
271        if (*oSoundBufSize < sizeof(*chunkHeader)) {
272            ALOGE("EOF reading chunk headers");
273            return false;
274        }
275
276        *oSoundBuf += sizeof(*chunkHeader);
277        *oSoundBufSize -= sizeof(*chunkHeader);
278
279        bool endLoop = false;
280        switch (chunkHeader->id) {
281            case ID_FMT:
282                *oChunkFormat = (const ChunkFormat*)*oSoundBuf;
283                *oSoundBuf += chunkHeader->sz;
284                *oSoundBufSize -= chunkHeader->sz;
285                break;
286            case ID_DATA:
287                /* Stop looking for chunks */
288                *oSoundBufSize = chunkHeader->sz;
289                endLoop = true;
290                break;
291            default:
292                /* Unknown chunk, skip bytes */
293                *oSoundBuf += chunkHeader->sz;
294                *oSoundBufSize -= chunkHeader->sz;
295        }
296        if (endLoop) {
297            break;
298        }
299    }
300
301    if (*oChunkFormat == NULL) {
302        ALOGE("format not found in WAV file");
303        return false;
304    }
305    return true;
306}
307
308} // namespace
309
310bool create(const uint8_t* exampleClipBuf, int exampleClipBufSize) {
311    if (!createEngine()) {
312        return false;
313    }
314
315    // Parse the example clip.
316    const ChunkFormat* chunkFormat;
317    const uint8_t* soundBuf;
318    unsigned soundBufSize;
319    if (!parseClipBuf(exampleClipBuf, exampleClipBufSize, &chunkFormat, &soundBuf, &soundBufSize)) {
320        return false;
321    }
322
323    // Initialize the BufferQueue based on this clip's format.
324    if (!createBufferQueueAudioPlayer(chunkFormat)) {
325        return false;
326    }
327    return true;
328}
329
330bool playClip(const uint8_t* buf, int size) {
331    // Parse the WAV header
332    const ChunkFormat* chunkFormat;
333    if (!parseClipBuf(buf, size, &chunkFormat, &nextBuffer, &nextSize)) {
334        return false;
335    }
336
337    if (!hasPlayer()) {
338        ALOGD("cannot play clip %p without a player", buf);
339        return false;
340    }
341
342    CHATTY("playClip on player %p: buf=%p size=%d nextSize %d",
343           bqPlayerBufferQueue, buf, size, nextSize);
344
345    if (nextSize > 0) {
346        // here we only enqueue one buffer because it is a long clip,
347        // but for streaming playback we would typically enqueue at least 2 buffers to start
348        SLresult result;
349        result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, nextBuffer, nextSize);
350        if (SL_RESULT_SUCCESS != result) {
351            return false;
352        }
353        audioplay::setPlaying(true);
354    }
355
356    return true;
357}
358
359// set the playing state for the buffer queue audio player
360void setPlaying(bool isPlaying) {
361    if (!hasPlayer()) return;
362
363    SLresult result;
364
365    if (NULL != bqPlayerPlay) {
366        // set the player's state
367        result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay,
368            isPlaying ? SL_PLAYSTATE_PLAYING : SL_PLAYSTATE_STOPPED);
369    }
370
371}
372
373void destroy() {
374    // destroy buffer queue audio player object, and invalidate all associated interfaces
375    if (bqPlayerObject != NULL) {
376        CHATTY("destroying audio player");
377        (*bqPlayerObject)->Destroy(bqPlayerObject);
378        bqPlayerObject = NULL;
379        bqPlayerPlay = NULL;
380        bqPlayerBufferQueue = NULL;
381        bqPlayerMuteSolo = NULL;
382        bqPlayerVolume = NULL;
383    }
384
385    // destroy output mix object, and invalidate all associated interfaces
386    if (outputMixObject != NULL) {
387        (*outputMixObject)->Destroy(outputMixObject);
388        outputMixObject = NULL;
389    }
390
391    // destroy engine object, and invalidate all associated interfaces
392    if (engineObject != NULL) {
393        CHATTY("destroying audio engine");
394        (*engineObject)->Destroy(engineObject);
395        engineObject = NULL;
396        engineEngine = NULL;
397    }
398}
399
400}  // namespace audioplay
401