Skip to content

Commit 15e8890

Browse files
committed
Enable HEVC over WebRTC
1 parent 5e6628a commit 15e8890

4 files changed

Lines changed: 309 additions & 29 deletions

File tree

client/src/app/AppShell.tsx

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1249,10 +1249,6 @@ export function AppShell() {
12491249
}
12501250
const udid = selectedSimulator.udid;
12511251
setVideoCodec(codec);
1252-
if (codec === "hevc" && streamTransportMode !== "webtransport") {
1253-
setStreamTransportMode("webtransport");
1254-
setStreamSettingsRevision((current) => current + 1);
1255-
}
12561252
void (async () => {
12571253
codecSwitchInFlightRef.current = true;
12581254
setStreamPaused(true);

client/src/features/stream/streamWorkerClient.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,11 @@ class WebRtcStreamClient implements StreamClientBackend {
173173
const transceiver = peerConnection.addTransceiver("video", {
174174
direction: "recvonly",
175175
});
176+
const health = await fetchHealth();
177+
if (generation !== this.connectGeneration) {
178+
return;
179+
}
180+
configureReceiverCodecPreferences(transceiver, health.videoCodec);
176181
configureLowLatencyReceiver(transceiver.receiver);
177182
const controlChannel = peerConnection.createDataChannel(
178183
WEBRTC_CONTROL_CHANNEL_LABEL,
@@ -608,6 +613,44 @@ function configureLowLatencyReceiver(receiver: RTCRtpReceiver) {
608613
}
609614
}
610615

616+
function configureReceiverCodecPreferences(
617+
transceiver: RTCRtpTransceiver,
618+
videoCodec?: string | null,
619+
) {
620+
if (!transceiver.setCodecPreferences) {
621+
return;
622+
}
623+
const preferredMimeType = preferredWebRtcMimeType(videoCodec);
624+
if (!preferredMimeType) {
625+
return;
626+
}
627+
const capabilities = RTCRtpReceiver.getCapabilities("video");
628+
const codecs = capabilities?.codecs ?? [];
629+
const preferred = codecs.filter(
630+
(codec) => codec.mimeType.toLowerCase() === preferredMimeType,
631+
);
632+
if (preferred.length === 0) {
633+
return;
634+
}
635+
transceiver.setCodecPreferences([
636+
...preferred,
637+
...codecs.filter(
638+
(codec) => codec.mimeType.toLowerCase() !== preferredMimeType,
639+
),
640+
]);
641+
}
642+
643+
function preferredWebRtcMimeType(videoCodec?: string | null): string | null {
644+
const normalized = videoCodec?.toLowerCase();
645+
if (normalized === "hevc") {
646+
return "video/h265";
647+
}
648+
if (normalized === "h264" || normalized === "h264-software") {
649+
return "video/h264";
650+
}
651+
return null;
652+
}
653+
611654
export function initialStreamTransportMode(): StreamTransportMode {
612655
if (typeof window === "undefined") {
613656
return "auto";

docs/guide/architecture.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ Inside the bridge:
5454

5555
### `client/` — React browser UI
5656

57-
The React app served at `/` is a thin shell that calls the REST API and consumes live video over WebTransport by default. It automatically selects WebRTC media for `h264-software`, forces HEVC back to WebTransport, and exposes runtime codec and transport controls in the simulator menu. URLs can still seed a transport with `?transport=webtransport` or `?transport=webrtc`.
57+
The React app served at `/` is a thin shell that calls the REST API and consumes live video over WebTransport by default. It automatically selects WebRTC media for `h264-software`, supports WebRTC media for H.264 and HEVC when selected, and exposes runtime codec and transport controls in the simulator menu. URLs can still seed a transport with `?transport=webtransport` or `?transport=webrtc`.
5858

5959
Layout under `client/src/`:
6060

0 commit comments

Comments
 (0)