Merge "Fixes delay when playing first sound in BootAnimation" into nyc-mr1-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
ebfa6df9a0
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
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 @@ 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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();
|
||||
|
Reference in New Issue
Block a user