1 of 130

1

WebRTC

Chairs:

  • Jan-Ivar Bruaroey - Mozilla
  • Youenn Fablet - Apple
  • Guido Urdaneta - Google

Tuesday November 11, 2025

16:30 - 18:00 JST

TPAC 2025

Kobe Japan

Hybrid meeting

2 of 130

W3C WG IPR Policy

2

3 of 130

W3C meeting rules & etiquette

Meeting : 11 November 2025, 16:30–18:00 JST

This meeting is run under the W3C Code of Ethics and Professional Conduct. Please be respectful, inclusive, and kind.

IRC chat: https://irc.w3.org in channel #webrtc

Reminder to the chairs to ensure that the automated captions have been activated and press record.

3

4 of 130

About Today’s Meeting

  • TPAC 2025 Schedule
    • Tuesday November 11, 16:30-18:00 JST
    • Thursday November 13, 09:00-10:30 JST
    • Thursday November 13, 13:45-15:00 JST (Media WG Joint Meeting)�
  • Today’s Meeting info:
  • Link to slides has been published on WG wiki
  • Scribe? IRC http://irc.w3.org/ Channel: #webrtc
  • Volunteers for note taking?

4

5 of 130

Virtual Meeting Tips (Zoom)

  • We’ll try the Zoom speaker queue. If you’re in the room, please join muted.
  • To ask a question, please raise your hand in Zoom (button found under the React icon) before going to the mic. Keep the “hand raised” state active to maintain your place in the queue.
  • You can also join irc.w3.org channel #webrtc and use “+q” in irc to get into the speaker queue and “-q” to get out of the speaker queue.
  • The first time you speak, please state your name and affiliation.
  • Remotes participation:
    • Please use headphones when speaking to avoid echo.
    • Please wait for microphone access to be granted before speaking.
  • Click to lower your hand after speaking

5

6 of 130

For Discussion Today (Tuesday)

  • 16:35 - 16:55 State of the WG (Harald)
  • 16:55 - 17:20 Transport exploration
    • RTCTransport API - 10 minutes (Tony Herre)
    • WebTransport over WebRTC ICE? - 5 minutes (Jan-Ivar)
    • Discussion - 10 minutes
  • 17:20 - 17:35 Encoder Complexity API (Erik)
  • 17:35 - 17:55 PEPC (Marian Harbach)
  • 17:55 - 18:00 Wrap-up and Next Steps (Chairs)

Time control:

  • A warning will be given 2 minutes before time is up.
  • Once time has elapsed we will move on to the next item.

6

7 of 130

State of the WG

(Harald)

7

8 of 130

The Web Ecosystem Environment

  • The tussle between the open Web and “native” apps is ongoing
    • Web is competitive on the desktop
    • “Native” is near dominance on mobile
  • Power vs Security and Privacy
    • “Native” is unlimited on desktop, restricted on mobile
    • Web tries to add power - but delayed by security and privacy worries and standardization timelines.

9 of 130

External Environment

  • WebRTC over RTP is the dominant browser VC platform (and decent chunks of non-browser)
  • WebRTC over RTP is being used in many niche applications (ex WHIP for recording)
  • Explorations of other protocols (MOQ, WebCodecs over WebTransport) ongoing, have achieved some deployment traction (Zoom)
  • Interoperability is mostly “proprietary app on multiple browsers”
  • Still the same as in 2024

9

10 of 130

Activity since TPAC 2024

  • Repo activity
    • Mediacapture-main
      • Still not at REC
    • Mediacapture-extensions
      • Holding pen for new ideas
    • Webrtc-pc
      • Merging some things from -extensions (when implemented)
        • Rule for merge is “1 implementation and 1 promise”
    • Webrtc-extensions
      • Holding pen for new ideas
    • Webrtc-stats
      • Living Standard-like. Simplification and removal of Old Stuff
    • Webrtc-nv-use-cases
      • Little activity
    • Webrtc-Encoded-Transform
      • Significantly revised and implemented - SFrame activity

10

11 of 130

Implementation activity

  • Compatibility continues to improve
    • Typically >1900 of 2178 tests in webrtc pass
      • A year ago, approx 1700 of 2093 passed
    • Allowed moving stuff from -extensions to main
  • Lots of work to extend test coverage
    • A strict policy of “all changes must have tests” helps
  • Significant convergence on encoded-transform

11

12 of 130

Things that seem stable (and used)

  • Mediacapture-record
  • Mediacapture-fromelement
  • Mediacapture-image
  • Webtc-priority
    • (still no real implementation)
  • Mst-content-hint
  • WebRTC-SVC

12

13 of 130

Things that have stabilized

  • Screen capture
    • Many new features spec’ed, activity decreasing
  • Webrtc-ice
    • Principal investigator busy elsewhere
  • Platform processing for effects and faces
    • Project cancelled in Chrome after background blur
  • Custom Codecs
    • Implementation hit snags, priority reduced

14 of 130

Major new or expanded topics

  • Webrtc-encoded-transform
    • SFrame operation revised, cleanups
  • Congestion Control with L4S
    • Major spec change is stats for monitoring
  • Mediacapture-Transform
    • Disputes on aligning spec and shipping SW

14

15 of 130

The Transport Exploration

More low-level access to transport desired

  • MOQ (IETF) is an entirely new effort
    • Protocol still changing on a monthly basis
    • Builds on QUIC - no realtime CC or P2P yet
  • WebTransport is stable, seeing some use
    • But hasn’t solved congestion control or P2P
  • RtcTransport is a new exploration
    • Aims to preserve “realtime” properties
  • RTP over QUIC (datagrams)
    • Explored as specs, no adoption detected

