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

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