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
diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h
index 56e131523..dffbfde 100644
--- a/cmds/bootanimation/BootAnimation.h
+++ b/cmds/bootanimation/BootAnimation.h
@@ -22,6 +22,7 @@
#include <androidfw/AssetManager.h>
#include <utils/Thread.h>
+#include <binder/IBinder.h>
#include <EGL/egl.h>
#include <GLES/gl.h>
diff --git a/cmds/bootanimation/BootAnimationUtil.cpp b/cmds/bootanimation/BootAnimationUtil.cpp
index 7718daf..1e417e9 100644
--- a/cmds/bootanimation/BootAnimationUtil.cpp
+++ b/cmds/bootanimation/BootAnimationUtil.cpp
@@ -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 @@
}
}
+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
diff --git a/cmds/bootanimation/BootAnimationUtil.h b/cmds/bootanimation/BootAnimationUtil.h
index 60987cd1..1e1140a 100644
--- a/cmds/bootanimation/BootAnimationUtil.h
+++ b/cmds/bootanimation/BootAnimationUtil.h
@@ -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 @@
// 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
diff --git a/cmds/bootanimation/audioplay.cpp b/cmds/bootanimation/audioplay.cpp
index c546072..874aab0 100644
--- a/cmds/bootanimation/audioplay.cpp
+++ b/cmds/bootanimation/audioplay.cpp
@@ -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 @@
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 = ∂
+ 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 @@
}
}
+sp<BootAnimation::Callbacks> createAnimationCallbacks() {
+ return new AudioAnimationCallbacks();
+}
+
} // namespace audioplay
diff --git a/cmds/bootanimation/audioplay.h b/cmds/bootanimation/audioplay.h
index 0e5705af..4704a70 100644
--- a/cmds/bootanimation/audioplay.h
+++ b/cmds/bootanimation/audioplay.h
@@ -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 @@
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_
diff --git a/cmds/bootanimation/bootanimation_main.cpp b/cmds/bootanimation/bootanimation_main.cpp
index 8501982..a52a5e9 100644
--- a/cmds/bootanimation/bootanimation_main.cpp
+++ b/cmds/bootanimation/bootanimation_main.cpp
@@ -26,8 +26,6 @@
#include <sys/resource.h>
#include <utils/Log.h>
#include <utils/SystemClock.h>
-#include <utils/threads.h>
-#include <android-base/properties.h>
#include "BootAnimation.h"
#include "BootAnimationUtil.h"
@@ -35,113 +33,6 @@
using namespace android;
-// ---------------------------------------------------------------------------
-
-namespace {
-
-// Create a typedef for readability.
-typedef android::BootAnimation::Animation Animation;
-
-static const char PLAY_SOUND_PROP_NAME[] = "persist.sys.bootanim.play_sound";
-static const char BOOT_COMPLETED_PROP_NAME[] = "sys.boot_completed";
-static const char POWER_CTL_PROP_NAME[] = "sys.powerctl";
-static const char BOOTREASON_PROP_NAME[] = "ro.boot.bootreason";
-static const std::vector<std::string> PLAY_SOUND_BOOTREASON_BLACKLIST {
- "kernel_panic",
- "Panic",
- "Watchdog",
-};
-
-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;
-};
-
-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;
-}
-
-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 = ∂
- }
- }
-
- if (partWithAudio == nullptr) {
- return;
- }
-
- ALOGD("found audio.wav, creating playback engine");
- 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
-
-
int main()
{
setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_DISPLAY);
@@ -156,7 +47,7 @@
waitForSurfaceFlinger();
// create the boot animation object
- sp<BootAnimation> boot = new BootAnimation(new AudioAnimationCallbacks());
+ sp<BootAnimation> boot = new BootAnimation(audioplay::createAnimationCallbacks());
ALOGV("Boot animation set up. Joining pool.");
IPCThreadState::self()->joinThreadPool();