Title: [280958] trunk
Revision
280958
Author
[email protected]
Date
2021-08-12 02:37:05 -0700 (Thu, 12 Aug 2021)

Log Message

Implement SFrameTransform error handling
https://bugs.webkit.org/show_bug.cgi?id=228947

Reviewed by Eric Carlson.

Source/WebCore:

Add support for RTCRtpSFrameTransformErrorEvent.
When RTCRtpSFrameTransformer encounters an issue, dispatch a task to RTCRtpSFrameTransform context and fire a corresponding event.
This follows https://w3c.github.io/webrtc-encoded-transform/#sframe-transform-algorithm, except that:
- we are not yet exposing some fields in RTCRtpSFrameTransformErrorEvent.
- we are using errorType instead of type which should be fixed in the spec.

Test: imported/w3c/web-platform-tests/webrtc-encoded-transform/sframe-transform-error.html

* CMakeLists.txt:
* DerivedSources-input.xcfilelist:
* DerivedSources-output.xcfilelist:
* DerivedSources.make:
* Modules/mediastream/RTCRtpSFrameTransform.cpp:
(WebCore::RTCRtpSFrameTransform::RTCRtpSFrameTransform):
(WebCore::errorTypeFromInformation):
(WebCore::processFrame):
(WebCore::RTCRtpSFrameTransform::hasKey const):
(WebCore::RTCRtpSFrameTransform::initializeTransformer):
(WebCore::transformFrame):
(WebCore::RTCRtpSFrameTransform::createStreams):
(WebCore::RTCRtpSFrameTransform::writable):
(WebCore::RTCRtpSFrameTransform::virtualHasPendingActivity const):
* Modules/mediastream/RTCRtpSFrameTransform.h:
* Modules/mediastream/RTCRtpSFrameTransform.idl:
* Modules/mediastream/RTCRtpSFrameTransformErrorEvent.cpp: Added.
(WebCore::RTCRtpSFrameTransformErrorEvent::create):
(WebCore::RTCRtpSFrameTransformErrorEvent::RTCRtpSFrameTransformErrorEvent):
(WebCore::RTCRtpSFrameTransformErrorEvent::eventInterface const):
* Modules/mediastream/RTCRtpSFrameTransformErrorEvent.h: Added.
* Modules/mediastream/RTCRtpSFrameTransformErrorEvent.idl: Added.
* Modules/mediastream/RTCRtpSFrameTransformer.cpp:
(WebCore::RTCRtpSFrameTransformer::hasKey const):
(WebCore::RTCRtpSFrameTransformer::decryptFrame):
(WebCore::RTCRtpSFrameTransformer::encryptFrame):
(WebCore::RTCRtpSFrameTransformer::transform):
* Modules/mediastream/RTCRtpSFrameTransformer.h:
* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* bindings/js/WebCoreBuiltinNames.h:
* dom/EventNames.in:
* dom/EventTargetFactory.in:

Tools:

* TestWebKitAPI/Tests/WebCore/RTCRtpSFrameTransformerTests.cpp:
(TestWebKitAPI::TEST):

LayoutTests:

* http/wpt/webrtc/sframe-transform-error-worker.js: Added.
(onrtctransform.async event):
* http/wpt/webrtc/sframe-transform-error.html: Added.
* http/wpt/webrtc/sframe-transform-error-expected: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (280957 => 280958)


--- trunk/LayoutTests/ChangeLog	2021-08-12 04:35:22 UTC (rev 280957)
+++ trunk/LayoutTests/ChangeLog	2021-08-12 09:37:05 UTC (rev 280958)
@@ -1,3 +1,15 @@
+2021-08-12  Youenn Fablet  <[email protected]>
+
+        Implement SFrameTransform error handling
+        https://bugs.webkit.org/show_bug.cgi?id=228947
+
+        Reviewed by Eric Carlson.
+
+        * http/wpt/webrtc/sframe-transform-error-worker.js: Added.
+        (onrtctransform.async event):
+        * http/wpt/webrtc/sframe-transform-error.html: Added.
+        * http/wpt/webrtc/sframe-transform-error-expected: Added.
+
 2021-08-11  Lauro Moura  <[email protected]>
 
         [GLIB] Gardening a few failures and passes

Added: trunk/LayoutTests/http/wpt/webrtc/sframe-transform-error-expected.txt (0 => 280958)


--- trunk/LayoutTests/http/wpt/webrtc/sframe-transform-error-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/wpt/webrtc/sframe-transform-error-expected.txt	2021-08-12 09:37:05 UTC (rev 280958)
@@ -0,0 +1,5 @@
+
+
+PASS Missing key triggers an error that can be corrected by adding a key
+PASS Tampered data should trigger SFrameTransform errors
+

Added: trunk/LayoutTests/http/wpt/webrtc/sframe-transform-error-worker.js (0 => 280958)


--- trunk/LayoutTests/http/wpt/webrtc/sframe-transform-error-worker.js	                        (rev 0)
+++ trunk/LayoutTests/http/wpt/webrtc/sframe-transform-error-worker.js	2021-08-12 09:37:05 UTC (rev 280958)
@@ -0,0 +1,32 @@
+let triggerError;
+_onmessage_ = (event) => triggerError = event.data.action;
+
+_onrtctransform_ = async (event) => {
+    const transformer = event.transformer;
+
+    const key = await crypto.subtle.importKey("raw", new Uint8Array([143, 77, 43, 10, 72, 19, 37, 67, 236, 219, 24, 93, 26, 165, 91, 178]), "HKDF", false, ["deriveBits", "deriveKey"]);
+    const sframeTransform = new SFrameTransform({ role: "encrypt", authenticationSize: "4" });
+    sframeTransform.setEncryptionKey(key, 1);
+
+    const postTransform = new TransformStream({transform: (frame, controller) => {
+       if (triggerError === "authenticationError") {
+          const data = "" Uint8Array(frame.data);
+          // We change the authentication tag.
+          data[data.byteLength - 1] = !data[data.byteLength - 1];
+          frame.data = ""
+       } else if (triggerError === "syntaxError") {
+          const data = "" Uint8Array(frame.data);
+          // We set the signature bit.
+          data[0] = 255;
+          frame.data = ""
+       }
+       triggerError = undefined;
+       controller.enqueue(frame);
+    }});
+
+    transformer.readable.pipeThrough(sframeTransform)
+		.pipeThrough(postTransform)
+		.pipeTo(transformer.writable);
+}
+self.postMessage("registered");
+

Added: trunk/LayoutTests/http/wpt/webrtc/sframe-transform-error.html (0 => 280958)


