From 7baf2bd0ceb4b1dd359afca59e26dda2cbc0c295 Mon Sep 17 00:00:00 2001 From: Sean DuBois Date: Tue, 12 Mar 2019 23:54:35 -0700 Subject: [PATCH] Migrate SDP generation to Unified Plan This commit has breaking changes. This API change means we can no longer support an arbitrary number of receivers. For every track you want to receive you MUST call PeerConnection.AddTransceiver We do now support sending an multiple audio/video feeds. You can see this behavior via gstreamer-receive and gstreamer-send currently. Resolves #54 --- gstreamer-receive/README.md | 2 +- gstreamer-receive/jsfiddle/demo.html | 6 ++++-- gstreamer-receive/jsfiddle/demo.js | 23 +++++++++++++++++++++-- gstreamer-receive/main.go | 9 +++++++++ gstreamer-send/README.md | 2 +- gstreamer-send/jsfiddle/demo.js | 6 +++++- gstreamer-send/main.go | 22 ++++++++++++++++------ janus-gateway/streaming/main.go | 7 +++++++ sfu-ws/room.go | 16 ++++++++++++++-- sfu-ws/sfu.html | 7 +++++-- 10 files changed, 83 insertions(+), 17 deletions(-) diff --git a/gstreamer-receive/README.md b/gstreamer-receive/README.md index ce8ebf57..cd43bb0b 100644 --- a/gstreamer-receive/README.md +++ b/gstreamer-receive/README.md @@ -14,7 +14,7 @@ go get github.com/pions/webrtc/examples/gstreamer-receive ``` ### Open gstreamer-receive example page -[jsfiddle.net](https://jsfiddle.net/pdm7bqfr/) you should see your Webcam, two text-areas and a 'Start Session' button +[jsfiddle.net](https://jsfiddle.net/8t2g5Lar/) you should see your Webcam, two text-areas and a 'Start Session' button ### Run gstreamer-receive with your browsers SessionDescription as stdin In the jsfiddle the top textarea is your browser, copy that and: diff --git a/gstreamer-receive/jsfiddle/demo.html b/gstreamer-receive/jsfiddle/demo.html index fad2a618..7612e161 100644 --- a/gstreamer-receive/jsfiddle/demo.html +++ b/gstreamer-receive/jsfiddle/demo.html @@ -4,12 +4,14 @@ Golang base64 Session Description

-
+ +

Video
-
+