16 of 130

Transport Exploration

(Tony and Jan-Ivar)

16

17 of 130

RtcTransport packet-level API

Discussion Group Update

(Tony)

17

18 of 130

RtcTransport - Status Update

  • Efforts during 2024
    • Pursuing a "piecemeal" (incremental) low-level RTP/RTCP functionality
    • A repository: https://github.com/w3c/webrtc-rtptransport

  • Changes since then
    • Difficulties designing & implementing such a large interface & combining built-in + web app control
    • Changed aim to ultimate use-case: low-level packet functionality (not RTP specific)
    • A prototype in Chromium Canary

18

19 of 130

RtcTransport - Targeted usecases

Basically same as before, but not RTP specific:

Allow Ultra-low latency media streaming over UDP, with strong app control

  • Custom Codecs/Data/Metadata/Packetization
  • Custom Reliability (FEC, NACK/RTX)
  • Custom Jitter Buffer
  • Custom Congestion Control (BWE, pacing, probing, bitrate allocation)
  • Custom Control/Feedback messages

19

20 of 130

RtcTransport - Examples of usecases

  • Send arbitrary data with the same congestion controller as audio and video
  • Do processing (face tracking) on video frames and attach metadata to frames
  • Use WebCodecs to get support for AAC
  • Use WebCodecs to get per-frame QP rate control
  • Use WebCodecs to get long-term reference frames
  • Implement an audio codec using WASM
  • Implement FEC designed for high-loss scenarios
  • Implement a jitter buffer more suitable to streaming applications
  • Forward packets from one endpoint to another
  • Implement a congestion control algorithm using L4S signals
  • Implement control messages like LRR, RSPI, SLI, RTCP-XR
  • ...

20

21 of 130

RtcTransport - What's been figured out

  • Overall direction
    • Browser does p2p encrypted packets
    • App does everything else (jitter buffers, packetization, SDP if they want it)
    • We'll have example impls of jitter buffers, packetization

  • Rough API shape
    • Send/receive packets (without RTP details)
    • Performance: no per-packet event loop scheduling + BYOB

  • UA enforces a congestion control Circuit Breaker
    • Must have a feedback format
    • Can be more lenient than how we expect app CC to behave
    • Shut down abusive behavior

21

22 of 130

RtcTransport - Things in progress

  • Exact details of API details
    • Especially regarding ICE controls

  • Exact details of Packet format
    • RTP or DTLS or QUIC or ???
    • ICE or not
    • Circuit Breaker Feedback (RTCP or QUIC or ???)

  • Exact details of Circuit Breaker

22

23 of 130

RtcTransport - Conclusion

  • A new direction
  • We're making good progress (again)
  • Still much work to do
  • Breakout session tomorrow

23

24 of 130

WebTransport over WebRTC ICE?

(Jan-Ivar)

24

25 of 130

WebTransport over WebRTC ICE? (Jan-Ivar)

WebTransport(url, options) solves server ↔ client head-of-line blocking, with browser CC and flow control. Its streams-based API + estimatedSendRate let apps fill send queues efficiently for maximum throughput on the network process.

What if we could leverage this API over WebRTC ICE? It might look like this:

const pc = new RTCPeerConnection();

const wt = pc.createWebTransport(options); // ← new idea

pc.onnegotiationneeded = () => { /* existing webrtc signaling */ };

pc.onicecandidate = () => { /* existing trickle ICE exchange */ };

await wt.ready; // WebTransport resolves promises instead of firing events

Benefit: web developers get the same (send/receive) WebTransport API surface, with nothing to relearn. It just skips the constructor (and fetch). Same semantics

25

26 of 130

WebTransport over WebRTC ICE (Jan-Ivar)

But importantly, such an API can likely be shimmed today on top of createDataChannel() and stats like availableOutgoingBitrate.�Data channels also have send queues and are subject to browser CC.

E.g. datagrams might be sent over unreliable/unordered data channels.�

How well this would perform is the question, but isn’t answered by API.

The point here is that starting with a new API to solve performance seems like a category mistake. It’s not pinpointing the performance bottlenecks.

Is it JS? Vendor CC? Why would vendors make different decisions per API?

26

27 of 130

Encoder Complexity API

(Erik)

27

28 of 130

Encoder Complexity API

