Skip to content

Commit 7edfb70

Browse files
committed
New Track API
The Pion WebRTC API has been dramatically redesigned. The design docs are located here [0] You can also read the release notes [1] on how to migrate your application. [0] https://github.com/pion/webrtc-v3-design [1] https://github.com/pion/webrtc/wiki/[email protected]
1 parent 159ba5a commit 7edfb70

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+1703
-2012
lines changed

api_test.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ package webrtc
44

55
import (
66
"testing"
7+
8+
"github.com/stretchr/testify/assert"
79
)
810

911
func TestNewAPI(t *testing.T) {
@@ -22,7 +24,7 @@ func TestNewAPI_Options(t *testing.T) {
2224
s := SettingEngine{}
2325
s.DetachDataChannels()
2426
m := MediaEngine{}
25-
m.RegisterDefaultCodecs()
27+
assert.NoError(t, m.RegisterDefaultCodecs())
2628

2729
api := NewAPI(
2830
WithSettingEngine(s),
@@ -33,7 +35,7 @@ func TestNewAPI_Options(t *testing.T) {
3335
t.Error("Failed to set settings engine")
3436
}
3537

36-
if len(api.mediaEngine.codecs) == 0 {
38+
if len(api.mediaEngine.audioCodecs) == 0 || len(api.mediaEngine.videoCodecs) == 0 {
3739
t.Error("Failed to set media engine")
3840
}
3941
}

e2e/e2e_test.go

Lines changed: 5 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,16 @@ package main
55
import (
66
"context"
77
"encoding/json"
8-
"errors"
98
"fmt"
109
"os"
1110
"strconv"
1211
"strings"
1312
"testing"
1413
"time"
1514

16-
"github.com/sclevine/agouti"
17-
18-
"github.com/pion/randutil"
1915
"github.com/pion/webrtc/v3"
2016
"github.com/pion/webrtc/v3/pkg/media"
17+
"github.com/sclevine/agouti"
2118
)
2219

2320
var silentOpusFrame = []byte{0xf8, 0xff, 0xfe} // 20ms, 8kHz, mono
@@ -103,7 +100,7 @@ func TestE2E_Audio(t *testing.T) {
103100
go func() {
104101
for {
105102
if err := track.WriteSample(
106-
media.Sample{Data: silentOpusFrame, Samples: 960},
103+
media.Sample{Data: silentOpusFrame, Duration: time.Millisecond * 20},
107104
); err != nil {
108105
t.Errorf("Failed to WriteSample: %v", err)
109106
return
@@ -330,28 +327,13 @@ func parseLog(log agouti.Log) (string, string, bool) {
330327
return k, v, true
331328
}
332329

333-
func createTrack(offer webrtc.SessionDescription) (*webrtc.PeerConnection, *webrtc.SessionDescription, *webrtc.Track, error) {
334-
mediaEngine := webrtc.MediaEngine{}
335-
if err := mediaEngine.PopulateFromSDP(offer); err != nil {
336-
return nil, nil, nil, err
337-
}
338-
var payloadType uint8
339-
for _, videoCodec := range mediaEngine.GetCodecsByKind(webrtc.RTPCodecTypeAudio) {
340-
if videoCodec.Name == webrtc.Opus {
341-
payloadType = videoCodec.PayloadType
342-
break
343-
}
344-
}
345-
if payloadType == 0 {
346-
return nil, nil, nil, errors.New("Remote peer does not support VP8")
347-
}
348-
api := webrtc.NewAPI(webrtc.WithMediaEngine(mediaEngine))
349-
pc, errPc := api.NewPeerConnection(webrtc.Configuration{})
330+
func createTrack(offer webrtc.SessionDescription) (*webrtc.PeerConnection, *webrtc.SessionDescription, *webrtc.TrackLocalStaticSample, error) {
331+
pc, errPc := webrtc.NewPeerConnection(webrtc.Configuration{})
350332
if errPc != nil {
351333
return nil, nil, nil, errPc
352334
}
353335

354-
track, errTrack := pc.NewTrack(payloadType, randutil.NewMathRandomGenerator().Uint32(), "video", "pion")
336+
track, errTrack := webrtc.NewTrackLocalStaticSample(webrtc.RTPCodecCapability{MimeType: "audio/opus"}, "audio", "pion")
355337
if errTrack != nil {
356338
return nil, nil, nil, errTrack
357339
}

errors.go

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,18 @@ var (
129129
// ErrFailedToGenerateCertificateFingerprint indicates that we failed to generate the fingerprint used for comparing certificates
130130
ErrFailedToGenerateCertificateFingerprint = errors.New("failed to generate certificate fingerprint")
131131

132+
// ErrNoCodecsAvailable indicates that operation isn't possible because the MediaEngine has no codecs available
133+
ErrNoCodecsAvailable = errors.New("operation failed no codecs are available")
134+
135+
// ErrUnsupportedCodec indicates the remote peer doesn't support the requested codec
136+
ErrUnsupportedCodec = errors.New("unable to start track, codec is not supported by remote")
137+
138+
// ErrUnbindFailed indicates that a TrackLocal was not able to be unbind
139+
ErrUnbindFailed = errors.New("failed to unbind TrackLocal from PeerConnection")
140+
141+
// ErrNoPayloaderForCodec indicates that the requested codec does not have a payloader
142+
ErrNoPayloaderForCodec = errors.New("the requested codec does not have a payloader")
143+
132144
errDetachNotEnabled = errors.New("enable detaching by calling webrtc.DetachDataChannels()")
133145
errDetachBeforeOpened = errors.New("datachannel not opened yet, try calling Detach from OnOpen")
134146
errDtlsTransportNotStarted = errors.New("the DTLS transport has not started yet")
@@ -149,9 +161,7 @@ var (
149161
errICEProtocolUnknown = errors.New("unknown protocol")
150162
errICEGathererNotStarted = errors.New("gatherer not started")
151163

152-
errMediaEngineParseError = errors.New("format parse error")
153-
errMediaEngineCodecNotFound = errors.New("could not find codec")
154-
errNetworkTypeUnknown = errors.New("unknown network type")
164+
errNetworkTypeUnknown = errors.New("unknown network type")
155165

156166
errSDPDoesNotMatchOffer = errors.New("new sdp does not match previous offer")
157167
errSDPDoesNotMatchAnswer = errors.New("new sdp does not match previous answer")
@@ -163,16 +173,15 @@ var (
163173
errPeerConnRemoteDescriptionNil = errors.New("remoteDescription has not been set yet")
164174
errPeerConnSingleMediaSectionHasExplicitSSRC = errors.New("single media section has an explicit SSRC")
165175
errPeerConnRemoteSSRCAddTransceiver = errors.New("could not add transceiver for remote SSRC")
166-
errPeerConnSimulcastMidAndRidRTPExtensionRequired = errors.New("mid and rid RTP Extensions required for Simulcast")
176+
errPeerConnSimulcastMidRTPExtensionRequired = errors.New("mid RTP Extensions required for Simulcast")
177+
errPeerConnSimulcastStreamIDRTPExtensionRequired = errors.New("stream id RTP Extensions required for Simulcast")
167178
errPeerConnSimulcastIncomingSSRCFailed = errors.New("incoming SSRC failed Simulcast probing")
168179
errPeerConnAddTransceiverFromKindOnlyAcceptsOne = errors.New("AddTransceiverFromKind only accepts one RtpTransceiverInit")
169180
errPeerConnAddTransceiverFromTrackOnlyAcceptsOne = errors.New("AddTransceiverFromTrack only accepts one RtpTransceiverInit")
170-
errPeerConnCodecsNotFound = errors.New("no codecs found")
171-
errPeerConnAddTransceiverFromKindSupport = errors.New("AddTransceiverFromKind currently only supports recvonly and sendrecv")
172-
errPeerConnAddTransceiverFromTrackOneTransceiver = errors.New("AddTransceiverFromTrack only accepts one RtpTransceiverInit")
181+
errPeerConnAddTransceiverFromKindSupport = errors.New("AddTransceiverFromKind currently only supports recvonly")
182+
errPeerConnAddTransceiverFromTrackSupport = errors.New("AddTransceiverFromTrack currently only supports sendonly and sendrecv")
173183
errPeerConnSetIdentityProviderNotImplemented = errors.New("TODO SetIdentityProvider")
174184
errPeerConnWriteRTCPOpenWriteStream = errors.New("WriteRTCP failed to open WriteStream")
175-
errPeerConnCodecPayloaderNotSet = errors.New("codec payloader not set")
176185
errPeerConnTranscieverMidNil = errors.New("cannot find transceiver with mid")
177186

178187
errRTPReceiverDTLSTransportNil = errors.New("DTLSTransport must not be nil")
@@ -181,11 +190,9 @@ var (
181190
errRTPReceiverForSSRCTrackStreamNotFound = errors.New("no trackStreams found for SSRC")
182191
errRTPReceiverForRIDTrackStreamNotFound = errors.New("no trackStreams found for RID")
183192

184-
errRTPSenderTrackNil = errors.New("Track must not be nil")
185-
errRTPSenderDTLSTransportNil = errors.New("DTLSTransport must not be nil")
186-
errRTPSenderCannotConstructRemoteTrack = errors.New("RTPSender can not be constructed with remote track")
187-
errRTPSenderSendAlreadyCalled = errors.New("Send has already been called")
188-
errRTPSenderStopped = errors.New("RTPSender has been stopped")
193+
errRTPSenderTrackNil = errors.New("Track must not be nil")
194+
errRTPSenderDTLSTransportNil = errors.New("DTLSTransport must not be nil")
195+
errRTPSenderSendAlreadyCalled = errors.New("Send has already been called")
189196

190197
errRTPTransceiverCannotChangeMid = errors.New("errRTPSenderTrackNil")
191198
errRTPTransceiverSetSendingInvalidState = errors.New("invalid state change in RTPTransceiver.setSending")
@@ -195,17 +202,11 @@ var (
195202
errSDPZeroTransceivers = errors.New("addTransceiverSDP() called with 0 transceivers")
196203
errSDPMediaSectionMediaDataChanInvalid = errors.New("invalid Media Section. Media + DataChannel both enabled")
197204
errSDPMediaSectionMultipleTrackInvalid = errors.New("invalid Media Section. Can not have multiple tracks in one MediaSection in UnifiedPlan")
198-
errSDPParseExtMap = errors.New("failed to parse ExtMap")
199-
errSDPRemoteDescriptionChangedExtMap = errors.New("RemoteDescription changed some extmaps values")
200205

201206
errSettingEngineSetAnsweringDTLSRole = errors.New("SetAnsweringDTLSRole must DTLSRoleClient or DTLSRoleServer")
202207

203208
errSignalingStateCannotRollback = errors.New("can't rollback from stable state")
204209
errSignalingStateProposedTransitionInvalid = errors.New("invalid proposed signaling state transition")
205210

206211
errStatsICECandidateStateInvalid = errors.New("cannot convert to StatsICECandidatePairStateSucceeded invalid ice candidate state")
207-
208-
errTrackLocalTrackRead = errors.New("this is a local track and must not be read from")
209-
errTrackLocalTrackWrite = errors.New("this is a remote track and must not be written to")
210-
errTrackSSRCNewTrackZero = errors.New("SSRC supplied to NewTrack() must be non-zero")
211212
)

examples/broadcast/main.go

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,6 @@ func main() { // nolint:gocognit
2323
signal.Decode(<-sdpChan, &offer)
2424
fmt.Println("")
2525

26-
// Since we are answering use PayloadTypes declared by offerer
27-
mediaEngine := webrtc.MediaEngine{}
28-
err := mediaEngine.PopulateFromSDP(offer)
29-
if err != nil {
30-
panic(err)
31-
}
32-
33-
// Create the API object with the MediaEngine
34-
api := webrtc.NewAPI(webrtc.WithMediaEngine(mediaEngine))
35-
3626
peerConnectionConfig := webrtc.Configuration{
3727
ICEServers: []webrtc.ICEServer{
3828
{
@@ -42,7 +32,7 @@ func main() { // nolint:gocognit
4232
}
4333

4434
// Create a new RTCPeerConnection
45-
peerConnection, err := api.NewPeerConnection(peerConnectionConfig)
35+
peerConnection, err := webrtc.NewPeerConnection(peerConnectionConfig)
4636
if err != nil {
4737
panic(err)
4838
}
@@ -52,23 +42,23 @@ func main() { // nolint:gocognit
5242
panic(err)
5343
}
5444

55-
localTrackChan := make(chan *webrtc.Track)
45+
localTrackChan := make(chan *webrtc.TrackLocalStaticRTP)
5646
// Set a handler for when a new remote track starts, this just distributes all our packets
5747
// to connected peers
58-
peerConnection.OnTrack(func(remoteTrack *webrtc.Track, receiver *webrtc.RTPReceiver) {
48+
peerConnection.OnTrack(func(remoteTrack *webrtc.TrackRemote, receiver *webrtc.RTPReceiver) {
5949
// Send a PLI on an interval so that the publisher is pushing a keyframe every rtcpPLIInterval
6050
// This can be less wasteful by processing incoming RTCP events, then we would emit a NACK/PLI when a viewer requests it
6151
go func() {
6252
ticker := time.NewTicker(rtcpPLIInterval)
6353
for range ticker.C {
64-
if rtcpSendErr := peerConnection.WriteRTCP([]rtcp.Packet{&rtcp.PictureLossIndication{MediaSSRC: remoteTrack.SSRC()}}); rtcpSendErr != nil {
54+
if rtcpSendErr := peerConnection.WriteRTCP([]rtcp.Packet{&rtcp.PictureLossIndication{MediaSSRC: uint32(remoteTrack.SSRC())}}); rtcpSendErr != nil {
6555
fmt.Println(rtcpSendErr)
6656
}
6757
}
6858
}()
6959

7060
// Create a local track, all our SFU clients will be fed via this track
71-
localTrack, newTrackErr := peerConnection.NewTrack(remoteTrack.PayloadType(), remoteTrack.SSRC(), "video", "pion")
61+
localTrack, newTrackErr := webrtc.NewTrackLocalStaticRTP(remoteTrack.Codec().RTPCodecCapability, "video", "pion")
7262
if newTrackErr != nil {
7363
panic(newTrackErr)
7464
}
@@ -126,7 +116,7 @@ func main() { // nolint:gocognit
126116
signal.Decode(<-sdpChan, &recvOnlyOffer)
127117

128118
// Create a new PeerConnection
129-
peerConnection, err := api.NewPeerConnection(peerConnectionConfig)
119+
peerConnection, err := webrtc.NewPeerConnection(peerConnectionConfig)
130120
if err != nil {
131121
panic(err)
132122
}

examples/custom-logger/main.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,11 @@ func main() {
6161
panic(err)
6262
}
6363

64+
// We need a DataChannel so we can have ICE Candidates
65+
if _, err = offerPeerConnection.CreateDataChannel("custom-logger", nil); err != nil {
66+
panic(err)
67+
}
68+
6469
// Create a new RTCPeerConnection
6570
answerPeerConnection, err := api.NewPeerConnection(webrtc.Configuration{})
6671
if err != nil {

examples/ice-tcp/main.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ func doSignaling(w http.ResponseWriter, r *http.Request) {
1717

1818
if peerConnection == nil {
1919
m := webrtc.MediaEngine{}
20-
m.RegisterDefaultCodecs()
20+
if err = m.RegisterDefaultCodecs(); err != nil {
21+
panic(err)
22+
}
2123

2224
settingEngine := webrtc.SettingEngine{}
2325

examples/insertable-streams/main.go

Lines changed: 7 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import (
77
"os"
88
"time"
99

10-
"github.com/pion/randutil"
1110
"github.com/pion/webrtc/v3"
1211
"github.com/pion/webrtc/v3/examples/internal/signal"
1312
"github.com/pion/webrtc/v3/pkg/media"
@@ -17,34 +16,7 @@ import (
1716
const cipherKey = 0xAA
1817

1918
func main() {
20-
// Wait for the offer to be pasted
21-
offer := webrtc.SessionDescription{}
22-
signal.Decode(signal.MustReadStdin(), &offer)
23-
24-
// We make our own mediaEngine so we can place the sender's codecs in it. This because we must use the
25-
// dynamic media type from the sender in our answer. This is not required if we are the offerer
26-
mediaEngine := webrtc.MediaEngine{}
27-
err := mediaEngine.PopulateFromSDP(offer)
28-
if err != nil {
29-
panic(err)
30-
}
31-
32-
// Search for VP8 Payload type. If the offer doesn't support VP8 exit since
33-
// since they won't be able to decode anything we send them
34-
var payloadType uint8
35-
for _, videoCodec := range mediaEngine.GetCodecsByKind(webrtc.RTPCodecTypeVideo) {
36-
if videoCodec.Name == "VP8" {
37-
payloadType = videoCodec.PayloadType
38-
break
39-
}
40-
}
41-
if payloadType == 0 {
42-
panic("Remote peer does not support VP8")
43-
}
44-
45-
// Create a new RTCPeerConnection
46-
api := webrtc.NewAPI(webrtc.WithMediaEngine(mediaEngine))
47-
peerConnection, err := api.NewPeerConnection(webrtc.Configuration{
19+
peerConnection, err := webrtc.NewPeerConnection(webrtc.Configuration{
4820
ICEServers: []webrtc.ICEServer{
4921
{
5022
URLs: []string{"stun:stun.l.google.com:19302"},
@@ -56,7 +28,7 @@ func main() {
5628
}
5729

5830
// Create a video track
59-
videoTrack, err := peerConnection.NewTrack(payloadType, randutil.NewMathRandomGenerator().Uint32(), "video", "pion")
31+
videoTrack, err := webrtc.NewTrackLocalStaticSample(webrtc.RTPCodecCapability{MimeType: "video/vp8"}, "video", "pion")
6032
if err != nil {
6133
panic(err)
6234
}
@@ -100,7 +72,7 @@ func main() {
10072
}
10173

10274
time.Sleep(sleepTime)
103-
if ivfErr = videoTrack.WriteSample(media.Sample{Data: frame, Samples: 90000}); ivfErr != nil {
75+
if ivfErr = videoTrack.WriteSample(media.Sample{Data: frame, Duration: time.Second}); ivfErr != nil {
10476
panic(ivfErr)
10577
}
10678
}
@@ -115,6 +87,10 @@ func main() {
11587
}
11688
})
11789

90+
// Wait for the offer to be pasted
91+
offer := webrtc.SessionDescription{}
92+
signal.Decode(signal.MustReadStdin(), &offer)
93+
11894
// Set the remote SessionDescription
11995
if err = peerConnection.SetRemoteDescription(offer); err != nil {
12096
panic(err)

examples/play-from-disk-renegotation/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ <h3> Logs </h3>
1717

1818
<script>
1919
let activeVideos = 0
20-
let pc = new RTCPeerConnection()({
20+
let pc = new RTCPeerConnection({
2121
iceServers: [
2222
{
2323
urls: 'stun:stun.l.google.com:19302'

examples/play-from-disk-renegotation/main.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,8 @@ func createPeerConnection(w http.ResponseWriter, r *http.Request) {
6666

6767
// Add a single video track
6868
func addVideo(w http.ResponseWriter, r *http.Request) {
69-
videoTrack, err := peerConnection.NewTrack(
70-
webrtc.DefaultPayloadTypeVP8,
71-
randutil.NewMathRandomGenerator().Uint32(),
69+
videoTrack, err := webrtc.NewTrackLocalStaticSample(
70+
webrtc.RTPCodecCapability{MimeType: "video/vp8"},
7271
fmt.Sprintf("video-%d", randutil.NewMathRandomGenerator().Uint32()),
7372
fmt.Sprintf("video-%d", randutil.NewMathRandomGenerator().Uint32()),
7473
)
@@ -121,7 +120,7 @@ func main() {
121120

122121
// Read a video file from disk and write it to a webrtc.Track
123122
// When the video has been completely read this exits without error
124-
func writeVideoToTrack(t *webrtc.Track) {
123+
func writeVideoToTrack(t *webrtc.TrackLocalStaticSample) {
125124
// Open a IVF file and start reading using our IVFReader
126125
file, err := os.Open("output.ivf")
127126
if err != nil {
@@ -144,7 +143,7 @@ func writeVideoToTrack(t *webrtc.Track) {
144143
}
145144

146145
time.Sleep(sleepTime)
147-
if err = t.WriteSample(media.Sample{Data: frame, Samples: 90000}); err != nil {
146+
if err = t.WriteSample(media.Sample{Data: frame, Duration: time.Second}); err != nil {
148147
fmt.Printf("Finish writing video track: %s ", err)
149148
return
150149
}

0 commit comments

Comments
 (0)