|
|
|
@ -11,62 +11,16 @@ import ( |
|
|
|
"github.com/bluenviron/mediamtx/internal/logger" |
|
|
|
"github.com/bluenviron/mediamtx/internal/logger" |
|
|
|
) |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
type peerConnection struct { |
|
|
|
var videoCodecs = map[string][]webrtc.RTPCodecParameters{ |
|
|
|
*webrtc.PeerConnection |
|
|
|
"av1": {{ |
|
|
|
stateChangeMutex sync.Mutex |
|
|
|
|
|
|
|
localCandidateRecv chan *webrtc.ICECandidateInit |
|
|
|
|
|
|
|
connected chan struct{} |
|
|
|
|
|
|
|
disconnected chan struct{} |
|
|
|
|
|
|
|
closed chan struct{} |
|
|
|
|
|
|
|
gatheringDone chan struct{} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func newPeerConnection( |
|
|
|
|
|
|
|
videoCodec string, |
|
|
|
|
|
|
|
audioCodec string, |
|
|
|
|
|
|
|
iceServers []webrtc.ICEServer, |
|
|
|
|
|
|
|
iceHostNAT1To1IPs []string, |
|
|
|
|
|
|
|
iceUDPMux ice.UDPMux, |
|
|
|
|
|
|
|
iceTCPMux ice.TCPMux, |
|
|
|
|
|
|
|
log logger.Writer, |
|
|
|
|
|
|
|
) (*peerConnection, error) { |
|
|
|
|
|
|
|
configuration := webrtc.Configuration{ICEServers: iceServers} |
|
|
|
|
|
|
|
settingsEngine := webrtc.SettingEngine{} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if len(iceHostNAT1To1IPs) != 0 { |
|
|
|
|
|
|
|
settingsEngine.SetNAT1To1IPs(iceHostNAT1To1IPs, webrtc.ICECandidateTypeHost) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if iceUDPMux != nil { |
|
|
|
|
|
|
|
settingsEngine.SetICEUDPMux(iceUDPMux) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if iceTCPMux != nil { |
|
|
|
|
|
|
|
settingsEngine.SetICETCPMux(iceTCPMux) |
|
|
|
|
|
|
|
settingsEngine.SetNetworkTypes([]webrtc.NetworkType{webrtc.NetworkTypeTCP4}) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mediaEngine := &webrtc.MediaEngine{} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if videoCodec != "" || audioCodec != "" { |
|
|
|
|
|
|
|
switch videoCodec { |
|
|
|
|
|
|
|
case "av1": |
|
|
|
|
|
|
|
err := mediaEngine.RegisterCodec( |
|
|
|
|
|
|
|
webrtc.RTPCodecParameters{ |
|
|
|
|
|
|
|
RTPCodecCapability: webrtc.RTPCodecCapability{ |
|
|
|
RTPCodecCapability: webrtc.RTPCodecCapability{ |
|
|
|
MimeType: webrtc.MimeTypeAV1, |
|
|
|
MimeType: webrtc.MimeTypeAV1, |
|
|
|
ClockRate: 90000, |
|
|
|
ClockRate: 90000, |
|
|
|
}, |
|
|
|
}, |
|
|
|
PayloadType: 96, |
|
|
|
PayloadType: 96, |
|
|
|
}, |
|
|
|
}}, |
|
|
|
webrtc.RTPCodecTypeVideo) |
|
|
|
"vp9": { |
|
|
|
if err != nil { |
|
|
|
{ |
|
|
|
return nil, err |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case "vp9": |
|
|
|
|
|
|
|
err := mediaEngine.RegisterCodec( |
|
|
|
|
|
|
|
webrtc.RTPCodecParameters{ |
|
|
|
|
|
|
|
RTPCodecCapability: webrtc.RTPCodecCapability{ |
|
|
|
RTPCodecCapability: webrtc.RTPCodecCapability{ |
|
|
|
MimeType: webrtc.MimeTypeVP9, |
|
|
|
MimeType: webrtc.MimeTypeVP9, |
|
|
|
ClockRate: 90000, |
|
|
|
ClockRate: 90000, |
|
|
|
@ -74,13 +28,7 @@ func newPeerConnection( |
|
|
|
}, |
|
|
|
}, |
|
|
|
PayloadType: 96, |
|
|
|
PayloadType: 96, |
|
|
|
}, |
|
|
|
}, |
|
|
|
webrtc.RTPCodecTypeVideo) |
|
|
|
{ |
|
|
|
if err != nil { |
|
|
|
|
|
|
|
return nil, err |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
err = mediaEngine.RegisterCodec( |
|
|
|
|
|
|
|
webrtc.RTPCodecParameters{ |
|
|
|
|
|
|
|
RTPCodecCapability: webrtc.RTPCodecCapability{ |
|
|
|
RTPCodecCapability: webrtc.RTPCodecCapability{ |
|
|
|
MimeType: webrtc.MimeTypeVP9, |
|
|
|
MimeType: webrtc.MimeTypeVP9, |
|
|
|
ClockRate: 90000, |
|
|
|
ClockRate: 90000, |
|
|
|
@ -88,45 +36,26 @@ func newPeerConnection( |
|
|
|
}, |
|
|
|
}, |
|
|
|
PayloadType: 96, |
|
|
|
PayloadType: 96, |
|
|
|
}, |
|
|
|
}, |
|
|
|
webrtc.RTPCodecTypeVideo) |
|
|
|
}, |
|
|
|
if err != nil { |
|
|
|
"vp8": {{ |
|
|
|
return nil, err |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case "vp8": |
|
|
|
|
|
|
|
err := mediaEngine.RegisterCodec( |
|
|
|
|
|
|
|
webrtc.RTPCodecParameters{ |
|
|
|
|
|
|
|
RTPCodecCapability: webrtc.RTPCodecCapability{ |
|
|
|
RTPCodecCapability: webrtc.RTPCodecCapability{ |
|
|
|
MimeType: webrtc.MimeTypeVP8, |
|
|
|
MimeType: webrtc.MimeTypeVP8, |
|
|
|
ClockRate: 90000, |
|
|
|
ClockRate: 90000, |
|
|
|
}, |
|
|
|
}, |
|
|
|
PayloadType: 96, |
|
|
|
PayloadType: 96, |
|
|
|
}, |
|
|
|
}}, |
|
|
|
webrtc.RTPCodecTypeVideo) |
|
|
|
"h264": {{ |
|
|
|
if err != nil { |
|
|
|
|
|
|
|
return nil, err |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case "h264": |
|
|
|
|
|
|
|
err := mediaEngine.RegisterCodec( |
|
|
|
|
|
|
|
webrtc.RTPCodecParameters{ |
|
|
|
|
|
|
|
RTPCodecCapability: webrtc.RTPCodecCapability{ |
|
|
|
RTPCodecCapability: webrtc.RTPCodecCapability{ |
|
|
|
MimeType: webrtc.MimeTypeH264, |
|
|
|
MimeType: webrtc.MimeTypeH264, |
|
|
|
ClockRate: 90000, |
|
|
|
ClockRate: 90000, |
|
|
|
SDPFmtpLine: "level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f", |
|
|
|
SDPFmtpLine: "level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f", |
|
|
|
}, |
|
|
|
}, |
|
|
|
PayloadType: 96, |
|
|
|
PayloadType: 96, |
|
|
|
}, |
|
|
|
}}, |
|
|
|
webrtc.RTPCodecTypeVideo) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
return nil, err |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
switch audioCodec { |
|
|
|
var audioCodecs = map[string][]webrtc.RTPCodecParameters{ |
|
|
|
case "opus": |
|
|
|
"opus": {{ |
|
|
|
err := mediaEngine.RegisterCodec( |
|
|
|
|
|
|
|
webrtc.RTPCodecParameters{ |
|
|
|
|
|
|
|
RTPCodecCapability: webrtc.RTPCodecCapability{ |
|
|
|
RTPCodecCapability: webrtc.RTPCodecCapability{ |
|
|
|
MimeType: webrtc.MimeTypeOpus, |
|
|
|
MimeType: webrtc.MimeTypeOpus, |
|
|
|
ClockRate: 48000, |
|
|
|
ClockRate: 48000, |
|
|
|
@ -134,73 +63,106 @@ func newPeerConnection( |
|
|
|
SDPFmtpLine: "minptime=10;useinbandfec=1", |
|
|
|
SDPFmtpLine: "minptime=10;useinbandfec=1", |
|
|
|
}, |
|
|
|
}, |
|
|
|
PayloadType: 111, |
|
|
|
PayloadType: 111, |
|
|
|
}, |
|
|
|
}}, |
|
|
|
webrtc.RTPCodecTypeAudio) |
|
|
|
"g722": {{ |
|
|
|
if err != nil { |
|
|
|
|
|
|
|
return nil, err |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case "g722": |
|
|
|
|
|
|
|
err := mediaEngine.RegisterCodec( |
|
|
|
|
|
|
|
webrtc.RTPCodecParameters{ |
|
|
|
|
|
|
|
RTPCodecCapability: webrtc.RTPCodecCapability{ |
|
|
|
RTPCodecCapability: webrtc.RTPCodecCapability{ |
|
|
|
MimeType: webrtc.MimeTypeG722, |
|
|
|
MimeType: webrtc.MimeTypeG722, |
|
|
|
ClockRate: 8000, |
|
|
|
ClockRate: 8000, |
|
|
|
}, |
|
|
|
}, |
|
|
|
PayloadType: 9, |
|
|
|
PayloadType: 9, |
|
|
|
}, |
|
|
|
}}, |
|
|
|
webrtc.RTPCodecTypeAudio) |
|
|
|
"pcmu": {{ |
|
|
|
if err != nil { |
|
|
|
|
|
|
|
return nil, err |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case "pcmu": |
|
|
|
|
|
|
|
err := mediaEngine.RegisterCodec( |
|
|
|
|
|
|
|
webrtc.RTPCodecParameters{ |
|
|
|
|
|
|
|
RTPCodecCapability: webrtc.RTPCodecCapability{ |
|
|
|
RTPCodecCapability: webrtc.RTPCodecCapability{ |
|
|
|
MimeType: webrtc.MimeTypePCMU, |
|
|
|
MimeType: webrtc.MimeTypePCMU, |
|
|
|
ClockRate: 8000, |
|
|
|
ClockRate: 8000, |
|
|
|
}, |
|
|
|
}, |
|
|
|
PayloadType: 0, |
|
|
|
PayloadType: 0, |
|
|
|
}, |
|
|
|
}}, |
|
|
|
webrtc.RTPCodecTypeAudio) |
|
|
|
"pcma": {{ |
|
|
|
if err != nil { |
|
|
|
|
|
|
|
return nil, err |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case "pcma": |
|
|
|
|
|
|
|
err := mediaEngine.RegisterCodec( |
|
|
|
|
|
|
|
webrtc.RTPCodecParameters{ |
|
|
|
|
|
|
|
RTPCodecCapability: webrtc.RTPCodecCapability{ |
|
|
|
RTPCodecCapability: webrtc.RTPCodecCapability{ |
|
|
|
MimeType: webrtc.MimeTypePCMA, |
|
|
|
MimeType: webrtc.MimeTypePCMA, |
|
|
|
ClockRate: 8000, |
|
|
|
ClockRate: 8000, |
|
|
|
}, |
|
|
|
}, |
|
|
|
PayloadType: 8, |
|
|
|
PayloadType: 8, |
|
|
|
}, |
|
|
|
}}, |
|
|
|
webrtc.RTPCodecTypeAudio) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
type peerConnection struct { |
|
|
|
|
|
|
|
*webrtc.PeerConnection |
|
|
|
|
|
|
|
stateChangeMutex sync.Mutex |
|
|
|
|
|
|
|
localCandidateRecv chan *webrtc.ICECandidateInit |
|
|
|
|
|
|
|
connected chan struct{} |
|
|
|
|
|
|
|
disconnected chan struct{} |
|
|
|
|
|
|
|
closed chan struct{} |
|
|
|
|
|
|
|
gatheringDone chan struct{} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func newPeerConnection( |
|
|
|
|
|
|
|
videoCodec string, |
|
|
|
|
|
|
|
audioCodec string, |
|
|
|
|
|
|
|
iceServers []webrtc.ICEServer, |
|
|
|
|
|
|
|
iceHostNAT1To1IPs []string, |
|
|
|
|
|
|
|
iceUDPMux ice.UDPMux, |
|
|
|
|
|
|
|
iceTCPMux ice.TCPMux, |
|
|
|
|
|
|
|
log logger.Writer, |
|
|
|
|
|
|
|
) (*peerConnection, error) { |
|
|
|
|
|
|
|
configuration := webrtc.Configuration{ICEServers: iceServers} |
|
|
|
|
|
|
|
settingsEngine := webrtc.SettingEngine{} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if len(iceHostNAT1To1IPs) != 0 { |
|
|
|
|
|
|
|
settingsEngine.SetNAT1To1IPs(iceHostNAT1To1IPs, webrtc.ICECandidateTypeHost) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if iceUDPMux != nil { |
|
|
|
|
|
|
|
settingsEngine.SetICEUDPMux(iceUDPMux) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if iceTCPMux != nil { |
|
|
|
|
|
|
|
settingsEngine.SetICETCPMux(iceTCPMux) |
|
|
|
|
|
|
|
settingsEngine.SetNetworkTypes([]webrtc.NetworkType{webrtc.NetworkTypeTCP4}) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mediaEngine := &webrtc.MediaEngine{} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if videoCodec != "" || audioCodec != "" { |
|
|
|
|
|
|
|
codec, ok := videoCodecs[videoCodec] |
|
|
|
|
|
|
|
if ok { |
|
|
|
|
|
|
|
for _, params := range codec { |
|
|
|
|
|
|
|
err := mediaEngine.RegisterCodec(params, webrtc.RTPCodecTypeVideo) |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
return nil, err |
|
|
|
return nil, err |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
} |
|
|
|
// register all codecs
|
|
|
|
|
|
|
|
err := mediaEngine.RegisterDefaultCodecs() |
|
|
|
codec, ok = audioCodecs[audioCodec] |
|
|
|
|
|
|
|
if ok { |
|
|
|
|
|
|
|
for _, params := range codec { |
|
|
|
|
|
|
|
err := mediaEngine.RegisterCodec(params, webrtc.RTPCodecTypeAudio) |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
return nil, err |
|
|
|
return nil, err |
|
|
|
} |
|
|
|
} |
|
|
|
err = mediaEngine.RegisterCodec( |
|
|
|
} |
|
|
|
webrtc.RTPCodecParameters{ |
|
|
|
} |
|
|
|
RTPCodecCapability: webrtc.RTPCodecCapability{ |
|
|
|
} else { // register all codecs
|
|
|
|
MimeType: webrtc.MimeTypeAV1, |
|
|
|
for _, codec := range videoCodecs { |
|
|
|
ClockRate: 90000, |
|
|
|
for _, params := range codec { |
|
|
|
}, |
|
|
|
err := mediaEngine.RegisterCodec(params, webrtc.RTPCodecTypeVideo) |
|
|
|
PayloadType: 105, |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
webrtc.RTPCodecTypeVideo) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
return nil, err |
|
|
|
return nil, err |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for _, codec := range audioCodecs { |
|
|
|
|
|
|
|
for _, params := range codec { |
|
|
|
|
|
|
|
err := mediaEngine.RegisterCodec(params, webrtc.RTPCodecTypeAudio) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
return nil, err |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
interceptorRegistry := &interceptor.Registry{} |
|
|
|
interceptorRegistry := &interceptor.Registry{} |
|
|
|
if err := webrtc.RegisterDefaultInterceptors(mediaEngine, interceptorRegistry); err != nil { |
|
|
|
if err := webrtc.RegisterDefaultInterceptors(mediaEngine, interceptorRegistry); err != nil { |
|
|
|
|