blob: e20ef0c7c6cc24ce95abc5a4fff6b2cc70a272be [file] [log] [blame]
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -07001/*
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
24#include <assert.h>
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 assert(bq == bqPlayerBufferQueue);
84 assert(NULL == context);
85 audioplay::setPlaying(false);
86}
87
88bool hasPlayer() {
89 return (engineObject != NULL && bqPlayerObject != NULL);
90}
91
92// create the engine and output mix objects
93void createEngine() {
94 SLresult result;
95
96 // create engine
97 result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
98 assert(SL_RESULT_SUCCESS == result);
99 (void)result;
100
101 // realize the engine
102 result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
103 assert(SL_RESULT_SUCCESS == result);
104 (void)result;
105
106 // get the engine interface, which is needed in order to create other objects
107 result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
108 assert(SL_RESULT_SUCCESS == result);
109 (void)result;
110
111 // create output mix, with environmental reverb specified as a non-required interface
112 const SLInterfaceID ids[1] = {SL_IID_ENVIRONMENTALREVERB};
113 const SLboolean req[1] = {SL_BOOLEAN_FALSE};
114 result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 1, ids, req);
115 assert(SL_RESULT_SUCCESS == result);
116 (void)result;
117
118 // realize the output mix
119 result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
120 assert(SL_RESULT_SUCCESS == result);
121 (void)result;
122}
123
124// create buffer queue audio player
125void createBufferQueueAudioPlayer(const ChunkFormat* chunkFormat) {
126 SLresult result;
127
128 // configure audio source
129 SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 1};
130
131 SLDataFormat_PCM format_pcm = {
132 SL_DATAFORMAT_PCM,
133 chunkFormat->num_channels,
134 chunkFormat->sample_rate * 1000, // convert to milliHz
135 chunkFormat->bits_per_sample,
136 16,
137 SL_SPEAKER_FRONT_CENTER,
138 SL_BYTEORDER_LITTLEENDIAN
139 };
140 SLDataSource audioSrc = {&loc_bufq, &format_pcm};
141
142 // configure audio sink
143 SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};
144 SLDataSink audioSnk = {&loc_outmix, NULL};
145
146 // create audio player
147 const SLInterfaceID ids[2] = {SL_IID_BUFFERQUEUE, SL_IID_VOLUME};
148 const SLboolean req[2] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
149 result = (*engineEngine)->CreateAudioPlayer(engineEngine, &bqPlayerObject, &audioSrc, &audioSnk,
150 2, ids, req);
151 assert(SL_RESULT_SUCCESS == result);
152 (void)result;
153
154 // realize the player
155 result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE);
156 assert(SL_RESULT_SUCCESS == result);
157 (void)result;
158
159 // get the play interface
160 result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay);
161 assert(SL_RESULT_SUCCESS == result);
162 (void)result;
163
164 // get the buffer queue interface
165 result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_BUFFERQUEUE,
166 &bqPlayerBufferQueue);
167 assert(SL_RESULT_SUCCESS == result);
168 (void)result;
169
170 // register callback on the buffer queue
171 result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, NULL);
172 assert(SL_RESULT_SUCCESS == result);
173 (void)result;
174
175#if 0 // mute/solo is not supported for sources that are known to be mono, as this is
176 // get the mute/solo interface
177 result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_MUTESOLO, &bqPlayerMuteSolo);
178 assert(SL_RESULT_SUCCESS == result);
179 (void)result;
180#endif
181
182 // get the volume interface
183 result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_VOLUME, &bqPlayerVolume);
184 assert(SL_RESULT_SUCCESS == result);
185 (void)result;
186
187 // set the player's state to playing
188 audioplay::setPlaying(true);
189 CHATTY("Created buffer queue player: %p", bqPlayerBufferQueue);
190}
191
192} // namespace
193
194void create() {
195 createEngine();
196}
197
198bool playClip(const uint8_t* buf, int size) {
199 // Parse the WAV header
200 nextBuffer = buf;
201 nextSize = size;
202 const RiffWaveHeader* wavHeader = (const RiffWaveHeader*)buf;
203 if (nextSize < sizeof(*wavHeader) || (wavHeader->riff_id != ID_RIFF) ||
204 (wavHeader->wave_id != ID_WAVE)) {
205 ALOGE("Error: audio file is not a riff/wave file\n");
206 return false;
207 }
208 nextBuffer += sizeof(*wavHeader);
209 nextSize -= sizeof(*wavHeader);
210
211 const ChunkFormat* chunkFormat = nullptr;
212 while (true) {
213 const ChunkHeader* chunkHeader = (const ChunkHeader*)nextBuffer;
214 if (nextSize < sizeof(*chunkHeader)) {
215 ALOGE("EOF reading chunk headers");
216 return false;
217 }
218
219 nextBuffer += sizeof(*chunkHeader);
220 nextSize -= sizeof(*chunkHeader);
221
222 bool endLoop = false;
223 switch (chunkHeader->id) {
224 case ID_FMT:
225 chunkFormat = (const ChunkFormat*)nextBuffer;
226 nextBuffer += chunkHeader->sz;
227 nextSize -= chunkHeader->sz;
228 break;
229 case ID_DATA:
230 /* Stop looking for chunks */
231 endLoop = true;
232 break;
233 default:
234 /* Unknown chunk, skip bytes */
235 nextBuffer += chunkHeader->sz;
236 nextSize -= chunkHeader->sz;
237 }
238 if (endLoop) {
239 break;
240 }
241 }
242
243 if (!chunkFormat) {
244 ALOGE("format not found in WAV file");
245 return false;
246 }
247
248 // If this is the first clip, create the buffer based on this WAV's header.
249 // We assume all future clips with be in the same format.
250 if (bqPlayerBufferQueue == nullptr) {
251 createBufferQueueAudioPlayer(chunkFormat);
252 }
253
254 assert(bqPlayerBufferQueue != nullptr);
255 assert(buf != nullptr);
256
257 if (!hasPlayer()) {
258 ALOGD("cannot play clip %p without a player", buf);
259 return false;
260 }
261
262 CHATTY("playClip on player %p: buf=%p size=%d", bqPlayerBufferQueue, buf, size);
263
264 if (nextSize > 0) {
265 // here we only enqueue one buffer because it is a long clip,
266 // but for streaming playback we would typically enqueue at least 2 buffers to start
267 SLresult result;
268 result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, nextBuffer, nextSize);
269 if (SL_RESULT_SUCCESS != result) {
270 return false;
271 }
272 audioplay::setPlaying(true);
273 }
274
275 return true;
276}
277
278// set the playing state for the buffer queue audio player
279void setPlaying(bool isPlaying) {
280 if (!hasPlayer()) return;
281
282 SLresult result;
283
284 if (NULL != bqPlayerPlay) {
285 // set the player's state
286 result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay,
287 isPlaying ? SL_PLAYSTATE_PLAYING : SL_PLAYSTATE_STOPPED);
288 assert(SL_RESULT_SUCCESS == result);
289 (void)result;
290 }
291
292}
293
294void destroy() {
295 // destroy buffer queue audio player object, and invalidate all associated interfaces
296 if (bqPlayerObject != NULL) {
297 CHATTY("destroying audio player");
298 (*bqPlayerObject)->Destroy(bqPlayerObject);
299 bqPlayerObject = NULL;
300 bqPlayerPlay = NULL;
301 bqPlayerBufferQueue = NULL;
302 bqPlayerMuteSolo = NULL;
303 bqPlayerVolume = NULL;
304 }
305
306 // destroy output mix object, and invalidate all associated interfaces
307 if (outputMixObject != NULL) {
308 (*outputMixObject)->Destroy(outputMixObject);
309 outputMixObject = NULL;
310 }
311
312 // destroy engine object, and invalidate all associated interfaces
313 if (engineObject != NULL) {
314 CHATTY("destroying audio engine");
315 (*engineObject)->Destroy(engineObject);
316 engineObject = NULL;
317 engineEngine = NULL;
318 }
319}
320
321} // namespace audioplay