/* * Copyright (C) 2014-2019 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 "SocketAPI" #include "SubtitleReportAPI.h" #include #include #include #include #include #include #include #include "AmSocketClient.h" #include "SubtitleClientLinux.h" #include "SubtitleLog.h" int mLastDuration = 0; int mSubType = 0; int mSubTotal = 0; char mSubTypeStr[1024] = {0}; char mSubLanStr[1024] = {0}; typedef struct { SubtitleClientLinux *mRemote; std::unique_ptr mSocketClient; int sId; std::mutex mLock; // TODO: maybe we need global lock } SubtitleReportContext; typedef enum { SUBTITLE_TOTAL_TRACK = 0x53544F54, // 'STOT' SUBTITLE_START_PTS = 0x53505453, // 'SPTS' SUBTITLE_RENDER_TIME = 0x53524454, // 'SRDT' SUBTITLE_SUB_TYPE = 0x53545950, // 'STYP' SUBTITLE_TYPE_STRING = 0x54505352, // 'TPSR' SUBTITLE_LANG_STRING = 0x4C475352, // 'LGSR' SUBTITLE_SUB_DATA = 0x504C4454, // 'PLDT' SUBTITLE_RESET_SERVER = 0x43545244, // 'CDRT' SUBTITLE_EXIT_SERVER = 0x43444558 // 'CDEX' } PayloadType; /** payload is: startFlag : 4bytes sessionID : 4Bytes (TBD) magic : 4bytes (for double confirm) payload size: 4Bytes (indicate the size of payload, size is total_send_bytes - 4*5) exclude this and above 4 items. payload Type: defined in PayloadType_t payload data: TO BE PARSED data */ const static unsigned int START_FLAG = 0xF0D0C0B1; const static unsigned int MAGIC_FLAG = 0xCFFFFFFB; const static unsigned int HEADER_SIZE = 4 * 5; static void inline makeHeader(char *buf, int sessionId, PayloadType t, int payloadSize) { unsigned int val = START_FLAG; memcpy(buf, &val, sizeof(val)); memcpy(buf + sizeof(int), &sessionId, sizeof(int)); val = MAGIC_FLAG; // magic memcpy(buf + 2 * sizeof(int), &val, sizeof(int)); memcpy(buf + 3 * sizeof(int), &payloadSize, sizeof(int)); val = t; memcpy(buf + 4 * sizeof(val), &val, sizeof(val)); } static void socketSendData(SubtitleReportContext *ctx, const char *mbuf, size_t length, int64_t pts) { if (mbuf == NULL) { return; } unsigned int sub_type; float duration = 0; int64_t sub_pts = 0; int64_t start_time = 0; int data_size = length; if (length <= 0) { SUBTITLE_LOGE("[sendToSubtitleService]not enough data.data_size:%d\n", length); return; } sub_type = CODEC_ID_DVB_SUBTITLE; // streamCodecID; if (sub_type == CODEC_ID_DVD_SUBTITLE) { mSubType = 0; } else if (sub_type == CODEC_ID_HDMV_PGS_SUBTITLE) { mSubType = 1; } else if (sub_type == CODEC_ID_XSUB) { mSubType = 2; } else if (sub_type == CODEC_ID_TEXT || sub_type == CODEC_ID_SSA || sub_type == CODEC_ID_ASS) { mSubType = 3; } else if (sub_type == CODEC_ID_DVB_SUBTITLE) { mSubType = 5; } else if (sub_type == 0x17005) { mSubType = 7; } else if (sub_type == CODEC_ID_DVB_TELETEXT) { mSubType = 9; // SUBTITLE_DVB_TELETEXT } else { mSubType = 4; } // if (mDebug) { // SUBTITLE_LOGE("[sendToSubtitleService]sub_type:0x%x, data_size:%d, sub_pts:%" PRId64 // "\n", sub_type, data_size, pts); // } if (sub_type == 0x17000) { sub_type = 0x1700a; } else if (sub_type == 0x17002) { mLastDuration = 0; //(unsigned)pktConvergenceDuration * 90; } // 0x1780d:mkv internal ass 0x17808:internal UTF-8 else if (sub_type == 0x1780d || sub_type == 0x17808) { mLastDuration = 0; //(unsigned)pktDuration * 90; //time(ms) convert to pts, need *90 } else if (sub_type == 0x17003) { return; // not need to support xsub } unsigned char sub_header[24] = {0x41, 0x4d, 0x4c, 0x55, 0x77, 0}; // unsigned char sub_header[24] = {0}; // unsigned char subInfo_header[10] = {0}; //add info header mSubType, mSubTotal send with // subtitle packet. sub_header[5] = (sub_type >> 16) & 0xff; sub_header[6] = (sub_type >> 8) & 0xff; sub_header[7] = sub_type & 0xff; sub_header[8] = (data_size >> 24) & 0xff; sub_header[9] = (data_size >> 16) & 0xff; sub_header[10] = (data_size >> 8) & 0xff; sub_header[11] = data_size & 0xff; sub_header[12] = (pts >> 56) & 0xff; sub_header[13] = (pts >> 48) & 0xff; sub_header[14] = (pts >> 40) & 0xff; sub_header[15] = (pts >> 32) & 0xff; sub_header[16] = (pts >> 24) & 0xff; sub_header[17] = (pts >> 16) & 0xff; sub_header[18] = (pts >> 8) & 0xff; sub_header[19] = pts & 0xff; sub_header[20] = (mLastDuration >> 24) & 0xff; sub_header[21] = (mLastDuration >> 16) & 0xff; sub_header[22] = (mLastDuration >> 8) & 0xff; sub_header[23] = mLastDuration & 0xff; int size = 24 + data_size + 5 * 4; int data_length = 24 + data_size; char *data = (char *)malloc(size); memset(data, 0, size); int sessionId = 1; unsigned int val = START_FLAG; memcpy(data, &val, sizeof(val)); memcpy(data + 1 * sizeof(int), &sessionId, sizeof(int)); int val1 = MAGIC_FLAG; // magic memcpy(data + 2 * sizeof(int), &val1, sizeof(int)); memcpy(data + 3 * sizeof(int), &data_length, sizeof(int)); int type = SUBTITLE_SUB_DATA; memcpy(data + 4 * sizeof(int), &type, sizeof(int)); memcpy(data + 5 * sizeof(int), sub_header, 24); memcpy(data + 5 * sizeof(int) + 24, mbuf, data_size); if (ctx->mSocketClient != NULL) { usleep(500); ctx->mSocketClient->socketSend(data, size); } else { SUBTITLE_LOGE("[sendToSubtitleService] mClient == NULL\n"); } if (data != nullptr) { free(data); data = nullptr; } } // TODO: move all the report API to subtitlebinder SubSourceHandle SubSource_Create(int sId) { SubtitleReportContext *ctx = new SubtitleReportContext(); if (ctx == nullptr) return nullptr; SUBTITLE_LOGI("SubSource Create %d", sId); ctx->mLock.lock(); SUBTITLE_LOGI("ctx->mSocketClient: %p", ctx->mSocketClient.get()); if (ctx->mSocketClient == NULL) { std::unique_ptr pTemp(new AmSocketClient); ctx->mSocketClient = std::move(pTemp); // unique_ptr;//new // AmSocketClient(); // socket may not ready due to 2 process synchr, checking and retry int retry = 100; while (retry-- >= 0) { SUBTITLE_LOGI("socketConnect..., %d", retry); if (ctx->mSocketClient->socketConnect() == 0) { break; } usleep(10 * 1000); } } ctx->sId = sId; ctx->mLock.unlock(); SUBTITLE_LOGI_FUNC_OUT(); return ctx; } SubSourceStatus SubSource_Destroy(SubSourceHandle handle) { SubtitleReportContext *ctx = (SubtitleReportContext *)handle; if (ctx == nullptr) { SUBTITLE_LOGE("ctx is null"); return SUB_STAT_INV; } SUBTITLE_LOGI("SubSource destroy %d", ctx->sId); ctx->mLock.lock(); // ctx->mRemote = nullptr; ctx->mSocketClient->socketDisconnect(); ctx->mSocketClient.reset(); ctx->mLock.unlock(); delete ctx; SUBTITLE_LOGI_FUNC_OUT(); return SUB_STAT_OK; } SubSourceStatus SubSource_Reset(SubSourceHandle handle) { SubtitleReportContext *ctx = (SubtitleReportContext *)handle; if (ctx == nullptr) return SUB_STAT_INV; SUBTITLE_LOGI("SubSource reset %d", ctx->sId); std::lock_guard guard(ctx->mLock); char buffer[64]; memset(buffer, 0, 64); makeHeader(buffer, ctx->sId, SUBTITLE_RESET_SERVER, 7); strcpy(buffer + HEADER_SIZE, "reset\n"); ctx->mSocketClient->socketSend(buffer, HEADER_SIZE + 7); return SUB_STAT_OK; } SubSourceStatus SubSource_Stop(SubSourceHandle handle) { SubtitleReportContext *ctx = (SubtitleReportContext *)handle; if (ctx == nullptr) return SUB_STAT_INV; SUBTITLE_LOGI("SubSource destroy %d", ctx->sId); std::lock_guard guard(ctx->mLock); char buffer[64]; memset(buffer, 0, 64); makeHeader(buffer, ctx->sId, SUBTITLE_EXIT_SERVER, 6); strcpy(buffer + HEADER_SIZE, "exit\n"); ctx->mSocketClient->socketSend(buffer, HEADER_SIZE + 6); SUBTITLE_LOGI_FUNC_OUT(); return SUB_STAT_OK; } SubSourceStatus SubSource_ReportRenderTime(SubSourceHandle handle, int64_t timeUs) { SubtitleReportContext *ctx = (SubtitleReportContext *)handle; static int count = 0; if (ctx == nullptr) return SUB_STAT_INV; if (count++ % 1000 == 0) SUBTITLE_LOGI("SubSource ReportRenderTime %d 0x%llx", ctx->sId, timeUs); std::lock_guard guard(ctx->mLock); char buffer[64]; makeHeader(buffer, ctx->sId, SUBTITLE_RENDER_TIME, sizeof(int64_t)); memcpy(buffer + HEADER_SIZE, &timeUs, sizeof(int64_t)); ctx->mSocketClient->socketSend(buffer, HEADER_SIZE + sizeof(int64_t)); return SUB_STAT_OK; } SubSourceStatus SubSource_ReportStartPts(SubSourceHandle handle, int64_t pts) { SubtitleReportContext *ctx = (SubtitleReportContext *)handle; if (ctx == nullptr) return SUB_STAT_INV; SUBTITLE_LOGI("SubSource ReportStartPts %d 0x%llx", ctx->sId, pts); std::lock_guard guard(ctx->mLock); char buffer[64]; makeHeader(buffer, ctx->sId, SUBTITLE_START_PTS, sizeof(pts)); memcpy(buffer + HEADER_SIZE, &pts, sizeof(pts)); ctx->mSocketClient->socketSend(buffer, HEADER_SIZE + sizeof(pts)); return SUB_STAT_OK; } SubSourceStatus SubSource_ReportTotalTracks(SubSourceHandle handle, int trackNum) { SubtitleReportContext *ctx = (SubtitleReportContext *)handle; if (ctx == nullptr) return SUB_STAT_INV; SUBTITLE_LOGI("SubSource ReportTotalTracks %d 0x%x", ctx->sId, trackNum); std::lock_guard guard(ctx->mLock); char buffer[64]; makeHeader(buffer, ctx->sId, SUBTITLE_TOTAL_TRACK, sizeof(trackNum)); memcpy(buffer + HEADER_SIZE, &trackNum, sizeof(trackNum)); ctx->mSocketClient->socketSend(buffer, HEADER_SIZE + sizeof(trackNum)); return SUB_STAT_OK; } SubSourceStatus SubSource_ReportType(SubSourceHandle handle, int type) { SubtitleReportContext *ctx = (SubtitleReportContext *)handle; if (ctx == nullptr) return SUB_STAT_INV; SUBTITLE_LOGI("SubSource ReportType %d 0x%x", ctx->sId, type); std::lock_guard guard(ctx->mLock); char buffer[64]; makeHeader(buffer, ctx->sId, SUBTITLE_SUB_TYPE, sizeof(type)); memcpy(buffer + HEADER_SIZE, &type, sizeof(type)); ctx->mSocketClient->socketSend(buffer, HEADER_SIZE + sizeof(type)); return SUB_STAT_OK; } SubSourceStatus SubSource_ReportSubTypeString(SubSourceHandle handle, const char *type) { SubtitleReportContext *ctx = (SubtitleReportContext *)handle; std::lock_guard guard(ctx->mLock); if (ctx == nullptr) return SUB_STAT_INV; char *buffer = new char[strlen(type) + 1 + HEADER_SIZE](); if (buffer == nullptr) return SUB_STAT_INV; SUBTITLE_LOGI("SubSource ReportTypeString %d %s", ctx->sId, type); makeHeader(buffer, ctx->sId, SUBTITLE_TYPE_STRING, strlen(type) + 1); memcpy(buffer + HEADER_SIZE, type, strlen(type)); ctx->mSocketClient->socketSend(buffer, HEADER_SIZE + sizeof(type) + 1); delete[] buffer; return SUB_STAT_OK; } SubSourceStatus SubSource_ReportLauguageString(SubSourceHandle handle, const char *lang) { SubtitleReportContext *ctx = (SubtitleReportContext *)handle; std::lock_guard guard(ctx->mLock); if (ctx == nullptr) return SUB_STAT_INV; SUBTITLE_LOGI("SubSource ReportLangString %d %s", ctx->sId, lang); char *buffer = new char[strlen(lang) + 1 + HEADER_SIZE](); if (buffer == nullptr) return SUB_STAT_INV; makeHeader(buffer, ctx->sId, SUBTITLE_LANG_STRING, strlen(lang) + 1); memcpy(buffer + HEADER_SIZE, lang, strlen(lang)); ctx->mSocketClient->socketSend(buffer, HEADER_SIZE + strlen(lang) + 1); delete[] buffer; return SUB_STAT_OK; } // Send subtitle data without durationPts SubSourceStatus SubSource_SendData(SubSourceHandle handle, const char *mbuf, int length, int64_t pts, enum CodecID sub_type) { SubtitleReportContext *ctx = (SubtitleReportContext *)handle; if (ctx == nullptr) return SUB_STAT_INV; SUBTITLE_LOGI( "sId=%d, length=%d," "pts=%" PRId64 ", sub_type=%d", ctx->sId, length, pts, sub_type); std::lock_guard guard(ctx->mLock); float duration = 0; int64_t sub_pts = 0; int64_t start_time = 0; int data_size = length; if (length <= 0) { SUBTITLE_LOGE("[sendToSubtitleService]not enough data.data_size:%d\n", length); return SUB_STAT_INV; } // sub_type = CODEC_ID_DVB_SUBTITLE;//streamCodecID; if (sub_type == CODEC_ID_DVD_SUBTITLE) { mSubType = 0; } else if (sub_type == CODEC_ID_HDMV_PGS_SUBTITLE) { mSubType = 1; } else if (sub_type == CODEC_ID_XSUB) { mSubType = 2; } else if (sub_type == CODEC_ID_TEXT || sub_type == CODEC_ID_SSA || sub_type == CODEC_ID_ASS) { mSubType = 3; } else if (sub_type == CODEC_ID_DVB_SUBTITLE) { mSubType = 5; } else if (sub_type == CODEC_ID_MOV_TEXT) { mSubType = 7; } else if (sub_type == CODEC_ID_DVB_TELETEXT) { mSubType = 9; // SUBTITLE_DVB_TELETEXT } else if (sub_type == CODEC_ID_TTML_SUBTITLE) { mSubType = 18; // SUBTITLE_TTML } else if (sub_type == CODEC_ID_SMPTE_TTML_SUBTITLE) { mSubType = 20; // SUBTITLE_SMPTE_TTML } else { mSubType = 4; } // if (mDebug) { // SUBTITLE_LOGE("[sendToSubtitleService]sub_type:0x%x, data_size:%d, sub_pts:%" PRId64 ", // durationPts:%" PRId64 "\n", sub_type, data_size, pts, durationPts); // } if (sub_type == CODEC_ID_DVD_SUBTITLE) { sub_type = static_cast(0x1700a); // Invalid } // 0x1780d:mkv internal ass 0x17808:internal UTF-8 else if (sub_type == CODEC_ID_XSUB) { return SUB_STAT_INV; // not need to support xsub } unsigned char sub_header[24] = {0x41, 0x4d, 0x4c, 0x55, 0x77, 0}; // unsigned char sub_header[24] = {0}; // unsigned char subInfo_header[10] = {0}; //add info header mSubType, mSubTotal send with // subtitle packet. sub_header[5] = (sub_type >> 16) & 0xff; sub_header[6] = (sub_type >> 8) & 0xff; sub_header[7] = sub_type & 0xff; sub_header[8] = (data_size >> 24) & 0xff; sub_header[9] = (data_size >> 16) & 0xff; sub_header[10] = (data_size >> 8) & 0xff; sub_header[11] = data_size & 0xff; sub_header[12] = (pts >> 56) & 0xff; sub_header[13] = (pts >> 48) & 0xff; sub_header[14] = (pts >> 40) & 0xff; sub_header[15] = (pts >> 32) & 0xff; sub_header[16] = (pts >> 24) & 0xff; sub_header[17] = (pts >> 16) & 0xff; sub_header[18] = (pts >> 8) & 0xff; sub_header[19] = pts & 0xff; sub_header[20] = (mLastDuration >> 24) & 0xff; sub_header[21] = (mLastDuration >> 16) & 0xff; sub_header[22] = (mLastDuration >> 8) & 0xff; sub_header[23] = mLastDuration & 0xff; int size = 24 + data_size + 5 * 4; int data_length = 24 + data_size; char *data = (char *)malloc(size); memset(data, 0, size); SUBTITLE_LOGI("data_length= %d", data_length); makeHeader(data, ctx->sId, SUBTITLE_SUB_DATA, data_length); /*int sessionId = ctx->sId; unsigned int val = START_FLAG; memcpy(data, &val, sizeof(val)); memcpy(data+1*sizeof(int), &sessionId, sizeof(int)); int val1 = MAGIC_FLAG; // magic memcpy(data+2*sizeof(int), &val1, sizeof(int)); memcpy(data+3*sizeof(int), &data_length, sizeof(int)); int type =SUBTITLE_SUB_DATA; memcpy(data+4*sizeof(int), &type, sizeof(int));*/ memcpy(data + 5 * sizeof(int), sub_header, 24); memcpy(data + 5 * sizeof(int) + 24, mbuf, data_size); if (ctx->mSocketClient != NULL) { usleep(500); ctx->mSocketClient->socketSend(data, size); } else { SUBTITLE_LOGE("[sendToSubtitleService] mClient == NULL\n"); } if (data != nullptr) { free(data); data = nullptr; } SUBTITLE_LOGI("end %d %d", ctx->sId, size); return SUB_STAT_OK; } // Send subtitle data with durationPts SubSourceStatus SubSource_SendDataEx(SubSourceHandle handle, const char *mbuf, int length, int64_t pts, int64_t durationPts, enum CodecID sub_type) { // protocol socket only supports 32-bit durationPts mLastDuration = (int)durationPts; return SubSource_SendData(handle, mbuf, length, pts, sub_type); } SubSourceStatus SubSource_GetVersion(SubSourceHandle handle, int *version) { *version = 2; return SUB_STAT_OK; };