/* * 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 #include #include #include #include #include #include #include #include #include #include #include #include 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 MediaCallBack::Notify(int32_t msg, int32_t ext1, int32_t ext2, const hidl_string &obj) { Parcel parcelObj; parcelObj.setData(reinterpret_cast(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 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 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(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 transGetTrackInfo = m_player->getTrackInfo( [&reply, this](int32_t ret, const hidl_string &replyString) { if (ret != 0) { HLOGE("getTrackInfo failed"); return; } reply->setData(reinterpret_cast(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 *headers) { HLOGI("call %s in, uri", __FUNCTION__); if (url != nullptr && m_player.get() != nullptr) { hidl_string urlHidl(url); hidl_vec
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 transSetDataSourceNetwork = m_player->setDataSourceUrl(urlHidl, headersHidl); if (!transSetDataSourceNetwork.isOk() || static_cast(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(sb.st_uid), static_cast(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 transSetDataSourceLocal = m_player->setDataSourceFd(fdHandle, offset, length); (void)native_handle_delete(nativeHdl); if (!transSetDataSourceLocal.isOk() || static_cast(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 &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 &nativeWindow) { if (nativeWindow.get() == nullptr) { return; } sp curSf = static_cast(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 &bufferProducer, sp &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 transSetSurfaceTextureFB = m_player->setSurfaceTexture(bufferProducer, isSurfaceView); if (!transSetSurfaceTextureFB.isOk() || static_cast(transSetSurfaceTextureFB) != 0) { HLOGE("SetSurfaceTexture FB failed"); return UNKNOWN_ERROR; } (void)CreateNxMediaMsg(); /* async notify msg for SurfaceTexture */ } else { Return transSetSurfaceTextureSB = m_player->setSurfaceTexture(nullptr, isSurfaceView); if (!transSetSurfaceTextureSB.isOk() || static_cast(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(MEDIA_PLAYER_INITIALIZED) | static_cast(MEDIA_PLAYER_STOPPED))) != 0) { m_currentState = MEDIA_PLAYER_PREPARING; HLOGD("async prepare"); Return transPrepareAsync = m_player->prepare(ASYNC); if (!transPrepareAsync.isOk() || static_cast(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(MEDIA_PLAYER_STARTED)) != 0) { ret = NO_ERROR; goto RE; } if ((m_player.get() != nullptr) && (m_currentState & (static_cast(MEDIA_PLAYER_STOPPED) | static_cast(MEDIA_PLAYER_PREPARED) | static_cast(MEDIA_PLAYER_PLAYBACK_COMPLETE) | static_cast(MEDIA_PLAYER_PAUSED))) != 0) { m_player->setLooping(m_loop); m_currentState = MEDIA_PLAYER_STARTED; Return transStart = m_player->start(); if (!transStart.isOk() || static_cast(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(MEDIA_PLAYER_STOPPED)) != 0) { return NO_ERROR; } if ((m_player.get() != nullptr) && (m_currentState & (static_cast(MEDIA_PLAYER_STARTED) | static_cast(MEDIA_PLAYER_PREPARED) | static_cast(MEDIA_PLAYER_PAUSED) | static_cast(MEDIA_PLAYER_PLAYBACK_COMPLETE))) != 0) { HLOGI("call stop player, m_currentState=%d", m_currentState); Return transStop = m_player->stop(); if (!transStop.isOk() || static_cast(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(MEDIA_PLAYER_PAUSED) | static_cast(MEDIA_PLAYER_PLAYBACK_COMPLETE))) != 0) { return NO_ERROR; } if ((m_player.get() != nullptr) && (m_currentState & static_cast(MEDIA_PLAYER_STARTED)) != 0) { Return transPause = m_player->pause(); if (!transPause.isOk() || static_cast(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 transStatus = m_player->getPlayStatus(); if (transStatus.isOk() && static_cast(transStatus) != 0) { isPlaying = true; } else { isPlaying = false; } if ((m_currentState & static_cast(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 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 transSetPlaybackSettings = m_player->setPlaybackSettings(setting); if (!transSetPlaybackSettings.isOk() || static_cast(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& 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(MEDIA_PLAYER_STARTED) | static_cast(MEDIA_PLAYER_PREPARED) | static_cast(MEDIA_PLAYER_PAUSED) | static_cast(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 transSeekTo = m_player->seekTo(msec, static_cast(m_seekMode)); if (!transSeekTo.isOk() || static_cast(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 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(MEDIA_PLAYER_PLAYBACK_COMPLETE)) != 0) { ret = CallGetDuration(); *millisecond = m_duration; return ret; } Return 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(MEDIA_PLAYER_PREPARED) | static_cast(MEDIA_PLAYER_STARTED) | static_cast(MEDIA_PLAYER_PAUSED) | static_cast(MEDIA_PLAYER_STOPPED) | static_cast(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 transRest = m_player->reset(); if (!transRest.isOk() || static_cast(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 transSetLooping = m_player->setLooping(loop); if (!transSetLooping.isOk() || static_cast(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 transSetVolume = m_player->setVolume(leftVolume, rightVolume); if (!transSetVolume.isOk() || static_cast(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(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 transAddTimedTextSource = m_player->addTimedTextSource(fdHandle, offset, length, mime); (void)native_handle_delete(nativeHdl); if (!transAddTimedTextSource.isOk() || static_cast(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 transSelectTrack = m_player->selectTrack(tracksIndex, true); if (!transSelectTrack.isOk() || static_cast(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 transSelectTrack = m_player->selectTrack(tracksIndex, false); if (!transSelectTrack.isOk() || static_cast(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 transSetVideoScaling = m_player->setVideoScaling(scalingMode); if (!transSetVideoScaling.isOk() || static_cast(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 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(replyString.c_str()), replyString.size()); } }); if (!transGetSelectedTrack.isOk()) { HLOGE("GetSelectedTrack failed"); return UNKNOWN_ERROR; } return NO_ERROR; } status_t NxMediaPlayerManage::setSubSurface(const sp &bufferProducer) { /* add for androidp: surface.writeToParcel is changed */ HLOGI("call %s in", __FUNCTION__); if (m_player.get() == nullptr) { return UNKNOWN_ERROR; } Return transSetSubSurface = m_player->setSubtitleSurface(bufferProducer, 1); if (!transSetSubSurface.isOk() || static_cast(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(request.data()) + currentPos, request.dataSize() - currentPos); Return 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(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(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(request.data()), request.dataSize()); Return transSetParameter = m_player->setParameter(key, requestStr); if (!transSetParameter.isOk() || static_cast(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 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(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 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 &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 &player) { status_t err = UNKNOWN_ERROR; sp p; { Mutex::Autolock l(m_lock); /* scope for the lock */ if (!((m_currentState & static_cast(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 NxMediaPlayerManage::CreatePlayer() { sp 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 transCreate = m_playerStore->createNxMediaPlayer( [&p, this](int32_t status, const sp &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(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(const_cast(request.data())), request.dataSize()); Return 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(const_cast(request.data())), request.dataSize()); Return 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 binder = defaultServiceManager()->checkService(String16(kServiceName)); HLOGD("start pid %d", pid); if (binder.get() != nullptr) { HLOGD("notify resource granted"); sp service = interface_cast(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; } };