• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.google.android.exoplayer2.drm;
17 
18 import android.media.DeniedByServerException;
19 import android.media.MediaCryptoException;
20 import android.media.MediaDrm;
21 import android.media.MediaDrmException;
22 import android.media.NotProvisionedException;
23 import android.os.Handler;
24 import android.os.PersistableBundle;
25 import androidx.annotation.Nullable;
26 import com.google.android.exoplayer2.drm.DrmInitData.SchemeData;
27 import java.util.HashMap;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.UUID;
31 
32 /**
33  * Used to obtain keys for decrypting protected media streams. See {@link android.media.MediaDrm}.
34  *
35  * <h3>Reference counting</h3>
36  *
37  * <p>Access to an instance is managed by reference counting, where {@link #acquire()} increments
38  * the reference count and {@link #release()} decrements it. When the reference count drops to 0
39  * underlying resources are released, and the instance cannot be re-used.
40  *
41  * <p>Each new instance has an initial reference count of 1. Hence application code that creates a
42  * new instance does not normally need to call {@link #acquire()}, and must call {@link #release()}
43  * when the instance is no longer required.
44  */
45 public interface ExoMediaDrm {
46 
47   /** {@link ExoMediaDrm} instances provider. */
48   interface Provider {
49 
50     /**
51      * Returns an {@link ExoMediaDrm} instance with an incremented reference count. When the caller
52      * no longer needs to use the instance, it must call {@link ExoMediaDrm#release()} to decrement
53      * the reference count.
54      */
acquireExoMediaDrm(UUID uuid)55     ExoMediaDrm acquireExoMediaDrm(UUID uuid);
56   }
57 
58   /**
59    * Provides an {@link ExoMediaDrm} instance owned by the app.
60    *
61    * <p>Note that when using this provider the app will have instantiated the {@link ExoMediaDrm}
62    * instance, and remains responsible for calling {@link ExoMediaDrm#release()} on the instance
63    * when it's no longer being used.
64    */
65   final class AppManagedProvider implements Provider {
66 
67     private final ExoMediaDrm exoMediaDrm;
68 
69     /** Creates an instance that provides the given {@link ExoMediaDrm}. */
AppManagedProvider(ExoMediaDrm exoMediaDrm)70     public AppManagedProvider(ExoMediaDrm exoMediaDrm) {
71       this.exoMediaDrm = exoMediaDrm;
72     }
73 
74     @Override
acquireExoMediaDrm(UUID uuid)75     public ExoMediaDrm acquireExoMediaDrm(UUID uuid) {
76       exoMediaDrm.acquire();
77       return exoMediaDrm;
78     }
79   }
80 
81   /** @see MediaDrm#EVENT_KEY_REQUIRED */
82   @SuppressWarnings("InlinedApi")
83   int EVENT_KEY_REQUIRED = MediaDrm.EVENT_KEY_REQUIRED;
84   /**
85    * @see MediaDrm#EVENT_KEY_EXPIRED
86    */
87   @SuppressWarnings("InlinedApi")
88   int EVENT_KEY_EXPIRED = MediaDrm.EVENT_KEY_EXPIRED;
89   /**
90    * @see MediaDrm#EVENT_PROVISION_REQUIRED
91    */
92   @SuppressWarnings("InlinedApi")
93   int EVENT_PROVISION_REQUIRED = MediaDrm.EVENT_PROVISION_REQUIRED;
94 
95   /**
96    * @see MediaDrm#KEY_TYPE_STREAMING
97    */
98   @SuppressWarnings("InlinedApi")
99   int KEY_TYPE_STREAMING = MediaDrm.KEY_TYPE_STREAMING;
100   /**
101    * @see MediaDrm#KEY_TYPE_OFFLINE
102    */
103   @SuppressWarnings("InlinedApi")
104   int KEY_TYPE_OFFLINE = MediaDrm.KEY_TYPE_OFFLINE;
105   /**
106    * @see MediaDrm#KEY_TYPE_RELEASE
107    */
108   @SuppressWarnings("InlinedApi")
109   int KEY_TYPE_RELEASE = MediaDrm.KEY_TYPE_RELEASE;
110 
111   /** @see android.media.MediaDrm.OnEventListener */
112   interface OnEventListener {
113     /**
114      * Called when an event occurs that requires the app to be notified
115      *
116      * @param mediaDrm The {@link ExoMediaDrm} object on which the event occurred.
117      * @param sessionId The DRM session ID on which the event occurred.
118      * @param event Indicates the event type.
119      * @param extra A secondary error code.
120      * @param data Optional byte array of data that may be associated with the event.
121      */
onEvent( ExoMediaDrm mediaDrm, @Nullable byte[] sessionId, int event, int extra, @Nullable byte[] data)122     void onEvent(
123         ExoMediaDrm mediaDrm,
124         @Nullable byte[] sessionId,
125         int event,
126         int extra,
127         @Nullable byte[] data);
128   }
129 
130   /** @see android.media.MediaDrm.OnKeyStatusChangeListener */
131   interface OnKeyStatusChangeListener {
132     /**
133      * Called when the keys in a session change status, such as when the license is renewed or
134      * expires.
135      *
136      * @param mediaDrm The {@link ExoMediaDrm} object on which the event occurred.
137      * @param sessionId The DRM session ID on which the event occurred.
138      * @param exoKeyInformation A list of {@link KeyStatus} that contains key ID and status.
139      * @param hasNewUsableKey Whether a new key became usable.
140      */
onKeyStatusChange( ExoMediaDrm mediaDrm, byte[] sessionId, List<KeyStatus> exoKeyInformation, boolean hasNewUsableKey)141     void onKeyStatusChange(
142         ExoMediaDrm mediaDrm,
143         byte[] sessionId,
144         List<KeyStatus> exoKeyInformation,
145         boolean hasNewUsableKey);
146   }
147 
148   /** @see android.media.MediaDrm.OnExpirationUpdateListener */
149   interface OnExpirationUpdateListener {
150 
151     /**
152      * Called when a session expiration update occurs, to inform the app about the change in
153      * expiration time
154      *
155      * @param mediaDrm The {@link ExoMediaDrm} object on which the event occurred.
156      * @param sessionId The DRM session ID on which the event occurred
157      * @param expirationTimeMs The new expiration time for the keys in the session. The time is in
158      *     milliseconds, relative to the Unix epoch. A time of 0 indicates that the keys never
159      *     expire.
160      */
onExpirationUpdate(ExoMediaDrm mediaDrm, byte[] sessionId, long expirationTimeMs)161     void onExpirationUpdate(ExoMediaDrm mediaDrm, byte[] sessionId, long expirationTimeMs);
162   }
163 
164   /** @see android.media.MediaDrm.KeyStatus */
165   final class KeyStatus {
166 
167     private final int statusCode;
168     private final byte[] keyId;
169 
KeyStatus(int statusCode, byte[] keyId)170     public KeyStatus(int statusCode, byte[] keyId) {
171       this.statusCode = statusCode;
172       this.keyId = keyId;
173     }
174 
getStatusCode()175     public int getStatusCode() {
176       return statusCode;
177     }
178 
getKeyId()179     public byte[] getKeyId() {
180       return keyId;
181     }
182 
183   }
184 
185   /** @see android.media.MediaDrm.KeyRequest */
186   final class KeyRequest {
187 
188     private final byte[] data;
189     private final String licenseServerUrl;
190 
KeyRequest(byte[] data, String licenseServerUrl)191     public KeyRequest(byte[] data, String licenseServerUrl) {
192       this.data = data;
193       this.licenseServerUrl = licenseServerUrl;
194     }
195 
getData()196     public byte[] getData() {
197       return data;
198     }
199 
getLicenseServerUrl()200     public String getLicenseServerUrl() {
201       return licenseServerUrl;
202     }
203 
204   }
205 
206   /** @see android.media.MediaDrm.ProvisionRequest */
207   final class ProvisionRequest {
208 
209     private final byte[] data;
210     private final String defaultUrl;
211 
ProvisionRequest(byte[] data, String defaultUrl)212     public ProvisionRequest(byte[] data, String defaultUrl) {
213       this.data = data;
214       this.defaultUrl = defaultUrl;
215     }
216 
getData()217     public byte[] getData() {
218       return data;
219     }
220 
getDefaultUrl()221     public String getDefaultUrl() {
222       return defaultUrl;
223     }
224 
225   }
226 
227   /**
228    * Sets the listener for DRM events.
229    *
230    * <p>This is an optional method, and some implementations may only support it on certain Android
231    * API levels.
232    *
233    * @param listener The listener to receive events, or {@code null} to stop receiving events.
234    * @throws UnsupportedOperationException if the implementation doesn't support this method.
235    * @see MediaDrm#setOnEventListener(MediaDrm.OnEventListener)
236    */
setOnEventListener(@ullable OnEventListener listener)237   void setOnEventListener(@Nullable OnEventListener listener);
238 
239   /**
240    * Sets the listener for key status change events.
241    *
242    * <p>This is an optional method, and some implementations may only support it on certain Android
243    * API levels.
244    *
245    * @param listener The listener to receive events, or {@code null} to stop receiving events.
246    * @throws UnsupportedOperationException if the implementation doesn't support this method.
247    * @see MediaDrm#setOnKeyStatusChangeListener(MediaDrm.OnKeyStatusChangeListener, Handler)
248    */
setOnKeyStatusChangeListener(@ullable OnKeyStatusChangeListener listener)249   void setOnKeyStatusChangeListener(@Nullable OnKeyStatusChangeListener listener);
250 
251   /**
252    * Sets the listener for session expiration events.
253    *
254    * <p>This is an optional method, and some implementations may only support it on certain Android
255    * API levels.
256    *
257    * @param listener The listener to receive events, or {@code null} to stop receiving events.
258    * @throws UnsupportedOperationException if the implementation doesn't support this method.
259    * @see MediaDrm#setOnExpirationUpdateListener(MediaDrm.OnExpirationUpdateListener, Handler)
260    */
setOnExpirationUpdateListener(@ullable OnExpirationUpdateListener listener)261   void setOnExpirationUpdateListener(@Nullable OnExpirationUpdateListener listener);
262 
263   /** @see MediaDrm#openSession() */
openSession()264   byte[] openSession() throws MediaDrmException;
265 
266   /**
267    * @see MediaDrm#closeSession(byte[])
268    */
closeSession(byte[] sessionId)269   void closeSession(byte[] sessionId);
270 
271   /**
272    * Generates a key request.
273    *
274    * @param scope If {@code keyType} is {@link #KEY_TYPE_STREAMING} or {@link #KEY_TYPE_OFFLINE},
275    *     the session id that the keys will be provided to. If {@code keyType} is {@link
276    *     #KEY_TYPE_RELEASE}, the keySetId of the keys to release.
277    * @param schemeDatas If key type is {@link #KEY_TYPE_STREAMING} or {@link #KEY_TYPE_OFFLINE}, a
278    *     list of {@link SchemeData} instances extracted from the media. Null otherwise.
279    * @param keyType The type of the request. Either {@link #KEY_TYPE_STREAMING} to acquire keys for
280    *     streaming, {@link #KEY_TYPE_OFFLINE} to acquire keys for offline usage, or {@link
281    *     #KEY_TYPE_RELEASE} to release acquired keys. Releasing keys invalidates them for all
282    *     sessions.
283    * @param optionalParameters Are included in the key request message to allow a client application
284    *     to provide additional message parameters to the server. This may be {@code null} if no
285    *     additional parameters are to be sent.
286    * @return The generated key request.
287    * @see MediaDrm#getKeyRequest(byte[], byte[], String, int, HashMap)
288    */
getKeyRequest( byte[] scope, @Nullable List<SchemeData> schemeDatas, int keyType, @Nullable HashMap<String, String> optionalParameters)289   KeyRequest getKeyRequest(
290       byte[] scope,
291       @Nullable List<SchemeData> schemeDatas,
292       int keyType,
293       @Nullable HashMap<String, String> optionalParameters)
294       throws NotProvisionedException;
295 
296   /** @see MediaDrm#provideKeyResponse(byte[], byte[]) */
297   @Nullable
provideKeyResponse(byte[] scope, byte[] response)298   byte[] provideKeyResponse(byte[] scope, byte[] response)
299       throws NotProvisionedException, DeniedByServerException;
300 
301   /**
302    * @see MediaDrm#getProvisionRequest()
303    */
getProvisionRequest()304   ProvisionRequest getProvisionRequest();
305 
306   /**
307    * @see MediaDrm#provideProvisionResponse(byte[])
308    */
provideProvisionResponse(byte[] response)309   void provideProvisionResponse(byte[] response) throws DeniedByServerException;
310 
311   /**
312    * @see MediaDrm#queryKeyStatus(byte[])
313    */
queryKeyStatus(byte[] sessionId)314   Map<String, String> queryKeyStatus(byte[] sessionId);
315 
316   /**
317    * Increments the reference count. When the caller no longer needs to use the instance, it must
318    * call {@link #release()} to decrement the reference count.
319    *
320    * <p>A new instance will have an initial reference count of 1, and therefore it is not normally
321    * necessary for application code to call this method.
322    */
acquire()323   void acquire();
324 
325   /**
326    * Decrements the reference count. If the reference count drops to 0 underlying resources are
327    * released, and the instance cannot be re-used.
328    */
release()329   void release();
330 
331   /**
332    * @see MediaDrm#restoreKeys(byte[], byte[])
333    */
restoreKeys(byte[] sessionId, byte[] keySetId)334   void restoreKeys(byte[] sessionId, byte[] keySetId);
335 
336   /**
337    * Returns drm metrics. May be null if unavailable.
338    *
339    * @see MediaDrm#getMetrics()
340    */
341   @Nullable
getMetrics()342   PersistableBundle getMetrics();
343 
344   /**
345    * @see MediaDrm#getPropertyString(String)
346    */
getPropertyString(String propertyName)347   String getPropertyString(String propertyName);
348 
349   /**
350    * @see MediaDrm#getPropertyByteArray(String)
351    */
getPropertyByteArray(String propertyName)352   byte[] getPropertyByteArray(String propertyName);
353 
354   /**
355    * @see MediaDrm#setPropertyString(String, String)
356    */
setPropertyString(String propertyName, String value)357   void setPropertyString(String propertyName, String value);
358 
359   /**
360    * @see MediaDrm#setPropertyByteArray(String, byte[])
361    */
setPropertyByteArray(String propertyName, byte[] value)362   void setPropertyByteArray(String propertyName, byte[] value);
363 
364   /**
365    * @see android.media.MediaCrypto#MediaCrypto(UUID, byte[])
366    * @param sessionId The DRM session ID.
367    * @return An object extends {@link ExoMediaCrypto}, using opaque crypto scheme specific data.
368    * @throws MediaCryptoException If the instance can't be created.
369    */
createMediaCrypto(byte[] sessionId)370   ExoMediaCrypto createMediaCrypto(byte[] sessionId) throws MediaCryptoException;
371 
372   /**
373    * Returns the {@link ExoMediaCrypto} type created by {@link #createMediaCrypto(byte[])}, or null
374    * if this instance cannot create any {@link ExoMediaCrypto} instances.
375    */
376   @Nullable
getExoMediaCryptoType()377   Class<? extends ExoMediaCrypto> getExoMediaCryptoType();
378 }
379