+ Logs
diff --git a/gstreamer-receive/jsfiddle/demo.js b/gstreamer-receive/jsfiddle/demo.js index 8599c763..8e185ec0 100644 --- a/gstreamer-receive/jsfiddle/demo.js +++ b/gstreamer-receive/jsfiddle/demo.js @@ -7,13 +7,24 @@ let pc = new RTCPeerConnection({ } ] }) -var log = msg => { +let log = msg => { document.getElementById('logs').innerHTML += msg + '
' } +let displayVideo = video => { + var el = document.createElement('video') + el.srcObject = video + el.autoplay = true + el.muted = true + el.width = 160 + el.height = 120 + + document.getElementById('localVideos').appendChild(el) + return video +} navigator.mediaDevices.getUserMedia({ video: true, audio: true }) .then(stream => { - pc.addStream(document.getElementById('video1').srcObject = stream) + pc.addStream(displayVideo(stream)) pc.createOffer().then(d => pc.setLocalDescription(d)).catch(log) }).catch(log) @@ -36,3 +47,11 @@ window.startSession = () => { alert(e) } } + +window.addDisplayCapture = () => { + navigator.mediaDevices.getDisplayMedia().then(stream => { + document.getElementById('displayCapture').disabled = true + pc.addStream(displayVideo(stream)) + pc.createOffer().then(d => pc.setLocalDescription(d)).catch(log) + }) +} diff --git a/gstreamer-receive/main.go b/gstreamer-receive/main.go index 6b1d13c3..fa920ea4 100644 --- a/gstreamer-receive/main.go +++ b/gstreamer-receive/main.go @@ -32,6 +32,15 @@ func gstreamerReceiveMain() { panic(err) } + // Allow us to receive 1 audio track, and 2 video tracks + if _, err = peerConnection.AddTransceiver(webrtc.RTPCodecTypeAudio); err != nil { + panic(err) + } else if _, err = peerConnection.AddTransceiver(webrtc.RTPCodecTypeVideo); err != nil { + panic(err) + } else if _, err = peerConnection.AddTransceiver(webrtc.RTPCodecTypeVideo); err != nil { + panic(err) + } + // Set a handler for when a new remote track starts, this handler creates a gstreamer pipeline // for the given codec peerConnection.OnTrack(func(track *webrtc.Track, receiver *webrtc.RTPReceiver) { diff --git a/gstreamer-send/README.md b/gstreamer-send/README.md index 894a5c66..edeee01f 100644 --- a/gstreamer-send/README.md +++ b/gstreamer-send/README.md @@ -14,7 +14,7 @@ go get github.com/pions/webrtc/examples/gstreamer-send ``` ### Open gstreamer-send example page -[jsfiddle.net](https://jsfiddle.net/Laf7ujeo/164/) you should see two text-areas and a 'Start Session' button +[jsfiddle.net](https://jsfiddle.net/z7ms3u5r/) you should see two text-areas and a 'Start Session' button ### Run gstreamer-send with your browsers SessionDescription as stdin In the jsfiddle the top textarea is your browser, copy that and: diff --git a/gstreamer-send/jsfiddle/demo.js b/gstreamer-send/jsfiddle/demo.js index 8e0ca2ed..1acb68f3 100644 --- a/gstreamer-send/jsfiddle/demo.js +++ b/gstreamer-send/jsfiddle/demo.js @@ -27,7 +27,11 @@ pc.onicecandidate = event => { } } -pc.createOffer({ offerToReceiveVideo: true, offerToReceiveAudio: true }).then(d => pc.setLocalDescription(d)).catch(log) +// Offer to receive 1 audio, and 2 video tracks +pc.addTransceiver('audio', {'direction': 'recvonly'}) +pc.addTransceiver('video', {'direction': 'recvonly'}) +pc.addTransceiver('video', {'direction': 'recvonly'}) +pc.createOffer().then(d => pc.setLocalDescription(d)).catch(log) window.startSession = () => { let sd = document.getElementById('remoteSessionDescription').value diff --git a/gstreamer-send/main.go b/gstreamer-send/main.go index 8cd760ab..858ebcb6 100644 --- a/gstreamer-send/main.go +++ b/gstreamer-send/main.go @@ -40,21 +40,31 @@ func main() { }) // Create a audio track - opusTrack, err := peerConnection.NewTrack(webrtc.DefaultPayloadTypeOpus, rand.Uint32(), "audio", "pion1") + audioTrack, err := peerConnection.NewTrack(webrtc.DefaultPayloadTypeOpus, rand.Uint32(), "audio", "pion1") if err != nil { panic(err) } - _, err = peerConnection.AddTrack(opusTrack) + _, err = peerConnection.AddTrack(audioTrack) if err != nil { panic(err) } // Create a video track - vp8Track, err := peerConnection.NewTrack(webrtc.DefaultPayloadTypeVP8, rand.Uint32(), "video", "pion2") + firstVideoTrack, err := peerConnection.NewTrack(webrtc.DefaultPayloadTypeVP8, rand.Uint32(), "video", "pion2") if err != nil { panic(err) } - _, err = peerConnection.AddTrack(vp8Track) + _, err = peerConnection.AddTrack(firstVideoTrack) + if err != nil { + panic(err) + } + + // Create a second video track + secondVideoTrack, err := peerConnection.NewTrack(webrtc.DefaultPayloadTypeVP8, rand.Uint32(), "video", "pion3") + if err != nil { + panic(err) + } + _, err = peerConnection.AddTrack(secondVideoTrack) if err != nil { panic(err) } @@ -85,8 +95,8 @@ func main() { fmt.Println(signal.Encode(answer)) // Start pushing buffers on these tracks - gst.CreatePipeline(webrtc.Opus, []*webrtc.Track{opusTrack}, *audioSrc).Start() - gst.CreatePipeline(webrtc.VP8, []*webrtc.Track{vp8Track}, *videoSrc).Start() + gst.CreatePipeline(webrtc.Opus, []*webrtc.Track{audioTrack}, *audioSrc).Start() + gst.CreatePipeline(webrtc.VP8, []*webrtc.Track{firstVideoTrack, secondVideoTrack}, *videoSrc).Start() // Block forever select {} diff --git a/janus-gateway/streaming/main.go b/janus-gateway/streaming/main.go index 11280609..2ce78d0f 100644 --- a/janus-gateway/streaming/main.go +++ b/janus-gateway/streaming/main.go @@ -68,6 +68,13 @@ func main() { panic(err) } + // Allow us to receive 1 audio track, and 1 video track + if _, err = peerConnection.AddTransceiver(webrtc.RTPCodecTypeAudio); err != nil { + panic(err) + } else if _, err = peerConnection.AddTransceiver(webrtc.RTPCodecTypeVideo); err != nil { + panic(err) + } + peerConnection.OnICEConnectionStateChange(func(connectionState webrtc.ICEConnectionState) { fmt.Printf("Connection State has changed %s \n", connectionState.String()) }) diff --git a/sfu-ws/room.go b/sfu-ws/room.go index 976addf4..f5b8f713 100644 --- a/sfu-ws/room.go +++ b/sfu-ws/room.go @@ -1,6 +1,7 @@ package main import ( + "io" "net/http" "sync" @@ -69,6 +70,12 @@ func room(w http.ResponseWriter, r *http.Request) { pubReceiver, err = api.NewPeerConnection(peerConnectionConfig) checkError(err) + _, err = pubReceiver.AddTransceiver(webrtc.RTPCodecTypeAudio) + checkError(err) + + _, err = pubReceiver.AddTransceiver(webrtc.RTPCodecTypeVideo) + checkError(err) + pubReceiver.OnTrack(func(remoteTrack *webrtc.Track, receiver *webrtc.RTPReceiver) { if remoteTrack.PayloadType() == webrtc.DefaultPayloadTypeVP8 || remoteTrack.PayloadType() == webrtc.DefaultPayloadTypeVP9 || remoteTrack.PayloadType() == webrtc.DefaultPayloadTypeH264 { @@ -94,7 +101,10 @@ func room(w http.ResponseWriter, r *http.Request) { videoTrackLock.RLock() _, err = videoTrack.Write(rtpBuf[:i]) videoTrackLock.RUnlock() - checkError(err) + + if err != io.ErrClosedPipe { + checkError(err) + } } } else { @@ -113,7 +123,9 @@ func room(w http.ResponseWriter, r *http.Request) { audioTrackLock.RLock() _, err = audioTrack.Write(rtpBuf[:i]) audioTrackLock.RUnlock() - checkError(err) + if err != io.ErrClosedPipe { + checkError(err) + } } } }) diff --git a/sfu-ws/sfu.html b/sfu-ws/sfu.html index d8a782ac..a053a4dd 100644 --- a/sfu-ws/sfu.html +++ b/sfu-ws/sfu.html @@ -66,7 +66,7 @@ return alert('Message must not be empty') } dataChannel.send(message) - element.value = '' + element.value = '' } } @@ -103,7 +103,10 @@ document.getElementById('msginput').style = 'display: none' dataChannel = pc.createDataChannel('data') dataChannel.onmessage = e => log(`receive data from '${dataChannel.label}' payload '${e.data}'`) - pc.createOffer({ offerToReceiveVideo: true , offerToReceiveAudio: true}) + pc.addTransceiver('audio', {'direction': 'recvonly'}) + pc.addTransceiver('video', {'direction': 'recvonly'}) + + pc.createOffer() .then(d => pc.setLocalDescription(d)) .catch(log)