Skip to content

Add support for packet trailer features#1886

Open
chenosaurus wants to merge 25 commits intomainfrom
dc/feature/packet_trailer
Open

Add support for packet trailer features#1886
chenosaurus wants to merge 25 commits intomainfrom
dc/feature/packet_trailer

Conversation

@chenosaurus
Copy link
Copy Markdown

  • Add support for packet trailer features (user timestamp, frame ID).
  • Add new web worker for packet trailer parsing.
  • update example/demo to have options to enable packet trailer & render the parsed metadata.
  • Unit tests for packet trailer parsing.

@chenosaurus chenosaurus requested review from 1egoman and lukasIO April 14, 2026 23:43
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Apr 14, 2026

⚠️ No Changeset found

Latest commit: 49942ef

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

Comment thread examples/demo/demo.ts Dismissed
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 15, 2026

size-limit report 📦

Path Size
dist/livekit-client.esm.mjs 97.27 KB (+1.67% 🔺)
dist/livekit-client.umd.js 106.15 KB (+1.37% 🔺)

Comment thread src/e2ee/E2eeManager.ts Outdated
// Disabling it for Chrome based browsers until the API has stabilized
!isChromiumBased()
!isChromiumBased() &&
!ptPreProcessed
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I follow why this is being checked for here, can you elaborate on the intention behind it?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed, it was left over.

Comment thread src/e2ee/packetTrailer.ts
@@ -0,0 +1,198 @@
export const PACKET_TRAILER_MAGIC = Uint8Array.from([
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

have you considered signalling packet-trailer presence as part of the publication info instead of relying on checking every frame on every publication for the magic bytes?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is already support on track publication to declare which packet trailer features are available on the track. It's exposed to the subscriber in TrackInfo. I have updated all place to check TrackInfo before attaching transformer.

Comment thread src/e2ee/packetTrailer.ts
if (typeof metadata.rtpTimestamp === 'number') {
return metadata.rtpTimestamp;
}
if (typeof metadata.timestamp === 'number') {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is this referring to? I don't see a timestamp value on getMetadata here

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cleaned up

Comment thread src/e2ee/packetTrailer.ts
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it intentional that this file lives in the /e2ee folder? 👀

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, that's a mistake. Moved.

Comment thread src/version.ts

export const version = v;
export const protocolVersion = 16;
export const protocolVersion = 17;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The related protocol PR talks about stripping the trailer on the SFU side, but I don't think bumping protocolVersion is enough: what happens if a client with protocolVersion 17 doesn't have the trailer worker set?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

^ This is probably my biggest question as well.

It sort of sounds like you want a "feature" you can communicate support of unrelated to a protocol / client version. I recently wrote a note about this in the context of the in flight rpc protocol updates here: #1832 (comment)

Keeping in mind we haven't discussed mechanically how this pattern would work yet (ie, new fields in ParticipantInfo, something in the JoinResponse, etc?), I think if you did something like that then the SFU could know if packet trailer processing is enabled on the client independent of the protocol version and opt to strip or not strip conditionally.

Thoughts on that proposal?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The packet trailer transform is lightweight enough to run on the main thread, we can as a backup attach the transform automatically (when worker is not passed in) when we see any tracks that declared packet trailer features in its TrackInfo. That would always work and avoid having to change any signaling to the SFU.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The packet trailer transform is lightweight enough to run on the main thread

If this is the case, is there a reason why it shouldn't always be run on the main thread then rather than having the optional worker?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see response on a later comment, it's possible to attach the packet trailer transformer directly to the transceiver in the main thread to avoid the issue of worker not being initialized. However, we should try to use the worker whenever possible to not have to process frames in the main thread.

Comment on lines +486 to +488
} catch {
// best-effort: never break the media pipeline if trailer parsing fails
}
Copy link
Copy Markdown
Contributor

@1egoman 1egoman Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: Is it worth at least logging something here to make it clear that a failure happened?

Comment thread src/e2ee/packetTrailer.ts
Comment on lines +184 to +186
} catch {
// getMetadata() might not be available
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Another place where it might be worth logging

Comment on lines +23 to +26
* When E2EE is active, the E2EE FrameCryptor worker handles trailer
* extraction directly (before decryption), so this manager only creates
* the extractor/metadata cache — no separate insertable-streams pipeline
* is needed.
Copy link
Copy Markdown
Contributor

@1egoman 1egoman Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: I'm not sure I understand why this packet trailer logic exists both in the e2ee worker and in the new packet trailer worker. Can you shed some light on why you made this decision? Does it have to do with the goal of encrypting the packet payload and trailer separately so the SFU can strip out the trailer without that process requiring decrypting a single large block?

I don't have enough context to be incredibly confident in this suggestion, but if you can't attach multiple transforms which run in series there might be some value in adding some sort of "stream transform composer" layer above both this and the e2ee manager which would connect a series of transforms together and allows each to fully own their respective responsibilities.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The main reason is each track transceiver can only have a single transform attached, so if e2ee is enabled, we can't also attach the packetTrailer transform worker. Thus the need to have the same logic inside e2ee for parsing packet trailers if both features are enabled.

I think your suggestion makes sense but would mean a much bigger refactor where e2eeManager & e2ee worker needs to be replaced by a more generic frameTransformManager & a new worker that can handle both e2ee & packetTrailer.

Comment thread src/options.ts
Comment on lines +104 to +110
/**
* @experimental
* Options for enabling packet trailer extraction on received video tracks.
* Packet trailers carry frame-level metadata such as user timestamps and frame IDs.
*/
packetTrailer?: PacketTrailerOptions;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thought: After this gets eventually is merged, you may want to add a todo for yourself to wire this through in components-js in a similar way to what we recently did for encryption, see here for more info: livekit/components-js#1317

Comment thread src/version.ts

export const version = v;
export const protocolVersion = 16;
export const protocolVersion = 17;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

^ This is probably my biggest question as well.

It sort of sounds like you want a "feature" you can communicate support of unrelated to a protocol / client version. I recently wrote a note about this in the context of the in flight rpc protocol updates here: #1832 (comment)

Keeping in mind we haven't discussed mechanically how this pattern would work yet (ie, new fields in ParticipantInfo, something in the JoinResponse, etc?), I think if you did something like that then the SFU could know if packet trailer processing is enabled on the client independent of the protocol version and opt to strip or not strip conditionally.

Thoughts on that proposal?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants