1*d57664e9SAndroid Build Coastguard Worker /*
2*d57664e9SAndroid Build Coastguard Worker * Copyright (C) 2016 The Android Open Source Project
3*d57664e9SAndroid Build Coastguard Worker *
4*d57664e9SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*d57664e9SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*d57664e9SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*d57664e9SAndroid Build Coastguard Worker *
8*d57664e9SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*d57664e9SAndroid Build Coastguard Worker *
10*d57664e9SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*d57664e9SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*d57664e9SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*d57664e9SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*d57664e9SAndroid Build Coastguard Worker * limitations under the License.
15*d57664e9SAndroid Build Coastguard Worker *
16*d57664e9SAndroid Build Coastguard Worker */
17*d57664e9SAndroid Build Coastguard Worker
18*d57664e9SAndroid Build Coastguard Worker // cribbed from samples/native-audio
19*d57664e9SAndroid Build Coastguard Worker
20*d57664e9SAndroid Build Coastguard Worker #define CHATTY ALOGD
21*d57664e9SAndroid Build Coastguard Worker #define LOG_TAG "audioplay"
22*d57664e9SAndroid Build Coastguard Worker
23*d57664e9SAndroid Build Coastguard Worker #include <binder/IServiceManager.h>
24*d57664e9SAndroid Build Coastguard Worker
25*d57664e9SAndroid Build Coastguard Worker #include "audioplay.h"
26*d57664e9SAndroid Build Coastguard Worker
27*d57664e9SAndroid Build Coastguard Worker #include <string.h>
28*d57664e9SAndroid Build Coastguard Worker
29*d57664e9SAndroid Build Coastguard Worker #include <utils/Log.h>
30*d57664e9SAndroid Build Coastguard Worker #include <utils/threads.h>
31*d57664e9SAndroid Build Coastguard Worker
32*d57664e9SAndroid Build Coastguard Worker // for native audio
33*d57664e9SAndroid Build Coastguard Worker #include <SLES/OpenSLES.h>
34*d57664e9SAndroid Build Coastguard Worker #include <SLES/OpenSLES_Android.h>
35*d57664e9SAndroid Build Coastguard Worker
36*d57664e9SAndroid Build Coastguard Worker #include "BootAnimationUtil.h"
37*d57664e9SAndroid Build Coastguard Worker
38*d57664e9SAndroid Build Coastguard Worker namespace audioplay {
39*d57664e9SAndroid Build Coastguard Worker namespace {
40*d57664e9SAndroid Build Coastguard Worker
41*d57664e9SAndroid Build Coastguard Worker using namespace android;
42*d57664e9SAndroid Build Coastguard Worker
43*d57664e9SAndroid Build Coastguard Worker // engine interfaces
44*d57664e9SAndroid Build Coastguard Worker static SLObjectItf engineObject = nullptr;
45*d57664e9SAndroid Build Coastguard Worker static SLEngineItf engineEngine;
46*d57664e9SAndroid Build Coastguard Worker
47*d57664e9SAndroid Build Coastguard Worker // output mix interfaces
48*d57664e9SAndroid Build Coastguard Worker static SLObjectItf outputMixObject = nullptr;
49*d57664e9SAndroid Build Coastguard Worker
50*d57664e9SAndroid Build Coastguard Worker // buffer queue player interfaces
51*d57664e9SAndroid Build Coastguard Worker static SLObjectItf bqPlayerObject = nullptr;
52*d57664e9SAndroid Build Coastguard Worker static SLPlayItf bqPlayerPlay;
53*d57664e9SAndroid Build Coastguard Worker static SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue;
54*d57664e9SAndroid Build Coastguard Worker static SLMuteSoloItf bqPlayerMuteSolo;
55*d57664e9SAndroid Build Coastguard Worker static SLVolumeItf bqPlayerVolume;
56*d57664e9SAndroid Build Coastguard Worker
57*d57664e9SAndroid Build Coastguard Worker // pointer and size of the next player buffer to enqueue, and number of remaining buffers
58*d57664e9SAndroid Build Coastguard Worker static const uint8_t* nextBuffer;
59*d57664e9SAndroid Build Coastguard Worker static unsigned nextSize;
60*d57664e9SAndroid Build Coastguard Worker
61*d57664e9SAndroid Build Coastguard Worker static const uint32_t ID_RIFF = 0x46464952;
62*d57664e9SAndroid Build Coastguard Worker static const uint32_t ID_WAVE = 0x45564157;
63*d57664e9SAndroid Build Coastguard Worker static const uint32_t ID_FMT = 0x20746d66;
64*d57664e9SAndroid Build Coastguard Worker static const uint32_t ID_DATA = 0x61746164;
65*d57664e9SAndroid Build Coastguard Worker
66*d57664e9SAndroid Build Coastguard Worker struct RiffWaveHeader {
67*d57664e9SAndroid Build Coastguard Worker uint32_t riff_id;
68*d57664e9SAndroid Build Coastguard Worker uint32_t riff_sz;
69*d57664e9SAndroid Build Coastguard Worker uint32_t wave_id;
70*d57664e9SAndroid Build Coastguard Worker };
71*d57664e9SAndroid Build Coastguard Worker
72*d57664e9SAndroid Build Coastguard Worker struct ChunkHeader {
73*d57664e9SAndroid Build Coastguard Worker uint32_t id;
74*d57664e9SAndroid Build Coastguard Worker uint32_t sz;
75*d57664e9SAndroid Build Coastguard Worker };
76*d57664e9SAndroid Build Coastguard Worker
77*d57664e9SAndroid Build Coastguard Worker struct ChunkFormat {
78*d57664e9SAndroid Build Coastguard Worker uint16_t audio_format;
79*d57664e9SAndroid Build Coastguard Worker uint16_t num_channels;
80*d57664e9SAndroid Build Coastguard Worker uint32_t sample_rate;
81*d57664e9SAndroid Build Coastguard Worker uint32_t byte_rate;
82*d57664e9SAndroid Build Coastguard Worker uint16_t block_align;
83*d57664e9SAndroid Build Coastguard Worker uint16_t bits_per_sample;
84*d57664e9SAndroid Build Coastguard Worker };
85*d57664e9SAndroid Build Coastguard Worker
86*d57664e9SAndroid Build Coastguard Worker // this callback handler is called every time a buffer finishes playing
bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq,void * context)87*d57664e9SAndroid Build Coastguard Worker void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context) {
88*d57664e9SAndroid Build Coastguard Worker (void)bq;
89*d57664e9SAndroid Build Coastguard Worker (void)context;
90*d57664e9SAndroid Build Coastguard Worker audioplay::setPlaying(false);
91*d57664e9SAndroid Build Coastguard Worker }
92*d57664e9SAndroid Build Coastguard Worker
hasPlayer()93*d57664e9SAndroid Build Coastguard Worker bool hasPlayer() {
94*d57664e9SAndroid Build Coastguard Worker return (engineObject != nullptr && bqPlayerObject != nullptr);
95*d57664e9SAndroid Build Coastguard Worker }
96*d57664e9SAndroid Build Coastguard Worker
97*d57664e9SAndroid Build Coastguard Worker // create the engine and output mix objects
createEngine()98*d57664e9SAndroid Build Coastguard Worker bool createEngine() {
99*d57664e9SAndroid Build Coastguard Worker SLresult result;
100*d57664e9SAndroid Build Coastguard Worker
101*d57664e9SAndroid Build Coastguard Worker // create engine
102*d57664e9SAndroid Build Coastguard Worker result = slCreateEngine(&engineObject, 0, nullptr, 0, nullptr, nullptr);
103*d57664e9SAndroid Build Coastguard Worker if (result != SL_RESULT_SUCCESS) {
104*d57664e9SAndroid Build Coastguard Worker ALOGE("slCreateEngine failed with result %d", result);
105*d57664e9SAndroid Build Coastguard Worker return false;
106*d57664e9SAndroid Build Coastguard Worker }
107*d57664e9SAndroid Build Coastguard Worker (void)result;
108*d57664e9SAndroid Build Coastguard Worker
109*d57664e9SAndroid Build Coastguard Worker // realize the engine
110*d57664e9SAndroid Build Coastguard Worker result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
111*d57664e9SAndroid Build Coastguard Worker if (result != SL_RESULT_SUCCESS) {
112*d57664e9SAndroid Build Coastguard Worker ALOGE("sl engine Realize failed with result %d", result);
113*d57664e9SAndroid Build Coastguard Worker return false;
114*d57664e9SAndroid Build Coastguard Worker }
115*d57664e9SAndroid Build Coastguard Worker (void)result;
116*d57664e9SAndroid Build Coastguard Worker
117*d57664e9SAndroid Build Coastguard Worker // get the engine interface, which is needed in order to create other objects
118*d57664e9SAndroid Build Coastguard Worker result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
119*d57664e9SAndroid Build Coastguard Worker if (result != SL_RESULT_SUCCESS) {
120*d57664e9SAndroid Build Coastguard Worker ALOGE("sl engine GetInterface failed with result %d", result);
121*d57664e9SAndroid Build Coastguard Worker return false;
122*d57664e9SAndroid Build Coastguard Worker }
123*d57664e9SAndroid Build Coastguard Worker (void)result;
124*d57664e9SAndroid Build Coastguard Worker
125*d57664e9SAndroid Build Coastguard Worker // create output mix
126*d57664e9SAndroid Build Coastguard Worker result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, nullptr, nullptr);
127*d57664e9SAndroid Build Coastguard Worker if (result != SL_RESULT_SUCCESS) {
128*d57664e9SAndroid Build Coastguard Worker ALOGE("sl engine CreateOutputMix failed with result %d", result);
129*d57664e9SAndroid Build Coastguard Worker return false;
130*d57664e9SAndroid Build Coastguard Worker }
131*d57664e9SAndroid Build Coastguard Worker (void)result;
132*d57664e9SAndroid Build Coastguard Worker
133*d57664e9SAndroid Build Coastguard Worker // realize the output mix
134*d57664e9SAndroid Build Coastguard Worker result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
135*d57664e9SAndroid Build Coastguard Worker if (result != SL_RESULT_SUCCESS) {
136*d57664e9SAndroid Build Coastguard Worker ALOGE("sl outputMix Realize failed with result %d", result);
137*d57664e9SAndroid Build Coastguard Worker return false;
138*d57664e9SAndroid Build Coastguard Worker }
139*d57664e9SAndroid Build Coastguard Worker (void)result;
140*d57664e9SAndroid Build Coastguard Worker
141*d57664e9SAndroid Build Coastguard Worker return true;
142*d57664e9SAndroid Build Coastguard Worker }
143*d57664e9SAndroid Build Coastguard Worker
144*d57664e9SAndroid Build Coastguard Worker // create buffer queue audio player
createBufferQueueAudioPlayer(const ChunkFormat * chunkFormat)145*d57664e9SAndroid Build Coastguard Worker bool createBufferQueueAudioPlayer(const ChunkFormat* chunkFormat) {
146*d57664e9SAndroid Build Coastguard Worker SLresult result;
147*d57664e9SAndroid Build Coastguard Worker
148*d57664e9SAndroid Build Coastguard Worker // configure audio source
149*d57664e9SAndroid Build Coastguard Worker SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 1};
150*d57664e9SAndroid Build Coastguard Worker
151*d57664e9SAndroid Build Coastguard Worker // Determine channelMask from num_channels
152*d57664e9SAndroid Build Coastguard Worker SLuint32 channelMask;
153*d57664e9SAndroid Build Coastguard Worker switch (chunkFormat->num_channels) {
154*d57664e9SAndroid Build Coastguard Worker case 1:
155*d57664e9SAndroid Build Coastguard Worker channelMask = SL_SPEAKER_FRONT_CENTER;
156*d57664e9SAndroid Build Coastguard Worker break;
157*d57664e9SAndroid Build Coastguard Worker case 2:
158*d57664e9SAndroid Build Coastguard Worker channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
159*d57664e9SAndroid Build Coastguard Worker break;
160*d57664e9SAndroid Build Coastguard Worker default:
161*d57664e9SAndroid Build Coastguard Worker // Default of 0 will derive mask from num_channels and log a warning.
162*d57664e9SAndroid Build Coastguard Worker channelMask = 0;
163*d57664e9SAndroid Build Coastguard Worker }
164*d57664e9SAndroid Build Coastguard Worker
165*d57664e9SAndroid Build Coastguard Worker SLDataFormat_PCM format_pcm = {
166*d57664e9SAndroid Build Coastguard Worker SL_DATAFORMAT_PCM,
167*d57664e9SAndroid Build Coastguard Worker chunkFormat->num_channels,
168*d57664e9SAndroid Build Coastguard Worker chunkFormat->sample_rate * 1000, // convert to milliHz
169*d57664e9SAndroid Build Coastguard Worker chunkFormat->bits_per_sample,
170*d57664e9SAndroid Build Coastguard Worker 16,
171*d57664e9SAndroid Build Coastguard Worker channelMask,
172*d57664e9SAndroid Build Coastguard Worker SL_BYTEORDER_LITTLEENDIAN
173*d57664e9SAndroid Build Coastguard Worker };
174*d57664e9SAndroid Build Coastguard Worker SLDataSource audioSrc = {&loc_bufq, &format_pcm};
175*d57664e9SAndroid Build Coastguard Worker
176*d57664e9SAndroid Build Coastguard Worker // configure audio sink
177*d57664e9SAndroid Build Coastguard Worker SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};
178*d57664e9SAndroid Build Coastguard Worker SLDataSink audioSnk = {&loc_outmix, nullptr};
179*d57664e9SAndroid Build Coastguard Worker
180*d57664e9SAndroid Build Coastguard Worker // create audio player
181*d57664e9SAndroid Build Coastguard Worker const SLInterfaceID ids[3] = {SL_IID_BUFFERQUEUE, SL_IID_VOLUME, SL_IID_ANDROIDCONFIGURATION};
182*d57664e9SAndroid Build Coastguard Worker const SLboolean req[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
183*d57664e9SAndroid Build Coastguard Worker result = (*engineEngine)->CreateAudioPlayer(engineEngine, &bqPlayerObject, &audioSrc, &audioSnk,
184*d57664e9SAndroid Build Coastguard Worker 3, ids, req);
185*d57664e9SAndroid Build Coastguard Worker if (result != SL_RESULT_SUCCESS) {
186*d57664e9SAndroid Build Coastguard Worker ALOGE("sl CreateAudioPlayer failed with result %d", result);
187*d57664e9SAndroid Build Coastguard Worker return false;
188*d57664e9SAndroid Build Coastguard Worker }
189*d57664e9SAndroid Build Coastguard Worker (void)result;
190*d57664e9SAndroid Build Coastguard Worker
191*d57664e9SAndroid Build Coastguard Worker // Use the System stream for boot sound playback.
192*d57664e9SAndroid Build Coastguard Worker SLAndroidConfigurationItf playerConfig;
193*d57664e9SAndroid Build Coastguard Worker result = (*bqPlayerObject)->GetInterface(bqPlayerObject,
194*d57664e9SAndroid Build Coastguard Worker SL_IID_ANDROIDCONFIGURATION, &playerConfig);
195*d57664e9SAndroid Build Coastguard Worker if (result != SL_RESULT_SUCCESS) {
196*d57664e9SAndroid Build Coastguard Worker ALOGE("config GetInterface failed with result %d", result);
197*d57664e9SAndroid Build Coastguard Worker return false;
198*d57664e9SAndroid Build Coastguard Worker }
199*d57664e9SAndroid Build Coastguard Worker SLint32 streamType = SL_ANDROID_STREAM_SYSTEM;
200*d57664e9SAndroid Build Coastguard Worker result = (*playerConfig)->SetConfiguration(playerConfig,
201*d57664e9SAndroid Build Coastguard Worker SL_ANDROID_KEY_STREAM_TYPE, &streamType, sizeof(SLint32));
202*d57664e9SAndroid Build Coastguard Worker if (result != SL_RESULT_SUCCESS) {
203*d57664e9SAndroid Build Coastguard Worker ALOGE("SetConfiguration failed with result %d", result);
204*d57664e9SAndroid Build Coastguard Worker return false;
205*d57664e9SAndroid Build Coastguard Worker }
206*d57664e9SAndroid Build Coastguard Worker // use normal performance mode as low latency is not needed. This is not mandatory so
207*d57664e9SAndroid Build Coastguard Worker // do not bail if we fail
208*d57664e9SAndroid Build Coastguard Worker SLuint32 performanceMode = SL_ANDROID_PERFORMANCE_NONE;
209*d57664e9SAndroid Build Coastguard Worker result = (*playerConfig)->SetConfiguration(
210*d57664e9SAndroid Build Coastguard Worker playerConfig, SL_ANDROID_KEY_PERFORMANCE_MODE, &performanceMode, sizeof(SLuint32));
211*d57664e9SAndroid Build Coastguard Worker ALOGW_IF(result != SL_RESULT_SUCCESS,
212*d57664e9SAndroid Build Coastguard Worker "could not set performance mode on player, error %d", result);
213*d57664e9SAndroid Build Coastguard Worker (void)result;
214*d57664e9SAndroid Build Coastguard Worker
215*d57664e9SAndroid Build Coastguard Worker // realize the player
216*d57664e9SAndroid Build Coastguard Worker result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE);
217*d57664e9SAndroid Build Coastguard Worker if (result != SL_RESULT_SUCCESS) {
218*d57664e9SAndroid Build Coastguard Worker ALOGE("sl player Realize failed with result %d", result);
219*d57664e9SAndroid Build Coastguard Worker return false;
220*d57664e9SAndroid Build Coastguard Worker }
221*d57664e9SAndroid Build Coastguard Worker (void)result;
222*d57664e9SAndroid Build Coastguard Worker
223*d57664e9SAndroid Build Coastguard Worker // get the play interface
224*d57664e9SAndroid Build Coastguard Worker result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay);
225*d57664e9SAndroid Build Coastguard Worker if (result != SL_RESULT_SUCCESS) {
226*d57664e9SAndroid Build Coastguard Worker ALOGE("sl player GetInterface failed with result %d", result);
227*d57664e9SAndroid Build Coastguard Worker return false;
228*d57664e9SAndroid Build Coastguard Worker }
229*d57664e9SAndroid Build Coastguard Worker (void)result;
230*d57664e9SAndroid Build Coastguard Worker
231*d57664e9SAndroid Build Coastguard Worker // get the buffer queue interface
232*d57664e9SAndroid Build Coastguard Worker result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_BUFFERQUEUE,
233*d57664e9SAndroid Build Coastguard Worker &bqPlayerBufferQueue);
234*d57664e9SAndroid Build Coastguard Worker if (result != SL_RESULT_SUCCESS) {
235*d57664e9SAndroid Build Coastguard Worker ALOGE("sl playberBufferQueue GetInterface failed with result %d", result);
236*d57664e9SAndroid Build Coastguard Worker return false;
237*d57664e9SAndroid Build Coastguard Worker }
238*d57664e9SAndroid Build Coastguard Worker (void)result;
239*d57664e9SAndroid Build Coastguard Worker
240*d57664e9SAndroid Build Coastguard Worker // register callback on the buffer queue
241*d57664e9SAndroid Build Coastguard Worker result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, nullptr);
242*d57664e9SAndroid Build Coastguard Worker if (result != SL_RESULT_SUCCESS) {
243*d57664e9SAndroid Build Coastguard Worker ALOGE("sl bqPlayerBufferQueue RegisterCallback failed with result %d", result);
244*d57664e9SAndroid Build Coastguard Worker return false;
245*d57664e9SAndroid Build Coastguard Worker }
246*d57664e9SAndroid Build Coastguard Worker (void)result;
247*d57664e9SAndroid Build Coastguard Worker
248*d57664e9SAndroid Build Coastguard Worker // get the volume interface
249*d57664e9SAndroid Build Coastguard Worker result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_VOLUME, &bqPlayerVolume);
250*d57664e9SAndroid Build Coastguard Worker if (result != SL_RESULT_SUCCESS) {
251*d57664e9SAndroid Build Coastguard Worker ALOGE("sl volume GetInterface failed with result %d", result);
252*d57664e9SAndroid Build Coastguard Worker return false;
253*d57664e9SAndroid Build Coastguard Worker }
254*d57664e9SAndroid Build Coastguard Worker (void)result;
255*d57664e9SAndroid Build Coastguard Worker
256*d57664e9SAndroid Build Coastguard Worker // set the player's state to playing
257*d57664e9SAndroid Build Coastguard Worker audioplay::setPlaying(true);
258*d57664e9SAndroid Build Coastguard Worker CHATTY("Created buffer queue player: %p", bqPlayerBufferQueue);
259*d57664e9SAndroid Build Coastguard Worker return true;
260*d57664e9SAndroid Build Coastguard Worker }
261*d57664e9SAndroid Build Coastguard Worker
parseClipBuf(const uint8_t * clipBuf,int clipBufSize,const ChunkFormat ** oChunkFormat,const uint8_t ** oSoundBuf,unsigned * oSoundBufSize)262*d57664e9SAndroid Build Coastguard Worker bool parseClipBuf(const uint8_t* clipBuf, int clipBufSize, const ChunkFormat** oChunkFormat,
263*d57664e9SAndroid Build Coastguard Worker const uint8_t** oSoundBuf, unsigned* oSoundBufSize) {
264*d57664e9SAndroid Build Coastguard Worker *oSoundBuf = clipBuf;
265*d57664e9SAndroid Build Coastguard Worker *oSoundBufSize = clipBufSize;
266*d57664e9SAndroid Build Coastguard Worker *oChunkFormat = nullptr;
267*d57664e9SAndroid Build Coastguard Worker const RiffWaveHeader* wavHeader = (const RiffWaveHeader*)*oSoundBuf;
268*d57664e9SAndroid Build Coastguard Worker if (*oSoundBufSize < sizeof(*wavHeader) || (wavHeader->riff_id != ID_RIFF) ||
269*d57664e9SAndroid Build Coastguard Worker (wavHeader->wave_id != ID_WAVE)) {
270*d57664e9SAndroid Build Coastguard Worker ALOGE("Error: audio file is not a riff/wave file\n");
271*d57664e9SAndroid Build Coastguard Worker return false;
272*d57664e9SAndroid Build Coastguard Worker }
273*d57664e9SAndroid Build Coastguard Worker *oSoundBuf += sizeof(*wavHeader);
274*d57664e9SAndroid Build Coastguard Worker *oSoundBufSize -= sizeof(*wavHeader);
275*d57664e9SAndroid Build Coastguard Worker
276*d57664e9SAndroid Build Coastguard Worker while (true) {
277*d57664e9SAndroid Build Coastguard Worker const ChunkHeader* chunkHeader = (const ChunkHeader*)*oSoundBuf;
278*d57664e9SAndroid Build Coastguard Worker if (*oSoundBufSize < sizeof(*chunkHeader)) {
279*d57664e9SAndroid Build Coastguard Worker ALOGE("EOF reading chunk headers");
280*d57664e9SAndroid Build Coastguard Worker return false;
281*d57664e9SAndroid Build Coastguard Worker }
282*d57664e9SAndroid Build Coastguard Worker
283*d57664e9SAndroid Build Coastguard Worker *oSoundBuf += sizeof(*chunkHeader);
284*d57664e9SAndroid Build Coastguard Worker *oSoundBufSize -= sizeof(*chunkHeader);
285*d57664e9SAndroid Build Coastguard Worker
286*d57664e9SAndroid Build Coastguard Worker bool endLoop = false;
287*d57664e9SAndroid Build Coastguard Worker switch (chunkHeader->id) {
288*d57664e9SAndroid Build Coastguard Worker case ID_FMT:
289*d57664e9SAndroid Build Coastguard Worker *oChunkFormat = (const ChunkFormat*)*oSoundBuf;
290*d57664e9SAndroid Build Coastguard Worker *oSoundBuf += chunkHeader->sz;
291*d57664e9SAndroid Build Coastguard Worker *oSoundBufSize -= chunkHeader->sz;
292*d57664e9SAndroid Build Coastguard Worker break;
293*d57664e9SAndroid Build Coastguard Worker case ID_DATA:
294*d57664e9SAndroid Build Coastguard Worker /* Stop looking for chunks */
295*d57664e9SAndroid Build Coastguard Worker *oSoundBufSize = chunkHeader->sz;
296*d57664e9SAndroid Build Coastguard Worker endLoop = true;
297*d57664e9SAndroid Build Coastguard Worker break;
298*d57664e9SAndroid Build Coastguard Worker default:
299*d57664e9SAndroid Build Coastguard Worker /* Unknown chunk, skip bytes */
300*d57664e9SAndroid Build Coastguard Worker *oSoundBuf += chunkHeader->sz;
301*d57664e9SAndroid Build Coastguard Worker *oSoundBufSize -= chunkHeader->sz;
302*d57664e9SAndroid Build Coastguard Worker }
303*d57664e9SAndroid Build Coastguard Worker if (endLoop) {
304*d57664e9SAndroid Build Coastguard Worker break;
305*d57664e9SAndroid Build Coastguard Worker }
306*d57664e9SAndroid Build Coastguard Worker }
307*d57664e9SAndroid Build Coastguard Worker
308*d57664e9SAndroid Build Coastguard Worker if (*oChunkFormat == nullptr) {
309*d57664e9SAndroid Build Coastguard Worker ALOGE("format not found in WAV file");
310*d57664e9SAndroid Build Coastguard Worker return false;
311*d57664e9SAndroid Build Coastguard Worker }
312*d57664e9SAndroid Build Coastguard Worker return true;
313*d57664e9SAndroid Build Coastguard Worker }
314*d57664e9SAndroid Build Coastguard Worker
315*d57664e9SAndroid Build Coastguard Worker class InitAudioThread : public Thread {
316*d57664e9SAndroid Build Coastguard Worker public:
InitAudioThread(uint8_t * exampleAudioData,int exampleAudioLength)317*d57664e9SAndroid Build Coastguard Worker InitAudioThread(uint8_t* exampleAudioData, int exampleAudioLength)
318*d57664e9SAndroid Build Coastguard Worker : Thread(false),
319*d57664e9SAndroid Build Coastguard Worker mExampleAudioData(exampleAudioData),
320*d57664e9SAndroid Build Coastguard Worker mExampleAudioLength(exampleAudioLength) {}
321*d57664e9SAndroid Build Coastguard Worker
322*d57664e9SAndroid Build Coastguard Worker private:
threadLoop()323*d57664e9SAndroid Build Coastguard Worker virtual bool threadLoop() {
324*d57664e9SAndroid Build Coastguard Worker if (defaultServiceManager()->checkService(String16("audio")) == nullptr) {
325*d57664e9SAndroid Build Coastguard Worker ALOGW("Audio service is not ready yet, ignore creating playback engine");
326*d57664e9SAndroid Build Coastguard Worker return false;
327*d57664e9SAndroid Build Coastguard Worker }
328*d57664e9SAndroid Build Coastguard Worker audioplay::create(mExampleAudioData, mExampleAudioLength);
329*d57664e9SAndroid Build Coastguard Worker // Exit immediately
330*d57664e9SAndroid Build Coastguard Worker return false;
331*d57664e9SAndroid Build Coastguard Worker }
332*d57664e9SAndroid Build Coastguard Worker
333*d57664e9SAndroid Build Coastguard Worker uint8_t* mExampleAudioData;
334*d57664e9SAndroid Build Coastguard Worker int mExampleAudioLength;
335*d57664e9SAndroid Build Coastguard Worker };
336*d57664e9SAndroid Build Coastguard Worker
337*d57664e9SAndroid Build Coastguard Worker // Typedef to aid readability.
338*d57664e9SAndroid Build Coastguard Worker typedef android::BootAnimation::Animation Animation;
339*d57664e9SAndroid Build Coastguard Worker
340*d57664e9SAndroid Build Coastguard Worker class AudioAnimationCallbacks : public android::BootAnimation::Callbacks {
341*d57664e9SAndroid Build Coastguard Worker public:
init(const Vector<Animation::Part> & parts)342*d57664e9SAndroid Build Coastguard Worker void init(const Vector<Animation::Part>& parts) override {
343*d57664e9SAndroid Build Coastguard Worker const Animation::Part* partWithAudio = nullptr;
344*d57664e9SAndroid Build Coastguard Worker
345*d57664e9SAndroid Build Coastguard Worker if (!playSoundsAllowed()) {
346*d57664e9SAndroid Build Coastguard Worker return;
347*d57664e9SAndroid Build Coastguard Worker }
348*d57664e9SAndroid Build Coastguard Worker
349*d57664e9SAndroid Build Coastguard Worker for (const Animation::Part& part : parts) {
350*d57664e9SAndroid Build Coastguard Worker if (part.audioData != nullptr) {
351*d57664e9SAndroid Build Coastguard Worker partWithAudio = ∂
352*d57664e9SAndroid Build Coastguard Worker break;
353*d57664e9SAndroid Build Coastguard Worker }
354*d57664e9SAndroid Build Coastguard Worker }
355*d57664e9SAndroid Build Coastguard Worker
356*d57664e9SAndroid Build Coastguard Worker if (partWithAudio == nullptr) {
357*d57664e9SAndroid Build Coastguard Worker return;
358*d57664e9SAndroid Build Coastguard Worker }
359*d57664e9SAndroid Build Coastguard Worker
360*d57664e9SAndroid Build Coastguard Worker ALOGD("found audio.wav, creating playback engine");
361*d57664e9SAndroid Build Coastguard Worker // The audioData is used to initialize the audio system. Different data
362*d57664e9SAndroid Build Coastguard Worker // can be played later for other parts BUT the assumption is that they
363*d57664e9SAndroid Build Coastguard Worker // will all be the same format and only the format of this audioData
364*d57664e9SAndroid Build Coastguard Worker // will work correctly.
365*d57664e9SAndroid Build Coastguard Worker initAudioThread = new InitAudioThread(partWithAudio->audioData,
366*d57664e9SAndroid Build Coastguard Worker partWithAudio->audioLength);
367*d57664e9SAndroid Build Coastguard Worker initAudioThread->run("BootAnimation::InitAudioThread", PRIORITY_NORMAL);
368*d57664e9SAndroid Build Coastguard Worker };
369*d57664e9SAndroid Build Coastguard Worker
playPart(int partNumber,const Animation::Part & part,int playNumber)370*d57664e9SAndroid Build Coastguard Worker void playPart(int partNumber, const Animation::Part& part, int playNumber) override {
371*d57664e9SAndroid Build Coastguard Worker // only play audio file the first time we animate the part
372*d57664e9SAndroid Build Coastguard Worker if (playNumber == 0 && part.audioData && playSoundsAllowed()) {
373*d57664e9SAndroid Build Coastguard Worker ALOGD("playing clip for part%d, size=%d",
374*d57664e9SAndroid Build Coastguard Worker partNumber, part.audioLength);
375*d57664e9SAndroid Build Coastguard Worker // Block until the audio engine is finished initializing.
376*d57664e9SAndroid Build Coastguard Worker if (initAudioThread != nullptr) {
377*d57664e9SAndroid Build Coastguard Worker initAudioThread->join();
378*d57664e9SAndroid Build Coastguard Worker }
379*d57664e9SAndroid Build Coastguard Worker audioplay::playClip(part.audioData, part.audioLength);
380*d57664e9SAndroid Build Coastguard Worker }
381*d57664e9SAndroid Build Coastguard Worker };
382*d57664e9SAndroid Build Coastguard Worker
shutdown()383*d57664e9SAndroid Build Coastguard Worker void shutdown() override {
384*d57664e9SAndroid Build Coastguard Worker // we've finally played everything we're going to play
385*d57664e9SAndroid Build Coastguard Worker audioplay::setPlaying(false);
386*d57664e9SAndroid Build Coastguard Worker audioplay::destroy();
387*d57664e9SAndroid Build Coastguard Worker };
388*d57664e9SAndroid Build Coastguard Worker
389*d57664e9SAndroid Build Coastguard Worker private:
390*d57664e9SAndroid Build Coastguard Worker sp<InitAudioThread> initAudioThread = nullptr;
391*d57664e9SAndroid Build Coastguard Worker };
392*d57664e9SAndroid Build Coastguard Worker
393*d57664e9SAndroid Build Coastguard Worker } // namespace
394*d57664e9SAndroid Build Coastguard Worker
create(const uint8_t * exampleClipBuf,int exampleClipBufSize)395*d57664e9SAndroid Build Coastguard Worker bool create(const uint8_t* exampleClipBuf, int exampleClipBufSize) {
396*d57664e9SAndroid Build Coastguard Worker if (!createEngine()) {
397*d57664e9SAndroid Build Coastguard Worker return false;
398*d57664e9SAndroid Build Coastguard Worker }
399*d57664e9SAndroid Build Coastguard Worker
400*d57664e9SAndroid Build Coastguard Worker // Parse the example clip.
401*d57664e9SAndroid Build Coastguard Worker const ChunkFormat* chunkFormat;
402*d57664e9SAndroid Build Coastguard Worker const uint8_t* soundBuf;
403*d57664e9SAndroid Build Coastguard Worker unsigned soundBufSize;
404*d57664e9SAndroid Build Coastguard Worker if (!parseClipBuf(exampleClipBuf, exampleClipBufSize, &chunkFormat, &soundBuf, &soundBufSize)) {
405*d57664e9SAndroid Build Coastguard Worker return false;
406*d57664e9SAndroid Build Coastguard Worker }
407*d57664e9SAndroid Build Coastguard Worker
408*d57664e9SAndroid Build Coastguard Worker // Initialize the BufferQueue based on this clip's format.
409*d57664e9SAndroid Build Coastguard Worker if (!createBufferQueueAudioPlayer(chunkFormat)) {
410*d57664e9SAndroid Build Coastguard Worker return false;
411*d57664e9SAndroid Build Coastguard Worker }
412*d57664e9SAndroid Build Coastguard Worker return true;
413*d57664e9SAndroid Build Coastguard Worker }
414*d57664e9SAndroid Build Coastguard Worker
playClip(const uint8_t * buf,int size)415*d57664e9SAndroid Build Coastguard Worker bool playClip(const uint8_t* buf, int size) {
416*d57664e9SAndroid Build Coastguard Worker if (!hasPlayer()) {
417*d57664e9SAndroid Build Coastguard Worker ALOGE("cannot play clip %p without a player", buf);
418*d57664e9SAndroid Build Coastguard Worker return false;
419*d57664e9SAndroid Build Coastguard Worker }
420*d57664e9SAndroid Build Coastguard Worker
421*d57664e9SAndroid Build Coastguard Worker // Parse the WAV header
422*d57664e9SAndroid Build Coastguard Worker const ChunkFormat* chunkFormat;
423*d57664e9SAndroid Build Coastguard Worker if (!parseClipBuf(buf, size, &chunkFormat, &nextBuffer, &nextSize)) {
424*d57664e9SAndroid Build Coastguard Worker return false;
425*d57664e9SAndroid Build Coastguard Worker }
426*d57664e9SAndroid Build Coastguard Worker
427*d57664e9SAndroid Build Coastguard Worker CHATTY("playClip on player %p: buf=%p size=%d nextSize %d",
428*d57664e9SAndroid Build Coastguard Worker bqPlayerBufferQueue, buf, size, nextSize);
429*d57664e9SAndroid Build Coastguard Worker
430*d57664e9SAndroid Build Coastguard Worker if (nextSize > 0) {
431*d57664e9SAndroid Build Coastguard Worker // here we only enqueue one buffer because it is a long clip,
432*d57664e9SAndroid Build Coastguard Worker // but for streaming playback we would typically enqueue at least 2 buffers to start
433*d57664e9SAndroid Build Coastguard Worker SLresult result;
434*d57664e9SAndroid Build Coastguard Worker result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, nextBuffer, nextSize);
435*d57664e9SAndroid Build Coastguard Worker if (SL_RESULT_SUCCESS != result) {
436*d57664e9SAndroid Build Coastguard Worker return false;
437*d57664e9SAndroid Build Coastguard Worker }
438*d57664e9SAndroid Build Coastguard Worker audioplay::setPlaying(true);
439*d57664e9SAndroid Build Coastguard Worker }
440*d57664e9SAndroid Build Coastguard Worker
441*d57664e9SAndroid Build Coastguard Worker return true;
442*d57664e9SAndroid Build Coastguard Worker }
443*d57664e9SAndroid Build Coastguard Worker
444*d57664e9SAndroid Build Coastguard Worker // set the playing state for the buffer queue audio player
setPlaying(bool isPlaying)445*d57664e9SAndroid Build Coastguard Worker void setPlaying(bool isPlaying) {
446*d57664e9SAndroid Build Coastguard Worker if (!hasPlayer()) return;
447*d57664e9SAndroid Build Coastguard Worker
448*d57664e9SAndroid Build Coastguard Worker if (nullptr != bqPlayerPlay) {
449*d57664e9SAndroid Build Coastguard Worker // set the player's state
450*d57664e9SAndroid Build Coastguard Worker (*bqPlayerPlay)->SetPlayState(bqPlayerPlay,
451*d57664e9SAndroid Build Coastguard Worker isPlaying ? SL_PLAYSTATE_PLAYING : SL_PLAYSTATE_STOPPED);
452*d57664e9SAndroid Build Coastguard Worker }
453*d57664e9SAndroid Build Coastguard Worker
454*d57664e9SAndroid Build Coastguard Worker }
455*d57664e9SAndroid Build Coastguard Worker
destroy()456*d57664e9SAndroid Build Coastguard Worker void destroy() {
457*d57664e9SAndroid Build Coastguard Worker // destroy buffer queue audio player object, and invalidate all associated interfaces
458*d57664e9SAndroid Build Coastguard Worker if (bqPlayerObject != nullptr) {
459*d57664e9SAndroid Build Coastguard Worker CHATTY("destroying audio player");
460*d57664e9SAndroid Build Coastguard Worker (*bqPlayerObject)->Destroy(bqPlayerObject);
461*d57664e9SAndroid Build Coastguard Worker bqPlayerObject = nullptr;
462*d57664e9SAndroid Build Coastguard Worker bqPlayerPlay = nullptr;
463*d57664e9SAndroid Build Coastguard Worker bqPlayerBufferQueue = nullptr;
464*d57664e9SAndroid Build Coastguard Worker bqPlayerMuteSolo = nullptr;
465*d57664e9SAndroid Build Coastguard Worker bqPlayerVolume = nullptr;
466*d57664e9SAndroid Build Coastguard Worker }
467*d57664e9SAndroid Build Coastguard Worker
468*d57664e9SAndroid Build Coastguard Worker // destroy output mix object, and invalidate all associated interfaces
469*d57664e9SAndroid Build Coastguard Worker if (outputMixObject != nullptr) {
470*d57664e9SAndroid Build Coastguard Worker (*outputMixObject)->Destroy(outputMixObject);
471*d57664e9SAndroid Build Coastguard Worker outputMixObject = nullptr;
472*d57664e9SAndroid Build Coastguard Worker }
473*d57664e9SAndroid Build Coastguard Worker
474*d57664e9SAndroid Build Coastguard Worker // destroy engine object, and invalidate all associated interfaces
475*d57664e9SAndroid Build Coastguard Worker if (engineObject != nullptr) {
476*d57664e9SAndroid Build Coastguard Worker CHATTY("destroying audio engine");
477*d57664e9SAndroid Build Coastguard Worker (*engineObject)->Destroy(engineObject);
478*d57664e9SAndroid Build Coastguard Worker engineObject = nullptr;
479*d57664e9SAndroid Build Coastguard Worker engineEngine = nullptr;
480*d57664e9SAndroid Build Coastguard Worker }
481*d57664e9SAndroid Build Coastguard Worker }
482*d57664e9SAndroid Build Coastguard Worker
createAnimationCallbacks()483*d57664e9SAndroid Build Coastguard Worker sp<BootAnimation::Callbacks> createAnimationCallbacks() {
484*d57664e9SAndroid Build Coastguard Worker return new AudioAnimationCallbacks();
485*d57664e9SAndroid Build Coastguard Worker }
486*d57664e9SAndroid Build Coastguard Worker
487*d57664e9SAndroid Build Coastguard Worker } // namespace audioplay
488