13b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang/*
23b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang * Copyright (C) 2017 The Android Open Source Project
33b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang *
43b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang * Licensed under the Apache License, Version 2.0 (the "License");
53b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang * you may not use this file except in compliance with the License.
63b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang * You may obtain a copy of the License at
73b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang *
83b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang *      http://www.apache.org/licenses/LICENSE-2.0
93b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang *
103b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang * Unless required by applicable law or agreed to in writing, software
113b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang * distributed under the License is distributed on an "AS IS" BASIS,
123b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang * See the License for the specific language governing permissions and
143b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang * limitations under the License.
153b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang */
163b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang
173b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang//#define LOG_NDEBUG 0
183b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang#define LOG_TAG "CasManager"
193b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang#include "CasManager.h"
203b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang
213b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang#include <android/media/ICas.h>
223b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang#include <android/media/IDescrambler.h>
233b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang#include <android/media/IMediaCasService.h>
243b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang#include <binder/IServiceManager.h>
253b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang#include <media/stagefright/foundation/ABitReader.h>
263b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang#include <utils/Log.h>
273b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang
283b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhangnamespace android {
293b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhangusing binder::Status;
303b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang
313b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhangstruct ATSParser::CasManager::ProgramCasManager : public RefBase {
323b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    ProgramCasManager(unsigned programNumber, const CADescriptor &descriptor);
333b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    ProgramCasManager(unsigned programNumber);
343b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang
353b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    bool addStream(unsigned elementaryPID, const CADescriptor &descriptor);
363b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang
373b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    status_t setMediaCas(const sp<ICas> &cas, PidToSessionMap &sessionMap);
383b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang
393b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    bool getCasSession(unsigned elementaryPID,
403b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang            sp<IDescrambler> *descrambler, std::vector<uint8_t> *sessionId) const;
413b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang
423b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    void closeAllSessions(const sp<ICas>& cas);
433b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang
443b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhangprivate:
453b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    struct CasSession {
463b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        CasSession() {}
473b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        CasSession(const CADescriptor &descriptor) :
483b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang            mCADescriptor(descriptor) {}
493b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang
503b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        CADescriptor mCADescriptor;
513b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        std::vector<uint8_t> mSessionId;
523b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        sp<IDescrambler> mDescrambler;
533b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    };
543b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    status_t initSession(
55a78c1cc9773532b1f9d066ed8fa0d9414c1bb8bbChong Zhang            const sp<ICas>& cas,
56a78c1cc9773532b1f9d066ed8fa0d9414c1bb8bbChong Zhang            PidToSessionMap &sessionMap,
57a78c1cc9773532b1f9d066ed8fa0d9414c1bb8bbChong Zhang            CasSession *session);
583b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    void closeSession(const sp<ICas>& cas, const CasSession &casSession);
593b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang
603b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    unsigned mProgramNumber;
613b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    bool mHasProgramCas;
623b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    CasSession mProgramCas;
633b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    KeyedVector<unsigned, CasSession> mStreamPidToCasMap;
643b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang};
653b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang
663b2847fa5506dc265d2e46f067bfbb66ae209f74Chong ZhangATSParser::CasManager::ProgramCasManager::ProgramCasManager(
673b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        unsigned programNumber, const CADescriptor &descriptor) :
683b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    mProgramNumber(programNumber),
693b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    mHasProgramCas(true),
703b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    mProgramCas(descriptor) {}
713b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang
723b2847fa5506dc265d2e46f067bfbb66ae209f74Chong ZhangATSParser::CasManager::ProgramCasManager::ProgramCasManager(
733b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        unsigned programNumber) :
743b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    mProgramNumber(programNumber),
753b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    mHasProgramCas(false) {}
763b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang
773b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhangbool ATSParser::CasManager::ProgramCasManager::addStream(
783b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        unsigned elementaryPID, const CADescriptor &descriptor) {
793b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    ssize_t index = mStreamPidToCasMap.indexOfKey(elementaryPID);
803b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    if (index >= 0) {
813b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        return false;
823b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    }
833b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    ALOGV("addStream: program=%d, elementaryPID=%d, CA_system_ID=0x%x",
843b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang            mProgramNumber, elementaryPID, descriptor.mSystemID);
853b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    mStreamPidToCasMap.add(elementaryPID, CasSession(descriptor));
863b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    return true;
873b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang}
883b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang
893b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhangstatus_t ATSParser::CasManager::ProgramCasManager::setMediaCas(
903b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        const sp<ICas> &cas, PidToSessionMap &sessionMap) {
913b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    if (mHasProgramCas) {
92a78c1cc9773532b1f9d066ed8fa0d9414c1bb8bbChong Zhang        return initSession(cas, sessionMap, &mProgramCas);
933b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    }
94a78c1cc9773532b1f9d066ed8fa0d9414c1bb8bbChong Zhang    // TODO: share session among streams that has identical CA_descriptors.
95a78c1cc9773532b1f9d066ed8fa0d9414c1bb8bbChong Zhang    // For now, we open one session for each stream that has CA_descriptor.
963b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    for (size_t index = 0; index < mStreamPidToCasMap.size(); index++) {
97a78c1cc9773532b1f9d066ed8fa0d9414c1bb8bbChong Zhang        status_t err = initSession(
98a78c1cc9773532b1f9d066ed8fa0d9414c1bb8bbChong Zhang                cas, sessionMap, &mStreamPidToCasMap.editValueAt(index));
99a78c1cc9773532b1f9d066ed8fa0d9414c1bb8bbChong Zhang        if (err != OK) {
1003b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang            return err;
1013b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        }
1023b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    }
1033b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    return OK;
1043b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang}
1053b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang
1063b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhangbool ATSParser::CasManager::ProgramCasManager::getCasSession(
1073b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        unsigned elementaryPID, sp<IDescrambler> *descrambler,
1083b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        std::vector<uint8_t> *sessionId) const {
1093b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    if (mHasProgramCas) {
1103b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        *descrambler = mProgramCas.mDescrambler;
1113b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        *sessionId = mProgramCas.mSessionId;
1123b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        return true;
1133b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    }
1143b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    ssize_t index = mStreamPidToCasMap.indexOfKey(elementaryPID);
1153b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    if (index < 0) {
1163b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        return false;
1173b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    }
1183b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang
1193b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    *descrambler = mStreamPidToCasMap[index].mDescrambler;
1203b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    *sessionId = mStreamPidToCasMap[index].mSessionId;
1213b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    return true;
1223b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang}
1233b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang
1243b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhangstatus_t ATSParser::CasManager::ProgramCasManager::initSession(
125a78c1cc9773532b1f9d066ed8fa0d9414c1bb8bbChong Zhang         const sp<ICas>& cas,
126a78c1cc9773532b1f9d066ed8fa0d9414c1bb8bbChong Zhang         PidToSessionMap &sessionMap,
127a78c1cc9773532b1f9d066ed8fa0d9414c1bb8bbChong Zhang         CasSession *session) {
1283b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    sp<IServiceManager> sm = defaultServiceManager();
1293b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    sp<IBinder> casServiceBinder = sm->getService(String16("media.cas"));
1303b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    sp<IMediaCasService> casService =
1313b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang            interface_cast<IMediaCasService>(casServiceBinder);
1323b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang
1333b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    if (casService == NULL) {
1343b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        ALOGE("Cannot obtain IMediaCasService");
1353b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        return NO_INIT;
1363b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    }
1373b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang
1383b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    sp<IDescrambler> descrambler;
1393b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    std::vector<uint8_t> sessionId;
1403b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    const CADescriptor &descriptor = session->mCADescriptor;
1413b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang
142a78c1cc9773532b1f9d066ed8fa0d9414c1bb8bbChong Zhang    Status status = cas->openSession(&sessionId);
1433b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    if (!status.isOk()) {
1443b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        ALOGE("Failed to open session: exception=%d, error=%d",
1453b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang                status.exceptionCode(), status.serviceSpecificErrorCode());
1463b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        goto l_fail;
1473b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    }
1483b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang
1493b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    cas->setSessionPrivateData(sessionId, descriptor.mPrivateData);
1503b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    if (!status.isOk()) {
1513b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        ALOGE("Failed to set private data: exception=%d, error=%d",
1523b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang                status.exceptionCode(), status.serviceSpecificErrorCode());
1533b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        goto l_fail;
1543b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    }
1553b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang
1563b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    status = casService->createDescrambler(descriptor.mSystemID, &descrambler);
1573b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    if (!status.isOk() || descrambler == NULL) {
1583b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        ALOGE("Failed to create descrambler: : exception=%d, error=%d",
1593b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang                status.exceptionCode(), status.serviceSpecificErrorCode());
1603b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        goto l_fail;
1613b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    }
1623b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang
1633b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    status = descrambler->setMediaCasSession(sessionId);
1643b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    if (!status.isOk()) {
1653b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        ALOGE("Failed to init descrambler: : exception=%d, error=%d",
1663b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang                status.exceptionCode(), status.serviceSpecificErrorCode());
1673b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        goto l_fail;
1683b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    }
1693b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang
1703b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    session->mSessionId = sessionId;
1713b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    session->mDescrambler = descrambler;
1723b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    sessionMap.add(descriptor.mPID, sessionId);
1733b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang
1743b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    return OK;
1753b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang
1763b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhangl_fail:
1773b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    if (!sessionId.empty()) {
1783b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        cas->closeSession(sessionId);
1793b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    }
1803b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    if (descrambler != NULL) {
1813b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        descrambler->release();
1823b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    }
1833b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    return NO_INIT;
1843b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang}
1853b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang
1863b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhangvoid ATSParser::CasManager::ProgramCasManager::closeSession(
1873b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        const sp<ICas>& cas, const CasSession &casSession) {
1883b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    if (casSession.mDescrambler != NULL) {
1893b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        casSession.mDescrambler->release();
1903b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    }
1913b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    if (!casSession.mSessionId.empty()) {
1923b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        cas->closeSession(casSession.mSessionId);
1933b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    }
1943b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang}
1953b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang
1963b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhangvoid ATSParser::CasManager::ProgramCasManager::closeAllSessions(
1973b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        const sp<ICas>& cas) {
1983b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    if (mHasProgramCas) {
1993b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        closeSession(cas, mProgramCas);
2003b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    }
2013b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    for (size_t index = 0; index < mStreamPidToCasMap.size(); index++) {
2023b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        closeSession(cas, mStreamPidToCasMap.editValueAt(index));
2033b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    }
2043b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang}
2053b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang
2063b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang////////////////////////////////////////////////////////////////////////////////
2073b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang
2083b2847fa5506dc265d2e46f067bfbb66ae209f74Chong ZhangATSParser::CasManager::CasManager() : mSystemId(-1) {}
2093b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang
2103b2847fa5506dc265d2e46f067bfbb66ae209f74Chong ZhangATSParser::CasManager::~CasManager() {
2113b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    // Explictly close the sessions opened by us, since the CAS object is owned
2123b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    // by the app and may not go away after the parser is destroyed, and the app
2133b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    // may not have information about the sessions.
2143b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    if (mICas != NULL) {
2153b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        for (size_t index = 0; index < mProgramCasMap.size(); index++) {
2163b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang            mProgramCasMap.editValueAt(index)->closeAllSessions(mICas);
2173b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        }
2183b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    }
2193b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang}
2203b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang
2213b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhangbool ATSParser::CasManager::setSystemId(int32_t CA_system_ID) {
2223b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    if (mSystemId == -1) {
2233b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        // Verify the CA_system_ID is within range on the first program
2243b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        if (CA_system_ID < 0 || CA_system_ID > 0xffff) {
2253b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang            ALOGE("Invalid CA_system_id: %d", CA_system_ID);
2263b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang            return false;
2273b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        }
2283b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        mSystemId = CA_system_ID;
2293b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    } else if (mSystemId != CA_system_ID) {
2303b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        // All sessions need to be under the same CA system
2313b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        ALOGE("Multiple CA systems not allowed: %d vs %d",
2323b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang                mSystemId, CA_system_ID);
2333b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        return false;
2343b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    }
2353b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    return true;
2363b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang}
2373b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang
2383b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhangstatus_t ATSParser::CasManager::setMediaCas(const sp<ICas> &cas) {
2393b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    if (cas == NULL) {
2403b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        ALOGE("setMediaCas: received NULL object");
2413b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        return BAD_VALUE;
2423b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    }
2433b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    if (mICas != NULL) {
2443b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        ALOGW("setMediaCas: already set");
2453b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        return ALREADY_EXISTS;
2463b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    }
2473b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    for (size_t index = 0; index < mProgramCasMap.size(); index++) {
2483b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        status_t err;
2493b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        if ((err = mProgramCasMap.editValueAt(
2503b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang                index)->setMediaCas(cas, mCAPidToSessionIdMap)) != OK) {
2513b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang            return err;
2523b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        }
2533b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    }
2543b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    mICas = cas;
2553b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    return OK;
2563b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang}
2573b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang
2583b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhangbool ATSParser::CasManager::addProgram(
2593b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        unsigned programNumber, const CADescriptor &descriptor) {
2603b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    if (!setSystemId(descriptor.mSystemID)) {
2613b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        return false;
2623b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    }
2633b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang
2643b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    ssize_t index = mProgramCasMap.indexOfKey(programNumber);
2653b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    if (index < 0) {
2663b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        ALOGV("addProgram: programNumber=%d, CA_system_ID=0x%x",
2673b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang                programNumber, descriptor.mSystemID);
2683b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        mProgramCasMap.add(programNumber,
2693b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang                new ProgramCasManager(programNumber, descriptor));
2703b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        mCAPidSet.insert(descriptor.mPID);
2713b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    }
2723b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    return true;
2733b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang}
2743b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang
2753b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhangbool ATSParser::CasManager::addStream(
2763b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        unsigned programNumber, unsigned elementaryPID,
2773b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        const CADescriptor &descriptor) {
2783b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    if (!setSystemId(descriptor.mSystemID)) {
2793b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        return false;
2803b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    }
2813b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang
2823b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    ssize_t index = mProgramCasMap.indexOfKey(programNumber);
2833b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    sp<ProgramCasManager> programCasManager;
2843b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    if (index < 0) {
2853b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        ALOGV("addProgram (no CADescriptor): programNumber=%d", programNumber);
2863b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        programCasManager = new ProgramCasManager(programNumber);
2873b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        mProgramCasMap.add(programNumber, programCasManager);
2883b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    } else {
2893b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        programCasManager = mProgramCasMap.editValueAt(index);
2903b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    }
2913b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    if (programCasManager->addStream(elementaryPID, descriptor)) {
2923b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        mCAPidSet.insert(descriptor.mPID);
2933b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    }
2943b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    return true;
2953b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang}
2963b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang
297bc7aae4ff7e72e5bf0fa888f946835840a4357bbChong Zhangbool ATSParser::CasManager::getCasInfo(
2983b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        unsigned programNumber, unsigned elementaryPID,
299bc7aae4ff7e72e5bf0fa888f946835840a4357bbChong Zhang        int32_t *systemId, sp<IDescrambler> *descrambler,
300bc7aae4ff7e72e5bf0fa888f946835840a4357bbChong Zhang        std::vector<uint8_t> *sessionId) const {
3013b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    ssize_t index = mProgramCasMap.indexOfKey(programNumber);
3023b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    if (index < 0) {
3033b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        return false;
3043b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    }
305bc7aae4ff7e72e5bf0fa888f946835840a4357bbChong Zhang    *systemId = mSystemId;
3063b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    return mProgramCasMap[index]->getCasSession(
3073b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang            elementaryPID, descrambler, sessionId);
3083b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang}
3093b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang
3103b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhangbool ATSParser::CasManager::isCAPid(unsigned pid) {
3113b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    return mCAPidSet.find(pid) != mCAPidSet.end();
3123b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang}
3133b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang
3143b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhangbool ATSParser::CasManager::parsePID(ABitReader *br, unsigned pid) {
3153b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    ssize_t index = mCAPidToSessionIdMap.indexOfKey(pid);
3163b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    if (index < 0) {
3173b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        return false;
3183b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    }
3193b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    MediaCas::ParcelableCasData ecm(br->data(), br->numBitsLeft() / 8);
3203b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    Status status = mICas->processEcm(mCAPidToSessionIdMap[index], ecm);
3213b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    if (!status.isOk()) {
3223b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang        ALOGE("Failed to process ECM: exception=%d, error=%d",
3233b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang                status.exceptionCode(), status.serviceSpecificErrorCode());
3243b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    }
3253b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang    return true; // handled
3263b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang}
3273b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang
3283b2847fa5506dc265d2e46f067bfbb66ae209f74Chong Zhang}  // namespace android
329