CAS 프레임워크

미디어 CAS(미디어 조건부 액세스 시스템) 프레임워크는 디지털 케이블, 위성, 지상파 시스템 및 IPTV 시스템을 비롯한 다양한 디지털 TV 하드웨어에서 조건부 액세스(CA) 서비스를 가능하게 하는 표준 API를 제공합니다. 프레임워크는 Android TV 입력 프레임워크Android TV 튜너 프레임 워크와 함께 작동하여 TIS(TV 입력 서비스) 앱에서 호출되는 Java API를 제공합니다.

Media CAS의 주요 목적은 다음과 같습니다.

  • Android에서 방송 TV용 CAS를 지원하기 위해 타사 개발자 및 OEM이 사용할 수 있는 공개 Java API 및 기본 플러그인 프레임워크를 제공합니다.
  • ATV OEM이 다양한 CAS 공급업체와 일관된 방식으로 상호 운용할 수 있도록 Android 내 CAS 프레임워크를 제공합니다.
  • 기본 플러그인을 사용하여 여러 타사 CAS 공급업체를 지원합니다. CAS 플러그인은 공급업체별 네트워크 프로토콜, EMM(자격 관리 메시지)/ECM(자격 제어 메시지) 형식 및 디스크램블러를 사용할 수 있습니다.
  • 키 사다리와 같은 하드웨어 보안을 지원합니다.
  • TrustZone과 같은 TEE(신뢰할 수 있는 실행 환경)를 지원합니다.

지원되는 구성

하드웨어 튜너 구성

하드웨어가 MPEG 전송 스트림 역다중화 및 디스크램블링을 담당하는 경우 튜너 프레임워크 는 하드웨어 기반 TV 튜너와 인터페이스하기 위해 TIS 앱에 조건부 액세스 프로그램별 정보(PSI) 데이터를 제공합니다.

조건부 액세스 PSI 데이터에는 CA 설명자, ECM 및 EMM이 포함됩니다. 이러한 구조를 통해 CAS 플러그인은 콘텐츠 스트림을 해독하는 데 필요한 키를 얻을 수 있습니다.

하드웨어 튜너 구성 다이어그램.

그림 1. 하드웨어 튜너 구성

하드웨어 구성에는 그림 1에 나와 있는 TrustZone과 같은 TEE 계층이 있을 수 있습니다. TEE 계층이 없는 경우 CAS 클라이언트 플러그인은 플랫폼에서 제공하는 하드웨어 키 래더 서비스와 통신할 수 있습니다. 이러한 인터페이스의 공급업체별 변형으로 인해 Media CAS는 이를 표준화하지 않습니다.

소프트웨어 구성

Android 11 이전에는 Media CAS 프레임워크를 사용하여 IP 멀티캐스트/유니캐스트의 IPTV와 같은 소프트웨어 기반 콘텐츠를 처리할 수 있었습니다. TIS 앱은 Media CAS Java 객체를 인스턴스화하고 적절하게 프로비저닝하는 역할을 합니다.

앱은 MediaExtractor 또는 기타 MPEG2-TS 파서를 사용하여 CA 설명자, ECM 및 EMM과 같은 CA 관련 PSI 데이터를 추출할 수 있습니다. 앱이 프레임워크 MediaExtractor를 사용하는 경우 세션 열기 및 EMM/ECM 처리와 같은 CAS 세션 관리를 프레임워크 MediaExtractor에 위임할 수 있습니다. 그런 다음 MediaExtractor는 네이티브 API를 직접 사용하여 CAS 세션을 구성합니다.

그렇지 않으면 앱이 Media CAS Java API를 사용하여 CA 관련 PSI 데이터를 추출하고 CAS 세션을 구성해야 합니다(예: 앱이 자체 MPEG2-TS 파서를 사용하는 경우).

튜너 구성 다이어그램.

그림 2. MediaExtractor 프레임워크를 사용한 IPTV 입력, CAS 및 디스크램블러 구성

