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