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
diff --git a/cmds/bootanimation/Android.mk b/cmds/bootanimation/Android.mk
index 3cf13d9..3a92b9e 100644
--- a/cmds/bootanimation/Android.mk
+++ b/cmds/bootanimation/Android.mk
@@ -36,8 +36,4 @@
 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 4098772..ebcc9ff 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -588,7 +588,7 @@
         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 @@
                             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 @@
     }
 
     // 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 @@
     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 e20ef0c..8a5c2c6 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 @@
 void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context) {
     (void)bq;
     (void)context;
-    assert(bq == bqPlayerBufferQueue);
-    assert(NULL == context);
     audioplay::setPlaying(false);
 }
 
@@ -90,39 +87,56 @@
 }
 
 // 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 @@
     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);
+    if (result != SL_RESULT_SUCCESS) {
+        ALOGE("sl bqPlayerBufferQueue RegisterCallback failed with result %d", result);
+        return false;
+    }
     (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);
-    (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 @@
                 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 @@
         // 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 bdc0a1c..0e5705a 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();