소프트웨어 추출기 시나리오에서 추출기는 트랙이 보안 디코더를 요구하는지 여부에 관계없이 각 스크램블된 트랙에 대해 소프트웨어 또는 하드웨어 기반 디스크램블러 개체가 필요합니다. 이것은 다음 때문입니다.

  • 트랙에 보안 디코딩이 필요하지 않은 경우 추출기는 액세스 유닛을 디스크램블하여 버퍼를 지우고 마치 클리어 스트림에서처럼 샘플을 추출합니다. 이렇게 하면 MediaCodec 이 디스크램블링에 관여할 필요가 없습니다.
  • 트랙에 보안 디코딩이 필요한 경우 추출기에 여전히 디스크램블러가 필요할 수 있습니다. 이것은 전송 스트림이 PES(Packetized Elementary Stream) 헤더가 스크램블되는 전송 패킷 레벨에서 스크램블될 때 발생합니다. 추출기는 특정 정보(예: 프레젠테이션 타임스탬프)를 다운스트림하기 위해 PES 헤더에 액세스해야 합니다.

    전송 스트림이 PES 패킷 수준에서 스크램블링되는 경우 추출기는 디스크램블러를 사용하지 않으며, 여기서 PES 헤더는 지워집니다. 그러나 실제 스크램블된 패킷이 도착하기 전까지는 스크램블링이 언제 발생했는지 확인할 수 없습니다. 편의상, PMT(Program Mapping Table)를 기반으로 트랙이 스크램블되는 것으로 판단되면 디스크램블러를 사용한다고 가정한다.

소프트웨어 구성의 제한 사항

트랙에 보안 디코딩이 필요한 경우 디스크램블러는 디스크램블 작업을 버퍼를 지우는 데 주의해야 합니다. 안전하지 않은 오디오 디코딩이 필요하기 때문에 비디오 디코딩에 보안 디코더가 필요한 경우 오디오와 다른 세션에서 스크램블해야 합니다. 세션의 ECM은 보안 디코더가 필요하다는 신호를 플러그인에 보내야 합니다.

또는 플러그인이 보안 정책에 키를 안정적으로 연결할 수 있어야 합니다. 그렇지 않으면 앱이 오디오 디스크램블러를 사용하여 비디오 프레임을 쉽게 가져올 수 있습니다.

세션에 보안 디코더가 필요한 경우에도 추출기는 PES 헤더를 처리하기 위해 버퍼를 지우기 위해 소량의 데이터를 출력하도록 요청할 수 있습니다. 악성 앱이 플러그인이 전체 액세스 단위를 반환하도록 하지 않으려면 플러그인이 전송 페이로드를 구문 분석하여 페이로드가 적절한 스트림 유형의 PES 헤더로 시작하도록 해야 합니다. 그렇지 않으면 플러그인이 요청을 거부해야 합니다.

CA 튜닝 시퀀스

새 채널로 튜닝할 때 TIS 모듈은 PSI 튜너 프레임워크에서 CA 설명자, ECM 및 EMM을 수신하도록 등록합니다. CA 설명자는 특정 CA 공급업체 및 기타 공급업체별 데이터를 고유하게 식별하는 CA 시스템 ID를 포함합니다. TIS는 CA 디스크립터를 처리할 수 있는 CAS 플러그인이 존재하는지 확인하기 위해 미디어 CAS를 쿼리합니다.

CAS 콘텐츠 튜닝 다이어그램.

그림 3. CAS 콘텐츠 조정

CA 시스템 ID가 지원되면 미디어 CAS의 인스턴스가 생성되고 CA 디스크립터의 공급업체 개인 데이터가 플러그인에 제공됩니다. 그런 다음 오디오 및 비디오 스트림을 처리하기 위해 Media CAS에서 새 세션이 열립니다. 새로 열린 세션은 플러그인에 대한 ECM 및 EMM을 수신합니다.

샘플 CAS 플러그인 흐름

TIS는 Media CAS API를 사용하여 CAS 플러그인에 ECM을 제공합니다. ECM에는 EMM의 정보를 사용하여 해독해야 하는 암호화된 제어 단어가 포함되어 있습니다. CAS 플러그인은 setPrivateData() 메서드에서 제공하는 CA 디스크립터의 공급업체별 정보를 기반으로 자산에 대한 EMM을 획득하는 방법을 결정합니다.

EMM은 콘텐츠 스트림의 대역 내 또는 CA 플러그인에 의해 시작된 네트워크 요청을 사용하여 대역 외 전달될 수 있습니다. TIS는 processEMM() 메서드를 사용하여 대역 내 EMM을 CA 플러그인에 전달합니다.

EMM을 얻기 위해 네트워크 요청이 필요한 경우 CA 플러그인은 라이선스 서버와 네트워크 트랜잭션을 수행하는 역할을 합니다.

