From a504f14cfdb33b8f09f1aac8af7e598ea31dddf1 Mon Sep 17 00:00:00 2001 From: Joey Parrish Date: Fri, 2 Jun 2017 16:08:39 -0700 Subject: [PATCH] Fix PlayReady on IE and Edge We broke PlayReady on IE and Edge in #815 when we fixed PlayReady for Tizen. This should work for both, but will still need to be tested on Tizen after merging. Closes #837 Change-Id: Iff41845ae6a4b369e8f21a80623ebb2cb5475fd6 --- lib/media/drm_engine.js | 34 ++++++++++++---------------- lib/util/string_utils.js | 9 +++++--- test/media/drm_engine_integration.js | 3 +-- 3 files changed, 22 insertions(+), 24 deletions(-) diff --git a/lib/media/drm_engine.js b/lib/media/drm_engine.js index 091b55a374..cb6ebda2b5 100644 --- a/lib/media/drm_engine.js +++ b/lib/media/drm_engine.js @@ -1119,23 +1119,9 @@ shaka.media.DrmEngine.prototype.sendLicenseRequest_ = function(event) { * @private */ shaka.media.DrmEngine.prototype.unpackPlayReadyRequest_ = function(request) { - // PlayReady CDMs in some clients (e.g. IE11, Edge) wrap the license message - // in UTF-16 encoded XML which can't be directly delivered to a license - // server. However, not all clients exhibit this behaviour. The Tizen - // PlayReady CDM message is UTF-8 encoded and can be passed to the license - // server as-is. Other CDMs do not seem to need this kind of special - // handling. - var xml = String.fromCharCode.apply(null, new Uint8Array(request.body)); - - if (xml.indexOf(' // - xml = shaka.util.StringUtils.fromUTF16( - request.body, true /* littleEndian */); + var xml = shaka.util.StringUtils.fromUTF16( + request.body, true /* littleEndian */, true /* noThrow */); + if (xml.indexOf('PlayReadyKeyMessage') == -1) { + // This does not appear to be a wrapped message as on IE and Edge. Some + // clients do not need this unwrapping, so we will assume this is one of + // them. Note that "xml" at this point probably looks like random garbage, + // since we interpreted UTF-8 as UTF-16. + shaka.log.debug('PlayReady request is already unwrapped.'); + request.headers['Content-Type'] = 'text/xml; charset=utf-8'; + return; + } + shaka.log.debug('Unwrapping PlayReady request.'); var dom = new DOMParser().parseFromString(xml, 'application/xml'); // Set request headers. diff --git a/lib/util/string_utils.js b/lib/util/string_utils.js index 39f5ed2ad2..98114d3dc0 100644 --- a/lib/util/string_utils.js +++ b/lib/util/string_utils.js @@ -70,14 +70,17 @@ shaka.util.StringUtils.fromUTF8 = function(data) { * * @param {?BufferSource} data * @param {boolean} littleEndian true to read little endian, false to read big. + * @param {boolean=} opt_noThrow true to avoid throwing in cases where we may + * expect invalid input. If noThrow is true and the data has an odd length, + * it will be truncated. * @return {string} * @throws {shaka.util.Error} * @export */ -shaka.util.StringUtils.fromUTF16 = function(data, littleEndian) { +shaka.util.StringUtils.fromUTF16 = function(data, littleEndian, opt_noThrow) { if (!data) return ''; - if (data.byteLength % 2 != 0) { + if (!opt_noThrow && data.byteLength % 2 != 0) { shaka.log.error('Data has an incorrect length, must be even.'); throw new shaka.util.Error( shaka.util.Error.Severity.CRITICAL, shaka.util.Error.Category.TEXT, @@ -98,7 +101,7 @@ shaka.util.StringUtils.fromUTF16 = function(data, littleEndian) { } // Use a DataView to ensure correct endianness. - var length = data.byteLength / 2; + var length = Math.floor(data.byteLength / 2); var arr = new Uint16Array(length); var dataView = new DataView(buffer); for (var i = 0; i < length; i++) { diff --git a/test/media/drm_engine_integration.js b/test/media/drm_engine_integration.js index b2425bec7a..5bab7451d3 100644 --- a/test/media/drm_engine_integration.js +++ b/test/media/drm_engine_integration.js @@ -247,9 +247,8 @@ describe('DrmEngine', function() { }); // describe('basic flow') function checkKeySystems() { - // TODO: re-enable these tests for PlayReady (b/38496036) // Our test asset for this suite can use any of these key systems: - if (!support['com.widevine.alpha']) { + if (!support['com.widevine.alpha'] && !support['com.microsoft.playready']) { // pending() throws a special exception that Jasmine uses to skip a test. // It can only be used from inside it(), not describe() or beforeEach(). pending('Skipping DrmEngine tests.');