1791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang/*
2791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang * Copyright (C) 2017 The Android Open Source Project
3791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang *
4791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang * Licensed under the Apache License, Version 2.0 (the "License");
5791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang * you may not use this file except in compliance with the License.
6791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang * You may obtain a copy of the License at
7791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang *
8791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang *      http://www.apache.org/licenses/LICENSE-2.0
9791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang *
10791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang * Unless required by applicable law or agreed to in writing, software
11791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang * distributed under the License is distributed on an "AS IS" BASIS,
12791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang * See the License for the specific language governing permissions and
14791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang * limitations under the License.
15791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang */
16791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
17791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang// Data objects encapsulating the clear key Ecm (Entitlement Control
18791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang// Message) and related container messages. Deserialization and decryption
19791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang// are handled externally to reduce build-time dependencies.
20791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang//
21791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang// Simplified typical client-side use:
22791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang//   Asset asset; // from the AssetRegistry.
23791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang//   uint8[] ecm_buffer; // received over network, contains an EcmContainer.
24791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang//   EcmContainer ecm_container;
25791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang//   util::Status status = ecm_container.Parse(ecm_buffer);
26791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang//   status = ecm_container.descriptor(1).ecm().Decrypt(
27791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang//      ecm_container.descriptor(1).ecm().buffer(), asset_key);
28791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang//   string content_key;
29791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang//   if (ecm_container.descriptor(1).ecm().has_content_key()) {
30791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang//     content_key = ecm_container.descriptor(1).ecm().content_key();
31791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang//   }
32791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang//   // use |content_key| to decrypt content.
33791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang//
34791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang// Simplified typical server-side use:
35791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang//   EcmContainer container;
36791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang//   string encoded_ecm;
37791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang//   // Use the ecm_generator API to encode and encrypt an ECM from data fields.
38791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang//   util::Status status = ecm_generator::EncodeECM(..., &encoded_ecm);
39791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang//   // Use |encoded_ecm| to initialized the Ecm from this library.
40791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang//   Ecm ecm;
41791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang//   util::Status status = ecm.Parse(encoded_ecm);
42791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang//   EcmDescriptor descriptor(crypto_period_id, ecm);
43791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang//   status = container.Add(descriptor);
44791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang//   string serialized_container;
45791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang//   status = container.Marshall(&serialized_container);
46791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang//   // now |serialized_container| can be sent to the STB.
47791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang//
48791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang// Due to past overloading of the term "ECM" this library introduces some
49791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang// new terminology.
50791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang//
51791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang// Ecm: the 32-byte message sent from the head end to a packager that contains
52791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang// the asset_id, system_id, and content_key (clear).
53791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang//
54791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang// EcmDescriptor: contains an Ecm and an id (the crypto period id in the case
55791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang// of the BroadcastEncryptor). It contains no encrypted fields.
56791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang//
57791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang// EcmContainer: sent by the server in the video stream using the ECM pid.
58791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang// This contains 1 or 2 EcmDescriptors and a count. It contains no
59791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang// encrypted fields.
60791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang//
61791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang// The first EcmContainer sent by the server has only one EcmDescriptor. After
62791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang// the first crypto period change, an EcmContainer contains 2 EcmDescriptors.
63791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang// One has an odd id and one has an even id. The decrypted content keys from the
64791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang// Ecms in the EcmDescriptors are used by the Mpeg2 parser as odd and even
65791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang// scrambling keys. As the crypto period changes, the oldest EcmDescriptor is
66791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang// dropped from the EcmContainer and the new EcmDescriptor is added.
67791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang//
68791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang// These classes use a simplified protobuf model. For non-repeating fields,
69791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang// - has_foo() indicates whether the field is populated.
70791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang// - the accessor foo() returns either a value or a const reference.
71791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang// - a mutator sets the value.  Primitive types and strings use
72791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang//   set_foo(value) while for objects mutable_foo() returns a pointer.
73791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang//
74791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang// To prevent null references, objects (like the Asset contained in an Emm)
75791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang// are allocated as members and can be accessed via foo() even if they have
76791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang// not been populated. The caller must call has_foo() to make sure that the
77791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang// object is valid. Calling mutable_foo() to obtain a pointer causes has_foo()
78791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang// to return true.
79791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang//
80791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang// Repeated fields (like the EcmDescriptors contained in an EcmContainer) are
81791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang// handled differently.
82791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang// - foo_size() returns the number of instances.
83791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang// - the accessor foo(index) returns either a value or a const reference to
84791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang//   the instance at index. It is illegal to call with |index| >= the value
85791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang//   returned by foo_size(). |index| is checked with CHECK.
86791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang// - a mutator to change the value of the instance.  Primitive types and
87791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang//   strings use set_foo(index, value) while for objects mutable_foo(index)
88791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang//   returns a pointer. It is illegal to call with |index| >= the value
89791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang//   returned by foo_size(). |index| is checked with CHECK.
90791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang//
91791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang// Accessing a repeated field with an invalid index causes CHECK to fail.
92791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang// Be sure to call EcmContainer::decriptor_size() before calling descriptor()
93791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang// or mutable_descriptor()!
94791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang//
95791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang#ifndef CLEAR_KEY_ECM_H_
96791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang#define CLEAR_KEY_ECM_H_
97791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
98791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang#include <stddef.h>
99791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang#include <string>
100791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
101791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang#include "protos/license_protos.pb.h"
102791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
103791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang#include <media/stagefright/foundation/ABase.h>
104791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang#include <media/stagefright/foundation/ABuffer.h>
105791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang#include <utils/Errors.h>
106791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
107791a1a206b56be8601a6fffd2614926e67d64790Chong Zhangusing namespace std;
108791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
109791a1a206b56be8601a6fffd2614926e67d64790Chong Zhangnamespace android {
110791a1a206b56be8601a6fffd2614926e67d64790Chong Zhangnamespace clearkeycas {
111791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
112791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang// Entitlement Control Message. It contains clear fields. The asset_id
113791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang// and system_id as well as the content_key are clear.
114791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang//
115791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang// This class is not thread-safe.
116791a1a206b56be8601a6fffd2614926e67d64790Chong Zhangclass Ecm {
117791a1a206b56be8601a6fffd2614926e67d64790Chong Zhangpublic:
118791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // Wire size of ECM.
119791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    static constexpr size_t kSizeBytes = 16 + 16; // clear fields + clear key
120791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
121791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // Creates an empty ECM which must be initialized via Parse().
122791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    Ecm();
123791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
124791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    ~Ecm();
125791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
126791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // Parses clear fields of Ecm serialized in |buffer_as_binary| and saves
127791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // a copy of |buffer_as_binary| for a future DecryptEcm call.
128791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // Returns:
129791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // - BAD_VALUE if |buffer_as_binary| is too small.
130791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // - CLEARKEY_STATUS_INVALIDASSETID via ecm_generator::DecodeEcmClearFields if
131791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    //   asset_id is 0.
132791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // - CLEARKEY_STATUS_INVALIDSYSTEMID via ecm_generator::DecodeEcmClearFields if
133791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    //   system_id is 0.
134791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // Postconditions:
135791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // - |asset_id_| and |system_id_| are populated with non-zero values.
136791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // - |buffer_| contains a copy of the serialized Ecm.
137791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    status_t Parse(const sp<ABuffer>& buffer_as_binary);
138791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
139791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // Parses and decrypts Ecm serialized in |buffer_as_binary| using
140791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // |asset_from_emm|.asset_key().encryption_key(). It is not necessary to call
141791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // Parse() first.
142791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // Returns BAD_VALUE if |buffer_as_binary| is too small.
143791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // Returns CLEARKEY_STATUS_INVALIDASSETID via
144791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    //   ecm_generator::DecodeEcmClearFields if asset_id is 0.
145791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // Returns CLEARKEY_STATUS_INVALIDSYSTEMID via
146791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    //   ecm_generator::DecodeEcmClearFields if system_id is 0.
147791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // Returns CLEARKEY_STATUS_INVALID_PARAMETER if
148791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // - asset_id in |asset_from_emm| does not match asset_id in serialized Ecm.
149791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // Preconditions: |asset_from_emm| must contain asset_id and asset_key fields.
150791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // Postconditions: asset_id() and system_id() are populated with non-zero
151791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // values, content_key() is populated with the clear content key.
152791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    status_t Decrypt(const sp<ABuffer>& buffer_as_binary,
153791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang            const Asset& asset_from_emm);
154791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
155791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // |buffer_| is a serialized copy of the Ecm used for later decryption or
156791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // for marshalling.
157791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    inline bool has_buffer() const { return buffer_ != NULL; }
158791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    const sp<ABuffer> buffer() const { return buffer_; }
159791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    inline void set_buffer(const sp<ABuffer>& buffer) {
160791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang        buffer_ = ABuffer::CreateAsCopy(buffer->data(), buffer->size());
161791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    }
162791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
163791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // |content_key| is the clear, encryption/decryption key generated by the server.
164791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    inline bool has_content_key() const { return content_key_ != NULL; }
165791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    inline void set_content_key(const sp<ABuffer>& value) {
166791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang        content_key_ = ABuffer::CreateAsCopy(value->data(), value->size());
167791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    }
168791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    inline const sp<ABuffer> content_key() const { return content_key_; }
169791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
170791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // |asset_id| from the server.
171791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    inline bool has_asset_id() const { return asset_id_set_; }
172791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    inline uint64_t asset_id() const { return asset_id_; }
173791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    inline void set_asset_id(uint64_t value) {
174791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang        asset_id_ = value;
175791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang        asset_id_set_ = true;
176791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    }
177791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
178791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // |system_id| from the server.
179791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    inline bool has_system_id() const { return system_id_set_; }
180791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    inline uint32_t system_id() const { return system_id_; }
181791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    inline void set_system_id(uint32_t value) {
182791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang        system_id_ = value;
183791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang        system_id_set_ = true;
184791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    }
185791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
186791a1a206b56be8601a6fffd2614926e67d64790Chong Zhangprivate:
187791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    uint64_t asset_id_;
188791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    bool asset_id_set_;
189791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    sp<ABuffer> buffer_;
190791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    sp<ABuffer> content_key_;
191791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    uint32_t system_id_;
192791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    bool system_id_set_;
193791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang};
194791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
195791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang// Contains an Ecm and and Id.
196791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang// This class is not thread-safe.
197791a1a206b56be8601a6fffd2614926e67d64790Chong Zhangclass EcmDescriptor {
198791a1a206b56be8601a6fffd2614926e67d64790Chong Zhangpublic:
199791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // Wire size of Id field.
200791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    static constexpr size_t kIdSizeBytes = sizeof(uint16_t);
201791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // Wire size of EcmDescriptor.
202791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    static constexpr size_t kSizeBytes = Ecm::kSizeBytes + kIdSizeBytes;
203791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
204791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // Client-side ctor. Populate from a buffer with Parse().
205791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    EcmDescriptor();
206791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
207791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // Server-side ctor.
208791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // Args:
209791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // - |id| is the crypto period ID.
210791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // - |ecm| is an ECM which must have been intialized with Ecm::Parse().
211791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    EcmDescriptor(uint16_t id, const Ecm& ecm);
212791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
213791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    ~EcmDescriptor();
214791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
215791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // Parses EcmDescriptor and its contained Ecm which are serialized in the
216791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // binary string |buffer_as_binary|.
217791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // Returns
218791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // - BAD_VALUE if |buffer_as_binary| is too short to contain a
219791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    //   serialized EcmDescriptor.
220791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // - Errors returned by Ecm::Parse.
221791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // Postconditions:
222791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // - id() is populated. Note that 0 is a legal value.
223791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // - the clear fields of the contained Ecm have been populated.
224791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    status_t Parse(const sp<ABuffer>& buffer_as_binary);
225791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
226791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // |id| of the contained Ecm. Typically the crypto period id.
227791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    inline bool has_id() const { return id_set_; }
228791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    inline void set_id(uint16_t value) {
229791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang        id_ = value;
230791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang        id_set_ = true;
231791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    }
232791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    inline uint16_t id() const { return id_; }
233791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
234791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // The contained |ecm|.
235791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    inline bool has_ecm() const { return ecm_set_; }
236791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    inline Ecm* mutable_ecm() {
237791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang        ecm_set_ = true;
238791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang        return &ecm_;
239791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    }
240791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    inline const Ecm& ecm() const { return ecm_; }
241791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
242791a1a206b56be8601a6fffd2614926e67d64790Chong Zhangprivate:
243791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    Ecm ecm_;
244791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    bool ecm_set_;
245791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    uint16_t id_;
246791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    bool id_set_;
247791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang};
248791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
249791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang// Contains a count and 1 or 2 EcmDescriptors. This is included in the video
250791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang// stream by the sender in the ECM pid.
251791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang// This class is not thread-safe.
252791a1a206b56be8601a6fffd2614926e67d64790Chong Zhangclass EcmContainer {
253791a1a206b56be8601a6fffd2614926e67d64790Chong Zhangpublic:
254791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // Wire size of the count field.
255791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    static constexpr size_t kCountSizeBytes = sizeof(uint16_t);
256791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // Minimum wire size assuming one EcmDescriptor.
257791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    static constexpr size_t kMinimumSizeBytes =
258791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang            EcmDescriptor::kSizeBytes + kCountSizeBytes;
259791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    static constexpr size_t kMinDescriptorCount = 1;
260791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    static constexpr size_t kMaxDescriptorCount = 2;
261791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
262791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // Creates an empty EcmContainer which must be populated via Parse()
263791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // (client-side) or Add() (server-side).
264791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    EcmContainer();
265791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
266791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    ~EcmContainer();
267791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
268791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // Adds an EcmDescriptor for server-side applications.
269791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // If |count_| is 2, |descriptor| replaces the oldest EcmDescriptor.
270791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    //
271791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // Returns:
272791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // - INTERNAL if the EcmContainer is in a bad state (count != 0, 1, or 2).
273791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // Postconditions:
274791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // - count() is within bounds (1 or 2).
275791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    status_t Add(const EcmDescriptor& descriptor);
276791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
277791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // Parses EcmContainer and its contained EcmDescriptors which are serialized
278791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // in |buffer_as_binary|.
279791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // Returns
280791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // - BAD_VALUE if |buffer_as_binary| is too short to contain a
281791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    //   serialized EcmDescriptor.
282791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // - ERROR_OUT_OF_RANGE if the count contained in the serialized EcmContainer
283791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    //   is not 1 or 2.
284791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // - Errors returned by EcmDescriptor::Parse.
285791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // Postconditions:
286791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // - count() is within bounds (1 or 2) and.
287791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // - contained EcmDescriptor(s) parsed and populated.
288791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    status_t Parse(const sp<ABuffer>& buffer_as_binary);
289791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
290791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    inline bool has_count() const { return count_set_; }
291791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // Sets the |count| of contained EcmDecriptors. Illegal values are silently
292791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // ignored.
293791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    inline void set_count(size_t count) {
294791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang        if (!CountLegal(count)) return;
295791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang        count_ = count;
296791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang        count_set_ = true;
297791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    }
298791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // Number of contained EcmDecriptors. Only 1 and 2 are legal values.
299791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    inline size_t count() const { return count_; }
300791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
301791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // Returns the number of allowable descriptors. This is redundant but is
302791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // provided for protobuf compatibility.
303791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    inline size_t descriptor_size() const { return count_; }
304791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
305791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // Returns a pointer to the EcmDescriptor at |index| for valid index values,
306791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // otherwise calls CHECK and aborts. Always call descriptor_size() first!
307791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    inline EcmDescriptor* mutable_descriptor(size_t index) {
308791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang        //CHECK(IndexValid(index));
309791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang        return &descriptor_[index];
310791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    }
311791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
312791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // Returns a reference to the EcmDescriptor at |index| for valid index
313791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // values, otherwise calls CHECK and aborts. Call descriptor_size() first!
314791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    inline const EcmDescriptor& descriptor(size_t index) const {
315791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang        //CHECK(IndexValid(index));
316791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang        return descriptor_[index];
317791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    }
318791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
319791a1a206b56be8601a6fffd2614926e67d64790Chong Zhangprivate:
320791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // Count value must be 1 or 2.
321791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    inline bool CountLegal(size_t count) const {
322791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang        return count <= kMaxDescriptorCount && count >= kMinDescriptorCount;
323791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    }
324791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // Index must be 0 or 1.
325791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    inline bool IndexLegal(size_t index) const {
326791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang        return index < kMaxDescriptorCount;
327791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    }
328791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // |index| is valid for this object: it is legal and < count_.
329791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    inline bool IndexValid(size_t index) const {
330791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang        if (!IndexLegal(index)) return false;
331791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang        return index < count_;
332791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    }
333791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    size_t count_;
334791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    bool count_set_;
335791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    EcmDescriptor descriptor_[kMaxDescriptorCount];
336791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
337791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    DISALLOW_EVIL_CONSTRUCTORS(EcmContainer);
338791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang};
339791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
340791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang}  // namespace clearkeycas
341791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang}  // namespace android
342791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
343791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang#endif  // CLEAR_KEY_ECM_H_
344