From 374c989ad23bfd10c9f3744f2f3d61508dbe5217 Mon Sep 17 00:00:00 2001 From: Anunay Maheshwari Date: Mon, 19 Jan 2026 23:25:42 +0530 Subject: [PATCH 1/3] move codecs from SFU, add helper to convert to pion type --- codecs/codecs.go | 221 +++++++++++++++++++++++++++ codecs/mimetype.go | 365 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 586 insertions(+) create mode 100644 codecs/codecs.go create mode 100644 codecs/mimetype.go diff --git a/codecs/codecs.go b/codecs/codecs.go new file mode 100644 index 00000000..dddaaadd --- /dev/null +++ b/codecs/codecs.go @@ -0,0 +1,221 @@ +// Copyright 2026 LiveKit, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package codecs + +import ( + "strings" + + "github.com/livekit/protocol/livekit" + "github.com/pion/webrtc/v4" +) + +var ( + OpusCodecParameters = webrtc.RTPCodecParameters{ + RTPCodecCapability: webrtc.RTPCodecCapability{ + MimeType: MimeTypeOpus.String(), + ClockRate: 48000, + Channels: 2, + SDPFmtpLine: "minptime=10;useinbandfec=1", + }, + PayloadType: 111, + } + + RedCodecParameters = webrtc.RTPCodecParameters{ + RTPCodecCapability: webrtc.RTPCodecCapability{ + MimeType: MimeTypeRED.String(), + ClockRate: 48000, + Channels: 2, + SDPFmtpLine: "111/111", + }, + PayloadType: 63, + } + + PCMUCodecParameters = webrtc.RTPCodecParameters{ + RTPCodecCapability: webrtc.RTPCodecCapability{ + MimeType: MimeTypePCMU.String(), + ClockRate: 8000, + }, + PayloadType: 0, + } + + PCMACodecParameters = webrtc.RTPCodecParameters{ + RTPCodecCapability: webrtc.RTPCodecCapability{ + MimeType: MimeTypePCMA.String(), + ClockRate: 8000, + }, + PayloadType: 8, + } + + VideoRTXCodecParameters = webrtc.RTPCodecParameters{ + RTPCodecCapability: webrtc.RTPCodecCapability{ + MimeType: MimeTypeRTX.String(), + ClockRate: 90000, + }, + } + + VP8CodecParameters = webrtc.RTPCodecParameters{ + RTPCodecCapability: webrtc.RTPCodecCapability{ + MimeType: MimeTypeVP8.String(), + ClockRate: 90000, + }, + PayloadType: 96, + } + + VP9ProfileId0CodecParameters = webrtc.RTPCodecParameters{ + RTPCodecCapability: webrtc.RTPCodecCapability{ + MimeType: MimeTypeVP9.String(), + ClockRate: 90000, + SDPFmtpLine: "profile-id=0", + }, + PayloadType: 98, + } + + VP9ProfileId1CodecParameters = webrtc.RTPCodecParameters{ + RTPCodecCapability: webrtc.RTPCodecCapability{ + MimeType: MimeTypeVP9.String(), + ClockRate: 90000, + SDPFmtpLine: "profile-id=1", + }, + PayloadType: 100, + } + + H264ProfileLevelId42e01fPacketizationMode0CodecParameters = webrtc.RTPCodecParameters{ + RTPCodecCapability: webrtc.RTPCodecCapability{ + MimeType: MimeTypeH264.String(), + ClockRate: 90000, + SDPFmtpLine: "level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f", + }, + PayloadType: 125, + } + + H264ProfileLevelId42e01fPacketizationMode1CodecParameters = webrtc.RTPCodecParameters{ + RTPCodecCapability: webrtc.RTPCodecCapability{ + MimeType: MimeTypeH264.String(), + ClockRate: 90000, + SDPFmtpLine: "level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f", + }, + PayloadType: 108, + } + + H264HighProfileFmtp = "level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032" + H264HighProfileCodecParameters = webrtc.RTPCodecParameters{ + RTPCodecCapability: webrtc.RTPCodecCapability{ + MimeType: MimeTypeH264.String(), + ClockRate: 90000, + SDPFmtpLine: H264HighProfileFmtp, + }, + PayloadType: 123, + } + + AV1CodecParameters = webrtc.RTPCodecParameters{ + RTPCodecCapability: webrtc.RTPCodecCapability{ + MimeType: MimeTypeAV1.String(), + ClockRate: 90000, + }, + PayloadType: 35, + } + + H265CodecParameters = webrtc.RTPCodecParameters{ + RTPCodecCapability: webrtc.RTPCodecCapability{ + MimeType: MimeTypeH265.String(), + ClockRate: 90000, + }, + PayloadType: 116, + } + + VideoCodecsParameters = []webrtc.RTPCodecParameters{ + VP8CodecParameters, + VP9ProfileId0CodecParameters, + VP9ProfileId1CodecParameters, + H264ProfileLevelId42e01fPacketizationMode0CodecParameters, + H264ProfileLevelId42e01fPacketizationMode1CodecParameters, + H264HighProfileCodecParameters, + AV1CodecParameters, + H265CodecParameters, + } +) + +func mergeFmtpLines(defaultFmtp, inputFmtp string) string { + if inputFmtp == "" { + return defaultFmtp + } + if defaultFmtp == "" { + return inputFmtp + } + + var result strings.Builder + result.WriteString(defaultFmtp) + + defaultKeys := make(map[string]struct{}) + for _, param := range strings.Split(defaultFmtp, ";") { + if key, _, found := strings.Cut(param, "="); found { + defaultKeys[key] = struct{}{} + } + } + + for _, param := range strings.Split(inputFmtp, ";") { + if key, _, found := strings.Cut(param, "="); found { + if _, exists := defaultKeys[key]; !exists { + result.WriteByte(';') + result.WriteString(param) + } + } + } + + return result.String() +} + +func ToWebrtcCodecParameters(codec *livekit.Codec) webrtc.RTPCodecParameters { + fmtp := codec.GetFmtpLine() + var params webrtc.RTPCodecParameters + + switch NormalizeMimeType(codec.GetMime()) { + case MimeTypeOpus: + params = OpusCodecParameters + case MimeTypeRED: + params = RedCodecParameters + case MimeTypePCMU: + params = PCMUCodecParameters + case MimeTypePCMA: + params = PCMACodecParameters + case MimeTypeRTX: + params = VideoRTXCodecParameters + case MimeTypeVP8: + params = VP8CodecParameters + case MimeTypeVP9: + if strings.Contains(fmtp, "profile-id=1") { + params = VP9ProfileId1CodecParameters + } else { + params = VP9ProfileId0CodecParameters + } + case MimeTypeAV1: + params = AV1CodecParameters + case MimeTypeH264: + if strings.Contains(fmtp, "profile-level-id=640032") { + params = H264HighProfileCodecParameters + } else if strings.Contains(fmtp, "packetization-mode=0") { + params = H264ProfileLevelId42e01fPacketizationMode0CodecParameters + } else { + params = H264ProfileLevelId42e01fPacketizationMode1CodecParameters + } + case MimeTypeH265: + params = H265CodecParameters + default: + return webrtc.RTPCodecParameters{} + } + + params.SDPFmtpLine = mergeFmtpLines(params.SDPFmtpLine, fmtp) + return params +} diff --git a/codecs/mimetype.go b/codecs/mimetype.go new file mode 100644 index 00000000..e99edb00 --- /dev/null +++ b/codecs/mimetype.go @@ -0,0 +1,365 @@ +// Copyright 2026 LiveKit, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package codecs + +import ( + "strings" + + "github.com/pion/webrtc/v4" + + "github.com/livekit/protocol/observability/roomobs" +) + +const ( + MimeTypePrefixAudio = "audio/" + MimeTypePrefixVideo = "video/" +) + +type MimeTypeCodec int + +const ( + MimeTypeCodecUnknown MimeTypeCodec = iota + MimeTypeCodecH264 + MimeTypeCodecH265 + MimeTypeCodecOpus + MimeTypeCodecRED + MimeTypeCodecVP8 + MimeTypeCodecVP9 + MimeTypeCodecAV1 + MimeTypeCodecG722 + MimeTypeCodecPCMU + MimeTypeCodecPCMA + MimeTypeCodecRTX + MimeTypeCodecFlexFEC + MimeTypeCodecULPFEC +) + +func (m MimeTypeCodec) String() string { + switch m { + case MimeTypeCodecUnknown: + return "MimeTypeCodecUnknown" + case MimeTypeCodecH264: + return "H264" + case MimeTypeCodecH265: + return "H265" + case MimeTypeCodecOpus: + return "opus" + case MimeTypeCodecRED: + return "red" + case MimeTypeCodecVP8: + return "VP8" + case MimeTypeCodecVP9: + return "VP9" + case MimeTypeCodecAV1: + return "AV1" + case MimeTypeCodecG722: + return "G722" + case MimeTypeCodecPCMU: + return "PCMU" + case MimeTypeCodecPCMA: + return "PCMA" + case MimeTypeCodecRTX: + return "rtx" + case MimeTypeCodecFlexFEC: + return "flexfec" + case MimeTypeCodecULPFEC: + return "ulpfec" + } + + return "MimeTypeCodecUnknown" +} + +func (m MimeTypeCodec) ToMimeType() MimeType { + switch m { + case MimeTypeCodecUnknown: + return MimeTypeUnknown + case MimeTypeCodecH264: + return MimeTypeH264 + case MimeTypeCodecH265: + return MimeTypeH265 + case MimeTypeCodecOpus: + return MimeTypeOpus + case MimeTypeCodecRED: + return MimeTypeRED + case MimeTypeCodecVP8: + return MimeTypeVP8 + case MimeTypeCodecVP9: + return MimeTypeVP9 + case MimeTypeCodecAV1: + return MimeTypeAV1 + case MimeTypeCodecG722: + return MimeTypeG722 + case MimeTypeCodecPCMU: + return MimeTypePCMU + case MimeTypeCodecPCMA: + return MimeTypePCMA + case MimeTypeCodecRTX: + return MimeTypeRTX + case MimeTypeCodecFlexFEC: + return MimeTypeFlexFEC + case MimeTypeCodecULPFEC: + return MimeTypeULPFEC + } + + return MimeTypeUnknown +} + +func NormalizeMimeTypeCodec(codec string) MimeTypeCodec { + switch { + case strings.EqualFold(codec, "h264"): + return MimeTypeCodecH264 + case strings.EqualFold(codec, "h265"): + return MimeTypeCodecH265 + case strings.EqualFold(codec, "opus"): + return MimeTypeCodecOpus + case strings.EqualFold(codec, "red"): + return MimeTypeCodecRED + case strings.EqualFold(codec, "vp8"): + return MimeTypeCodecVP8 + case strings.EqualFold(codec, "vp9"): + return MimeTypeCodecVP9 + case strings.EqualFold(codec, "av1"): + return MimeTypeCodecAV1 + case strings.EqualFold(codec, "g722"): + return MimeTypeCodecG722 + case strings.EqualFold(codec, "pcmu"): + return MimeTypeCodecPCMU + case strings.EqualFold(codec, "pcma"): + return MimeTypeCodecPCMA + case strings.EqualFold(codec, "rtx"): + return MimeTypeCodecRTX + case strings.EqualFold(codec, "flexfec"): + return MimeTypeCodecFlexFEC + case strings.EqualFold(codec, "ulpfec"): + return MimeTypeCodecULPFEC + } + + return MimeTypeCodecUnknown +} + +func GetMimeTypeCodec(mime string) MimeTypeCodec { + i := strings.IndexByte(mime, '/') + if i == -1 { + return MimeTypeCodecUnknown + } + + return NormalizeMimeTypeCodec(mime[i+1:]) +} + +func IsMimeTypeCodecStringOpus(codec string) bool { + return NormalizeMimeTypeCodec(codec) == MimeTypeCodecOpus +} + +func IsMimeTypeCodecStringRED(codec string) bool { + return NormalizeMimeTypeCodec(codec) == MimeTypeCodecRED +} + +func IsMimeTypeCodecStringPCMA(codec string) bool { + return NormalizeMimeTypeCodec(codec) == MimeTypeCodecPCMA +} + +func IsMimeTypeCodecStringPCMU(codec string) bool { + return NormalizeMimeTypeCodec(codec) == MimeTypeCodecPCMU +} + +func IsMimeTypeCodecStringH264(codec string) bool { + return NormalizeMimeTypeCodec(codec) == MimeTypeCodecH264 +} + +type MimeType int + +const ( + MimeTypeUnknown MimeType = iota + MimeTypeH264 + MimeTypeH265 + MimeTypeOpus + MimeTypeRED + MimeTypeVP8 + MimeTypeVP9 + MimeTypeAV1 + MimeTypeG722 + MimeTypePCMU + MimeTypePCMA + MimeTypeRTX + MimeTypeFlexFEC + MimeTypeULPFEC +) + +func (m MimeType) String() string { + switch m { + case MimeTypeUnknown: + return "MimeTypeUnknown" + case MimeTypeH264: + return webrtc.MimeTypeH264 + case MimeTypeH265: + return webrtc.MimeTypeH265 + case MimeTypeOpus: + return webrtc.MimeTypeOpus + case MimeTypeRED: + return "audio/red" + case MimeTypeVP8: + return webrtc.MimeTypeVP8 + case MimeTypeVP9: + return webrtc.MimeTypeVP9 + case MimeTypeAV1: + return webrtc.MimeTypeAV1 + case MimeTypeG722: + return webrtc.MimeTypeG722 + case MimeTypePCMU: + return webrtc.MimeTypePCMU + case MimeTypePCMA: + return webrtc.MimeTypePCMA + case MimeTypeRTX: + return webrtc.MimeTypeRTX + case MimeTypeFlexFEC: + return webrtc.MimeTypeFlexFEC + case MimeTypeULPFEC: + return "video/ulpfec" + } + + return "MimeTypeUnknown" +} + +func (m MimeType) ReporterType() roomobs.MimeType { + switch m { + case MimeTypeUnknown: + return roomobs.MimeTypeUndefined + case MimeTypeH264: + return roomobs.MimeTypeVideoH264 + case MimeTypeH265: + return roomobs.MimeTypeVideoH265 + case MimeTypeOpus: + return roomobs.MimeTypeAudioOpus + case MimeTypeRED: + return roomobs.MimeTypeAudioRed + case MimeTypeVP8: + return roomobs.MimeTypeVideoVp8 + case MimeTypeVP9: + return roomobs.MimeTypeVideoVp9 + case MimeTypeAV1: + return roomobs.MimeTypeVideoAv1 + case MimeTypeG722: + return roomobs.MimeTypeAudioG722 + case MimeTypePCMU: + return roomobs.MimeTypeAudioPcmu + case MimeTypePCMA: + return roomobs.MimeTypeAudioPcma + case MimeTypeRTX: + return roomobs.MimeTypeVideoRtx + case MimeTypeFlexFEC: + return roomobs.MimeTypeVideoFlexfec + case MimeTypeULPFEC: + return roomobs.MimeTypeVideoUlpfec + } + + return roomobs.MimeTypeUndefined +} + +func NormalizeMimeType(mime string) MimeType { + switch { + case strings.EqualFold(mime, webrtc.MimeTypeH264): + return MimeTypeH264 + case strings.EqualFold(mime, webrtc.MimeTypeH265): + return MimeTypeH265 + case strings.EqualFold(mime, webrtc.MimeTypeOpus): + return MimeTypeOpus + case strings.EqualFold(mime, "audio/red"): + return MimeTypeRED + case strings.EqualFold(mime, webrtc.MimeTypeVP8): + return MimeTypeVP8 + case strings.EqualFold(mime, webrtc.MimeTypeVP9): + return MimeTypeVP9 + case strings.EqualFold(mime, webrtc.MimeTypeAV1): + return MimeTypeAV1 + case strings.EqualFold(mime, webrtc.MimeTypeG722): + return MimeTypeG722 + case strings.EqualFold(mime, webrtc.MimeTypePCMU): + return MimeTypePCMU + case strings.EqualFold(mime, webrtc.MimeTypePCMA): + return MimeTypePCMA + case strings.EqualFold(mime, webrtc.MimeTypeRTX): + return MimeTypeRTX + case strings.EqualFold(mime, webrtc.MimeTypeFlexFEC): + return MimeTypeFlexFEC + case strings.EqualFold(mime, "video/ulpfec"): + return MimeTypeULPFEC + } + + return MimeTypeUnknown +} + +func IsMimeTypeStringEqual(mime1 string, mime2 string) bool { + return NormalizeMimeType(mime1) == NormalizeMimeType(mime2) +} + +func IsMimeTypeStringAudio(mime string) bool { + return strings.HasPrefix(mime, MimeTypePrefixAudio) +} + +func IsMimeTypeAudio(mimeType MimeType) bool { + return strings.HasPrefix(mimeType.String(), MimeTypePrefixAudio) +} + +func IsMimeTypeStringVideo(mime string) bool { + return strings.HasPrefix(mime, MimeTypePrefixVideo) +} + +func IsMimeTypeVideo(mimeType MimeType) bool { + return strings.HasPrefix(mimeType.String(), MimeTypePrefixVideo) +} + +func IsMimeTypeSVCCapable(mimeType MimeType) bool { + switch mimeType { + case MimeTypeAV1, MimeTypeVP9: + return true + } + return false +} + +func IsMimeTypeStringSVCCapable(mime string) bool { + return IsMimeTypeSVCCapable(NormalizeMimeType(mime)) +} + +func IsMimeTypeStringRED(mime string) bool { + return NormalizeMimeType(mime) == MimeTypeRED +} + +func IsMimeTypeStringOpus(mime string) bool { + return NormalizeMimeType(mime) == MimeTypeOpus +} + +func IsMimeTypeStringPCMA(mime string) bool { + return NormalizeMimeType(mime) == MimeTypePCMA +} + +func IsMimeTypeStringPCMU(mime string) bool { + return NormalizeMimeType(mime) == MimeTypePCMU +} + +func IsMimeTypeStringRTX(mime string) bool { + return NormalizeMimeType(mime) == MimeTypeRTX +} + +func IsMimeTypeStringVP8(mime string) bool { + return NormalizeMimeType(mime) == MimeTypeVP8 +} + +func IsMimeTypeStringVP9(mime string) bool { + return NormalizeMimeType(mime) == MimeTypeVP9 +} + +func IsMimeTypeStringH264(mime string) bool { + return NormalizeMimeType(mime) == MimeTypeH264 +} From b8899c82fb7e39302c150524a7df9bc7dcb541b5 Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 19 Jan 2026 17:57:08 +0000 Subject: [PATCH 2/3] generated protobuf --- livekit/agent/livekit_agent_session.pb.go | 2 +- livekit/livekit_phone_number.pb.go | 2 +- livekit/livekit_phone_number.twirp.go | 153 +++++++++++----------- livekit/logger/options.pb.go | 2 +- 4 files changed, 80 insertions(+), 79 deletions(-) diff --git a/livekit/agent/livekit_agent_session.pb.go b/livekit/agent/livekit_agent_session.pb.go index e171671b..e7cb97e1 100644 --- a/livekit/agent/livekit_agent_session.pb.go +++ b/livekit/agent/livekit_agent_session.pb.go @@ -802,7 +802,7 @@ const file_agent_livekit_agent_session_proto_rawDesc = "" + "\n" + "\x06SYSTEM\x10\x01\x12\b\n" + "\x04USER\x10\x02\x12\r\n" + - "\tASSISTANT\x10\x03B+Z)github.com/livekit/protocol/livekit/agentb\x06proto3" + "\tASSISTANT\x10\x03BLZ)github.com/livekit/protocol/livekit/agent\xaa\x02\rLiveKit.Proto\xea\x02\x0eLiveKit::Protob\x06proto3" var ( file_agent_livekit_agent_session_proto_rawDescOnce sync.Once diff --git a/livekit/livekit_phone_number.pb.go b/livekit/livekit_phone_number.pb.go index 4a0de416..5d790672 100644 --- a/livekit/livekit_phone_number.pb.go +++ b/livekit/livekit_phone_number.pb.go @@ -1051,7 +1051,7 @@ const file_livekit_phone_number_proto_rawDesc = "" + "\x10ListPhoneNumbers\x12 .livekit.ListPhoneNumbersRequest\x1a!.livekit.ListPhoneNumbersResponse\"\x00\x12S\n" + "\x0eGetPhoneNumber\x12\x1e.livekit.GetPhoneNumberRequest\x1a\x1f.livekit.GetPhoneNumberResponse\"\x00\x12\\\n" + "\x11UpdatePhoneNumber\x12!.livekit.UpdatePhoneNumberRequest\x1a\".livekit.UpdatePhoneNumberResponse\"\x00\x12b\n" + - "\x13ReleasePhoneNumbers\x12#.livekit.ReleasePhoneNumbersRequest\x1a$.livekit.ReleasePhoneNumbersResponse\"\x00B%Z#github.com/livekit/protocol/livekitb\x06proto3" + "\x13ReleasePhoneNumbers\x12#.livekit.ReleasePhoneNumbersRequest\x1a$.livekit.ReleasePhoneNumbersResponse\"\x00BFZ#github.com/livekit/protocol/livekit\xaa\x02\rLiveKit.Proto\xea\x02\x0eLiveKit::Protob\x06proto3" var ( file_livekit_phone_number_proto_rawDescOnce sync.Once diff --git a/livekit/livekit_phone_number.twirp.go b/livekit/livekit_phone_number.twirp.go index fc4f0c61..0229abb6 100644 --- a/livekit/livekit_phone_number.twirp.go +++ b/livekit/livekit_phone_number.twirp.go @@ -1919,80 +1919,81 @@ func (s *phoneNumberServiceServer) PathPrefix() string { } var twirpFileDescriptor6 = []byte{ - // 1190 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x57, 0xdd, 0x6e, 0xe2, 0x46, - 0x14, 0x66, 0x20, 0x64, 0xc3, 0x81, 0x24, 0xec, 0xec, 0x4f, 0x1c, 0x67, 0xb3, 0x61, 0x9d, 0xb6, - 0x42, 0xb9, 0x20, 0xda, 0xec, 0x6a, 0xab, 0xa8, 0xbd, 0x28, 0x24, 0xce, 0x06, 0x95, 0x05, 0x6a, - 0x48, 0xdb, 0xad, 0x2a, 0x59, 0xc6, 0x4c, 0xc8, 0x68, 0x8d, 0xed, 0xda, 0xc3, 0xaa, 0x79, 0x83, - 0x55, 0xd5, 0x8b, 0xaa, 0xcf, 0xb3, 0xea, 0x0b, 0x54, 0xea, 0x33, 0xf4, 0x51, 0xaa, 0x19, 0x1b, - 0xc7, 0xc4, 0x36, 0xb9, 0x68, 0xa5, 0xde, 0xe1, 0x73, 0xbe, 0x73, 0xe6, 0xcc, 0x37, 0xdf, 0x9c, - 0x33, 0x80, 0x6c, 0xd1, 0xf7, 0xe4, 0x1d, 0x65, 0xba, 0x7b, 0xe5, 0xd8, 0x44, 0xb7, 0x67, 0xd3, - 0x11, 0xf1, 0x1a, 0xae, 0xe7, 0x30, 0x07, 0xdf, 0x0b, 0x7d, 0xf2, 0xde, 0xc4, 0x71, 0x26, 0x16, - 0x39, 0x14, 0xe6, 0xd1, 0xec, 0xf2, 0x90, 0xd1, 0x29, 0xf1, 0x99, 0x31, 0x75, 0x03, 0xa4, 0xfc, - 0x70, 0x9e, 0x65, 0xea, 0x8c, 0x89, 0xe5, 0x07, 0x56, 0xe5, 0x6f, 0x04, 0xdb, 0x03, 0x62, 0x78, - 0xe6, 0x55, 0x9f, 0x27, 0xef, 0x8a, 0xdc, 0xbe, 0x46, 0x7e, 0x9a, 0x11, 0x9f, 0xe1, 0x67, 0x50, - 0x31, 0x9d, 0x99, 0xcd, 0xbc, 0x6b, 0xdd, 0x74, 0xc6, 0x44, 0x42, 0x35, 0x54, 0x2f, 0x69, 0xe5, - 0xd0, 0x76, 0xe2, 0x8c, 0x09, 0xae, 0x41, 0xc9, 0xf0, 0x88, 0x11, 0xf8, 0xf3, 0xdc, 0x7f, 0x9e, - 0xd3, 0xd6, 0xb8, 0x89, 0xbb, 0x3f, 0x20, 0x84, 0xb7, 0xa1, 0x68, 0xd1, 0x29, 0x65, 0x52, 0xa1, - 0x86, 0xea, 0xc5, 0x73, 0xa4, 0x05, 0x9f, 0xdc, 0xf5, 0x25, 0x80, 0x6b, 0x4c, 0x88, 0xce, 0x9c, - 0x77, 0xc4, 0x96, 0x56, 0x6a, 0xa8, 0x5e, 0x3e, 0x92, 0x1a, 0x61, 0xa1, 0x8d, 0x21, 0xb7, 0xf6, - 0x8d, 0x09, 0xb5, 0x0d, 0x46, 0x1d, 0xfb, 0x3c, 0xaf, 0x95, 0x38, 0x5a, 0x98, 0x3f, 0x20, 0xd4, - 0xaa, 0x00, 0xe8, 0xd1, 0xda, 0xad, 0x35, 0x58, 0xd5, 0x45, 0xe2, 0xd6, 0x3a, 0x94, 0xf5, 0x9b, - 0xb4, 0xca, 0x2f, 0x08, 0xe4, 0xb4, 0x2d, 0xfa, 0xae, 0x63, 0xfb, 0x04, 0x1f, 0x40, 0x91, 0x32, - 0x32, 0xf5, 0x25, 0x54, 0x2b, 0xd4, 0xcb, 0x47, 0x0f, 0xa3, 0xe5, 0x63, 0x68, 0x2d, 0x80, 0xe0, - 0xaf, 0x60, 0xd3, 0x26, 0x3f, 0xb3, 0x58, 0x76, 0xb1, 0xe5, 0x25, 0x45, 0x6b, 0xeb, 0x3c, 0xa0, - 0x3f, 0x2f, 0x5b, 0xf9, 0x0d, 0x81, 0xdc, 0x9f, 0x79, 0xe6, 0x95, 0xe1, 0x93, 0xf8, 0x02, 0x21, - 0xe1, 0xfb, 0xb0, 0x1e, 0x3f, 0xe4, 0xa0, 0xa8, 0x92, 0x56, 0x71, 0x63, 0x95, 0xe3, 0x97, 0xf0, - 0xd0, 0xa7, 0xae, 0x3e, 0xa6, 0xbe, 0x6b, 0x30, 0xf3, 0x4a, 0xf7, 0x66, 0x16, 0xd1, 0xe9, 0x38, - 0x62, 0xff, 0xbe, 0x4f, 0xdd, 0xd3, 0xd0, 0xa9, 0xcd, 0x2c, 0xd2, 0x1e, 0x73, 0xb6, 0xb6, 0xe0, - 0x91, 0x9e, 0x16, 0xa6, 0x7c, 0x0f, 0x3b, 0xa9, 0x15, 0x85, 0xfc, 0x1c, 0xa7, 0x95, 0x94, 0xc5, - 0xd3, 0x42, 0xa1, 0xca, 0xef, 0x79, 0xd8, 0xea, 0x50, 0x9f, 0xa5, 0x49, 0x2b, 0x52, 0x05, 0x12, - 0xaa, 0xc8, 0xc5, 0x54, 0xf1, 0x0a, 0xd6, 0x7c, 0x66, 0xb0, 0x99, 0x4f, 0x7c, 0x29, 0x5f, 0x2b, - 0xd4, 0x37, 0x8e, 0xe4, 0xb4, 0xc5, 0x06, 0x02, 0xa3, 0x45, 0xd8, 0x5b, 0x6a, 0x2a, 0xdc, 0xa1, - 0x26, 0xb4, 0xa8, 0xa6, 0x4c, 0x56, 0x57, 0x04, 0xab, 0xf9, 0x0c, 0x56, 0xb3, 0x54, 0x97, 0x4d, - 0xf7, 0x5f, 0x08, 0xa4, 0x24, 0x29, 0xff, 0x87, 0x18, 0xf1, 0x1e, 0x94, 0x99, 0xc3, 0x0c, 0x4b, - 0x17, 0x17, 0x3a, 0xb8, 0x9f, 0x1a, 0x08, 0xd3, 0x09, 0xb7, 0x70, 0x39, 0x3a, 0x97, 0x97, 0x16, - 0xb5, 0x49, 0x08, 0x59, 0x11, 0x90, 0x4a, 0x68, 0x14, 0x20, 0xc5, 0x82, 0x47, 0xaf, 0x09, 0x4b, - 0x11, 0xf3, 0x03, 0xc8, 0xd3, 0x71, 0xd0, 0x33, 0xce, 0x73, 0x5a, 0x9e, 0x72, 0xc2, 0xf0, 0x67, - 0x50, 0x89, 0xcb, 0x29, 0x14, 0x2d, 0xd2, 0xca, 0x31, 0xe5, 0x70, 0x62, 0x8b, 0x50, 0xd0, 0xe9, - 0xb8, 0xb5, 0x09, 0xeb, 0x0b, 0x6d, 0x4f, 0xf9, 0x06, 0x1e, 0xdf, 0x5e, 0x2d, 0xe4, 0xee, 0xf3, - 0x5b, 0x99, 0x91, 0x20, 0x23, 0x9d, 0xc2, 0xf8, 0x6a, 0xca, 0x1f, 0x08, 0xa4, 0x0b, 0x77, 0x6c, - 0x30, 0xf2, 0x1f, 0x6f, 0x22, 0x53, 0x53, 0x85, 0xa5, 0x9a, 0xca, 0xd8, 0x7a, 0xb6, 0xa4, 0x86, - 0xb0, 0x9d, 0x52, 0xff, 0xbf, 0xa5, 0x65, 0x00, 0xb2, 0x46, 0x2c, 0xb2, 0xd8, 0x16, 0xa2, 0xfb, - 0x5b, 0x85, 0x02, 0x1d, 0xcf, 0xfb, 0x13, 0xff, 0x99, 0xec, 0x5d, 0xf9, 0x64, 0xef, 0x52, 0x76, - 0x61, 0x27, 0x35, 0x69, 0x50, 0xac, 0xf2, 0xb1, 0x08, 0xe5, 0x98, 0x03, 0x6f, 0xdc, 0xb0, 0xcf, - 0xb9, 0xe7, 0x8a, 0x25, 0xcf, 0x5f, 0xbd, 0xd4, 0x2f, 0x1d, 0x6f, 0x6a, 0xb0, 0x80, 0x77, 0x0d, - 0xb8, 0xe9, 0x4c, 0x58, 0x12, 0x13, 0xab, 0x90, 0x9c, 0x58, 0x3b, 0xf1, 0x89, 0x25, 0x6e, 0xf7, - 0xcd, 0xbc, 0xc2, 0xc7, 0x50, 0x0e, 0xca, 0xd7, 0xd9, 0xb5, 0x4b, 0xa4, 0x62, 0x0d, 0xd5, 0x37, - 0x62, 0x17, 0x2a, 0x56, 0xdb, 0xf0, 0xda, 0x25, 0x1a, 0xd8, 0xd1, 0x6f, 0x2c, 0xc3, 0x9a, 0xe5, - 0x98, 0x86, 0x45, 0xd9, 0xb5, 0xb4, 0x1a, 0xa4, 0x9d, 0x7f, 0xe3, 0xc7, 0xb0, 0xea, 0x91, 0x09, - 0x75, 0x6c, 0xe9, 0x9e, 0xf0, 0x84, 0x5f, 0x78, 0x17, 0xc0, 0x77, 0x8d, 0xa9, 0xee, 0x9b, 0x8e, - 0x47, 0xa4, 0xb5, 0x1a, 0xaa, 0x23, 0xad, 0xc4, 0x2d, 0x03, 0x6e, 0xc0, 0xc7, 0x00, 0xa6, 0x47, - 0x0c, 0x46, 0xc6, 0xba, 0xc1, 0xa4, 0x92, 0x38, 0x39, 0xb9, 0x11, 0x4c, 0xfa, 0xc6, 0x7c, 0xd2, - 0x37, 0x86, 0xf3, 0x49, 0xaf, 0x95, 0x42, 0x74, 0x93, 0xf1, 0xd0, 0x99, 0xd0, 0x84, 0x08, 0x85, - 0xbb, 0x43, 0x43, 0x74, 0x93, 0x61, 0x05, 0x2a, 0xa6, 0xe1, 0x1a, 0x23, 0x6a, 0x51, 0x46, 0x89, - 0x2f, 0x95, 0x83, 0x73, 0x8c, 0xdb, 0xf0, 0x11, 0xac, 0x06, 0x7d, 0x57, 0xaa, 0x08, 0x8a, 0x96, - 0x75, 0xe8, 0x10, 0x89, 0xbf, 0x80, 0xb2, 0xe1, 0xfb, 0x74, 0x62, 0x07, 0x35, 0xad, 0xdf, 0x59, - 0x13, 0xcc, 0xe1, 0x4d, 0xc6, 0x83, 0xbd, 0x40, 0x38, 0x22, 0x78, 0xe3, 0xee, 0xe0, 0x39, 0xbc, - 0xc9, 0xf0, 0x8b, 0x8c, 0x7b, 0xb8, 0xc9, 0x0f, 0xa3, 0x95, 0x97, 0x50, 0xca, 0x4d, 0xc4, 0xcf, - 0xe1, 0x51, 0x5a, 0x90, 0x2f, 0x55, 0x05, 0x1f, 0x38, 0x11, 0xe1, 0x1f, 0x7c, 0x44, 0x70, 0x3f, - 0xb1, 0x7f, 0xbc, 0x0f, 0x7b, 0xfd, 0xf3, 0x5e, 0x57, 0xd5, 0xbb, 0x17, 0x6f, 0x5a, 0xaa, 0xa6, - 0x0f, 0x86, 0xcd, 0xe1, 0xc5, 0x40, 0xbf, 0xe8, 0x0e, 0xfa, 0xea, 0x49, 0xfb, 0xac, 0xad, 0x9e, - 0x56, 0x73, 0xf8, 0x29, 0xc8, 0x69, 0xa0, 0xe6, 0xc9, 0xb0, 0xfd, 0xad, 0x5a, 0x45, 0x78, 0x0f, - 0x76, 0xd2, 0xfc, 0x7d, 0xb5, 0x7b, 0xda, 0xee, 0xbe, 0xae, 0xe6, 0x71, 0x0d, 0x9e, 0xa4, 0x01, - 0x34, 0xb5, 0xa3, 0x36, 0x07, 0xea, 0x69, 0xb5, 0x90, 0x95, 0xa2, 0x77, 0x76, 0xd6, 0x69, 0x77, - 0xd5, 0xea, 0xca, 0xc1, 0xaf, 0x08, 0x36, 0x6f, 0x29, 0x1c, 0xef, 0xc2, 0xf6, 0x42, 0xd0, 0xf0, - 0x6d, 0x5f, 0xd5, 0x2f, 0xba, 0x5f, 0x77, 0x7b, 0xdf, 0x75, 0xab, 0x39, 0xfc, 0x04, 0xa4, 0xa4, - 0xfb, 0x4d, 0xaf, 0xd5, 0xee, 0xf0, 0xa2, 0x77, 0x60, 0x2b, 0xe9, 0xed, 0xf4, 0x4e, 0x9a, 0x9d, - 0x6a, 0x3e, 0x51, 0x8e, 0x70, 0x0e, 0x7b, 0x9d, 0x8e, 0x7e, 0xa6, 0xa9, 0x6a, 0xb5, 0x70, 0xf4, - 0xe7, 0x0a, 0xe0, 0x38, 0x9b, 0xc4, 0x7b, 0x4f, 0x4d, 0x82, 0x75, 0xc0, 0xc9, 0xe7, 0x1c, 0x56, - 0x22, 0x01, 0x66, 0x3e, 0x67, 0xe5, 0xfd, 0xa5, 0x98, 0xb0, 0x05, 0xe5, 0xf0, 0x08, 0x1e, 0xa4, - 0x3c, 0x88, 0xf0, 0x4d, 0x74, 0xf6, 0x03, 0x4e, 0xfe, 0x64, 0x39, 0x28, 0x5a, 0xe3, 0x2d, 0x54, - 0x6f, 0x3f, 0x02, 0x70, 0x2d, 0x8a, 0xcd, 0x78, 0x34, 0xc9, 0xcf, 0x96, 0x20, 0xa2, 0xd4, 0x03, - 0xd8, 0x58, 0x9c, 0x90, 0xf8, 0x69, 0x14, 0x96, 0x3a, 0xa8, 0xe5, 0xbd, 0x4c, 0x7f, 0x94, 0xf4, - 0x47, 0xb8, 0x9f, 0x18, 0x31, 0xf8, 0xa6, 0x9c, 0xac, 0xf1, 0x29, 0x2b, 0xcb, 0x20, 0x71, 0xc6, - 0x53, 0xa6, 0x42, 0x8c, 0xf1, 0xec, 0x41, 0x14, 0x63, 0x7c, 0xd9, 0x60, 0xc9, 0xb5, 0x3e, 0xfd, - 0x61, 0x7f, 0x42, 0xd9, 0xd5, 0x6c, 0xd4, 0x30, 0x9d, 0xe9, 0x61, 0x18, 0x13, 0xfc, 0x5d, 0x32, - 0x1d, 0x6b, 0x6e, 0x18, 0xad, 0x0a, 0xcb, 0x8b, 0x7f, 0x02, 0x00, 0x00, 0xff, 0xff, 0xc8, 0xbb, - 0xfd, 0x42, 0x75, 0x0d, 0x00, 0x00, + // 1213 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x57, 0x5d, 0x6e, 0xdb, 0x46, + 0x10, 0xd6, 0x52, 0xb6, 0x63, 0x8d, 0x64, 0x5b, 0xd9, 0xfc, 0xd1, 0x74, 0x12, 0x2b, 0x74, 0x51, + 0x08, 0x79, 0x50, 0x10, 0x27, 0x48, 0x91, 0xb4, 0x0f, 0x95, 0x6c, 0x3a, 0x16, 0xa2, 0x48, 0x2a, + 0x25, 0xb7, 0x4d, 0x51, 0x80, 0xa0, 0xa8, 0xb5, 0xbc, 0x08, 0x45, 0xb2, 0xe4, 0xca, 0xa8, 0x6f, + 0x10, 0x14, 0x7d, 0x28, 0x7a, 0x8c, 0x9e, 0x21, 0xe8, 0x05, 0x0a, 0xf4, 0x0c, 0x7d, 0xee, 0x29, + 0x8a, 0x5d, 0x52, 0x34, 0x65, 0x92, 0xf2, 0x43, 0x0b, 0xf4, 0x4d, 0x9c, 0xf9, 0x66, 0x76, 0xf6, + 0xdb, 0x6f, 0x67, 0x56, 0xa0, 0xd8, 0xf4, 0x9c, 0xbc, 0xa7, 0xcc, 0xf0, 0xce, 0x5c, 0x87, 0x18, + 0xce, 0x6c, 0x3a, 0x22, 0x7e, 0xc3, 0xf3, 0x5d, 0xe6, 0xe2, 0x1b, 0x91, 0x4f, 0xd9, 0x9d, 0xb8, + 0xee, 0xc4, 0x26, 0x4f, 0x84, 0x79, 0x34, 0x3b, 0x7d, 0xc2, 0xe8, 0x94, 0x04, 0xcc, 0x9c, 0x7a, + 0x21, 0x52, 0xb9, 0x3d, 0xcf, 0x32, 0x75, 0xc7, 0xc4, 0x0e, 0x42, 0xab, 0xfa, 0x17, 0x82, 0xed, + 0x01, 0x31, 0x7d, 0xeb, 0xac, 0xcf, 0x93, 0x77, 0x45, 0xee, 0x40, 0x27, 0x3f, 0xcc, 0x48, 0xc0, + 0xf0, 0x23, 0xa8, 0x58, 0xee, 0xcc, 0x61, 0xfe, 0x85, 0x61, 0xb9, 0x63, 0x22, 0xa3, 0x1a, 0xaa, + 0x97, 0xf4, 0x72, 0x64, 0x3b, 0x70, 0xc7, 0x04, 0xd7, 0xa0, 0x64, 0xfa, 0xc4, 0x0c, 0xfd, 0x12, + 0xf7, 0x1f, 0x17, 0xf4, 0x75, 0x6e, 0xe2, 0xee, 0x0f, 0x08, 0xe1, 0x6d, 0x58, 0xb5, 0xe9, 0x94, + 0x32, 0xb9, 0x58, 0x43, 0xf5, 0xd5, 0x63, 0xa4, 0x87, 0x9f, 0xdc, 0xf5, 0x05, 0x80, 0x67, 0x4e, + 0x88, 0xc1, 0xdc, 0xf7, 0xc4, 0x91, 0x57, 0x6a, 0xa8, 0x5e, 0xde, 0x97, 0x1b, 0x51, 0xa1, 0x8d, + 0x21, 0xb7, 0xf6, 0xcd, 0x09, 0x75, 0x4c, 0x46, 0x5d, 0xe7, 0x58, 0xd2, 0x4b, 0x1c, 0x2d, 0xcc, + 0x1f, 0x10, 0x6a, 0x55, 0x00, 0x8c, 0x78, 0xed, 0xd6, 0x3a, 0xac, 0x19, 0x22, 0x71, 0x6b, 0x03, + 0xca, 0xc6, 0x65, 0x5a, 0xf5, 0x27, 0x04, 0x4a, 0xd6, 0x16, 0x03, 0xcf, 0x75, 0x02, 0x82, 0x1f, + 0xc3, 0x2a, 0x65, 0x64, 0x1a, 0xc8, 0xa8, 0x56, 0xac, 0x97, 0xf7, 0x6f, 0xc7, 0xcb, 0x27, 0xd0, + 0x7a, 0x08, 0xc1, 0x5f, 0xc2, 0x96, 0x43, 0x7e, 0x64, 0x89, 0xec, 0x62, 0xcb, 0x4b, 0x8a, 0xd6, + 0x37, 0x78, 0x40, 0x7f, 0x5e, 0xb6, 0xfa, 0x0b, 0x02, 0xa5, 0x3f, 0xf3, 0xad, 0x33, 0x33, 0x20, + 0xc9, 0x05, 0x22, 0xc2, 0xf7, 0x60, 0x23, 0x79, 0xc8, 0x61, 0x51, 0x25, 0xbd, 0xe2, 0x25, 0x2a, + 0xc7, 0xcf, 0xe1, 0x76, 0x40, 0x3d, 0x63, 0x4c, 0x03, 0xcf, 0x64, 0xd6, 0x99, 0xe1, 0xcf, 0x6c, + 0x62, 0xd0, 0x71, 0xcc, 0xfe, 0xcd, 0x80, 0x7a, 0x87, 0x91, 0x53, 0x9f, 0xd9, 0xa4, 0x3d, 0xe6, + 0x6c, 0xdd, 0x83, 0x3b, 0x46, 0x56, 0x98, 0xfa, 0x2d, 0xec, 0x64, 0x56, 0x14, 0xf1, 0xf3, 0x32, + 0xab, 0xa4, 0x3c, 0x9e, 0x16, 0x0a, 0x55, 0x7f, 0x95, 0xe0, 0x5e, 0x87, 0x06, 0x2c, 0x4b, 0x5a, + 0xb1, 0x2a, 0x90, 0x50, 0x45, 0x21, 0xa1, 0x8a, 0x17, 0xb0, 0x1e, 0x30, 0x93, 0xcd, 0x02, 0x12, + 0xc8, 0x52, 0xad, 0x58, 0xdf, 0xdc, 0x57, 0xb2, 0x16, 0x1b, 0x08, 0x8c, 0x1e, 0x63, 0xaf, 0xa8, + 0xa9, 0x78, 0x8d, 0x9a, 0xd0, 0xa2, 0x9a, 0x72, 0x59, 0x5d, 0x11, 0xac, 0x4a, 0x39, 0xac, 0xe6, + 0xa9, 0x2e, 0x9f, 0xee, 0x3f, 0x11, 0xc8, 0x69, 0x52, 0xfe, 0x0f, 0x31, 0xe2, 0x5d, 0x28, 0x33, + 0x97, 0x99, 0xb6, 0x21, 0x2e, 0x74, 0x78, 0x3f, 0x75, 0x10, 0xa6, 0x03, 0x6e, 0xe1, 0x72, 0x74, + 0x4f, 0x4f, 0x6d, 0xea, 0x90, 0x08, 0xb2, 0x22, 0x20, 0x95, 0xc8, 0x28, 0x40, 0xaa, 0x0d, 0x77, + 0x5e, 0x13, 0x96, 0x21, 0xe6, 0x5b, 0x20, 0xd1, 0x71, 0xd8, 0x33, 0x8e, 0x0b, 0xba, 0x44, 0x39, + 0x61, 0xf8, 0x53, 0xa8, 0x24, 0xe5, 0x14, 0x89, 0x16, 0xe9, 0xe5, 0x84, 0x72, 0x38, 0xb1, 0xab, + 0x50, 0x34, 0xe8, 0xb8, 0xb5, 0x05, 0x1b, 0x0b, 0x6d, 0x4f, 0xfd, 0x0a, 0xee, 0x5e, 0x5d, 0x2d, + 0xe2, 0xee, 0xb3, 0x2b, 0x99, 0x91, 0x20, 0x23, 0x9b, 0xc2, 0xe4, 0x6a, 0xea, 0xef, 0x08, 0xe4, + 0x13, 0x6f, 0x6c, 0x32, 0xf2, 0x1f, 0x6f, 0x22, 0x57, 0x53, 0xc5, 0xa5, 0x9a, 0xca, 0xd9, 0x7a, + 0xbe, 0xa4, 0x86, 0xb0, 0x9d, 0x51, 0xff, 0xbf, 0xa5, 0x65, 0x00, 0x8a, 0x4e, 0x6c, 0xb2, 0xd8, + 0x16, 0xe2, 0xfb, 0x5b, 0x85, 0x22, 0x1d, 0xcf, 0xfb, 0x13, 0xff, 0x99, 0xee, 0x5d, 0x52, 0xba, + 0x77, 0xa9, 0x0f, 0x60, 0x27, 0x33, 0x69, 0x58, 0xac, 0xfa, 0x71, 0x15, 0xca, 0x09, 0x07, 0xde, + 0xbc, 0x64, 0x9f, 0x73, 0xcf, 0x15, 0x4b, 0x9e, 0xbe, 0x78, 0x6e, 0x9c, 0xba, 0xfe, 0xd4, 0x64, + 0x21, 0xef, 0x3a, 0x70, 0xd3, 0x91, 0xb0, 0xa4, 0x26, 0x56, 0x31, 0x3d, 0xb1, 0x76, 0x92, 0x13, + 0x4b, 0xdc, 0xee, 0xcb, 0x79, 0x85, 0x5f, 0x42, 0x39, 0x2c, 0xdf, 0x60, 0x17, 0x1e, 0x91, 0x57, + 0x6b, 0xa8, 0xbe, 0x99, 0xb8, 0x50, 0x89, 0xda, 0x86, 0x17, 0x1e, 0xd1, 0xc1, 0x89, 0x7f, 0x63, + 0x05, 0xd6, 0x6d, 0xd7, 0x32, 0x6d, 0xca, 0x2e, 0xe4, 0xb5, 0x30, 0xed, 0xfc, 0x1b, 0xdf, 0x85, + 0x35, 0x9f, 0x4c, 0xa8, 0xeb, 0xc8, 0x37, 0x84, 0x27, 0xfa, 0xc2, 0x0f, 0x00, 0x02, 0xcf, 0x9c, + 0x1a, 0x81, 0xe5, 0xfa, 0x44, 0x5e, 0xaf, 0xa1, 0x3a, 0xd2, 0x4b, 0xdc, 0x32, 0xe0, 0x06, 0xfc, + 0x12, 0xc0, 0xf2, 0x89, 0xc9, 0xc8, 0xd8, 0x30, 0x99, 0x5c, 0x12, 0x27, 0xa7, 0x34, 0xc2, 0x49, + 0xdf, 0x98, 0x4f, 0xfa, 0xc6, 0x70, 0x3e, 0xe9, 0xf5, 0x52, 0x84, 0x6e, 0x32, 0x1e, 0x3a, 0x13, + 0x9a, 0x10, 0xa1, 0x70, 0x7d, 0x68, 0x84, 0x6e, 0x32, 0xac, 0x42, 0xc5, 0x32, 0x3d, 0x73, 0x44, + 0x6d, 0xca, 0x28, 0x09, 0xe4, 0x72, 0x78, 0x8e, 0x49, 0x1b, 0xde, 0x87, 0xb5, 0xb0, 0xef, 0xca, + 0x15, 0x41, 0xd1, 0xb2, 0x0e, 0x1d, 0x21, 0xf1, 0xe7, 0x50, 0x36, 0x83, 0x80, 0x4e, 0x9c, 0xb0, + 0xa6, 0x8d, 0x6b, 0x6b, 0x82, 0x39, 0xbc, 0xc9, 0x78, 0xb0, 0x1f, 0x0a, 0x47, 0x04, 0x6f, 0x5e, + 0x1f, 0x3c, 0x87, 0x37, 0x19, 0x7e, 0x96, 0x73, 0x0f, 0xb7, 0xf8, 0x61, 0xb4, 0x24, 0x19, 0x65, + 0xdc, 0x44, 0xfc, 0x14, 0xee, 0x64, 0x05, 0x05, 0x72, 0x55, 0xf0, 0x81, 0x53, 0x11, 0xc1, 0xe3, + 0x8f, 0x08, 0x6e, 0xa6, 0xf6, 0x8f, 0xf7, 0x60, 0xb7, 0x7f, 0xdc, 0xeb, 0x6a, 0x46, 0xf7, 0xe4, + 0x6d, 0x4b, 0xd3, 0x8d, 0xc1, 0xb0, 0x39, 0x3c, 0x19, 0x18, 0x27, 0xdd, 0x41, 0x5f, 0x3b, 0x68, + 0x1f, 0xb5, 0xb5, 0xc3, 0x6a, 0x01, 0x3f, 0x04, 0x25, 0x0b, 0xd4, 0x3c, 0x18, 0xb6, 0xbf, 0xd6, + 0xaa, 0x08, 0xef, 0xc2, 0x4e, 0x96, 0xbf, 0xaf, 0x75, 0x0f, 0xdb, 0xdd, 0xd7, 0x55, 0x09, 0xd7, + 0xe0, 0x7e, 0x16, 0x40, 0xd7, 0x3a, 0x5a, 0x73, 0xa0, 0x1d, 0x56, 0x8b, 0x79, 0x29, 0x7a, 0x47, + 0x47, 0x9d, 0x76, 0x57, 0xab, 0xae, 0x3c, 0xfe, 0x19, 0xc1, 0xd6, 0x15, 0x85, 0xe3, 0x07, 0xb0, + 0xbd, 0x10, 0x34, 0x7c, 0xd7, 0xd7, 0x8c, 0x93, 0xee, 0x9b, 0x6e, 0xef, 0x9b, 0x6e, 0xb5, 0x80, + 0xef, 0x83, 0x9c, 0x76, 0xbf, 0xed, 0xb5, 0xda, 0x1d, 0x5e, 0xf4, 0x0e, 0xdc, 0x4b, 0x7b, 0x3b, + 0xbd, 0x83, 0x66, 0xa7, 0x2a, 0xa5, 0xca, 0x11, 0xce, 0x61, 0xaf, 0xd3, 0x31, 0x8e, 0x74, 0x4d, + 0xab, 0x16, 0xf7, 0xff, 0x58, 0x01, 0x9c, 0x64, 0x93, 0xf8, 0xe7, 0xd4, 0x22, 0xd8, 0x00, 0x9c, + 0x7e, 0xce, 0x61, 0x35, 0x16, 0x60, 0xee, 0x73, 0x56, 0xd9, 0x5b, 0x8a, 0x89, 0x5a, 0x50, 0x01, + 0x8f, 0xe0, 0x56, 0xc6, 0x83, 0x08, 0x5f, 0x46, 0xe7, 0x3f, 0xe0, 0x94, 0x4f, 0x96, 0x83, 0xe2, + 0x35, 0xde, 0x41, 0xf5, 0xea, 0x23, 0x00, 0xd7, 0xe2, 0xd8, 0x9c, 0x47, 0x93, 0xf2, 0x68, 0x09, + 0x22, 0x4e, 0x3d, 0x80, 0xcd, 0xc5, 0x09, 0x89, 0x1f, 0xc6, 0x61, 0x99, 0x83, 0x5a, 0xd9, 0xcd, + 0xf5, 0xc7, 0x49, 0xbf, 0x87, 0x9b, 0xa9, 0x11, 0x83, 0x2f, 0xcb, 0xc9, 0x1b, 0x9f, 0x8a, 0xba, + 0x0c, 0x92, 0x64, 0x3c, 0x63, 0x2a, 0x24, 0x18, 0xcf, 0x1f, 0x44, 0x09, 0xc6, 0x97, 0x0d, 0x96, + 0x42, 0xeb, 0xe8, 0xbb, 0xbd, 0x09, 0x65, 0x67, 0xb3, 0x51, 0xc3, 0x72, 0xa7, 0x4f, 0xa2, 0x98, + 0xf0, 0xef, 0x92, 0xe5, 0xda, 0x73, 0xc3, 0x6f, 0xd2, 0x46, 0x87, 0x9e, 0x93, 0x37, 0xfc, 0x00, + 0xb9, 0xeb, 0x6f, 0x69, 0x33, 0xfa, 0x7e, 0xf5, 0x4a, 0x18, 0x46, 0x6b, 0x22, 0xe4, 0xd9, 0x3f, + 0x01, 0x00, 0x00, 0xff, 0xff, 0xcd, 0x27, 0xeb, 0x6b, 0x96, 0x0d, 0x00, 0x00, } diff --git a/livekit/logger/options.pb.go b/livekit/logger/options.pb.go index caa4bdbf..53b675f0 100644 --- a/livekit/logger/options.pb.go +++ b/livekit/logger/options.pb.go @@ -54,7 +54,7 @@ const file_logger_options_proto_rawDesc = "" + "\n" + "\x14logger/options.proto\x12\x06logger\x1a google/protobuf/descriptor.proto:7\n" + "\x06redact\x12\x1d.google.protobuf.FieldOptions\x18\xc1\xcd\x05 \x01(\bR\x06redact:D\n" + - "\rredact_format\x12\x1d.google.protobuf.FieldOptions\x18\xc2\xcd\x05 \x01(\tR\fredactFormatB,Z*github.com/livekit/protocol/livekit/loggerb\x06proto3" + "\rredact_format\x12\x1d.google.protobuf.FieldOptions\x18\xc2\xcd\x05 \x01(\tR\fredactFormatBMZ*github.com/livekit/protocol/livekit/logger\xaa\x02\rLiveKit.Proto\xea\x02\x0eLiveKit::Protob\x06proto3" var file_logger_options_proto_goTypes = []any{ (*descriptorpb.FieldOptions)(nil), // 0: google.protobuf.FieldOptions From 9950768a4cd3a69598d51d188bde75fc5ece90b0 Mon Sep 17 00:00:00 2001 From: Anunay Maheshwari Date: Tue, 20 Jan 2026 01:01:15 +0530 Subject: [PATCH 3/3] use user supplied fmtp if available, log warning if unknown combination --- codecs/codecs.go | 46 +++++++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/codecs/codecs.go b/codecs/codecs.go index dddaaadd..3f3ce8a9 100644 --- a/codecs/codecs.go +++ b/codecs/codecs.go @@ -18,6 +18,7 @@ import ( "strings" "github.com/livekit/protocol/livekit" + "github.com/livekit/protocol/logger" "github.com/pion/webrtc/v4" ) @@ -147,34 +148,28 @@ var ( } ) -func mergeFmtpLines(defaultFmtp, inputFmtp string) string { - if inputFmtp == "" { - return defaultFmtp +func areFmtpLinesEqual(a, b string) bool { + if a == b { + return true } - if defaultFmtp == "" { - return inputFmtp - } - - var result strings.Builder - result.WriteString(defaultFmtp) - defaultKeys := make(map[string]struct{}) - for _, param := range strings.Split(defaultFmtp, ";") { - if key, _, found := strings.Cut(param, "="); found { - defaultKeys[key] = struct{}{} + paramsA := make(map[string]string) + for _, param := range strings.Split(a, ";") { + if key, value, found := strings.Cut(param, "="); found { + paramsA[key] = value } } - for _, param := range strings.Split(inputFmtp, ";") { - if key, _, found := strings.Cut(param, "="); found { - if _, exists := defaultKeys[key]; !exists { - result.WriteByte(';') - result.WriteString(param) + count := 0 + for _, param := range strings.Split(b, ";") { + if key, value, found := strings.Cut(param, "="); found { + if paramsA[key] != value { + return false } + count++ } } - - return result.String() + return count == len(paramsA) } func ToWebrtcCodecParameters(codec *livekit.Codec) webrtc.RTPCodecParameters { @@ -216,6 +211,15 @@ func ToWebrtcCodecParameters(codec *livekit.Codec) webrtc.RTPCodecParameters { return webrtc.RTPCodecParameters{} } - params.SDPFmtpLine = mergeFmtpLines(params.SDPFmtpLine, fmtp) + if fmtp != "" && !areFmtpLinesEqual(fmtp, params.SDPFmtpLine) { + logger.Warnw("non-standard fmtp, may not be supported", + nil, + "mime", codec.GetMime(), + "fmtp", fmtp, + "supportedFmtp", params.SDPFmtpLine, + ) + params.SDPFmtpLine = fmtp + } + return params }