OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 package org.chromium.media; | 5 package org.chromium.media; |
6 | 6 |
7 import android.annotation.SuppressLint; | 7 import android.annotation.SuppressLint; |
8 import android.annotation.TargetApi; | 8 import android.annotation.TargetApi; |
9 import android.media.MediaCrypto; | 9 import android.media.MediaCrypto; |
10 import android.media.MediaDrm; | 10 import android.media.MediaDrm; |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
90 private ArrayDeque<PendingCreateSessionData> mPendingCreateSessionDataQueue; | 90 private ArrayDeque<PendingCreateSessionData> mPendingCreateSessionDataQueue; |
91 | 91 |
92 private boolean mResetDeviceCredentialsPending; | 92 private boolean mResetDeviceCredentialsPending; |
93 | 93 |
94 // MediaDrmBridge is waiting for provisioning response from the server. | 94 // MediaDrmBridge is waiting for provisioning response from the server. |
95 private boolean mProvisioningPending; | 95 private boolean mProvisioningPending; |
96 | 96 |
97 // Boolean to track if 'ORIGIN' is set in MediaDrm. | 97 // Boolean to track if 'ORIGIN' is set in MediaDrm. |
98 private boolean mOriginSet = false; | 98 private boolean mOriginSet = false; |
99 | 99 |
100 // Delay the MediaDrm event handle if present. | |
101 private SessionEventDeferrer mSessionEventDeferrer = null; | |
102 | |
103 // Block MediaDrm event for |mSessionId|. | |
104 private static class SessionEventDeferrer { | |
xhwang
2017/04/05 18:31:50
Please add more comments why we need this.
yucliu1
2017/04/05 23:04:07
Done.
| |
105 private final SessionId mSessionId; | |
106 private final ArrayList<Runnable> mEventHandlers; | |
107 | |
108 SessionEventDeferrer(SessionId sessionId) { | |
109 mSessionId = sessionId; | |
110 mEventHandlers = new ArrayList<>(); | |
111 } | |
112 | |
113 boolean shouldDefer(SessionId sessionId) { | |
114 return mSessionId.isEqual(sessionId); | |
115 } | |
116 | |
117 void defer(Runnable handler) { | |
118 mEventHandlers.add(handler); | |
119 } | |
120 | |
121 void fire() { | |
122 for (Runnable r : mEventHandlers) { | |
123 r.run(); | |
124 } | |
125 | |
126 mEventHandlers.clear(); | |
127 } | |
128 } | |
129 | |
100 /** | 130 /** |
101 * An equivalent of MediaDrm.KeyStatus, which is only available on M+. | 131 * An equivalent of MediaDrm.KeyStatus, which is only available on M+. |
102 */ | 132 */ |
103 @MainDex | 133 @MainDex |
104 private static class KeyStatus { | 134 private static class KeyStatus { |
105 private final byte[] mKeyId; | 135 private final byte[] mKeyId; |
106 private final int mStatusCode; | 136 private final int mStatusCode; |
107 | 137 |
108 private KeyStatus(byte[] keyId, int statusCode) { | 138 private KeyStatus(byte[] keyId, int statusCode) { |
109 mKeyId = keyId; | 139 mKeyId = keyId; |
(...skipping 456 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
566 assert mMediaCryptoSession != null; | 596 assert mMediaCryptoSession != null; |
567 assert !mProvisioningPending; | 597 assert !mProvisioningPending; |
568 | 598 |
569 if (optionalParameters == null) { | 599 if (optionalParameters == null) { |
570 optionalParameters = new HashMap<String, String>(); | 600 optionalParameters = new HashMap<String, String>(); |
571 } | 601 } |
572 | 602 |
573 MediaDrm.KeyRequest request = null; | 603 MediaDrm.KeyRequest request = null; |
574 | 604 |
575 try { | 605 try { |
576 request = mMediaDrm.getKeyRequest( | 606 byte[] scopeId = |
577 sessionId.drmId(), data, mime, keyType, optionalParameters); | 607 keyType == MediaDrm.KEY_TYPE_RELEASE ? sessionId.keySetId() : sessionId.drmId(); |
608 assert scopeId != null; | |
609 request = mMediaDrm.getKeyRequest(scopeId, data, mime, keyType, opti onalParameters); | |
578 } catch (IllegalStateException e) { | 610 } catch (IllegalStateException e) { |
579 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && e | 611 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && e |
580 instanceof android.media.MediaDrm.MediaDrmStateException) { | 612 instanceof android.media.MediaDrm.MediaDrmStateException) { |
581 // See b/21307186 for details. | 613 // See b/21307186 for details. |
582 Log.e(TAG, "MediaDrmStateException fired during getKeyRequest(). ", e); | 614 Log.e(TAG, "MediaDrmStateException fired during getKeyRequest(). ", e); |
583 } | 615 } |
584 } | 616 } |
585 | 617 |
586 String result = (request != null) ? "successed" : "failed"; | 618 String result = (request != null) ? "successed" : "failed"; |
587 Log.d(TAG, "getKeyRequest %s!", result); | 619 Log.d(TAG, "getKeyRequest %s!", result); |
(...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
818 final SessionId sessionId = getSessionIdByEmeId(emeSessionId); | 850 final SessionId sessionId = getSessionIdByEmeId(emeSessionId); |
819 if (sessionId == null) { | 851 if (sessionId == null) { |
820 assert false; // Should never happen. | 852 assert false; // Should never happen. |
821 onPromiseRejected(promiseId, | 853 onPromiseRejected(promiseId, |
822 "Invalid session in updateSession: " + SessionId.toHexString (emeSessionId)); | 854 "Invalid session in updateSession: " + SessionId.toHexString (emeSessionId)); |
823 return; | 855 return; |
824 } | 856 } |
825 | 857 |
826 try { | 858 try { |
827 SessionInfo sessionInfo = mSessionManager.get(sessionId); | 859 SessionInfo sessionInfo = mSessionManager.get(sessionId); |
828 byte[] keySetId = mMediaDrm.provideKeyResponse(sessionId.drmId(), re sponse); | 860 boolean isKeyRelease = sessionInfo.keyType() == MediaDrm.KEY_TYPE_RE LEASE; |
829 | 861 |
830 if (keySetId != null && keySetId.length > 0) { | 862 byte[] keySetId = null; |
831 assert sessionInfo.keyType() == MediaDrm.KEY_TYPE_OFFLINE; | 863 if (isKeyRelease) { |
832 mSessionManager.setKeySetId(sessionId, keySetId, new Callback<Bo olean>() { | 864 Log.d(TAG, "updateSession() for key release"); |
833 @Override | 865 assert sessionId.keySetId() != null; |
834 public void onResult(Boolean success) { | 866 mMediaDrm.provideKeyResponse(sessionId.keySetId(), response); |
835 onKeyUpdated(sessionId, promiseId, success); | 867 } else { |
836 } | 868 keySetId = mMediaDrm.provideKeyResponse(sessionId.drmId(), respo nse); |
837 }); | 869 } |
870 | |
871 KeyUpdatedCallback cb = new KeyUpdatedCallback(sessionId, promiseId, isKeyRelease); | |
872 | |
873 if (isKeyRelease) { | |
874 mSessionManager.clearPersistentSessionInfo(sessionId, cb); | |
875 } else if (sessionInfo.keyType() == MediaDrm.KEY_TYPE_OFFLINE && key SetId != null | |
876 && keySetId.length > 0) { | |
877 mSessionManager.setKeySetId(sessionId, keySetId, cb); | |
838 } else { | 878 } else { |
839 // This can be either temporary license update or server certifi cate update. | 879 // This can be either temporary license update or server certifi cate update. |
840 onKeyUpdated(sessionId, promiseId, true); | 880 cb.onResult(true); |
841 } | 881 } |
842 | 882 |
843 return; | 883 return; |
844 } catch (android.media.NotProvisionedException e) { | 884 } catch (android.media.NotProvisionedException e) { |
845 // TODO(xhwang): Should we handle this? | 885 // TODO(xhwang): Should we handle this? |
846 Log.e(TAG, "failed to provide key response", e); | 886 Log.e(TAG, "failed to provide key response", e); |
847 } catch (android.media.DeniedByServerException e) { | 887 } catch (android.media.DeniedByServerException e) { |
848 Log.e(TAG, "failed to provide key response", e); | 888 Log.e(TAG, "failed to provide key response", e); |
849 } catch (java.lang.IllegalStateException e) { | 889 } catch (java.lang.IllegalStateException e) { |
850 Log.e(TAG, "failed to provide key response", e); | 890 Log.e(TAG, "failed to provide key response", e); |
851 } | 891 } |
852 onPromiseRejected(promiseId, "Update session failed."); | 892 onPromiseRejected(promiseId, "Update session failed."); |
853 release(); | 893 release(); |
854 } | 894 } |
855 | 895 |
856 private void onKeyUpdated(SessionId sessionId, long promiseId, boolean succe ss) { | 896 /** |
857 if (!success) { | 897 * Load persistent license from stroage. |
858 onPromiseRejected(promiseId, "failed to update key after response ac cepted"); | 898 */ |
899 @CalledByNative | |
900 private void loadSession(byte[] emeId, final long promiseId) { | |
901 Log.d(TAG, "loadSession()"); | |
902 if (mProvisioningPending) { | |
903 onPersistentLicenseNoExist(promiseId); | |
859 return; | 904 return; |
860 } | 905 } |
861 | 906 |
862 Log.d(TAG, "Key successfully added for session %s", sessionId.toHexStrin g()); | 907 mSessionManager.load(emeId, new Callback<SessionId>() { |
863 onPromiseResolved(promiseId); | 908 @Override |
909 public void onResult(SessionId sessionId) { | |
910 if (sessionId == null) { | |
911 onPersistentLicenseNoExist(promiseId); | |
912 return; | |
913 } | |
864 | 914 |
865 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { | 915 loadSessionWithLoadedStorage(sessionId, promiseId); |
866 onSessionKeysChange( | 916 } |
867 sessionId, getDummyKeysInfo(MediaDrm.KeyStatus.STATUS_USABLE ).toArray(), true); | 917 }); |
918 } | |
919 | |
920 /** | |
921 * Load session back to memory with MediaDrm. Load persistent storage | |
922 * before calling this. It will fail if persistent storage isn't loaded. | |
923 */ | |
924 private void loadSessionWithLoadedStorage(SessionId sessionId, final long pr omiseId) { | |
925 byte[] drmId = null; | |
926 try { | |
927 drmId = openSession(); | |
928 if (drmId == null) { | |
929 onPromiseRejected(promiseId, "Failed to open session to load lic ense"); | |
930 return; | |
931 } | |
932 | |
933 mSessionManager.setDrmId(sessionId, drmId); | |
934 | |
935 // Defer event handlers until license is loaded. | |
936 assert mSessionEventDeferrer == null; | |
937 mSessionEventDeferrer = new SessionEventDeferrer(sessionId); | |
938 | |
939 assert sessionId.keySetId() != null; | |
940 mMediaDrm.restoreKeys(sessionId.drmId(), sessionId.keySetId()); | |
941 | |
942 onPromiseResolvedWithSession(promiseId, sessionId); | |
943 | |
944 mSessionEventDeferrer.fire(); | |
945 mSessionEventDeferrer = null; | |
946 | |
947 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { | |
948 onSessionKeysChange(sessionId, | |
949 getDummyKeysInfo(MediaDrm.KeyStatus.STATUS_USABLE).toArr ay(), true, false); | |
950 } | |
951 } catch (android.media.NotProvisionedException e) { | |
952 onPersistentLicenseNoExist(promiseId); | |
xhwang
2017/04/05 18:31:50
When can this happen? When user manually unprovisi
yucliu1
2017/04/05 23:04:07
Early return.
| |
953 } catch (java.lang.IllegalStateException e) { | |
954 // license doesn't exist | |
955 if (sessionId.drmId() == null) { | |
956 // TODO(yucliu): Check if the license is released or doesn't exi st. | |
957 onPersistentLicenseNoExist(promiseId); | |
958 return; | |
959 } | |
960 | |
961 closeSessionNoException(sessionId); | |
962 mSessionManager.clearPersistentSessionInfo(sessionId, new Callback<B oolean>() { | |
963 @Override | |
964 public void onResult(Boolean success) { | |
965 if (!success) { | |
966 Log.w(TAG, "Failed to clear persistent storage for non-e xist license"); | |
967 } | |
968 | |
969 onPersistentLicenseNoExist(promiseId); | |
970 } | |
971 }); | |
868 } | 972 } |
869 } | 973 } |
870 | 974 |
975 private void onPersistentLicenseNoExist(long promiseId) { | |
976 onPromiseResolvedWithSession(promiseId, SessionId.createNoExistSessionId ()); | |
977 } | |
978 | |
979 /** | |
980 * Remove session from device. This will mark the key as released and | |
981 * generate a key release request. The license is removed from the device | |
982 * when the session is updated with a license release response. | |
983 */ | |
984 @CalledByNative | |
985 private void removeSession(byte[] emeId, long promiseId) { | |
986 Log.d(TAG, "removeSession()"); | |
987 SessionId sessionId = getSessionIdByEmeId(emeId); | |
988 | |
989 if (sessionId == null) { | |
990 onPromiseRejected(promiseId, "Session doesn't exist"); | |
991 return; | |
992 } | |
993 | |
994 SessionInfo sessionInfo = mSessionManager.get(sessionId); | |
995 if (sessionInfo.keyType() != MediaDrm.KEY_TYPE_OFFLINE) { | |
996 // TODO(yucliu): Support 'remove' of temporary session. | |
997 onPromiseRejected(promiseId, "Removing temporary session isn't imple mented"); | |
998 return; | |
999 } | |
1000 | |
1001 assert sessionId.keySetId() != null; | |
1002 | |
1003 mSessionManager.markKeyReleased(sessionId); | |
1004 | |
1005 try { | |
1006 // Get key release request. | |
1007 MediaDrm.KeyRequest request = getKeyRequest( | |
1008 sessionId, null, sessionInfo.mimeType(), MediaDrm.KEY_TYPE_R ELEASE, null); | |
1009 | |
1010 if (request == null) { | |
1011 onPromiseRejected(promiseId, "Fail to generate key release reque st"); | |
1012 return; | |
1013 } | |
1014 | |
1015 onPromiseResolved(promiseId); | |
1016 onSessionMessage(sessionId, request); | |
xhwang
2017/04/05 18:31:50
The spec says queue the message, then return the p
yucliu1
2017/04/05 23:04:07
Switched sequence to match spec.
| |
1017 } catch (android.media.NotProvisionedException e) { | |
1018 Log.e(TAG, "removeSession called on unprovisioned device"); | |
1019 onPromiseRejected(promiseId, "Unknown failure"); | |
1020 } | |
1021 } | |
1022 | |
871 /** | 1023 /** |
872 * Return the security level of this DRM object. | 1024 * Return the security level of this DRM object. |
873 */ | 1025 */ |
874 @CalledByNative | 1026 @CalledByNative |
875 private String getSecurityLevel() { | 1027 private String getSecurityLevel() { |
876 if (mMediaDrm == null || !isWidevine()) { | 1028 if (mMediaDrm == null || !isWidevine()) { |
877 Log.e(TAG, "getSecurityLevel(): MediaDrm is null or security level i s not supported."); | 1029 Log.e(TAG, "getSecurityLevel(): MediaDrm is null or security level i s not supported."); |
878 return null; | 1030 return null; |
879 } | 1031 } |
880 return mMediaDrm.getPropertyString("securityLevel"); | 1032 return mMediaDrm.getPropertyString("securityLevel"); |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
962 mMediaDrm.provideProvisionResponse(response); | 1114 mMediaDrm.provideProvisionResponse(response); |
963 return true; | 1115 return true; |
964 } catch (android.media.DeniedByServerException e) { | 1116 } catch (android.media.DeniedByServerException e) { |
965 Log.e(TAG, "failed to provide provision response", e); | 1117 Log.e(TAG, "failed to provide provision response", e); |
966 } catch (java.lang.IllegalStateException e) { | 1118 } catch (java.lang.IllegalStateException e) { |
967 Log.e(TAG, "failed to provide provision response", e); | 1119 Log.e(TAG, "failed to provide provision response", e); |
968 } | 1120 } |
969 return false; | 1121 return false; |
970 } | 1122 } |
971 | 1123 |
1124 /** | |
1125 * Delay session event handler if |mSessionEventDeferrer| exists and | |
1126 * matches |sessionId|. Otherwise run the handler immediately. | |
1127 */ | |
1128 private void deferEventHandleIfNeeded(SessionId sessionId, Runnable handler) { | |
1129 if (mSessionEventDeferrer != null && mSessionEventDeferrer.shouldDefer(s essionId)) { | |
1130 mSessionEventDeferrer.defer(handler); | |
1131 return; | |
1132 } | |
1133 | |
1134 handler.run(); | |
1135 } | |
1136 | |
972 // Helper functions to make native calls. | 1137 // Helper functions to make native calls. |
973 | 1138 |
974 private void onMediaCryptoReady(MediaCrypto mediaCrypto) { | 1139 private void onMediaCryptoReady(MediaCrypto mediaCrypto) { |
975 if (isNativeMediaDrmBridgeValid()) { | 1140 if (isNativeMediaDrmBridgeValid()) { |
976 nativeOnMediaCryptoReady(mNativeMediaDrmBridge, mediaCrypto); | 1141 nativeOnMediaCryptoReady(mNativeMediaDrmBridge, mediaCrypto); |
977 } | 1142 } |
978 } | 1143 } |
979 | 1144 |
980 private void onPromiseResolved(final long promiseId) { | 1145 private void onPromiseResolved(final long promiseId) { |
981 if (isNativeMediaDrmBridgeValid()) { | 1146 if (isNativeMediaDrmBridgeValid()) { |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1015 mNativeMediaDrmBridge, sessionId.emeId(), requestType, request.g etData()); | 1180 mNativeMediaDrmBridge, sessionId.emeId(), requestType, request.g etData()); |
1016 } | 1181 } |
1017 | 1182 |
1018 private void onSessionClosed(final SessionId sessionId) { | 1183 private void onSessionClosed(final SessionId sessionId) { |
1019 if (isNativeMediaDrmBridgeValid()) { | 1184 if (isNativeMediaDrmBridgeValid()) { |
1020 nativeOnSessionClosed(mNativeMediaDrmBridge, sessionId.emeId()); | 1185 nativeOnSessionClosed(mNativeMediaDrmBridge, sessionId.emeId()); |
1021 } | 1186 } |
1022 } | 1187 } |
1023 | 1188 |
1024 private void onSessionKeysChange(final SessionId sessionId, final Object[] k eysInfo, | 1189 private void onSessionKeysChange(final SessionId sessionId, final Object[] k eysInfo, |
1025 final boolean hasAdditionalUsableKey) { | 1190 final boolean hasAdditionalUsableKey, final boolean isKeyRelease) { |
1026 if (isNativeMediaDrmBridgeValid()) { | 1191 if (isNativeMediaDrmBridgeValid()) { |
1027 nativeOnSessionKeysChange( | 1192 nativeOnSessionKeysChange(mNativeMediaDrmBridge, sessionId.emeId(), keysInfo, |
1028 mNativeMediaDrmBridge, sessionId.emeId(), keysInfo, hasAddit ionalUsableKey); | 1193 hasAdditionalUsableKey, isKeyRelease); |
1029 } | 1194 } |
1030 } | 1195 } |
1031 | 1196 |
1032 private void onSessionExpirationUpdate(final SessionId sessionId, final long expirationTime) { | 1197 private void onSessionExpirationUpdate(final SessionId sessionId, final long expirationTime) { |
1033 if (isNativeMediaDrmBridgeValid()) { | 1198 if (isNativeMediaDrmBridgeValid()) { |
1034 nativeOnSessionExpirationUpdate( | 1199 nativeOnSessionExpirationUpdate( |
1035 mNativeMediaDrmBridge, sessionId.emeId(), expirationTime); | 1200 mNativeMediaDrmBridge, sessionId.emeId(), expirationTime); |
1036 } | 1201 } |
1037 } | 1202 } |
1038 | 1203 |
(...skipping 13 matching lines...) Expand all Loading... | |
1052 return; | 1217 return; |
1053 } | 1218 } |
1054 SessionId sessionId = getSessionIdByDrmId(drmSessionId); | 1219 SessionId sessionId = getSessionIdByDrmId(drmSessionId); |
1055 | 1220 |
1056 if (sessionId == null) { | 1221 if (sessionId == null) { |
1057 Log.e(TAG, "EventListener: Invalid session %s", | 1222 Log.e(TAG, "EventListener: Invalid session %s", |
1058 SessionId.toHexString(drmSessionId)); | 1223 SessionId.toHexString(drmSessionId)); |
1059 return; | 1224 return; |
1060 } | 1225 } |
1061 | 1226 |
1227 SessionInfo sessionInfo = mSessionManager.get(sessionId); | |
1062 switch(event) { | 1228 switch(event) { |
1063 case MediaDrm.EVENT_KEY_REQUIRED: | 1229 case MediaDrm.EVENT_KEY_REQUIRED: |
1064 Log.d(TAG, "MediaDrm.EVENT_KEY_REQUIRED"); | 1230 Log.d(TAG, "MediaDrm.EVENT_KEY_REQUIRED"); |
1065 if (mProvisioningPending) { | 1231 if (mProvisioningPending) { |
1066 return; | 1232 return; |
1067 } | 1233 } |
1068 SessionInfo sessionInfo = mSessionManager.get(sessionId); | |
1069 MediaDrm.KeyRequest request = null; | 1234 MediaDrm.KeyRequest request = null; |
1070 try { | 1235 try { |
1071 request = getKeyRequest(sessionId, data, sessionInfo.mim eType(), | 1236 request = getKeyRequest(sessionId, data, sessionInfo.mim eType(), |
1072 sessionInfo.keyType(), null); | 1237 sessionInfo.keyType(), null); |
1073 } catch (android.media.NotProvisionedException e) { | 1238 } catch (android.media.NotProvisionedException e) { |
1074 Log.e(TAG, "Device not provisioned", e); | 1239 Log.e(TAG, "Device not provisioned", e); |
1075 startProvisioning(); | 1240 startProvisioning(); |
1076 return; | 1241 return; |
1077 } | 1242 } |
1078 if (request != null) { | 1243 if (request != null) { |
1079 onSessionMessage(sessionId, request); | 1244 onSessionMessage(sessionId, request); |
1080 } else { | 1245 } else { |
1081 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { | 1246 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { |
1082 onSessionKeysChange(sessionId, | 1247 onSessionKeysChange(sessionId, |
1083 getDummyKeysInfo(MediaDrm.KeyStatus.STATUS_I NTERNAL_ERROR) | 1248 getDummyKeysInfo(MediaDrm.KeyStatus.STATUS_I NTERNAL_ERROR) |
1084 .toArray(), | 1249 .toArray(), |
1085 false); | 1250 false, false); |
1086 } | 1251 } |
1087 Log.e(TAG, "EventListener: getKeyRequest failed."); | 1252 Log.e(TAG, "EventListener: getKeyRequest failed."); |
1088 return; | 1253 return; |
1089 } | 1254 } |
1090 break; | 1255 break; |
1091 case MediaDrm.EVENT_KEY_EXPIRED: | 1256 case MediaDrm.EVENT_KEY_EXPIRED: |
1092 Log.d(TAG, "MediaDrm.EVENT_KEY_EXPIRED"); | 1257 Log.d(TAG, "MediaDrm.EVENT_KEY_EXPIRED"); |
1093 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { | 1258 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { |
1094 onSessionKeysChange(sessionId, | 1259 onSessionKeysChange(sessionId, |
1095 getDummyKeysInfo(MediaDrm.KeyStatus.STATUS_EXPIR ED).toArray(), | 1260 getDummyKeysInfo(MediaDrm.KeyStatus.STATUS_EXPIR ED).toArray(), |
1096 false); | 1261 false, sessionInfo.keyType() == MediaDrm.KEY_TYP E_RELEASE); |
1097 } | 1262 } |
1098 break; | 1263 break; |
1099 case MediaDrm.EVENT_VENDOR_DEFINED: | 1264 case MediaDrm.EVENT_VENDOR_DEFINED: |
1100 Log.d(TAG, "MediaDrm.EVENT_VENDOR_DEFINED"); | 1265 Log.d(TAG, "MediaDrm.EVENT_VENDOR_DEFINED"); |
1101 assert false; // Should never happen. | 1266 assert false; // Should never happen. |
1102 break; | 1267 break; |
1103 default: | 1268 default: |
1104 Log.e(TAG, "Invalid DRM event " + event); | 1269 Log.e(TAG, "Invalid DRM event " + event); |
1105 return; | 1270 return; |
1106 } | 1271 } |
1107 } | 1272 } |
1108 } | 1273 } |
1109 | 1274 |
1110 @TargetApi(Build.VERSION_CODES.M) | 1275 @TargetApi(Build.VERSION_CODES.M) |
1111 @MainDex | 1276 @MainDex |
1112 private class KeyStatusChangeListener implements MediaDrm.OnKeyStatusChangeL istener { | 1277 private class KeyStatusChangeListener implements MediaDrm.OnKeyStatusChangeL istener { |
1113 private List<KeyStatus> getKeysInfo(List<MediaDrm.KeyStatus> keyInformat ion) { | 1278 private List<KeyStatus> getKeysInfo(List<MediaDrm.KeyStatus> keyInformat ion) { |
1114 List<KeyStatus> keysInfo = new ArrayList<KeyStatus>(); | 1279 List<KeyStatus> keysInfo = new ArrayList<KeyStatus>(); |
1115 for (MediaDrm.KeyStatus keyStatus : keyInformation) { | 1280 for (MediaDrm.KeyStatus keyStatus : keyInformation) { |
1116 keysInfo.add(new KeyStatus(keyStatus.getKeyId(), keyStatus.getSt atusCode())); | 1281 keysInfo.add(new KeyStatus(keyStatus.getKeyId(), keyStatus.getSt atusCode())); |
1117 } | 1282 } |
1118 return keysInfo; | 1283 return keysInfo; |
1119 } | 1284 } |
1120 | 1285 |
1121 @Override | 1286 @Override |
1122 public void onKeyStatusChange(MediaDrm md, byte[] drmSessionId, | 1287 public void onKeyStatusChange(MediaDrm md, byte[] drmSessionId, |
1123 List<MediaDrm.KeyStatus> keyInformation, boolean hasNewUsableKey ) { | 1288 final List<MediaDrm.KeyStatus> keyInformation, final boolean has NewUsableKey) { |
1124 SessionId sessionId = getSessionIdByDrmId(drmSessionId); | 1289 final SessionId sessionId = getSessionIdByDrmId(drmSessionId); |
1125 | 1290 |
1126 assert sessionId != null; | 1291 assert sessionId != null; |
1292 assert mSessionManager.get(sessionId) != null; | |
1127 | 1293 |
1128 Log.d(TAG, "KeysStatusChange: " + sessionId.toHexString() + ", " + h asNewUsableKey); | 1294 final boolean isKeyRelease = |
1295 mSessionManager.get(sessionId).keyType() == MediaDrm.KEY_TYP E_RELEASE; | |
1129 | 1296 |
1130 onSessionKeysChange(sessionId, getKeysInfo(keyInformation).toArray() , hasNewUsableKey); | 1297 deferEventHandleIfNeeded(sessionId, new Runnable() { |
1298 @Override | |
1299 public void run() { | |
1300 Log.d(TAG, | |
1301 "KeysStatusChange: " + sessionId.toHexString() + ", " | |
1302 + hasNewUsableKey); | |
1303 onSessionKeysChange(sessionId, getKeysInfo(keyInformation).t oArray(), | |
1304 hasNewUsableKey, isKeyRelease); | |
1305 } | |
1306 }); | |
1131 } | 1307 } |
1132 } | 1308 } |
1133 | 1309 |
1134 @TargetApi(Build.VERSION_CODES.M) | 1310 @TargetApi(Build.VERSION_CODES.M) |
1135 @MainDex | 1311 @MainDex |
1136 private class ExpirationUpdateListener implements MediaDrm.OnExpirationUpdat eListener { | 1312 private class ExpirationUpdateListener implements MediaDrm.OnExpirationUpdat eListener { |
1137 @Override | 1313 @Override |
1138 public void onExpirationUpdate(MediaDrm md, byte[] drmSessionId, long ex pirationTime) { | 1314 public void onExpirationUpdate( |
1139 SessionId sessionId = getSessionIdByDrmId(drmSessionId); | 1315 MediaDrm md, byte[] drmSessionId, final long expirationTime) { |
1316 final SessionId sessionId = getSessionIdByDrmId(drmSessionId); | |
1140 | 1317 |
1141 assert sessionId != null; | 1318 assert sessionId != null; |
1142 | 1319 |
1143 Log.d(TAG, "ExpirationUpdate: " + sessionId.toHexString() + ", " + e xpirationTime); | 1320 deferEventHandleIfNeeded(sessionId, new Runnable() { |
1144 onSessionExpirationUpdate(sessionId, expirationTime); | 1321 @Override |
1322 public void run() { | |
1323 Log.d(TAG, | |
1324 "ExpirationUpdate: " + sessionId.toHexString() + ", " + expirationTime); | |
1325 onSessionExpirationUpdate(sessionId, expirationTime); | |
1326 } | |
1327 }); | |
1145 } | 1328 } |
1146 } | 1329 } |
1147 | 1330 |
1331 @MainDex | |
1332 private class KeyUpdatedCallback extends Callback<Boolean> { | |
1333 private final SessionId mSessionId; | |
1334 private final long mPromiseId; | |
1335 private final boolean mIsKeyRelease; | |
1336 | |
1337 KeyUpdatedCallback(SessionId sessionId, long promiseId, boolean isKeyRel ease) { | |
1338 mSessionId = sessionId; | |
1339 mPromiseId = promiseId; | |
1340 mIsKeyRelease = isKeyRelease; | |
1341 } | |
1342 | |
1343 @Override | |
1344 public void onResult(Boolean success) { | |
1345 if (!success) { | |
1346 onPromiseRejected(mPromiseId, "failed to update key after respon se accepted"); | |
1347 return; | |
1348 } | |
1349 | |
1350 Log.d(TAG, "Key successfully %s for session %s", mIsKeyRelease ? "re leased" : "added", | |
1351 mSessionId.toHexString()); | |
1352 onPromiseResolved(mPromiseId); | |
1353 | |
1354 if (!mIsKeyRelease && Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { | |
1355 onSessionKeysChange(mSessionId, | |
1356 getDummyKeysInfo(MediaDrm.KeyStatus.STATUS_USABLE).toArr ay(), true, | |
1357 mIsKeyRelease); | |
1358 } | |
1359 } | |
1360 } | |
1361 | |
1148 // Native functions. At the native side, must post the task immediately to | 1362 // Native functions. At the native side, must post the task immediately to |
1149 // avoid reentrancy issues. | 1363 // avoid reentrancy issues. |
1150 private native void nativeOnMediaCryptoReady( | 1364 private native void nativeOnMediaCryptoReady( |
1151 long nativeMediaDrmBridge, MediaCrypto mediaCrypto); | 1365 long nativeMediaDrmBridge, MediaCrypto mediaCrypto); |
1152 | 1366 |
1153 private native void nativeOnStartProvisioning( | 1367 private native void nativeOnStartProvisioning( |
1154 long nativeMediaDrmBridge, String defaultUrl, byte[] requestData); | 1368 long nativeMediaDrmBridge, String defaultUrl, byte[] requestData); |
1155 | 1369 |
1156 private native void nativeOnPromiseResolved(long nativeMediaDrmBridge, long promiseId); | 1370 private native void nativeOnPromiseResolved(long nativeMediaDrmBridge, long promiseId); |
1157 private native void nativeOnPromiseResolvedWithSession( | 1371 private native void nativeOnPromiseResolvedWithSession( |
1158 long nativeMediaDrmBridge, long promiseId, byte[] emeSessionId); | 1372 long nativeMediaDrmBridge, long promiseId, byte[] emeSessionId); |
1159 private native void nativeOnPromiseRejected( | 1373 private native void nativeOnPromiseRejected( |
1160 long nativeMediaDrmBridge, long promiseId, String errorMessage); | 1374 long nativeMediaDrmBridge, long promiseId, String errorMessage); |
1161 | 1375 |
1162 private native void nativeOnSessionMessage( | 1376 private native void nativeOnSessionMessage( |
1163 long nativeMediaDrmBridge, byte[] emeSessionId, int requestType, byt e[] message); | 1377 long nativeMediaDrmBridge, byte[] emeSessionId, int requestType, byt e[] message); |
1164 private native void nativeOnSessionClosed(long nativeMediaDrmBridge, byte[] emeSessionId); | 1378 private native void nativeOnSessionClosed(long nativeMediaDrmBridge, byte[] emeSessionId); |
1165 private native void nativeOnSessionKeysChange(long nativeMediaDrmBridge, byt e[] emeSessionId, | 1379 private native void nativeOnSessionKeysChange(long nativeMediaDrmBridge, byt e[] emeSessionId, |
1166 Object[] keysInfo, boolean hasAdditionalUsableKey); | 1380 Object[] keysInfo, boolean hasAdditionalUsableKey, boolean isKeyRele ase); |
1167 private native void nativeOnSessionExpirationUpdate( | 1381 private native void nativeOnSessionExpirationUpdate( |
1168 long nativeMediaDrmBridge, byte[] emeSessionId, long expirationTime) ; | 1382 long nativeMediaDrmBridge, byte[] emeSessionId, long expirationTime) ; |
1169 | 1383 |
1170 private native void nativeOnResetDeviceCredentialsCompleted( | 1384 private native void nativeOnResetDeviceCredentialsCompleted( |
1171 long nativeMediaDrmBridge, boolean success); | 1385 long nativeMediaDrmBridge, boolean success); |
1172 } | 1386 } |
OLD | NEW |