CAS의 예 다이어그램.

그림 4. EMM 및 ECM 처리를 위한 CAS 플러그인의 예

EMM이 수신되면 CA 플러그인은 이를 구문 분석하여 제어 단어를 해독하기 위한 암호화된 키를 얻습니다. 암호화된 EMM 키 및 암호화된 제어 단어는 제어 단어 암호 해독 및 콘텐츠 스트림의 후속 디스크램블링을 수행하기 위해 키 래더 또는 신뢰할 수 있는 환경에 로드될 수 있습니다.

미디어 CAS 자바 API

Media CAS Java API에는 다음과 같은 메서드가 포함되어 있습니다.

  • 장치에서 사용 가능한 모든 CA 플러그인을 나열합니다.

    class MediaCas.PluginDescriptor {
      public String getName();
      public int getSystemId();
    }
    static PluginDescriptor[] enumeratePlugins();
    
  • 지정된 CA 시스템에 대한 미디어 CAS 인스턴스를 구성합니다. 이는 Media CAS 프레임워크가 여러 CAS 시스템을 동시에 처리할 수 있음을 의미합니다.

    MediaCas(int CA_system_id);
    MediaCas(@NonNull Context context, int casSystemId,
             @Nullable String tvInputServiceSessionId,
             @PriorityHintUseCaseType int priorityHint);
    
  • 이벤트 리스너를 등록하고 앱이 루퍼가 사용되는 핸들러를 지정하도록 허용합니다.

    interface MediaCas.EventListener {
      void onEvent(MediaCas, int event, int arg, byte[] data);
      void onSessionEvent(@NonNull MediaCas mediaCas, @NonNull Session session, int event, int arg, @Nullable byte[] data);
      void onPluginStatusUpdate(@NonNull MediaCas mediaCas, @PluginStatus int status, int arg);
      void onResourceLost(@NonNull MediaCas mediaCas);
    }
    void setEventListener(MediaCas.EventListener listener, Handler handler);
    
  • CA 시스템에 대한 개인 데이터를 보냅니다. 개인 데이터는 CA 설명자, 조건부 액세스 테이블 또는 대역 외 소스에서 가져올 수 있습니다. 이것은 특정 세션과 관련이 없습니다.

    void setPrivateData(@NonNull byte[] data);
    
  • EMM 패킷을 처리합니다.

    void processEmm(@NonNull byte[] data, int offset, int length);
    
  • CA 시스템에 이벤트를 보냅니다. 이벤트 형식은 체계에 따라 다르며 프레임워크에는 불투명합니다.

    void sendEvent(int event, int arg, @Nullable byte[] data);
    
  • CA 시스템에 대해 지정된 유형의 프로비저닝 작업을 시작합니다. 장치가 유료 TV 서비스에 처음 등록할 때 먼저 CAS 서버에 프로비저닝해야 합니다. 프로비저닝을 위해 장치에 관련 매개변수 세트를 제공합니다.

    void provision(String provisionString);
    
  • 권한 새로 고침을 트리거합니다. 사용자가 새 채널을 구독하면(예: 광고에 응답하거나 EPG(전자 프로그램 가이드)에 채널을 추가하여) 앱은 자격 키를 새로 고치도록 CA 클라이언트에 지시할 수 있어야 합니다.

    void refreshEntitlements(int refreshType);
    
  • 미디어 CAS 개체를 닫습니다.

    void close();
    
  • 세션을 엽니다.

    Session openSession();
    Session openSession(@SessionUsage int sessionUsage, @ScramblingMode int scramblingMode);
    
  • 이전에 열린 세션을 닫습니다.

    void Session#close();
    
  • 프로그램 정보 또는 ES 정보 섹션에 있을 수 있는 PMT의 CA 설명자에서 CAS 세션으로 CA 개인 데이터를 제공합니다.

    void Session#setPrivateData(@NonNull byte[] sessionId, @NonNull byte[] data);
    
  • 세션에 대한 ECM 패킷을 처리합니다.

    void Session#processEcm(@NonNull byte[] data, int offset, int length);
    
  • 세션 ID를 가져옵니다.

    byte[] Session#getSessionId();
    
  • CA 시스템에 세션 이벤트를 보냅니다. 이벤트 형식은 체계에 따라 다르며 프레임워크에는 불투명합니다.

    void Session#sendSessionEvent(int event, int arg, @Nullable byte[] data);