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

/*
* 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