Files
2026-08-24 10:03:24 +08:00

541 lines
17 KiB
C++

/*
* Copyright (C) 2014-2026 Amlogic, Inc. All rights reserved.
*
* All information contained herein is Amlogic confidential.
*
* This software is provided to you pursuant to Software License Agreement
* (SLA) with Amlogic Inc ("Amlogic"). This software may be used
* only in accordance with the terms of this agreement.
*
* Redistribution and use in source and binary forms, with or without
* modification is strictly prohibited without prior written permission from
* Amlogic.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define LOG_MOUDLE_TAG "Subtitle"
#define LOG_CLASS_TAG "SubtitleClientLinux"
#include "SubtitleClientLinux.h"
#include <EventsTracker.h>
#include <IpcSocket.h>
#include <inttypes.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include <utils/CallStack.h>
#include <memory>
#include "SubtitleLog.h"
#include "subtitlecmd.h"
extern "C" __attribute__((weak)) SubtitleLogLevel gSubtitleLogLevel = SUB_LOG_INFO;
#define SERVER_PORT 10200
#define format_string(format, ...) \
({ \
char fmt_buf[256] = {0}; \
sprintf(fmt_buf, format, ##__VA_ARGS__); \
fmt_buf; \
})
const int RET_SUCCESS = 0;
const int RET_FAILED = -1;
const int EVENT_SIGLE_DETECT = 4;
const int EVENT_SOURCE_CONNECT = 10;
SubtitleClientLinux *mInstance = NULL;
SubtitleClientLinux::SubtitleClientLinux(bool isFallback, sp<SubtitleListener> listener,
OpenType openType) {
SUBTITLE_LOGI("SubtitleServerHidlClient getSubtitleService ...");
// Mutex::Autolock _l(mLock);
mIsFallback = isFallback;
mSubtitleListener = listener;
mOpenType = openType;
initRemoteLocked();
}
void SubtitleClientLinux::initRemoteLocked() {
if (mIpcSocket == nullptr) {
mIpcSocket = std::make_shared<IpcSocket>(false);
mIpcSocket->start(SERVER_PORT, nullptr);
}
if (!mIpcSocket->isvalid()) {
SUBTITLE_LOGE("Client: initRemoteLocked failed");
mIpcSocket->stop();
return;
}
mIpcSocket->setEventListener(eventReceiver);
mSessionId = openConnection();
SUBTITLE_LOGI("Connected to subtitleservice. mSessionId = %d\n", mSessionId);
}
/*static */
int SubtitleClientLinux::eventReceiver(int fd, void * /*selfData*/) {
char retBuf[1024];
if (!IpcSocket::receive(fd, retBuf, sizeof(retBuf))) {
SUBTITLE_LOGI("Server broken, fd= %d, remove.", fd);
return EventsTracker::RET_REMOVE;
} else {
SUBTITLE_LOGI("Client received: %s", retBuf);
}
return EventsTracker::RET_CONTINUE;
}
SubtitleClientLinux::~SubtitleClientLinux() {
Parcel send, reply;
// mSubtitleServicebinder->transact(CMD_CLR_PQ_CB, send, &reply);
closeConnection();
mSubtitleServicebinder = nullptr;
if (mIpcSocket != nullptr) {
mIpcSocket->stop();
mIpcSocket->join();
}
}
int SubtitleClientLinux::SendMethodCall(char *CmdString, native_handle_t * /*handle*/) {
int ret = -1;
if (mIpcSocket != nullptr) {
std::string payload(CmdString);
int payloadSize = payload.size();
auto resultStr = mIpcSocket->sendForResult(mIpcSocket->fd(), payload.c_str(), payloadSize);
if (resultStr == "-1") {
SUBTITLE_LOGE("Server is broken, stop!!!");
mIpcSocket->stop();
return ret;
}
if (!resultStr.empty()) {
SUBTITLE_LOGI("%s ==> ||| <== %s", CmdString, resultStr.c_str());
ret = atoi(resultStr.c_str());
}
}
return ret;
}
int SubtitleClientLinux::SplitRetBuf(const char *commandData) {
char cmdbuff[1024];
char *token;
int cmd_size = 0;
const char *delimitation = ".";
strcpy(cmdbuff, commandData);
/* get first str*/
token = strtok(cmdbuff, delimitation);
/* continue get str*/
while (token != NULL) {
mRet[cmd_size].assign(token);
SUBTITLE_LOGI("%s mRet[%d]:%s\n", token, cmd_size, mRet[cmd_size].c_str());
cmd_size++;
token = strtok(NULL, delimitation);
}
SUBTITLE_LOGI("cmd_size = %d\n", cmd_size);
return cmd_size;
}
int SubtitleClientLinux::openConnection() {
SUBTITLE_LOGI_FUNC_IN();
int ret = -1;
int sessionId = SendMethodCall(format_string("subtitle.ctrl.%d", SUBTITLE_OPENCONNECTION));
if (sessionId >= 0) {
mSessionId = sessionId;
ret = 0;
}
return ret;
}
int SubtitleClientLinux::closeConnection() {
SUBTITLE_LOGI_FUNC_IN();
int ret =
SendMethodCall(format_string("subtitle.ctrl.%d.%d", SUBTITLE_CLOSECONNECTION, mSessionId));
SUBTITLE_LOGE("SubtitleClientLinux: ret %d.\n", ret);
return ret;
}
bool SubtitleClientLinux::open(const char *path, int ioType) {
SUBTITLE_LOGI_FUNC_IN();
return true;
}
bool SubtitleClientLinux::open(int fd, int ioType) {
SUBTITLE_LOGI("SubtitleClientLinux, fd=%d,ioType=%d mOpenType=%d", fd, ioType, mOpenType);
native_handle_t *nativeHandle = nullptr;
if (fd > 0) {
::lseek(fd, 0, SEEK_SET);
nativeHandle = native_handle_create(1, 0);
nativeHandle->data[0] = fd;
}
int ret = SendMethodCall(
format_string("subtitle.ctrl.%d.%d.%d.%d", SUBTITLE_OPEN, mSessionId, ioType, mOpenType),
nativeHandle);
SUBTITLE_LOGE("SubtitleClientLinux: ret %d.\n", ret);
return true;
}
int SubtitleClientLinux::close() {
SUBTITLE_LOGI_FUNC_IN();
int ret = SendMethodCall(format_string("subtitle.ctrl.%d.%d", SUBTITLE_CLOSE, mSessionId));
mWasRegisterOnDataCB = false;
SUBTITLE_LOGE("ret = %d", ret);
return ret;
}
int SubtitleClientLinux::resetForSeek() {
int ret =
SendMethodCall(format_string("subtitle.ctrl.%d.%d", SUBTITLE_RESETFORSEEK, mSessionId));
SUBTITLE_LOGE("SubtitleClientLinux: ret %d.\n", ret);
return ret;
}
int SubtitleClientLinux::updateVideoPos(int64_t pos) {
int ret = SendMethodCall(
format_string("subtitle.ctrl.%d.%d.%" PRId64, SUBTITLE_UPDATEVIDEOPTS, mSessionId, pos));
static int logCnt = 0;
if (++logCnt % 100 == 0) {
SUBTITLE_LOGI("SubtitleClientLinux: ret %d.", ret);
}
return ret;
}
int SubtitleClientLinux::getTotalTracks() {
int ret =
SendMethodCall(format_string("subtitle.get.%d.%d", SUBTITLE_GETTOTALTRACKS, mSessionId));
SUBTITLE_LOGE("SubtitleClientLinux: ret %d.\n", ret);
return ret;
}
int SubtitleClientLinux::getType() {
int ret = SendMethodCall(format_string("subtitle.get.%d.%d", SUBTITLE_GETTYPE, mSessionId));
SUBTITLE_LOGE("SubtitleClientLinux: ret %d.\n", ret);
return ret;
}
int SubtitleClientLinux::getLanguage() {
int ret = SendMethodCall(format_string("subtitle.get.%d.%d", SUBTITLE_GETLANGUAGE, mSessionId));
SUBTITLE_LOGE("SubtitleClientLinux: ret %d.\n", ret);
return ret;
}
int SubtitleClientLinux::getSessionId() {
return mSessionId;
}
int SubtitleClientLinux::setSubType(int32_t type) {
int ret = SendMethodCall(
format_string("subtitle.set.%d.%d.%d", SUBTITLE_SETSUBTYPE, mSessionId, type));
return ret;
}
int SubtitleClientLinux::setSubPid(int32_t pid) {
int ret =
SendMethodCall(format_string("subtitle.set.%d.%d.%d", SUBTITLE_GETSUBPID, mSessionId, pid));
SUBTITLE_LOGE("SubtitleClientLinux: ret %d.\n", ret);
return ret;
}
int SubtitleClientLinux::setPageId(int32_t pageId) {
int ret = SendMethodCall(
format_string("subtitle.set.%d.%d.%d", SUBTITLE_SETPAGEID, mSessionId, pageId));
SUBTITLE_LOGE("SubtitleClientLinux: ret %d.\n", ret);
return ret;
}
int SubtitleClientLinux::setAncPageId(int32_t ancPageId) {
int ret = SendMethodCall(
format_string("subtitle.set.%d.%d.%d", SUBTITLE_SETANCPAGEID, mSessionId, ancPageId));
SUBTITLE_LOGE("SubtitleClientLinux: ret %d.\n", ret);
return ret;
}
int SubtitleClientLinux::setSecureLevel(int32_t flag) {
int ret = SendMethodCall(
format_string("subtitle.set.%d.%d.%d", SUBTITLE_SETSECURELEVEL, mSessionId, flag));
SUBTITLE_LOGE("SubtitleClientLinux: ret %d.\n", ret);
return ret;
}
int SubtitleClientLinux::setChannelId(int32_t channelId) {
int ret = SendMethodCall(
format_string("subtitle.set.%d.%d.%d", SBUTITLE_SETCHANNELID, mSessionId, channelId));
SUBTITLE_LOGE("SubtitleClientLinux: ret %d.\n", ret);
return ret;
}
int SubtitleClientLinux::setClosedCaptionVfmt(int32_t vfmt) {
int ret = SendMethodCall(
format_string("subtitle.set.%d.%d.%d", SUBTITLE_SETCLOSECAPTIONVFMT, mSessionId, vfmt));
SUBTITLE_LOGE("SubtitleClientLinux: ret %d.\n", ret);
return ret;
}
int SubtitleClientLinux::getSubtitleStatus(int type, int event) {
int ret = SendMethodCall(format_string("subtitle.getSubtitleStatus.%d.%d.%d.%d",
SUBTITLE_GETSUBTITLESTATUS, mSessionId, type, event));
SUBTITLE_LOGE("SubtitleClientLinux: ret %d.\n", ret);
return ret;
}
int SubtitleClientLinux::ttControl(int cmd, int magazine, int page, int regionId, int param) {
int ret =
SendMethodCall(format_string("subtitle.ttcontrol.%d.%d.%d.%d.%d.%d.%d", SUBTITLE_TTCONTROL,
mSessionId, cmd, magazine, page, regionId, param));
SUBTITLE_LOGE("SubtitleClientLinux: ret %d.\n", ret);
return ret;
}
int SubtitleClientLinux::ttGoHome() {
int ret =
SendMethodCall(format_string("subtitle.ttcontrol.%d.%d", SUBTITLE_TTGOHOME, mSessionId));
SUBTITLE_LOGE("SubtitleClientLinux: ret %d\n", ret);
return ret;
}
int SubtitleClientLinux::ttNextPage(int32_t dir) {
int ret = SendMethodCall(
format_string("subtitle.ttcontrol.%d.%d.%d", SUBTITLE_TTNEXTPAGE, mSessionId, dir));
SUBTITLE_LOGE("SubtitleClientLinux: ret %d.\n", ret);
return ret;
}
int SubtitleClientLinux::ttNextSubPage(int32_t dir) {
int ret = SendMethodCall(
format_string("subtitle.ttcontrol.%d.%d.%d", SUBTITLE_TTNEXTSUBPAGE, mSessionId, dir));
SUBTITLE_LOGE("SubtitleClientLinux: ret %d.\n", ret);
return ret;
}
int SubtitleClientLinux::ttGotoPage(int32_t pageNo, int32_t subPageNo) {
int ret = SendMethodCall(format_string("subtitle.ttcontrol.%d.%d.%d.%d", SUBTITLE_TTGOTOPAGE,
mSessionId, pageNo, subPageNo));
SUBTITLE_LOGE("SubtitleClientLinux: ret %d.\n", ret);
return ret;
}
int SubtitleClientLinux::userDataOpen() {
int ret = SendMethodCall(
format_string("subtitle.afdcontrol.%d.%d", SUBTITLE_USERDATAOPEN, mSessionId));
SUBTITLE_LOGE("SubtitleClientLinux: ret %d.\n", ret);
return ret;
}
int SubtitleClientLinux::userDataClose() {
int ret = SendMethodCall(
format_string("subtitle.afdcontrol.%d.%d", SUBTITLE_USERDATACLOSE, mSessionId));
SUBTITLE_LOGE("SubtitleClientLinux: ret %d.\n", ret);
return ret;
}
int SubtitleClientLinux::setPipId(int32_t mode, int32_t id) {
int ret = SendMethodCall(
format_string("subtitle.set.%d.%d.%d.%d", SUBTITLE_SETPIPID, mSessionId, mode, id));
SUBTITLE_LOGE("SubtitleClientLinux: setPipId, ret %d.\n", ret);
return ret;
}
// Below APIs are used only for controlling standalone UI.
// Such standalone UI is not recommended, which is only used by some native APPs or middlewares.
// The Linux platform can use the uishow and uihide interfaces to control the direct display
// solution
bool SubtitleClientLinux::uiShow() {
int ret = SendMethodCall(format_string("subtitle.set.%d.%d", SUBTITLE_UISHOW, mSessionId));
SUBTITLE_LOGE("SubtitleClientLinux: uiShow, ret %d.\n", ret);
return ret != -1 ? true : false;
}
bool SubtitleClientLinux::uiHide() {
int ret = SendMethodCall(format_string("subtitle.set.%d.%d", SUBTITLE_UIHIDE, mSessionId));
SUBTITLE_LOGE("SubtitleClientLinux: uiHide, ret %d.\n", ret);
return ret != -1 ? true : false;
}
bool SubtitleClientLinux::uiSetTextColor(int color) {
return true;
}
bool SubtitleClientLinux::uiSetTextSize(int size) {
return true;
}
bool SubtitleClientLinux::uiSetGravity(int gravity) {
return true;
}
bool SubtitleClientLinux::uiSetTextStyle(int style) {
return true;
}
bool SubtitleClientLinux::uiSetYOffset(int yOffset) {
return true;
}
bool SubtitleClientLinux::uiSetImageRatio(float ratioW, float ratioH, int32_t maxW, int32_t maxH) {
return true;
}
bool SubtitleClientLinux::uiGetSubDemision(int *pWidth, int *pHeight) {
return true;
}
bool SubtitleClientLinux::uiSetSurfaceViewRect(int x, int y, int width, int height) {
return true;
}
bool SubtitleClientLinux::setDvbCountryCode(int countryCode) {
int ret = SendMethodCall(format_string("subtitle.set.%d.%d.%d", SUBTITLE_SET_DVB_COUNTRYCODE,
mSessionId, countryCode));
SUBTITLE_LOGI("countryCode = %d, ret = %d", countryCode, ret);
return ret != -1 ? true : false;
}
void SubtitleClientLinux::prepareWritingQueue(int32_t size) {
/* char buf[32] = {0};
int ret = -1;
sprintf(buf, "subtitle.openConnection.%d", SUBTITLE_PREPAREWRITINGQUEUE);
SendMethodCall(buf);
ret = atoi(mRetBuf);
SUBTITLE_LOGE("SubtitleClientLinux: ret %d.\n", ret);
return ret;
*/
}
void SubtitleClientLinux::notify(int msg, int ext1, int ext2, const Parcel *obj) {
return;
}
void SubtitleClientLinux::setCallback(const sp<ISubtitleCallback> &callback, ConnectType type) {
/* char buf[32] = {0};
int ret = -1;
sprintf(buf, "subtitle.callback.%d", SUBTITLE_SETFALLCALLBACK);
SendMethodCall(buf);
ret = atoi(mRetBuf);
SUBTITLE_LOGE("SubtitleClientLinux: ret %d.\n", ret);
send.writeStrongBinder(sp<IBinder>(this));
tvServicebinder->transact(CMD_SET_TV_CB, send, &reply);
*/
// return ret;
}
void SubtitleClientLinux::setFallbackCallback(const sp<ISubtitleCallback> &callback,
ConnectType type) {
/* char buf[32] = {0};
int ret = -1;
sprintf(buf, "subtitle.addCallback.%d", SUBTITL_);
SendMethodCall(buf);
ret = atoi(mRetBuf);
SUBTITLE_LOGE("SubtitleClientLinux: ret %d.\n", ret);
return ret;
*/
}
void SubtitleClientLinux::removeCallback() {
char buf[32] = {0};
sprintf(buf, "subtitle.callback.%d", SUBTITLE_REMOVECALLBACK);
SendMethodCall(buf);
auto ret = atoi(mRetBuf);
SUBTITLE_LOGE("ret %d", ret);
}
void SubtitleClientLinux::registerOnDataCB() {
SUBTITLE_LOGI_FUNC_IN();
mWasRegisterOnDataCB = true;
}
void SubtitleClientLinux::doRegisterOnDataCB() {
if (!mWasRegisterOnDataCB) {
return;
}
auto ret =
SendMethodCall(format_string("subtitle.set.%d.%d", SUBTITLE_REGISTER_DATA_CB, mSessionId));
SUBTITLE_LOGE("ret = %d", ret);
}
void SubtitleClientLinux::SubtitleCallback::notify(int msg, int ext1, int ext2, const Parcel *obj) {
SUBTITLE_LOGI_FUNC_IN();
}
#if 1
void SubtitleClientLinux::SubtitleCallback::notifyDataCallback(SubtitleHidlParcel &parcel) {
// hidl_memory mem = parcel.mem;
int type = parcel.msgType;
// sp<IMemory> memory = mapMemory(mem);
int width = parcel.bodyInt[0];
int height = parcel.bodyInt[1];
int size = parcel.bodyInt[2];
int cmd = parcel.bodyInt[3];
int cordinateX = parcel.bodyInt[4];
int cordinateY = parcel.bodyInt[5];
int videoWidth = parcel.bodyInt[6];
int videoHeight = parcel.bodyInt[7];
int objectSegmetnId = parcel.bodyInt[8];
int keyid = parcel.shmid;
SUBTITLE_LOGI("processSubtitleData! aa %d %d,width=%d,height=%d", type, parcel.msgType, width,
height);
key_t key;
char pathname[30];
strcpy(pathname, "/tmp");
int shmId = shmget(6549, size, 0);
if (shmId == -1) {
SUBTITLE_LOGE("Error get shm ipc_id error shmid=%d, error=%s", shmId, strerror(errno));
return;
}
char *data = (char *)shmat(shmId, NULL, 0);
if (mListener != nullptr) {
mListener->onSubtitleEvent(data, size, type, cordinateX, cordinateY, width, height,
videoWidth, videoHeight, cmd, objectSegmetnId);
} else {
SUBTITLE_LOGI("error, no handle for this event!");
}
shmdt(data);
shmctl(shmId, IPC_RMID, NULL);
}
void SubtitleClientLinux::SubtitleCallback::eventNotify(SubtitleHidlParcel &parcel) {
}
void SubtitleClientLinux::SubtitleCallback::uiCommandCallback(SubtitleHidlParcel &parcel) {
}
#endif