• 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     // 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 
parseClipBuf(const uint8_t * clipBuf,int clipBufSize,const ChunkFormat ** oChunkFormat,const uint8_t ** oSoundBuf,unsigned * oSoundBufSize)255 bool 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 
create(const uint8_t * exampleClipBuf,int exampleClipBufSize)310 bool 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 
playClip(const uint8_t * buf,int size)330 bool 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
setPlaying(bool isPlaying)360 void 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 
destroy()373 void 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