--- trunk/LayoutTests/http/wpt/webrtc/sframe-transform-error.html	                        (rev 0)
+++ trunk/LayoutTests/http/wpt/webrtc/sframe-transform-error.html	2021-08-12 09:37:05 UTC (rev 280958)
@@ -0,0 +1,92 @@
+<!doctype html>
+<html>
+    <head>
+        <meta charset="utf-8">
+        <script src=""
+        <script src=""
+        <script src=""
+    </head>
+    <body>
+        <video id='video' controls autoplay playsinline></video>
+        <script>
+promise_test(async (test) => {
+    const key1 = await crypto.subtle.importKey("raw", new Uint8Array([143, 77, 43, 10, 72, 19, 37, 67, 236, 219, 24, 93, 26, 165, 91, 178]), "HKDF", false, ["deriveBits", "deriveKey"]);
+    const key2 = await crypto.subtle.importKey("raw", new Uint8Array([144, 77, 43, 10, 72, 19, 37, 67, 236, 219, 24, 93, 26, 165, 91, 178]), "HKDF", false, ["deriveBits", "deriveKey"]);
+    const key3 = await crypto.subtle.importKey("raw", new Uint8Array([145, 77, 43, 10, 72, 19, 37, 67, 236, 219, 24, 93, 26, 165, 91, 178]), "HKDF", false, ["deriveBits", "deriveKey"]);
+    const key4 = await crypto.subtle.importKey("raw", new Uint8Array([146, 77, 43, 10, 72, 19, 37, 67, 236, 219, 24, 93, 26, 165, 91, 178]), "HKDF", false, ["deriveBits", "deriveKey"]);
+
+    const localStream = await navigator.mediaDevices.getUserMedia({audio: true});
+    let receiver;
+    const stream = await new Promise((resolve, reject) => {
+        const connections = createConnections(test, (firstConnection) => {
+            const sender = firstConnection.addTrack(localStream.getAudioTracks()[0], localStream);
+            const transform = new SFrameTransform;
+            transform.setEncryptionKey(key1, 1);
+            sender.transform = transform;
+        }, (secondConnection) => {
+            secondConnection._ontrack_ = (trackEvent) => {
+                const transform = new SFrameTransform;
+                transform.setEncryptionKey(key1, 0);
+                receiver = trackEvent.receiver;
+                receiver.transform = transform;
+                resolve(trackEvent.streams[0]);
+            };
+        });
+        test.step_timeout(() => reject("Test timed out"), 5000);
+    });
+
+    let error = await new Promise(resolve => receiver.transform._onerror_ = resolve);
+    assert_equals(error.errorType, "keyID");
+    receiver.transform.setEncryptionKey(key1, 1);
+
+    await new Promise((resolve, reject) => {
+        receiver.transform._onerror_ = () => reject('sframe still has errors');
+        test.step_timeout(resolve, 100);
+    });
+}, "Missing key triggers an error that can be corrected by adding a key");
+
+promise_test(async (test) => {
+    worker = new Worker('sframe-transform-error-worker.js');
+    const data = "" new Promise(resolve => worker._onmessage_ = (event) => resolve(event.data));
+    assert_equals(data, "registered");
+    const localStream = await navigator.mediaDevices.getUserMedia({ audio: true });
+
+    let sender, receiver;
+
+    const receiverTransform = new SFrameTransform();
+    const key = await crypto.subtle.importKey("raw", new Uint8Array([143, 77, 43, 10, 72, 19, 37, 67, 236, 219, 24, 93, 26, 165, 91, 178]), "HKDF", false, ["deriveBits", "deriveKey"]);
+    receiverTransform.setEncryptionKey(key, 1);
+
+    const senderTransform = new RTCRtpScriptTransform(worker, "SFrameRTCRtpTransform");
+
+    const startedPromise = new Promise(resolve => worker._onmessage_ = (event) => resolve(event.data));
+
+    const remoteStream = await new Promise((resolve, reject) => {
+        createConnections(test, (firstConnection) => {
+            pc1 = firstConnection;
+            sender = firstConnection.addTrack(localStream.getTracks()[0], localStream);
+            sender.transform = senderTransform;
+        }, (secondConnection) => {
+            pc2 = secondConnection;
+            secondConnection._ontrack_ = (trackEvent) => {
+                receiver = trackEvent.receiver;
+                receiver.transform = receiverTransform;
+                resolve(trackEvent.streams[0]);
+            };
+        });
+        test.step_timeout(() => reject("Test timed out"), 5000);
+    });
+
+    video.srcObject = remoteStream;
+
+    worker.postMessage({action:"authenticationError"});
+    let error = await new Promise(resolve => receiver.transform._onerror_ = resolve);
+    assert_equals(error.errorType, "authentication");
+
+    worker.postMessage({action:"syntaxError"});
+    error = await new Promise(resolve => receiver.transform._onerror_ = resolve);
+    assert_equals(error.errorType, "syntax");
+}, "Tampered data should trigger SFrameTransform errors");
+        </script>
+    </body>
+</html>

Modified: trunk/Source/WebCore/CMakeLists.txt (280957 => 280958)


--- trunk/Source/WebCore/CMakeLists.txt	2021-08-12 04:35:22 UTC (rev 280957)
+++ trunk/Source/WebCore/CMakeLists.txt	2021-08-12 09:37:05 UTC (rev 280958)
@@ -412,6 +412,7 @@
     Modules/mediastream/RTCRtpReceiver.idl
     Modules/mediastream/RTCRtpRtxParameters.idl
     Modules/mediastream/RTCRtpSFrameTransform.idl
+    Modules/mediastream/RTCRtpSFrameTransformErrorEvent.idl
     Modules/mediastream/RTCRtpScriptTransform.idl
     Modules/mediastream/RTCRtpScriptTransformProvider.idl
     Modules/mediastream/RTCRtpScriptTransformer.idl

Modified: trunk/Source/WebCore/ChangeLog (280957 => 280958)


--- trunk/Source/WebCore/ChangeLog	2021-08-12 04:35:22 UTC (rev 280957)
+++ trunk/Source/WebCore/ChangeLog	2021-08-12 09:37:05 UTC (rev 280958)
@@ -1,3 +1,52 @@
+2021-08-12  Youenn Fablet  <[email protected]>
+
+        Implement SFrameTransform error handling
+        https://bugs.webkit.org/show_bug.cgi?id=228947
+
+        Reviewed by Eric Carlson.
+
+        Add support for RTCRtpSFrameTransformErrorEvent.
+        When RTCRtpSFrameTransformer encounters an issue, dispatch a task to RTCRtpSFrameTransform context and fire a corresponding event.
+        This follows https://w3c.github.io/webrtc-encoded-transform/#sframe-transform-algorithm, except that:
+        - we are not yet exposing some fields in RTCRtpSFrameTransformErrorEvent.
+        - we are using errorType instead of type which should be fixed in the spec.
+
+        Test: imported/w3c/web-platform-tests/webrtc-encoded-transform/sframe-transform-error.html
+
+        * CMakeLists.txt:
+        * DerivedSources-input.xcfilelist:
+        * DerivedSources-output.xcfilelist:
+        * DerivedSources.make:
+        * Modules/mediastream/RTCRtpSFrameTransform.cpp:
+        (WebCore::RTCRtpSFrameTransform::RTCRtpSFrameTransform):
+        (WebCore::errorTypeFromInformation):
+        (WebCore::processFrame):
+        (WebCore::RTCRtpSFrameTransform::hasKey const):
+        (WebCore::RTCRtpSFrameTransform::initializeTransformer):
+        (WebCore::transformFrame):
+        (WebCore::RTCRtpSFrameTransform::createStreams):
+        (WebCore::RTCRtpSFrameTransform::writable):
+        (WebCore::RTCRtpSFrameTransform::virtualHasPendingActivity const):
+        * Modules/mediastream/RTCRtpSFrameTransform.h:
+        * Modules/mediastream/RTCRtpSFrameTransform.idl:
+        * Modules/mediastream/RTCRtpSFrameTransformErrorEvent.cpp: Added.
+        (WebCore::RTCRtpSFrameTransformErrorEvent::create):
+        (WebCore::RTCRtpSFrameTransformErrorEvent::RTCRtpSFrameTransformErrorEvent):
+        (WebCore::RTCRtpSFrameTransformErrorEvent::eventInterface const):
+        * Modules/mediastream/RTCRtpSFrameTransformErrorEvent.h: Added.
+        * Modules/mediastream/RTCRtpSFrameTransformErrorEvent.idl: Added.
+        * Modules/mediastream/RTCRtpSFrameTransformer.cpp:
+        (WebCore::RTCRtpSFrameTransformer::hasKey const):
+        (WebCore::RTCRtpSFrameTransformer::decryptFrame):
+        (WebCore::RTCRtpSFrameTransformer::encryptFrame):
+        (WebCore::RTCRtpSFrameTransformer::transform):
+        * Modules/mediastream/RTCRtpSFrameTransformer.h:
+        * Sources.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+        * bindings/js/WebCoreBuiltinNames.h:
+        * dom/EventNames.in:
+        * dom/EventTargetFactory.in:
+
 2021-08-11  Alex Christensen  <[email protected]>
 
         Remove optimistic assertion added in r280931

