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