You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
379 lines
11 KiB
379 lines
11 KiB
4 months ago
|
/*
|
||
|
* Copyright (c) Hisilicon Technologies Co., Ltd.. 2016-2019. All rights reserved.
|
||
|
* Description: bootvideo manager
|
||
|
*/
|
||
|
|
||
|
#include "BootvideoManager.h"
|
||
|
#include <android-base/properties.h>
|
||
|
#include <utils/SystemClock.h>
|
||
|
#include <cutils/klog.h>
|
||
|
#include <cutils/properties.h>
|
||
|
|
||
|
#include "BootvideoInput.h"
|
||
|
#include "BootvideoApi.h"
|
||
|
#include "BootvideoConfiger.h"
|
||
|
#include "BootvideoDftevent.h"
|
||
|
#undef LOG_TAG
|
||
|
#define LOG_TAG "BootVideo"
|
||
|
|
||
|
namespace android {
|
||
|
using std::string;
|
||
|
using android::sp;
|
||
|
using std::make_unique;
|
||
|
|
||
|
string g_pathOne = "";
|
||
|
string g_pathApi = "";
|
||
|
sp<BootvideoUI> g_bootVideoUi = nullptr;
|
||
|
sp<BootvideoPlayer> g_bootVideoPlayer = nullptr;
|
||
|
|
||
|
namespace {
|
||
|
const short PLAYER_VOLUME_MAX = 30; // player init volume max
|
||
|
const short PLAYER_VOLUME_MIN = 10; // player init volume min
|
||
|
const short CONVERT_SEC_TO_MS = 1000; // unit convert: sec to ms
|
||
|
const short CONVERT_MS_TO_US = 1000; // unit convert: ms to us
|
||
|
const short DELAY_100_MS = 100; // delay is 100ms
|
||
|
const short PLAY_TIMER_INTERVAL = 10; // player timer, Once every 10 ms count
|
||
|
const short WAIT_UI_READY_COUNT = 10; // wait UI ready max count(10ms per count)
|
||
|
int g_totalPlayCounter = 0; // total play count, reference PLAY_TIMER_INTERVAL
|
||
|
int g_countTime = -1; // count down unit(s)
|
||
|
bool g_blFirst = true;
|
||
|
}
|
||
|
|
||
|
// signal handler of palyer timer, PLAY_TIMER_INTERVAL ms call
|
||
|
// 50ms once draw count time of ui
|
||
|
static void SignalHandler(int param)
|
||
|
{
|
||
|
(void)param;
|
||
|
g_totalPlayCounter++;
|
||
|
// first draw count time
|
||
|
if (g_blFirst && (g_countTime >= 0)) {
|
||
|
if (g_bootVideoUi != nullptr) {
|
||
|
g_bootVideoUi->SetCountdownTime(g_countTime--);
|
||
|
}
|
||
|
g_blFirst = false;
|
||
|
}
|
||
|
// calculate the count time
|
||
|
int counterSec = CONVERT_SEC_TO_MS / PLAY_TIMER_INTERVAL; // every 1s count
|
||
|
if ((g_totalPlayCounter % counterSec == 0) && (g_countTime >= 0)) {
|
||
|
if (g_bootVideoUi != nullptr) {
|
||
|
g_bootVideoUi->SetCountdownTime(g_countTime--);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// limitMs unit is ms
|
||
|
bool CheckIfTimeOut(int limitMs)
|
||
|
{
|
||
|
// check player count
|
||
|
int maxCounter = limitMs / PLAY_TIMER_INTERVAL;
|
||
|
if (g_totalPlayCounter >= maxCounter) {
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
int GetPlayTimeInfo()
|
||
|
{
|
||
|
if (g_bootVideoPlayer == nullptr) {
|
||
|
ALOGE("GetPlayTimeInfo: bootVideo Player is NULL");
|
||
|
return -1;
|
||
|
}
|
||
|
int playedMs, totalMs;
|
||
|
if (g_bootVideoPlayer->GetPlayTimeInfo(playedMs, totalMs)) {
|
||
|
return totalMs - playedMs;
|
||
|
} else {
|
||
|
ALOGE("GetPlayTimeInfo: bootVideo Player get play time info failure");
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool SetDrawTime(int limitMs)
|
||
|
{
|
||
|
int playedMs, totalMs;
|
||
|
if (g_bootVideoPlayer == nullptr) {
|
||
|
ALOGE("SetDrawTime: bootVideo Player is NULL");
|
||
|
return false;
|
||
|
}
|
||
|
if (g_bootVideoPlayer->GetPlayTimeInfo(playedMs, totalMs)) {
|
||
|
int remainMs = totalMs - playedMs; // player countdown
|
||
|
int leftMs = limitMs - playedMs; // actually countdown
|
||
|
if (remainMs < leftMs) {
|
||
|
g_countTime = remainMs / CONVERT_SEC_TO_MS;
|
||
|
} else {
|
||
|
g_countTime = leftMs / CONVERT_SEC_TO_MS;
|
||
|
}
|
||
|
ALOGI("SetDrawTime: Total count time is %d.", g_countTime);
|
||
|
return true;
|
||
|
} else {
|
||
|
ALOGE("SetDrawTime: bootVideo Player get play time info failure");
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void ManagerSetTimer()
|
||
|
{
|
||
|
// Calculation of seconds
|
||
|
const long sec = 0;
|
||
|
// Calculation of microseconds
|
||
|
const long us = (PLAY_TIMER_INTERVAL % CONVERT_SEC_TO_MS) * CONVERT_SEC_TO_MS;
|
||
|
|
||
|
struct itimerval itv;
|
||
|
itv.it_value.tv_sec = sec;
|
||
|
itv.it_value.tv_usec = us;
|
||
|
itv.it_interval.tv_sec = sec;
|
||
|
itv.it_interval.tv_usec = us;
|
||
|
// warning: don't change the timer type
|
||
|
setitimer(ITIMER_REAL, &itv, nullptr);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// SUPPORT_LIB_BOOTVIDEO is true
|
||
|
void BootvideoSetPath(string path)
|
||
|
{
|
||
|
// if you are using the API, you must call this function to set path
|
||
|
// else you must not call this function and the path of config.xml
|
||
|
g_pathApi = path;
|
||
|
}
|
||
|
|
||
|
int BootvideoInitVolume()
|
||
|
{
|
||
|
int initVolume = 0;
|
||
|
char propVloume[PROPERTY_VALUE_MAX] = {0};
|
||
|
// get init volume
|
||
|
if (property_get("persist.service.bootvideo.volume", propVloume, nullptr)) {
|
||
|
initVolume = atoi(propVloume);
|
||
|
ALOGD("volume property is %s, init bootvideo volume is %d", propVloume, initVolume);
|
||
|
} else {
|
||
|
ALOGE("volume property get failure");
|
||
|
}
|
||
|
// cancel the mute state
|
||
|
property_set("persist.service.bootvideo.mute", "0");
|
||
|
// check init volume
|
||
|
if (initVolume > PLAYER_VOLUME_MAX) {
|
||
|
initVolume = PLAYER_VOLUME_MAX;
|
||
|
}
|
||
|
if (initVolume < PLAYER_VOLUME_MIN) {
|
||
|
initVolume = PLAYER_VOLUME_MIN;
|
||
|
}
|
||
|
return initVolume;
|
||
|
}
|
||
|
bool IsBootComplete()
|
||
|
{
|
||
|
char proVal[PROPERTY_VALUE_MAX] = {0};
|
||
|
// property is boot complete , default is 0
|
||
|
if (!property_get(SYS_BOOTCOMPLETE.c_str(), proVal, nullptr)) {
|
||
|
return false;
|
||
|
}
|
||
|
if (proVal[0] == '1') {
|
||
|
return true;
|
||
|
} else {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool IsSTRPlay()
|
||
|
{
|
||
|
char strprop[PROPERTY_VALUE_MAX] = {0};
|
||
|
char bootop[PROPERTY_VALUE_MAX] = {0};
|
||
|
if (!property_get("sys.str.enable", strprop, nullptr)) {
|
||
|
return false;
|
||
|
}
|
||
|
if (!property_get("persist.service.strbootop.type", bootop, nullptr)) {
|
||
|
ALOGE("failed to get prop strbootop");
|
||
|
return false;
|
||
|
}
|
||
|
if ((!strncmp(strprop, "true", strlen("true"))) && (!strncmp(bootop, "bootvideo", strlen("bootvideo")))) {
|
||
|
ALOGD("str bootvideo enable");
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
// start bootanim when bootvideo play failed
|
||
|
bool BootvideoFailProc()
|
||
|
{
|
||
|
if (!IsSTRPlay()) {
|
||
|
ALOGE("property_set bootanim");
|
||
|
property_set("service.bootop.type", "bootanim");
|
||
|
// Clear BootAnimation exit flag
|
||
|
property_set("service.bootanim.exit", "0");
|
||
|
// Start BootAnimation if not started
|
||
|
property_set("ctl.start", "bootanim");
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
// get bootvideo path
|
||
|
string BootvideoGetPath()
|
||
|
{
|
||
|
string tempPathOne = "";
|
||
|
auto configer = make_unique<BootvideoConfiger>();
|
||
|
if (IsSTRPlay()) {
|
||
|
tempPathOne = configer->GetFeature(BootvideoConfiger::PROPERTY_PATH_STR_FIRST);
|
||
|
} else {
|
||
|
tempPathOne = configer->GetFeature(BootvideoConfiger::PROPERTY_PATH_FIRST);
|
||
|
}
|
||
|
// if api set path, the video path is g_pathApi
|
||
|
if (!g_pathApi.empty()) {
|
||
|
tempPathOne = g_pathApi;
|
||
|
}
|
||
|
return tempPathOne;
|
||
|
}
|
||
|
|
||
|
void InitAudioVolume()
|
||
|
{
|
||
|
const int speaker = 0;
|
||
|
const int headPhone = 1;
|
||
|
int volume = GetVolume(speaker);
|
||
|
SetVolume(speaker, volume);
|
||
|
volume = GetVolume(headPhone);
|
||
|
SetVolume(headPhone, volume);
|
||
|
}
|
||
|
|
||
|
// start paly bootvideo
|
||
|
bool StartPlayBootvideo()
|
||
|
{
|
||
|
// creat palyer
|
||
|
g_bootVideoUi = new BootvideoUI();
|
||
|
g_bootVideoPlayer = new BootvideoPlayer();
|
||
|
// init player
|
||
|
bool isSuc = g_bootVideoPlayer->InitPlay();
|
||
|
if (!isSuc) {
|
||
|
ALOGE("palyer init failure");
|
||
|
BootvideoFailProc();
|
||
|
StopPlayBootVideo();
|
||
|
return false;
|
||
|
}
|
||
|
// set player path
|
||
|
isSuc = g_bootVideoPlayer->SetDataSource(BootvideoGetPath());
|
||
|
if (!isSuc) {
|
||
|
ALOGE("palyer set path failure");
|
||
|
BootvideoFailProc();
|
||
|
StopPlayBootVideo();
|
||
|
return false;
|
||
|
}
|
||
|
// init system volume
|
||
|
int initVolume = BootvideoInitVolume();
|
||
|
auto configer = make_unique<BootvideoConfiger>();
|
||
|
// start input and ui
|
||
|
if (configer->IsFeature(BootvideoConfiger::PROPERTY_EN_INPUT)) {
|
||
|
ALOGD("support input");
|
||
|
StartInput(initVolume, g_bootVideoUi, g_bootVideoPlayer);
|
||
|
}
|
||
|
InitAudioManager();
|
||
|
// if not strplay, set port volume
|
||
|
if (!IsSTRPlay()) {
|
||
|
InitAudioVolume();
|
||
|
}
|
||
|
// set player sideband
|
||
|
isSuc = g_bootVideoPlayer->SetSideBand(g_bootVideoUi->GetSideBand());
|
||
|
if (!isSuc) {
|
||
|
ALOGE("palyer set side band failure");
|
||
|
}
|
||
|
|
||
|
int waitUiCount = WAIT_UI_READY_COUNT;
|
||
|
while (!g_bootVideoUi->CheckReady() && waitUiCount > 0) {
|
||
|
waitUiCount--;
|
||
|
usleep(PLAY_TIMER_INTERVAL * CONVERT_MS_TO_US);
|
||
|
}
|
||
|
ALOGD("Bootvideo UI is ready.");
|
||
|
// start player
|
||
|
if (!g_bootVideoPlayer->StartPlay(initVolume)) {
|
||
|
ALOGE("palyer start play failure");
|
||
|
BootvideoFailProc();
|
||
|
StopPlayBootVideo();
|
||
|
return false;
|
||
|
}
|
||
|
// loop player
|
||
|
CheckIfExitPlay();
|
||
|
return true;
|
||
|
}
|
||
|
// stop play bootvideo
|
||
|
bool StopPlayBootVideo()
|
||
|
{
|
||
|
auto configer = make_unique<BootvideoConfiger>();
|
||
|
// stop input
|
||
|
if (configer->IsFeature(BootvideoConfiger::PROPERTY_EN_INPUT)) {
|
||
|
ALOGI("StopPlayBootVideo: start to stop input thread.");
|
||
|
StopInput();
|
||
|
}
|
||
|
// stop ui
|
||
|
ALOGI("StopPlayBootVideo: start to stop UI thread.");
|
||
|
if (g_bootVideoUi) {
|
||
|
g_bootVideoUi->SetUIFinish();
|
||
|
g_bootVideoUi = nullptr;
|
||
|
}
|
||
|
// stop palyer
|
||
|
ALOGI("StopPlayBootVideo: start to stop player thread.");
|
||
|
if (g_bootVideoPlayer) {
|
||
|
g_bootVideoPlayer->StopPlay();
|
||
|
g_bootVideoPlayer = nullptr;
|
||
|
}
|
||
|
ALOGI("StopPlayBootVideo: all thread stop.");
|
||
|
return true;
|
||
|
}
|
||
|
// loop check bootvideo
|
||
|
void CheckIfExitPlay()
|
||
|
{
|
||
|
auto configer = make_unique<BootvideoConfiger>();
|
||
|
// playing duration time
|
||
|
const short tmpLimit = configer->GetVideoLimit();
|
||
|
const short limit = tmpLimit > 120 ? 120 : tmpLimit; // 120 is in 2minute in second
|
||
|
const int limitTimeMs = limit * CONVERT_SEC_TO_MS;
|
||
|
bool isPlayErr = false;
|
||
|
bool isPlayFail = false;
|
||
|
bool isPlayStop = false;
|
||
|
// static frame play: if the system has not complete and player is end, on the last frame
|
||
|
bool isSyscmp = false;
|
||
|
string bootvideoPath = BootvideoGetPath();
|
||
|
|
||
|
// set and init remaining play time
|
||
|
SetDrawTime(limitTimeMs);
|
||
|
// set signal of draw the remaining play time
|
||
|
signal(SIGALRM, SignalHandler);
|
||
|
// set timer interval, unit is ms
|
||
|
ManagerSetTimer();
|
||
|
// start loop
|
||
|
while (true) {
|
||
|
// check player
|
||
|
if (g_bootVideoPlayer == nullptr) {
|
||
|
ALOGE("paly loop: bootVideoPlayer is NULL");
|
||
|
isPlayErr = true;
|
||
|
break;
|
||
|
}
|
||
|
// check paly failed
|
||
|
isPlayFail = g_bootVideoPlayer->IsPlayFail();
|
||
|
if (isPlayFail) {
|
||
|
BootvideoDfteventReport(E_955050801, "CheckIfExitPlay", "StartPlayBootvideo", bootvideoPath);
|
||
|
ALOGE("paly loop: bootVideoPlayer failure");
|
||
|
break;
|
||
|
}
|
||
|
// check system boot complete
|
||
|
isSyscmp = IsBootComplete();
|
||
|
// check play end
|
||
|
bool isPlayEnd = g_bootVideoPlayer->IsPlayEnd();
|
||
|
if (isPlayEnd) {
|
||
|
ALOGE("paly loop: bootvideo player end");
|
||
|
}
|
||
|
// check play timeout
|
||
|
bool isTimeout = CheckIfTimeOut(limitTimeMs);
|
||
|
if (isTimeout) {
|
||
|
ALOGE("paly loop: bootvideo player time out");
|
||
|
}
|
||
|
// when timeout or end, stop play and stop
|
||
|
if (isPlayEnd || isTimeout) {
|
||
|
isPlayStop = true;
|
||
|
break;
|
||
|
}
|
||
|
usleep(DELAY_100_MS * CONVERT_MS_TO_US); // wait delay 100ms
|
||
|
}
|
||
|
// need start bootanim
|
||
|
if (isPlayFail || isPlayErr) {
|
||
|
BootvideoFailProc();
|
||
|
StopPlayBootVideo();
|
||
|
}
|
||
|
// stop bootvideo
|
||
|
if (isPlayStop) {
|
||
|
StopPlayBootVideo();
|
||
|
}
|
||
|
}
|
||
|
} // namespace android
|