Add examples/ping-pong

Simple demonstration of how to use ICE Agent
This commit is contained in:
Sean DuBois
2020-10-08 10:08:23 -07:00
parent 16697891be
commit 5cc522b7c8
2 changed files with 211 additions and 0 deletions

View File

@@ -0,0 +1,34 @@
# ping-pong
This example demonstrates how to connect two peers via ICE. Once started they send the current time between each other.
Currently this example exchanges candidates over a HTTP server running on localhost. In a real world setup `pion/ice` will typically
exchange auth and candidates via a signaling server.
## Instruction
### Run controlling
```sh
go run main.go -controlling
```
### Run controlled
```sh
go run main.go
```
### Press enter in both to start the connection!
You will see terminal output showing the messages being sent back and forth
```
Local Agent is controlled
Press 'Enter' when both processes have started
ICE Connection State has changed: Checking
ICE Connection State has changed: Connected
Sent: 'fCFXXlnGmXdYjOy'
Received: 'EpqTQYLQMUCjBDX'
Sent: 'yhgOtrufSfVmvrR'
Received: 'xYSTPxBPZKfgnFr'
```

177
examples/ping-pong/main.go Normal file
View File

@@ -0,0 +1,177 @@
package main
import (
"bufio"
"context"
"flag"
"fmt"
"net/http"
"net/url"
"os"
"time"
"github.com/pion/ice/v2"
"github.com/pion/randutil"
)
var (
isControlling bool
iceAgent *ice.Agent
remoteAuthChannel chan string
localHTTPPort, remoteHTTPPort int
)
// HTTP Listener to get ICE Credentials from remote Peer
func remoteAuth(w http.ResponseWriter, r *http.Request) {
if err := r.ParseForm(); err != nil {
panic(err)
}
remoteAuthChannel <- r.PostForm["ufrag"][0]
remoteAuthChannel <- r.PostForm["pwd"][0]
}
// HTTP Listener to get ICE Candidate from remote Peer
func remoteCandidate(w http.ResponseWriter, r *http.Request) {
if err := r.ParseForm(); err != nil {
panic(err)
}
c, err := ice.UnmarshalCandidate(r.PostForm["candidate"][0])
if err != nil {
panic(err)
}
if err := iceAgent.AddRemoteCandidate(c); err != nil {
panic(err)
}
}
func main() {
var (
err error
conn *ice.Conn
)
remoteAuthChannel = make(chan string, 3)
flag.BoolVar(&isControlling, "controlling", false, "is ICE Agent controlling")
flag.Parse()
if isControlling {
localHTTPPort = 9000
remoteHTTPPort = 9001
} else {
localHTTPPort = 9001
remoteHTTPPort = 9000
}
http.HandleFunc("/remoteAuth", remoteAuth)
http.HandleFunc("/remoteCandidate", remoteCandidate)
go func() {
if err = http.ListenAndServe(fmt.Sprintf(":%d", localHTTPPort), nil); err != nil {
panic(err)
}
}()
if isControlling {
fmt.Println("Local Agent is controlling")
} else {
fmt.Println("Local Agent is controlled")
}
fmt.Print("Press 'Enter' when both processes have started")
if _, err = bufio.NewReader(os.Stdin).ReadBytes('\n'); err != nil {
panic(err)
}
iceAgent, err = ice.NewAgent(&ice.AgentConfig{
NetworkTypes: []ice.NetworkType{ice.NetworkTypeUDP4},
})
if err != nil {
panic(err)
}
// When we have gathered a new ICE Candidate send it to the remote peer
if err = iceAgent.OnCandidate(func(c ice.Candidate) {
if c == nil {
return
}
_, err = http.PostForm(fmt.Sprintf("http://localhost:%d/remoteCandidate", remoteHTTPPort),
url.Values{
"candidate": {c.Marshal()},
})
if err != nil {
panic(err)
}
}); err != nil {
panic(err)
}
// When ICE Connection state has change print to stdout
if err = iceAgent.OnConnectionStateChange(func(c ice.ConnectionState) {
fmt.Printf("ICE Connection State has changed: %s\n", c.String())
}); err != nil {
panic(err)
}
// Get the local auth details and send to remote peer
localUfrag, localPwd, err := iceAgent.GetLocalUserCredentials()
if err != nil {
panic(err)
}
_, err = http.PostForm(fmt.Sprintf("http://localhost:%d/remoteAuth", remoteHTTPPort),
url.Values{
"ufrag": {localUfrag},
"pwd": {localPwd},
})
if err != nil {
panic(err)
}
remoteUfrag := <-remoteAuthChannel
remotePwd := <-remoteAuthChannel
if err = iceAgent.GatherCandidates(); err != nil {
panic(err)
}
// Start the ICE Agent. One side must be controlled, and the other must be controlling
if isControlling {
conn, err = iceAgent.Dial(context.TODO(), remoteUfrag, remotePwd)
} else {
conn, err = iceAgent.Accept(context.TODO(), remoteUfrag, remotePwd)
}
if err != nil {
panic(err)
}
// Send messages in a loop to the remote peer
go func() {
for {
time.Sleep(time.Second * 3)
val, err := randutil.GenerateCryptoRandomString(15, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
if err != nil {
panic(err)
}
if _, err = conn.Write([]byte(val)); err != nil {
panic(err)
}
fmt.Printf("Sent: '%s'\n", val)
}
}()
// Receive messages in a loop from the remote peer
buf := make([]byte, 1500)
for {
n, err := conn.Read(buf)
if err != nil {
panic(err)
}
fmt.Printf("Received: '%s'\n", string(buf[:n]))
}
}