Modified: trunk/Source/WebCore/DerivedSources-input.xcfilelist (280957 => 280958)


--- trunk/Source/WebCore/DerivedSources-input.xcfilelist	2021-08-12 04:35:22 UTC (rev 280957)
+++ trunk/Source/WebCore/DerivedSources-input.xcfilelist	2021-08-12 09:37:05 UTC (rev 280958)
@@ -256,6 +256,7 @@
 $(PROJECT_DIR)/Modules/mediastream/RTCRtpReceiver.idl
 $(PROJECT_DIR)/Modules/mediastream/RTCRtpRtxParameters.idl
 $(PROJECT_DIR)/Modules/mediastream/RTCRtpSFrameTransform.idl
+$(PROJECT_DIR)/Modules/mediastream/RTCRtpSFrameTransformErrorEvent.idl
 $(PROJECT_DIR)/Modules/mediastream/RTCRtpScriptTransform.idl
 $(PROJECT_DIR)/Modules/mediastream/RTCRtpScriptTransformProvider.idl
 $(PROJECT_DIR)/Modules/mediastream/RTCRtpScriptTransformer.idl

Modified: trunk/Source/WebCore/DerivedSources-output.xcfilelist (280957 => 280958)


--- trunk/Source/WebCore/DerivedSources-output.xcfilelist	2021-08-12 04:35:22 UTC (rev 280957)
+++ trunk/Source/WebCore/DerivedSources-output.xcfilelist	2021-08-12 09:37:05 UTC (rev 280958)
@@ -1697,6 +1697,8 @@
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSRTCRtpRtxParameters.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSRTCRtpSFrameTransform.cpp
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSRTCRtpSFrameTransform.h
+$(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSRTCRtpSFrameTransformErrorEvent.cpp
+$(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSRTCRtpSFrameTransformErrorEvent.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSRTCRtpScriptTransform.cpp
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSRTCRtpScriptTransform.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSRTCRtpScriptTransformProvider.cpp

Modified: trunk/Source/WebCore/DerivedSources.make (280957 => 280958)


--- trunk/Source/WebCore/DerivedSources.make	2021-08-12 04:35:22 UTC (rev 280957)
+++ trunk/Source/WebCore/DerivedSources.make	2021-08-12 09:37:05 UTC (rev 280958)
@@ -283,6 +283,7 @@
     $(WebCore)/Modules/mediastream/RTCRtpSender.idl \
     $(WebCore)/Modules/mediastream/RTCRtpSender+Transform.idl \
     $(WebCore)/Modules/mediastream/RTCRtpSFrameTransform.idl \
+    $(WebCore)/Modules/mediastream/RTCRtpSFrameTransformErrorEvent.idl \
     $(WebCore)/Modules/mediastream/RTCRtpScriptTransform.idl \
     $(WebCore)/Modules/mediastream/RTCRtpScriptTransformProvider.idl \
     $(WebCore)/Modules/mediastream/RTCRtpScriptTransformer.idl \

Modified: trunk/Source/WebCore/Modules/mediastream/RTCRtpSFrameTransform.cpp (280957 => 280958)


--- trunk/Source/WebCore/Modules/mediastream/RTCRtpSFrameTransform.cpp	2021-08-12 04:35:22 UTC (rev 280957)
+++ trunk/Source/WebCore/Modules/mediastream/RTCRtpSFrameTransform.cpp	2021-08-12 09:37:05 UTC (rev 280958)
@@ -35,6 +35,7 @@
 #include "Logging.h"
 #include "RTCEncodedAudioFrame.h"
 #include "RTCEncodedVideoFrame.h"
+#include "RTCRtpSFrameTransformErrorEvent.h"
 #include "RTCRtpSFrameTransformer.h"
 #include "RTCRtpTransformBackend.h"
 #include "RTCRtpTransformableFrame.h"
@@ -43,13 +44,18 @@
 #include "SharedBuffer.h"
 #include "WritableStream.h"
 #include "WritableStreamSink.h"
+#include <wtf/IsoMallocInlines.h>
 
 namespace WebCore {
 
+WTF_MAKE_ISO_ALLOCATED_IMPL(RTCRtpSFrameTransform);
+
 RTCRtpSFrameTransform::RTCRtpSFrameTransform(ScriptExecutionContext& context, Options options)
-    : ContextDestructionObserver(&context)
+    : ActiveDOMObject(&context)
     , m_transformer(RTCRtpSFrameTransformer::create(options.compatibilityMode))
 {
+    suspendIfNeeded();
+
     m_transformer->setIsEncrypting(options.role == Role::Encrypt);
     m_transformer->setAuthenticationSize(options.authenticationSize);
 }
@@ -95,10 +101,53 @@
     return m_isAttached || (m_readable && m_readable->isLocked()) || (m_writable && m_writable->isLocked());
 }
 
+static RTCRtpSFrameTransformErrorEvent::Type errorTypeFromInformation(const RTCRtpSFrameTransformer::ErrorInformation& errorInformation)
+{
+    switch (errorInformation.error) {
+    case RTCRtpSFrameTransformer::Error::KeyID:
+        return RTCRtpSFrameTransformErrorEvent::Type::KeyID;
+    case RTCRtpSFrameTransformer::Error::Authentication:
+        return RTCRtpSFrameTransformErrorEvent::Type::Authentication;
+    case RTCRtpSFrameTransformer::Error::Syntax:
+        return RTCRtpSFrameTransformErrorEvent::Type::Syntax;
+    case RTCRtpSFrameTransformer::Error::Other:
+        return RTCRtpSFrameTransformErrorEvent::Type::Other;
+    }
+}
+
+static std::optional<Vector<uint8_t>> processFrame(const uint8_t* data, size_t size, RTCRtpSFrameTransformer& transformer, ScriptExecutionContextIdentifier identifier, const WeakPtr<RTCRtpSFrameTransform>& weakTransform)
+{
+    auto result = transformer.transform(data, size);
+    if (!result.has_value()) {
+        auto errorInformation = WTFMove(result.error());
+        errorInformation.message = { };
+        RELEASE_LOG_ERROR(WebRTC, "RTCRtpSFrameTransform failed transforming a frame with error %d", errorInformation.error);
+        // Call the error event handler.
+        ScriptExecutionContext::postTaskTo(identifier, [errorInformation, weakTransform](auto&&) {
+            if (!weakTransform || weakTransform->isContextStopped())
+                return;
+            if (errorInformation.error == RTCRtpSFrameTransformer::Error::KeyID && weakTransform->hasKey(errorInformation.keyId))
+                return;
+            weakTransform->dispatchEvent(RTCRtpSFrameTransformErrorEvent::create(Event::CanBubble::No, Event::IsCancelable::No, errorTypeFromInformation(errorInformation)));
+        });
+        return { };
+    }
+    return WTFMove(result.value());
+}
+
+bool RTCRtpSFrameTransform::hasKey(uint64_t keyID) const
+{
+    return m_transformer->hasKey(keyID);
+}
+
 void RTCRtpSFrameTransform::initializeTransformer(RTCRtpTransformBackend& backend, Side side)
 {
     ASSERT(!isAttached());
 
+    auto* context = scriptExecutionContext();
+    if (!context)
+        return;
+
     m_isAttached = true;
     if (m_readable)
         m_readable->lock();
@@ -108,16 +157,16 @@
     m_transformer->setIsEncrypting(side == Side::Sender);
     m_transformer->setMediaType(backend.mediaType());
 
-    backend.setTransformableFrameCallback([transformer = m_transformer, backend = makeRef(backend)](auto&& frame) {
+    backend.setTransformableFrameCallback([transformer = m_transformer, identifier = context->contextIdentifier(), backend = makeRef(backend), weakThis = makeWeakPtr(this)](auto&& frame) {
         auto chunk = frame->data();
-        auto result = transformer->transform(chunk.data, chunk.size);
+        if (!chunk.data || !chunk.size)
+            return;
+        auto result = processFrame(chunk.data, chunk.size, transformer.get(), identifier, weakThis);
 
-        if (result.hasException()) {
-            RELEASE_LOG_ERROR(WebRTC, "RTCRtpSFrameTransform failed transforming a frame");
+        if (!result)
             return;
-        }
 
-        frame->setData({ result.returnValue().data(), result.returnValue().size() });
+        frame->setData({ result.value().data(), result.value().size() });
 
         backend->processTransformedFrame(frame.get());
     });
@@ -138,31 +187,25 @@
     backend.clearTransformableFrameCallback();
 }
 
+static void transformFrame(const uint8_t* data, size_t size, JSDOMGlobalObject& globalObject, RTCRtpSFrameTransformer& transformer, SimpleReadableStreamSource& source, ScriptExecutionContextIdentifier identifier, const WeakPtr<RTCRtpSFrameTransform>& weakTransform)
+{
+    auto result = processFrame(data, size, transformer, identifier, weakTransform);
+    auto buffer = result ? SharedBuffer::create(WTFMove(*result)) : SharedBuffer::create();
+    source.enqueue(toJS(&globalObject, &globalObject, buffer->tryCreateArrayBuffer().get()));
+}
+
 template<typename Frame>
-void transformFrame(Frame& frame, JSDOMGlobalObject& globalObject, RTCRtpSFrameTransformer& transformer, SimpleReadableStreamSource& source)
+void transformFrame(Frame& frame, JSDOMGlobalObject& globalObject, RTCRtpSFrameTransformer& transformer, SimpleReadableStreamSource& source, ScriptExecutionContextIdentifier identifier, const WeakPtr<RTCRtpSFrameTransform>& weakTransform)
 {
     auto chunk = frame.rtcFrame().data();
-    auto result = transformer.transform(chunk.data, chunk.size);
-    RELEASE_LOG_ERROR_IF(result.hasException(), WebRTC, "RTCRtpSFrameTransform failed transforming a frame");
-
+    auto result = processFrame(chunk.data, chunk.size, transformer, identifier, weakTransform);
     RTCRtpTransformableFrame::Data transformedChunk;
-    // In case of error, we just pass along the frame with empty data.
-    if (!result.hasException())
-        transformedChunk = { result.returnValue().data(), result.returnValue().size() };
-
+    if (result)
+        transformedChunk = { result->data(), result->size() };
     frame.rtcFrame().setData(transformedChunk);
     source.enqueue(toJS(&globalObject, &globalObject, frame));
 }
 
-static void transformFrame(const uint8_t* data, size_t size, JSDOMGlobalObject& globalObject, RTCRtpSFrameTransformer& transformer, SimpleReadableStreamSource& source)
-{
-    auto result = transformer.transform(data, size);
-    RELEASE_LOG_ERROR_IF(result.hasException(), WebRTC, "RTCRtpSFrameTransform failed transforming a frame");
-
-    auto buffer = result.hasException() ? SharedBuffer::create() : SharedBuffer::create(result.releaseReturnValue());
-    source.enqueue(toJS(&globalObject, &globalObject, buffer->tryCreateArrayBuffer().get()));
-}
-
 void RTCRtpSFrameTransform::createStreams(JSC::JSGlobalObject& globalObject)
 {
     m_readableStreamSource = SimpleReadableStreamSource::create();
@@ -170,7 +213,7 @@
     if (readable.hasException())
         return;
 
-    auto writable = WritableStream::create(globalObject, SimpleWritableStreamSink::create([transformer = m_transformer, readableStreamSource = m_readableStreamSource](auto& context, auto value) -> ExceptionOr<void> {
+    auto writable = WritableStream::create(globalObject, SimpleWritableStreamSink::create([transformer = m_transformer, readableStreamSource = m_readableStreamSource, weakThis = makeWeakPtr(this)](auto& context, auto value) -> ExceptionOr<void> {
         if (!context.globalObject())
             return Exception { InvalidStateError };
         auto& globalObject = *JSC::jsCast<JSDOMGlobalObject*>(context.globalObject());
@@ -182,13 +225,13 @@
 
         // We do not want to throw any exception in the transform to make sure we do not error the transform.
         WTF::switchOn(frame, [&](RefPtr<RTCEncodedAudioFrame>& value) {
-            transformFrame(*value, globalObject, transformer.get(), *readableStreamSource);
+            transformFrame(*value, globalObject, transformer.get(), *readableStreamSource, context.contextIdentifier(), weakThis);
         }, [&](RefPtr<RTCEncodedVideoFrame>& value) {
-            transformFrame(*value, globalObject, transformer.get(), *readableStreamSource);
+            transformFrame(*value, globalObject, transformer.get(), *readableStreamSource, context.contextIdentifier(), weakThis);
         }, [&](RefPtr<ArrayBuffer>& value) {
-            transformFrame(static_cast<const uint8_t*>(value->data()), value->byteLength(), globalObject, transformer.get(), *readableStreamSource);
+            transformFrame(static_cast<const uint8_t*>(value->data()), value->byteLength(), globalObject, transformer.get(), *readableStreamSource, context.contextIdentifier(), weakThis);
         }, [&](RefPtr<ArrayBufferView>& value) {
-            transformFrame(static_cast<const uint8_t*>(value->data()), value->byteLength(), globalObject, transformer.get(), *readableStreamSource);
+            transformFrame(static_cast<const uint8_t*>(value->data()), value->byteLength(), globalObject, transformer.get(), *readableStreamSource, context.contextIdentifier(), weakThis);
         });
         return { };
     }));
@@ -232,9 +275,15 @@
     if (!m_writable)
         createStreams(*globalObject);
 
+    m_hasWritable = true;
     return m_writable.copyRef();
 }
 
+bool RTCRtpSFrameTransform::virtualHasPendingActivity() const
+{
+    return (m_isAttached || m_hasWritable) && hasEventListeners();
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(WEB_RTC)

Modified: trunk/Source/WebCore/Modules/mediastream/RTCRtpSFrameTransform.h (280957 => 280958)


--- trunk/Source/WebCore/Modules/mediastream/RTCRtpSFrameTransform.h	2021-08-12 04:35:22 UTC (rev 280957)
+++ trunk/Source/WebCore/Modules/mediastream/RTCRtpSFrameTransform.h	2021-08-12 09:37:05 UTC (rev 280958)
@@ -27,9 +27,11 @@
 
 #if ENABLE(WEB_RTC)
 
-#include "ContextDestructionObserver.h"
+#include "ActiveDOMObject.h"
+#include "EventTarget.h"
 #include "JSDOMPromiseDeferred.h"
 #include "RTCRtpSFrameTransformer.h"
+#include <wtf/WeakPtr.h>
 
 namespace JSC {
 class JSGlobalObject;
@@ -43,7 +45,8 @@
 class SimpleReadableStreamSource;
 class WritableStream;
 
-class RTCRtpSFrameTransform : public RefCounted<RTCRtpSFrameTransform>, private ContextDestructionObserver {
+class RTCRtpSFrameTransform : public RefCounted<RTCRtpSFrameTransform>, public ActiveDOMObject, public EventTargetWithInlineData {
+    WTF_MAKE_ISO_ALLOCATED(RTCRtpSFrameTransform);
 public:
     enum class Role { Encrypt, Decrypt };
     using CompatibilityMode = RTCRtpSFrameTransformer::CompatibilityMode;
@@ -70,14 +73,30 @@
     ExceptionOr<RefPtr<ReadableStream>> readable();
     ExceptionOr<RefPtr<WritableStream>> writable();
 
+    bool hasKey(uint64_t) const;
+
+    using RefCounted<RTCRtpSFrameTransform>::ref;
+    using RefCounted<RTCRtpSFrameTransform>::deref;
+
 private:
     RTCRtpSFrameTransform(ScriptExecutionContext&, Options);
 
+    // ActiveDOMObject
+    const char* activeDOMObjectName() const final { return "RTCRtpSFrameTransform"; }
+    bool virtualHasPendingActivity() const final;
+
+    // EventTargetWithInlineData
+    EventTargetInterface eventTargetInterface() const final { return RTCRtpSFrameTransformEventTargetInterfaceType; }
+    ScriptExecutionContext* scriptExecutionContext() const final { return ContextDestructionObserver::scriptExecutionContext(); }
+    void refEventTarget() final { ref(); }
+    void derefEventTarget() final { deref(); }
+
     enum class Side { Sender, Receiver };
     void initializeTransformer(RTCRtpTransformBackend&, Side);
     void createStreams(JSC::JSGlobalObject&);
 
     bool m_isAttached { false };
+    bool m_hasWritable { false };
     Ref<RTCRtpSFrameTransformer> m_transformer;
     RefPtr<ReadableStream> m_readable;
     RefPtr<WritableStream> m_writable;

Modified: trunk/Source/WebCore/Modules/mediastream/RTCRtpSFrameTransform.idl (280957 => 280958)


--- trunk/Source/WebCore/Modules/mediastream/RTCRtpSFrameTransform.idl	2021-08-12 04:35:22 UTC (rev 280957)
+++ trunk/Source/WebCore/Modules/mediastream/RTCRtpSFrameTransform.idl	2021-08-12 09:37:05 UTC (rev 280958)
@@ -41,6 +41,7 @@
 };
 
 [
+    ActiveDOMObject,
     Conditional=WEB_RTC,
     EnabledBySetting=WebRTCInsertableStreams,
     ExportMacro=WEBCORE_EXPORT,
@@ -47,7 +48,7 @@
     Exposed=(Window,DedicatedWorker),
     InterfaceName=SFrameTransform,
     JSGenerateToNativeObject,
-] interface RTCRtpSFrameTransform {
+] interface RTCRtpSFrameTransform : EventTarget {
     [CallWith=ScriptExecutionContext] constructor(optional RTCRtpSFrameTransformOptions options);
 
     [Custom] Promise<undefined> setEncryptionKey(CryptoKey key, optional any keyID);
@@ -57,4 +58,6 @@
 
     readonly attribute ReadableStream readable;
     readonly attribute WritableStream writable;
+
+    attribute EventHandler onerror;
 };

Added: trunk/Source/WebCore/Modules/mediastream/RTCRtpSFrameTransformErrorEvent.cpp (0 => 280958)


--- trunk/Source/WebCore/Modules/mediastream/RTCRtpSFrameTransformErrorEvent.cpp	                        (rev 0)
+++ trunk/Source/WebCore/Modules/mediastream/RTCRtpSFrameTransformErrorEvent.cpp	2021-08-12 09:37:05 UTC (rev 280958)
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2021 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "RTCRtpSFrameTransformErrorEvent.h"
+
+#if ENABLE(WEB_RTC)
+
+#include "EventNames.h"
+#include <wtf/IsoMallocInlines.h>
+
+namespace WebCore {
+
+WTF_MAKE_ISO_ALLOCATED_IMPL(RTCRtpSFrameTransformErrorEvent);
+
+Ref<RTCRtpSFrameTransformErrorEvent> RTCRtpSFrameTransformErrorEvent::create(CanBubble canBubble, IsCancelable isCancelable, Type errorType)
+{
+    return adoptRef(*new RTCRtpSFrameTransformErrorEvent(eventNames().errorEvent, canBubble, isCancelable, errorType));
+}
+
+Ref<RTCRtpSFrameTransformErrorEvent> RTCRtpSFrameTransformErrorEvent::create(const AtomString& type, Init&& init)
+{
+    return adoptRef(*new RTCRtpSFrameTransformErrorEvent(type, init.bubbles ? CanBubble::Yes : CanBubble::No,
+        init.cancelable ? IsCancelable::Yes : IsCancelable::No, init.errorType));
+}
+
+RTCRtpSFrameTransformErrorEvent::RTCRtpSFrameTransformErrorEvent(const AtomString& type, CanBubble canBubble, IsCancelable cancelable, Type errorType)
+    : Event(type, canBubble, cancelable)
+    , m_errorType(errorType)
+{
+}
+
+RTCRtpSFrameTransformErrorEvent::~RTCRtpSFrameTransformErrorEvent() = default;
+
+EventInterface RTCRtpSFrameTransformErrorEvent::eventInterface() const
+{
+    return RTCRtpSFrameTransformErrorEventInterfaceType;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_RTC)

Copied: trunk/Source/WebCore/Modules/mediastream/RTCRtpSFrameTransformErrorEvent.h (from rev 280957, trunk/Source/WebCore/Modules/mediastream/RTCRtpSFrameTransform.idl) (0 => 280958)


--- trunk/Source/WebCore/Modules/mediastream/RTCRtpSFrameTransformErrorEvent.h	                        (rev 0)
+++ trunk/Source/WebCore/Modules/mediastream/RTCRtpSFrameTransformErrorEvent.h	2021-08-12 09:37:05 UTC (rev 280958)
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2021 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(WEB_RTC)
+
+#include "Event.h"
+
+namespace WebCore {
+
+class RTCRtpSFrameTransformErrorEvent final : public Event {
+    WTF_MAKE_ISO_ALLOCATED(RTCRtpSFrameTransformErrorEvent);
+public:
+    virtual ~RTCRtpSFrameTransformErrorEvent();
+
+    enum Type { Authentication, KeyID, Other, Syntax };
+
+    struct Init : EventInit {
+        Type errorType;
+    };
+
+    static Ref<RTCRtpSFrameTransformErrorEvent> create(const AtomString& type, Init&&);
+    static Ref<RTCRtpSFrameTransformErrorEvent> create(CanBubble, IsCancelable, Type);
+
+    Type errorType() const { return m_errorType; }
+
+    virtual EventInterface eventInterface() const;
+
+private:
+    RTCRtpSFrameTransformErrorEvent(const AtomString& type, CanBubble, IsCancelable, Type);
+
+    Type m_errorType;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_RTC)

Copied: trunk/Source/WebCore/Modules/mediastream/RTCRtpSFrameTransformErrorEvent.idl (from rev 280957, trunk/Source/WebCore/Modules/mediastream/RTCRtpSFrameTransform.idl) (0 => 280958)


--- trunk/Source/WebCore/Modules/mediastream/RTCRtpSFrameTransformErrorEvent.idl	                        (rev 0)
+++ trunk/Source/WebCore/Modules/mediastream/RTCRtpSFrameTransformErrorEvent.idl	2021-08-12 09:37:05 UTC (rev 280958)
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2021 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+enum RTCRtpSFrameTransformErrorEventType {
+    "authentication",
+    "keyID",
+    "other",
+    "syntax"
+};
+
+dictionary RTCRtpSFrameTransformErrorEventInit : EventInit {
+    required RTCRtpSFrameTransformErrorEventType errorType;
+};
+
+[
+    Conditional=WEB_RTC,
+    EnabledBySetting=WebRTCInsertableStreams,
+    Exposed=(Window,DedicatedWorker),
+    InterfaceName=SFrameTransformErrorEvent
+] interface RTCRtpSFrameTransformErrorEvent : Event {
+    constructor(DOMString type, RTCRtpSFrameTransformErrorEventInit eventInitDict);
+
+    readonly attribute RTCRtpSFrameTransformErrorEventType errorType;
+    // FIXME: Add below fields
+    // readonly attribute CryptoKeyID? keyID;
+    // readonly attribute any frame;
+};

Modified: trunk/Source/WebCore/Modules/mediastream/RTCRtpSFrameTransformer.cpp (280957 => 280958)


--- trunk/Source/WebCore/Modules/mediastream/RTCRtpSFrameTransformer.cpp	2021-08-12 04:35:22 UTC (rev 280957)
+++ trunk/Source/WebCore/Modules/mediastream/RTCRtpSFrameTransformer.cpp	2021-08-12 09:37:05 UTC (rev 280958)
@@ -29,6 +29,7 @@
 #if ENABLE(WEB_RTC)
 
 #include "SFrameUtils.h"
+#include <wtf/Algorithms.h>
 
 namespace WebCore {
 
@@ -160,6 +161,12 @@
     return updateEncryptionKey(rawKey, keyId, ShouldUpdateKeys::Yes);
 }
 
+bool RTCRtpSFrameTransformer::hasKey(uint64_t keyId) const
+{
+    Locker locker { m_keyLock };
+    return WTF::anyOf(m_keys, [keyId](auto& key) { return keyId == key.keyId; });
+}
+
 ExceptionOr<void> RTCRtpSFrameTransformer::updateEncryptionKey(const Vector<uint8_t>& rawKey, std::optional<uint64_t> keyId, ShouldUpdateKeys shouldUpdateKeys)
 {
     ASSERT(m_keyLock.isLocked());
@@ -199,7 +206,7 @@
     return { };
 }
 
-ExceptionOr<Vector<uint8_t>> RTCRtpSFrameTransformer::decryptFrame(const uint8_t* frameData, size_t frameSize)
+RTCRtpSFrameTransformer::TransformResult RTCRtpSFrameTransformer::decryptFrame(const uint8_t* frameData, size_t frameSize)
 {
     Vector<uint8_t> buffer;
     switch (m_compatibilityMode) {
@@ -229,23 +236,23 @@
     auto header = parseSFrameHeader(frameData, frameSize);
 
     if (!header)
-        return Exception { NotSupportedError };
+        return makeUnexpected(ErrorInformation {Error::Syntax, "Invalid header"_s, 0 });
 
     if (header->counter <= m_counter && m_counter)
-        return Exception { InvalidStateError };
+        return makeUnexpected(ErrorInformation {Error::Syntax, "Invalid counter"_s, 0 });
     m_counter = header->counter;
 
     if (header->keyId != m_keyId) {
         auto position = m_keys.findMatching([keyId = header->keyId](auto& item) { return item.keyId == keyId; });
         if (position == notFound)
-            return Exception { DataError, "Key ID is unknown" };
+            return makeUnexpected(ErrorInformation { Error::KeyID,  "Key ID is unknown"_s, header->keyId });
         auto result = updateEncryptionKey(m_keys[position].keyData, header->keyId, ShouldUpdateKeys::No);
         if (result.hasException())
-            return result.releaseException();
+            return makeUnexpected(ErrorInformation {Error::Other, result.exception().message(), 0 });
     }
 
     if (frameSize < (header->size + m_authenticationSize))
-        return Exception { DataError, "Chunk is too small for authentication size" };
+        return makeUnexpected(ErrorInformation { Error::Syntax, "Chunk is too small for authentication size"_s, 0 });
 
     auto iv = computeIV(m_counter, m_saltKey);
 
@@ -255,7 +262,7 @@
     for (size_t cptr = 0; cptr < m_authenticationSize; ++cptr) {
         if (signature[cptr] != transmittedSignature[cptr]) {
             // FIXME: We should try ratcheting.
-            return Exception { NotSupportedError };
+            return makeUnexpected(ErrorInformation { Error::Authentication, "Authentication failed"_s, 0 });
         }
     }
 
@@ -264,12 +271,12 @@
     auto result = decryptData(frameData + header->size, dataSize, iv, m_encryptionKey);
 
     if (result.hasException())
-        return result.releaseException();
+        return makeUnexpected(ErrorInformation { Error::Other, result.exception().message(), 0 });
 
     return result.releaseReturnValue();
 }
 
-ExceptionOr<Vector<uint8_t>> RTCRtpSFrameTransformer::encryptFrame(const uint8_t* frameData, size_t frameSize)
+RTCRtpSFrameTransformer::TransformResult RTCRtpSFrameTransformer::encryptFrame(const uint8_t* frameData, size_t frameSize)
 {
     static const unsigned MaxHeaderSize = 17;
 
@@ -314,7 +321,7 @@
     auto encryptedData = encryptData(frameData, frameSize, iv, m_encryptionKey);
     ASSERT(!encryptedData.hasException());
     if (encryptedData.hasException())
-        return encryptedData.releaseException();
+        return makeUnexpected(ErrorInformation { Error::Other, encryptedData.exception().message(), 0 });
 
     std::memcpy(newDataPointer + headerSize, encryptedData.returnValue().data(), frameSize);
 
@@ -330,10 +337,10 @@
     return transformedData;
 }
 
-ExceptionOr<Vector<uint8_t>> RTCRtpSFrameTransformer::transform(const uint8_t* data, size_t size)
+RTCRtpSFrameTransformer::TransformResult RTCRtpSFrameTransformer::transform(const uint8_t* data, size_t size)
 {
     if (!m_hasKey)
-        return Exception { InvalidStateError, "Key is not initialized"_s };
+        return makeUnexpected(ErrorInformation { Error::KeyID,  "Key is not initialized", 0 });
 
     return m_isEncrypting ? encryptFrame(data, size) : decryptFrame(data, size);
 }

Modified: trunk/Source/WebCore/Modules/mediastream/RTCRtpSFrameTransformer.h (280957 => 280958)


--- trunk/Source/WebCore/Modules/mediastream/RTCRtpSFrameTransformer.h	2021-08-12 04:35:22 UTC (rev 280957)
+++ trunk/Source/WebCore/Modules/mediastream/RTCRtpSFrameTransformer.h	2021-08-12 09:37:05 UTC (rev 280958)
@@ -48,8 +48,16 @@
     void setMediaType(RTCRtpTransformBackend::MediaType);
 
     WEBCORE_EXPORT ExceptionOr<void> setEncryptionKey(const Vector<uint8_t>& rawKey, std::optional<uint64_t>);
-    WEBCORE_EXPORT ExceptionOr<Vector<uint8_t>> transform(const uint8_t*, size_t);
 
+    enum class Error { KeyID, Authentication, Syntax, Other };
+    struct ErrorInformation {
+        Error error;
+        String message;
+        uint64_t keyId { 0 };
+    };
+    using TransformResult = Expected<Vector<uint8_t>, ErrorInformation>;
+    WEBCORE_EXPORT TransformResult transform(const uint8_t*, size_t);
+
     const Vector<uint8_t>& authenticationKey() const { return m_authenticationKey; }
     const Vector<uint8_t>& encryptionKey() const { return m_encryptionKey; }
     const Vector<uint8_t>& saltKey() const { return m_saltKey; }
@@ -58,11 +66,13 @@
     uint64_t counter() const { return m_counter; }
     void setCounter(uint64_t counter) { m_counter = counter; }
 
+    bool hasKey(uint64_t) const;
+
 private:
     WEBCORE_EXPORT explicit RTCRtpSFrameTransformer(CompatibilityMode);
 
-    ExceptionOr<Vector<uint8_t>> decryptFrame(const uint8_t*, size_t);
-    ExceptionOr<Vector<uint8_t>> encryptFrame(const uint8_t*, size_t);
+    TransformResult decryptFrame(const uint8_t*, size_t);
+    TransformResult encryptFrame(const uint8_t*, size_t);
 
     enum class ShouldUpdateKeys { No, Yes };
     ExceptionOr<void> updateEncryptionKey(const Vector<uint8_t>& rawKey, std::optional<uint64_t>, ShouldUpdateKeys = ShouldUpdateKeys::Yes) WTF_REQUIRES_LOCK(m_keyLock);
@@ -76,7 +86,7 @@
     Vector<uint8_t> computeEncryptedDataSignature(const Vector<uint8_t>& nonce, const uint8_t* header, size_t headerSize, const uint8_t* data, size_t dataSize, const Vector<uint8_t>& key);
     void updateAuthenticationSize();
 
-    Lock m_keyLock;
+    mutable Lock m_keyLock;
     bool m_hasKey { false };
     Vector<uint8_t> m_authenticationKey;
     Vector<uint8_t> m_encryptionKey;

Modified: trunk/Source/WebCore/Sources.txt (280957 => 280958)


--- trunk/Source/WebCore/Sources.txt	2021-08-12 04:35:22 UTC (rev 280957)
+++ trunk/Source/WebCore/Sources.txt	2021-08-12 09:37:05 UTC (rev 280958)
@@ -171,6 +171,7 @@
 Modules/mediastream/RTCPeerConnectionIceErrorEvent.cpp
 Modules/mediastream/RTCRtpReceiver.cpp
 Modules/mediastream/RTCRtpSFrameTransform.cpp
+Modules/mediastream/RTCRtpSFrameTransformErrorEvent.cpp
 Modules/mediastream/RTCRtpSFrameTransformer.cpp
 Modules/mediastream/RTCRtpScriptTransform.cpp
 Modules/mediastream/RTCRtpScriptTransformer.cpp
@@ -3326,6 +3327,7 @@
 JSRTCRtpReceiver.cpp
 JSRTCRtpRtxParameters.cpp
 JSRTCRtpSFrameTransform.cpp
+JSRTCRtpSFrameTransformErrorEvent.cpp
 JSRTCRtpScriptTransform.cpp
 JSRTCRtpScriptTransformer.cpp
 JSRTCRtpSendParameters.cpp

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (280957 => 280958)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2021-08-12 04:35:22 UTC (rev 280957)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2021-08-12 09:37:05 UTC (rev 280958)
@@ -7986,6 +7986,9 @@
 		41B2A6251EF1BF60002B9D7A /* WebAudioSourceProvider.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebAudioSourceProvider.h; sourceTree = "<group>"; };
 		41B459DA1F4CADB90000F6FD /* ReadableStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReadableStream.h; sourceTree = "<group>"; };
 		41B459ED1F55EBC70000F6FD /* ReadableStream.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ReadableStream.cpp; sourceTree = "<group>"; };
+		41B6AA4F26B995F800AADFA7 /* RTCRtpSFrameTransformErrorEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RTCRtpSFrameTransformErrorEvent.h; sourceTree = "<group>"; };
+		41B6AA5126B995F800AADFA7 /* RTCRtpSFrameTransformErrorEvent.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = RTCRtpSFrameTransformErrorEvent.idl; sourceTree = "<group>"; };
+		41B6AA5226B995F900AADFA7 /* RTCRtpSFrameTransformErrorEvent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RTCRtpSFrameTransformErrorEvent.cpp; sourceTree = "<group>"; };
 		41B8776023DE1042003638B8 /* RealtimeMediaSourceIdentifier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RealtimeMediaSourceIdentifier.h; sourceTree = "<group>"; };
 		41B9137623584D0E0025BFA3 /* MockAudioDestinationCocoa.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MockAudioDestinationCocoa.h; sourceTree = "<group>"; };
 		41B9137823584D0F0025BFA3 /* MockAudioDestinationCocoa.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MockAudioDestinationCocoa.cpp; sourceTree = "<group>"; };
@@ -17241,6 +17244,9 @@
 				4181C641255B4C2600AEB0FF /* RTCRtpSFrameTransformer.cpp */,
 				4181C642255B4C2600AEB0FF /* RTCRtpSFrameTransformer.h */,
 				4181C63F255B4C2500AEB0FF /* RTCRtpSFrameTransformerCocoa.cpp */,
+				41B6AA5226B995F900AADFA7 /* RTCRtpSFrameTransformErrorEvent.cpp */,
+				41B6AA4F26B995F800AADFA7 /* RTCRtpSFrameTransformErrorEvent.h */,
+				41B6AA5126B995F800AADFA7 /* RTCRtpSFrameTransformErrorEvent.idl */,
 				415E1BB62150152A0022DA96 /* RTCRtpSynchronizationSource.h */,
 				415E1BB7215015300022DA96 /* RTCRtpSynchronizationSource.idl */,
 				5E5E2B101CFC3E4B000C0D85 /* RTCRtpTransceiver.cpp */,

Modified: trunk/Source/WebCore/bindings/js/WebCoreBuiltinNames.h (280957 => 280958)


--- trunk/Source/WebCore/bindings/js/WebCoreBuiltinNames.h	2021-08-12 04:35:22 UTC (rev 280957)
+++ trunk/Source/WebCore/bindings/js/WebCoreBuiltinNames.h	2021-08-12 09:37:05 UTC (rev 280958)
@@ -219,6 +219,7 @@
     macro(Request) \
     macro(Response) \
     macro(SFrameTransform) \
+    macro(SFrameTransformErrorEvent) \
     macro(ScreenLuminance) \
     macro(ServiceWorker) \
     macro(ServiceWorkerContainer) \

Modified: trunk/Source/WebCore/dom/EventNames.in (280957 => 280958)


--- trunk/Source/WebCore/dom/EventNames.in	2021-08-12 04:35:22 UTC (rev 280957)
+++ trunk/Source/WebCore/dom/EventNames.in	2021-08-12 09:37:05 UTC (rev 280958)
@@ -64,6 +64,7 @@
 RTCPeerConnectionIceEvent conditional=WEB_RTC
 RTCDataChannelEvent conditional=WEB_RTC
 RTCDTMFToneChangeEvent conditional=WEB_RTC
+RTCRtpSFrameTransformErrorEvent conditional=WEB_RTC
 RTCTrackEvent conditional=WEB_RTC
 RTCTransformEvent conditional=WEB_RTC
 SpeechRecognitionErrorEvent

Modified: trunk/Source/WebCore/dom/EventTargetFactory.in (280957 => 280958)


--- trunk/Source/WebCore/dom/EventTargetFactory.in	2021-08-12 04:35:22 UTC (rev 280957)
+++ trunk/Source/WebCore/dom/EventTargetFactory.in	2021-08-12 09:37:05 UTC (rev 280958)
@@ -40,6 +40,7 @@
 RTCDataChannel conditional=WEB_RTC
 RTCDTMFSender conditional=WEB_RTC
 RTCPeerConnection conditional=WEB_RTC
+RTCRtpSFrameTransform conditional=WEB_RTC
 RTCRtpScriptTransform conditional=WEB_RTC
 ServiceWorker conditional=SERVICE_WORKER
 ServiceWorkerContainer conditional=SERVICE_WORKER

Modified: trunk/Tools/ChangeLog (280957 => 280958)


--- trunk/Tools/ChangeLog	2021-08-12 04:35:22 UTC (rev 280957)
+++ trunk/Tools/ChangeLog	2021-08-12 09:37:05 UTC (rev 280958)
@@ -1,3 +1,13 @@
+2021-08-12  Youenn Fablet  <[email protected]>
+
+        Implement SFrameTransform error handling
+        https://bugs.webkit.org/show_bug.cgi?id=228947
+
+        Reviewed by Eric Carlson.
+
+        * TestWebKitAPI/Tests/WebCore/RTCRtpSFrameTransformerTests.cpp:
+        (TestWebKitAPI::TEST):
+
 2021-08-11  Peng Liu  <[email protected]>
 
         [ BigSur Debug ] TestWebKitAPI.GPUProcess.CrashWhilePlayingAudioViaCreateMediaElementSource is flaky, hitting ASSERTION FAILED: !isInRoutingArbitrationForToken(token)

Modified: trunk/Tools/TestWebKitAPI/Tests/WebCore/RTCRtpSFrameTransformerTests.cpp (280957 => 280958)


--- trunk/Tools/TestWebKitAPI/Tests/WebCore/RTCRtpSFrameTransformerTests.cpp	2021-08-12 04:35:22 UTC (rev 280957)
+++ trunk/Tools/TestWebKitAPI/Tests/WebCore/RTCRtpSFrameTransformerTests.cpp	2021-08-12 09:37:05 UTC (rev 280958)
@@ -200,13 +200,13 @@
     auto frame = Vector<uint8_t>::from(135, 89, 51, 166, 248, 129, 157, 111, 190, 134, 220);
 
     auto encryptedResult = encryptor->transform(frame.data(), frame.size());
-    EXPECT_FALSE(encryptedResult.hasException());
+    EXPECT_TRUE(encryptedResult.has_value());
 
-    auto encrypted = encryptedResult.releaseReturnValue();
+    auto encrypted = WTFMove(encryptedResult.value());
     auto decryptedResult = decryptor->transform(encrypted.data(), encrypted.size());
-    EXPECT_FALSE(decryptedResult.hasException());
+    EXPECT_TRUE(decryptedResult.has_value());
 
-    checkVectorsAreEqual(decryptedResult.returnValue(), frame);
+    checkVectorsAreEqual(decryptedResult.value(), frame);
 }
 
 TEST(RTCRtpSFrameTransformer, EncryptDecryptKeyID0)
@@ -220,13 +220,13 @@
     auto frame = Vector<uint8_t>::from(135, 89, 51, 166, 248, 129, 157, 111, 190, 134, 220);
 
     auto encryptedResult = encryptor->transform(frame.data(), frame.size());
-    EXPECT_FALSE(encryptedResult.hasException());
+    EXPECT_TRUE(encryptedResult.has_value());
 
-    auto encrypted = encryptedResult.releaseReturnValue();
+    auto encrypted = WTFMove(encryptedResult.value());
     auto decryptedResult = decryptor->transform(encrypted.data(), encrypted.size());
-    EXPECT_FALSE(decryptedResult.hasException());
+    EXPECT_TRUE(decryptedResult.has_value());
 
-    checkVectorsAreEqual(decryptedResult.returnValue(), frame);
+    checkVectorsAreEqual(decryptedResult.value(), frame);
 }
 
 TEST(RTCRtpSFrameTransformer, EncryptDecryptAudio)
@@ -242,13 +242,13 @@
     auto frame = Vector<uint8_t>::from(135, 89, 51, 166, 248, 129, 157, 111, 190, 134, 220, 56);
 
     auto encryptedResult = encryptor->transform(frame.data(), frame.size());
-    EXPECT_FALSE(encryptedResult.hasException());
+    EXPECT_TRUE(encryptedResult.has_value());
 
-    auto encrypted = encryptedResult.releaseReturnValue();
+    auto encrypted = WTFMove(encryptedResult.value());
     auto decryptedResult = decryptor->transform(encrypted.data(), encrypted.size());
-    EXPECT_FALSE(decryptedResult.hasException());
+    EXPECT_TRUE(decryptedResult.has_value());
 
-    checkVectorsAreEqual(decryptedResult.returnValue(), frame);
+    checkVectorsAreEqual(decryptedResult.value(), frame);
 }
 
 TEST(RTCRtpSFrameTransformer, TransformCounter0)
@@ -257,9 +257,9 @@
 
     uint8_t frame1[] = { 135, 89, 51, 166, 248, 129, 157, 111, 190, 134, 220 };
     auto result = transformer->transform(frame1, sizeof(frame1));
-    EXPECT_FALSE(result.hasException());
+    EXPECT_TRUE(result.has_value());
 
-    checkVectorsAreEqual(result.releaseReturnValue(), Vector<uint8_t>::from(
+    checkVectorsAreEqual(result.value(), Vector<uint8_t>::from(
         15,
         198,
         31,
@@ -299,14 +299,14 @@
     auto transformer = createVideoTransformer();
 
     uint8_t frame1[] = { 8, 164, 189, 18, 61, 117, 132, 43, 117, 169, 42 };
-    WebCore::ExceptionOr<Vector<uint8_t>> result = Vector<uint8_t>();
-    result = transformer->transform(frame1, sizeof(frame1));
+    auto result = transformer->transform(frame1, sizeof(frame1));
+    EXPECT_TRUE(result.has_value());
     for (size_t cptr = 0; cptr < 256; ++cptr) {
         result = transformer->transform(frame1, sizeof(frame1));
-        EXPECT_FALSE(result.hasException());
+        EXPECT_TRUE(result.has_value());
     }
 
-    checkVectorsAreEqual(result.releaseReturnValue(), Vector<uint8_t>::from(
+    checkVectorsAreEqual(result.value(), Vector<uint8_t>::from(
         31,
         198,
         31,
@@ -349,9 +349,9 @@
 
     uint8_t frame1[] = { 0, 33, 244, 24, 236, 156, 127, 8, 48, 88, 220 };
     auto result = transformer->transform(frame1, sizeof(frame1));
-    EXPECT_FALSE(result.hasException());
+    EXPECT_TRUE(result.has_value());
 
-    checkVectorsAreEqual(result.releaseReturnValue(), Vector<uint8_t>::from(
+    checkVectorsAreEqual(result.value(), Vector<uint8_t>::from(
         47,
         198,
         31,
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to