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

Commit 33f4b7d6 authored by Ed Coyne's avatar Ed Coyne
Browse files

Refactor audio code out of bootanimation_main.

So it can be shared with the iot/ variant I refactored it into the
audioplay.h file. This keeps all of the audio code local, we could hide
the functions and only expose the callback but that would make testing
harder.

Test: Ran a bootanimation.zip with audio.wav on Marlin, works as expected.
Bug: 67051984
Change-Id: Ie31dc5f2cfaad5bb23134ef81be712afa6b3cd6f
parent 3bb9562f
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@

#include <androidfw/AssetManager.h>
#include <utils/Thread.h>
#include <binder/IBinder.h>

#include <EGL/egl.h>
#include <GLES/gl.h>
+43 −0
Original line number Diff line number Diff line
@@ -16,14 +16,30 @@

#include "BootAnimationUtil.h"

#include <vector>
#include <inttypes.h>

#include <binder/IServiceManager.h>
#include <cutils/properties.h>
#include <utils/Log.h>
#include <utils/SystemClock.h>
#include <android-base/properties.h>

namespace android {
namespace {

static constexpr char PLAY_SOUND_PROP_NAME[] = "persist.sys.bootanim.play_sound";
static constexpr char BOOT_COMPLETED_PROP_NAME[] = "sys.boot_completed";
static constexpr char POWER_CTL_PROP_NAME[] = "sys.powerctl";
static constexpr char BOOTREASON_PROP_NAME[] = "ro.boot.bootreason";
static const std::vector<std::string> PLAY_SOUND_BOOTREASON_BLACKLIST {
  "kernel_panic",
  "Panic",
  "Watchdog",
};

}  // namespace


bool bootAnimationDisabled() {
    char value[PROPERTY_VALUE_MAX];
@@ -58,4 +74,31 @@ void waitForSurfaceFlinger() {
    }
}

bool playSoundsAllowed() {
    // Only play sounds for system boots, not runtime restarts.
    if (android::base::GetBoolProperty(BOOT_COMPLETED_PROP_NAME, false)) {
        return false;
    }
    // no audio while shutting down
    if (!android::base::GetProperty(POWER_CTL_PROP_NAME, "").empty()) {
        return false;
    }
    // Read the system property to see if we should play the sound.
    // If it's not present, default to allowed.
    if (!property_get_bool(PLAY_SOUND_PROP_NAME, 1)) {
        return false;
    }

    // Don't play sounds if this is a reboot due to an error.
    char bootreason[PROPERTY_VALUE_MAX];
    if (property_get(BOOTREASON_PROP_NAME, bootreason, nullptr) > 0) {
        for (const auto& str : PLAY_SOUND_BOOTREASON_BLACKLIST) {
            if (strcasecmp(str.c_str(), bootreason) == 0) {
                return false;
            }
        }
    }
    return true;
}

}  // namespace android
+7 −0
Original line number Diff line number Diff line
@@ -14,6 +14,9 @@
 * limitations under the License.
 */

#ifndef ANDROID_BOOTANIMATION_UTIL_H
#define ANDROID_BOOTANIMATION_UTIL_H

namespace android {

// Returns true if boot animation is disabled.
@@ -22,4 +25,8 @@ bool bootAnimationDisabled();
// Waits until the surface flinger is up.
void waitForSurfaceFlinger();

// Returns whether sounds should be played during current boot.
bool playSoundsAllowed();
}  // namespace android

#endif  // ANDROID_BOOTANIMATION_UTIL_H
+79 −2
Original line number Diff line number Diff line
@@ -17,22 +17,27 @@

// cribbed from samples/native-audio

#include "audioplay.h"

#define CHATTY ALOGD
#define LOG_TAG "audioplay"

#include "audioplay.h"

#include <string.h>

#include <utils/Log.h>
#include <utils/threads.h>

// for native audio
#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>

#include "BootAnimationUtil.h"

namespace audioplay {
namespace {

using namespace android;

// engine interfaces
static SLObjectItf engineObject = NULL;
static SLEngineItf engineEngine;
@@ -305,6 +310,74 @@ bool parseClipBuf(const uint8_t* clipBuf, int clipBufSize, const ChunkFormat** o
    return true;
}

class InitAudioThread : public Thread {
public:
    InitAudioThread(uint8_t* exampleAudioData, int exampleAudioLength)
        : Thread(false),
          mExampleAudioData(exampleAudioData),
          mExampleAudioLength(exampleAudioLength) {}
private:
    virtual bool threadLoop() {
        audioplay::create(mExampleAudioData, mExampleAudioLength);
        // Exit immediately
        return false;
    }

    uint8_t* mExampleAudioData;
    int mExampleAudioLength;
};

// Typedef to aid readability.
typedef android::BootAnimation::Animation Animation;

class AudioAnimationCallbacks : public android::BootAnimation::Callbacks {
public:
    void init(const Vector<Animation::Part>& parts) override {
        const Animation::Part* partWithAudio = nullptr;
        for (const Animation::Part& part : parts) {
            if (part.audioData != nullptr) {
                partWithAudio = &part;
                break;
            }
        }

        if (partWithAudio == nullptr) {
            return;
        }

        ALOGD("found audio.wav, creating playback engine");
        // The audioData is used to initialize the audio system. Different data
        // can be played later for other parts BUT the assumption is that they
        // will all be the same format and only the format of this audioData
        // will work correctly.
        initAudioThread = new InitAudioThread(partWithAudio->audioData,
                partWithAudio->audioLength);
        initAudioThread->run("BootAnimation::InitAudioThread", PRIORITY_NORMAL);
    };

    void playPart(int partNumber, const Animation::Part& part, int playNumber) override {
        // only play audio file the first time we animate the part
        if (playNumber == 0 && part.audioData && playSoundsAllowed()) {
            ALOGD("playing clip for part%d, size=%d",
                  partNumber, part.audioLength);
            // Block until the audio engine is finished initializing.
            if (initAudioThread != nullptr) {
                initAudioThread->join();
            }
            audioplay::playClip(part.audioData, part.audioLength);
        }
    };

    void shutdown() override {
        // we've finally played everything we're going to play
        audioplay::setPlaying(false);
        audioplay::destroy();
    };

private:
    sp<InitAudioThread> initAudioThread = nullptr;
};

} // namespace

bool create(const uint8_t* exampleClipBuf, int exampleClipBufSize) {
@@ -397,4 +470,8 @@ void destroy() {
    }
}

sp<BootAnimation::Callbacks> createAnimationCallbacks() {
  return new AudioAnimationCallbacks();
}

}  // namespace audioplay
+5 −0
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@

#include <string.h>

#include "BootAnimation.h"

namespace audioplay {

// Initializes the engine with an example of the type of WAV clip to play.
@@ -32,6 +34,9 @@ bool playClip(const uint8_t* buf, int size);
void setPlaying(bool isPlaying);
void destroy();

// Generates callbacks to integrate the audioplay system with the BootAnimation.
android::sp<android::BootAnimation::Callbacks> createAnimationCallbacks();

}

#endif // AUDIOPLAY_H_
Loading