fix: try VP9/AV1 too, not just H264, and fail loudly if none available
A real test with the H264-preference fix still negotiated VP8 —
RTCRtpSender.getCapabilities('video') apparently didn't list H264 on
that browser/machine (Chrome's H264 encoder is a separate downloadable
component, not guaranteed present). Confirmed via mediamtx's live path
list: still 'tracks: ["VP8"]' after the fix was deployed.
Now tries every MediaMTX-HLS-supported codec in priority order (H264,
VP9, AV1) instead of only H264, and throws a clear error instead of
silently falling back to VP8 if literally none of them are available —
better than a stream that looks live but can never produce working
HLS.
This commit is contained in:
+29
-13
@@ -10,24 +10,40 @@ export async function publishWhip(
|
||||
bearer: string,
|
||||
stream: MediaStream,
|
||||
): Promise<WhipSession> {
|
||||
// MediaMTX's HLS output only muxes AV1, VP9, H265, H264, Opus, MPEG-4
|
||||
// Audio, or KLV (confirmed live in its logs: "the stream doesn't contain
|
||||
// any supported codec" — the muxer gets created then immediately
|
||||
// destroyed, so the WHIP publish itself still succeeds and the stream
|
||||
// shows as live, but hls/live/<id>/index.m3u8 permanently 404s with
|
||||
// "muxer is waiting to be created"). Browsers default to VP8 for
|
||||
// getUserMedia/getDisplayMedia video, which isn't in that list at all.
|
||||
// Reordering codec preference to H264 first didn't actually change what
|
||||
// got negotiated on a real test (RTCRtpSender.getCapabilities('video')
|
||||
// apparently didn't list H264 on that browser/machine — Chrome's H264
|
||||
// encoder is a separate downloadable component and isn't guaranteed
|
||||
// present) — so try every MediaMTX-supported codec in priority order
|
||||
// instead of only H264, and fail loudly if literally none of them are
|
||||
// available rather than silently falling back to the broken default.
|
||||
const MEDIAMTX_HLS_VIDEO_CODECS = ['video/H264', 'video/VP9', 'video/AV1'];
|
||||
|
||||
const pc = new RTCPeerConnection();
|
||||
for (const track of stream.getTracks()) {
|
||||
const transceiver = pc.addTransceiver(track, { direction: 'sendonly' });
|
||||
// Browsers default to VP8 for getUserMedia/getDisplayMedia video, which
|
||||
// MediaMTX's HLS output can't mux at all (confirmed live: "the stream
|
||||
// doesn't contain any supported codec, which are currently AV1, VP9,
|
||||
// H265, H264, Opus, MPEG-4 Audio, KLV" — the muxer gets created then
|
||||
// immediately destroyed, so the WHIP publish itself succeeds and the
|
||||
// stream shows as live, but hls/live/<id>/index.m3u8 permanently 404s
|
||||
// with "muxer is waiting to be created"). Reorder codec preference so
|
||||
// H264 is offered first — matches what OBS already sends over RTMP, so
|
||||
// this keeps a single well-tested codec through the whole pipeline
|
||||
// (HLS, recording) instead of introducing a second one.
|
||||
if (track.kind === 'video' && typeof transceiver.setCodecPreferences === 'function') {
|
||||
const capabilities = RTCRtpSender.getCapabilities('video');
|
||||
const h264 = capabilities?.codecs.filter((c) => c.mimeType.toLowerCase() === 'video/h264') ?? [];
|
||||
const rest = capabilities?.codecs.filter((c) => c.mimeType.toLowerCase() !== 'video/h264') ?? [];
|
||||
if (h264.length > 0) transceiver.setCodecPreferences([...h264, ...rest]);
|
||||
const available = capabilities?.codecs ?? [];
|
||||
const preferred = MEDIAMTX_HLS_VIDEO_CODECS.flatMap((mime) =>
|
||||
available.filter((c) => c.mimeType.toLowerCase() === mime.toLowerCase()),
|
||||
);
|
||||
if (preferred.length === 0) {
|
||||
pc.close();
|
||||
throw new Error(
|
||||
"This browser doesn't support any video codec MediaMTX can turn into HLS " +
|
||||
`(needs one of: ${MEDIAMTX_HLS_VIDEO_CODECS.join(', ')}). Try a different browser, or use OBS instead.`,
|
||||
);
|
||||
}
|
||||
const rest = available.filter((c) => !preferred.includes(c));
|
||||
transceiver.setCodecPreferences([...preferred, ...rest]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user