From 73fdc2fce773b6bed39480da29bc78b167ca9900 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoine=20Bach=C3=A9?= Date: Mon, 28 Jun 2021 22:39:11 +0200 Subject: [PATCH] Update examples TestNonFatalRead now has an timeout. Examples now use Mime types, instead of raw strings. Fixes #839 --- examples/broadcast/main.go | 5 +++ examples/custom-logger/main.go | 42 +++++++++++++++++- examples/data-channels-close/main.go | 25 ++++++++--- examples/data-channels-create/main.go | 25 ++++++++--- examples/data-channels-detach-create/main.go | 25 ++++++++--- examples/data-channels-detach/main.go | 25 ++++++++--- examples/data-channels-flow-control/main.go | 45 +++++++++++++++++++- examples/data-channels/main.go | 25 ++++++++--- examples/insertable-streams/main.go | 21 ++++++++- examples/pion-to-pion/answer/main.go | 20 +++++++-- examples/pion-to-pion/offer/main.go | 20 +++++++-- examples/play-from-disk-renegotation/main.go | 30 ++++++++++--- examples/play-from-disk/main.go | 26 +++++++++-- examples/reflect/main.go | 25 ++++++++--- examples/rtp-forwarder/main.go | 34 ++++++++++----- examples/rtp-to-webrtc/main.go | 13 ++++++ examples/save-to-disk/main.go | 15 ++++--- examples/simulcast/main.go | 33 ++++++++++---- examples/swap-tracks/main.go | 38 ++++++++++++++--- examples/vnet/show-network-usage/main.go | 43 ++++++++++++++++++- internal/mux/mux_test.go | 4 ++ 21 files changed, 459 insertions(+), 80 deletions(-) diff --git a/examples/broadcast/main.go b/examples/broadcast/main.go index e11f76732fc..74fef6974f2 100644 --- a/examples/broadcast/main.go +++ b/examples/broadcast/main.go @@ -38,6 +38,11 @@ func main() { // nolint:gocognit if err != nil { panic(err) } + defer func() { + if cErr := peerConnection.Close(); cErr != nil { + fmt.Printf("cannot close peerConnection: %v\n", cErr) + } + }() // Allow us to receive 1 video track if _, err = peerConnection.AddTransceiverFromKind(webrtc.RTPCodecTypeVideo); err != nil { diff --git a/examples/custom-logger/main.go b/examples/custom-logger/main.go index 49c187d8ac9..215c1bba994 100644 --- a/examples/custom-logger/main.go +++ b/examples/custom-logger/main.go @@ -3,6 +3,7 @@ package main import ( + "context" "fmt" "github.com/pion/logging" @@ -60,6 +61,11 @@ func main() { if err != nil { panic(err) } + defer func() { + if cErr := offerPeerConnection.Close(); cErr != nil { + fmt.Printf("cannot close offerPeerConnection: %v\n", cErr) + } + }() // We need a DataChannel so we can have ICE Candidates if _, err = offerPeerConnection.CreateDataChannel("custom-logger", nil); err != nil { @@ -71,6 +77,39 @@ func main() { if err != nil { panic(err) } + defer func() { + if cErr := answerPeerConnection.Close(); cErr != nil { + fmt.Printf("cannot close answerPeerConnection: %v\n", cErr) + } + }() + + ctx, done := context.WithCancel(context.Background()) + + // Set the handler for Peer connection state + // This will notify you when the peer has connected/disconnected + offerPeerConnection.OnConnectionStateChange(func(s webrtc.PeerConnectionState) { + fmt.Printf("Peer Connection State has changed: %s (offerer)\n", s.String()) + + if s == webrtc.PeerConnectionStateFailed { + // Wait until PeerConnection has had no network activity for 30 seconds or another failure. It may be reconnected using an ICE Restart. + // Use webrtc.PeerConnectionStateDisconnected if you are interested in detecting faster timeout. + // Note that the PeerConnection may come back from PeerConnectionStateDisconnected. + done() + } + }) + + // Set the handler for Peer connection state + // This will notify you when the peer has connected/disconnected + answerPeerConnection.OnConnectionStateChange(func(s webrtc.PeerConnectionState) { + fmt.Printf("Peer Connection State has changed: %s (answerer)\n", s.String()) + + if s == webrtc.PeerConnectionStateFailed { + // Wait until PeerConnection has had no network activity for 30 seconds or another failure. It may be reconnected using an ICE Restart. + // Use webrtc.PeerConnectionStateDisconnected if you are interested in detecting faster timeout. + // Note that the PeerConnection may come back from PeerConnectionStateDisconnected. + done() + } + }) // Set ICE Candidate handler. As soon as a PeerConnection has gathered a candidate // send it to the other peer @@ -126,5 +165,6 @@ func main() { panic(err) } - select {} + // Block until one PeerConnection goes to PeerConnectionStateFailed + <-ctx.Done() } diff --git a/examples/data-channels-close/main.go b/examples/data-channels-close/main.go index 238a2eb952f..69d5f7c032b 100644 --- a/examples/data-channels-close/main.go +++ b/examples/data-channels-close/main.go @@ -1,6 +1,7 @@ package main import ( + "context" "flag" "fmt" "time" @@ -29,11 +30,25 @@ func main() { if err != nil { panic(err) } + defer func() { + if cErr := peerConnection.Close(); cErr != nil { + fmt.Printf("cannot close peerConnection: %v\n", cErr) + } + }() - // Set the handler for ICE connection state + ctx, done := context.WithCancel(context.Background()) + + // Set the handler for Peer connection state // This will notify you when the peer has connected/disconnected - peerConnection.OnICEConnectionStateChange(func(connectionState webrtc.ICEConnectionState) { - fmt.Printf("ICE Connection State has changed: %s\n", connectionState.String()) + peerConnection.OnConnectionStateChange(func(s webrtc.PeerConnectionState) { + fmt.Printf("Peer Connection State has changed: %s\n", s.String()) + + if s == webrtc.PeerConnectionStateFailed { + // Wait until PeerConnection has had no network activity for 30 seconds or another failure. It may be reconnected using an ICE Restart. + // Use webrtc.PeerConnectionStateDisconnected if you are interested in detecting faster timeout. + // Note that the PeerConnection may come back from PeerConnectionStateDisconnected. + done() + } }) // Register data channel creation handling @@ -113,6 +128,6 @@ func main() { // Output the answer in base64 so we can paste it in browser fmt.Println(signal.Encode(*peerConnection.LocalDescription())) - // Block forever - select {} + // Block until PeerConnection goes to PeerConnectionStateFailed + <-ctx.Done() } diff --git a/examples/data-channels-create/main.go b/examples/data-channels-create/main.go index deeee9a514e..aa0a1c30a79 100644 --- a/examples/data-channels-create/main.go +++ b/examples/data-channels-create/main.go @@ -1,6 +1,7 @@ package main import ( + "context" "fmt" "time" @@ -25,6 +26,11 @@ func main() { if err != nil { panic(err) } + defer func() { + if cErr := peerConnection.Close(); cErr != nil { + fmt.Printf("cannot close peerConnection: %v\n", cErr) + } + }() // Create a datachannel with label 'data' dataChannel, err := peerConnection.CreateDataChannel("data", nil) @@ -32,10 +38,19 @@ func main() { panic(err) } - // Set the handler for ICE connection state + ctx, done := context.WithCancel(context.Background()) + + // Set the handler for Peer connection state // This will notify you when the peer has connected/disconnected - peerConnection.OnICEConnectionStateChange(func(connectionState webrtc.ICEConnectionState) { - fmt.Printf("ICE Connection State has changed: %s\n", connectionState.String()) + peerConnection.OnConnectionStateChange(func(s webrtc.PeerConnectionState) { + fmt.Printf("Peer Connection State has changed: %s\n", s.String()) + + if s == webrtc.PeerConnectionStateFailed { + // Wait until PeerConnection has had no network activity for 30 seconds or another failure. It may be reconnected using an ICE Restart. + // Use webrtc.PeerConnectionStateDisconnected if you are interested in detecting faster timeout. + // Note that the PeerConnection may come back from PeerConnectionStateDisconnected. + done() + } }) // Register channel opening handling @@ -92,6 +107,6 @@ func main() { panic(err) } - // Block forever - select {} + // Block until PeerConnection goes to PeerConnectionStateFailed + <-ctx.Done() } diff --git a/examples/data-channels-detach-create/main.go b/examples/data-channels-detach-create/main.go index ecaec3263ff..99540af068a 100644 --- a/examples/data-channels-detach-create/main.go +++ b/examples/data-channels-detach-create/main.go @@ -1,6 +1,7 @@ package main import ( + "context" "fmt" "io" "time" @@ -39,6 +40,11 @@ func main() { if err != nil { panic(err) } + defer func() { + if cErr := peerConnection.Close(); cErr != nil { + fmt.Printf("cannot close peerConnection: %v\n", cErr) + } + }() // Create a datachannel with label 'data' dataChannel, err := peerConnection.CreateDataChannel("data", nil) @@ -46,10 +52,19 @@ func main() { panic(err) } - // Set the handler for ICE connection state + ctx, done := context.WithCancel(context.Background()) + + // Set the handler for Peer connection state // This will notify you when the peer has connected/disconnected - peerConnection.OnICEConnectionStateChange(func(connectionState webrtc.ICEConnectionState) { - fmt.Printf("ICE Connection State has changed: %s\n", connectionState.String()) + peerConnection.OnConnectionStateChange(func(s webrtc.PeerConnectionState) { + fmt.Printf("Peer Connection State has changed: %s\n", s.String()) + + if s == webrtc.PeerConnectionStateFailed { + // Wait until PeerConnection has had no network activity for 30 seconds or another failure. It may be reconnected using an ICE Restart. + // Use webrtc.PeerConnectionStateDisconnected if you are interested in detecting faster timeout. + // Note that the PeerConnection may come back from PeerConnectionStateDisconnected. + done() + } }) // Register channel opening handling @@ -102,8 +117,8 @@ func main() { panic(err) } - // Block forever - select {} + // Block until PeerConnection goes to PeerConnectionStateFailed + <-ctx.Done() } // ReadLoop shows how to read from the datachannel directly diff --git a/examples/data-channels-detach/main.go b/examples/data-channels-detach/main.go index ebfa7b86cea..606ac241e85 100644 --- a/examples/data-channels-detach/main.go +++ b/examples/data-channels-detach/main.go @@ -1,6 +1,7 @@ package main import ( + "context" "fmt" "io" "time" @@ -39,11 +40,25 @@ func main() { if err != nil { panic(err) } + defer func() { + if cErr := peerConnection.Close(); cErr != nil { + fmt.Printf("cannot close peerConnection: %v\n", cErr) + } + }() + + ctx, done := context.WithCancel(context.Background()) - // Set the handler for ICE connection state + // Set the handler for Peer connection state // This will notify you when the peer has connected/disconnected - peerConnection.OnICEConnectionStateChange(func(connectionState webrtc.ICEConnectionState) { - fmt.Printf("ICE Connection State has changed: %s\n", connectionState.String()) + peerConnection.OnConnectionStateChange(func(s webrtc.PeerConnectionState) { + fmt.Printf("Peer Connection State has changed: %s\n", s.String()) + + if s == webrtc.PeerConnectionStateFailed { + // Wait until PeerConnection has had no network activity for 30 seconds or another failure. It may be reconnected using an ICE Restart. + // Use webrtc.PeerConnectionStateDisconnected if you are interested in detecting faster timeout. + // Note that the PeerConnection may come back from PeerConnectionStateDisconnected. + done() + } }) // Register data channel creation handling @@ -101,8 +116,8 @@ func main() { // Output the answer in base64 so we can paste it in browser fmt.Println(signal.Encode(*peerConnection.LocalDescription())) - // Block forever - select {} + // Block until PeerConnection goes to PeerConnectionStateFailed + <-ctx.Done() } // ReadLoop shows how to read from the datachannel directly diff --git a/examples/data-channels-flow-control/main.go b/examples/data-channels-flow-control/main.go index 0fa897fce89..ceb90ba4328 100644 --- a/examples/data-channels-flow-control/main.go +++ b/examples/data-channels-flow-control/main.go @@ -1,7 +1,9 @@ package main import ( + "context" "encoding/json" + "fmt" "log" "sync/atomic" "time" @@ -120,7 +122,18 @@ func createAnswerer() *webrtc.PeerConnection { func main() { offerPC := createOfferer() + defer func() { + if err := offerPC.Close(); err != nil { + fmt.Printf("cannot close offerPC: %v\n", err) + } + }() + answerPC := createAnswerer() + defer func() { + if err := answerPC.Close(); err != nil { + fmt.Printf("cannot close answerPC: %v\n", err) + } + }() // Set ICE Candidate handler. As soon as a PeerConnection has gathered a candidate // send it to the other peer @@ -138,6 +151,34 @@ func main() { } }) + ctx, done := context.WithCancel(context.Background()) + + // Set the handler for Peer connection state + // This will notify you when the peer has connected/disconnected + offerPC.OnConnectionStateChange(func(s webrtc.PeerConnectionState) { + fmt.Printf("Peer Connection State has changed: %s (offerer)\n", s.String()) + + if s == webrtc.PeerConnectionStateFailed { + // Wait until PeerConnection has had no network activity for 30 seconds or another failure. It may be reconnected using an ICE Restart. + // Use webrtc.PeerConnectionStateDisconnected if you are interested in detecting faster timeout. + // Note that the PeerConnection may come back from PeerConnectionStateDisconnected. + done() + } + }) + + // Set the handler for Peer connection state + // This will notify you when the peer has connected/disconnected + answerPC.OnConnectionStateChange(func(s webrtc.PeerConnectionState) { + fmt.Printf("Peer Connection State has changed: %s (answerer)\n", s.String()) + + if s == webrtc.PeerConnectionStateFailed { + // Wait until PeerConnection has had no network activity for 30 seconds or another failure. It may be reconnected using an ICE Restart. + // Use webrtc.PeerConnectionStateDisconnected if you are interested in detecting faster timeout. + // Note that the PeerConnection may come back from PeerConnectionStateDisconnected. + done() + } + }) + // Now, create an offer offer, err := offerPC.CreateOffer(nil) check(err) @@ -155,6 +196,6 @@ func main() { setRemoteDescription(offerPC, desc2) - // Block forever - select {} + // Block until one PeerConnection goes to PeerConnectionStateFailed + <-ctx.Done() } diff --git a/examples/data-channels/main.go b/examples/data-channels/main.go index 89f74002cee..530bf197c40 100644 --- a/examples/data-channels/main.go +++ b/examples/data-channels/main.go @@ -1,6 +1,7 @@ package main import ( + "context" "fmt" "time" @@ -25,11 +26,25 @@ func main() { if err != nil { panic(err) } + defer func() { + if cErr := peerConnection.Close(); cErr != nil { + fmt.Printf("cannot close peerConnection: %v\n", cErr) + } + }() - // Set the handler for ICE connection state + ctx, done := context.WithCancel(context.Background()) + + // Set the handler for Peer connection state // This will notify you when the peer has connected/disconnected - peerConnection.OnICEConnectionStateChange(func(connectionState webrtc.ICEConnectionState) { - fmt.Printf("ICE Connection State has changed: %s\n", connectionState.String()) + peerConnection.OnConnectionStateChange(func(s webrtc.PeerConnectionState) { + fmt.Printf("Peer Connection State has changed: %s\n", s.String()) + + if s == webrtc.PeerConnectionStateFailed { + // Wait until PeerConnection has had no network activity for 30 seconds or another failure. It may be reconnected using an ICE Restart. + // Use webrtc.PeerConnectionStateDisconnected if you are interested in detecting faster timeout. + // Note that the PeerConnection may come back from PeerConnectionStateDisconnected. + done() + } }) // Register data channel creation handling @@ -91,6 +106,6 @@ func main() { // Output the answer in base64 so we can paste it in browser fmt.Println(signal.Encode(*peerConnection.LocalDescription())) - // Block forever - select {} + // Block until PeerConnection goes to PeerConnectionStateFailed + <-ctx.Done() } diff --git a/examples/insertable-streams/main.go b/examples/insertable-streams/main.go index 652e40aacb8..7325fdc643a 100644 --- a/examples/insertable-streams/main.go +++ b/examples/insertable-streams/main.go @@ -28,9 +28,14 @@ func main() { if err != nil { panic(err) } + defer func() { + if cErr := peerConnection.Close(); cErr != nil { + fmt.Printf("cannot close peerConnection: %v\n", cErr) + } + }() // Create a video track - videoTrack, err := webrtc.NewTrackLocalStaticSample(webrtc.RTPCodecCapability{MimeType: "video/vp8"}, "video", "pion") + videoTrack, err := webrtc.NewTrackLocalStaticSample(webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeVP8}, "video", "pion") if err != nil { panic(err) } @@ -102,6 +107,20 @@ func main() { } }) + // Set the handler for Peer connection state + // This will notify you when the peer has connected/disconnected + peerConnection.OnConnectionStateChange(func(s webrtc.PeerConnectionState) { + fmt.Printf("Peer Connection State has changed: %s\n", s.String()) + + if s == webrtc.PeerConnectionStateFailed { + // Wait until PeerConnection has had no network activity for 30 seconds or another failure. It may be reconnected using an ICE Restart. + // Use webrtc.PeerConnectionStateDisconnected if you are interested in detecting faster timeout. + // Note that the PeerConnection may come back from PeerConnectionStateDisconnected. + fmt.Println("Peer Connection has gone to failed exiting") + os.Exit(0) + } + }) + // Wait for the offer to be pasted offer := webrtc.SessionDescription{} signal.Decode(signal.MustReadStdin(), &offer) diff --git a/examples/pion-to-pion/answer/main.go b/examples/pion-to-pion/answer/main.go index 81ad7c8acbf..84cd39d77ff 100644 --- a/examples/pion-to-pion/answer/main.go +++ b/examples/pion-to-pion/answer/main.go @@ -7,6 +7,7 @@ import ( "fmt" "io/ioutil" "net/http" + "os" "sync" "time" @@ -52,6 +53,11 @@ func main() { // nolint:gocognit if err != nil { panic(err) } + defer func() { + if err := peerConnection.Close(); err != nil { + fmt.Printf("cannot close peerConnection: %v\n", err) + } + }() // When an ICE candidate is available send to the other Pion instance // the other Pion instance will add this candidate by calling AddICECandidate @@ -129,10 +135,18 @@ func main() { // nolint:gocognit candidatesMux.Unlock() }) - // Set the handler for ICE connection state + // Set the handler for Peer connection state // This will notify you when the peer has connected/disconnected - peerConnection.OnICEConnectionStateChange(func(connectionState webrtc.ICEConnectionState) { - fmt.Printf("ICE Connection State has changed: %s\n", connectionState.String()) + peerConnection.OnConnectionStateChange(func(s webrtc.PeerConnectionState) { + fmt.Printf("Peer Connection State has changed: %s\n", s.String()) + + if s == webrtc.PeerConnectionStateFailed { + // Wait until PeerConnection has had no network activity for 30 seconds or another failure. It may be reconnected using an ICE Restart. + // Use webrtc.PeerConnectionStateDisconnected if you are interested in detecting faster timeout. + // Note that the PeerConnection may come back from PeerConnectionStateDisconnected. + fmt.Println("Peer Connection has gone to failed exiting") + os.Exit(0) + } }) // Register data channel creation handling diff --git a/examples/pion-to-pion/offer/main.go b/examples/pion-to-pion/offer/main.go index c153b72b7bf..ef845c9f763 100644 --- a/examples/pion-to-pion/offer/main.go +++ b/examples/pion-to-pion/offer/main.go @@ -7,6 +7,7 @@ import ( "fmt" "io/ioutil" "net/http" + "os" "sync" "time" @@ -52,6 +53,11 @@ func main() { //nolint:gocognit if err != nil { panic(err) } + defer func() { + if cErr := peerConnection.Close(); cErr != nil { + fmt.Printf("cannot close peerConnection: %v\n", cErr) + } + }() // When an ICE candidate is available send to the other Pion instance // the other Pion instance will add this candidate by calling AddICECandidate @@ -113,10 +119,18 @@ func main() { //nolint:gocognit panic(err) } - // Set the handler for ICE connection state + // Set the handler for Peer connection state // This will notify you when the peer has connected/disconnected - peerConnection.OnICEConnectionStateChange(func(connectionState webrtc.ICEConnectionState) { - fmt.Printf("ICE Connection State has changed: %s\n", connectionState.String()) + peerConnection.OnConnectionStateChange(func(s webrtc.PeerConnectionState) { + fmt.Printf("Peer Connection State has changed: %s\n", s.String()) + + if s == webrtc.PeerConnectionStateFailed { + // Wait until PeerConnection has had no network activity for 30 seconds or another failure. It may be reconnected using an ICE Restart. + // Use webrtc.PeerConnectionStateDisconnected if you are interested in detecting faster timeout. + // Note that the PeerConnection may come back from PeerConnectionStateDisconnected. + fmt.Println("Peer Connection has gone to failed exiting") + os.Exit(0) + } }) // Register channel opening handling diff --git a/examples/play-from-disk-renegotation/main.go b/examples/play-from-disk-renegotation/main.go index 4aed7b60d74..50b79aca8de 100644 --- a/examples/play-from-disk-renegotation/main.go +++ b/examples/play-from-disk-renegotation/main.go @@ -69,7 +69,7 @@ func createPeerConnection(w http.ResponseWriter, r *http.Request) { // Add a single video track func addVideo(w http.ResponseWriter, r *http.Request) { videoTrack, err := webrtc.NewTrackLocalStaticSample( - webrtc.RTPCodecCapability{MimeType: "video/vp8"}, + webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeVP8}, fmt.Sprintf("video-%d", randutil.NewMathRandomGenerator().Uint32()), fmt.Sprintf("video-%d", randutil.NewMathRandomGenerator().Uint32()), ) @@ -117,11 +117,24 @@ func main() { if peerConnection, err = webrtc.NewPeerConnection(webrtc.Configuration{}); err != nil { panic(err) } + defer func() { + if cErr := peerConnection.Close(); cErr != nil { + fmt.Printf("cannot close peerConnection: %v\n", cErr) + } + }() - // Set the handler for ICE connection state + // Set the handler for Peer connection state // This will notify you when the peer has connected/disconnected - peerConnection.OnICEConnectionStateChange(func(connectionState webrtc.ICEConnectionState) { - fmt.Printf("ICE Connection State has changed: %s\n", connectionState.String()) + peerConnection.OnConnectionStateChange(func(s webrtc.PeerConnectionState) { + fmt.Printf("Peer Connection State has changed: %s\n", s.String()) + + if s == webrtc.PeerConnectionStateFailed { + // Wait until PeerConnection has had no network activity for 30 seconds or another failure. It may be reconnected using an ICE Restart. + // Use webrtc.PeerConnectionStateDisconnected if you are interested in detecting faster timeout. + // Note that the PeerConnection may come back from PeerConnectionStateDisconnected. + fmt.Println("Peer Connection has gone to failed exiting") + os.Exit(0) + } }) http.Handle("/", http.FileServer(http.Dir("."))) @@ -129,8 +142,13 @@ func main() { http.HandleFunc("/addVideo", addVideo) http.HandleFunc("/removeVideo", removeVideo) - fmt.Println("Open http://localhost:8080 to access this demo") - panic(http.ListenAndServe(":8080", nil)) + go func() { + fmt.Println("Open http://localhost:8080 to access this demo") + panic(http.ListenAndServe(":8080", nil)) + }() + + // Block forever + select {} } // Read a video file from disk and write it to a webrtc.Track diff --git a/examples/play-from-disk/main.go b/examples/play-from-disk/main.go index 08615942bfe..2aed3a92807 100644 --- a/examples/play-from-disk/main.go +++ b/examples/play-from-disk/main.go @@ -44,11 +44,17 @@ func main() { if err != nil { panic(err) } + defer func() { + if cErr := peerConnection.Close(); cErr != nil { + fmt.Printf("cannot close peerConnection: %v\n", cErr) + } + }() + iceConnectedCtx, iceConnectedCtxCancel := context.WithCancel(context.Background()) if haveVideoFile { // Create a video track - videoTrack, videoTrackErr := webrtc.NewTrackLocalStaticSample(webrtc.RTPCodecCapability{MimeType: "video/vp8"}, "video", "pion") + videoTrack, videoTrackErr := webrtc.NewTrackLocalStaticSample(webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeVP8}, "video", "pion") if videoTrackErr != nil { panic(videoTrackErr) } @@ -109,7 +115,7 @@ func main() { if haveAudioFile { // Create a audio track - audioTrack, audioTrackErr := webrtc.NewTrackLocalStaticSample(webrtc.RTPCodecCapability{MimeType: "audio/opus"}, "audio", "pion") + audioTrack, audioTrackErr := webrtc.NewTrackLocalStaticSample(webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeOpus}, "audio", "pion") if audioTrackErr != nil { panic(audioTrackErr) } @@ -183,6 +189,20 @@ func main() { } }) + // Set the handler for Peer connection state + // This will notify you when the peer has connected/disconnected + peerConnection.OnConnectionStateChange(func(s webrtc.PeerConnectionState) { + fmt.Printf("Peer Connection State has changed: %s\n", s.String()) + + if s == webrtc.PeerConnectionStateFailed { + // Wait until PeerConnection has had no network activity for 30 seconds or another failure. It may be reconnected using an ICE Restart. + // Use webrtc.PeerConnectionStateDisconnected if you are interested in detecting faster timeout. + // Note that the PeerConnection may come back from PeerConnectionStateDisconnected. + fmt.Println("Peer Connection has gone to failed exiting") + os.Exit(0) + } + }) + // Wait for the offer to be pasted offer := webrtc.SessionDescription{} signal.Decode(signal.MustReadStdin(), &offer) @@ -214,6 +234,6 @@ func main() { // Output the answer in base64 so we can paste it in browser fmt.Println(signal.Encode(*peerConnection.LocalDescription())) - // Block forever + // Block forver select {} } diff --git a/examples/reflect/main.go b/examples/reflect/main.go index 4d75e6fda39..0e667bab0e2 100644 --- a/examples/reflect/main.go +++ b/examples/reflect/main.go @@ -4,6 +4,7 @@ package main import ( "fmt" + "os" "time" "github.com/pion/interceptor" @@ -21,7 +22,7 @@ func main() { // Setup the codecs you want to use. // We'll use a VP8 and Opus but you can also define your own if err := m.RegisterCodec(webrtc.RTPCodecParameters{ - RTPCodecCapability: webrtc.RTPCodecCapability{MimeType: "video/VP8", ClockRate: 90000, Channels: 0, SDPFmtpLine: "", RTCPFeedback: nil}, + RTPCodecCapability: webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeVP8, ClockRate: 90000, Channels: 0, SDPFmtpLine: "", RTCPFeedback: nil}, PayloadType: 96, }, webrtc.RTPCodecTypeVideo); err != nil { panic(err) @@ -54,9 +55,14 @@ func main() { if err != nil { panic(err) } + defer func() { + if cErr := peerConnection.Close(); cErr != nil { + fmt.Printf("cannot close peerConnection: %v\n", cErr) + } + }() // Create Track that we send video back to browser on - outputTrack, err := webrtc.NewTrackLocalStaticRTP(webrtc.RTPCodecCapability{MimeType: "video/vp8"}, "video", "pion") + outputTrack, err := webrtc.NewTrackLocalStaticRTP(webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeVP8}, "video", "pion") if err != nil { panic(err) } @@ -117,10 +123,19 @@ func main() { } } }) - // Set the handler for ICE connection state + + // Set the handler for Peer connection state // This will notify you when the peer has connected/disconnected - peerConnection.OnICEConnectionStateChange(func(connectionState webrtc.ICEConnectionState) { - fmt.Printf("Connection State has changed %s \n", connectionState.String()) + peerConnection.OnConnectionStateChange(func(s webrtc.PeerConnectionState) { + fmt.Printf("Peer Connection State has changed: %s\n", s.String()) + + if s == webrtc.PeerConnectionStateFailed { + // Wait until PeerConnection has had no network activity for 30 seconds or another failure. It may be reconnected using an ICE Restart. + // Use webrtc.PeerConnectionStateDisconnected if you are interested in detecting faster timeout. + // Note that the PeerConnection may come back from PeerConnectionStateDisconnected. + fmt.Println("Peer Connection has gone to failed exiting") + os.Exit(0) + } }) // Create an answer diff --git a/examples/rtp-forwarder/main.go b/examples/rtp-forwarder/main.go index a1b6c639878..ebce74421a5 100644 --- a/examples/rtp-forwarder/main.go +++ b/examples/rtp-forwarder/main.go @@ -3,9 +3,9 @@ package main import ( - "context" "fmt" "net" + "os" "time" "github.com/pion/interceptor" @@ -30,12 +30,12 @@ func main() { // Setup the codecs you want to use. // We'll use a VP8 and Opus but you can also define your own if err := m.RegisterCodec(webrtc.RTPCodecParameters{ - RTPCodecCapability: webrtc.RTPCodecCapability{MimeType: "video/VP8", ClockRate: 90000, Channels: 0, SDPFmtpLine: "", RTCPFeedback: nil}, + RTPCodecCapability: webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeVP8, ClockRate: 90000, Channels: 0, SDPFmtpLine: "", RTCPFeedback: nil}, }, webrtc.RTPCodecTypeVideo); err != nil { panic(err) } if err := m.RegisterCodec(webrtc.RTPCodecParameters{ - RTPCodecCapability: webrtc.RTPCodecCapability{MimeType: "audio/opus", ClockRate: 48000, Channels: 0, SDPFmtpLine: "", RTCPFeedback: nil}, + RTPCodecCapability: webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeOpus, ClockRate: 48000, Channels: 0, SDPFmtpLine: "", RTCPFeedback: nil}, }, webrtc.RTPCodecTypeAudio); err != nil { panic(err) } @@ -68,6 +68,11 @@ func main() { if err != nil { panic(err) } + defer func() { + if cErr := peerConnection.Close(); cErr != nil { + fmt.Printf("cannot close peerConnection: %v\n", cErr) + } + }() // Allow us to receive 1 audio track, and 1 video track if _, err = peerConnection.AddTransceiverFromKind(webrtc.RTPCodecTypeAudio); err != nil { @@ -163,9 +168,6 @@ func main() { } }) - // Create context - ctx, cancel := context.WithCancel(context.Background()) - // Set the handler for ICE connection state // This will notify you when the peer has connected/disconnected peerConnection.OnICEConnectionStateChange(func(connectionState webrtc.ICEConnectionState) { @@ -173,10 +175,20 @@ func main() { if connectionState == webrtc.ICEConnectionStateConnected { fmt.Println("Ctrl+C the remote client to stop the demo") - } else if connectionState == webrtc.ICEConnectionStateFailed || - connectionState == webrtc.ICEConnectionStateDisconnected { + } + }) + + // Set the handler for Peer connection state + // This will notify you when the peer has connected/disconnected + peerConnection.OnConnectionStateChange(func(s webrtc.PeerConnectionState) { + fmt.Printf("Peer Connection State has changed: %s\n", s.String()) + + if s == webrtc.PeerConnectionStateFailed { + // Wait until PeerConnection has had no network activity for 30 seconds or another failure. It may be reconnected using an ICE Restart. + // Use webrtc.PeerConnectionStateDisconnected if you are interested in detecting faster timeout. + // Note that the PeerConnection may come back from PeerConnectionStateDisconnected. fmt.Println("Done forwarding") - cancel() + os.Exit(0) } }) @@ -211,6 +223,6 @@ func main() { // Output the answer in base64 so we can paste it in browser fmt.Println(signal.Encode(*peerConnection.LocalDescription())) - // Wait for context to be done - <-ctx.Done() + // Block forever + select {} } diff --git a/examples/rtp-to-webrtc/main.go b/examples/rtp-to-webrtc/main.go index 04dded41e0b..73ac87c328c 100644 --- a/examples/rtp-to-webrtc/main.go +++ b/examples/rtp-to-webrtc/main.go @@ -3,7 +3,9 @@ package main import ( + "errors" "fmt" + "io" "net" "github.com/pion/webrtc/v3" @@ -59,6 +61,12 @@ func main() { // This will notify you when the peer has connected/disconnected peerConnection.OnICEConnectionStateChange(func(connectionState webrtc.ICEConnectionState) { fmt.Printf("Connection State has changed %s \n", connectionState.String()) + + if connectionState == webrtc.ICEConnectionStateFailed { + if closeErr := peerConnection.Close(); closeErr != nil { + panic(closeErr) + } + } }) // Wait for the offer to be pasted @@ -101,6 +109,11 @@ func main() { } if _, err = videoTrack.Write(inboundRTPPacket[:n]); err != nil { + if errors.Is(err, io.ErrClosedPipe) { + // The peerConnection has been closed. + return + } + panic(err) } } diff --git a/examples/save-to-disk/main.go b/examples/save-to-disk/main.go index c2b68c83250..c657f218b31 100644 --- a/examples/save-to-disk/main.go +++ b/examples/save-to-disk/main.go @@ -133,19 +133,22 @@ func main() { if connectionState == webrtc.ICEConnectionStateConnected { fmt.Println("Ctrl+C the remote client to stop the demo") - } else if connectionState == webrtc.ICEConnectionStateFailed || - connectionState == webrtc.ICEConnectionStateDisconnected { - closeErr := oggFile.Close() - if closeErr != nil { + } else if connectionState == webrtc.ICEConnectionStateFailed { + if closeErr := oggFile.Close(); closeErr != nil { panic(closeErr) } - closeErr = ivfFile.Close() - if closeErr != nil { + if closeErr := ivfFile.Close(); closeErr != nil { panic(closeErr) } fmt.Println("Done writing media files") + + // Gracefully shutdown the peer connection + if closeErr := peerConnection.Close(); closeErr != nil { + panic(closeErr) + } + os.Exit(0) } }) diff --git a/examples/simulcast/main.go b/examples/simulcast/main.go index e035907c3a0..c124b3474a0 100644 --- a/examples/simulcast/main.go +++ b/examples/simulcast/main.go @@ -3,6 +3,7 @@ package main import ( + "context" "errors" "fmt" "io" @@ -57,23 +58,28 @@ func main() { if err != nil { panic(err) } + defer func() { + if cErr := peerConnection.Close(); cErr != nil { + fmt.Printf("cannot close peerConnection: %v\n", cErr) + } + }() outputTracks := map[string]*webrtc.TrackLocalStaticRTP{} // Create Track that we send video back to browser on - outputTrack, err := webrtc.NewTrackLocalStaticRTP(webrtc.RTPCodecCapability{MimeType: "video/vp8"}, "video_q", "pion_q") + outputTrack, err := webrtc.NewTrackLocalStaticRTP(webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeVP8}, "video_q", "pion_q") if err != nil { panic(err) } outputTracks["q"] = outputTrack - outputTrack, err = webrtc.NewTrackLocalStaticRTP(webrtc.RTPCodecCapability{MimeType: "video/vp8"}, "video_h", "pion_h") + outputTrack, err = webrtc.NewTrackLocalStaticRTP(webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeVP8}, "video_h", "pion_h") if err != nil { panic(err) } outputTracks["h"] = outputTrack - outputTrack, err = webrtc.NewTrackLocalStaticRTP(webrtc.RTPCodecCapability{MimeType: "video/vp8"}, "video_f", "pion_f") + outputTrack, err = webrtc.NewTrackLocalStaticRTP(webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeVP8}, "video_f", "pion_f") if err != nil { panic(err) } @@ -140,9 +146,20 @@ func main() { } } }) - // Set the handler for ICE connection state and update chan if connected - peerConnection.OnICEConnectionStateChange(func(connectionState webrtc.ICEConnectionState) { - fmt.Printf("Connection State has changed %s \n", connectionState.String()) + + ctx, done := context.WithCancel(context.Background()) + + // Set the handler for Peer connection state + // This will notify you when the peer has connected/disconnected + peerConnection.OnConnectionStateChange(func(s webrtc.PeerConnectionState) { + fmt.Printf("Peer Connection State has changed: %s\n", s.String()) + + if s == webrtc.PeerConnectionStateFailed { + // Wait until PeerConnection has had no network activity for 30 seconds or another failure. It may be reconnected using an ICE Restart. + // Use webrtc.PeerConnectionStateDisconnected if you are interested in detecting faster timeout. + // Note that the PeerConnection may come back from PeerConnectionStateDisconnected. + done() + } }) // Create an answer @@ -168,6 +185,6 @@ func main() { // Output the answer in base64 so we can paste it in browser fmt.Println(signal.Encode(*peerConnection.LocalDescription())) - // Block forever - select {} + // Block until PeerConnection goes to PeerConnectionStateFailed + <-ctx.Done() } diff --git a/examples/swap-tracks/main.go b/examples/swap-tracks/main.go index df14458cf95..90ab309d980 100644 --- a/examples/swap-tracks/main.go +++ b/examples/swap-tracks/main.go @@ -3,6 +3,7 @@ package main import ( + "context" "errors" "fmt" "io" @@ -30,9 +31,14 @@ func main() { // nolint:gocognit if err != nil { panic(err) } + defer func() { + if cErr := peerConnection.Close(); cErr != nil { + fmt.Printf("cannot close peerConnection: %v\n", cErr) + } + }() // Create Track that we send video back to browser on - outputTrack, err := webrtc.NewTrackLocalStaticRTP(webrtc.RTPCodecCapability{MimeType: "video/vp8"}, "video", "pion") + outputTrack, err := webrtc.NewTrackLocalStaticRTP(webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeVP8}, "video", "pion") if err != nil { panic(err) } @@ -114,9 +120,20 @@ func main() { // nolint:gocognit } } }) - // Set the handler for ICE connection state and update chan if connected - peerConnection.OnICEConnectionStateChange(func(connectionState webrtc.ICEConnectionState) { - fmt.Printf("Connection State has changed %s \n", connectionState.String()) + + ctx, done := context.WithCancel(context.Background()) + + // Set the handler for Peer connection state + // This will notify you when the peer has connected/disconnected + peerConnection.OnConnectionStateChange(func(s webrtc.PeerConnectionState) { + fmt.Printf("Peer Connection State has changed: %s\n", s.String()) + + if s == webrtc.PeerConnectionStateFailed { + // Wait until PeerConnection has had no network activity for 30 seconds or another failure. It may be reconnected using an ICE Restart. + // Use webrtc.PeerConnectionStateDisconnected if you are interested in detecting faster timeout. + // Note that the PeerConnection may come back from PeerConnectionStateDisconnected. + done() + } }) // Create an answer @@ -153,7 +170,12 @@ func main() { // nolint:gocognit // Keep an increasing sequence number packet.SequenceNumber = i // Write out the packet, ignoring closed pipe if nobody is listening - if err := outputTrack.WriteRTP(packet); err != nil && !errors.Is(err, io.ErrClosedPipe) { + if err := outputTrack.WriteRTP(packet); err != nil { + if errors.Is(err, io.ErrClosedPipe) { + // The peerConnection has been closed. + return + } + panic(err) } } @@ -162,6 +184,12 @@ func main() { // nolint:gocognit // Wait for connection, then rotate the track every 5s fmt.Printf("Waiting for connection\n") for { + select { + case <-ctx.Done(): + return + default: + } + // We haven't gotten any tracks yet if trackCount == 0 { continue diff --git a/examples/vnet/show-network-usage/main.go b/examples/vnet/show-network-usage/main.go index 91efd5524f8..bbb19a2d931 100644 --- a/examples/vnet/show-network-usage/main.go +++ b/examples/vnet/show-network-usage/main.go @@ -3,6 +3,8 @@ package main import ( + "context" + "fmt" "log" "net" "sync/atomic" @@ -106,9 +108,47 @@ func main() { offerPeerConnection, err := offerAPI.NewPeerConnection(webrtc.Configuration{}) panicIfError(err) + defer func() { + if cErr := offerPeerConnection.Close(); cErr != nil { + fmt.Printf("cannot close offerPeerConnection: %v\n", cErr) + } + }() answerPeerConnection, err := answerAPI.NewPeerConnection(webrtc.Configuration{}) panicIfError(err) + defer func() { + if cErr := answerPeerConnection.Close(); cErr != nil { + fmt.Printf("cannot close answerPeerConnection: %v\n", cErr) + } + }() + + ctx, done := context.WithCancel(context.Background()) + + // Set the handler for Peer connection state + // This will notify you when the peer has connected/disconnected + offerPeerConnection.OnConnectionStateChange(func(s webrtc.PeerConnectionState) { + fmt.Printf("Peer Connection State has changed: %s (offerer)\n", s.String()) + + if s == webrtc.PeerConnectionStateFailed { + // Wait until PeerConnection has had no network activity for 30 seconds or another failure. It may be reconnected using an ICE Restart. + // Use webrtc.PeerConnectionStateDisconnected if you are interested in detecting faster timeout. + // Note that the PeerConnection may come back from PeerConnectionStateDisconnected. + done() + } + }) + + // Set the handler for Peer connection state + // This will notify you when the peer has connected/disconnected + answerPeerConnection.OnConnectionStateChange(func(s webrtc.PeerConnectionState) { + fmt.Printf("Peer Connection State has changed: %s (answerer)\n", s.String()) + + if s == webrtc.PeerConnectionStateFailed { + // Wait until PeerConnection has had no network activity for 30 seconds or another failure. It may be reconnected using an ICE Restart. + // Use webrtc.PeerConnectionStateDisconnected if you are interested in detecting faster timeout. + // Note that the PeerConnection may come back from PeerConnectionStateDisconnected. + done() + } + }) // Set ICE Candidate handler. As soon as a PeerConnection has gathered a candidate // send it to the other peer @@ -158,7 +198,8 @@ func main() { panicIfError(answerPeerConnection.SetLocalDescription(answer)) panicIfError(offerPeerConnection.SetRemoteDescription(answer)) - select {} + // Block until one PeerConnection goes to PeerConnectionStateFailed + <-ctx.Done() } func panicIfError(err error) { diff --git a/internal/mux/mux_test.go b/internal/mux/mux_test.go index e8baaa09e85..6b6a23dadee 100644 --- a/internal/mux/mux_test.go +++ b/internal/mux/mux_test.go @@ -106,6 +106,10 @@ func (m *muxErrorConn) Read(b []byte) (n int, err error) { pion/webrtc#1720 */ func TestNonFatalRead(t *testing.T) { + // Limit runtime in case of deadlocks + lim := test.TimeOut(time.Second * 20) + defer lim.Stop() + expectedData := []byte("expectedData") // In memory pipe