api: support a custom media engine

This commit is contained in:
backkem
2018-07-16 22:25:54 +02:00
committed by Sean DuBois
parent f7c5ecd57f
commit ab6910899c
10 changed files with 78 additions and 73 deletions

View File

@@ -67,7 +67,7 @@ var (
ErrModPeerIdentity = errors.New("peer identity cannot be modified")
ErrModCertificates = errors.New("certificates cannot be modified")
ErrModRtcpMuxPolicy = errors.New("rtcp mux policy cannot be modified")
ErrModIceCandidatePoolSize = errors.New("ice candidate pool size cannot be modified")
ErrModICECandidatePoolSize = errors.New("ice candidate pool size cannot be modified")
)
// InvalidModificationError indicates the object can not be modified in this way.

View File

@@ -45,7 +45,7 @@ func main() {
}
// Create a audio track
opusTrack, err := peerConnection.NewRTCTrack(webrtc.PayloadTypeOpus, "audio", "pion1")
opusTrack, err := peerConnection.NewRTCTrack(webrtc.DefaultPayloadTypeOpus, "audio", "pion1")
if err != nil {
panic(err)
}
@@ -55,7 +55,7 @@ func main() {
}
// Create a video track
vp8Track, err := peerConnection.NewRTCTrack(webrtc.PayloadTypeVP8, "video", "pion2")
vp8Track, err := peerConnection.NewRTCTrack(webrtc.DefaultPayloadTypeVP8, "video", "pion2")
if err != nil {
panic(err)
}

View File

