/* * Copyright (C) 2014-2025 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_TAG "SubtitleServiceLinux" #include "SubtitleServiceLinux.h" #include #include #include #include #include #include #include #include #include "SubtitleLog.h" #include "SubtitleServer.h" #include "subtitlecmd.h" #define SERVER_PORT 10200 #ifdef __cplusplus extern "C" { #endif SubtitleServiceLinux *mInstance = NULL; SubtitleServiceLinux *SubtitleServiceLinux::GetInstance() { SUBTITLE_LOGI("SubtitleServiceLinux"); if (mInstance == NULL) { mInstance = new SubtitleServiceLinux(); } return mInstance; } static pthread_once_t threadFlag = PTHREAD_ONCE_INIT; SubtitleServiceLinux::SubtitleServiceLinux() { mIpcSocket = std::make_shared(true); mIpcSocket->start(SERVER_PORT, this, []() { pthread_once(&threadFlag, [] { SubtitleSignalHandler::instance().installSignalHandlers(); }); }); if (!mIpcSocket->isvalid()) { SUBTITLE_LOGE("Server socket init failed"); mIpcSocket->stop(); return; } mIpcSocket->setEventListener(eventReceiver); mpSubtitlecontrol = SubtitleServer::Instance(); } /*static*/ int SubtitleServiceLinux::eventReceiver(int fd, void *selfData) { auto subService = static_cast(selfData); if (subService == nullptr) { return EventsTracker::RET_REMOVE; } char recvBuf[1024] = {0}; int retLen = IpcSocket::receive(fd, recvBuf, sizeof(recvBuf)); if (retLen <= 0) { if (retLen == 0) { SUBTITLE_LOGE("Client broken, fd=%d, remove.", fd); subService->onRemoteDead(0); return EventsTracker::RET_REMOVE; } if (errno == EAGAIN || errno == EWOULDBLOCK) { return EventsTracker::RET_CONTINUE; } SUBTITLE_LOGE("recv error (fd=%d): %m", fd); return EventsTracker::RET_REMOVE; } SUBTITLE_LOGI("Receive: %s", recvBuf); int ret = subService->ParserSubtitleCommand(recvBuf, nullptr); std::string retStr = std::to_string(ret); bool send = IpcSocket::send(fd, retStr.c_str(), retStr.size()); SUBTITLE_LOGI("Reply %s", (send ? "OK" : "NG")); return EventsTracker::RET_CONTINUE; } SubtitleServiceLinux::~SubtitleServiceLinux() { SUBTITLE_LOGI("SubtitleServiceLinux"); if (mpSubtitlecontrol != NULL) { delete mpSubtitlecontrol; mpSubtitlecontrol = NULL; } } int SubtitleServiceLinux::SplitCommand(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) { mSubtitleCommand[cmd_size].assign(token); // SUBTITLE_LOGE("%s mSubtitleCommand[%d]:%s\n", token, cmd_size, // mSubtitleCommand[cmd_size].c_str()); cmd_size++; token = strtok(NULL, delimitation); } // SUBTITLE_LOGI("cmd_size = %d\n", cmd_size); return cmd_size; } int SubtitleServiceLinux::SetTeleCmd(subtitle_module_param_t param) { int ret = 0; int moduleId = param.moduleId; if ((moduleId >= SUBTITLE_MODULE_CMD_START) && (moduleId <= SUBTITLE_CMD_MAX)) { int paramData[32] = {0}; int i = 0; for (i = 0; i < param.paramLength; i++) { paramData[i] = param.paramBuf[i]; } switch (moduleId) { case SUBTITLE_TTCONTROL: mpSubtitlecontrol->ttControl(paramData[0], paramData[1], paramData[2], paramData[3], paramData[4], paramData[5]); break; case SUBTITLE_TTGOHOME: mpSubtitlecontrol->ttGoHome(paramData[0]); break; case SUBTITLE_TTNEXTPAGE: mpSubtitlecontrol->ttNextPage(paramData[0], paramData[1]); break; case SUBTITLE_TTNEXTSUBPAGE: mpSubtitlecontrol->ttNextSubPage(paramData[0], paramData[1]); break; case SUBTITLE_TTGOTOPAGE: mpSubtitlecontrol->ttGotoPage(paramData[0], paramData[1], paramData[2]); break; default: break; } } else { SUBTITLE_LOGE("invalid Subtitle cmd: %d\n", moduleId); ret = -1; } return ret; } int SubtitleServiceLinux::SetCmd(subtitle_module_param_t param, native_handle_t *handle) { int ret = 0; int moduleId = param.moduleId; SUBTITLE_LOGD("moduleId = %d", moduleId); if ((moduleId >= SUBTITLE_MODULE_CMD_START) && (moduleId <= SUBTITLE_CMD_MAX)) { int paramData[32] = {0}; int i = 0; for (i = 0; i < param.paramLength; i++) { paramData[i] = param.paramBuf[i]; } SUBTITLE_LOGD("moduleId = %d, paramData[0]=%d, paramData[1]=%d", moduleId, paramData[0], paramData[1]); switch (moduleId) { case SUBTITLE_OPENCONNECTION: ret = mpSubtitlecontrol->openConnection(); break; case SUBTITLE_CLOSECONNECTION: ret = mpSubtitlecontrol->closeConnection(paramData[0]); break; case SUBTITLE_OPEN: updateSubtitleLogLevel(); ret = mpSubtitlecontrol->open(paramData[0], paramData[1], (OpenType)paramData[2], handle); break; case SUBTITLE_CLOSE: SUBTITLE_LOGI("SUBTITLE_CLOSE"); ret = mpSubtitlecontrol->close(paramData[0]); break; case SUBTITLE_RESETFORSEEK: SUBTITLE_LOGI("SUBTITLE_RESETFORSEEK"); break; case SUBTITLE_UPDATEVIDEOPTS: static int logCnt = 0; if (++logCnt % 100 == 0) { SUBTITLE_LOGI("SUBTITLE_UPDATEVIDEOPTS"); } ret = mpSubtitlecontrol->updateVideoPos(paramData[0], paramData[1]); break; case SUBTITLE_SETPAGEID: SUBTITLE_LOGI("SUBTITLE_SETPAGEID"); ret = mpSubtitlecontrol->setPageId(paramData[0], paramData[1]); break; case SUBTITLE_SETANCPAGEID: SUBTITLE_LOGI("SUBTITLE_SETANCPAGEID"); ret = mpSubtitlecontrol->setAncPageId(paramData[0], paramData[1]); break; case SBUTITLE_SETCHANNELID: SUBTITLE_LOGI("SBUTITLE_SETCHANNELID"); ret = mpSubtitlecontrol->setChannelId(paramData[0], paramData[1]); break; case SUBTITLE_SETCLOSECAPTIONVFMT: SUBTITLE_LOGI("SUBTITLE_SETCLOSECAPTIONVFMT"); break; case SUBTITLE_USERDATAOPEN: SUBTITLE_LOGI("SUBTITLE_USERDATAOPEN"); ret = mpSubtitlecontrol->userDataOpen(paramData[0]); break; case SUBTITLE_USERDATACLOSE: SUBTITLE_LOGI("SUBTITLE_USERDATACLOSE"); ret = mpSubtitlecontrol->userDataClose(paramData[0]); break; case SUBTITLE_SETSUBTYPE: ret = mpSubtitlecontrol->setSubType(paramData[0], paramData[1]); break; case SUBTITLE_REGISTER_DATA_CB: ret = mpSubtitlecontrol->registerOnDataCB(paramData[0]); break; case SUBTITLE_SETPIPID: ret = mpSubtitlecontrol->setPipId(paramData[0], paramData[1], paramData[2]); break; case SUBTITLE_GETSUBPID: ret = mpSubtitlecontrol->setSubPid(paramData[0], paramData[1]); break; case SUBTITLE_GETSUBTITLESTATUS: ret = mpSubtitlecontrol->getSubtitleStatus(paramData[0], paramData[1], paramData[2]); break; case SUBTITLE_SETSECURELEVEL: ret = mpSubtitlecontrol->setSecureLevel(paramData[0], paramData[1]); break; case SUBTITLE_UISHOW: ret = mpSubtitlecontrol->show(paramData[0]); break; case SUBTITLE_UIHIDE: ret = mpSubtitlecontrol->hide(paramData[0]); break; case SUBTITLE_SET_DVB_COUNTRYCODE: ret = mpSubtitlecontrol->setDvbCountryCode(paramData[0], paramData[1]); break; default: SUBTITLE_LOGE("Can not be recognized moduleId: %d", moduleId); break; } } else { SUBTITLE_LOGE("invalid Subtitle cmd: %d\n", moduleId); ret = -1; } return ret; } void SubtitleServiceLinux::join() { if (mIpcSocket != nullptr) { mIpcSocket->join(); } } int SubtitleServiceLinux::GetCmd(subtitle_module_param_t param) { int ret = 0; int moduleId = param.moduleId; if ((moduleId >= SUBTITLE_MODULE_CMD_START) && (moduleId <= SUBTITLE_CMD_MAX)) { switch (moduleId) { case SUBTITLE_GETTYPE: // ret = mpSubtitlecontrol->GetHue(); break; case SUBTITLE_GETTOTALTRACKS: // ret = mpSubtitlecontrol->GetGrayPattern(); break; case SUBTITLE_GETLANGUAGE: break; case SUBTITLE_GETSUBTYPE: break; case SUBTITLE_GETSUBPID: break; case SUBTITLE_GETANCPAGE: break; default: break; } } else { SUBTITLE_LOGE("invalid SUBTITLE cmd: %d!\n", moduleId); ret = -1; } return ret; } void SubtitleServiceLinux::onRemoteDead(int sessionId) { if (mpSubtitlecontrol && !mpSubtitlecontrol->isClosed(sessionId)) { if (mpSubtitlecontrol->close(sessionId) == Result::OK && mpSubtitlecontrol->closeConnection(sessionId) == Result::OK) { SUBTITLE_LOGI("onRemoteDead, self close OK for id %d", sessionId); } else { SUBTITLE_LOGI("onRemoteDead, self close failed for id %d", sessionId); } } else { SUBTITLE_LOGI("onRemoteDead, already closed for id %d", sessionId); } } int SubtitleServiceLinux::ParserSubtitleCommand(const char *commandData, native_handle_t *handle) { SUBTITLE_LOGI("cmd data is %s\n", commandData); int cmd_size = 0; int ret = 0; int i = 0; // split command cmd_size = SplitCommand(commandData); // parse command subtitle_module_param_t subtitleParam; memset(&subtitleParam, 0, sizeof(subtitle_module_param_t)); subtitleParam.moduleId = atoi(mSubtitleCommand[2].c_str()); subtitleParam.paramLength = cmd_size - 3; for (i = 0; i < subtitleParam.paramLength; i++) { subtitleParam.paramBuf[i] = atoi(mSubtitleCommand[i + 3].c_str()); } SUBTITLE_LOGD("cmd command0 is %s, command1 is %s\n", mSubtitleCommand[0].c_str(), mSubtitleCommand[1].c_str()); if (strcmp(mSubtitleCommand[0].c_str(), "subtitle") == 0) { if ((strcmp(mSubtitleCommand[1].c_str(), "ctrl") == 0) || (strcmp(mSubtitleCommand[1].c_str(), "set") == 0) || (strcmp(mSubtitleCommand[1].c_str(), "afdcontrol") == 0)) { ret = SetCmd(subtitleParam, handle); } else if (strcmp(mSubtitleCommand[1].c_str(), "get") == 0) { ret = GetCmd(subtitleParam); } else if (strcmp(mSubtitleCommand[1].c_str(), "ttcontrol") == 0) { ret = SetTeleCmd(subtitleParam); } else if (strcmp(mSubtitleCommand[1].c_str(), "getSubtitleStatus") == 0) { ret = SetCmd(subtitleParam, handle); } else if (strcmp(mSubtitleCommand[1].c_str(), "afdctrl") == 0) { ret = GetCmd(subtitleParam); } else { SUBTITLE_LOGI("invalid cmd\n"); ret = 0; } } else { SUBTITLE_LOGI("invalie cmdType\n"); } return ret; } #ifdef __cplusplus } #endif