Proposed change (https://github.com/w3c/webrtc-extensions/issues/191):

enum RTCEncodeComplexityMode {

"low",

"normal",

"high",

  • “high”, “max”, ...?

};

partial dictionary RTCRtpEncodingParameters {

RTCEncodeComplexityMode encodeComplexityMode = "normal";

};

28

29 of 130

Encoder Complexity API

The what:

  • Allow applications to make tradeoffs between CPU usage and quality
  • This is especially important with RTCDegradationPreference = maintain-framerate-and-resolution
    • A.k.a. “Bring your own adaptation”

29

Encoding 1

Encoding 2

GetStats()

setParameters()

Application

Encode Time

QP

Resolution

FPS

Complexity

30 of 130

Encoder Complexity API

Notable caveats:

  • Complexity is a best effort setting
    • Encoder implementation might not support it
  • Setting should be seen as an upper bound
    • System may choose to use a lower complexity if compute pressure is high
    • May also use a faster lower complexity due to quality heuristics

30

31 of 130

Encoder Complexity API

Raised objections

  • If this is to preserve battery, shouldn’t it be a global setting?
    • Using lower complexity when battery is low is certainly a use case.
    • Using higher complexity when bandwidth is constrained is another - might not affect streams equally.
  • Can we use RTCPriorityType instead?
    • Possibly, but that also maps to other aspects, such as bandwidth and QoS.

Ultimately, the application has the best knowledge of the properties of each stream and if power usage is important in this setting or not - and also how that affects remote quality and power usage => Let the application decide!

31

32 of 130

The <usermedia> element

Marian Harbach, Google Chrome

33 of 130

Using gUM and permissions - A balancing act

  • Gate site access to sensitive capabilities
  • Timing is controlled by the site
  • Users should not be overloaded
  • Show only prompts relevant to context and intention

User wants a prompt

User does not want a prompt

Prompt is shown

🤬

Prompt is not shown

😫

34 of 130

Solution avenues

  • Iterate on heuristics etc.
  • Get user attention on other UI surfaces
  • Change imperative API shapes
  • Trusted user signal:
    • How to tell what the user wants?

35 of 130

<usermedia> element

  • In-page HTML element
  • Mostly browser-controlled
  • Some limited styling and display options
  • Previously <permission>
  • A functional component of the site
  • Can be icon-only or with text

36 of 130

Guaranteeing the signal integrity

  • AKA prevent clickjacking
  • Two conditions to be met:
    • Make sure the text is visible and legible
    • Make sure this has been the case�for sufficient time

37 of 130

Real-life example usage

38 of 130

Links

39 of 130

Current discussion topics

  • Permission handling vs. stream handling
  • Mute/unmute functionality
    • Styling restrictions and badges
  • Element granularity: One vs. Three Elements

40 of 130

End of Tuesday Slides

40

41 of 130

Thursday Slides follow

41

42 of 130

42

WebRTC

Chairs:

  • Jan-Ivar Bruaroey - Mozilla
  • Youenn Fablet - Apple
  • Guido Urdaneta - Google

Thursday November 13, 2025

09:00 - 10:30 JST

TPAC 2025

Kobe Japan

Hybrid meeting

43 of 130

W3C WG IPR Policy

43

44 of 130

W3C meeting rules & etiquette

Meeting : 13 November 2025, 09:00–10:30 JST

This meeting is run under the W3C Code of Ethics and Professional Conduct. Please be respectful, inclusive, and kind.

IRC chat: https://irc.w3.org in channel #webrtc

44

45 of 130

About Today’s Meeting

  • TPAC 2025 Schedule
    • Tuesday November 11, 16:30-18:00 JST
    • Thursday November 13, 09:00-10:30 JST
    • Thursday November 13, 13:45-15:00 JST (Media WG Joint Meeting)�
  • Today’s Meeting info:
  • Link to slides has been published on WG wiki
  • Scribe? IRC http://irc.w3.org/ Channel: #webrtc
  • Volunteers for note taking?

45

46 of 130

Virtual Meeting Tips (Zoom)

  • We’ll try the Zoom speaker queue. If you’re in the room, please join muted.
  • To ask a question, please raise your hand in Zoom (button found under the React icon) before going to the mic. Keep the “hand raised” state active to maintain your place in the queue.
  • You can also join irc.w3.org channel #webrtc and use “+q” in irc to get into the speaker queue and “-q” to get out of the speaker queue.
  • The first time you speak, please state your name and affiliation.
  • Remotes participation:
    • Please use headphones when speaking to avoid echo.
    • Please wait for microphone access to be granted before speaking.
  • Click to lower your hand after speaking

46

47 of 130

For Discussion Today (Thursday)

Time control:

  • A warning will be given 2 minutes before time is up.
  • Once time has elapsed we will move on to the next item.

47

48 of 130

WebRTC Event Log uploads

with the Reporting API

(Guido)

48

49 of 130

WebRTC Event Logs

Diagnostic logs that can be generated by libwebrtc

  • RTP/RTCP Packets (no media)
  • ICE candidate pairs (metadata only, no addresses)
  • Bandwidth estimation events
  • Audio playout events
  • And more

No personally identifiable information or user-generated content

Significant overlap with stats, but structured for offline analysis

49

50 of 130

WebRTC Event Logs

Example use cases:

  • Debugging media quality
  • Network behavior analysis
  • Connectivity troubleshooting

Binary file format

  • Based on protocol buffers

Open-source tools available to analyze them

50

51 of 130

WebRTC Event Logs

Native applications can generate these logs using native APIs

In Chrome, the user can enable them locally via chrome://webrtc-internals

51

52 of 130

WebRTC Event Logs - Reporting API

We propose an API to allow collecting and uploading with the Reporting API

  • Provides standard mechanism for websites to receive reports out of band from the browser about various events
  • Existing examples:
    • Security policy violations
    • Use of deprecated APIs
    • Deprecated feature usage
    • Occurrence of crashes
  • The main spec defines the reporting framework and some report types
  • Other report types have their own spec

52

53 of 130

WebRTC Event Logs - Reporting API

Configuration via HTTP Headers

  • Reporting-Endpoints HTTP response header. This header maps endpoint names to URLs where the browser should send the reports

Reporting-Endpoints: main-endpoint="https://reports.example.com/main", default="https://reports.example.com/default"

  • Report-specific headers specify which endpoint to use

Content-Security-Policy: script-src 'self'; report-to main-endpoint;

  • The browser sends these reports out-of-band as HTTP POST requests with Content-Type: application/reports+json to the configured endpoint URL
  • Best effort

53

54 of 130

WebRTC Event Logs - Reporting API

Some report types also support the ReportingObserver JavaScript API

  • In this case, the report is delivered directly to the application
  • By default, report types are not visible to ReportingObservers
  • Since WebRTC event logs are intended for offline analysis and contain a lot of information, we propose to make them NOT visible to ReportingObservers
  • Large overlap with stats, which are more suitable for JS exposure

54

55 of 130

WebRTC Event Logs - Proposal

Define a report type for WebRTC Event logs

  • One report per RTCPeerConnection
  • Not visible to ReportingObservers

Challenge

  • WebRTC Event Logs have a binary format but Reports are JSON
  • Solution: Make the report contain a single field with a string that is the Base64 encoding of the event log binary format
    • Allows easy integration with existing open-source tools
    • Single definition
    • Easy implementation
  • Alternative: JSON mapping of binary format
    • More complex implementation and maintenance
    • Little benefit, since it is not visible to JavaScript

55

56 of 130

WebRTC Event Logs - Proposal

Applications do not always want to enable logging. Use a JS API to explicitly enable it:

partial interface RTCPeerConnection {

undefined startEventLogging(RTCEventLoggingOptions options);

undefined stopEventLogging();

undefined discardEventLogging();

}

dictionary RTCEventLoggingOptions {

bool upload = true;

}

56

57 of 130

WebRTC Event Logs - Authorization

Let the user decide if event logging is allowed for applications.

User agents can implement a number of strategies:

  • Allow it if an enterprise policy is enabled
  • Provide UI controls for the user
  • No integration with permission API seems necessary

Since the Reporting API is best effort by design , the proposed JS part does not return errors.

57

58 of 130

Discussion

58

59 of 130

SFrame

(Youenn)

59

60 of 130

SFrame status

SFrame draft presented at IETF 124

  • https://ietf-wg-avtcore.github.io/draft-ietf-avtcore-rtp-sframe/draft-ietf-avtcore-rtp-sframe.html
  • Overall approach seems fine
    • Simple SDP negotiation
    • SFrame payload descriptor
  • Feedback
    • Whether to expose per-packet vs. per-frame approach
      • Or whether SFrame is encrypting raw content or packetized content
      • Via SDP or in the stream (SFrame payload descriptor)
    • Current draft mainly focusing on what browsers are doing

60

61 of 130

SFrameTransform API (1/4)

Issues

  • per-packet /per-frame option
  • setEncryptionKey not well suited for receiver side
  • onerror not used for sender side
  • We introduced SFrameDecryptedStream/SFrameEncrypterStream

61

interface mixin SFrameKeyManagement {

Promise<undefined> setEncryptionKey(CryptoKey key, optional CryptoKeyID keyID);

attribute EventHandler onerror;

};

interface SFrameTransform : EventTarget {

constructor(optional SFrameTransformOptions options = {});

};

SFrameTransform includes SFrameKeyManagement;

62 of 130

SFrameTransform API (2/4)

Solution for per-packet/per-frame: introduce an enum!

enum SFrameType{

"per-frame",

"per-packet"

};

dictionary SFrameTransformOptions {

required SFrameType type;

required SFrameCipherSuite cipherSuite;

};

62

63 of 130

SFrameTransform API (3/4)

Solution for decrypter/encrypter: introduce more interfaces!

interface mixin SFrameEncrypterManagement {

Promise<CryptoKeyID> setEncryptionKey(CryptoKey key, optional CryptoKeyID keyID);

};�SFrameEncrypterStream includes SFrameEncrypterManagement;

�interface mixin SFrameDecrypterManagement {

Promise<undefined> addDecryptionKey(CryptoKey key, CryptoKeyID keyID);

Promise<undefined> removeDecryptionKey(CryptoKeyID keyID);

attribute EventHandler onerror;

};�SFrameDecrypterStream includes SFrameDecrypterManagement;

63

64 of 130

SFrameTransform API (4/4)

64

65 of 130

SFrame + RTCRtpScriptTransform (1/3)

What if I want to use both SFrame native support & RTCRtpScriptTransform?

  • Use SFrameDecrypterStream/SFrameEncrypterStream

onrtctransform = transformer => {

const decrypter = new SFrameDecryterStream();

transformer.readable

.pipeThrough(new TransformStream(myMetadataTransform))

.pipeThrough(decrypter)

.pipeTo(writable);

};

65

66 of 130

SFrame + RTCRtpScriptTransform (2/3)

What if I want to use per-packet SFrame with RTCRtpScriptTransform?

  • Need a way to tie transform and SFrameTransform object

// Expose SFrameReceiverTransform and SFrameSenderTransform to worker AND

partial interface RTCRtpScriptTransformer {

attribute (SFrameReceiverTransform or SFrameSenderTransform)? sframe;

};�

onrtctransform = transformer => {

transformer.sframe = new SFrameReceiverTransform({ type: ‘per-packet’, cipherSuite: …’})

transformer.readable

.pipeThrough(new TransformStream(myMetadataTransform))

.pipeTo(transformer.writable);

};

No request so far, just a proof of concept

66

67 of 130

SFrame + RTCRtpScriptTransform (3/3)

What if I want to do my own custom SFrame-in-JS scheme but per-packet?

  • Feasible by extending RTCEncodedAudioFrame & RTCEncodedVideoFrame API
    • Expose the raw-or-packetized bit (read-only)
    • Allow web app to tell UA the SFrame payload boundaries for a given frame data
  • SFrame per-packet or whatever granularity useful to the app

No request so far, just a proof of concept

67

68 of 130

Discussion

68

69 of 130

Encoded Source update

(Guido)

69

70 of 130

Encoded Source

Last year we presented a proposal for an encode source API for RTCRtpSender

Original use case: Peer-assisted media forwarding

70

Server

71 of 130

Encoded Source (RTCRtpSender)

Similar model to Encoded Transform

  • Single-side "transform" (no readable, only writable)
  • Good match for frame-centric SFU-like operations

More control signals, state and error handling

  • Bandwidth
  • Expected queue time
  • Dropped frames
  • Sync errors for incorrect frames
    • Timestamps in the past
    • Decreasing frame ID

71

72 of 130

Encoded Source (RTCRtpSender) - IDL

partial interface RTCRtpSender {

Promise<undefined> createEncodedSource(

Worker worker, optional any options, optional sequence<object> transfer);

}

partial interface DedicatedWorkerGlobalScope {

attribute EventHandler onrtcsenderencodedsource;

}

[Exposed=DedicatedWorker] interface RTCRtpSenderEncodedSourceEvent : Event {

readonly attribute RTCRtpSenderEncodedSource encodedSource;

};

72

73 of 130

Encoded Source (RTCRtpSender) - IDL

[Exposed=DedicatedWorker] interface RTCRtpSenderEncodedSource {

// Accepts RTCRtpEncoded{Video|Audio}Frame, rejects on incorrect frames

readonly attribute WritableStream writable;

attribute EventHandler onkeyframerequest;

attribute EventHandler onbandwidthestimate;

readonly attribute any options;

readonly attribute unsigned long long droppedFrames;

readonly attribute double expectedSendQueueTime; // milliseconds

readonly attribute long allocatedBitrate; // bits per second

readonly attribute long availableOutgoingBitrate;

};

73

74 of 130

Encoded Source - Status

No implementation or completed spec

  • Planning to fix this in 2026

We have identified two additional use cases:

  • Fan-in at the receiver in peer-assisted media delivery
  • Integration with external codecs (WebCodecs/WASM)

74

75 of 130

Encoded Source update - Receiver

In peer-assisted media delivery media flows through redundant paths

  • Receivers receive the same media from multiple paths
    • Each individual path can fail at any time
  • Media needs to be aggregated into a single track for local playback
    • Discard duplicate frames
    • Adjust metadata in case of failover
  • Option 1: WebCodecs/WASM + AudioWorklet/MediaSource/VideoTrackGenerator
    • Complex solution
    • Similar to replicating the internals of an RTCRtpReceiver
  • Option 2: Manually feed frames to an RTCRtpReceiver

75

76 of 130

Encoded Source update - Receiver

  • Receivers 1 and 2 provide the same media
  • Output receiver masks failures, no timeouts necessary. Single track for local rendering
  • There may be more than 2 input receivers, but only one output

76

RTCRtp

Receiver 1

RTCRtp

Receiver 2

Output

RTCRtp Receiver

P2P Node

Use Encoded Transform to read frames from input receivers

Custom processing to produce output frames (discard duplicates, adjust metadata)

Write to Output Receiver using

RTCRtpReceiverEncodedSource

To media element / web audio

77 of 130

Encoded Source update - Receiver

An encoded source for an RTCRtpReceiver is simpler than for an RTCRtpSender

  • Does not use the network
  • No need for bandwidth signals or network status
  • Keep the synchronous checks for invalid frames

77

78 of 130

Encoded Source update - Receiver IDL

partial interface RTCRtpReceiver {

Promise<undefined> createEncodedSource(

Worker worker, optional any options, optional sequence<object> transfer);

}

partial interface DedicatedWorkerGlobalScope {

attribute EventHandler onrtcreceiverencodedsource;

}

[Exposed=DedicatedWorker] interface RTCRtpReceiverEncodedSourceEvent : Event {

readonly attribute RTCRtpReceiverEncodedSource encodedSource;

};

[Exposed=DedicatedWorker] interface RTCRtpReceiverEncodedSource {

// Accepts RTCRtpEncoded{Video|Audio}Frame, rejects on incorrect frames

readonly attribute WritableStream writable;

};

78

79 of 130

Encoded Source update - external codecs

Application encodes using WebCodecs or other codec and sends the result over the network using RTCPeerConnection

Clear use case for RTCRtpSenderEncodedSource

Problem: We have no way to create a new encoded frame

  • We have a copy constructor that allows cloning frames and changing metadata
  • In this use case, there is no initial frame to copy/clone

Solution: new constructor

Issues: some metadata fields may need to be overwritten by the peer connection

79

80 of 130

Encoded Source update - external codecs

dictionary RTCEncodedVideoFrameOptions {

RTCEncodedVideoFrameMetadata metadata;

ArrayBuffer data;

};

[Exposed=(Window,DedicatedWorker), Serializable]

interface RTCEncodedVideoFrame {

constructor(RTCEncodedVideoFrameOptions options);

constructor(RTCEncodedVideoFrame originalFrame,

optional RTCEncodedVideoFrameOptions options = {});

...

};

80

81 of 130

Discussion

81

82 of 130

Camera intrinsics in MediaTrackSettings

(Rik)

82

83 of 130

Camera intrinsics in MediaTrackSettings

Meta Quest browser gives sessions access to its front facing cameras.

These cameras are offset and rotated wrt the screen and developers need this information to match the camera image with the screen

83

translation

rotation

84 of 130

Camera intrinsics in MediaTrackSettings

Proposal:

dictionary MediaTrackSettings {

DOMPointReadOnly lensTranslation;

DOMPointReadOnly lensRotation;

sequence<float> lensCalibration;

sequence<float> lensDistortion;

}

Definition of the parameters will match this spec.

84

85 of 130

Mediacapture-transform and track transfer

(Guido and Jan-Ivar)

85

86 of 130

Track transfer in MSTP/VTG (Guido)

Mediacapture-transform spec requires track transfer for MSTP and VTG

  • Control and data planes are strongly coupled in MSTP
    • Flawed pattern
    • Workers are great for the data plane, but a poor choice for the control plane
    • It should be straightforward to manage these planes independently
  • Limited DOM/API access
    • Impossible to use the same track with MSTP and another sink (common use case)
    • All other track sinks are on Window
    • Application logic normally uses other APIs on Window and integration is easier if the control plane is on Window
  • Working around these limitations at the application level is not trivial
    • Requires complex libraries or shims that are not full drop-in replacements
      • Extensive use of message passing and track cloning
      • Sync operations become async
      • Need to manage lifetime of more objects
    • Difficult to integrate in complex applications like major VCs

86

87 of 130

Track transfer in MSTP/VTG (Guido)

Proposal

  • Add a way to use MSTP and VTG that does not require transferring the track
    • Or, more generally, does not force the control panel to be on Worker
      • Includes tracks (and VTG.muted)
    • Encoded transform solves this same problem without forcing control-plane objects (RTCRtpSender/Receiver/track/RTCRtpScriptTransform) on Worker
    • Chrome also has a solution (transfer of streams, which are the only data-plane object)
  • Track transfer should be an orthogonal feature.
    • No need to remove existing support in the spec or its implementations
    • It should just not be a requirement

87

88 of 130

Aid transition to MSTP in worker (Jan-Ivar)

Using MediaStreamTrackProcessor requires transferring a MediaStreamTrack to a worker:

// assume a worker accepting {cmd, value} messages� worker.postMessage({cmd: "track", value: track}, [track]);�

Changes to the source track must go through the worker as well:

range.oninput = () => worker.postMessage({cmd: "applyConstraints",

value: {height: range.value});

But right now, websites must straddle spec & nonstandard MSTP on window (transient):

if (safari) {� range.oninput = () => worker.postMessage({cmd: "applyConstraints",

value: {height: range.value});

} else if (chrome) {

range.oninput = () => track.applyConstraints({height: range.value});

}

88

89 of 130

Aid transition to MSTP in worker (Jan-Ivar)

Can track clones help? No they have independent settings. But what if we had:

// not a proposalconst mirroredTrack = track.clone({mirror: true});

worker.postMessage({cmd: "track", value: track}, [track]);� range.oninput = () => mirroredTrack.applyConstraints({height: range.value});

stop.onclick = () => mirroredTrack.stop();

mute.onclick = () => mirroredTrack.enabled = !mute.checked;�

Mirrored tracks would share settings. Stop one stops all. With one transferred, this would accept input from worker and main alike, which would solve this.��But adds complexity and invites racy code between worker and main thread.�So not proposing this. A more targeted shim might do…

89

90 of 130

Aid transition to MSTP in worker (Jan-Ivar)

Using mirrorTrack() from https://jan-ivar.github.io/polyfills/mirrortrack.js:

// returns a real track clone that sends {cmd, value} messages to sync upconst mirroredTrack = mirrorTrack(original, {send: msg => worker.postMessage(msg)});

worker.postMessage({cmd: "track", value: track}, [track]);� range.oninput = () => mirroredTrack.applyConstraints({height: range.value});

stop.onclick = () => mirroredTrack.stop();

mute.onclick = () => mirroredTrack.enabled = !mute.checked;�

A seamless drop-in for a real track, as it is a real track (clone), with synchronous observable state. applyConstraints will succeed/fail reliably on same input.

This still assumes a worker that accepts {cmd:"applyConstraints" | "setEnabled" | "stop"}, but hides browser difference from the rest of the app.

90

91 of 130

Aid transition to MSTP in worker (Jan-Ivar)

Standard example w/fallback (runs in Safari and Chrome): https://jsfiddle.net/jib1/0mxc68s2/ — Excerpt:

const stream = await navigator.mediaDevices.getUserMedia({video: true});

const [originalTrack] = stream.getVideoTracks(); let track;

try {

// Try standard first + use mirrored control track

track = mirrorTrack(originalTrack, {send: msg => worker.postMessage(msg)});

worker.postMessage({cmd: "track", value: originalTrack}, [originalTrack]);

const {data} = await new Promise(r => worker.onmessage = r);

video.srcObject = new MediaStream([data.track]);

} catch (e) {

if (e.name != "DataCloneError") throw e;

// Fall back to nonstandard

track.stop(); track = originalTrack;

const {readable} = new MediaStreamTrackProcessor({track});

const mstg = new MediaStreamTrackGenerator({kind: "video"});

worker.postMessage({cmd: "streams", value: {readable, writable: mstg.writable}},

{transfer: [readable, mstg.writable]});

video.srcObject = new MediaStream([mstg]);

}� // agnostic code from here on out� mute.onclick = () => { track.enabled = !mute.checked; }

stop.onclick = () => track.stop();

range.oninput = () => track.applyConstraints({height: range.value});

91

92 of 130

Discussion

92

93 of 130

Start of Joint Meeting Thursday Slides

93

94 of 130

94

Media Chairs:

  • Marcos Caceres - Apple
  • Chris Needham - BBC

Joint Meeting�Thursday November 13, 2025

13:45 - 15:00 JST

TPAC 2025

Kobe Japan

Hybrid meeting

WebRTC Chairs:

  • Jan-Ivar Bruaroey - Mozilla
  • Youenn Fablet - Apple
  • Guido Urdaneta - Google

Media + WebRTC

95 of 130

W3C WG IPR Policy

95

96 of 130

W3C meeting rules & etiquette

Meeting : 13 November 2025, 13:45–15:00 JST

This meeting is run under the W3C Code of Ethics and Professional Conduct. Please be respectful, inclusive, and kind.

IRC chat: https://irc.w3.org in channel #mediawg

96

97 of 130

About Today’s Meeting

  • TPAC 2025 Schedule
    • Tuesday November 11, 16:30-18:00 JST
    • Thursday November 13, 09:00-10:30 JST
    • Thursday November 13, 13:45-15:00 JST (Media WG Joint Meeting)�
  • Today’s Meeting info:
  • Link to slides has been published on WG wiki
  • Scribe? IRC http://irc.w3.org/ Channel: #mediawg

97

98 of 130

Virtual Meeting Tips (Zoom)

  • Both local and remote participants need to be on irc.w3.org channel #mediawg.
  • Use “+q” in irc to get into the speaker queue and “-q” to get out of the speaker queue.
  • Remotes participation:
    • Please use headphones when speaking to avoid echo.
    • Please wait for microphone access to be granted before speaking.
  • Please state your full name before speaking.

98

99 of 130

Thursday - Joint Meeting Media + WebRTC

  • 13:45 - 14:10 MSTP for Audio / AudioTrackGenerator (Guido)
  • 14:10 - 14:30 Decoder failure API (Steve)
  • 14:30 - 14:55 Reconciling WebRTC & Media constructs (Youenn)
    • Media playback quality (Markus)
    • WebCodecs & WebRTC Encoded Transform
  • 14:55 - 15:00 Wrap-up and Next Steps (Chairs)

Time control:

  • A warning will be given 2 minutes before time is up.
  • Once time has elapsed we will move on to the next item.

99

100 of 130

Mediacapture-transform for Audio

(Guido)

100

101 of 130

Mediacapture-transform

Mediacapture-transform allows working with raw media and MediaStreamTracks

  • Given a track, get access to the raw media flowing through it
  • Given raw media, produce a track that carries the raw media
  • Combine both to create transforms

Raw media uses interfaces defined in WebCodecs

  • VideoFrame for video (consensus)
  • AudioData for audio (no consensus yet, shipped by Chrome)

101

102 of 130

Mediacapture-transform

MediaStreamTrackProcessor provides access to raw media from a MediaStreamTrack on a Worker

const processor = new MediaStreamTrackProcessor({ track: videoTrack });

const reader = processor.readable.getReader();

while (true) {

const frameOrDone = await reader.read();

If (frameOrDone.done) break;

DoSomethingWith(frameOrDone.value);

}

102

103 of 130

Mediacapture-transform

With VideoTrackSource it is possible to produce a track , given frames:

const generator = new VideoTrackGenerator();

connectTrackToSomeSink(generator.track);

const writer = generator.readable.getReader();

while (true) {

const frame = createVideoFrame();

try {

await writer.write(frame);

} catch (e) {

frame.close();

}

}

103

104 of 130

Mediacapture-transform

MSTG and VTG can be used together to produce a transformed track:

const generator = new VideoTrackGenerator();

// generator.track has the output track

const processor = new MediaStreamTrackProcessor({ track: inputTrack });

const transformer = new TransformStream({

async transform(inputFrame, controller) {

const outputFrame = createTransformedFrame(inputFrame);

inputFrame.close();

controller.enqueue(outputFrame);

}

});

await processor.readable.pipeThrough(transformer).pipeTo(generator.writable);

104

105 of 130

Mediacapture-transform for Audio

We have consensus to support video tracks

Chrome supports audio tracks, but no consensus yet

Why or why not audio?

  • Redundant with AudioWorklet
  • Audio processing sometimes requires a realtime thread all the way through
    • AudioWorklet provides it
    • Workers cannot provide it
    • Audio playback is the most common use case

105

106 of 130

Mediacapture-transform for Audio

There are some use cases where the mediacapture-transform model thread is a good fit

  • Buffering is acceptable
  • No audio playback (e.g., output to the network or not output at all)
  • Processing has high variance
  • Easier integration with video tracks and WebCodecs
  • Access to and forwarding of input metadata (e.g., capture timestamps)
  • Saves a realtime thread

Examples:

  • Audio analysis (MediaStreamTrackProcessor only)
    • Including combined audio/video analysis
  • Encoding
  • Transforms with no playback (e.g., output to network only)

106

107 of 130

Chrome's experience

107

108 of 130

Chrome's experience

mediacapture-transform usage (audio and video) is roughly 50% of AudioWorklet

  • Audio is ~27% of all Processor usage
    • Widely used
    • Mainly without connecting to a generator

  • Audio is ~2.6% of all Generator usage
    • Less used than Processor
    • Main use case is transformations that output only to the network (RTCPeerConnection)

  • Generator to processor:
    • Video: ~1.47 X, 47% more generator
    • Audio: ~0.11 X, 824% more processor

108

109 of 130

Mediacapture-transform for Audio

Conclusions

  • Processor for Audio
    • Widely used and many use cases
    • Proposal: add it to the spec

  • Generator for Audio
    • Suitable for sending over peer connection
    • Saves a realtime thread
    • Not good for playback
    • Experience in Chrome suggests that people know when and how to use it
    • Can be combined with fallbacks
    • Proposal: add it to the spec, with guidance about when to and when not to use it

109

110 of 130

Decoder failure API

(Steve)

110

111 of 130

Decoder Fallback and Failure Events #146

Status

Special thanks to

  • Nishitha Burman Dey, Philipp Hancke, Diego Perez Botero, Henrik Boström, Sun Shin, Gabriel Brito and everyone else who’s provided guidance.

111

112 of 130

Problem

Game streaming platforms like Nvidia GeForce Now, Xbox Cloud Gaming, and many others rely on hardware decoding to deliver low-latency, power efficient interactive gaming experiences.

However, there is currently no reliable way for these applications to detect when decoding falls back to software during a stream without prompting users for camera/mic permissions.

This gap makes it difficult to diagnose performance regressions and provide troubleshooting guidance.

112

113 of 130

Goals

  • Detect decoder fallback from hardware to software at runtime without requiring additional permissions like camera/mic.
  • Help applications diagnose regressions (e.g. codec negotiation issues, device specific problems).
  • Enable apps to adapt (e.g. lowering resolution, re-negotiating codecs), alerting end users when software decode occurs, and displaying troubleshooting information.

Non-Goals

  • Exposing vendor-specific hardware information.
  • Exposing additional codec information beyond what MediaCapabilities already provides.

113

114 of 130

Proposed API

partial interface RTCRtpReceiver {

attribute EventHandler ondecoderstatechange;

attribute EventHandler ondecodererror;

};

  • Two new events on RTCRtpReceiver:
    • Decoder State Changed
    • Decoder Error

114

115 of 130

Decoder State Change Event

interface RTCDecoderStateChangeEvent : Event {

// The media timeline reference when the event occurred.

readonly attribute unsigned long rtpTimestamp;

// Identifies the codec in-use after the state change.

//

// Nullable, allowing implementers to decide when to omit for privacy.

readonly attribute RTCRtpCodecParameters? codecParameters;

// powerEfficientDecoder changes primarily based on hardware/software decoder.

// Aligns with MediaCapabilitiesInfo:

// https://www.w3.org/TR/media-capabilities/#media-capabilities-info

//

// Also available through getStats().

// https://w3c.github.io/webrtc-stats/#dom-rtcinboundrtpstreamstats-powerefficientdecoder

//

// // Nullable, allowing implementers to decide when to omit for privacy.

readonly attribute boolean? powerEfficientDecoder;

};

115

116 of 130

Decoder State Change Event

  • Occurs after:
    • Transitioning from hardware to software decode.
    • Switching decoders.
  • Example usage:

116

const pc = new RTCPeerConnection();

pc.addEventListener('track', (event) => {

event.receiver.addEventListener('decoderstatechange', (ev) => {

// Adapt behavior based on software decoder usage.

if (!ev.powerEfficientDecoder) {

showToast('Playback quality may be reduced'); // Notify the user.

adjustQuality('low'); // Lower resolution or disable heavy post-processing.

// Log telemetry signal with codec and RTP timestamp.

let codecParams = 'unknown';

if (ev.codecParameters) {

codecParams = `${ev.codecParameters.mimeType}|${ev.codecParameters.sdpFmtpLine}`;

}

logMetric(`Fallback: codec=${codecParams}, time=${ev.rtpTimestamp}`);

117 of 130

Decoder Error Event

interface RTCDecoderErrorEvent : RTCDecoderStateChangeEvent {

// The inherited `RTCDecoderStateChangeEvent` members identify the failing codec.

// Provide a description of the error.

readonly attribute unsigned short errorCode;

readonly attribute USVString errorText;

};

117

118 of 130

Media playback quality

(Markus)

118

119 of 130

119

(Markus Handell, Google Meet, Stockholm)

  • Present proposal for improved metrics for temporal video quality
  • Relay a feeling for the metrics
  • Gather feedback + next steps

120 of 130

RTC video recap

Requirement: Reproduce captured cadence of frames

120

121 of 130

  1. Recap: Framerate

Oldie goldie

121

Quality Topic

FPS

Local video tiles

Remote video tiles

Hitch sensitivity

Video (isochronous)

Screen share (non-isochronous)

Accuracy

Frame drops

122 of 130

  • Recap: WebRTC Harmonic Framerate

…in receiver getStats()

122

Quality Topic

hFPS

Local video tiles

Remote video tiles

✅ish

Hitch sensitivity

Video (isochronous)

Screen share (non-isochronous)

Accuracy

⛔ish

Frame drops

123 of 130

  • Proposed:�getVideoPlaybackQuality() Harmonic FPS

123

Quality Topic

hFPS

Local video tiles

Remote video tiles

✅😇

Hitch sensitivity

Video (isochronous)

Screen share (non-isochronous)

Accuracy

✅🙋

Frame drops

exposed!

124 of 130

  • Proposed:�getVideoPlaybackQuality() Reproduction Jitter RMSE

124

Quality Topic

RMSE

Availability: local video tiles

Availability: remote video tiles

Hitch sensitivity

Video (isochronous)

Screen share (non-isochronous)

Accuracy

Frame drops

exposed!

125 of 130

  • Proposed:�getVideoPlaybackQuality() Reproduction Jitter Metric

Remote end: trick to estimate remote capture time/frame duration.�Assumes RTP timestamp avail at time of display.

125

exposed!

90 kHz for all current codecs…

126 of 130

Proposed IDL

interface VideoPlaybackQuality {

readonly attribute DOMHighResTimeStamp creationTime;

readonly attribute unsigned long totalVideoFrames;

readonly attribute unsigned long droppedVideoFrames;

readonly attribute unsigned long corruptedVideoFrames;

// Harmonic framerate

readonly attribute unsigned long presentedFrameDurationSum;

readonly attribute unsigned long presentedFrameDurationSquaredSum;

// Reproduction jitter RMSE

readonly attribute unsigned long presentedFrameErrorSquaredSum;

readonly attribute unsigned long framesWithCaptureTimestamp;

readonly attribute unsigned long presentedFrameErrorSquaredSumRtp;

readonly attribute unsigned long framesWithRtpTimestamp;

}

126

127 of 130

DEMO TIME!

127

128 of 130

WebCodecs and WebRTC Encoded Transform

(Youenn)

128

129 of 130

129

130 of 130

End of Thursday Slides

130