Files
livekit/pkg/rtc/mediaengine.go
2020-11-13 12:31:01 -08:00

102 lines
3.0 KiB
Go

package rtc
import (
"fmt"
"strconv"
"strings"
"github.com/pion/sdp/v3"
"github.com/pion/webrtc/v3"
)
const (
mediaNameAudio = "audio"
mediaNameVideo = "video"
)
// MediaEngine handles stream codecs
type MediaEngine struct {
webrtc.MediaEngine
feedbackTypes []webrtc.RTCPFeedback
TCCExt int
}
// PopulateFromSDP finds all codecs in sd and adds them to m, using the dynamic
// payload types and parameters from sd.
// PopulateFromSDP is intended for use when answering a request.
// The offerer sets the PayloadTypes for the connection.
// PopulateFromSDP allows an answerer to properly match the PayloadTypes from the offerer.
// A MediaEngine populated by PopulateFromSDP should be used only for a single session.
func (e *MediaEngine) PopulateFromSDP(sd webrtc.SessionDescription) error {
s := sdp.SessionDescription{}
if err := s.Unmarshal([]byte(sd.SDP)); err != nil {
return err
}
for _, md := range s.MediaDescriptions {
if md.MediaName.Media != mediaNameAudio && md.MediaName.Media != mediaNameVideo {
continue
}
for _, att := range md.Attributes {
if att.Key == sdp.AttrKeyExtMap && strings.HasSuffix(att.Value, sdp.TransportCCURI) {
e.TCCExt, _ = strconv.Atoi(att.Value[:1])
break
}
}
for _, format := range md.MediaName.Formats {
pt, err := strconv.Atoi(format)
if err != nil {
return fmt.Errorf("format parse error")
}
payloadType := uint8(pt)
payloadCodec, err := s.GetCodecForPayloadType(payloadType)
if err != nil {
return fmt.Errorf("could not find codec for payload type %d", payloadType)
}
var codec *webrtc.RTPCodec
switch {
case strings.EqualFold(payloadCodec.Name, webrtc.Opus):
codec = webrtc.NewRTPOpusCodec(payloadType, payloadCodec.ClockRate)
case strings.EqualFold(payloadCodec.Name, webrtc.VP8):
codec = webrtc.NewRTPVP8CodecExt(payloadType, payloadCodec.ClockRate, e.feedbackTypes, payloadCodec.Fmtp)
case strings.EqualFold(payloadCodec.Name, webrtc.VP9):
codec = webrtc.NewRTPVP9CodecExt(payloadType, payloadCodec.ClockRate, e.feedbackTypes, payloadCodec.Fmtp)
case strings.EqualFold(payloadCodec.Name, webrtc.H264):
codec = webrtc.NewRTPH264CodecExt(payloadType, payloadCodec.ClockRate, e.feedbackTypes, payloadCodec.Fmtp)
default:
// ignoring other codecs
continue
}
e.RegisterCodec(codec)
}
}
// Use defaults for codecs not provided in sdp
if len(e.GetCodecsByName(webrtc.Opus)) == 0 {
codec := webrtc.NewRTPOpusCodec(webrtc.DefaultPayloadTypeOpus, 48000)
e.RegisterCodec(codec)
}
if len(e.GetCodecsByName(webrtc.VP8)) == 0 {
codec := webrtc.NewRTPVP8CodecExt(webrtc.DefaultPayloadTypeVP8, 90000, e.feedbackTypes, "")
e.RegisterCodec(codec)
}
if len(e.GetCodecsByName(webrtc.VP9)) == 0 {
codec := webrtc.NewRTPVP9CodecExt(webrtc.DefaultPayloadTypeVP9, 90000, e.feedbackTypes, "")
e.RegisterCodec(codec)
}
if len(e.GetCodecsByName(webrtc.H264)) == 0 {
codec := webrtc.NewRTPH264CodecExt(webrtc.DefaultPayloadTypeH264, 90000, e.feedbackTypes, "")
e.RegisterCodec(codec)
}
return nil
}