Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a91a2d73 authored by Geoffrey Pitsch's avatar Geoffrey Pitsch
Browse files

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
parent f6d76602
Loading
Loading
Loading
Loading
+0 −4
Original line number Original line Diff line number Diff line
@@ -36,8 +36,4 @@ ifdef TARGET_32_BIT_SURFACEFLINGER
LOCAL_32_BIT_ONLY := true
LOCAL_32_BIT_ONLY := true
endif
endif


# get asserts to work
APP_OPTIM := debug
LOCAL_CFLAGS += -UNDEBUG

include $(BUILD_EXECUTABLE)
include $(BUILD_EXECUTABLE)
+10 −5
Original line number Original line Diff line number Diff line
@@ -588,7 +588,7 @@ bool BootAnimation::preloadZip(Animation& animation)
        return false;
        return false;
    }
    }


    bool hasAudio = false;
    Animation::Part* partWithAudio = NULL;
    ZipEntryRO entry;
    ZipEntryRO entry;
    char name[ANIM_ENTRY_NAME_MAX];
    char name[ANIM_ENTRY_NAME_MAX];
    while ((entry = zip->nextEntry(cookie)) != NULL) {
    while ((entry = zip->nextEntry(cookie)) != NULL) {
@@ -612,10 +612,10 @@ bool BootAnimation::preloadZip(Animation& animation)
                            if (map) {
                            if (map) {
                                Animation::Part& part(animation.parts.editItemAt(j));
                                Animation::Part& part(animation.parts.editItemAt(j));
                                if (leaf == "audio.wav") {
                                if (leaf == "audio.wav") {
                                    hasAudio = true;
                                    // a part may have at most one audio file
                                    // a part may have at most one audio file
                                    part.audioData = (uint8_t *)map->getDataPtr();
                                    part.audioData = (uint8_t *)map->getDataPtr();
                                    part.audioLength = map->getDataLength();
                                    part.audioLength = map->getDataLength();
                                    partWithAudio = ∂
                                } else if (leaf == "trim.txt") {
                                } else if (leaf == "trim.txt") {
                                    part.trimData.setTo((char const*)map->getDataPtr(),
                                    part.trimData.setTo((char const*)map->getDataPtr(),
                                                        map->getDataLength());
                                                        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.
    // 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");
        ALOGD("found audio.wav, creating playback engine");
        audioplay::create();
        if (!audioplay::create(partWithAudio->audioData, partWithAudio->audioLength)) {
            return false;
        }
    }
    }


    zip->endIteration(cookie);
    zip->endIteration(cookie);
@@ -904,7 +906,10 @@ BootAnimation::Animation* BootAnimation::loadAnimation(const String8& fn)
    mLoadedFiles.add(animation->fileName);
    mLoadedFiles.add(animation->fileName);


    parseAnimationDesc(*animation);
    parseAnimationDesc(*animation);
    preloadZip(*animation);
    if (!preloadZip(*animation)) {
        return NULL;
    }



    mLoadedFiles.remove(fn);
    mLoadedFiles.remove(fn);
    return animation;
    return animation;
+96 −56
Original line number Original line Diff line number Diff line
@@ -21,7 +21,6 @@


#define CHATTY ALOGD
#define CHATTY ALOGD


#include <assert.h>
#include <string.h>
#include <string.h>


#include <utils/Log.h>
#include <utils/Log.h>
@@ -80,8 +79,6 @@ struct ChunkFormat {
void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context) {
void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context) {
    (void)bq;
    (void)bq;
    (void)context;
    (void)context;
    assert(bq == bqPlayerBufferQueue);
    assert(NULL == context);
    audioplay::setPlaying(false);
    audioplay::setPlaying(false);
}
}


@@ -90,39 +87,56 @@ bool hasPlayer() {
}
}


// create the engine and output mix objects
// create the engine and output mix objects
void createEngine() {
bool createEngine() {
    SLresult result;
    SLresult result;


    // create engine
    // create engine
    result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
    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;
    (void)result;


    // realize the engine
    // realize the engine
    result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
    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;
    (void)result;


    // get the engine interface, which is needed in order to create other objects
    // get the engine interface, which is needed in order to create other objects
    result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
    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;
    (void)result;


    // create output mix, with environmental reverb specified as a non-required interface
    // create output mix, with environmental reverb specified as a non-required interface
    const SLInterfaceID ids[1] = {SL_IID_ENVIRONMENTALREVERB};
    const SLInterfaceID ids[1] = {SL_IID_ENVIRONMENTALREVERB};
    const SLboolean req[1] = {SL_BOOLEAN_FALSE};
    const SLboolean req[1] = {SL_BOOLEAN_FALSE};
    result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 1, ids, req);
    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;
    (void)result;


    // realize the output mix
    // realize the output mix
    result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
    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;
    (void)result;

    return true;
}
}


// create buffer queue audio player
// create buffer queue audio player
void createBufferQueueAudioPlayer(const ChunkFormat* chunkFormat) {
bool createBufferQueueAudioPlayer(const ChunkFormat* chunkFormat) {
    SLresult result;
    SLresult result;


    // configure audio source
    // configure audio source
@@ -148,83 +162,89 @@ void createBufferQueueAudioPlayer(const ChunkFormat* chunkFormat) {
    const SLboolean req[2] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
    const SLboolean req[2] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
    result = (*engineEngine)->CreateAudioPlayer(engineEngine, &bqPlayerObject, &audioSrc, &audioSnk,
    result = (*engineEngine)->CreateAudioPlayer(engineEngine, &bqPlayerObject, &audioSrc, &audioSnk,
            2, ids, req);
            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;
    (void)result;


    // realize the player
    // realize the player
    result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE);
    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;
    (void)result;


    // get the play interface
    // get the play interface
    result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay);
    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;
    (void)result;


    // get the buffer queue interface
    // get the buffer queue interface
    result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_BUFFERQUEUE,
    result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_BUFFERQUEUE,
            &bqPlayerBufferQueue);
            &bqPlayerBufferQueue);
    assert(SL_RESULT_SUCCESS == result);
    if (result != SL_RESULT_SUCCESS) {
        ALOGE("sl playberBufferQueue GetInterface failed with result %d", result);
        return false;
    }
    (void)result;
    (void)result;


    // register callback on the buffer queue
    // register callback on the buffer queue
    result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, NULL);
    result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, NULL);
    assert(SL_RESULT_SUCCESS == result);
    if (result != SL_RESULT_SUCCESS) {
    (void)result;
        ALOGE("sl bqPlayerBufferQueue RegisterCallback failed with result %d", result);

        return false;
#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;
    (void)result;
#endif


    // get the volume interface
    // get the volume interface
    result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_VOLUME, &bqPlayerVolume);
    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;
    (void)result;


    // set the player's state to playing
    // set the player's state to playing
    audioplay::setPlaying(true);
    audioplay::setPlaying(true);
    CHATTY("Created buffer queue player: %p", bqPlayerBufferQueue);
    CHATTY("Created buffer queue player: %p", bqPlayerBufferQueue);
    return true;
}
}


} // namespace
bool parseClipBuf(const uint8_t* clipBuf, int clipBufSize, const ChunkFormat** oChunkFormat,

                  const uint8_t** oSoundBuf, unsigned* oSoundBufSize) {
void create() {
    *oSoundBuf = clipBuf;
    createEngine();
    *oSoundBufSize = clipBufSize;
}
    *oChunkFormat = NULL;

    const RiffWaveHeader* wavHeader = (const RiffWaveHeader*)*oSoundBuf;
bool playClip(const uint8_t* buf, int size) {
    if (*oSoundBufSize < sizeof(*wavHeader) || (wavHeader->riff_id != ID_RIFF) ||
    // Parse the WAV header
    nextBuffer = buf;
    nextSize = size;
    const RiffWaveHeader* wavHeader = (const RiffWaveHeader*)buf;
    if (nextSize < sizeof(*wavHeader) || (wavHeader->riff_id != ID_RIFF) ||
        (wavHeader->wave_id != ID_WAVE)) {
        (wavHeader->wave_id != ID_WAVE)) {
        ALOGE("Error: audio file is not a riff/wave file\n");
        ALOGE("Error: audio file is not a riff/wave file\n");
        return false;
        return false;
    }
    }
    nextBuffer += sizeof(*wavHeader);
    *oSoundBuf += sizeof(*wavHeader);
    nextSize -= sizeof(*wavHeader);
    *oSoundBufSize -= sizeof(*wavHeader);


    const ChunkFormat* chunkFormat = nullptr;
    while (true) {
    while (true) {
        const ChunkHeader* chunkHeader = (const ChunkHeader*)nextBuffer;
        const ChunkHeader* chunkHeader = (const ChunkHeader*)*oSoundBuf;
        if (nextSize < sizeof(*chunkHeader)) {
        if (*oSoundBufSize < sizeof(*chunkHeader)) {
            ALOGE("EOF reading chunk headers");
            ALOGE("EOF reading chunk headers");
            return false;
            return false;
        }
        }


        nextBuffer += sizeof(*chunkHeader);
        *oSoundBuf += sizeof(*chunkHeader);
        nextSize -= sizeof(*chunkHeader);
        *oSoundBufSize -= sizeof(*chunkHeader);


        bool endLoop = false;
        bool endLoop = false;
        switch (chunkHeader->id) {
        switch (chunkHeader->id) {
            case ID_FMT:
            case ID_FMT:
                chunkFormat = (const ChunkFormat*)nextBuffer;
                *oChunkFormat = (const ChunkFormat*)*oSoundBuf;
                nextBuffer += chunkHeader->sz;
                *oSoundBuf += chunkHeader->sz;
                nextSize -= chunkHeader->sz;
                *oSoundBufSize -= chunkHeader->sz;
                break;
                break;
            case ID_DATA:
            case ID_DATA:
                /* Stop looking for chunks */
                /* Stop looking for chunks */
@@ -232,27 +252,49 @@ bool playClip(const uint8_t* buf, int size) {
                break;
                break;
            default:
            default:
                /* Unknown chunk, skip bytes */
                /* Unknown chunk, skip bytes */
                nextBuffer += chunkHeader->sz;
                *oSoundBuf += chunkHeader->sz;
                nextSize -= chunkHeader->sz;
                *oSoundBufSize -= chunkHeader->sz;
        }
        }
        if (endLoop) {
        if (endLoop) {
            break;
            break;
        }
        }
    }
    }


    if (!chunkFormat) {
    if (*oChunkFormat == NULL) {
        ALOGE("format not found in WAV file");
        ALOGE("format not found in WAV file");
        return false;
        return false;
    }
    }
    return true;
}

} // namespace


    // If this is the first clip, create the buffer based on this WAV's header.
bool create(const uint8_t* exampleClipBuf, int exampleClipBufSize) {
    // We assume all future clips with be in the same format.
    if (!createEngine()) {
    if (bqPlayerBufferQueue == nullptr) {
        return false;
        createBufferQueueAudioPlayer(chunkFormat);
    }
    }


    assert(bqPlayerBufferQueue != nullptr);
    // Parse the example clip.
    assert(buf != nullptr);
    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()) {
    if (!hasPlayer()) {
        ALOGD("cannot play clip %p without a player", buf);
        ALOGD("cannot play clip %p without a player", buf);
@@ -285,8 +327,6 @@ void setPlaying(bool isPlaying) {
        // set the player's state
        // set the player's state
        result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay,
        result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay,
            isPlaying ? SL_PLAYSTATE_PLAYING : SL_PLAYSTATE_STOPPED);
            isPlaying ? SL_PLAYSTATE_PLAYING : SL_PLAYSTATE_STOPPED);
        assert(SL_RESULT_SUCCESS == result);
        (void)result;
    }
    }


}
}
+5 −3
Original line number Original line Diff line number Diff line
@@ -22,10 +22,12 @@


namespace audioplay {
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.
// Plays a WAV contained in buf.
// playClip should not be called while a clip is still playing.
// Should not be called while a clip is still playing.
bool playClip(const uint8_t* buf, int size);
bool playClip(const uint8_t* buf, int size);
void setPlaying(bool isPlaying);
void setPlaying(bool isPlaying);
void destroy();
void destroy();