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.
2163 lines
74 KiB
2163 lines
74 KiB
/*
|
|
* Copyright (c) Hisilicon Technologies Co., Ltd. 2019-2020. All rights reserved.
|
|
* Description: NxMediaPlayerManager class implement
|
|
* Author: NxPlayer software group
|
|
* Create: 2019-11-21
|
|
*/
|
|
#define LOG_NDEBUG 0
|
|
#define LOG_TAG "NP_MGR"
|
|
|
|
#include "NxMediaPlayerManage.h"
|
|
#include <utils/Log.h>
|
|
#include <cutils/properties.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <cinttypes>
|
|
#include <utils/String8.h>
|
|
#include <binder/IPCThreadState.h>
|
|
#include <IMediaResourceMonitor.h>
|
|
#include <binder/IServiceManager.h>
|
|
#include <hardware/gralloc1.h>
|
|
#include <gui/Surface.h>
|
|
|
|
using vendor::hardware::hwnxmediaplayerhal::V1_0::INxMediaPlayer;
|
|
using vendor::hardware::hwnxmediaplayerhal::V1_0::IMediaCallBack;
|
|
using HPlaybackRate = vendor::hardware::hwnxmediaplayerhal::V1_0::INxMediaPlayer::HPlaybackRate;
|
|
using HMediaPlayerSeekMode =
|
|
vendor::hardware::hwnxmediaplayerhal::V1_0::INxMediaPlayer::HMediaPlayerSeekMode;
|
|
|
|
using ::android::hardware::hidl_array;
|
|
using ::android::hardware::hidl_string;
|
|
using ::android::hardware::hidl_vec;
|
|
using ::android::hardware::hidl_handle;
|
|
using ::android::hardware::Return;
|
|
using ::android::hardware::Void;
|
|
using ::android::sp;
|
|
using ::android::hardware::hidl_handle;
|
|
|
|
namespace android {
|
|
namespace {
|
|
const std::string PROPERTY_NP_OUTPUT = "persist.sys.media.np.output";
|
|
const int ERR_BUF_LEN = 256;
|
|
}
|
|
enum SYNC_ASYNC {
|
|
ASYNC = 0,
|
|
SYNC = 1
|
|
};
|
|
|
|
enum PlayerManagerState {
|
|
MEDIA_PLAYER_STATE_ERROR = 0,
|
|
MEDIA_PLAYER_IDLE = 1 << 0,
|
|
MEDIA_PLAYER_INITIALIZED = 1 << 1,
|
|
MEDIA_PLAYER_PREPARING = 1 << 2,
|
|
MEDIA_PLAYER_PREPARED = 1 << 3,
|
|
MEDIA_PLAYER_STARTED = 1 << 4,
|
|
MEDIA_PLAYER_PAUSED = 1 << 5,
|
|
MEDIA_PLAYER_STOPPED = 1 << 6,
|
|
MEDIA_PLAYER_PLAYBACK_COMPLETE = 1 << 7
|
|
};
|
|
|
|
enum PlayerInvokeCmd {
|
|
INVOKE_ID_GET_TRACK_INFO = 1,
|
|
INVOKE_ID_ADD_EXTERNAL_SOURCE = 2,
|
|
INVOKE_ID_ADD_EXTERNAL_SOURCE_FD = 3,
|
|
INVOKE_ID_SELECT_TRACK = 4,
|
|
INVOKE_ID_UNSELECT_TRACK = 5,
|
|
INVOKE_ID_SET_VIDEO_SCALING_MODE = 6,
|
|
INVOKE_ID_GET_SELECTED_TRACK = 7,
|
|
INVOKE_ID_SET_EXT_SUBTITLE_FILE = 5016
|
|
};
|
|
|
|
enum ParameterKeys {
|
|
/*
|
|
* Playback rate expressed in permille (1000 is normal speed), saved as int32_t, with negative
|
|
* values used for rewinding or reverse playback.
|
|
*/
|
|
KEY_PARAMETER_PLAYBACK_RATE_PERMILLE = 1300,
|
|
};
|
|
|
|
enum EventType {
|
|
MEDIA_NOP = 0, /* interface test message */
|
|
MEDIA_PREPARED = 1,
|
|
MEDIA_PLAYBACK_COMPLETE = 2,
|
|
MEDIA_BUFFERING_UPDATE = 3,
|
|
MEDIA_SEEK_COMPLETE = 4,
|
|
MEDIA_SET_VIDEO_SIZE = 5,
|
|
MEDIA_STARTED = 6,
|
|
MEDIA_PAUSED = 7,
|
|
MEDIA_STOPPED = 8,
|
|
MEDIA_SKIPPED = 9,
|
|
MEDIA_NOTIFY_TIME = 98,
|
|
MEDIA_TIMED_TEXT = 99,
|
|
MEDIA_ERROR = 100,
|
|
MEDIA_INFO = 200,
|
|
MEDIA_SUBTITLE_DATA = 201,
|
|
MEDIA_META_DATA = 202,
|
|
MEDIA_DRM_INFO = 210,
|
|
MEDIA_TIME_DISCONTINUITY = 211,
|
|
MEDIA_AUDIO_ROUTING_CHANGED = 10000,
|
|
};
|
|
|
|
enum InfoType {
|
|
/* 0xx */
|
|
MEDIA_INFO_UNKNOWN = 1,
|
|
/*
|
|
* The player was started because it was used as the next player for another
|
|
* player, which just completed playback
|
|
*/
|
|
MEDIA_INFO_STARTED_AS_NEXT = 2,
|
|
/* The player just pushed the very first video frame for rendering */
|
|
MEDIA_INFO_RENDERING_START = 3,
|
|
/*
|
|
* 7xx
|
|
* The video is too complex for the decoder: it can't decode frames fast
|
|
* enough. Possibly only the audio plays fine at this stage.
|
|
*/
|
|
MEDIA_INFO_VIDEO_TRACK_LAGGING = 700,
|
|
/*
|
|
* MediaPlayer is temporarily pausing playback internally in order to
|
|
* buffer more data.
|
|
*/
|
|
MEDIA_INFO_BUFFERING_START = 701,
|
|
/* MediaPlayer is resuming playback after filling buffers. */
|
|
MEDIA_INFO_BUFFERING_END = 702,
|
|
/* Bandwidth in recent past */
|
|
MEDIA_INFO_NETWORK_BANDWIDTH = 703,
|
|
/*
|
|
* 8xx
|
|
* Bad interleaving means that a media has been improperly interleaved or not
|
|
* interleaved at all, e.g has all the video samples first then all the audio
|
|
* ones. Video is playing but a lot of disk seek may be happening.
|
|
*/
|
|
MEDIA_INFO_BAD_INTERLEAVING = 800,
|
|
/* The media is not seekable (e.g live stream). */
|
|
MEDIA_INFO_NOT_SEEKABLE = 801,
|
|
/* New media metadata is available. */
|
|
MEDIA_INFO_METADATA_UPDATE = 802,
|
|
/* Audio can not be played. */
|
|
MEDIA_INFO_PLAY_AUDIO_ERROR = 804,
|
|
/* Video can not be played. */
|
|
MEDIA_INFO_PLAY_VIDEO_ERROR = 805,
|
|
/* 9xx */
|
|
MEDIA_INFO_TIMED_TEXT_ERROR = 900,
|
|
};
|
|
|
|
Return<void> MediaCallBack::Notify(int32_t msg, int32_t ext1, int32_t ext2, const hidl_string &obj)
|
|
{
|
|
Parcel parcelObj;
|
|
parcelObj.setData(reinterpret_cast<const uint8_t *>(obj.c_str()), obj.size());
|
|
HLOGD("notify msg=%d, ext1=%d, ext2=%d, parcel=%zu-%zu", msg, ext1, ext2, obj.size(), parcelObj.dataPosition());
|
|
|
|
NxMediaPlayerManage *mediaPlayerManage = nullptr;
|
|
{
|
|
Mutex::Autolock autoLock(m_notifyLock);
|
|
mediaPlayerManage = m_mediaPlayerManage;
|
|
}
|
|
|
|
if (mediaPlayerManage != nullptr) {
|
|
if (mediaPlayerManage->UseAsycModeNotifyMsg()) {
|
|
mediaPlayerManage->PostMsg(msg, ext1, ext2, parcelObj);
|
|
} else {
|
|
mediaPlayerManage->notifyFunc(msg, ext1, ext2, &parcelObj);
|
|
}
|
|
}
|
|
HLOGI("notify msg msg=%d, ext1=%d, ext2=%d back", msg, ext1, ext2);
|
|
|
|
return Void();
|
|
}
|
|
|
|
void MediaCallBack::SetMediaCallBack(NxMediaPlayerManage *p)
|
|
{
|
|
HLOGI("%s", __FUNCTION__);
|
|
Mutex::Autolock autoLock(m_notifyLock);
|
|
m_mediaPlayerManage = p;
|
|
}
|
|
|
|
std::vector<std::string> NxMediaPlayerManage::g_extSubSuffixName = {
|
|
"idx", "sub", "srt",
|
|
"ssa", "ass", "smi",
|
|
"utf", "utf8", "utf-8",
|
|
"txt", "rt", "aqt",
|
|
"usf", "jss", "cdg",
|
|
"psb", "mpsub", "mpl2",
|
|
"pjs", "dks", "lrc",
|
|
"sami", "mpl",
|
|
""
|
|
};
|
|
|
|
NxMediaPlayerManage::NxMediaPlayerManage(int idx)
|
|
:m_isSurfaceView(-1),
|
|
m_isSeeking(0),
|
|
m_isStarting(0),
|
|
m_listener(nullptr),
|
|
m_cookie(nullptr),
|
|
m_currentState(MEDIA_PLAYER_IDLE),
|
|
m_duration(-1),
|
|
m_currentPosition(-1),
|
|
m_seekPosition(-1),
|
|
m_seekMode(NxPlayerSeekMode::NX_PLAYER_SEEK_PRE_KEY),
|
|
m_prepareSync(false),
|
|
m_prepareStatus(NO_ERROR),
|
|
m_loop(false),
|
|
m_leftVolume(1.0),
|
|
m_rightVolume(1.0),
|
|
m_videoWidth(0),
|
|
m_videoHeight(0),
|
|
m_sendLevel(0),
|
|
m_videoSurfaceX(-1),
|
|
m_videoSurfaceY(-1),
|
|
m_videoSurfaceWidth(-1),
|
|
m_videoSurfaceHeight(-1),
|
|
m_instIdx(idx)
|
|
{
|
|
HLOGI("call %s in", __FUNCTION__);
|
|
/* create player for setting video surface */
|
|
sp<INxMediaPlayer> player = CreatePlayer();
|
|
AttachNewPlayer(player);
|
|
InitDeathRecipient();
|
|
HLOGI("call %s out", __FUNCTION__);
|
|
}
|
|
|
|
NxMediaPlayerManage::~NxMediaPlayerManage()
|
|
{
|
|
HLOGI("call %s in", __FUNCTION__);
|
|
PostMsg(NX_MSG_EXIT);
|
|
if (m_nxMsgHandle.get() != nullptr) {
|
|
m_nxMsgHandle->SetCbPlayer(nullptr);
|
|
}
|
|
DeInitDeathRecipient();
|
|
HLOGI("call %s out", __FUNCTION__);
|
|
}
|
|
|
|
void NxMediaPlayerManage::InitDeathRecipient()
|
|
{
|
|
m_deathRecipient = new(std::nothrow) DeathRecipient(this, m_instIdx);
|
|
if (m_deathRecipient.get() == nullptr) {
|
|
HLOGE("new DeathRecipient failed");
|
|
}
|
|
|
|
if (m_deathRecipient != nullptr && m_player != nullptr) {
|
|
uint64_t cookie = reinterpret_cast<uintptr_t>(m_player.get());
|
|
if (!m_player->linkToDeath(m_deathRecipient, cookie)) {
|
|
HLOGE("register death notification failed");
|
|
} else {
|
|
HLOGD("register death notification success");
|
|
}
|
|
}
|
|
}
|
|
|
|
void NxMediaPlayerManage::DeInitDeathRecipient() const
|
|
{
|
|
HLOGD("%s", __FUNCTION__);
|
|
if (m_deathRecipient != nullptr && m_player != nullptr) {
|
|
m_player->unlinkToDeath(m_deathRecipient);
|
|
}
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::initCheck()
|
|
{
|
|
HLOGD("%s ok", __FUNCTION__);
|
|
return OK;
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::setUID(uid_t uid) const
|
|
{
|
|
(void)uid;
|
|
return OK;
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::getTrackInfo(Parcel *reply)
|
|
{
|
|
HLOGI("call %s in", __FUNCTION__);
|
|
if (m_player.get() == nullptr) {
|
|
return NO_INIT;
|
|
}
|
|
|
|
if (reply == nullptr) {
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
|
|
Return<void> transGetTrackInfo = m_player->getTrackInfo(
|
|
[&reply, this](int32_t ret, const hidl_string &replyString) {
|
|
if (ret != 0) {
|
|
HLOGE("getTrackInfo failed");
|
|
return;
|
|
}
|
|
reply->setData(reinterpret_cast<const uint8_t *>(replyString.c_str()), replyString.size());
|
|
});
|
|
size_t pos = reply->dataPosition();
|
|
reply->setDataPosition(0);
|
|
int totalTrackNum = reply->readInt32();
|
|
if (totalTrackNum > MAX_TRACK_NUM) {
|
|
HLOGE("track number is too large!");
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
|
|
HLOGI("trackinfo: %s, len=%d, num=%d, pos=%d", reply->data(), reply->dataSize(), totalTrackNum, pos);
|
|
for (int i = 0; i < totalTrackNum; i++) {
|
|
int element = reply->readInt32();
|
|
int type = reply->readInt32();
|
|
String16 mine = reply->readString16();
|
|
String16 lang = reply->readString16();
|
|
HLOGI(" element: %d, type:%d mine:%s, lang:%s",
|
|
element, type, String8(mine).c_str(), String8(lang).c_str());
|
|
}
|
|
reply->setDataPosition(pos);
|
|
if (!transGetTrackInfo.isOk()) {
|
|
HLOGE("GetTrackInfo failed");
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
HLOGI("call %s out", __FUNCTION__);
|
|
return OK;
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::setDataSource(const char *url, const KeyedVector<String8, String8> *headers)
|
|
{
|
|
HLOGI("call %s in, uri", __FUNCTION__);
|
|
if (url != nullptr && m_player.get() != nullptr) {
|
|
hidl_string urlHidl(url);
|
|
hidl_vec<Header> headersHidl;
|
|
if (headers != nullptr) {
|
|
headersHidl.resize(headers->size());
|
|
for (size_t i = 0; i < headers->size(); i++) {
|
|
headersHidl[i].key = headers->keyAt(i).c_str();
|
|
headersHidl[i].value = headers->valueAt(i).c_str();
|
|
}
|
|
}
|
|
Return<int32_t> transSetDataSourceNetwork = m_player->setDataSourceUrl(urlHidl, headersHidl);
|
|
if (!transSetDataSourceNetwork.isOk() || static_cast<int32_t>(transSetDataSourceNetwork) != 0) {
|
|
HLOGE("SetDataSourceNetwork failed");
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
}
|
|
HLOGI("call %s out", __FUNCTION__);
|
|
|
|
return OK;
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::setDataSource(int fd, int64_t offset, int64_t length)
|
|
{
|
|
HLOGI("call %s in, fd", __FUNCTION__);
|
|
char url[PATH_MAX] = {0};
|
|
struct stat sb;
|
|
int ret = fstat(fd, &sb);
|
|
if (ret != 0) {
|
|
char errbuf[ERR_BUF_LEN] = {0};
|
|
HLOGE("fstat fd=%d ret=%d, reason:%s", fd, ret, strerror_r(errno, errbuf, sizeof(errbuf)));
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
|
|
HLOGD("file stat: (st_dev, st_mode, st_size, st_uid, st_gid)=(%" PRIu64", %u, %" PRIu64", %lu, %lu)",
|
|
sb.st_dev, sb.st_mode, sb.st_size,
|
|
static_cast<unsigned long>(sb.st_uid), static_cast<unsigned long>(sb.st_gid));
|
|
|
|
if ((sb.st_mode & S_IFMT) == S_IFCHR) {
|
|
HLOGE("fd:%d is a character device, st_mod:%u, can not play", fd, sb.st_mode);
|
|
return UNKNOWN_ERROR;
|
|
} else if (offset >= sb.st_size) {
|
|
HLOGE("offset %" PRId64" bigger than file size %" PRId64"", offset, sb.st_size);
|
|
return UNKNOWN_ERROR;
|
|
} else if (offset + length > sb.st_size) {
|
|
length = sb.st_size - offset;
|
|
HLOGW("recalculated play length=%" PRId64"", length);
|
|
}
|
|
|
|
if (GetUrlFromFd(fd, url, sizeof(url)) == OK) {
|
|
if (FindExtSubTitleFromUrl(url, sizeof(url)) == OK) {
|
|
for (size_t i = 0; i < m_extSubUrl.size(); i++) {
|
|
AddTimedTextSource(m_extSubUrl[i].c_str());
|
|
}
|
|
}
|
|
}
|
|
|
|
if (fd != 0 && m_player.get() != nullptr) {
|
|
native_handle_t * const nativeHdl = native_handle_create(1, 0);
|
|
if (nativeHdl == nullptr) {
|
|
HLOGE("create native handle failed!");
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
nativeHdl->data[0] = fd;
|
|
hidl_handle fdHandle;
|
|
fdHandle.setTo(nativeHdl, false);
|
|
Return<int32_t> transSetDataSourceLocal = m_player->setDataSourceFd(fdHandle, offset, length);
|
|
(void)native_handle_delete(nativeHdl);
|
|
if (!transSetDataSourceLocal.isOk() || static_cast<int32_t>(transSetDataSourceLocal) != 0) {
|
|
HLOGE("transSetDataSourceLocal failed");
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
}
|
|
HLOGI("call %s out", __FUNCTION__);
|
|
|
|
return OK;
|
|
}
|
|
|
|
static int PropertyGet(const char *propertyName, char *propertyValue, unsigned int valueLen __unused,
|
|
const char *defaultPropertyValue)
|
|
{
|
|
return property_get(propertyName, propertyValue, defaultPropertyValue);
|
|
}
|
|
|
|
|
|
/* for double screen display */
|
|
status_t NxMediaPlayerManage::SetSubScreenDisplay()
|
|
{
|
|
HLOGD("%s", __FUNCTION__);
|
|
int useSubScreenDisplay = 0;
|
|
if (m_nativeWindow.get() != nullptr) {
|
|
uint64_t usage = 0;
|
|
native_window_get_consumer_usage(m_nativeWindow.get(), &usage);
|
|
if ((usage & GRALLOC1_CONSUMER_USAGE_PRIVATE_19) == GRALLOC1_CONSUMER_USAGE_PRIVATE_19) {
|
|
HLOGD("Native window display on sub screen");
|
|
useSubScreenDisplay = 1;
|
|
}
|
|
}
|
|
|
|
Parcel request;
|
|
Parcel reply;
|
|
request.writeInt32(CMD_SET_USE_SUB_SCREEN);
|
|
request.writeInt32(useSubScreenDisplay);
|
|
request.setDataPosition(0);
|
|
return invoke(request, &reply);
|
|
}
|
|
|
|
bool NxMediaPlayerManage::SwitchModeIsBlack()
|
|
{
|
|
// notify: invoke is use m_lock
|
|
Parcel requestSwitch;
|
|
Parcel replySwitch;
|
|
requestSwitch.writeInt32(CMD_GET_SWITCH_MODE);
|
|
requestSwitch.setDataPosition(0);
|
|
invoke(requestSwitch, &replySwitch);
|
|
replySwitch.setDataPosition(0);
|
|
int isBlackMode = replySwitch.readInt32();
|
|
return (isBlackMode == 0) ? false : true;
|
|
}
|
|
|
|
int NxMediaPlayerManage::SetSidebandHandle(const sp<ANativeWindow> &native)
|
|
{
|
|
HLOGD("%s", __FUNCTION__);
|
|
native_handle_t *sideBandHandle = nullptr;
|
|
unsigned int win = NX_SVR_PLAYER_INVALID_HDL;
|
|
if (m_nativeWindow.get() && native.get() != m_nativeWindow.get()) {
|
|
(void)native_window_set_sideband_stream(m_nativeWindow.get(), nullptr);
|
|
}
|
|
|
|
if (native.get()) {
|
|
Parcel requestWin;
|
|
Parcel replyWin;
|
|
requestWin.writeInt32(CMD_GET_WIN_HANDLE);
|
|
requestWin.setDataPosition(0);
|
|
invoke(requestWin, &replyWin);
|
|
replyWin.setDataPosition(0);
|
|
win = replyWin.readUint32();
|
|
if (win == NX_SVR_PLAYER_INVALID_HDL) {
|
|
HLOGE("get NxPlayer win handle failed");
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
sideBandHandle = native_handle_create(0, NUM_INTS);
|
|
if (sideBandHandle == nullptr) {
|
|
HLOGE("native_handle_create failed");
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
HLOGI("sidebandhdl, hWin=%#x", win);
|
|
sideBandHandle->data[0] = win;
|
|
|
|
bool isBlack = SwitchModeIsBlack();
|
|
if (isBlack) {
|
|
sideBandHandle->data[1] = SIDEBAND_NXPLAY_MAGIC_NUM_BLACK;
|
|
HLOGD("SIDEBAND_NXPLAY_MAGIC_NUM_BLACK#");
|
|
} else {
|
|
/* surfaceflinger need this flag to diff with tunel mode */
|
|
sideBandHandle->data[1] = SIDEBAND_NXPLAY_MAGIC_NUM;
|
|
HLOGD("SIDEBAND_NXPLAY_MAGIC_NUM#");
|
|
}
|
|
(void)native_window_set_sideband_stream(native.get(), sideBandHandle);
|
|
(void)native_handle_delete(sideBandHandle);
|
|
}
|
|
return NO_ERROR;
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::CreateNxMediaMsg()
|
|
{
|
|
if (m_nxMsg.get() != nullptr && m_nxMsgHandle.get() != nullptr) {
|
|
m_nxMsg->EnableNxMediaMsg(true);
|
|
return OK;
|
|
}
|
|
|
|
m_nxMsg = new (std::nothrow) NxMediaMsg(m_instIdx);
|
|
if (m_nxMsg.get() != nullptr) {
|
|
m_nxMsgHandle = new (std::nothrow) NxMediaMsgHandle(m_nxMsg, this, m_instIdx);
|
|
if (m_nxMsgHandle.get() != nullptr) {
|
|
HLOGI("create NxMediaMsg to async notify msg");
|
|
return OK;
|
|
} else {
|
|
HLOGE("create NxMediaMsgHandle failed!");
|
|
}
|
|
} else {
|
|
HLOGE("create NxMediaMsg failed!");
|
|
}
|
|
|
|
return NO_INIT;
|
|
}
|
|
|
|
bool NxMediaPlayerManage::UseAsycModeNotifyMsg() const
|
|
{
|
|
if (m_nxMsg.get() != nullptr && m_nxMsgHandle.get() != nullptr) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void NxMediaPlayerManage::PostMsg(int msg, int ext1, int ext2, const Parcel &obj) const
|
|
{
|
|
if (m_nxMsg.get() != nullptr) {
|
|
NxMessage nxMsg = NxMessage();
|
|
nxMsg.Init(msg, ext1, ext2, obj);
|
|
m_nxMsg->PostMessage(m_nxMsgHandle, nxMsg);
|
|
}
|
|
}
|
|
|
|
/* after call setVideoSurfaceTexture can be use */
|
|
bool NxMediaPlayerManage::IsUseSidebandMode() const
|
|
{
|
|
bool isSidebandMode = false;
|
|
|
|
char value[PROPERTY_VALUE_MAX] = {0};
|
|
if (PropertyGet(PROPERTY_NP_OUTPUT.c_str(), value, sizeof(value), "sideband") != 0 &&
|
|
strcasecmp("sideband", value) != 0) {
|
|
HLOGW("persist.sys.media.np.output [%s]", value);
|
|
return false;
|
|
}
|
|
|
|
if (m_isSurfaceView == 1) { /* SurfaceView */
|
|
isSidebandMode = true;
|
|
} else if (m_isSurfaceView == 0) { /* SurfaceTexture */
|
|
isSidebandMode = false;
|
|
} else {
|
|
HLOGE("something wrong, default fb");
|
|
isSidebandMode = false;
|
|
}
|
|
|
|
HLOGI("isSidebandMode=%d", isSidebandMode);
|
|
return isSidebandMode;
|
|
}
|
|
|
|
void NxMediaPlayerManage::SetSurfaceUniqueId(const sp<ANativeWindow> &nativeWindow)
|
|
{
|
|
if (nativeWindow.get() == nullptr) {
|
|
return;
|
|
}
|
|
|
|
sp<Surface> curSf = static_cast<Surface*>(nativeWindow.get());
|
|
uint64_t uniqueId = 0;
|
|
if (curSf.get() == nullptr || curSf->getUniqueId(&uniqueId) != NO_ERROR) {
|
|
HLOGW("SetSurfaceUniqueId faild");
|
|
return;
|
|
}
|
|
/* notify: invoke is use m_lock */
|
|
Parcel request;
|
|
Parcel reply;
|
|
request.writeInt32(CMD_SET_SURFACE_UNIQUE_ID);
|
|
request.writeUint64(uniqueId);
|
|
request.setDataPosition(0);
|
|
invoke(request, &reply);
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::setVideoSurfaceTexture(const sp<HGraphicBufferProducer> &bufferProducer,
|
|
sp<ANativeWindow> &nativeWindow, int isSurfaceView)
|
|
{
|
|
HLOGI("call in");
|
|
if (m_player.get() == nullptr) {
|
|
return NO_INIT;
|
|
}
|
|
|
|
m_isSurfaceView = isSurfaceView;
|
|
|
|
SetSurfaceUniqueId(nativeWindow);
|
|
|
|
if ((m_currentState >= MEDIA_PLAYER_STARTED) && IsUseSidebandMode()) {
|
|
SetSidebandHandle(nativeWindow);
|
|
}
|
|
|
|
m_nativeWindow = nativeWindow;
|
|
|
|
if (SetSubScreenDisplay() != OK) {
|
|
HLOGE("set sub screen failed, check it");
|
|
}
|
|
|
|
if (!IsUseSidebandMode()) {
|
|
Return<int32_t> transSetSurfaceTextureFB = m_player->setSurfaceTexture(bufferProducer, isSurfaceView);
|
|
if (!transSetSurfaceTextureFB.isOk() || static_cast<int32_t>(transSetSurfaceTextureFB) != 0) {
|
|
HLOGE("SetSurfaceTexture FB failed");
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
|
|
(void)CreateNxMediaMsg(); /* async notify msg for SurfaceTexture */
|
|
} else {
|
|
Return<int32_t> transSetSurfaceTextureSB = m_player->setSurfaceTexture(nullptr, isSurfaceView);
|
|
if (!transSetSurfaceTextureSB.isOk() || static_cast<int32_t>(transSetSurfaceTextureSB) != 0) {
|
|
HLOGE("SetSurfaceTexture sideband failed");
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
}
|
|
HLOGI("call %s out", __FUNCTION__);
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::prepare()
|
|
{
|
|
HLOGI("call %s in", __FUNCTION__);
|
|
Mutex::Autolock l(m_lock);
|
|
if (m_prepareSync) {
|
|
HLOGW("already prepared");
|
|
return -EALREADY;
|
|
}
|
|
|
|
m_prepareSync = true;
|
|
status_t ret = PrepareAsyncL();
|
|
if (ret != NO_ERROR) {
|
|
HLOGE("PrepareAsyncL failed");
|
|
return ret;
|
|
}
|
|
|
|
if (m_prepareSync) {
|
|
m_signal.wait(m_lock); /* wait for prepare done */
|
|
m_prepareSync = false;
|
|
}
|
|
HLOGI("call %s out, mPrepareStatus=%d", __FUNCTION__, m_prepareStatus);
|
|
return m_prepareStatus;
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::PrepareAsyncL()
|
|
{
|
|
ProcessScreenOrient(); /* set home version screen orient */
|
|
SetUserID(); /* set user id to nxmediaplayer */
|
|
if ((m_player.get() != nullptr) && (m_currentState & (static_cast<uint32_t>(MEDIA_PLAYER_INITIALIZED) |
|
|
static_cast<uint32_t>(MEDIA_PLAYER_STOPPED))) != 0) {
|
|
m_currentState = MEDIA_PLAYER_PREPARING;
|
|
HLOGD("async prepare");
|
|
Return<int32_t> transPrepareAsync = m_player->prepare(ASYNC);
|
|
if (!transPrepareAsync.isOk() || static_cast<int32_t>(transPrepareAsync) != 0) {
|
|
HLOGE("async prepare failed");
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
return OK;
|
|
}
|
|
|
|
HLOGE("invalid operation, called out state=%u", m_currentState);
|
|
return INVALID_OPERATION;
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::prepareAsync()
|
|
{
|
|
HLOGI("call %s in", __FUNCTION__);
|
|
Mutex::Autolock l(m_lock);
|
|
status_t ret = PrepareAsyncL();
|
|
HLOGI("call %s out, ret=%d", __FUNCTION__, ret);
|
|
return ret;
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::start()
|
|
{
|
|
HLOGI("call %s in", __FUNCTION__);
|
|
if (IsUseSidebandMode()) {
|
|
SetSidebandHandle(m_nativeWindow);
|
|
} else {
|
|
(void)CreateNxMediaMsg(); /* async notify msg for SurfaceTexture */
|
|
}
|
|
|
|
status_t ret = NO_ERROR;
|
|
{
|
|
Mutex::Autolock l(m_lock);
|
|
m_isStarting = 1;
|
|
if ((m_currentState & static_cast<uint32_t>(MEDIA_PLAYER_STARTED)) != 0) {
|
|
ret = NO_ERROR;
|
|
goto RE;
|
|
}
|
|
|
|
if ((m_player.get() != nullptr) && (m_currentState & (static_cast<uint32_t>(MEDIA_PLAYER_STOPPED) |
|
|
static_cast<uint32_t>(MEDIA_PLAYER_PREPARED) | static_cast<uint32_t>(MEDIA_PLAYER_PLAYBACK_COMPLETE) |
|
|
static_cast<uint32_t>(MEDIA_PLAYER_PAUSED))) != 0) {
|
|
m_player->setLooping(m_loop);
|
|
m_currentState = MEDIA_PLAYER_STARTED;
|
|
Return<int32_t> transStart = m_player->start();
|
|
if (!transStart.isOk() || static_cast<int32_t>(transStart) != 0) {
|
|
HLOGE("start failed");
|
|
ret = MEDIA_INFO_UNKNOWN;
|
|
} else {
|
|
ret = NO_ERROR;
|
|
}
|
|
if (ret != NO_ERROR) {
|
|
m_currentState = MEDIA_PLAYER_STATE_ERROR;
|
|
} else {
|
|
if (m_currentState == MEDIA_PLAYER_PLAYBACK_COMPLETE) {
|
|
HLOGW("playback completed immediately following start()");
|
|
}
|
|
}
|
|
goto RE;
|
|
}
|
|
RE:
|
|
m_isStarting = 0;
|
|
}
|
|
NotifyResourceManage();
|
|
HLOGI("call %s out, ret=%d", __FUNCTION__, ret);
|
|
return ret;
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::stop()
|
|
{
|
|
HLOGI("call %s in", __FUNCTION__);
|
|
Mutex::Autolock l(m_lock);
|
|
status_t ret;
|
|
if ((m_currentState & static_cast<uint32_t>(MEDIA_PLAYER_STOPPED)) != 0) {
|
|
return NO_ERROR;
|
|
}
|
|
|
|
if ((m_player.get() != nullptr) && (m_currentState &
|
|
(static_cast<uint32_t>(MEDIA_PLAYER_STARTED) | static_cast<uint32_t>(MEDIA_PLAYER_PREPARED) |
|
|
static_cast<uint32_t>(MEDIA_PLAYER_PAUSED) |
|
|
static_cast<uint32_t>(MEDIA_PLAYER_PLAYBACK_COMPLETE))) != 0) {
|
|
HLOGI("call stop player, m_currentState=%d", m_currentState);
|
|
Return<int32_t> transStop = m_player->stop();
|
|
if (!transStop.isOk() || static_cast<int32_t>(transStop) != 0) {
|
|
HLOGE("stop failed");
|
|
ret = UNKNOWN_ERROR;
|
|
} else {
|
|
ret = NO_ERROR;
|
|
}
|
|
if (ret != NO_ERROR) {
|
|
m_currentState = MEDIA_PLAYER_STATE_ERROR;
|
|
} else {
|
|
m_currentState = MEDIA_PLAYER_STOPPED;
|
|
Parcel parcelObj;
|
|
parcelObj.setData(nullptr, 0);
|
|
PostMsg(MEDIA_STOPPED, 0, 0, parcelObj);
|
|
}
|
|
HLOGI("call %s out, ret=%d", __FUNCTION__, ret);
|
|
return ret;
|
|
}
|
|
|
|
HLOGE("invalid operation, called out state=%u", m_currentState);
|
|
return INVALID_OPERATION;
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::pause()
|
|
{
|
|
HLOGI("call %s in", __FUNCTION__);
|
|
Mutex::Autolock l(m_lock);
|
|
status_t ret;
|
|
if ((m_currentState & (static_cast<uint32_t>(MEDIA_PLAYER_PAUSED) |
|
|
static_cast<uint32_t>(MEDIA_PLAYER_PLAYBACK_COMPLETE))) != 0) {
|
|
return NO_ERROR;
|
|
}
|
|
|
|
if ((m_player.get() != nullptr) && (m_currentState & static_cast<uint32_t>(MEDIA_PLAYER_STARTED)) != 0) {
|
|
Return<int32_t> transPause = m_player->pause();
|
|
if (!transPause.isOk() || static_cast<int32_t>(transPause) != 0) {
|
|
HLOGE("pause failed");
|
|
ret = UNKNOWN_ERROR;
|
|
} else {
|
|
ret = NO_ERROR;
|
|
}
|
|
if (ret != NO_ERROR) {
|
|
m_currentState = MEDIA_PLAYER_STATE_ERROR;
|
|
} else {
|
|
m_currentState = MEDIA_PLAYER_PAUSED;
|
|
}
|
|
HLOGI("call %s out, ret=%d", __FUNCTION__, ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
HLOGE("invalid operation, called out state=%u", m_currentState);
|
|
return INVALID_OPERATION;
|
|
}
|
|
|
|
bool NxMediaPlayerManage::isPlaying()
|
|
{
|
|
HLOGI("call %s in", __FUNCTION__);
|
|
Mutex::Autolock l(m_lock);
|
|
|
|
if (m_player.get() != nullptr) {
|
|
bool isPlaying = false;
|
|
Return<int32_t> transStatus = m_player->getPlayStatus();
|
|
if (transStatus.isOk() && static_cast<int32_t>(transStatus) != 0) {
|
|
isPlaying = true;
|
|
} else {
|
|
isPlaying = false;
|
|
}
|
|
if ((m_currentState & static_cast<uint32_t>(MEDIA_PLAYER_STARTED)) != 0 && !isPlaying) {
|
|
HLOGE("internal/external state mismatch corrected");
|
|
m_currentState = MEDIA_PLAYER_PAUSED;
|
|
}
|
|
|
|
HLOGD("call %s out, isPlaying=%d", __FUNCTION__, isPlaying);
|
|
return isPlaying;
|
|
}
|
|
|
|
HLOGW("isPlaying: no active player");
|
|
return false;
|
|
}
|
|
status_t NxMediaPlayerManage::getPlaybackSettings(NxPlayerRate *rate)
|
|
{
|
|
HLOGD("call %s in", __FUNCTION__);
|
|
Mutex::Autolock l(m_lock);
|
|
if (m_player.get() == nullptr) {
|
|
HLOGE("invalid operation, state=%u", m_currentState);
|
|
return INVALID_OPERATION;
|
|
}
|
|
|
|
Return<void> transGetPlaybackSettings = m_player->getPlaybackSettings(
|
|
[&rate, this](int32_t ret, const HPlaybackRate &settings) {
|
|
if (ret != 0) {
|
|
HLOGE("transGetPlaybackSettings failed");
|
|
return;
|
|
}
|
|
rate->speed = settings.mSpeed;
|
|
});
|
|
if (!transGetPlaybackSettings.isOk()) {
|
|
HLOGE("transGetPlaybackSettings failed");
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
HLOGI("call %s out", __FUNCTION__);
|
|
return OK;
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::setPlaybackSettings(const NxPlayerRate &rate)
|
|
{
|
|
HLOGI("call %s in, speed=%.2f, mCurrentState=0x%x", __FUNCTION__, rate.speed, m_currentState);
|
|
if (IsUseSidebandMode()) {
|
|
SetSidebandHandle(m_nativeWindow);
|
|
}
|
|
status_t err = NO_ERROR;
|
|
Mutex::Autolock l(m_lock);
|
|
if (m_player.get() != nullptr) {
|
|
HPlaybackRate setting = { rate.speed };
|
|
Return<int32_t> transSetPlaybackSettings = m_player->setPlaybackSettings(setting);
|
|
if (!transSetPlaybackSettings.isOk() || static_cast<int32_t>(transSetPlaybackSettings) != 0) {
|
|
HLOGE("transSetPlaybackSettings failed");
|
|
err = UNKNOWN_ERROR;
|
|
} else {
|
|
err = NO_ERROR;
|
|
}
|
|
if (err == NO_ERROR) {
|
|
if (fabs(rate.speed) <= 0.000001f && m_currentState == MEDIA_PLAYER_STARTED) {
|
|
m_currentState = MEDIA_PLAYER_PAUSED;
|
|
} else if (fabs(rate.speed) > 0.000001f &&
|
|
(m_currentState == MEDIA_PLAYER_PREPARED ||
|
|
m_currentState == MEDIA_PLAYER_PAUSED ||
|
|
m_currentState == MEDIA_PLAYER_PLAYBACK_COMPLETE)) {
|
|
m_currentState = MEDIA_PLAYER_STARTED;
|
|
}
|
|
}
|
|
} else {
|
|
HLOGE("invalid operation, state=%u", m_currentState);
|
|
return INVALID_OPERATION;
|
|
}
|
|
HLOGI("call %s out, m_currentState=0x%x", __FUNCTION__, m_currentState);
|
|
return err;
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::getDefaultBufferingSettings(NxPlayerBufferingSettings *buffering)
|
|
{
|
|
if (buffering == nullptr) {
|
|
return BAD_VALUE;
|
|
}
|
|
|
|
HLOGI("call %s in", __FUNCTION__);
|
|
if (m_player != nullptr) {
|
|
Parcel requestDefBufSet;
|
|
Parcel replyDefBufSet;
|
|
requestDefBufSet.writeInt32(CMD_GET_DEFAULT_BUFFERING_SETTING);
|
|
requestDefBufSet.setDataPosition(0);
|
|
invoke(requestDefBufSet, &replyDefBufSet);
|
|
replyDefBufSet.setDataPosition(0);
|
|
buffering->mInitialMarkMs = replyDefBufSet.readInt32();
|
|
buffering->mResumePlaybackMarkMs = replyDefBufSet.readInt32();
|
|
HLOGD("call %s out, mInitialMarkMs=%d, mResumePlaybackMarkMs=%d",
|
|
__FUNCTION__, buffering->mInitialMarkMs, buffering->mResumePlaybackMarkMs);
|
|
return NO_ERROR;
|
|
} else {
|
|
return NO_INIT;
|
|
}
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::getBufferingSettings(NxPlayerBufferingSettings *buffering)
|
|
{
|
|
if (buffering == nullptr) {
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
|
|
HLOGI("call %s in", __FUNCTION__);
|
|
if (m_player != nullptr) {
|
|
Parcel requestBufSet;
|
|
Parcel replyBufSet;
|
|
requestBufSet.writeInt32(CMD_GET_BUFFERING_SETTING);
|
|
requestBufSet.setDataPosition(0);
|
|
invoke(requestBufSet, &replyBufSet);
|
|
replyBufSet.setDataPosition(0);
|
|
buffering->mInitialMarkMs = replyBufSet.readInt32();
|
|
buffering->mResumePlaybackMarkMs = replyBufSet.readInt32();
|
|
HLOGD("call %s out, mInitialMarkMs=%d, mResumePlaybackMarkMs=%d",
|
|
__FUNCTION__, buffering->mInitialMarkMs, buffering->mResumePlaybackMarkMs);
|
|
return NO_ERROR;
|
|
} else {
|
|
return NO_INIT;
|
|
}
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::setBufferingSettings(const NxPlayerBufferingSettings &buffering)
|
|
{
|
|
HLOGI("call %s in, mInitialMarkMs=%d, mResumePlaybackMarkMs=%d",
|
|
__FUNCTION__, buffering.mInitialMarkMs, buffering.mResumePlaybackMarkMs);
|
|
|
|
if (m_player != nullptr) {
|
|
Parcel request;
|
|
Parcel reply;
|
|
request.writeInt32(CMD_SET_BUFFERING_SETTING);
|
|
request.writeInt32(buffering.mInitialMarkMs);
|
|
request.writeInt32(buffering.mResumePlaybackMarkMs);
|
|
request.setDataPosition(0);
|
|
status_t ret = invoke(request, &reply);
|
|
HLOGI("call %s out, ret=%d", __FUNCTION__, ret);
|
|
return ret;
|
|
} else {
|
|
return NO_INIT;
|
|
}
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::setAudioStreamType(int streamType)
|
|
{
|
|
HLOGI("call %s out, streamType=%d", __FUNCTION__, streamType);
|
|
return NO_ERROR;
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::notifyAt(int64_t mediaTimeUs)
|
|
{
|
|
HLOGI("call %s, mediaTimeUs=%" PRId64"", __FUNCTION__, mediaTimeUs);
|
|
return NO_ERROR;
|
|
}
|
|
|
|
/* 16: uuid length */
|
|
status_t NxMediaPlayerManage::prepareDrm(const uint8_t uuid[16], const Vector<uint8_t>& drmSessionId)
|
|
{
|
|
HLOGI("call %s", __FUNCTION__);
|
|
(void)uuid;
|
|
(void)drmSessionId;
|
|
return NO_ERROR;
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::releaseDrm()
|
|
{
|
|
return NO_ERROR;
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::SeekToL(int msec)
|
|
{
|
|
if ((m_player.get() != nullptr) && (m_currentState & (static_cast<uint32_t>(MEDIA_PLAYER_STARTED) |
|
|
static_cast<uint32_t>(MEDIA_PLAYER_PREPARED) | static_cast<uint32_t>(MEDIA_PLAYER_PAUSED) |
|
|
static_cast<uint32_t>(MEDIA_PLAYER_PLAYBACK_COMPLETE))) != 0) {
|
|
if (msec < 0) {
|
|
HLOGW("seek to invalid position, msec=%d", msec);
|
|
msec = 0;
|
|
} else if ((m_duration > 0) && (msec > m_duration)) {
|
|
HLOGW("seek to past end of file, msec=%d, mDuration=%d", msec, m_duration);
|
|
msec = m_duration;
|
|
}
|
|
|
|
m_currentPosition = msec; /* cache duration */
|
|
if (m_seekPosition < 0) {
|
|
GetDurationL(nullptr);
|
|
m_seekPosition = msec;
|
|
Return<int32_t> transSeekTo = m_player->seekTo(msec, static_cast<HMediaPlayerSeekMode>(m_seekMode));
|
|
if (!transSeekTo.isOk() || static_cast<int32_t>(transSeekTo) != 0) {
|
|
HLOGE("SeekTo failed");
|
|
}
|
|
return NO_ERROR;
|
|
} else {
|
|
HLOGD("seek in progress - queue up seekTo %d", msec);
|
|
return NO_ERROR;
|
|
}
|
|
}
|
|
|
|
HLOGE("invalid operation, called out state=%u", m_currentState);
|
|
return INVALID_OPERATION;
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::seekTo(int msec, NxPlayerSeekMode mode)
|
|
{
|
|
HLOGI("call %s in, msec=%d, seekMode=%d", __FUNCTION__, msec, mode);
|
|
Mutex::Autolock l(m_lock);
|
|
m_isSeeking = 1;
|
|
m_seekMode = mode;
|
|
status_t ret = SeekToL(msec);
|
|
m_isSeeking = 0;
|
|
|
|
HLOGI("call %s out, ret=%d", __FUNCTION__, ret);
|
|
return ret;
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::CallGetDuration()
|
|
{
|
|
status_t ret = NO_ERROR;
|
|
if (m_player.get() == nullptr) {
|
|
HLOGE("invalid operation, called in state=%u, mPlayer is NULL", m_currentState);
|
|
return INVALID_OPERATION;
|
|
}
|
|
|
|
if (m_duration <= 0) {
|
|
Return<void> transGetDuration = m_player->getDuration(
|
|
[this](int32_t ret, int32_t msec) {
|
|
if (ret != 0) {
|
|
HLOGE("GetDuration failed");
|
|
return;
|
|
}
|
|
m_duration = msec;
|
|
});
|
|
if (!transGetDuration.isOk()) {
|
|
HLOGE("GetDuration failed");
|
|
ret = UNKNOWN_ERROR;
|
|
} else {
|
|
HLOGD("call %s out, duration=%d", __FUNCTION__, m_duration);
|
|
ret = NO_ERROR;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::getCurrentPosition(int *millisecond)
|
|
{
|
|
Mutex::Autolock l(m_lock);
|
|
status_t ret = NO_ERROR;
|
|
|
|
if (m_player.get() == nullptr || millisecond == nullptr) {
|
|
HLOGE("invalid operation, called in state=%u, mPlayer or millisecond is NULL", m_currentState);
|
|
return INVALID_OPERATION;
|
|
}
|
|
|
|
if (m_currentPosition >= 0) {
|
|
HLOGD("call %s out, cached seek position %d", __FUNCTION__, m_currentPosition);
|
|
*millisecond = m_currentPosition;
|
|
return NO_ERROR;
|
|
}
|
|
|
|
if ((m_currentState & static_cast<uint32_t>(MEDIA_PLAYER_PLAYBACK_COMPLETE)) != 0) {
|
|
ret = CallGetDuration();
|
|
*millisecond = m_duration;
|
|
return ret;
|
|
}
|
|
Return<void> transGetCurrentPosition = m_player->getCurrentPosition(
|
|
[&millisecond, this](int32_t ret, int32_t hidlMsec) {
|
|
if (ret != 0) {
|
|
HLOGE("GetCurrentPosition failed");
|
|
return;
|
|
}
|
|
*millisecond = hidlMsec;
|
|
});
|
|
if (!transGetCurrentPosition.isOk()) {
|
|
HLOGE("GetCurrentPosition failed");
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::GetDurationL(int *msec)
|
|
{
|
|
if ((m_player.get() != nullptr) && (m_currentState & (static_cast<uint32_t>(MEDIA_PLAYER_PREPARED) |
|
|
static_cast<uint32_t>(MEDIA_PLAYER_STARTED) | static_cast<uint32_t>(MEDIA_PLAYER_PAUSED) |
|
|
static_cast<uint32_t>(MEDIA_PLAYER_STOPPED) |
|
|
static_cast<uint32_t>(MEDIA_PLAYER_PLAYBACK_COMPLETE))) != 0) {
|
|
status_t ret = NO_ERROR;
|
|
ret = CallGetDuration();
|
|
|
|
if (msec != nullptr) {
|
|
*msec = m_duration;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
HLOGE("invalid operation, called out state=%u", m_currentState);
|
|
return INVALID_OPERATION;
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::getDuration(int *msec)
|
|
{
|
|
HLOGD("call %s in", __FUNCTION__);
|
|
Mutex::Autolock l(m_lock);
|
|
status_t ret = GetDurationL(msec);
|
|
if (msec != nullptr) {
|
|
HLOGD("call %s out, msec=%d", __FUNCTION__, *msec);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::ResetL()
|
|
{
|
|
m_loop = false;
|
|
if (m_currentState == MEDIA_PLAYER_IDLE) {
|
|
return NO_ERROR;
|
|
}
|
|
|
|
if (m_currentState != MEDIA_PLAYER_STOPPED) {
|
|
Parcel parcelObj;
|
|
parcelObj.setData(nullptr, 0);
|
|
PostMsg(MEDIA_STOPPED, 0, 0, parcelObj);
|
|
}
|
|
|
|
m_prepareSync = false;
|
|
status_t ret = NO_ERROR;
|
|
if (m_player.get() != nullptr) {
|
|
Return<int32_t> transRest = m_player->reset();
|
|
if (!transRest.isOk() || static_cast<int32_t>(transRest) != 0) {
|
|
HLOGE("SetVolume failed");
|
|
ret = UNKNOWN_ERROR;
|
|
} else {
|
|
ret = NO_ERROR;
|
|
}
|
|
if (ret != NO_ERROR) {
|
|
HLOGE("reset failed");
|
|
m_currentState = MEDIA_PLAYER_STATE_ERROR;
|
|
} else {
|
|
m_currentState = MEDIA_PLAYER_IDLE;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
Clear();
|
|
return NO_ERROR;
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::reset()
|
|
{
|
|
HLOGI("call %s in", __FUNCTION__);
|
|
bool isBlackMode = SwitchModeIsBlack();
|
|
Mutex::Autolock l(m_lock);
|
|
if (IsUseSidebandMode() && isBlackMode) {
|
|
SetSidebandHandle(nullptr);
|
|
}
|
|
status_t ret = ResetL();
|
|
if (m_callback != nullptr) {
|
|
m_callback->SetMediaCallBack(nullptr);
|
|
}
|
|
if (m_nxMsg.get() != nullptr) {
|
|
m_nxMsg->EnableNxMediaMsg(false);
|
|
}
|
|
|
|
HLOGI("call %s out, ret=%d", __FUNCTION__, ret);
|
|
return ret;
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::setLooping(int loop)
|
|
{
|
|
HLOGI("call %s in, loop=%d", __FUNCTION__, loop);
|
|
Mutex::Autolock l(m_lock);
|
|
m_loop = (loop != 0);
|
|
if (m_player != nullptr) {
|
|
Return<int32_t> transSetLooping = m_player->setLooping(loop);
|
|
if (!transSetLooping.isOk() || static_cast<int32_t>(transSetLooping) != 0) {
|
|
HLOGE("SetLooping failed");
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
}
|
|
HLOGI("call %s out", __FUNCTION__);
|
|
|
|
return OK;
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::setVolume(float leftVolume, float rightVolume)
|
|
{
|
|
HLOGI("call %s in, leftVolume=%.2f, rightVolume=%.2f", __FUNCTION__, leftVolume, rightVolume);
|
|
Mutex::Autolock l(m_lock);
|
|
|
|
if (m_player.get() != nullptr) {
|
|
Return<int32_t> transSetVolume = m_player->setVolume(leftVolume, rightVolume);
|
|
if (!transSetVolume.isOk() || static_cast<int32_t>(transSetVolume) != 0) {
|
|
HLOGE("SetVolume failed");
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
}
|
|
HLOGI("call %s out", __FUNCTION__);
|
|
|
|
return OK;
|
|
}
|
|
|
|
bool NxMediaPlayerManage::isLooping()
|
|
{
|
|
HLOGI("call %s in", __FUNCTION__);
|
|
Mutex::Autolock l(m_lock);
|
|
if (m_player.get() != nullptr) {
|
|
HLOGD("call %s out, mLoop = %d", __FUNCTION__, m_loop);
|
|
return m_loop;
|
|
}
|
|
|
|
HLOGW("isLooping: no active player");
|
|
return false;
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::InvokeGetTrackInfo(const Parcel &request __unused, Parcel *reply)
|
|
{
|
|
const bool hasBeenInitialized = (m_currentState != MEDIA_PLAYER_STATE_ERROR) &&
|
|
((m_currentState & static_cast<uint32_t>(MEDIA_PLAYER_IDLE)) != MEDIA_PLAYER_IDLE);
|
|
|
|
HLOGD("hasBeenInitialized=%d", hasBeenInitialized);
|
|
if ((m_player.get() != nullptr) && hasBeenInitialized) {
|
|
getTrackInfo(reply);
|
|
}
|
|
return NO_ERROR;
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::AddSubtitle(int fd, int subFd, int64_t offset, int64_t length,
|
|
const hidl_string &mime) const
|
|
{
|
|
int numFds = 1;
|
|
if (subFd >= 0) {
|
|
numFds++;
|
|
}
|
|
native_handle_t* const nativeHdl = native_handle_create(numFds, 0);
|
|
if (nativeHdl == nullptr) {
|
|
HLOGE("nativeHdl is null");
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
|
|
nativeHdl->data[0] = fd;
|
|
if (numFds > 1) {
|
|
nativeHdl->data[1] = subFd;
|
|
}
|
|
hidl_handle fdHandle;
|
|
fdHandle.setTo(nativeHdl, false);
|
|
|
|
Return<int32_t> transAddTimedTextSource = m_player->addTimedTextSource(fdHandle, offset, length, mime);
|
|
(void)native_handle_delete(nativeHdl);
|
|
|
|
if (!transAddTimedTextSource.isOk() || static_cast<int32_t>(transAddTimedTextSource) != 0) {
|
|
HLOGE("AddTimedTextSource failed");
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
return NO_ERROR;
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::InvokeAddExternalSource(const Parcel &request __unused, Parcel *reply __unused) const
|
|
{
|
|
HLOGD("%s", __FUNCTION__);
|
|
return NO_ERROR;
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::InvokeAddExternalSourceFd(const Parcel &request, Parcel *reply __unused) const
|
|
{
|
|
if (m_player.get() == nullptr) {
|
|
return NO_INIT;
|
|
}
|
|
|
|
HLOGD("%s", __FUNCTION__);
|
|
/* Parcel --> hidl_string */
|
|
int fd = request.readFileDescriptor();
|
|
int64_t offset = request.readInt64();
|
|
int64_t length = request.readInt64();
|
|
String8 mimeType(request.readString16());
|
|
hidl_string mime(mimeType.c_str());
|
|
char url[PATH_MAX] = {};
|
|
int subFd = INVALID_FD;
|
|
if (GetUrlFromFd(fd, url, PATH_MAX) == NO_ERROR) {
|
|
CheckIdxSub(String8(url), subFd);
|
|
}
|
|
|
|
status_t ret = AddSubtitle(fd, subFd, offset, length, mime);
|
|
if (subFd >= 0) {
|
|
close(subFd);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::InvokeSetExtSubtitleFile(const Parcel &request, Parcel *reply __unused) const
|
|
{
|
|
if (m_player.get() == nullptr) {
|
|
return NO_INIT;
|
|
}
|
|
|
|
hidl_handle fdHandle;
|
|
int idxFd = INVALID_FD;
|
|
int64_t idxOffset = 0;
|
|
int64_t idxLength = 0;
|
|
int subFd = INVALID_FD;
|
|
|
|
int subCount = request.readInt32();
|
|
HLOGI("ExtSubtitleFile Count:%d", subCount);
|
|
for (int i = 0; i < subCount; i++) {
|
|
int fd = request.readFileDescriptor();
|
|
int64_t offset = request.readInt64();
|
|
int64_t length = request.readInt64();
|
|
String8 suffix(request.readString16());
|
|
if (strcasecmp(suffix, "idx") == 0) {
|
|
idxFd = fd;
|
|
idxOffset = offset;
|
|
idxLength = length;
|
|
continue;
|
|
} else if (strcasecmp(suffix, "sub") == 0) {
|
|
subFd = fd;
|
|
}
|
|
status_t ret = AddSubtitle(fd, INVALID_FD, offset, length, nullptr);
|
|
if (ret != NO_ERROR) {
|
|
HLOGE("etExtSubtitleFile fd:%d offset:%lld length:%lld", fd, offset, length);
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
}
|
|
if (idxFd != -1 && subFd != -1) {
|
|
status_t ret = AddSubtitle(idxFd, subFd, idxOffset, idxLength, nullptr);
|
|
if (ret != NO_ERROR) {
|
|
HLOGE("etExtSubtitleFile fd:%d offset:%lld length:%lld", idxFd, idxOffset, idxLength);
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
}
|
|
return NO_ERROR;
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::InvokeSelectTrack(const Parcel &request, Parcel *reply __unused) const
|
|
{
|
|
if (m_player.get() == nullptr) {
|
|
return NO_INIT;
|
|
}
|
|
|
|
int tracksIndex = request.readInt32();
|
|
HLOGD("%s, tracksIndex=%d", __FUNCTION__, tracksIndex);
|
|
Return<int32_t> transSelectTrack = m_player->selectTrack(tracksIndex, true);
|
|
if (!transSelectTrack.isOk() || static_cast<int32_t>(transSelectTrack) != 0) {
|
|
HLOGE("SelectTrack failed");
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
return NO_ERROR;
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::InvokeUnSelectTrack(const Parcel &request, Parcel *reply __unused) const
|
|
{
|
|
if (m_player.get() == nullptr) {
|
|
return NO_INIT;
|
|
}
|
|
|
|
int tracksIndex = request.readInt32();
|
|
HLOGD("%s, tracksIndex=%d", __FUNCTION__, tracksIndex);
|
|
Return<int32_t> transSelectTrack = m_player->selectTrack(tracksIndex, false);
|
|
if (!transSelectTrack.isOk() || static_cast<int32_t>(transSelectTrack) != 0) {
|
|
HLOGE("SelectTrack failed");
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
return NO_ERROR;
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::InvokeSetVidScalMode(const Parcel &request, Parcel *reply __unused) const
|
|
{
|
|
if (m_player.get() == nullptr) {
|
|
return NO_INIT;
|
|
}
|
|
|
|
int scalingMode = request.readInt32();
|
|
HLOGD("%s, scalingMode=%d", __FUNCTION__, scalingMode);
|
|
Return<int32_t> transSetVideoScaling = m_player->setVideoScaling(scalingMode);
|
|
if (!transSetVideoScaling.isOk() || static_cast<int32_t>(transSetVideoScaling) != 0) {
|
|
HLOGE("transSetVideoScaling failed");
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
return NO_ERROR;
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::InvokeGetSelectedTrack(const Parcel &request, Parcel *reply) const
|
|
{
|
|
if (m_player.get() == nullptr) {
|
|
return NO_INIT;
|
|
}
|
|
|
|
int type = request.readInt32();
|
|
Return<void> transGetSelectedTrack = m_player->getSelectedTrack(
|
|
type,
|
|
[&reply, this](int32_t ret, const hidl_string &replyString) {
|
|
if (ret != 0) {
|
|
HLOGE("GetDefaultBufferingSettings failed");
|
|
return;
|
|
}
|
|
if (reply != nullptr) {
|
|
reply->setData(reinterpret_cast<const uint8_t *>(replyString.c_str()), replyString.size());
|
|
}
|
|
});
|
|
if (!transGetSelectedTrack.isOk()) {
|
|
HLOGE("GetSelectedTrack failed");
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
return NO_ERROR;
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::setSubSurface(const sp<HGraphicBufferProducer> &bufferProducer)
|
|
{
|
|
/* add for androidp: surface.writeToParcel is changed */
|
|
HLOGI("call %s in", __FUNCTION__);
|
|
if (m_player.get() == nullptr) {
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
Return<int32_t> transSetSubSurface = m_player->setSubtitleSurface(bufferProducer, 1);
|
|
if (!transSetSubSurface.isOk() || static_cast<int32_t>(transSetSubSurface) != 0) {
|
|
HLOGE("SetSubSurface failed");
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
HLOGI("call %s out", __FUNCTION__);
|
|
return NO_ERROR;
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::TransInvoke(const Parcel &request, Parcel *reply, uint32_t currentPos) const
|
|
{
|
|
request.setDataPosition(currentPos);
|
|
hidl_string requestString(reinterpret_cast<const char *>(request.data()) + currentPos,
|
|
request.dataSize() - currentPos);
|
|
Return<void> transInvoke = m_player->invoke(
|
|
requestString,
|
|
[&reply, this](int32_t ret, const hidl_string &replyString) {
|
|
if (ret != 0) {
|
|
HLOGE("GetDefaultBufferingSettings failed");
|
|
return;
|
|
}
|
|
if (reply != nullptr) {
|
|
reply->setData(reinterpret_cast<const uint8_t *>(replyString.c_str()), replyString.size());
|
|
}
|
|
});
|
|
if (!transInvoke.isOk()) {
|
|
HLOGE("Invoke failed");
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::invoke(const Parcel &request, Parcel *reply)
|
|
{
|
|
Mutex::Autolock l(m_lock);
|
|
const bool hasBeenInitialized = (m_currentState != MEDIA_PLAYER_STATE_ERROR) &&
|
|
((m_currentState & static_cast<uint32_t>(MEDIA_PLAYER_IDLE)) != MEDIA_PLAYER_IDLE);
|
|
size_t currentPos = request.dataPosition();
|
|
int invokeId = request.readInt32();
|
|
/* do not support android invoke now,android invoke is conflict with nxplayer invoke id */
|
|
HLOGI("call %s in, invokeId=%d, currentPos:%d-%zu-%zu",
|
|
__FUNCTION__, invokeId, currentPos, request.dataPosition(), request.dataSize());
|
|
switch (invokeId) {
|
|
case INVOKE_ID_GET_TRACK_INFO:
|
|
return InvokeGetTrackInfo(request, reply);
|
|
/* INVOKE_ID_ADD_EXTERNAL_SOURCE and INVOKE_ID_ADD_EXTERNAL_SOURCE_FD using same code */
|
|
case INVOKE_ID_ADD_EXTERNAL_SOURCE:
|
|
InvokeAddExternalSource(request, reply);
|
|
break;
|
|
case INVOKE_ID_ADD_EXTERNAL_SOURCE_FD:
|
|
return InvokeAddExternalSourceFd(request, reply);
|
|
case INVOKE_ID_SELECT_TRACK:
|
|
return InvokeSelectTrack(request, reply);
|
|
case INVOKE_ID_UNSELECT_TRACK:
|
|
return InvokeUnSelectTrack(request, reply);
|
|
case INVOKE_ID_SET_VIDEO_SCALING_MODE:
|
|
return InvokeSetVidScalMode(request, reply);
|
|
case INVOKE_ID_GET_SELECTED_TRACK:
|
|
return InvokeGetSelectedTrack(request, reply);
|
|
case INVOKE_ID_SET_EXT_SUBTITLE_FILE:
|
|
return InvokeSetExtSubtitleFile(request, reply);
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if ((m_player.get() != nullptr) && hasBeenInitialized) {
|
|
status_t ret = TransInvoke(request, reply, currentPos);
|
|
HLOGI("call %s out, invokeId=%d, ret=%d", __FUNCTION__, invokeId, ret);
|
|
return ret;
|
|
}
|
|
HLOGW("invalid operation, call invoke under wrong state %X", m_currentState);
|
|
return INVALID_OPERATION;
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::setParameter(int key, const Parcel &request)
|
|
{
|
|
HLOGI("call %s in, key=%d", __FUNCTION__, key);
|
|
switch (key) {
|
|
case KEY_PARAMETER_PLAYBACK_RATE_PERMILLE: {
|
|
if (m_player.get() == nullptr) {
|
|
HLOGE("m_player is null");
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
hidl_string requestStr(reinterpret_cast<const char *>(request.data()), request.dataSize());
|
|
Return<int32_t> transSetParameter = m_player->setParameter(key, requestStr);
|
|
if (!transSetParameter.isOk() || static_cast<int32_t>(transSetParameter) != 0) {
|
|
HLOGE("SetParameter failed");
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
return OK;
|
|
}
|
|
default: {
|
|
HLOGI("unsupport setParameter key=%d", key);
|
|
}
|
|
}
|
|
HLOGI("call %s out", __FUNCTION__);
|
|
return OK;
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::getParameter(int key, Parcel *reply)
|
|
{
|
|
HLOGI("call %s in, key=%d", __FUNCTION__, key);
|
|
if (m_player.get() == nullptr || reply == nullptr) {
|
|
HLOGE("m_player or reply is NULL");
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
|
|
int32_t retVal = 0;
|
|
Return<void> transGetParameter = m_player->getParameter(
|
|
key,
|
|
[&reply, &retVal, this](int32_t ret, const hidl_string &replyString) {
|
|
retVal = ret;
|
|
if (ret != 0) {
|
|
HLOGE("GetParameter failed");
|
|
return;
|
|
}
|
|
reply->setData(reinterpret_cast<const uint8_t *>(replyString.c_str()), replyString.size());
|
|
});
|
|
if (!transGetParameter.isOk() || retVal != 0) {
|
|
HLOGE("GetParameter failed");
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
HLOGI("call %s out", __FUNCTION__);
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::getMetadata(Parcel *records)
|
|
{
|
|
HLOGI("call %s in", __FUNCTION__);
|
|
Mutex::Autolock lock(m_lock);
|
|
status_t ret;
|
|
if (m_player.get() == nullptr) {
|
|
return NO_INIT;
|
|
}
|
|
|
|
if (records == nullptr) {
|
|
return BAD_VALUE;
|
|
}
|
|
|
|
Return<void> transGetMetadata = m_player->getMetadata(
|
|
[&records, this](int32_t ret, const hidl_string &recordsString) {
|
|
if (ret != 0) {
|
|
HLOGE("GetMetadata failed");
|
|
return;
|
|
}
|
|
records->write(recordsString.c_str(), recordsString.size());
|
|
});
|
|
if (!transGetMetadata.isOk()) {
|
|
HLOGE("GetMetadata failed");
|
|
ret = UNKNOWN_ERROR;
|
|
} else {
|
|
ret = OK;
|
|
}
|
|
if (ret != OK) {
|
|
records->writeInt32(ret);
|
|
return ret;
|
|
}
|
|
HLOGI("call %s out, ret=%d", __FUNCTION__, ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::dump(int fd, const Vector<String16> &args)
|
|
{
|
|
(void)fd;
|
|
(void)args;
|
|
return 0;
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::setUID(int uid)
|
|
{
|
|
(void)uid;
|
|
return 0;
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::GetUrlFromFd(int fd, char *url, int urlLen) const
|
|
{
|
|
char path[PATH_MAX] = {0};
|
|
int ret = snprintf_s(path, PATH_MAX, PATH_MAX - 1, "/proc/%d/fd/%d", getpid(), fd);
|
|
if (ret < 0) {
|
|
HLOGE("snprintf_s failed");
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
|
|
ret = readlink(path, url, urlLen - 1);
|
|
if (ret < 0 || ret > urlLen - 1) {
|
|
HLOGE("readlink failed, path=%s, ret=%d", path, ret);
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
void NxMediaPlayerManage::ScanExtSubPath(const char *path, struct dirent **fileList, const char *prefixName,
|
|
int fileNum)
|
|
{
|
|
char *p = nullptr;
|
|
char subUrl[PATH_MAX] = {0};
|
|
if (path == nullptr || fileList == nullptr || prefixName == nullptr) {
|
|
return;
|
|
}
|
|
unsigned int pathLen = strlen(path);
|
|
unsigned int prefixNameLen = strlen(prefixName);
|
|
int ret = 0;
|
|
|
|
for (int i = 0; i < fileNum; i++) {
|
|
if (strncasecmp(prefixName, fileList[i]->d_name, prefixNameLen) != 0) {
|
|
free(fileList[i]);
|
|
fileList[i] = nullptr;
|
|
continue;
|
|
}
|
|
/* type of this file, as "srt", not include character '.' */
|
|
p = strrchr(fileList[i]->d_name, '.');
|
|
if (p == nullptr) {
|
|
continue;
|
|
}
|
|
|
|
p++;
|
|
|
|
if (IsSubSuffixName(p)) {
|
|
if ((pathLen + strlen(fileList[i]->d_name)) >= PATH_MAX) {
|
|
HLOGW("%s + %s is too long", path, fileList[i]->d_name);
|
|
continue;
|
|
}
|
|
|
|
ret = snprintf_s(subUrl, PATH_MAX, PATH_MAX - 1, "%s%s", path, fileList[i]->d_name);
|
|
if (ret < 0) {
|
|
HLOGE("snprintf_s failed");
|
|
continue;
|
|
}
|
|
m_extSubUrl.push_back(String8(subUrl));
|
|
}
|
|
free(fileList[i]);
|
|
fileList[i] = nullptr;
|
|
}
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::ScanExtSubFile(const char *path, unsigned int pathLenMax, const char *prefixName,
|
|
unsigned int nameLenMax)
|
|
{
|
|
DIR *dirp = nullptr;
|
|
int fileNum;
|
|
struct dirent **fileList = nullptr;
|
|
|
|
unsigned int pathLen = strlen(path);
|
|
unsigned int prefixNameLen = strlen(prefixName);
|
|
if (pathLen >= pathLenMax || prefixNameLen >= nameLenMax) {
|
|
HLOGE("memory overread!");
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
|
|
dirp = opendir(path);
|
|
if (dirp == nullptr) {
|
|
HLOGE("open dir=* failed");
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
|
|
fileNum = scandir(path, &fileList, nullptr, alphasort);
|
|
if (fileNum < 0) {
|
|
HLOGE("scan dir=* failed");
|
|
closedir(dirp);
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
|
|
ScanExtSubPath(path, fileList, prefixName, fileNum);
|
|
|
|
free(fileList);
|
|
closedir(dirp);
|
|
|
|
return OK;
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::FindExtSubTitleFromUrl(const char *url, int len __unused)
|
|
{
|
|
char path[PATH_MAX] = {0};
|
|
char prefixName[PATH_MAX] = {0};
|
|
|
|
const char *p = strrchr(url, '/');
|
|
if (p == nullptr) {
|
|
HLOGE("stream path error.");
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
|
|
p++;
|
|
int pathLen = p - url;
|
|
|
|
p = strrchr(url + pathLen, '.');
|
|
if (p == nullptr) {
|
|
HLOGE("stream has no suffix.");
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
|
|
p++;
|
|
int prefixNameLen = p - url - pathLen;
|
|
|
|
int ret = strncpy_s(path, sizeof(path), url, pathLen);
|
|
if (ret != EOK) {
|
|
HLOGE("strncpy_s failed");
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
|
|
ret = strncpy_s(prefixName, sizeof(prefixName), url + pathLen, prefixNameLen);
|
|
if (ret != EOK) {
|
|
HLOGE("strncpy_s failed");
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
|
|
return ScanExtSubFile(path, PATH_MAX, prefixName, PATH_MAX);
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::AddTimedTextSource(const char *subUrl) const
|
|
{
|
|
HLOGD("%s", __FUNCTION__);
|
|
if (m_player.get() == nullptr) {
|
|
HLOGW("player is not init");
|
|
return NO_INIT;
|
|
}
|
|
|
|
char subRealUrl[PATH_MAX] = {0};
|
|
if (realpath(subUrl, subRealUrl) == nullptr) {
|
|
HLOGW("realpath failed, subUrl=*");
|
|
return INVALID_OPERATION;
|
|
}
|
|
|
|
int fd = open(subRealUrl, O_RDONLY);
|
|
if (fd < 0) {
|
|
char errbuf[ERR_BUF_LEN] = {0};
|
|
HLOGW("open subRealUrl=* failed, %s", strerror_r(errno, errbuf, sizeof(errbuf)));
|
|
return INVALID_OPERATION;
|
|
}
|
|
|
|
int subFd = INVALID_FD; /* -1 is invalid fd */
|
|
CheckIdxSub(String8(subRealUrl), subFd);
|
|
|
|
int64_t length = lseek64(fd, 0, SEEK_END);
|
|
status_t ret = AddSubtitle(fd, subFd, 0, length, nullptr);
|
|
close(fd);
|
|
if (subFd >= 0) {
|
|
close(subFd);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void NxMediaPlayerManage::NotifyMediaPrepared()
|
|
{
|
|
HLOGI("notify prepared");
|
|
m_currentState = MEDIA_PLAYER_PREPARED;
|
|
if (m_prepareSync) {
|
|
HLOGD("signal application thread player prepared");
|
|
m_prepareSync = false;
|
|
m_prepareStatus = NO_ERROR;
|
|
m_signal.signal();
|
|
}
|
|
}
|
|
|
|
void NxMediaPlayerManage::NotifyPlayBackComplete()
|
|
{
|
|
HLOGI("notify play complete");
|
|
if (m_currentState == MEDIA_PLAYER_IDLE) {
|
|
HLOGE("playback complete in idle state");
|
|
}
|
|
/* MEDIA_PLAYBACK_COMPLETE and mCurrentPosition >=0 reset mCurrentPosition = mSeekPosition = -1 */
|
|
if (m_seekPosition >= 0) {
|
|
m_currentPosition = m_seekPosition = -1;
|
|
}
|
|
if (!m_loop) {
|
|
m_currentState = MEDIA_PLAYER_PLAYBACK_COMPLETE;
|
|
}
|
|
}
|
|
|
|
void NxMediaPlayerManage::NotifyMediaError(const int &ext1, const int &ext2)
|
|
{
|
|
/*
|
|
* Always log errors.
|
|
* ext1: Media framework error code.
|
|
* ext2: Implementation dependant error code.
|
|
*/
|
|
HLOGE("notify media error (%d, %d)", ext1, ext2);
|
|
m_currentState = MEDIA_PLAYER_STATE_ERROR;
|
|
if (m_prepareSync) {
|
|
HLOGD("signal application thread");
|
|
m_prepareSync = false;
|
|
m_prepareStatus = ext1;
|
|
m_signal.signal();
|
|
}
|
|
}
|
|
|
|
void NxMediaPlayerManage::NotifyMediaInfo(int &ext1, const int &ext2)
|
|
{
|
|
/*
|
|
* ext1: Media framework error code.
|
|
* ext2: Implementation dependant error code.
|
|
*/
|
|
if (ext1 != MEDIA_INFO_VIDEO_TRACK_LAGGING) {
|
|
HLOGI("notify media info/warning (%d, %d)", ext1, ext2);
|
|
}
|
|
|
|
if (ext1 == MEDIA_INFO_RMEVENT_CB && ext2 == 1 && IsUseSidebandMode()) {
|
|
HLOGI("mircast un SidebandHandle");
|
|
SetSidebandHandle(nullptr); /* ext2 == 1 means mircast, un sideband */
|
|
}
|
|
}
|
|
|
|
void NxMediaPlayerManage::NotifySeekComplete()
|
|
{
|
|
HLOGI("notify seek complete");
|
|
if (m_seekPosition != m_currentPosition) {
|
|
HLOGD("executing queued seekTo(%d)", m_seekPosition);
|
|
m_seekPosition = -1;
|
|
SeekToL(m_currentPosition);
|
|
} else {
|
|
HLOGI("all seeks complete, seekPosition=%d", m_seekPosition);
|
|
m_currentPosition = m_seekPosition = -1;
|
|
}
|
|
}
|
|
|
|
void NxMediaPlayerManage::NotifySetVidSize(const int &ext1, const int &ext2)
|
|
{
|
|
HLOGI("notify video size, %d x %d ", ext1, ext2);
|
|
m_videoWidth = ext1;
|
|
m_videoHeight = ext2;
|
|
}
|
|
|
|
void NxMediaPlayerManage::NotifyFastForwordComplete()
|
|
{
|
|
HLOGI("notify fast forword complete");
|
|
if (!m_loop) {
|
|
/*
|
|
* while the fast backword complete,
|
|
* the player should start auto to play reset the media player state.
|
|
*/
|
|
m_currentState = MEDIA_PLAYER_PLAYBACK_COMPLETE;
|
|
}
|
|
}
|
|
|
|
void NxMediaPlayerManage::NotifyFastBackwordComplete()
|
|
{
|
|
HLOGI("notify fast back forword complete");
|
|
if (!m_loop) {
|
|
/*
|
|
* while the fast backword complete,
|
|
* the player should start auto to play reset the media player state
|
|
*/
|
|
m_currentState = MEDIA_PLAYER_STARTED;
|
|
}
|
|
}
|
|
|
|
void NxMediaPlayerManage::notifyFunc(int msg, int ext1, int ext2, const Parcel *obj)
|
|
{
|
|
switch (msg) {
|
|
case MEDIA_NOP: /* interface test message */
|
|
break;
|
|
case MEDIA_PREPARED:
|
|
NotifyMediaPrepared();
|
|
break;
|
|
case MEDIA_PLAYBACK_COMPLETE:
|
|
NotifyPlayBackComplete();
|
|
break;
|
|
case MEDIA_ERROR:
|
|
NotifyMediaError(ext1, ext2);
|
|
break;
|
|
case MEDIA_INFO:
|
|
NotifyMediaInfo(ext1, ext2);
|
|
break;
|
|
case MEDIA_SEEK_COMPLETE:
|
|
NotifySeekComplete();
|
|
break;
|
|
case MEDIA_BUFFERING_UPDATE:
|
|
HLOGD("notify buffering %d", ext1);
|
|
break;
|
|
case MEDIA_SET_VIDEO_SIZE:
|
|
NotifySetVidSize(ext1, ext2);
|
|
break;
|
|
case MEDIA_TIMED_TEXT:
|
|
HLOGD("notify timed text");
|
|
break;
|
|
case MEDIA_FAST_FORWORD_COMPLETE:
|
|
NotifyFastForwordComplete();
|
|
break;
|
|
case MEDIA_FAST_BACKWORD_COMPLETE:
|
|
NotifyFastBackwordComplete();
|
|
break;
|
|
default:
|
|
HLOGD("notify message: (%d, %d, %d)", msg, ext1, ext2);
|
|
break;
|
|
}
|
|
|
|
sendEvent(msg, ext1, ext2, obj);
|
|
}
|
|
|
|
void NxMediaPlayerManage::notify(NxMediaPlayerManage *cookie, int msg, int ext1, int ext2, const Parcel *obj)
|
|
{
|
|
NxMediaPlayerManage *pthis = cookie;
|
|
if (pthis == nullptr) {
|
|
ALOGE("[*][%s:%d]: invalid operation, player cookie is null, notify failed",
|
|
__FUNCTION__, __LINE__);
|
|
return;
|
|
}
|
|
|
|
pthis->notifyFunc(msg, ext1, ext2, obj);
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::AttachNewPlayer(const sp<INxMediaPlayer> &player)
|
|
{
|
|
status_t err = UNKNOWN_ERROR;
|
|
|
|
sp<INxMediaPlayer> p;
|
|
{
|
|
Mutex::Autolock l(m_lock); /* scope for the lock */
|
|
|
|
if (!((m_currentState & static_cast<uint32_t>(MEDIA_PLAYER_IDLE)) != 0 ||
|
|
(m_currentState == MEDIA_PLAYER_STATE_ERROR))) {
|
|
HLOGE("invalid operation, called state=%u", m_currentState);
|
|
return INVALID_OPERATION;
|
|
}
|
|
|
|
Clear();
|
|
p = m_player;
|
|
m_player = player;
|
|
if (player != nullptr) {
|
|
m_currentState = MEDIA_PLAYER_INITIALIZED;
|
|
err = NO_ERROR;
|
|
} else {
|
|
HLOGE("unable to create player");
|
|
}
|
|
}
|
|
if (p != nullptr && p != player) {
|
|
p.clear();
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
sp<INxMediaPlayer> NxMediaPlayerManage::CreatePlayer()
|
|
{
|
|
sp<INxMediaPlayer> p = m_player;
|
|
if (p.get() != nullptr) {
|
|
p.clear();
|
|
}
|
|
|
|
if (p.get() != nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
HLOGD("call %s in", __FUNCTION__);
|
|
m_playerStore = INxMediaPlayerStore::getService();
|
|
if (m_playerStore.get() == nullptr) {
|
|
HLOGE("getService INxMediaPlayerStore failed");
|
|
return nullptr;
|
|
}
|
|
|
|
Return<void> transCreate = m_playerStore->createNxMediaPlayer(
|
|
[&p, this](int32_t status, const sp<INxMediaPlayer> &comp) {
|
|
if (status != 0) {
|
|
HLOGE("INxMediaPlayerStore createNxMediaPlayer failed");
|
|
return;
|
|
}
|
|
p = comp;
|
|
});
|
|
if (p.get() == nullptr || !transCreate.isOk()) {
|
|
HLOGE("get INxMediaPlayer failed");
|
|
return nullptr;
|
|
}
|
|
|
|
if (p->init() == NO_ERROR) {
|
|
m_callback = new MediaCallBack(this, m_instIdx);
|
|
if (m_callback != nullptr) {
|
|
p->setNotifyCallback(m_callback);
|
|
}
|
|
} else {
|
|
p.clear();
|
|
}
|
|
|
|
HLOGD("call out");
|
|
return p;
|
|
}
|
|
|
|
void NxMediaPlayerManage::Clear()
|
|
{
|
|
m_duration = -1;
|
|
m_currentPosition = -1;
|
|
m_seekPosition = -1;
|
|
m_seekMode = NxPlayerSeekMode::NX_PLAYER_SEEK_PRE_KEY;
|
|
m_videoWidth = 0;
|
|
m_videoHeight = 0;
|
|
}
|
|
|
|
bool NxMediaPlayerManage::IsSubSuffixName(const char *name) const
|
|
{
|
|
for (auto it = g_extSubSuffixName.begin(); it != g_extSubSuffixName.end(); it++) {
|
|
if (strcasecmp(name, (*it).c_str()) == 0) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
bool NxMediaPlayerManage::CheckIdxSub(String8 idxFileUrl, int &subFd) const
|
|
{
|
|
if (idxFileUrl.length() <= 0) {
|
|
return false;
|
|
}
|
|
|
|
if (idxFileUrl.getPathExtension() != ".idx") {
|
|
return false;
|
|
}
|
|
|
|
String8 subFileUrl;
|
|
int i = 0;
|
|
int fd = INVALID_FD;
|
|
char subRealUrl[PATH_MAX] = {0};
|
|
|
|
while (i < IDXSUB_EXTS_LEN && strlen(IDXSUB_EXTS[i]) != 0) {
|
|
subFileUrl = idxFileUrl.getBasePath() + "." + IDXSUB_EXTS[i];
|
|
if (realpath(subFileUrl.c_str(), subRealUrl) == nullptr) {
|
|
HLOGW("realpath failed, subUrl=*");
|
|
i++;
|
|
continue;
|
|
}
|
|
fd = open(subRealUrl, O_RDONLY);
|
|
if (fd >= 0) {
|
|
HLOGD("find sub file, fd=%d", fd);
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
|
|
if (fd < 0) {
|
|
return false;
|
|
}
|
|
subFd = fd;
|
|
|
|
return true;
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::ProcessScreenOrient() const
|
|
{
|
|
const bool hasBeenInitialized = (m_currentState != MEDIA_PLAYER_STATE_ERROR) &&
|
|
((m_currentState & static_cast<uint32_t>(MEDIA_PLAYER_IDLE)) != MEDIA_PLAYER_IDLE);
|
|
char bufferOrientation[PROPERTY_VALUE_MAX] = {0};
|
|
int rotation = 0;
|
|
const int vIdRotation0 = 0;
|
|
const int vIdRotation90 = 90;
|
|
const int vIdRotation180 = 180;
|
|
const int vIdRotation270 = 270;
|
|
|
|
/* home version properity */
|
|
PropertyGet("ro.panel.hw_orientation", bufferOrientation, sizeof(bufferOrientation), nullptr);
|
|
if (strcmp("0", bufferOrientation) == 0) {
|
|
rotation = vIdRotation0;
|
|
} else if (strcmp("90", bufferOrientation) == 0) {
|
|
rotation = vIdRotation90;
|
|
} else if (strcmp("180", bufferOrientation) == 0) {
|
|
rotation = vIdRotation180;
|
|
} else if (strcmp("270", bufferOrientation) == 0) {
|
|
rotation = vIdRotation270;
|
|
} else {
|
|
HLOGD("unset screen orient");
|
|
return NO_ERROR;
|
|
}
|
|
|
|
HLOGI("get home version screen, orientation=%s", bufferOrientation);
|
|
if ((m_player.get() != nullptr) && hasBeenInitialized) {
|
|
Parcel request;
|
|
request.writeInt32(CMD_SET_VIDEO_ROTATION);
|
|
request.writeInt32(rotation);
|
|
hidl_string requestString(reinterpret_cast<char *>(const_cast<uint8_t *>(request.data())),
|
|
request.dataSize());
|
|
Return<void> transInvoke = m_player->invoke(
|
|
requestString,
|
|
[this](int32_t ret, const hidl_string &replyString) {
|
|
if (ret != 0) {
|
|
HLOGE("GetDefaultBufferingSettings failed");
|
|
return;
|
|
}
|
|
});
|
|
if (!transInvoke.isOk()) {
|
|
HLOGE("Invoke failed");
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
return NO_ERROR;
|
|
}
|
|
HLOGW("invalid operation, call invoke under wrong state %X", m_currentState);
|
|
return INVALID_OPERATION;
|
|
}
|
|
|
|
status_t NxMediaPlayerManage::SetUserID() const
|
|
{
|
|
pid_t pid = IPCThreadState::self()->getCallingPid();
|
|
HLOGI("SetUserID, pid:%d", pid);
|
|
if (m_player.get() != nullptr) {
|
|
Parcel request;
|
|
request.writeInt32(CMD_SET_USER_ID);
|
|
request.writeInt32(pid);
|
|
hidl_string requestString(reinterpret_cast<char *>(const_cast<uint8_t *>(request.data())),
|
|
request.dataSize());
|
|
Return<void> transInvoke = m_player->invoke(
|
|
requestString,
|
|
[this](int32_t ret, const hidl_string &replyString) {
|
|
if (ret != 0) {
|
|
HLOGE("invoke CMD_SET_USER_ID failed");
|
|
return;
|
|
}
|
|
});
|
|
if (!transInvoke.isOk()) {
|
|
HLOGE("Invoke failed");
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
return NO_ERROR;
|
|
}
|
|
HLOGW("invalid operation, call invoke under wrong state %X", m_currentState);
|
|
return INVALID_OPERATION;
|
|
}
|
|
|
|
void NxMediaPlayerManage::NotifyResourceManage()
|
|
{
|
|
Parcel request, reply;
|
|
request.setDataPosition(0);
|
|
request.writeInt32(CMD_GET_VIDEO_INFO);
|
|
request.setDataPosition(0);
|
|
|
|
int ret = invoke(request, &reply);
|
|
int invokeRet = reply.readInt32();
|
|
if ((ret == NO_ERROR) && (invokeRet != NX_FAILURE)) {
|
|
const String16 kServiceName("media_resource_monitor", strlen("media_resource_monitor"));
|
|
pid_t pid = IPCThreadState::self()->getCallingPid();
|
|
sp<IBinder> binder = defaultServiceManager()->checkService(String16(kServiceName));
|
|
HLOGD("start pid %d", pid);
|
|
if (binder.get() != nullptr) {
|
|
HLOGD("notify resource granted");
|
|
sp<IMediaResourceMonitor> service = interface_cast<IMediaResourceMonitor>(binder);
|
|
service->notifyResourceGranted(pid, IMediaResourceMonitor::TYPE_VIDEO_CODEC);
|
|
}
|
|
}
|
|
}
|
|
|
|
void NxMediaPlayerManage::DeathRecipient::serviceDied(uint64_t cookie,
|
|
const wp<::android::hidl::base::V1_0::IBase> &) /* who */
|
|
{
|
|
HLOGE("notify %s, player cookie=0x%llx", __FUNCTION__, cookie);
|
|
if (m_nxMediaPlayerManager != nullptr) { /* handle death notify */
|
|
m_nxMediaPlayerManager->m_player.clear();
|
|
}
|
|
}
|
|
|
|
NxMediaPlayerManage::DeathRecipient::~DeathRecipient()
|
|
{
|
|
HLOGD("release %s", __FUNCTION__);
|
|
}
|
|
|
|
extern "C" android::NxMediaPlayerInterface *CreateNxMediaPlayerInterfaeInstance(int idx)
|
|
{
|
|
ALOGI("[%d][%s:%d]: new NxMediaPlayerManage", idx, __FUNCTION__, __LINE__);
|
|
return new ::android::NxMediaPlayerManage(idx);
|
|
}
|
|
|
|
extern "C" void DestroyNxMediaPlayerInterfaeInstance(android::NxMediaPlayerInterface *player, int idx)
|
|
{
|
|
ALOGI("[%d][%s:%d]: delete player", idx, __FUNCTION__, __LINE__);
|
|
delete player;
|
|
}
|
|
};
|