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
This commit is contained in:
Sean DuBois
2019-03-12 23:54:35 -07:00
parent bc94eaa968
commit 1202dbaa06
20 changed files with 340 additions and 169 deletions

View File

@@ -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:

View File

@@ -4,12 +4,14 @@ Browser base64 Session Description<br />
Golang base64 Session Description<br />
<textarea id="remoteSessionDescription"></textarea> <br/>
<button onclick="window.startSession()"> Start Session </button><br />
<button onclick="window.startSession()"> Start Session </button>
<button onclick="window.addDisplayCapture()" id="displayCapture"> Display Capture </button><br />
<br />
Video<br />
<video id="video1" width="160" height="120" autoplay muted></video> <br />
<div id="localVideos"></div> <br />
Logs<br />
<div id="logs"></div>

View File

@@ -7,13 +7,24 @@ let pc = new RTCPeerConnection({
}
]
})
var log = msg => {
let log = msg => {
document.getElementById('logs').innerHTML += msg + '<br>'
}
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)
})
}

View File

@@ -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) {

View File

@@ -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:

View File

@@ -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

View File

@@ -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 {}

View File

@@ -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())
})

View File

@@ -61,6 +61,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)
}
opusFile, err := opuswriter.New("output.opus", 48000, 2)
if err != nil {
panic(err)

View File

@@ -10,7 +10,7 @@ go get github.com/pions/webrtc/examples/sfu-minimal
```
### Open sfu-minimal example page
[jsfiddle.net](https://jsfiddle.net/4g03uqrx/) You should see two buttons 'Publish a Broadcast' and 'Join a Broadcast'
[jsfiddle.net](https://jsfiddle.net/zhpya3n9/) You should see two buttons 'Publish a Broadcast' and 'Join a Broadcast'
### Run SFU Minimal
#### Linux/macOS

View File

@@ -27,7 +27,8 @@ window.createSession = isPublisher => {
.catch(log)
}).catch(log)
} else {
pc.createOffer({ offerToReceiveVideo: true })
pc.addTransceiver('video', {'direction': 'recvonly'})
pc.createOffer()
.then(d => pc.setLocalDescription(d))
.catch(log)

View File

@@ -2,6 +2,7 @@ package main
import (
"fmt"
"io"
"time"
"github.com/pions/rtcp"
@@ -46,6 +47,11 @@ func main() {
panic(err)
}
// Allow us to receive 1 video track
if _, err = peerConnection.AddTransceiver(webrtc.RTPCodecTypeVideo); err != nil {
panic(err)
}
localTrackChan := make(chan *webrtc.Track)
// Set a handler for when a new remote track starts, this just distributes all our packets
// to connected peers
@@ -75,7 +81,8 @@ func main() {
panic(readErr)
}
if _, err = localTrack.Write(rtpBuf[:i]); err != nil {
// ErrClosedPipe means we don't have any subscribers, this is ok if no peers have connected yet
if _, err = localTrack.Write(rtpBuf[:i]); err != nil && err != io.ErrClosedPipe {
panic(err)
}
}

View File

@@ -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)
}
}
}
})

View File

@@ -66,7 +66,7 @@ window.sendMessage = element => {
return alert('Message must not be empty')
}
dataChannel.send(message)
element.value = ''
element.value = ''
}
}
@@ -103,7 +103,10 @@ window.createSession = isPublisher => {
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)