-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Demonstrate how to use Trickle ICE when communicating pion-to-pion
- Loading branch information
1 parent
7c18bbc
commit 7124c22
Showing
4 changed files
with
335 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# pion-to-pion-trickle | ||
pion-to-pion-trickle is an example of two pion instances communicating directly! | ||
This example uses Trickle ICE, this allows communication to begin before gathering | ||
has completed. | ||
|
||
See `pion-to-pion` example of a non-Trickle version of this. | ||
|
||
The SDP offer and answer are exchanged automatically over HTTP. | ||
The `answer` side acts like a HTTP server and should therefore be ran first. | ||
|
||
## Instructions | ||
First run `answer`: | ||
```sh | ||
go install github.com/pion/webrtc/examples/pion-to-pion/answer | ||
answer | ||
``` | ||
Next, run `offer`: | ||
```sh | ||
go install github.com/pion/webrtc/examples/pion-to-pion/offer | ||
offer | ||
``` | ||
|
||
You should see them connect and start to exchange messages. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
package main | ||
|
||
import ( | ||
"bytes" | ||
"encoding/json" | ||
"flag" | ||
"fmt" | ||
"io/ioutil" | ||
"net/http" | ||
"time" | ||
|
||
"github.com/pion/webrtc/v2" | ||
|
||
"github.com/pion/webrtc/v2/examples/internal/signal" | ||
) | ||
|
||
func main() { | ||
offerAddr := flag.String("offer-address", "localhost:50000", "Address that the Offer HTTP server is hosted on.") | ||
answerAddr := flag.String("answer-address", ":60000", "Address that the Answer HTTP server is hosted on.") | ||
flag.Parse() | ||
|
||
// Everything below is the Pion WebRTC API! Thanks for using it ❤️. | ||
|
||
// Prepare the configuration | ||
config := webrtc.Configuration{ | ||
ICEServers: []webrtc.ICEServer{ | ||
{ | ||
URLs: []string{"stun:stun.l.google.com:19302"}, | ||
}, | ||
}, | ||
} | ||
|
||
// Create a new API with Trickle ICE enabled | ||
// This SettingEngine allows non-standard WebRTC behavior | ||
s := webrtc.SettingEngine{} | ||
s.SetTrickle(true) | ||
api := webrtc.NewAPI(webrtc.WithSettingEngine(s)) | ||
|
||
// Create a new RTCPeerConnection | ||
peerConnection, err := api.NewPeerConnection(config) | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
// When an ICE candidate is available send to the other Pion instance | ||
// the other Pion instance will add this candidate by calling AddICECandidate | ||
peerConnection.OnICECandidate(func(c *webrtc.ICECandidate) { | ||
if c == nil { | ||
return | ||
} | ||
|
||
payload := []byte(c.ToJSON().Candidate) | ||
resp, onICECandidateErr := http.Post(fmt.Sprintf("http://%s/candidate", *answerAddr), "application/json; charset=utf-8", bytes.NewReader(payload)) | ||
if onICECandidateErr != nil { | ||
panic(onICECandidateErr) | ||
} | ||
defer func() { | ||
closeErr := resp.Body.Close() | ||
if closeErr != nil { | ||
panic(closeErr) | ||
} | ||
}() | ||
}) | ||
|
||
// A HTTP handler that allows the other Pion instance to send us ICE candidates | ||
// This allows us to add ICE candidates faster, we don't have to wait for STUN or TURN | ||
// candidates which may be slower | ||
http.HandleFunc("/candidate", func(w http.ResponseWriter, r *http.Request) { | ||
candidate, candidateErr := ioutil.ReadAll(r.Body) | ||
if candidateErr != nil { | ||
panic(candidateErr) | ||
} | ||
if candidateErr := peerConnection.AddICECandidate(webrtc.ICECandidateInit{Candidate: string(candidate)}); candidateErr != nil { | ||
panic(candidateErr) | ||
} | ||
}) | ||
|
||
// A HTTP handler that processes a SessionDescription given to us from the other Pion process | ||
http.HandleFunc("/sdp", func(w http.ResponseWriter, r *http.Request) { | ||
sdp := webrtc.SessionDescription{} | ||
if err := json.NewDecoder(r.Body).Decode(&sdp); err != nil { | ||
panic(err) | ||
} | ||
|
||
if err := peerConnection.SetRemoteDescription(sdp); err != nil { | ||
panic(err) | ||
} | ||
|
||
// Create an answer to send to the other process | ||
answer, err := peerConnection.CreateAnswer(nil) | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
// Sets the LocalDescription, and starts our UDP listeners | ||
err = peerConnection.SetLocalDescription(answer) | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
// Send our answer to the HTTP server listening in the other process | ||
payload, err := json.Marshal(answer) | ||
if err != nil { | ||
panic(err) | ||
} | ||
resp, err := http.Post(fmt.Sprintf("http://%s/sdp", *offerAddr), "application/json; charset=utf-8", bytes.NewReader(payload)) | ||
if err != nil { | ||
panic(err) | ||
} | ||
defer func() { | ||
closeErr := resp.Body.Close() | ||
if closeErr != nil { | ||
panic(closeErr) | ||
} | ||
}() | ||
}) | ||
// Start HTTP server that accepts requests from the offer process | ||
go func() { panic(http.ListenAndServe(*answerAddr, nil)) }() | ||
|
||
// Set the handler for ICE 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()) | ||
}) | ||
|
||
// Register data channel creation handling | ||
peerConnection.OnDataChannel(func(d *webrtc.DataChannel) { | ||
fmt.Printf("New DataChannel %s %d\n", d.Label(), d.ID()) | ||
|
||
// Register channel opening handling | ||
d.OnOpen(func() { | ||
fmt.Printf("Data channel '%s'-'%d' open. Random messages will now be sent to any connected DataChannels every 5 seconds\n", d.Label(), d.ID()) | ||
|
||
for range time.NewTicker(5 * time.Second).C { | ||
message := signal.RandSeq(15) | ||
fmt.Printf("Sending '%s'\n", message) | ||
|
||
// Send the message as text | ||
sendTextErr := d.SendText(message) | ||
if sendTextErr != nil { | ||
panic(sendTextErr) | ||
} | ||
} | ||
}) | ||
|
||
// Register text message handling | ||
d.OnMessage(func(msg webrtc.DataChannelMessage) { | ||
fmt.Printf("Message from DataChannel '%s': '%s'\n", d.Label(), string(msg.Data)) | ||
}) | ||
}) | ||
|
||
// Block forever | ||
select {} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
package main | ||
|
||
import ( | ||
"bytes" | ||
"encoding/json" | ||
"flag" | ||
"fmt" | ||
"io/ioutil" | ||
"net/http" | ||
"time" | ||
|
||
"github.com/pion/webrtc/v2" | ||
|
||
"github.com/pion/webrtc/v2/examples/internal/signal" | ||
) | ||
|
||
func main() { | ||
offerAddr := flag.String("offer-address", ":50000", "Address that the Offer HTTP server is hosted on.") | ||
answerAddr := flag.String("answer-address", "127.0.0.1:60000", "Address that the Answer HTTP server is hosted on.") | ||
flag.Parse() | ||
|
||
// Everything below is the Pion WebRTC API! Thanks for using it ❤️. | ||
|
||
// Prepare the configuration | ||
config := webrtc.Configuration{ | ||
ICEServers: []webrtc.ICEServer{ | ||
{ | ||
URLs: []string{"stun:stun.l.google.com:19302"}, | ||
}, | ||
}, | ||
} | ||
|
||
// Create a new API with Trickle ICE enabled | ||
// This SettingEngine allows non-standard WebRTC behavior | ||
s := webrtc.SettingEngine{} | ||
s.SetTrickle(true) | ||
api := webrtc.NewAPI(webrtc.WithSettingEngine(s)) | ||
|
||
// Create a new RTCPeerConnection | ||
peerConnection, err := api.NewPeerConnection(config) | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
// When an ICE candidate is available send to the other Pion instance | ||
// the other Pion instance will add this candidate by calling AddICECandidate | ||
peerConnection.OnICECandidate(func(c *webrtc.ICECandidate) { | ||
if c == nil { | ||
return | ||
} | ||
|
||
payload := []byte(c.ToJSON().Candidate) | ||
resp, onICECandidateErr := http.Post(fmt.Sprintf("http://%s/candidate", *answerAddr), "application/json; charset=utf-8", bytes.NewReader(payload)) | ||
if onICECandidateErr != nil { | ||
panic(onICECandidateErr) | ||
} | ||
defer func() { | ||
closeErr := resp.Body.Close() | ||
if closeErr != nil { | ||
panic(closeErr) | ||
} | ||
}() | ||
}) | ||
|
||
// A HTTP handler that allows the other Pion instance to send us ICE candidates | ||
// This allows us to add ICE candidates faster, we don't have to wait for STUN or TURN | ||
// candidates which may be slower | ||
http.HandleFunc("/candidate", func(w http.ResponseWriter, r *http.Request) { | ||
candidate, candidateErr := ioutil.ReadAll(r.Body) | ||
if candidateErr != nil { | ||
panic(candidateErr) | ||
} | ||
if candidateErr := peerConnection.AddICECandidate(webrtc.ICECandidateInit{Candidate: string(candidate)}); candidateErr != nil { | ||
panic(candidateErr) | ||
} | ||
}) | ||
|
||
// A HTTP handler that processes a SessionDescription given to us from the other Pion process | ||
http.HandleFunc("/sdp", func(w http.ResponseWriter, r *http.Request) { | ||
sdp := webrtc.SessionDescription{} | ||
if sdpErr := json.NewDecoder(r.Body).Decode(&sdp); sdpErr != nil { | ||
panic(sdpErr) | ||
} | ||
|
||
if sdpErr := peerConnection.SetRemoteDescription(sdp); sdpErr != nil { | ||
panic(sdpErr) | ||
} | ||
}) | ||
// Start HTTP server that accepts requests from the answer process | ||
go func() { panic(http.ListenAndServe(*offerAddr, nil)) }() | ||
|
||
// Create a datachannel with label 'data' | ||
dataChannel, err := peerConnection.CreateDataChannel("data", nil) | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
// Set the handler for ICE 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()) | ||
}) | ||
|
||
// Register channel opening handling | ||
dataChannel.OnOpen(func() { | ||
fmt.Printf("Data channel '%s'-'%d' open. Random messages will now be sent to any connected DataChannels every 5 seconds\n", dataChannel.Label(), dataChannel.ID()) | ||
|
||
for range time.NewTicker(5 * time.Second).C { | ||
message := signal.RandSeq(15) | ||
fmt.Printf("Sending '%s'\n", message) | ||
|
||
// Send the message as text | ||
sendTextErr := dataChannel.SendText(message) | ||
if sendTextErr != nil { | ||
panic(sendTextErr) | ||
} | ||
} | ||
}) | ||
|
||
// Register text message handling | ||
dataChannel.OnMessage(func(msg webrtc.DataChannelMessage) { | ||
fmt.Printf("Message from DataChannel '%s': '%s'\n", dataChannel.Label(), string(msg.Data)) | ||
}) | ||
|
||
// Create an offer to send to the other process | ||
offer, err := peerConnection.CreateOffer(nil) | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
// Sets the LocalDescription, and starts our UDP listeners | ||
if err = peerConnection.SetLocalDescription(offer); err != nil { | ||
panic(err) | ||
} | ||
|
||
// Send our offer to the HTTP server listening in the other process | ||
payload, err := json.Marshal(offer) | ||
if err != nil { | ||
panic(err) | ||
} | ||
resp, err := http.Post(fmt.Sprintf("http://%s/sdp", *answerAddr), "application/json; charset=utf-8", bytes.NewReader(payload)) | ||
if err != nil { | ||
panic(err) | ||
} | ||
defer func() { | ||
closeErr := resp.Body.Close() | ||
if closeErr != nil { | ||
panic(closeErr) | ||
} | ||
}() | ||
|
||
// Block forever | ||
select {} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters