Skip to content

Commit 6226b9a

Browse files
committed
Add SFrame packetization handling for SFrameTransform
Introduce RTCRtpScriptTransformType with "sframe" value.
1 parent 73c5464 commit 6226b9a

File tree

1 file changed

+64
-12
lines changed

1 file changed

+64
-12
lines changed

index.bs

Lines changed: 64 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ spec:webidl; type:dfn; text:resolve
5959
<pre class=link-defaults>
6060
spec:streams; type:interface; text:ReadableStream
6161
</pre>
62+
<pre class=anchors>
63+
url: https://w3c.github.io/webrtc-pc/#dfn-update-the-negotiation-needed-flag; text: update the negotiation-needed flag; type: dfn; spec: WEBRTC
64+
</pre>
6265

6366
# Introduction # {#introduction}
6467

@@ -138,6 +141,7 @@ The <dfn abstract-op>readEncodedData</dfn> algorithm is given a |rtcObject| as p
138141
1. Increment |rtcObject|.`[[lastEnqueuedFrameCounter]]` by <code>1</code>.
139142
1. Let |frame| be the newly produced frame.
140143
1. Set |frame|.`[[owner]]` to |rtcObject|.
144+
1. Set |this|.`[[writable]]` to |this|.`[[transform]]`.`[[writable]]`.
141145
1. Set |frame|.`[[counter]]` to |rtcObject|.`[[lastEnqueuedFrameCounter]]`.
142146
1. If the frame has been produced by a {{RTCRtpReceiver}}:
143147
1. If the relevant RTP packet contains the
@@ -150,6 +154,7 @@ The <dfn abstract-op>readEncodedData</dfn> algorithm is given a |rtcObject| as p
150154
[[RTP-EXT-CAPTURE-TIME#timestamp-interpolation|timestamp interpolation]] and set |frame|.`[[senderCaptureTimeOffset]]`
151155
to the most recent value that was present.
152156
1. Otherwise, set |frame|.`[[captureTime]]` to undefined and set |frame|.`[[senderCaptureTimeOffset]]` to undefined.
157+
1. If |frame| was produced by a [=SFrame depacketizer=], set |frame|.`[[useSFrame]]` to true.
153158
1. If the frame has been produced by a {{RTCRtpSender}}, set |frame|.`[[captureTime]]` to the capture timestamp
154159
using the methodology described in [[RTP-EXT-CAPTURE-TIME#absolute-capture-timestamp]] and set frame.`[[senderCaptureTimeOffset]]`
155160
to undefined.
@@ -162,8 +167,10 @@ The <dfn abstract-op>writeEncodedData</dfn> algorithm is given a |rtcObject| as
162167
1. Let |data| be |frame|.`[[data]]`.
163168
1. Let |serializedFrame| be [$StructuredSerializeWithTransfer$](|frame|, « |data| »).
164169
1. Let |frameCopy| be [$StructuredDeserializeWithTransfer$](|serializedFrame|, |frame|'s [=relevant realm=]).
170+
1. If |frame|.`[[useSFrame]]` is true, set |frameCopy|.`[[useSFrame]]` to true.
165171
1. Enqueue |frameCopy| for processing as if it came directly from the encoded data source, by running one of the following steps:
166172
* If |rtcObject| is a {{RTCRtpSender}}, enqueue |frameCopy| to |rtcObject|'s packetizer, to be processed [=in parallel=].
173+
If |frameCopy|.`[[useSFrame]]` is true, |rtcObject|'s MUST use a [=SFrame packetizer=] or skip processing of |frameCopy|.
167174
* If |rtcObject| is a {{RTCRtpReceiver}}, enqueue |frameCopy| it to |rtcObject|'s decoder, to be processed [=in parallel=].
168175
1. Return [=a promise resolved with=] undefined.
169176

@@ -181,6 +188,7 @@ A RTCRtpTransform has private slots:
181188
* `[[readable]]` of type {{ReadableStream}}.
182189
* `[[writable]]` of type {{WritableStream}}.
183190
* `[[owner]]` of type {{RTCRtpSender}} or {{RTCRtpReceiver}}, initialized to null.
191+
1. `[[useSFrame]]` of type boolean. // FIXME: Decide whether augmenting this boolean with either cipher suite support or whether doing frame vs. packet based encryption.
184192

185193
Each RTCRtpTransform has an <dfn abstract-op for=RTCRtpTransform>association steps</dfn> set, which is empty by default.
186194

@@ -199,6 +207,16 @@ The `transform` setter steps are:
199207
1. [=AbortSignal/Add=] the [$chain transform algorithm$] to [=this=].`[[pipeToController]]`'s [=AbortController/signal=].
200208
2. [=AbortController/signal abort=] on [=this=].`[[pipeToController]]`.
201209
1. Else, run the [$chain transform algorithm$] steps.
210+
1. If [=this=] is a {{RTCRtpSender}}, run the following substeps:
211+
1. Let |useSFrame| be true if [=this=] is configured to use a [=SFrame packetizer=] and false otherwise.
212+
1. If |useSFrame| is equal to |checkedTransform|.`[[useSFrame]]`, abort these substeps.
213+
1. Configure [=this=]'s packetizer to use SFrame if |checkedTransform|.`[[useSFrame]]` is true and to not use SFrame if |checkedTransform|.`[[useSFrame]]` is false.
214+
1. [=Update the negotiation-needed flag=] for [=this=]'s connection.
215+
1. Otherwise, run the following steps:
216+
1. Let |useSFrame| be true if [=this=] is configured to use a [=SFrame depacketizer=] and false otherwise.
217+
1. If |useSFrame| is equal to |checkedTransform|.`[[useSFrame]]`, abort these substeps.
218+
1. Configure [=this=]'s depacketizer to use SFrame if |checkedTransform|.`[[useSFrame]]` is true and to not use SFrame if |checkedTransform|.`[[useSFrame]]` is false.
219+
1. [=Update the negotiation-needed flag=] for [=this=]'s connection.
202220
1. Set [=this=].`[[pipeToController]]` to |newPipeToController|.
203221
1. Set [=this=].`[[transform]]` to |transform|.
204222
1. Run the steps in the set of [$association steps$] of |transform| with [=this=].
@@ -248,7 +266,8 @@ SFrameTransform includes GenericTransformStream;
248266
enum SFrameTransformErrorEventType {
249267
"authentication",
250268
"keyID",
251-
"syntax"
269+
"syntax",
270+
"packetization"
252271
};
253272

254273
[Exposed=(Window,DedicatedWorker)]
@@ -275,13 +294,19 @@ The <dfn constructor for="SFrameTransform" lt="SFrameTransform(options)"><code>n
275294
5. Set |this|.`[[role]]` to |options|["{{SFrameTransformOptions/role}}"].
276295
6. Set |this|.`[[readable]]` to |this|.`[[transform]]`.`[[readable]]`.
277296
7. Set |this|.`[[writable]]` to |this|.`[[transform]]`.`[[writable]]`.
297+
7. Set |this|.`[[useSFrame]]` to true.
278298

279299
## Algorithm ## {#sframe-transform-algorithm}
280300

281301
The SFrame transform algorithm, given |sframe| as a SFrameTransform object and |frame|, runs these steps:
282302
1. Let |role| be |sframe|.`[[role]]`.
283-
1. If |frame|.`[[owner]]` is a {{RTCRtpSender}}, set |role| to 'encrypt'.
284-
1. If |frame|.`[[owner]]` is a {{RTCRtpReceiver}}, set |role| to 'decrypt'.
303+
1. If |sframe|.`[[owner]]` is a {{RTCRtpSender}}, set |role| to 'encrypt'.
304+
1. If |sframe|.`[[owner]]` is a {{RTCRtpReceiver}}, set |role| to 'decrypt'.
305+
1. If |sframe|.`[[owner]]` is a {{RTCRtpReceiver}} and |frame|.`[[useSFrame]]` is not true, [=queue a task=] to run the following steps:
306+
1. [=fire an event=] named {{SFrameTransform/onerror|error}} at |sframe|,
307+
using the {{SFrameTransformErrorEvent}} interface with its {{SFrameTransformErrorEvent/errorType}} attribute set to {{SFrameTransformErrorEventType/packetization}}
308+
and its {{SFrameTransformErrorEvent/frame}} attribute set to |frame|.
309+
1. Abort these steps.
285310
1. Let |data| be undefined.
286311
1. If |frame| is a {{BufferSource}}, set |data| to |frame|.
287312
1. If |frame| is a {{RTCEncodedAudioFrame}}, set |data| to |frame|.{{RTCEncodedAudioFrame/data}}
@@ -302,6 +327,7 @@ The SFrame transform algorithm, given |sframe| as a SFrameTransform object and |
302327
1. If |frame| is a {{BufferSource}}, set |frame| to |buffer|.
303328
1. If |frame| is a {{RTCEncodedAudioFrame}}, set |frame|.{{RTCEncodedAudioFrame/data}} to |buffer|.
304329
1. If |frame| is a {{RTCEncodedVideoFrame}}, set |frame|.{{RTCEncodedVideoFrame/data}} to |buffer|.
330+
1. Set |frame|.`[[useSFrame]]` to true.
305331
1. [=ReadableStream/Enqueue=] |frame| in |sframe|.`[[transform]]`.
306332

307333
## Methods ## {#sframe-transform-methods}
@@ -314,6 +340,27 @@ The <dfn method for="SFrameTransform">setEncryptionKey(|key|, |keyID|)</dfn> met
314340
3. [=Resolve=] |promise| with undefined.
315341
4. Return |promise|.
316342

343+
## SFrame packetization integration ## {#sframe-packetization}
344+
345+
A <dfn>SFrame packetizer</dfn> is responsible to generate SFrame packets from media content.
346+
In the context of this specification, the [=SFrame packetizer=] is not responsible for doing the actual encryption.
347+
Instead, the transform is responsible for doing so. The [=SFrame packetizer=] is responsible for splitting
348+
SFrame frames as needed so that they fit in RTP packets.
349+
350+
Similarly, a <dfn>SFrame depacketizer</dfn> is responsible to assemble RTP packets into a complete SFrame frame.
351+
It is not responsible for doing the actual decryption, the transform is responsible for doing so.
352+
353+
WebRTC encoded transform model is a per frame processing. SFrame can either be applied on each frame or on subframes.
354+
WebRTC encoded transform model is naturally aligned with aplying SFrame on a frame as a whole.
355+
To preserve WebRTC encoded transform model when applying SFrame on subframes, the following conceptual steps can be done:
356+
1. On sending side, the {{SFrameTransform}} may first split the media frame in subframes like would do a regular media packetizer,
357+
and apply the SFrame encryption on each subframe. It then concatenates the encrypted subframes as a unique encrypted frame.
358+
The transform provides the encrypted frame and information of each subframe so that the [=SFrame packetizer=]
359+
generates individual packets for each subframe.
360+
2. On receiving side, the [=SFrame depacketizer=] assembles all individual subframe RTP packets as a unique encrypted frame.
361+
It is responsible to give the necessary subframe information to the transform so that the transform can apply the SFrame decryption
362+
on each individual subframe contained in the unique encrypted frame and concatenate each decrypted subframe as a unique decrypted media frame.
363+
If decryption of a single subframe fails, the whole encrypted frame is discarded.
317364

318365
# RTCRtpScriptTransform # {#scriptTransform}
319366

@@ -881,9 +928,13 @@ interface RTCRtpScriptTransformer : EventTarget {
881928
readonly attribute any options;
882929
};
883930

931+
enum RTCRtpScriptTransformType {
932+
"sframe"
933+
};
934+
884935
[Exposed=Window]
885936
interface RTCRtpScriptTransform {
886-
constructor(Worker worker, optional any options, optional sequence&lt;object&gt; transfer);
937+
constructor(Worker worker, optional any options, optional sequence&lt;object&gt; transfer, optional RTCRtpScriptTransformType type);
887938
};
888939

889940
[Exposed=DedicatedWorker]
@@ -895,15 +946,16 @@ interface KeyFrameRequestEvent : Event {
895946

896947
## Operations ## {#RTCRtpScriptTransform-operations}
897948

898-
The <dfn constructor for="RTCRtpScriptTransform" lt="RTCRtpScriptTransform(worker, options)"><code>new RTCRtpScriptTransform(|worker|, |options|, |transfer|)</code></dfn> constructor steps are:
949+
The <dfn constructor for="RTCRtpScriptTransform" lt="RTCRtpScriptTransform(worker, options)"><code>new RTCRtpScriptTransform(|worker|, |options|, |transfer|, |type|)</code></dfn> constructor steps are:
899950
1. Set |t1| to an [=identity transform stream=].
900-
2. Set |t2| to an [=identity transform stream=].
901-
3. Set |this|.`[[writable]]` to |t1|.`[[writable]]`.
902-
4. Set |this|.`[[readable]]` to |t2|.`[[readable]]`.
903-
5. Let |serializedOptions| be the result of [$StructuredSerializeWithTransfer$](|options|, |transfer|).
904-
6. Let |serializedReadable| be the result of [$StructuredSerializeWithTransfer$](|t1|.`[[readable]]`, « |t1|.`[[readable]]` »).
905-
7. Let |serializedWritable| be the result of [$StructuredSerializeWithTransfer$](|t2|.`[[writable]]`, « |t2|.`[[writable]]` »).
906-
8. [=Queue a task=] on the DOM manipulation [=task source=] |worker|'s global scope to run the following steps:
951+
1. Set |t2| to an [=identity transform stream=].
952+
1. Set |this|.`[[writable]]` to |t1|.`[[writable]]`.
953+
1. Set |this|.`[[readable]]` to |t2|.`[[readable]]`.
954+
1. If |type| is equal to {{RTCRtpScriptTransformType/"sframe"}}, set |this|.`[[useSFrame]]` to true.
955+
1. Let |serializedOptions| be the result of [$StructuredSerializeWithTransfer$](|options|, |transfer|).
956+
1. Let |serializedReadable| be the result of [$StructuredSerializeWithTransfer$](|t1|.`[[readable]]`, « |t1|.`[[readable]]` »).
957+
1. Let |serializedWritable| be the result of [$StructuredSerializeWithTransfer$](|t2|.`[[writable]]`, « |t2|.`[[writable]]` »).
958+
1. [=Queue a task=] on the DOM manipulation [=task source=] |worker|'s global scope to run the following steps:
907959
1. Let |transformerOptions| be the result of [$StructuredDeserializeWithTransfer$](|serializedOptions|, the current Realm).
908960
2. Let |readable| be the result of [$StructuredDeserializeWithTransfer$](|serializedReadable|, the current Realm).
909961
3. Let |writable| be the result of [$StructuredDeserializeWithTransfer$](|serializedWritable|, the current Realm).

0 commit comments

Comments
 (0)