227 lines
6.0 KiB
Go
227 lines
6.0 KiB
Go
// 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/codecs/mime"
|
|
"github.com/livekit/protocol/livekit"
|
|
"github.com/livekit/protocol/logger"
|
|
"github.com/pion/webrtc/v4"
|
|
)
|
|
|
|
var (
|
|
OpusCodecParameters = webrtc.RTPCodecParameters{
|
|
RTPCodecCapability: webrtc.RTPCodecCapability{
|
|
MimeType: mime.MimeTypeOpus.String(),
|
|
ClockRate: 48000,
|
|
Channels: 2,
|
|
SDPFmtpLine: "minptime=10;useinbandfec=1",
|
|
},
|
|
PayloadType: 111,
|
|
}
|
|
|
|
RedCodecParameters = webrtc.RTPCodecParameters{
|
|
RTPCodecCapability: webrtc.RTPCodecCapability{
|
|
MimeType: mime.MimeTypeRED.String(),
|
|
ClockRate: 48000,
|
|
Channels: 2,
|
|
SDPFmtpLine: "111/111",
|
|
},
|
|
PayloadType: 63,
|
|
}
|
|
|
|
PCMUCodecParameters = webrtc.RTPCodecParameters{
|
|
RTPCodecCapability: webrtc.RTPCodecCapability{
|
|
MimeType: mime.MimeTypePCMU.String(),
|
|
ClockRate: 8000,
|
|
},
|
|
PayloadType: 0,
|
|
}
|
|
|
|
PCMACodecParameters = webrtc.RTPCodecParameters{
|
|
RTPCodecCapability: webrtc.RTPCodecCapability{
|
|
MimeType: mime.MimeTypePCMA.String(),
|
|
ClockRate: 8000,
|
|
},
|
|
PayloadType: 8,
|
|
}
|
|
|
|
VideoRTXCodecParameters = webrtc.RTPCodecParameters{
|
|
RTPCodecCapability: webrtc.RTPCodecCapability{
|
|
MimeType: mime.MimeTypeRTX.String(),
|
|
ClockRate: 90000,
|
|
},
|
|
}
|
|
|
|
VP8CodecParameters = webrtc.RTPCodecParameters{
|
|
RTPCodecCapability: webrtc.RTPCodecCapability{
|
|
MimeType: mime.MimeTypeVP8.String(),
|
|
ClockRate: 90000,
|
|
},
|
|
PayloadType: 96,
|
|
}
|
|
|
|
VP9ProfileId0CodecParameters = webrtc.RTPCodecParameters{
|
|
RTPCodecCapability: webrtc.RTPCodecCapability{
|
|
MimeType: mime.MimeTypeVP9.String(),
|
|
ClockRate: 90000,
|
|
SDPFmtpLine: "profile-id=0",
|
|
},
|
|
PayloadType: 98,
|
|
}
|
|
|
|
VP9ProfileId1CodecParameters = webrtc.RTPCodecParameters{
|
|
RTPCodecCapability: webrtc.RTPCodecCapability{
|
|
MimeType: mime.MimeTypeVP9.String(),
|
|
ClockRate: 90000,
|
|
SDPFmtpLine: "profile-id=1",
|
|
},
|
|
PayloadType: 100,
|
|
}
|
|
|
|
H264ProfileLevelId42e01fPacketizationMode0CodecParameters = webrtc.RTPCodecParameters{
|
|
RTPCodecCapability: webrtc.RTPCodecCapability{
|
|
MimeType: mime.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: mime.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: mime.MimeTypeH264.String(),
|
|
ClockRate: 90000,
|
|
SDPFmtpLine: H264HighProfileFmtp,
|
|
},
|
|
PayloadType: 123,
|
|
}
|
|
|
|
AV1CodecParameters = webrtc.RTPCodecParameters{
|
|
RTPCodecCapability: webrtc.RTPCodecCapability{
|
|
MimeType: mime.MimeTypeAV1.String(),
|
|
ClockRate: 90000,
|
|
},
|
|
PayloadType: 35,
|
|
}
|
|
|
|
H265CodecParameters = webrtc.RTPCodecParameters{
|
|
RTPCodecCapability: webrtc.RTPCodecCapability{
|
|
MimeType: mime.MimeTypeH265.String(),
|
|
ClockRate: 90000,
|
|
},
|
|
PayloadType: 116,
|
|
}
|
|
|
|
VideoCodecsParameters = []webrtc.RTPCodecParameters{
|
|
VP8CodecParameters,
|
|
VP9ProfileId0CodecParameters,
|
|
VP9ProfileId1CodecParameters,
|
|
H264ProfileLevelId42e01fPacketizationMode0CodecParameters,
|
|
H264ProfileLevelId42e01fPacketizationMode1CodecParameters,
|
|
H264HighProfileCodecParameters,
|
|
AV1CodecParameters,
|
|
H265CodecParameters,
|
|
}
|
|
)
|
|
|
|
func areFmtpLinesEqual(a, b string) bool {
|
|
if a == b {
|
|
return true
|
|
}
|
|
|
|
paramsA := make(map[string]string)
|
|
for _, param := range strings.Split(a, ";") {
|
|
if key, value, found := strings.Cut(param, "="); found {
|
|
paramsA[key] = value
|
|
}
|
|
}
|
|
|
|
count := 0
|
|
for _, param := range strings.Split(b, ";") {
|
|
if key, value, found := strings.Cut(param, "="); found {
|
|
if paramsA[key] != value {
|
|
return false
|
|
}
|
|
count++
|
|
}
|
|
}
|
|
return count == len(paramsA)
|
|
}
|
|
|
|
func ToWebrtcCodecParameters(codec *livekit.Codec) webrtc.RTPCodecParameters {
|
|
fmtp := codec.GetFmtpLine()
|
|
var params webrtc.RTPCodecParameters
|
|
|
|
switch mime.NormalizeMimeType(codec.GetMime()) {
|
|
case mime.MimeTypeOpus:
|
|
params = OpusCodecParameters
|
|
case mime.MimeTypeRED:
|
|
params = RedCodecParameters
|
|
case mime.MimeTypePCMU:
|
|
params = PCMUCodecParameters
|
|
case mime.MimeTypePCMA:
|
|
params = PCMACodecParameters
|
|
case mime.MimeTypeRTX:
|
|
params = VideoRTXCodecParameters
|
|
case mime.MimeTypeVP8:
|
|
params = VP8CodecParameters
|
|
case mime.MimeTypeVP9:
|
|
if strings.Contains(fmtp, "profile-id=1") {
|
|
params = VP9ProfileId1CodecParameters
|
|
} else {
|
|
params = VP9ProfileId0CodecParameters
|
|
}
|
|
case mime.MimeTypeAV1:
|
|
params = AV1CodecParameters
|
|
case mime.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 mime.MimeTypeH265:
|
|
params = H265CodecParameters
|
|
default:
|
|
return webrtc.RTPCodecParameters{}
|
|
}
|
|
|
|
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
|
|
}
|