Home | History | Annotate | Download | only in bootanimation
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  *
     16  */
     17 
     18 // cribbed from samples/native-audio
     19 
     20 #define CHATTY ALOGD
     21 #define LOG_TAG "audioplay"
     22 
     23 #include "audioplay.h"
     24 
     25 #include <string.h>
     26 
     27 #include <utils/Log.h>
     28 #include <utils/threads.h>
     29 
     30 // for native audio
     31 #include <SLES/OpenSLES.h>
     32 #include <SLES/OpenSLES_Android.h>
     33 
     34 #include "BootAnimationUtil.h"
     35 
     36 namespace audioplay {
     37 namespace {
     38 
     39 using namespace android;
     40 
     41 // engine interfaces
     42 static SLObjectItf engineObject = nullptr;
     43 static SLEngineItf engineEngine;
     44 
     45 // output mix interfaces
     46 static SLObjectItf outputMixObject = nullptr;
     47 
     48 // buffer queue player interfaces
     49 static SLObjectItf bqPlayerObject = nullptr;
     50 static SLPlayItf bqPlayerPlay;
     51 static SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue;
     52 static SLMuteSoloItf bqPlayerMuteSolo;
     53 static SLVolumeItf bqPlayerVolume;
     54 
     55 // pointer and size of the next player buffer to enqueue, and number of remaining buffers
     56 static const uint8_t* nextBuffer;
     57 static unsigned nextSize;
     58 
     59 static const uint32_t ID_RIFF = 0x46464952;
     60 static const uint32_t ID_WAVE = 0x45564157;
     61 static const uint32_t ID_FMT  = 0x20746d66;
     62 static const uint32_t ID_DATA = 0x61746164;
     63 
     64 struct RiffWaveHeader {
     65     uint32_t riff_id;
     66     uint32_t riff_sz;
     67     uint32_t wave_id;
     68 };
     69 
     70 struct ChunkHeader {
     71     uint32_t id;
     72     uint32_t sz;
     73 };
     74 
     75 struct ChunkFormat {
     76     uint16_t audio_format;
     77     uint16_t num_channels;
     78     uint32_t sample_rate;
     79     uint32_t byte_rate;
     80     uint16_t block_align;
     81     uint16_t bits_per_sample;
     82 };
     83 
     84 // this callback handler is called every time a buffer finishes playing
     85 void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context) {
     86     (void)bq;
     87     (void)context;
     88     audioplay::setPlaying(false);
     89 }
     90 
     91 bool hasPlayer() {
     92     return (engineObject != nullptr && bqPlayerObject != nullptr);
     93 }
     94 
     95 // create the engine and output mix objects
     96 bool createEngine() {
     97     SLresult result;
     98 
     99     // create engine
    100     result = slCreateEngine(&engineObject, 0, nullptr, 0, nullptr, nullptr);
    101     if (result != SL_RESULT_SUCCESS) {
    102         ALOGE("slCreateEngine failed with result %d", result);
    103         return false;
    104     }
    105     (void)result;
    106 
    107     // realize the engine
    108     result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
    109     if (result != SL_RESULT_SUCCESS) {
    110         ALOGE("sl engine Realize failed with result %d", result);
    111         return false;
    112     }
    113     (void)result;
    114 
    115     // get the engine interface, which is needed in order to create other objects
    116     result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
    117     if (result != SL_RESULT_SUCCESS) {
    118         ALOGE("sl engine GetInterface failed with result %d", result);
    119         return false;
    120     }
    121     (void)result;
    122 
    123     // create output mix
    124     result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, nullptr, nullptr);
    125     if (result != SL_RESULT_SUCCESS) {
    126         ALOGE("sl engine CreateOutputMix failed with result %d", result);
    127         return false;
    128     }
    129     (void)result;
    130 
    131     // realize the output mix
    132     result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
    133     if (result != SL_RESULT_SUCCESS) {
    134         ALOGE("sl outputMix Realize failed with result %d", result);
    135         return false;
    136     }
    137     (void)result;
    138 
    139     return true;
    140 }
    141 
    142 // create buffer queue audio player
    143 bool createBufferQueueAudioPlayer(const ChunkFormat* chunkFormat) {
    144     SLresult result;
    145 
    146     // configure audio source
    147     SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 1};
    148 
    149     // Determine channelMask from num_channels
    150     SLuint32 channelMask;
    151     switch (chunkFormat->num_channels) {
    152         case 1:
    153             channelMask = SL_SPEAKER_FRONT_CENTER;
    154             break;
    155         case 2:
    156             channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
    157             break;
    158         default:
    159             // Default of 0 will derive mask from num_channels and log a warning.
    160             channelMask = 0;
    161     }
    162 
    163     SLDataFormat_PCM format_pcm = {
    164         SL_DATAFORMAT_PCM,
    165         chunkFormat->num_channels,
    166         chunkFormat->sample_rate * 1000,  // convert to milliHz
    167         chunkFormat->bits_per_sample,
    168         16,
    169         channelMask,
    170         SL_BYTEORDER_LITTLEENDIAN
    171     };
    172     SLDataSource audioSrc = {&loc_bufq, &format_pcm};
    173 
    174     // configure audio sink
    175     SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};
    176     SLDataSink audioSnk = {&loc_outmix, nullptr};
    177 
    178     // create audio player
    179     const SLInterfaceID ids[3] = {SL_IID_BUFFERQUEUE, SL_IID_VOLUME, SL_IID_ANDROIDCONFIGURATION};
    180     const SLboolean req[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
    181     result = (*engineEngine)->CreateAudioPlayer(engineEngine, &bqPlayerObject, &audioSrc, &audioSnk,
    182             3, ids, req);
    183     if (result != SL_RESULT_SUCCESS) {
    184         ALOGE("sl CreateAudioPlayer failed with result %d", result);
    185         return false;
    186     }
    187     (void)result;
    188 
    189     // Use the System stream for boot sound playback.
    190     SLAndroidConfigurationItf playerConfig;
    191     result = (*bqPlayerObject)->GetInterface(bqPlayerObject,
    192         SL_IID_ANDROIDCONFIGURATION, &playerConfig);
    193     if (result != SL_RESULT_SUCCESS) {
    194         ALOGE("config GetInterface failed with result %d", result);
    195         return false;
    196     }
    197     SLint32 streamType = SL_ANDROID_STREAM_SYSTEM;
    198     result = (*playerConfig)->SetConfiguration(playerConfig,
    199         SL_ANDROID_KEY_STREAM_TYPE, &streamType, sizeof(SLint32));
    200     if (result != SL_RESULT_SUCCESS) {
    201         ALOGE("SetConfiguration failed with result %d", result);
    202         return false;
    203     }
    204     // use normal performance mode as low latency is not needed. This is not mandatory so
    205     // do not bail if we fail
    206     SLuint32 performanceMode = SL_ANDROID_PERFORMANCE_NONE;
    207     result = (*playerConfig)->SetConfiguration(
    208            playerConfig, SL_ANDROID_KEY_PERFORMANCE_MODE, &performanceMode, sizeof(SLuint32));
    209     ALOGW_IF(result != SL_RESULT_SUCCESS,
    210             "could not set performance mode on player, error %d", result);
    211     (void)result;
    212 
    213     // realize the player
    214     result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE);
    215     if (result != SL_RESULT_SUCCESS) {
    216         ALOGE("sl player Realize failed with result %d", result);
    217         return false;
    218     }
    219     (void)result;
    220 
    221     // get the play interface
    222     result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay);
    223     if (result != SL_RESULT_SUCCESS) {
    224         ALOGE("sl player GetInterface failed with result %d", result);
    225         return false;
    226     }
    227     (void)result;
    228 
    229     // get the buffer queue interface
    230     result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_BUFFERQUEUE,
    231             &bqPlayerBufferQueue);
    232     if (result != SL_RESULT_SUCCESS) {
    233         ALOGE("sl playberBufferQueue GetInterface failed with result %d", result);
    234         return false;
    235     }
    236     (void)result;
    237 
    238     // register callback on the buffer queue
    239     result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, nullptr);
    240     if (result != SL_RESULT_SUCCESS) {
    241         ALOGE("sl bqPlayerBufferQueue RegisterCallback failed with result %d", result);
    242         return false;
    243     }
    244     (void)result;
    245 
    246     // get the volume interface
    247     result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_VOLUME, &bqPlayerVolume);
    248     if (result != SL_RESULT_SUCCESS) {
    249         ALOGE("sl volume GetInterface failed with result %d", result);
    250         return false;
    251     }
    252     (void)result;
    253 
    254     // set the player's state to playing
    255     audioplay::setPlaying(true);
    256     CHATTY("Created buffer queue player: %p", bqPlayerBufferQueue);
    257     return true;
    258 }
    259 
    260 bool parseClipBuf(const uint8_t* clipBuf, int clipBufSize, const ChunkFormat** oChunkFormat,
    261                   const uint8_t** oSoundBuf, unsigned* oSoundBufSize) {
    262     *oSoundBuf = clipBuf;
    263     *oSoundBufSize = clipBufSize;
    264     *oChunkFormat = nullptr;
    265     const RiffWaveHeader* wavHeader = (const RiffWaveHeader*)*oSoundBuf;
    266     if (*oSoundBufSize < sizeof(*wavHeader) || (wavHeader->riff_id != ID_RIFF) ||
    267         (wavHeader->wave_id != ID_WAVE)) {
    268         ALOGE("Error: audio file is not a riff/wave file\n");
    269         return false;
    270     }
    271     *oSoundBuf += sizeof(*wavHeader);
    272     *oSoundBufSize -= sizeof(*wavHeader);
    273 
    274     while (true) {
    275         const ChunkHeader* chunkHeader = (const ChunkHeader*)*oSoundBuf;
    276         if (*oSoundBufSize < sizeof(*chunkHeader)) {
    277             ALOGE("EOF reading chunk headers");
    278             return false;
    279         }
    280 
    281         *oSoundBuf += sizeof(*chunkHeader);
    282         *oSoundBufSize -= sizeof(*chunkHeader);
    283 
    284         bool endLoop = false;
    285         switch (chunkHeader->id) {
    286             case ID_FMT:
    287                 *oChunkFormat = (const ChunkFormat*)*oSoundBuf;
    288                 *oSoundBuf += chunkHeader->sz;
    289                 *oSoundBufSize -= chunkHeader->sz;
    290                 break;
    291             case ID_DATA:
    292                 /* Stop looking for chunks */
    293                 *oSoundBufSize = chunkHeader->sz;
    294                 endLoop = true;
    295                 break;
    296             default:
    297                 /* Unknown chunk, skip bytes */
    298                 *oSoundBuf += chunkHeader->sz;
    299                 *oSoundBufSize -= chunkHeader->sz;
    300         }
    301         if (endLoop) {
    302             break;
    303         }
    304     }
    305 
    306     if (*oChunkFormat == nullptr) {
    307         ALOGE("format not found in WAV file");
    308         return false;
    309     }
    310     return true;
    311 }
    312 
    313 class InitAudioThread : public Thread {
    314 public:
    315     InitAudioThread(uint8_t* exampleAudioData, int exampleAudioLength)
    316         : Thread(false),
    317           mExampleAudioData(exampleAudioData),
    318           mExampleAudioLength(exampleAudioLength) {}
    319 private:
    320     virtual bool threadLoop() {
    321         audioplay::create(mExampleAudioData, mExampleAudioLength);
    322         // Exit immediately
    323         return false;
    324     }
    325 
    326     uint8_t* mExampleAudioData;
    327     int mExampleAudioLength;
    328 };
    329 
    330 // Typedef to aid readability.
    331 typedef android::BootAnimation::Animation Animation;
    332 
    333 class AudioAnimationCallbacks : public android::BootAnimation::Callbacks {
    334 public:
    335     void init(const Vector<Animation::Part>& parts) override {
    336         const Animation::Part* partWithAudio = nullptr;
    337         for (const Animation::Part& part : parts) {
    338             if (part.audioData != nullptr) {
    339                 partWithAudio = &part;
    340                 break;
    341             }
    342         }
    343 
    344         if (partWithAudio == nullptr) {
    345             return;
    346         }
    347 
    348         ALOGD("found audio.wav, creating playback engine");
    349         // The audioData is used to initialize the audio system. Different data
    350         // can be played later for other parts BUT the assumption is that they
    351         // will all be the same format and only the format of this audioData
    352         // will work correctly.
    353         initAudioThread = new InitAudioThread(partWithAudio->audioData,
    354                 partWithAudio->audioLength);
    355         initAudioThread->run("BootAnimation::InitAudioThread", PRIORITY_NORMAL);
    356     };
    357 
    358     void playPart(int partNumber, const Animation::Part& part, int playNumber) override {
    359         // only play audio file the first time we animate the part
    360         if (playNumber == 0 && part.audioData && playSoundsAllowed()) {
    361             ALOGD("playing clip for part%d, size=%d",
    362                   partNumber, part.audioLength);
    363             // Block until the audio engine is finished initializing.
    364             if (initAudioThread != nullptr) {
    365                 initAudioThread->join();
    366             }
    367             audioplay::playClip(part.audioData, part.audioLength);
    368         }
    369     };
    370 
    371     void shutdown() override {
    372         // we've finally played everything we're going to play
    373         audioplay::setPlaying(false);
    374         audioplay::destroy();
    375     };
    376 
    377 private:
    378     sp<InitAudioThread> initAudioThread = nullptr;
    379 };
    380 
    381 } // namespace
    382 
    383 bool create(const uint8_t* exampleClipBuf, int exampleClipBufSize) {
    384     if (!createEngine()) {
    385         return false;
    386     }
    387 
    388     // Parse the example clip.
    389     const ChunkFormat* chunkFormat;
    390     const uint8_t* soundBuf;
    391     unsigned soundBufSize;
    392     if (!parseClipBuf(exampleClipBuf, exampleClipBufSize, &chunkFormat, &soundBuf, &soundBufSize)) {
    393         return false;
    394     }
    395 
    396     // Initialize the BufferQueue based on this clip's format.
    397     if (!createBufferQueueAudioPlayer(chunkFormat)) {
    398         return false;
    399     }
    400     return true;
    401 }
    402 
    403 bool playClip(const uint8_t* buf, int size) {
    404     // Parse the WAV header
    405     const ChunkFormat* chunkFormat;
    406     if (!parseClipBuf(buf, size, &chunkFormat, &nextBuffer, &nextSize)) {
    407         return false;
    408     }
    409 
    410     if (!hasPlayer()) {
    411         ALOGD("cannot play clip %p without a player", buf);
    412         return false;
    413     }
    414 
    415     CHATTY("playClip on player %p: buf=%p size=%d nextSize %d",
    416            bqPlayerBufferQueue, buf, size, nextSize);
    417 
    418     if (nextSize > 0) {
    419         // here we only enqueue one buffer because it is a long clip,
    420         // but for streaming playback we would typically enqueue at least 2 buffers to start
    421         SLresult result;
    422         result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, nextBuffer, nextSize);
    423         if (SL_RESULT_SUCCESS != result) {
    424             return false;
    425         }
    426         audioplay::setPlaying(true);
    427     }
    428 
    429     return true;
    430 }
    431 
    432 // set the playing state for the buffer queue audio player
    433 void setPlaying(bool isPlaying) {
    434     if (!hasPlayer()) return;
    435 
    436     SLresult result;
    437 
    438     if (nullptr != bqPlayerPlay) {
    439         // set the player's state
    440         result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay,
    441             isPlaying ? SL_PLAYSTATE_PLAYING : SL_PLAYSTATE_STOPPED);
    442     }
    443 
    444 }
    445 
    446 void destroy() {
    447     // destroy buffer queue audio player object, and invalidate all associated interfaces
    448     if (bqPlayerObject != nullptr) {
    449         CHATTY("destroying audio player");
    450         (*bqPlayerObject)->Destroy(bqPlayerObject);
    451         bqPlayerObject = nullptr;
    452         bqPlayerPlay = nullptr;
    453         bqPlayerBufferQueue = nullptr;
    454         bqPlayerMuteSolo = nullptr;
    455         bqPlayerVolume = nullptr;
    456     }
    457 
    458     // destroy output mix object, and invalidate all associated interfaces
    459     if (outputMixObject != nullptr) {
    460         (*outputMixObject)->Destroy(outputMixObject);
    461         outputMixObject = nullptr;
    462     }
    463 
    464     // destroy engine object, and invalidate all associated interfaces
    465     if (engineObject != nullptr) {
    466         CHATTY("destroying audio engine");
    467         (*engineObject)->Destroy(engineObject);
    468         engineObject = nullptr;
    469         engineEngine = nullptr;
    470     }
    471 }
    472 
    473 sp<BootAnimation::Callbacks> createAnimationCallbacks() {
    474   return new AudioAnimationCallbacks();
    475 }
    476 
    477 }  // namespace audioplay
    478