diff options
author | 2016-07-12 14:46:19 -0400 | |
---|---|---|
committer | 2016-07-13 15:51:24 -0400 | |
commit | a91a2d737586ebd0040129333055d8093899751b (patch) | |
tree | 0ca3a04b3397357204fc39d968a3d6968aaf52f1 | |
parent | f6d766020f9b4d082ee38c38e6496655e1e56c61 (diff) |
Fixes delay when playing first sound in BootAnimation
audioplay is initialized with an example of the type of clip it
will play.
Also remove asserts and debug compile settings from BootAnimation.
BUG:24800792
Change-Id: Icb78489417aee0549c340c746b25e57ccdb3427e
-rw-r--r-- | cmds/bootanimation/Android.mk | 4 | ||||
-rw-r--r-- | cmds/bootanimation/BootAnimation.cpp | 15 | ||||
-rw-r--r-- | cmds/bootanimation/audioplay.cpp | 152 | ||||
-rw-r--r-- | cmds/bootanimation/audioplay.h | 8 |
4 files changed, 111 insertions, 68 deletions
diff --git a/cmds/bootanimation/Android.mk b/cmds/bootanimation/Android.mk index 3cf13d908632..3a92b9e74144 100644 --- a/cmds/bootanimation/Android.mk +++ b/cmds/bootanimation/Android.mk @@ -36,8 +36,4 @@ ifdef TARGET_32_BIT_SURFACEFLINGER LOCAL_32_BIT_ONLY := true endif -# get asserts to work -APP_OPTIM := debug -LOCAL_CFLAGS += -UNDEBUG - include $(BUILD_EXECUTABLE) diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp index 4098772bba12..ebcc9ff0451f 100644 --- a/cmds/bootanimation/BootAnimation.cpp +++ b/cmds/bootanimation/BootAnimation.cpp @@ -588,7 +588,7 @@ bool BootAnimation::preloadZip(Animation& animation) return false; } - bool hasAudio = false; + Animation::Part* partWithAudio = NULL; ZipEntryRO entry; char name[ANIM_ENTRY_NAME_MAX]; while ((entry = zip->nextEntry(cookie)) != NULL) { @@ -612,10 +612,10 @@ bool BootAnimation::preloadZip(Animation& animation) if (map) { Animation::Part& part(animation.parts.editItemAt(j)); if (leaf == "audio.wav") { - hasAudio = true; // a part may have at most one audio file part.audioData = (uint8_t *)map->getDataPtr(); part.audioLength = map->getDataLength(); + partWithAudio = ∂ } else if (leaf == "trim.txt") { part.trimData.setTo((char const*)map->getDataPtr(), map->getDataLength()); @@ -666,9 +666,11 @@ bool BootAnimation::preloadZip(Animation& animation) } // Create and initialize audioplay if there is a wav file in any of the animations. - if (hasAudio) { + if (partWithAudio != NULL) { ALOGD("found audio.wav, creating playback engine"); - audioplay::create(); + if (!audioplay::create(partWithAudio->audioData, partWithAudio->audioLength)) { + return false; + } } zip->endIteration(cookie); @@ -904,7 +906,10 @@ BootAnimation::Animation* BootAnimation::loadAnimation(const String8& fn) mLoadedFiles.add(animation->fileName); parseAnimationDesc(*animation); - preloadZip(*animation); + if (!preloadZip(*animation)) { + return NULL; + } + mLoadedFiles.remove(fn); return animation; diff --git a/cmds/bootanimation/audioplay.cpp b/cmds/bootanimation/audioplay.cpp index e20ef0c7c6cc..8a5c2c6d229c 100644 --- a/cmds/bootanimation/audioplay.cpp +++ b/cmds/bootanimation/audioplay.cpp @@ -21,7 +21,6 @@ #define CHATTY ALOGD -#include <assert.h> #include <string.h> #include <utils/Log.h> @@ -80,8 +79,6 @@ struct ChunkFormat { void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context) { (void)bq; (void)context; - assert(bq == bqPlayerBufferQueue); - assert(NULL == context); audioplay::setPlaying(false); } @@ -90,39 +87,56 @@ bool hasPlayer() { } // create the engine and output mix objects -void createEngine() { +bool createEngine() { SLresult result; // create engine result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL); - assert(SL_RESULT_SUCCESS == result); + if (result != SL_RESULT_SUCCESS) { + ALOGE("slCreateEngine failed with result %d", result); + return false; + } (void)result; // realize the engine result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE); - assert(SL_RESULT_SUCCESS == result); + if (result != SL_RESULT_SUCCESS) { + ALOGE("sl engine Realize failed with result %d", result); + return false; + } (void)result; // get the engine interface, which is needed in order to create other objects result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine); - assert(SL_RESULT_SUCCESS == result); + if (result != SL_RESULT_SUCCESS) { + ALOGE("sl engine GetInterface failed with result %d", result); + return false; + } (void)result; // create output mix, with environmental reverb specified as a non-required interface const SLInterfaceID ids[1] = {SL_IID_ENVIRONMENTALREVERB}; const SLboolean req[1] = {SL_BOOLEAN_FALSE}; result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 1, ids, req); - assert(SL_RESULT_SUCCESS == result); + if (result != SL_RESULT_SUCCESS) { + ALOGE("sl engine CreateOutputMix failed with result %d", result); + return false; + } (void)result; // realize the output mix result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE); - assert(SL_RESULT_SUCCESS == result); + if (result != SL_RESULT_SUCCESS) { + ALOGE("sl outputMix Realize failed with result %d", result); + return false; + } (void)result; + + return true; } // create buffer queue audio player -void createBufferQueueAudioPlayer(const ChunkFormat* chunkFormat) { +bool createBufferQueueAudioPlayer(const ChunkFormat* chunkFormat) { SLresult result; // configure audio source @@ -148,83 +162,89 @@ void createBufferQueueAudioPlayer(const ChunkFormat* chunkFormat) { const SLboolean req[2] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE}; result = (*engineEngine)->CreateAudioPlayer(engineEngine, &bqPlayerObject, &audioSrc, &audioSnk, 2, ids, req); - assert(SL_RESULT_SUCCESS == result); + if (result != SL_RESULT_SUCCESS) { + ALOGE("sl CreateAudioPlayer failed with result %d", result); + return false; + } (void)result; // realize the player result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE); - assert(SL_RESULT_SUCCESS == result); + if (result != SL_RESULT_SUCCESS) { + ALOGE("sl player Realize failed with result %d", result); + return false; + } (void)result; // get the play interface result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay); - assert(SL_RESULT_SUCCESS == result); + if (result != SL_RESULT_SUCCESS) { + ALOGE("sl player GetInterface failed with result %d", result); + return false; + } (void)result; // get the buffer queue interface result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_BUFFERQUEUE, &bqPlayerBufferQueue); - assert(SL_RESULT_SUCCESS == result); + if (result != SL_RESULT_SUCCESS) { + ALOGE("sl playberBufferQueue GetInterface failed with result %d", result); + return false; + } (void)result; // register callback on the buffer queue result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, NULL); - assert(SL_RESULT_SUCCESS == result); - (void)result; - -#if 0 // mute/solo is not supported for sources that are known to be mono, as this is - // get the mute/solo interface - result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_MUTESOLO, &bqPlayerMuteSolo); - assert(SL_RESULT_SUCCESS == result); + if (result != SL_RESULT_SUCCESS) { + ALOGE("sl bqPlayerBufferQueue RegisterCallback failed with result %d", result); + return false; + } (void)result; -#endif // get the volume interface result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_VOLUME, &bqPlayerVolume); - assert(SL_RESULT_SUCCESS == result); + if (result != SL_RESULT_SUCCESS) { + ALOGE("sl volume GetInterface failed with result %d", result); + return false; + } (void)result; // set the player's state to playing audioplay::setPlaying(true); CHATTY("Created buffer queue player: %p", bqPlayerBufferQueue); + return true; } -} // namespace - -void create() { - createEngine(); -} - -bool playClip(const uint8_t* buf, int size) { - // Parse the WAV header - nextBuffer = buf; - nextSize = size; - const RiffWaveHeader* wavHeader = (const RiffWaveHeader*)buf; - if (nextSize < sizeof(*wavHeader) || (wavHeader->riff_id != ID_RIFF) || +bool parseClipBuf(const uint8_t* clipBuf, int clipBufSize, const ChunkFormat** oChunkFormat, + const uint8_t** oSoundBuf, unsigned* oSoundBufSize) { + *oSoundBuf = clipBuf; + *oSoundBufSize = clipBufSize; + *oChunkFormat = NULL; + const RiffWaveHeader* wavHeader = (const RiffWaveHeader*)*oSoundBuf; + if (*oSoundBufSize < sizeof(*wavHeader) || (wavHeader->riff_id != ID_RIFF) || (wavHeader->wave_id != ID_WAVE)) { ALOGE("Error: audio file is not a riff/wave file\n"); return false; } - nextBuffer += sizeof(*wavHeader); - nextSize -= sizeof(*wavHeader); + *oSoundBuf += sizeof(*wavHeader); + *oSoundBufSize -= sizeof(*wavHeader); - const ChunkFormat* chunkFormat = nullptr; while (true) { - const ChunkHeader* chunkHeader = (const ChunkHeader*)nextBuffer; - if (nextSize < sizeof(*chunkHeader)) { + const ChunkHeader* chunkHeader = (const ChunkHeader*)*oSoundBuf; + if (*oSoundBufSize < sizeof(*chunkHeader)) { ALOGE("EOF reading chunk headers"); return false; } - nextBuffer += sizeof(*chunkHeader); - nextSize -= sizeof(*chunkHeader); + *oSoundBuf += sizeof(*chunkHeader); + *oSoundBufSize -= sizeof(*chunkHeader); bool endLoop = false; switch (chunkHeader->id) { case ID_FMT: - chunkFormat = (const ChunkFormat*)nextBuffer; - nextBuffer += chunkHeader->sz; - nextSize -= chunkHeader->sz; + *oChunkFormat = (const ChunkFormat*)*oSoundBuf; + *oSoundBuf += chunkHeader->sz; + *oSoundBufSize -= chunkHeader->sz; break; case ID_DATA: /* Stop looking for chunks */ @@ -232,27 +252,49 @@ bool playClip(const uint8_t* buf, int size) { break; default: /* Unknown chunk, skip bytes */ - nextBuffer += chunkHeader->sz; - nextSize -= chunkHeader->sz; + *oSoundBuf += chunkHeader->sz; + *oSoundBufSize -= chunkHeader->sz; } if (endLoop) { break; } } - if (!chunkFormat) { + if (*oChunkFormat == NULL) { ALOGE("format not found in WAV file"); return false; } + return true; +} - // If this is the first clip, create the buffer based on this WAV's header. - // We assume all future clips with be in the same format. - if (bqPlayerBufferQueue == nullptr) { - createBufferQueueAudioPlayer(chunkFormat); +} // namespace + +bool create(const uint8_t* exampleClipBuf, int exampleClipBufSize) { + if (!createEngine()) { + return false; } - assert(bqPlayerBufferQueue != nullptr); - assert(buf != nullptr); + // Parse the example clip. + const ChunkFormat* chunkFormat; + const uint8_t* soundBuf; + unsigned soundBufSize; + if (!parseClipBuf(exampleClipBuf, exampleClipBufSize, &chunkFormat, &soundBuf, &soundBufSize)) { + return false; + } + + // Initialize the BufferQueue based on this clip's format. + if (!createBufferQueueAudioPlayer(chunkFormat)) { + return false; + } + return true; +} + +bool playClip(const uint8_t* buf, int size) { + // Parse the WAV header + const ChunkFormat* chunkFormat; + if (!parseClipBuf(buf, size, &chunkFormat, &nextBuffer, &nextSize)) { + return false; + } if (!hasPlayer()) { ALOGD("cannot play clip %p without a player", buf); @@ -285,8 +327,6 @@ void setPlaying(bool isPlaying) { // set the player's state result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, isPlaying ? SL_PLAYSTATE_PLAYING : SL_PLAYSTATE_STOPPED); - assert(SL_RESULT_SUCCESS == result); - (void)result; } } diff --git a/cmds/bootanimation/audioplay.h b/cmds/bootanimation/audioplay.h index bdc0a1c84b6e..0e5705af0ad0 100644 --- a/cmds/bootanimation/audioplay.h +++ b/cmds/bootanimation/audioplay.h @@ -22,10 +22,12 @@ namespace audioplay { -void create(); +// Initializes the engine with an example of the type of WAV clip to play. +// All buffers passed to playClip are assumed to be in the same format. +bool create(const uint8_t* exampleClipBuf, int exampleClipBufSize); -// Play a WAV pointed to by buf. All clips are assumed to be in the same format. -// playClip should not be called while a clip is still playing. +// Plays a WAV contained in buf. +// Should not be called while a clip is still playing. bool playClip(const uint8_t* buf, int size); void setPlaying(bool isPlaying); void destroy(); |