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
|
LOCAL_32_BIT_ONLY := true
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# get asserts to work
|
|
||||||
APP_OPTIM := debug
|
|
||||||
LOCAL_CFLAGS += -UNDEBUG
|
|
||||||
|
|
||||||
include $(BUILD_EXECUTABLE)
|
include $(BUILD_EXECUTABLE)
|
||||||
|
@ -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;
|
||||||
|
@ -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) {
|
||||||
|
ALOGE("sl bqPlayerBufferQueue RegisterCallback failed with result %d", result);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
(void)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);
|
|
||||||
(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;
|
||||||
|
}
|
||||||
|
|
||||||
// If this is the first clip, create the buffer based on this WAV's header.
|
} // namespace
|
||||||
// We assume all future clips with be in the same format.
|
|
||||||
if (bqPlayerBufferQueue == nullptr) {
|
bool create(const uint8_t* exampleClipBuf, int exampleClipBufSize) {
|
||||||
createBufferQueueAudioPlayer(chunkFormat);
|
if (!createEngine()) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
Reference in New Issue
Block a user