/* * Copyright (c) 2019 Amlogic, Inc. All rights reserved. * * This source code is subject to the terms and conditions defined in the * file 'LICENSE' which is part of this source code package. * * Description: */ #define LOG_MODULE_TAG "TV" #define LOG_CLASS_TAG "TvClient" #include #include #include #include #include #include #include #include #include #include #include #include #include "CTvLog.h" #include "TvClient.h" #include "tvcmd.h" const int RET_SUCCESS = 0; const int RET_FAILED = -1; const int EVENT_SIGLE_DETECT = 4; const int EVENT_SOURCE_CONNECT = 10; pthread_mutex_t tvclient_mutex = PTHREAD_MUTEX_INITIALIZER; using namespace android; enum { CMD_START = IBinder::FIRST_CALL_TRANSACTION, CMD_TV_ACTION = IBinder::FIRST_CALL_TRANSACTION + 1, CMD_SET_TV_CB = IBinder::FIRST_CALL_TRANSACTION + 2, CMD_CLR_TV_CB = IBinder::FIRST_CALL_TRANSACTION + 3, EVT_SRC_CT_CB = IBinder::FIRST_CALL_TRANSACTION + 4, EVT_SIG_DT_CB = IBinder::FIRST_CALL_TRANSACTION + 5, DATA_SET_ACTION = IBinder::FIRST_CALL_TRANSACTION + 6, DATA_GET_ACTION = IBinder::FIRST_CALL_TRANSACTION + 7, CMD_DATA_REQ = IBinder::FIRST_CALL_TRANSACTION + 8, EVT_SIG_DV_ALLM = IBinder::FIRST_CALL_TRANSACTION + 9, CMT_GET_ALLM_INFO = IBinder::FIRST_CALL_TRANSACTION + 10, EVT_SIG_VRR_CB = IBinder::FIRST_CALL_TRANSACTION + 11, EVT_SIG_QMS_CB = IBinder::FIRST_CALL_TRANSACTION + 12, CMT_GET_STD_INFO = IBinder::FIRST_CALL_TRANSACTION + 13, EVT_PIP_SIG_DT_CB = IBinder::FIRST_CALL_TRANSACTION + 14, }; class TvClientPriv : public BBinder, public IBinder::DeathRecipient { public: class DeathNotifier : public IBinder::DeathRecipient { public: DeathNotifier() {} virtual void binderDied(const wp &who); }; static sp mDeathNotifier; TvClientPriv(); ~TvClientPriv(); void Release(); static TvClientPriv *GetInstance(bool reinit = false); protected: int SendMethodCall(char *CmdString); int SendDataRequest(char *CmdString, char *data, size_t datalen); sp tvServicebinder; int setObserver(TvClient::TvClientIObserver *observer); private: std::vector mTvClientObserver; int SendEvent(CTvEvent &event); private: static int HandSourceConnectEvent(const void *param); static int HandSignalDetectEvent(const void *param); static int HandSignalDvAllmEvent(const void *param); static int HandSignalVrrEvent(const void *param); static int HandSignalQmsEvent(const void *param); static int HandPipSignalDetectEvent(const void *param); virtual void binderDied(const wp &who); int tvServicebinderId; virtual status_t onTransact(uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags = 0); friend class TvClient; }; sp TvClientPriv::mDeathNotifier; TvClientPriv *TvClientPriv::GetInstance(bool reinit) { static sp inst_; if (inst_.get() != nullptr && reinit) { inst_.clear(); } if (inst_.get() == nullptr) { inst_ = new TvClientPriv(); } return inst_.get(); } TvClientPriv::TvClientPriv() { init_tv_logging(); LOGD("%s.\n", __FUNCTION__); pthread_mutex_lock(&tvclient_mutex); sp proc(ProcessState::self()); proc->startThreadPool(); Parcel send, reply; sp sm = defaultServiceManager(); do { tvServicebinder = sm->getService(String16("tvservice")); if (tvServicebinder != 0) break; LOGD("TvClient: Waiting tvservice published.\n"); usleep(500000); } while (true); if (mDeathNotifier == NULL) { mDeathNotifier = new DeathNotifier(); } tvServicebinder->linkToDeath(mDeathNotifier); LOGD("Connected to tvservice.\n"); send.writeStrongBinder(sp(this)); tvServicebinder->transact(CMD_SET_TV_CB, send, &reply); tvServicebinderId = reply.readInt32(); LOGD("tvServicebinderId:%d.\n", tvServicebinderId); pthread_mutex_unlock(&tvclient_mutex); } TvClientPriv::~TvClientPriv() { LOGD("%s.\n", __FUNCTION__); mDeathNotifier = nullptr; } void TvClientPriv::Release() { LOGD("%s.\n", __FUNCTION__); pthread_mutex_lock(&tvclient_mutex); if (tvServicebinder != NULL) { Parcel send, reply; send.writeInt32(tvServicebinderId); tvServicebinder->transact(CMD_CLR_TV_CB, send, &reply); tvServicebinder = NULL; } pthread_mutex_unlock(&tvclient_mutex); IPCThreadState::self()->stopProcess(); mDeathNotifier = nullptr; } int TvClientPriv::SendMethodCall(char *CmdString) { LOGD("%s.\n", __FUNCTION__); int ReturnVal = 0; Parcel send, reply; if (tvServicebinder != NULL) { send.writeCString(CmdString); if (tvServicebinder->transact(CMD_TV_ACTION, send, &reply) != 0) { ReturnVal = reply.readExceptionCode(); LOGE("%s: tvServicebinder failed, error code:%d\n", __FUNCTION__, ReturnVal); } else { ReturnVal = reply.readInt32(); } } else { LOGE("%s: tvServicebinder is NULL.\n", __FUNCTION__); } return ReturnVal; } int TvClientPriv::SendDataRequest(char *CmdString, char *data, size_t datalen) { LOGD("%s.\n", __FUNCTION__); int ReturnVal = 0; Parcel send, reply; pthread_mutex_lock(&tvclient_mutex); if (tvServicebinder != NULL) { send.writeCString(CmdString); if (tvServicebinder->transact(CMD_DATA_REQ, send, &reply) != 0) { LOGE("TvClient: call %s failed.\n", CmdString); ReturnVal = -1; } else { ReturnVal = reply.readInt32(); if (reply.read(data, datalen) != 0) ReturnVal = -1; } } pthread_mutex_unlock(&tvclient_mutex); return ReturnVal; } int TvClientPriv::setObserver(TvClient::TvClientIObserver *observer) { if (observer != nullptr) { mTvClientObserver.emplace_back(observer); LOGD("%s: mTvClientObserver[%p] has been register.\n", __FUNCTION__, observer); } else { LOGD("%s: observer is NULL.\n", __FUNCTION__); } return 0; } int TvClientPriv::SendEvent(CTvEvent &event) { for (const auto &o : mTvClientObserver) { if (o != nullptr) { o->onTvClientEvent(event); LOGD("send event for %p count TvClientObserver!\n", o); } } return 0; } int TvClientPriv::HandSourceConnectEvent(const void *param) { Parcel *parcel = (Parcel *)param; TvEvent::SourceConnectEvent event; event.mSourceInput = parcel->readInt32(); event.connectionState = parcel->readInt32(); GetInstance()->SendEvent(event); return 0; } int TvClientPriv::HandSignalDetectEvent(const void *param) { Parcel *parcel = (Parcel *)param; TvEvent::SignalDetectEvent event; event.mSourceInput = parcel->readInt32(); event.mFmt = parcel->readInt32(); event.mTrans_fmt = parcel->readInt32(); event.mStatus = parcel->readInt32(); event.mDviFlag = parcel->readInt32(); event.mhdr_info = parcel->readUint32(); GetInstance()->SendEvent(event); return 0; } int TvClientPriv::HandSignalDvAllmEvent(const void *param) { Parcel *parcel = (Parcel *)param; TvEvent::SignalDvAllmEvent event; event.allm_mode = parcel->readInt32(); event.it_content = parcel->readInt32(); event.cn_type = parcel->readInt32(); GetInstance()->SendEvent(event); return 0; } int TvClientPriv::HandSignalVrrEvent(const void *param) { Parcel *parcel = (Parcel *)param; TvEvent::SignalVrrEvent event; event.cur_vrr_status = parcel->readInt32(); GetInstance()->SendEvent(event); return 0; } int TvClientPriv::HandSignalQmsEvent(const void *param) { Parcel *parcel = (Parcel *)param; TvEvent::QMSEvent event; event.qms_en = parcel->readInt32(); event.qms_fps = parcel->readInt32(); event.qms_base_fps = parcel->readInt32(); GetInstance()->SendEvent(event); return 0; } int TvClientPriv::HandPipSignalDetectEvent(const void *param) { Parcel *parcel = (Parcel *)param; TvEvent::PipSignalDetectEvent event; event.mSourceInput = parcel->readInt32(); event.mFmt = parcel->readInt32(); event.mTrans_fmt = parcel->readInt32(); event.mStatus = parcel->readInt32(); event.mDviFlag = parcel->readInt32(); event.mhdr_info = parcel->readUint32(); GetInstance()->SendEvent(event); return 0; } status_t TvClientPriv::onTransact(uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) { pthread_mutex_lock(&tvclient_mutex); LOGD("TvClient get tanscode: %u\n", code); switch (code) { case EVT_SRC_CT_CB: { HandSourceConnectEvent(&data); break; } case EVT_SIG_DT_CB: { HandSignalDetectEvent(&data); break; } case EVT_SIG_DV_ALLM: { HandSignalDvAllmEvent(&data); break; } case EVT_SIG_VRR_CB: { HandSignalVrrEvent(&data); break; } case EVT_SIG_QMS_CB: { HandSignalQmsEvent(&data); break; } case EVT_PIP_SIG_DT_CB: { HandPipSignalDetectEvent(&data); break; } case CMD_START: default: pthread_mutex_unlock(&tvclient_mutex); return BBinder::onTransact(code, data, reply, flags); } pthread_mutex_unlock(&tvclient_mutex); return (0); } void TvClientPriv::binderDied(const wp &who) { LOGV("ITv died"); // notifyCallback(1, 2, 0); } void TvClientPriv::DeathNotifier::binderDied(const wp &who) { LOGV("-----Tv server died,reconnect-----\n"); TvClientPriv::GetInstance(true); LOGV("-----reconnect success-----\n"); } int TvClient::StartTv(tv_source_input_t source) { LOGD("%s\n", __FUNCTION__); char buf[32] = {0}; sprintf(buf, "control.%d.%d", TV_CONTROL_START_TV, source); return TvClientPriv::GetInstance()->SendMethodCall(buf); } int TvClient::StopTv(tv_source_input_t source) { LOGD("%s\n", __FUNCTION__); char buf[32] = {0}; sprintf(buf, "control.%d.%d", TV_CONTROL_STOP_TV, source); return TvClientPriv::GetInstance()->SendMethodCall(buf); } int TvClient::SwitchSource(tv_source_input_t source) { LOGD("%s\n", __FUNCTION__); char buf[32] = {0}; sprintf(buf, "control.%d.%d", TV_CONTROL_SWITCH_SOURCE, source); return TvClientPriv::GetInstance()->SendMethodCall(buf); } tv_source_input_t TvClient::GetCurrentSource() { LOGD("%s\n", __FUNCTION__); char buf[32] = {0}; sprintf(buf, "control.%d", TV_CONTROL_GET_CURRENT_SOURCE); return (tv_source_input_t)TvClientPriv::GetInstance()->SendMethodCall(buf); } int TvClient::SetVdinWorkMode(vdin_work_mode_t vdinWorkMode) { LOGD("%s\n", __FUNCTION__); char buf[512] = {0}; sprintf(buf, "control.%d.%d", TV_CONTROL_VDIN_WORK_MODE_SET, vdinWorkMode); return TvClientPriv::GetInstance()->SendMethodCall(buf); } int TvClient::SetEdidVersion(tv_source_input_t source, int edidVer) { LOGD("%s\n", __FUNCTION__); char buf[32] = {0}; sprintf(buf, "edid.set.%d.%d.%d", HDMI_EDID_VER_SET, source, edidVer); return TvClientPriv::GetInstance()->SendMethodCall(buf); } int TvClient::GetEdidVersion(tv_source_input_t source) { LOGD("%s\n", __FUNCTION__); char buf[32] = {0}; sprintf(buf, "edid.get.%d.%d", HDMI_EDID_VER_GET, source); return TvClientPriv::GetInstance()->SendMethodCall(buf); } int TvClient::SetEdidData(tv_source_input_t source, char *dataBuf) { LOGD("%s\n", __FUNCTION__); char CmdString[32] = {0}; sprintf(CmdString, "%d.%d.", HDMI_EDID_DATA_SET, source); int ret = -1; Parcel send, reply; if (TvClientPriv::GetInstance()->tvServicebinder != NULL) { send.writeCString(CmdString); send.writeInt32(256); for (int i = 0; i < 256; i++) { send.writeInt32(dataBuf[i]); } if (TvClientPriv::GetInstance()->tvServicebinder->transact( DATA_SET_ACTION, send, &reply) != 0) { LOGE("%s: tvServicebinder failed.\n", __FUNCTION__); } else { ret = reply.readInt32(); } } else { LOGE("%s: tvServicebinder is NULL.\n", __FUNCTION__); } return ret; } int TvClient::GetEdidData(tv_source_input_t source, char *dataBuf) { LOGD("%s\n", __FUNCTION__); char buf[32] = {0}; sprintf(buf, "%d.%d", HDMI_EDID_DATA_GET, source); int ret = -1; Parcel send, reply; if (TvClientPriv::GetInstance()->tvServicebinder != NULL) { send.writeCString(buf); if (TvClientPriv::GetInstance()->tvServicebinder->transact( DATA_GET_ACTION, send, &reply) != 0) { LOGE("%s: tvServicebinder failed.\n", __FUNCTION__); } else { // dataSize reply.readInt32(); for (int i = 0; i < 256; i++) { dataBuf[i] = (char)reply.readInt32(); } // ret = reply.readInt32(); ret = 0; } } else { LOGE("%s: tvServicebinder is NULL.\n", __FUNCTION__); } return ret; } int TvClient::GetHdmiSPDInfo(tv_source_input_t source, char *dataBuf, size_t datalen) { LOGD("%s\n", __FUNCTION__); char buf[512] = {0}; snprintf(buf, sizeof(buf), "pkttype.get.%d.%d.%d.%s", HDMI_SPD_INFO_GET, source, datalen, dataBuf); return TvClientPriv::GetInstance()->SendDataRequest(buf, dataBuf, datalen); } int TvClient::GetCurrentSourceFrameHeight() { LOGD("%s\n", __FUNCTION__); char buf[32] = {0}; sprintf(buf, "control.%d", TV_CONTROL_GET_FRAME_HEIGHT); return TvClientPriv::GetInstance()->SendMethodCall(buf); } int TvClient::GetCurrentSourceFrameWidth() { LOGD("%s\n", __FUNCTION__); char buf[32] = {0}; sprintf(buf, "control.%d", TV_CONTROL_GET_FRAME_WIDTH); return TvClientPriv::GetInstance()->SendMethodCall(buf); } int TvClient::GetCurrentSourceFrameFps() { LOGD("%s\n", __FUNCTION__); char buf[32] = {0}; sprintf(buf, "control.%d", TV_CONTROL_GET_FRAME_RATE); return TvClientPriv::GetInstance()->SendMethodCall(buf); } int TvClient::GetCurrentSourceColorDepth() { LOGD("%s\n", __FUNCTION__); char buf[32] = {0}; sprintf(buf, "control.%d", TV_CONTROL_GET_COLOR_DEPTH); return TvClientPriv::GetInstance()->SendMethodCall(buf); } tvin_aspect_ratio_t TvClient::GetCurrentSourceAspectRatio() { LOGD("%s\n", __FUNCTION__); char buf[32] = {0}; sprintf(buf, "hdmi.%d", HDMI_GET_ASPECT_RATIO); return (tvin_aspect_ratio_t)TvClientPriv::GetInstance()->SendMethodCall(buf); } tvin_color_fmt_t TvClient::GetCurrentSourceColorFormat() { LOGD("%s\n", __FUNCTION__); char buf[32] = {0}; sprintf(buf, "hdmi.%d", HDMI_GET_COLOR_FORMAT); return (tvin_color_fmt_t)TvClientPriv::GetInstance()->SendMethodCall(buf); } int TvClient::SetCurrentSourceColorRange(tvin_color_range_t range_mode) { LOGD("%s\n", __FUNCTION__); char buf[32] = {0}; sprintf(buf, "hdmi.%d.%d", HDMI_SET_COLOR_RANGE, (int)range_mode); return TvClientPriv::GetInstance()->SendMethodCall(buf); } tvin_color_range_t TvClient::GetCurrentSourceColorRange() { LOGD("%s\n", __FUNCTION__); char buf[32] = {0}; sprintf(buf, "hdmi.%d", HDMI_GET_COLOR_RANGE); return (tvin_color_range_t)TvClientPriv::GetInstance()->SendMethodCall(buf); } tvin_line_scan_mode_t TvClient::GetCurrentSourceLineScanMode() { LOGD("%s\n", __FUNCTION__); char buf[32] = {0}; sprintf(buf, "control.%d", TV_CONTROL_GET_LINE_SCAN_MODE); return (tvin_line_scan_mode_t)TvClientPriv::GetInstance()->SendMethodCall( buf); } int TvClient::GetSourceConnectStatus(tv_source_input_t source) { LOGD("%s\n", __FUNCTION__); char buf[32] = {0}; sprintf(buf, "control.%d.%d", TV_CONTROL_GET_CONNECT_STATUS, source); return TvClientPriv::GetInstance()->SendMethodCall(buf); } int TvClient::SetEdidBoostOn(int bBoostOn) { LOGD("%s\n", __FUNCTION__); char buf[32] = {0}; sprintf(buf, "control.%d.%d", TV_CONTROL_SET_BOOST_ON, bBoostOn); return TvClientPriv::GetInstance()->SendMethodCall(buf); } int TvClient::GetCurrentSourceAllmInfo(tvin_latency_s *info) { LOGD("%s\n", __FUNCTION__); int ret = 0; char CmdString[32] = {0}; sprintf(CmdString, "control.%d.", TV_CONTROL_GET_ALLM_INFO); Parcel send, reply; if (TvClientPriv::GetInstance()->tvServicebinder != NULL) { send.writeCString(CmdString); if (TvClientPriv::GetInstance()->tvServicebinder->transact( CMT_GET_ALLM_INFO, send, &reply) != 0) { LOGE("%s: tvServicebinder failed.\n", __FUNCTION__); ret = -1; } else { info->allm_mode = reply.readInt32(); info->it_content = reply.readInt32(); info->cn_type = (tvin_cn_type_t)reply.readInt32(); } } else { LOGE("%s: tvServicebinder is NULL.\n", __FUNCTION__); ret = -1; } return ret; } int TvClient::SetHdmiAllmEnabled(bool enable) { LOGD("%s: %s\n", __FUNCTION__, enable ? "enable" : "disable"); char buf[32] = {0}; sprintf(buf, "hdmi.%d.%d", HDMI_SET_ALLM_ENABLED, enable ? 1 : 0); return TvClientPriv::GetInstance()->SendMethodCall(buf); } bool TvClient::GetHdmiAllmEnabled() { LOGD("%s\n", __FUNCTION__); char buf[32] = {0}; sprintf(buf, "hdmi.%d", HDMI_GET_ALLM_ENABLED); if (TvClientPriv::GetInstance()->SendMethodCall(buf)) { return true; } return false; } bool TvClient::GetHdmiVrrSupport() { LOGD("%s\n", __FUNCTION__); char buf[32] = {0}; sprintf(buf, "hdmi.%d", HDMI_GET_VRR_SUPPORT); if (TvClientPriv::GetInstance()->SendMethodCall(buf)) { return true; } return false; } int TvClient::SetHdmiVrrEnabled(bool enable) { LOGD("%s: %s\n", __FUNCTION__, enable ? "enable" : "disable"); char buf[32] = {0}; sprintf(buf, "hdmi.%d.%d", HDMI_SET_VRR_ENABLED, enable ? 1 : 0); return TvClientPriv::GetInstance()->SendMethodCall(buf); } bool TvClient::GetHdmiVrrEnabled() { LOGD("%s\n", __FUNCTION__); char buf[32] = {0}; sprintf(buf, "hdmi.%d", HDMI_GET_VRR_ENABLED); if (TvClientPriv::GetInstance()->SendMethodCall(buf)) { return true; } return false; } vdin_vrr_mode_t TvClient::GetHdmiVrrMode() { LOGD("%s\n", __FUNCTION__); char buf[32] = {0}; sprintf(buf, "hdmi.%d", HDMI_GET_VRR_MODE); return (vdin_vrr_mode_t)TvClientPriv::GetInstance()->SendMethodCall(buf); } bool TvClient::GetHdmiQmsSupport() { LOGD("%s\n", __FUNCTION__); char buf[32] = {0}; sprintf(buf, "hdmi.%d", HDMI_GET_QMS_SUPPORT); if (TvClientPriv::GetInstance()->SendMethodCall(buf)) { return true; } return false; } int TvClient::SetHdmiQmsEnabled(bool enable) { LOGD("%s: %s\n", __FUNCTION__, enable ? "enable" : "disable"); char buf[32] = {0}; sprintf(buf, "hdmi.%d.%d", HDMI_SET_QMS_ENABLED, enable ? 1 : 0); return TvClientPriv::GetInstance()->SendMethodCall(buf); } bool TvClient::GetHdmiQmsEnabled() { LOGD("%s\n", __FUNCTION__); char buf[32] = {0}; sprintf(buf, "hdmi.%d", HDMI_GET_QMS_ENABLED); if (TvClientPriv::GetInstance()->SendMethodCall(buf)) { return true; } return false; } int TvClient::GetCurrentStdInfo(struct tvin_std_s *info) { LOGD("%s\n", __FUNCTION__); int ret = 0; Parcel send, reply; if (TvClientPriv::GetInstance()->tvServicebinder != NULL) { send.writeCString(""); if (TvClientPriv::GetInstance()->tvServicebinder->transact( CMT_GET_STD_INFO, send, &reply) != 0) { LOGE("%s: tvServicebinder failed.\n", __FUNCTION__); ret = -1; } else { info->source = reply.readInt32(); info->edid_version = reply.readInt32(); info->allm_enabled = (bool)reply.readInt32(); info->vrr_enabled = (bool)reply.readInt32(); info->qms_enabled = (bool)reply.readInt32(); } } else { LOGE("%s: tvServicebinder is NULL.\n", __FUNCTION__); ret = -1; } return ret; } int TvClient::SetAudioDecoderId(int channel, int id) { LOGD("%s\n", __FUNCTION__); char buf[32] = {0}; sprintf(buf, "control.%d.%d.%d", TV_CONTROL_SET_AUDIO_ID, channel, id); return TvClientPriv::GetInstance()->SendMethodCall(buf); } int TvClient::SetAvAudioModeEnabled(bool enable) { LOGD("%s: %s\n", __FUNCTION__, enable ? "enable" : "disable"); char buf[32] = {0}; sprintf(buf, "control.%d.%d", TV_CONTROL_SET_AVAUDIO_MODE, enable ? 1 : 0); return TvClientPriv::GetInstance()->SendMethodCall(buf); } int TvClient::StartTvInPIP(tv_source_input_t source) { LOGD("%s\n", __FUNCTION__); char buf[32] = {0}; sprintf(buf, "control.%d.%d", TV_CONTROL_START_TV_PIP, source); return TvClientPriv::GetInstance()->SendMethodCall(buf); } int TvClient::StopTvInPIP(tv_source_input_t source) { LOGD("%s\n", __FUNCTION__); char buf[32] = {0}; sprintf(buf, "control.%d.%d", TV_CONTROL_STOP_TV_PIP, source); return TvClientPriv::GetInstance()->SendMethodCall(buf); } bool TvClient::GetHdmiDlgSupport() { LOGD("%s\n", __FUNCTION__); char buf[32] = {0}; sprintf(buf, "hdmi.%d", HDMI_GET_DLG_SUPPORT); if (TvClientPriv::GetInstance()->SendMethodCall(buf)) { return true; } return false; } int TvClient::SetHdmiDlgEnabled(bool enable) { LOGD("%s: %s\n", __FUNCTION__, enable ? "enable" : "disable"); char buf[32] = {0}; sprintf(buf, "hdmi.%d.%d", HDMI_SET_DLG_ENABLED, enable ? 1 : 0); return TvClientPriv::GetInstance()->SendMethodCall(buf); } bool TvClient::GetHdmiDlgEnabled() { LOGD("%s\n", __FUNCTION__); char buf[32] = {0}; sprintf(buf, "hdmi.%d", HDMI_GET_DLG_ENABLED); if (TvClientPriv::GetInstance()->SendMethodCall(buf)) { return true; } return false; } int TvClient::setTvClientObserver(TvClientIObserver *observer) { return TvClientPriv::GetInstance()->setObserver(observer); } TvClient *TvClient::GetInstance() { static std::shared_ptr inst_; if (inst_.get() == nullptr) { inst_ = std::shared_ptr(new TvClient(), [](TvClient *ptr) { delete ptr; }); } return inst_.get(); } void TvClient::Release() { TvClientPriv::GetInstance()->Release(); } TvClient::TvClient() {} TvClient::~TvClient() {}