blob: 9b95b04149bfc5225c299b86684b6206f8b778ef [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
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -070020#define CHATTY ALOGD
Eric Laurent197e4792016-07-21 18:17:15 -070021#define LOG_TAG "audioplay"
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -070022
hoaxf12277b2022-05-18 08:58:40 +000023#include <binder/IServiceManager.h>
24
Ed Coyne33f4b7d2018-04-10 13:39:09 -070025#include "audioplay.h"
26
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -070027#include <string.h>
28
29#include <utils/Log.h>
Ed Coyne33f4b7d2018-04-10 13:39:09 -070030#include <utils/threads.h>
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -070031
32// for native audio
33#include <SLES/OpenSLES.h>
34#include <SLES/OpenSLES_Android.h>
35
Ed Coyne33f4b7d2018-04-10 13:39:09 -070036#include "BootAnimationUtil.h"
37
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -070038namespace audioplay {
39namespace {
40
Ed Coyne33f4b7d2018-04-10 13:39:09 -070041using namespace android;
42
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -070043// engine interfaces
Yi Kong911ac232019-03-24 01:49:02 -070044static SLObjectItf engineObject = nullptr;
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -070045static SLEngineItf engineEngine;
46
47// output mix interfaces
Yi Kong911ac232019-03-24 01:49:02 -070048static SLObjectItf outputMixObject = nullptr;
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -070049
50// buffer queue player interfaces
Yi Kong911ac232019-03-24 01:49:02 -070051static SLObjectItf bqPlayerObject = nullptr;
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -070052static SLPlayItf bqPlayerPlay;
53static SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue;
54static SLMuteSoloItf bqPlayerMuteSolo;
55static SLVolumeItf bqPlayerVolume;
56
57// pointer and size of the next player buffer to enqueue, and number of remaining buffers
58static const uint8_t* nextBuffer;
59static unsigned nextSize;
60
61static const uint32_t ID_RIFF = 0x46464952;
62static const uint32_t ID_WAVE = 0x45564157;
63static const uint32_t ID_FMT = 0x20746d66;
64static const uint32_t ID_DATA = 0x61746164;
65
66struct RiffWaveHeader {
67 uint32_t riff_id;
68 uint32_t riff_sz;
69 uint32_t wave_id;
70};
71
72struct ChunkHeader {
73 uint32_t id;
74 uint32_t sz;
75};
76
77struct 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
87void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context) {
88 (void)bq;
89 (void)context;
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -070090 audioplay::setPlaying(false);
91}
92
93bool hasPlayer() {
Yi Kong911ac232019-03-24 01:49:02 -070094 return (engineObject != nullptr && bqPlayerObject != nullptr);
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -070095}
96
97// create the engine and output mix objects
Geoffrey Pitscha91a2d72016-07-12 14:46:19 -040098bool createEngine() {
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -070099 SLresult result;
100
101 // create engine
Yi Kong911ac232019-03-24 01:49:02 -0700102 result = slCreateEngine(&engineObject, 0, nullptr, 0, nullptr, nullptr);
Geoffrey Pitscha91a2d72016-07-12 14:46:19 -0400103 if (result != SL_RESULT_SUCCESS) {
104 ALOGE("slCreateEngine failed with result %d", result);
105 return false;
106 }
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -0700107 (void)result;
108
109 // realize the engine
110 result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
Geoffrey Pitscha91a2d72016-07-12 14:46:19 -0400111 if (result != SL_RESULT_SUCCESS) {
112 ALOGE("sl engine Realize failed with result %d", result);
113 return false;
114 }
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -0700115 (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);
Geoffrey Pitscha91a2d72016-07-12 14:46:19 -0400119 if (result != SL_RESULT_SUCCESS) {
120 ALOGE("sl engine GetInterface failed with result %d", result);
121 return false;
122 }
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -0700123 (void)result;
124
Eric Laurent197e4792016-07-21 18:17:15 -0700125 // create output mix
Yi Kong911ac232019-03-24 01:49:02 -0700126 result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, nullptr, nullptr);
Geoffrey Pitscha91a2d72016-07-12 14:46:19 -0400127 if (result != SL_RESULT_SUCCESS) {
128 ALOGE("sl engine CreateOutputMix failed with result %d", result);
129 return false;
130 }
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -0700131 (void)result;
132
133 // realize the output mix
134 result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
Geoffrey Pitscha91a2d72016-07-12 14:46:19 -0400135 if (result != SL_RESULT_SUCCESS) {
136 ALOGE("sl outputMix Realize failed with result %d", result);
137 return false;
138 }
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -0700139 (void)result;
Geoffrey Pitscha91a2d72016-07-12 14:46:19 -0400140
141 return true;
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -0700142}
143
144// create buffer queue audio player
Geoffrey Pitscha91a2d72016-07-12 14:46:19 -0400145bool createBufferQueueAudioPlayer(const ChunkFormat* chunkFormat) {
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -0700146 SLresult result;
147
148 // configure audio source
149 SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 1};
150
Geoffrey Pitschdb908972016-08-24 14:35:09 -0400151 // 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
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -0700165 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,
Geoffrey Pitschdb908972016-08-24 14:35:09 -0400171 channelMask,
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -0700172 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};
Yi Kong911ac232019-03-24 01:49:02 -0700178 SLDataSink audioSnk = {&loc_outmix, nullptr};
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -0700179
180 // create audio player
Geoffrey Pitsch56133132016-07-15 10:50:04 -0400181 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};
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -0700183 result = (*engineEngine)->CreateAudioPlayer(engineEngine, &bqPlayerObject, &audioSrc, &audioSnk,
Geoffrey Pitsch56133132016-07-15 10:50:04 -0400184 3, ids, req);
Geoffrey Pitscha91a2d72016-07-12 14:46:19 -0400185 if (result != SL_RESULT_SUCCESS) {
186 ALOGE("sl CreateAudioPlayer failed with result %d", result);
187 return false;
188 }
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -0700189 (void)result;
190
Geoffrey Pitsch56133132016-07-15 10:50:04 -0400191 // 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 }
Eric Laurent197e4792016-07-21 18:17:15 -0700206 // 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;
Geoffrey Pitsch56133132016-07-15 10:50:04 -0400214
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -0700215 // realize the player
216 result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE);
Geoffrey Pitscha91a2d72016-07-12 14:46:19 -0400217 if (result != SL_RESULT_SUCCESS) {
218 ALOGE("sl player Realize failed with result %d", result);
219 return false;
220 }
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -0700221 (void)result;
222
223 // get the play interface
224 result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay);
Geoffrey Pitscha91a2d72016-07-12 14:46:19 -0400225 if (result != SL_RESULT_SUCCESS) {
226 ALOGE("sl player GetInterface failed with result %d", result);
227 return false;
228 }
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -0700229 (void)result;
230
231 // get the buffer queue interface
232 result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_BUFFERQUEUE,
233 &bqPlayerBufferQueue);
Geoffrey Pitscha91a2d72016-07-12 14:46:19 -0400234 if (result != SL_RESULT_SUCCESS) {
235 ALOGE("sl playberBufferQueue GetInterface failed with result %d", result);
236 return false;
237 }
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -0700238 (void)result;
239
240 // register callback on the buffer queue
Yi Kong911ac232019-03-24 01:49:02 -0700241 result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, nullptr);
Geoffrey Pitscha91a2d72016-07-12 14:46:19 -0400242 if (result != SL_RESULT_SUCCESS) {
243 ALOGE("sl bqPlayerBufferQueue RegisterCallback failed with result %d", result);
244 return false;
245 }
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -0700246 (void)result;
247
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -0700248 // get the volume interface
249 result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_VOLUME, &bqPlayerVolume);
Geoffrey Pitscha91a2d72016-07-12 14:46:19 -0400250 if (result != SL_RESULT_SUCCESS) {
251 ALOGE("sl volume GetInterface failed with result %d", result);
252 return false;
253 }
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -0700254 (void)result;
255
256 // set the player's state to playing
257 audioplay::setPlaying(true);
258 CHATTY("Created buffer queue player: %p", bqPlayerBufferQueue);
Geoffrey Pitscha91a2d72016-07-12 14:46:19 -0400259 return true;
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -0700260}
261
Geoffrey Pitscha91a2d72016-07-12 14:46:19 -0400262bool parseClipBuf(const uint8_t* clipBuf, int clipBufSize, const ChunkFormat** oChunkFormat,
263 const uint8_t** oSoundBuf, unsigned* oSoundBufSize) {
264 *oSoundBuf = clipBuf;
265 *oSoundBufSize = clipBufSize;
Yi Kong911ac232019-03-24 01:49:02 -0700266 *oChunkFormat = nullptr;
Geoffrey Pitscha91a2d72016-07-12 14:46:19 -0400267 const RiffWaveHeader* wavHeader = (const RiffWaveHeader*)*oSoundBuf;
268 if (*oSoundBufSize < sizeof(*wavHeader) || (wavHeader->riff_id != ID_RIFF) ||
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -0700269 (wavHeader->wave_id != ID_WAVE)) {
270 ALOGE("Error: audio file is not a riff/wave file\n");
271 return false;
272 }
Geoffrey Pitscha91a2d72016-07-12 14:46:19 -0400273 *oSoundBuf += sizeof(*wavHeader);
274 *oSoundBufSize -= sizeof(*wavHeader);
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -0700275
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -0700276 while (true) {
Geoffrey Pitscha91a2d72016-07-12 14:46:19 -0400277 const ChunkHeader* chunkHeader = (const ChunkHeader*)*oSoundBuf;
278 if (*oSoundBufSize < sizeof(*chunkHeader)) {
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -0700279 ALOGE("EOF reading chunk headers");
280 return false;
281 }
282
Geoffrey Pitscha91a2d72016-07-12 14:46:19 -0400283 *oSoundBuf += sizeof(*chunkHeader);
284 *oSoundBufSize -= sizeof(*chunkHeader);
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -0700285
286 bool endLoop = false;
287 switch (chunkHeader->id) {
288 case ID_FMT:
Geoffrey Pitscha91a2d72016-07-12 14:46:19 -0400289 *oChunkFormat = (const ChunkFormat*)*oSoundBuf;
290 *oSoundBuf += chunkHeader->sz;
291 *oSoundBufSize -= chunkHeader->sz;
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -0700292 break;
293 case ID_DATA:
294 /* Stop looking for chunks */
Eric Laurent197e4792016-07-21 18:17:15 -0700295 *oSoundBufSize = chunkHeader->sz;
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -0700296 endLoop = true;
297 break;
298 default:
299 /* Unknown chunk, skip bytes */
Geoffrey Pitscha91a2d72016-07-12 14:46:19 -0400300 *oSoundBuf += chunkHeader->sz;
301 *oSoundBufSize -= chunkHeader->sz;
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -0700302 }
303 if (endLoop) {
304 break;
305 }
306 }
307
Yi Kong911ac232019-03-24 01:49:02 -0700308 if (*oChunkFormat == nullptr) {
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -0700309 ALOGE("format not found in WAV file");
310 return false;
311 }
Geoffrey Pitscha91a2d72016-07-12 14:46:19 -0400312 return true;
313}
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -0700314
Ed Coyne33f4b7d2018-04-10 13:39:09 -0700315class InitAudioThread : public Thread {
316public:
317 InitAudioThread(uint8_t* exampleAudioData, int exampleAudioLength)
318 : Thread(false),
319 mExampleAudioData(exampleAudioData),
320 mExampleAudioLength(exampleAudioLength) {}
hoaxf12277b2022-05-18 08:58:40 +0000321
Ed Coyne33f4b7d2018-04-10 13:39:09 -0700322private:
323 virtual bool threadLoop() {
hoaxf12277b2022-05-18 08:58:40 +0000324 if (defaultServiceManager()->checkService(String16("audio")) == nullptr) {
325 ALOGW("Audio service is not ready yet, ignore creating playback engine");
326 return false;
327 }
Ed Coyne33f4b7d2018-04-10 13:39:09 -0700328 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.
338typedef android::BootAnimation::Animation Animation;
339
340class AudioAnimationCallbacks : public android::BootAnimation::Callbacks {
341public:
342 void init(const Vector<Animation::Part>& parts) override {
343 const Animation::Part* partWithAudio = nullptr;
Hoa Hoang1cd98762021-11-15 13:42:57 +0000344
345 if (!playSoundsAllowed()) {
346 return;
347 }
348
Ed Coyne33f4b7d2018-04-10 13:39:09 -0700349 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
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
383 void shutdown() override {
384 // we've finally played everything we're going to play
385 audioplay::setPlaying(false);
386 audioplay::destroy();
387 };
388
389private:
390 sp<InitAudioThread> initAudioThread = nullptr;
391};
392
Geoffrey Pitscha91a2d72016-07-12 14:46:19 -0400393} // namespace
394
395bool create(const uint8_t* exampleClipBuf, int exampleClipBufSize) {
396 if (!createEngine()) {
397 return false;
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -0700398 }
399
Geoffrey Pitscha91a2d72016-07-12 14:46:19 -0400400 // 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
415bool playClip(const uint8_t* buf, int size) {
hoaxf12277b2022-05-18 08:58:40 +0000416 if (!hasPlayer()) {
417 ALOGE("cannot play clip %p without a player", buf);
Geoffrey Pitscha91a2d72016-07-12 14:46:19 -0400418 return false;
419 }
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -0700420
hoaxf12277b2022-05-18 08:58:40 +0000421 // Parse the WAV header
422 const ChunkFormat* chunkFormat;
423 if (!parseClipBuf(buf, size, &chunkFormat, &nextBuffer, &nextSize)) {
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -0700424 return false;
425 }
426
Eric Laurent197e4792016-07-21 18:17:15 -0700427 CHATTY("playClip on player %p: buf=%p size=%d nextSize %d",
428 bqPlayerBufferQueue, buf, size, nextSize);
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -0700429
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
445void setPlaying(bool isPlaying) {
446 if (!hasPlayer()) return;
447
Yi Kong911ac232019-03-24 01:49:02 -0700448 if (nullptr != bqPlayerPlay) {
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -0700449 // set the player's state
hoaxf12277b2022-05-18 08:58:40 +0000450 (*bqPlayerPlay)->SetPlayState(bqPlayerPlay,
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -0700451 isPlaying ? SL_PLAYSTATE_PLAYING : SL_PLAYSTATE_STOPPED);
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -0700452 }
453
454}
455
456void destroy() {
457 // destroy buffer queue audio player object, and invalidate all associated interfaces
Yi Kong911ac232019-03-24 01:49:02 -0700458 if (bqPlayerObject != nullptr) {
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -0700459 CHATTY("destroying audio player");
460 (*bqPlayerObject)->Destroy(bqPlayerObject);
Yi Kong911ac232019-03-24 01:49:02 -0700461 bqPlayerObject = nullptr;
462 bqPlayerPlay = nullptr;
463 bqPlayerBufferQueue = nullptr;
464 bqPlayerMuteSolo = nullptr;
465 bqPlayerVolume = nullptr;
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -0700466 }
467
468 // destroy output mix object, and invalidate all associated interfaces
Yi Kong911ac232019-03-24 01:49:02 -0700469 if (outputMixObject != nullptr) {
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -0700470 (*outputMixObject)->Destroy(outputMixObject);
Yi Kong911ac232019-03-24 01:49:02 -0700471 outputMixObject = nullptr;
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -0700472 }
473
474 // destroy engine object, and invalidate all associated interfaces
Yi Kong911ac232019-03-24 01:49:02 -0700475 if (engineObject != nullptr) {
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -0700476 CHATTY("destroying audio engine");
477 (*engineObject)->Destroy(engineObject);
Yi Kong911ac232019-03-24 01:49:02 -0700478 engineObject = nullptr;
479 engineEngine = nullptr;
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -0700480 }
481}
482
Ed Coyne33f4b7d2018-04-10 13:39:09 -0700483sp<BootAnimation::Callbacks> createAnimationCallbacks() {
484 return new AudioAnimationCallbacks();
485}
486
Geoffrey Pitschd6d9a1d2016-06-08 00:38:58 -0700487} // namespace audioplay