@@ -28,8 +28,8 @@ func main() {
// Setup the codecs you want to use.
// We'll use a VP8 codec but you can also define your own
webrtc.RegisterCodec(webrtc.NewRTCRtpOpusCodec(webrtc.PayloadTypeOpus, 48000, 2))
webrtc.RegisterCodec(webrtc.NewRTCRtpVP8Codec(webrtc.PayloadTypeVP8, 90000))
webrtc.RegisterCodec(webrtc.NewRTCRtpOpusCodec(webrtc.DefaultPayloadTypeOpus, 48000, 2))
webrtc.RegisterCodec(webrtc.NewRTCRtpVP8Codec(webrtc.DefaultPayloadTypeVP8, 90000))
// Create a new RTCPeerConnection
peerConnection, err := webrtc.New(webrtc.RTCConfiguration{})

View File

@@ -121,10 +121,10 @@ func (d *MediaDescription) WithCodec(payloadType uint8, name string, clockrate u
// WithMediaSource adds media source information to the media description
func (d *MediaDescription) WithMediaSource(ssrc uint32, cname, streamLabel, label string) *MediaDescription {
return d.
WithValueAttribute("ssrc", fmt.Sprintf("%d cname:%s", ssrc, cname)). // Deprecated but not pased out?
WithValueAttribute("ssrc", fmt.Sprintf("%d cname:%s", ssrc, cname)). // Deprecated but not phased out?
WithValueAttribute("ssrc", fmt.Sprintf("%d msid:%s %s", ssrc, streamLabel, label)).
WithValueAttribute("ssrc", fmt.Sprintf("%d mslabel:%s", ssrc, streamLabel)). // Deprecated but not pased out?
WithValueAttribute("ssrc", fmt.Sprintf("%d label:%s", ssrc, label)) // Deprecated but not pased out?
WithValueAttribute("ssrc", fmt.Sprintf("%d mslabel:%s", ssrc, streamLabel)). // Deprecated but not phased out?
WithValueAttribute("ssrc", fmt.Sprintf("%d label:%s", ssrc, label)) // Deprecated but not phased out?
}
// WithCandidate adds an ICE candidate to the media description

View File

@@ -8,21 +8,6 @@ import (
"strings"
)
// SessionBuilderTrack represents a single track in a SessionBuilder
type SessionBuilderTrack struct {
SSRC uint32
IsAudio bool
}
// SessionBuilder provides an easy way to build an SDP for an RTCPeerConnection
type SessionBuilder struct {
IceUsername, IcePassword, Fingerprint string
Candidates []string
Tracks []*SessionBuilderTrack
}
// ConnectionRole indicates which of the end points should initiate the connection establishment
type ConnectionRole int

View File

@@ -133,7 +133,7 @@ type RTCTrack struct {
// NewRTCTrack is used to create a new RTCTrack
func (r *RTCPeerConnection) NewRTCTrack(payloadType uint8, id, label string) (*RTCTrack, error) {
codec, err := rtcMediaEngine.getCodec(payloadType)
codec, err := r.mediaEngine.getCodec(payloadType)
if err != nil {
return nil, err
}

View File

@@ -9,48 +9,50 @@ import (
"github.com/pkg/errors"
)
// RegisterCodec is used to register a codec with the DefaultMediaEngine
func RegisterCodec(codec *RTCRtpCodec) {
DefaultMediaEngine.RegisterCodec(codec)
}
// TODO: Phase out DefaultPayloadTypes in favor or dynamic assignment in 96-127 range
// PayloadTypes for the default codecs
const (
PayloadTypeOpus = 111
PayloadTypeVP8 = 96
PayloadTypeVP9 = 98
PayloadTypeH264 = 100
DefaultPayloadTypeOpus = 111
DefaultPayloadTypeVP8 = 96
DefaultPayloadTypeVP9 = 98
DefaultPayloadTypeH264 = 100
)
// Names for the default codecs
const (
Opus = "opus"
VP8 = "VP8"
VP9 = "VP9"
H264 = "H264"
)
var rtcMediaEngine = &mediaEngine{}
// RegisterDefaultCodecs is a helper that registers the default codecs supported by pions-webrtc
func RegisterDefaultCodecs() {
RegisterCodec(NewRTCRtpOpusCodec(PayloadTypeOpus, 48000, 2))
RegisterCodec(NewRTCRtpVP8Codec(PayloadTypeVP8, 90000))
RegisterCodec(NewRTCRtpH264Codec(PayloadTypeH264, 90000))
RegisterCodec(NewRTCRtpVP9Codec(PayloadTypeVP9, 90000))
RegisterCodec(NewRTCRtpOpusCodec(DefaultPayloadTypeOpus, 48000, 2))
RegisterCodec(NewRTCRtpVP8Codec(DefaultPayloadTypeVP8, 90000))
RegisterCodec(NewRTCRtpH264Codec(DefaultPayloadTypeH264, 90000))
RegisterCodec(NewRTCRtpVP9Codec(DefaultPayloadTypeVP9, 90000))
}
// RegisterCodec is used to register a codec
func RegisterCodec(codec *RTCRtpCodec) {
rtcMediaEngine.RegisterCodec(codec)
// DefaultMediaEngine is the default MediaEngine used by RTCPeerConnections
var DefaultMediaEngine = NewMediaEngine()
// NewMediaEngine creates a new MediaEngine
func NewMediaEngine() *MediaEngine {
return &MediaEngine{}
}
type mediaEngine struct {
// MediaEngine defines the codecs supported by a RTCPeerConnection
type MediaEngine struct {
codecs []*RTCRtpCodec
}
func (m *mediaEngine) RegisterCodec(codec *RTCRtpCodec) uint8 {
// RegisterCodec registers a codec to a media engine
func (m *MediaEngine) RegisterCodec(codec *RTCRtpCodec) uint8 {
// TODO: generate PayloadType if not set
m.codecs = append(m.codecs, codec)
return codec.PayloadType
}
func (m *mediaEngine) getCodec(payloadType uint8) (*RTCRtpCodec, error) {
func (m *MediaEngine) getCodec(payloadType uint8) (*RTCRtpCodec, error) {
for _, codec := range m.codecs {
if codec.PayloadType == payloadType {
return codec, nil
@@ -59,7 +61,7 @@ func (m *mediaEngine) getCodec(payloadType uint8) (*RTCRtpCodec, error) {
return nil, errors.New("Codec not found")
}
func (m *mediaEngine) getCodecSDP(sdpCodec sdp.Codec) (*RTCRtpCodec, error) {
func (m *MediaEngine) getCodecSDP(sdpCodec sdp.Codec) (*RTCRtpCodec, error) {
for _, codec := range m.codecs {
if codec.Name == sdpCodec.Name &&
codec.ClockRate == sdpCodec.ClockRate &&
@@ -72,9 +74,9 @@ func (m *mediaEngine) getCodecSDP(sdpCodec sdp.Codec) (*RTCRtpCodec, error) {
return nil, errors.New("Codec not found")
}
func (m *mediaEngine) getCodecsByKind(kind RTCRtpCodecType) []*RTCRtpCodec {
func (m *MediaEngine) getCodecsByKind(kind RTCRtpCodecType) []*RTCRtpCodec {
var codecs []*RTCRtpCodec
for _, codec := range rtcMediaEngine.codecs {
for _, codec := range m.codecs {
if codec.Type == kind {
codecs = append(codecs, codec)
}
@@ -82,6 +84,14 @@ func (m *mediaEngine) getCodecsByKind(kind RTCRtpCodecType) []*RTCRtpCodec {
return codecs
}
// Names for the default codecs supported by pions-webrtc
const (
Opus = "opus"
VP8 = "VP8"
VP9 = "VP9"
H264 = "H264"
)
// NewRTCRtpOpusCodec is a helper to create an Opus codec
func NewRTCRtpOpusCodec(payloadType uint8, clockrate uint32, channels uint16) *RTCRtpCodec {
c := NewRTCRtpCodec(RTCRtpCodecTypeAudio,

View File

@@ -231,7 +231,7 @@ func (r *RTCPeerConnection) validateICECandidatePoolSize(config RTCConfiguration
current := r.config
if r.LocalDescription != nil &&
config.ICECandidatePoolSize != current.ICECandidatePoolSize {
return &InvalidModificationError{Err: ErrModIceCandidatePoolSize}
return &InvalidModificationError{Err: ErrModICECandidatePoolSize}
}
return nil
}
@@ -265,23 +265,28 @@ func parseICEServer(server RTCICEServer, rawURL string) (ice.URL, error) {
return iceurl, &SyntaxError{Err: err}
}
_, isPass := server.Credential.(string)
_, isOauth := server.Credential.(RTCOAuthCredential)
noPass := !isPass && !isOauth
if iceurl.Type == ice.ServerTypeTURN {
if server.Username == "" ||
noPass {
if server.Username == "" {
return iceurl, &InvalidAccessError{Err: ErrNoTurnCred}
}
if server.CredentialType == RTCICECredentialTypePassword &&
!isPass {
switch t := server.Credential.(type) {
case string:
if t == "" {
return iceurl, &InvalidAccessError{Err: ErrNoTurnCred}
} else if server.CredentialType != RTCICECredentialTypePassword {
return iceurl, &InvalidAccessError{Err: ErrTurnCred}
}
if server.CredentialType == RTCICECredentialTypeOauth &&
!isOauth {
case RTCOAuthCredential:
if server.CredentialType != RTCICECredentialTypeOauth {
return iceurl, &InvalidAccessError{Err: ErrTurnCred}
}
default:
return iceurl, &InvalidAccessError{Err: ErrTurnCred}
}
}
return iceurl, nil
}

View File

@@ -100,13 +100,15 @@ type RTCPeerConnection struct {
connectionState RTCPeerConnectionState
// Media
mediaEngine *MediaEngine
rtpTransceivers []*RTCRtpTransceiver
Ontrack func(*RTCTrack)
}
// Public
// New creates a new RTCPeerConfiguration with the provided configuration
func New(config RTCConfiguration) (*RTCPeerConnection, error) {
r := &RTCPeerConnection{
config: config,
signalingState: RTCSignalingStateStable,
@@ -114,6 +116,7 @@ func New(config RTCConfiguration) (*RTCPeerConnection, error) {
iceGatheringState: ice.GatheringStateNew,
iceConnectionState: ice.ConnectionStateNew,
connectionState: RTCPeerConnectionStateNew,
mediaEngine: DefaultMediaEngine,
}
err := r.SetConfiguration(config)
if err != nil {
@@ -122,12 +125,14 @@ func New(config RTCConfiguration) (*RTCPeerConnection, error) {
r.tlscfg = dtls.NewTLSCfg()
// TODO: Initialize ICE Agent
return r, nil
}
// Public
// SetMediaEngine allows overwriting the default media engine used by the RTCPeerConnection
// This enables RTCPeerConnection with support for different codecs
func (r *RTCPeerConnection) SetMediaEngine(m *MediaEngine) {
r.mediaEngine = m
}
// SetIdentityProvider is used to configure an identity provider to generate identity assertions
func (r *RTCPeerConnection) SetIdentityProvider(provider string) error {
@@ -161,7 +166,7 @@ func (r *RTCPeerConnection) generateChannel(ssrc uint32, payloadType uint8) (buf
return nil
}
codec, err := rtcMediaEngine.getCodecSDP(sdpCodec)
codec, err := r.mediaEngine.getCodecSDP(sdpCodec)
if err != nil {
fmt.Printf("Codec %s in not registered\n", sdpCodec)
}

View File

@@ -151,7 +151,7 @@ func (r *RTCPeerConnection) SetRemoteDescription(desc RTCSessionDescription) err
// RTCOfferOptions describes the options used to control the offer creation process
type RTCOfferOptions struct {
VoiceActivityDetection bool
IceRestart bool
ICERestart bool
}
// CreateOffer starts the RTCPeerConnection and generates the localDescription
@@ -181,7 +181,7 @@ func (r *RTCPeerConnection) CreateOffer(options *RTCOfferOptions) (RTCSessionDes
track := tranceiver.Sender.Track
cname := "pion" // TODO: Support RTP streams synchronisation
steamlabel := "pion" // TODO: Support steam labels
codec, err := rtcMediaEngine.getCodec(track.PayloadType)
codec, err := r.mediaEngine.getCodec(track.PayloadType)
if err != nil {
return RTCSessionDescription{}, err
}
@@ -273,7 +273,7 @@ func (r *RTCPeerConnection) addAnswerMedia(d *sdp.SessionDescription, codecType
track := tranceiver.Sender.Track
cname := track.Label // TODO: Support RTP streams synchronisation
steamlabel := track.Label // TODO: Support steam labels
codec, err := rtcMediaEngine.getCodec(track.PayloadType)
codec, err := r.mediaEngine.getCodec(track.PayloadType)
if err != nil {
return "", err
}
@@ -314,7 +314,7 @@ func (r *RTCPeerConnection) addAnswerMedia(d *sdp.SessionDescription, codecType
WithPropertyAttribute(sdp.AttrKeyRtcpMux). // TODO: support RTCP fallback
WithPropertyAttribute(sdp.AttrKeyRtcpRsize) // TODO: Support Reduced-Size RTCP?
for _, codec := range rtcMediaEngine.getCodecsByKind(codecType) {
for _, codec := range r.mediaEngine.getCodecsByKind(codecType) {
media.WithCodec(
codec.PayloadType,
codec.Name,