diff --git a/media-source/dedicated-worker/mediasource-message-util.js b/media-source/dedicated-worker/mediasource-message-util.js index 247071db4f13f33..c62eb8e3f7dc9ab 100644 --- a/media-source/dedicated-worker/mediasource-message-util.js +++ b/media-source/dedicated-worker/mediasource-message-util.js @@ -4,6 +4,7 @@ const messageSubject = { ERROR: "error", // info field may contain more detail OBJECT_URL: "object url", // info field contains object URL + HANDLE: "handle", // info field contains the MediaSourceHandle STARTED_BUFFERING: "started buffering", FINISHED_BUFFERING: "finished buffering", VERIFY_DURATION: "verify duration", // info field contains expected duration diff --git a/media-source/dedicated-worker/mediasource-worker-detach-element.html b/media-source/dedicated-worker/mediasource-worker-detach-element.html index 7b00c59a07be9f2..0f74d953723a40f 100644 --- a/media-source/dedicated-worker/mediasource-worker-detach-element.html +++ b/media-source/dedicated-worker/mediasource-worker-detach-element.html @@ -7,11 +7,11 @@ + + + + diff --git a/media-source/dedicated-worker/mediasource-worker-handle.js b/media-source/dedicated-worker/mediasource-worker-handle.js new file mode 100644 index 000000000000000..577b1facbc9fcd0 --- /dev/null +++ b/media-source/dedicated-worker/mediasource-worker-handle.js @@ -0,0 +1,45 @@ +importScripts("/resources/testharness.js"); + +test(t => { + // The Window test html conditionally fetches and runs these tests only if the + // implementation exposes a true-valued static canConstructInDedicatedWorker + // attribute on MediaSource in the Window context. So, the implementation must + // agree on support here in the dedicated worker context. + + // Ensure we're executing in a dedicated worker context. + assert_true(self instanceof DedicatedWorkerGlobalScope, "self instanceof DedicatedWorkerGlobalScope"); + assert_true(MediaSource.hasOwnProperty("canConstructInDedicatedWorker", "DedicatedWorker MediaSource hasOwnProperty 'canConstructInDedicatedWorker'")); + assert_true(MediaSource.canConstructInDedicatedWorker, "DedicatedWorker MediaSource.canConstructInDedicatedWorker"); +}, "MediaSource in DedicatedWorker context must have true-valued canConstructInDedicatedWorker if Window context had it"); + +test(t => { + assert_true("getHandle" in MediaSource.prototype, "dedicated worker MediaSource must have getHandle"); + assert_true(self.hasOwnProperty("MediaSourceHandle"), "dedicated worker must have MediaSourceHandle visibility"); +}, "MediaSource prototype in DedicatedWorker context must have getHandle, and worker must have MediaSourceHandle"); + +test(t => { + const ms = new MediaSource(); + assert_equals(ms.readyState, "closed"); +}, "MediaSource construction succeeds with initial closed readyState in DedicatedWorker"); + +test(t => { + const ms = new MediaSource(); + const handle = ms.getHandle(); + assert_not_equals(handle, null, "must have a non-null getHandle result"); + assert_true(handle instanceof MediaSourceHandle, "must be a MediaSourceHandle"); +}, "mediaSource.getHandle() in DedicatedWorker returns a MediaSourceHandle"); + +test(t => { + const ms = new MediaSource(); + const handle1 = ms.getHandle(); + let handle2 = null; + assert_throws_dom("InvalidStateError", function() + { + handle2 = ms.getHandle(); + }, "getting second handle from MediaSource instance"); + assert_equals(handle2, null, "getting second handle from same MediaSource must have failed"); + assert_not_equals(handle1, null, "must have a non-null result of the first getHandle"); + assert_true(handle1 instanceof MediaSourceHandle, "first getHandle result must be a MediaSourceHandle"); +}, "mediaSource.getHandle() must not succeed more than precisely once for a MediaSource instance"); + +done(); diff --git a/media-source/dedicated-worker/mediasource-worker-objecturl.html b/media-source/dedicated-worker/mediasource-worker-objecturl.html index 5553b5c631e8919..ae6019967252e5c 100644 --- a/media-source/dedicated-worker/mediasource-worker-objecturl.html +++ b/media-source/dedicated-worker/mediasource-worker-objecturl.html @@ -1,6 +1,6 @@ -Test MediaSource object and objectUrl creation and revocation, with MediaSource in dedicated worker +Test MediaSource object and objectUrl creation and load via that url should fail, with MediaSource in dedicated worker @@ -11,7 +11,7 @@ assert_true(MediaSource.hasOwnProperty("canConstructInDedicatedWorker"), "MediaSource hasOwnProperty 'canConstructInDedicatedWorker'"); assert_true(MediaSource.canConstructInDedicatedWorker, "MediaSource.canConstructInDedicatedWorker"); - let worker = new Worker("mediasource-worker-play.js"); + let worker = new Worker("mediasource-worker-get-objecturl.js"); worker.onmessage = t.step_func(e => { let subject = e.data.subject; assert_true(subject != undefined, "message must have a subject field"); @@ -21,19 +21,21 @@ break; case messageSubject.OBJECT_URL: const url = e.data.info; - assert_true(url.match(/^blob:.+/) != null); - URL.revokeObjectURL(url); - // TODO(crbug.com/1196040): Revoking MediaSource objectURLs on thread - // that didn't create them is at best a no-op. This test case is - // possibly obsolete. - t.done(); + const video = document.createElement("video"); + document.body.appendChild(video); + video.onerror = t.step_func((target) => { + assert_true(video.error != null); + assert_equals(video.error.code, MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED); + t.done(); + }); + video.onended = t.unreached_func("video should not have successfully loaded and played to end"); + video.src = url; break; default: assert_unreached("Unexpected message subject: " + subject); - } }); -}, "Test main context revocation of DedicatedWorker MediaSource object URL"); +}, "Test main context load of a DedicatedWorker MediaSource object URL should fail"); if (MediaSource.hasOwnProperty("canConstructInDedicatedWorker") && MediaSource.canConstructInDedicatedWorker === true) { // If implementation claims support for MSE-in-Workers, then fetch and run diff --git a/media-source/dedicated-worker/mediasource-worker-objecturl.js b/media-source/dedicated-worker/mediasource-worker-objecturl.js index 9a7195fc5bda04e..2e70d99418173d5 100644 --- a/media-source/dedicated-worker/mediasource-worker-objecturl.js +++ b/media-source/dedicated-worker/mediasource-worker-objecturl.js @@ -20,9 +20,7 @@ test(t => { test(t => { const ms = new MediaSource(); const url = URL.createObjectURL(ms); - assert_true(url != null); - assert_true(url.match(/^blob:.+/) != null); -}, "URL.createObjectURL(mediaSource) in DedicatedWorker returns a Blob URI"); +}, "URL.createObjectURL(mediaSource) in DedicatedWorker does not throw exception"); test(t => { const ms = new MediaSource(); diff --git a/media-source/dedicated-worker/mediasource-worker-play-terminate-worker.html b/media-source/dedicated-worker/mediasource-worker-play-terminate-worker.html index ca8b6970f89576a..d6496afd6f4b29c 100644 --- a/media-source/dedicated-worker/mediasource-worker-play-terminate-worker.html +++ b/media-source/dedicated-worker/mediasource-worker-play-terminate-worker.html @@ -40,7 +40,7 @@ video.loop = true; } - if (when_to_start_timeouts == "before setting src") { + if (when_to_start_timeouts == "before setting srcObject") { terminateWorkerAfterMultipleSetTimeouts(test, worker, timeouts_to_await); } @@ -51,11 +51,10 @@ case messageSubject.ERROR: assert_unreached("Worker error: " + e.data.info); break; - case messageSubject.OBJECT_URL: - const url = e.data.info; - assert_true(url.match(/^blob:.+/) != null); - video.src = url; - if (when_to_start_timeouts == "after setting src") { + case messageSubject.HANDLE: + const handle = e.data.info; + video.srcObject = handle; + if (when_to_start_timeouts == "after setting srcObject") { terminateWorkerAfterMultipleSetTimeouts(test, worker, timeouts_to_await); } video.play().catch(error => { @@ -73,7 +72,7 @@ }); } -[ "before setting src", "after setting src", "after first ended event" ].forEach(when => { +[ "before setting srcObject", "after setting srcObject", "after first ended event" ].forEach(when => { for (let timeouts = 0; timeouts < 10; ++timeouts) { async_test(test => { startWorkerAndTerminateWorker(test, when, timeouts); }, "Test worker MediaSource termination after at least " + timeouts + diff --git a/media-source/dedicated-worker/mediasource-worker-play.html b/media-source/dedicated-worker/mediasource-worker-play.html index 07317e6d0c9f0b4..0292b13d09ff6aa 100644 --- a/media-source/dedicated-worker/mediasource-worker-play.html +++ b/media-source/dedicated-worker/mediasource-worker-play.html @@ -26,10 +26,9 @@ case messageSubject.ERROR: assert_unreached("Worker error: " + e.data.info); break; - case messageSubject.OBJECT_URL: - const url = e.data.info; - assert_true(url.match(/^blob:.+/) != null); - video.src = url; + case messageSubject.HANDLE: + const handle = e.data.info; + video.srcObject = handle; video.play(); break; default: diff --git a/media-source/dedicated-worker/mediasource-worker-play.js b/media-source/dedicated-worker/mediasource-worker-play.js index 0312f16fd99e7ac..e29b1b8de6397b9 100644 --- a/media-source/dedicated-worker/mediasource-worker-play.js +++ b/media-source/dedicated-worker/mediasource-worker-play.js @@ -11,7 +11,6 @@ onmessage = function(evt) { let util = new MediaSourceWorkerUtil(); util.mediaSource.addEventListener("sourceopen", () => { - URL.revokeObjectURL(util.mediaSourceObjectUrl); sourceBuffer = util.mediaSource.addSourceBuffer(util.mediaMetadata.type); sourceBuffer.onerror = (err) => { postMessage({ subject: messageSubject.ERROR, info: err }); @@ -43,4 +42,4 @@ util.mediaSource.addEventListener("sourceopen", () => { err => { postMessage({ subject: messageSubject.ERROR, info: err }) }); }, { once : true }); -postMessage({ subject: messageSubject.OBJECT_URL, info: util.mediaSourceObjectUrl }); +postMessage({ subject: messageSubject.HANDLE, info: util.mediaSource.getHandle() }); diff --git a/media-source/dedicated-worker/mediasource-worker-util.js b/media-source/dedicated-worker/mediasource-worker-util.js index 695d1179d39b181..7adaf82508d0d13 100644 --- a/media-source/dedicated-worker/mediasource-worker-util.js +++ b/media-source/dedicated-worker/mediasource-worker-util.js @@ -22,7 +22,6 @@ let MEDIA_LIST = [ class MediaSourceWorkerUtil { constructor() { this.mediaSource = new MediaSource(); - this.mediaSourceObjectUrl = URL.createObjectURL(this.mediaSource); // Find supported test media, if any. this.foundSupportedMedia = false;