Files
webrtc/examples/ice-proxy/answer.go
2025-08-17 19:19:00 +03:00

118 lines
3.3 KiB
Go

// SPDX-FileCopyrightText: 2025 The Pion community <https://pion.ly>
// SPDX-License-Identifier: MIT
//go:build !js
// +build !js
package main
import (
"encoding/json"
"log"
"net/http"
"github.com/pion/webrtc/v4"
)
// nolint:cyclop
func setupAnsweringAgent() {
// Create and start a simple HTTP proxy server.
proxyURL := newHTTPProxy()
// Create a proxy dialer that will use the created HTTP proxy.
proxyDialer := newProxyDialer(proxyURL)
var settingEngine webrtc.SettingEngine
// Set the ICEProxyDialer to use the proxy for TURN+TCP connections.
settingEngine.SetICEProxyDialer(proxyDialer)
api := webrtc.NewAPI(webrtc.WithSettingEngine(settingEngine))
peerConnection, err := api.NewPeerConnection(webrtc.Configuration{
ICEServers: []webrtc.ICEServer{
{
URLs: []string{turnServerURL},
Username: turnUsername,
Credential: turnPassword,
},
},
// ICETransportPolicyRelay forces the connection to go through a TURN server.
// This is required for the proxy to be used.
ICETransportPolicy: webrtc.ICETransportPolicyRelay,
})
if err != nil {
panic(err)
}
// Log peer connection and ICE connection state changes.
peerConnection.OnConnectionStateChange(func(pcs webrtc.PeerConnectionState) {
log.Printf("[Answerer] Peer Connection State has changed: %s", pcs.String())
})
peerConnection.OnICEConnectionStateChange(func(ics webrtc.ICEConnectionState) {
log.Printf("[Answerer] ICE Connection State has changed: %s", ics.String())
})
// Register a handler for when a data channel is created by the remote peer.
peerConnection.OnDataChannel(func(d *webrtc.DataChannel) {
icePair, err := d.Transport().Transport().ICETransport().GetSelectedCandidatePair()
if err != nil {
panic(err)
}
// Log the chosen ICE candidate pair.
log.Printf("[Answerer] New DataChannel %s, ICE pair: (%s)<->(%s)",
d.Label(), icePair.Local.String(), icePair.Remote.String())
// Register a handler to echo messages back to the sender.
d.OnMessage(func(msg webrtc.DataChannelMessage) {
if err := d.SendText(string(msg.Data)); err != nil {
panic(err)
}
})
})
// HTTP handler that accepts an offer, creates an answer,
// and sends it back to the offering agent.
http.HandleFunc("/sdp", func(rw http.ResponseWriter, r *http.Request) {
var sdp webrtc.SessionDescription
if err := json.NewDecoder(r.Body).Decode(&sdp); err != nil {
panic(err)
}
if err := peerConnection.SetRemoteDescription(sdp); err != nil {
panic(err)
}
gatherComplete := webrtc.GatheringCompletePromise(peerConnection)
answer, err := peerConnection.CreateAnswer(nil)
if err != nil {
panic(err)
}
if err = peerConnection.SetLocalDescription(answer); err != nil {
panic(err)
}
// Block until ICE Gathering is complete, disabling trickle ICE
// we do this because we only can exchange one signaling message
// in a production application you should exchange ICE Candidates via OnICECandidate
<-gatherComplete
resp, err := json.Marshal(*peerConnection.LocalDescription())
if err != nil {
panic(err)
}
if _, err := rw.Write(resp); err != nil {
panic(err)
}
})
// Start an HTTP server to handle the SDP exchange from the offering agent.
go func() {
// The HTTP server is not gracefully shutdown in this example.
// nolint:gosec
err := http.ListenAndServe("localhost:8080", nil)
if err != nil {
panic(err)
}
}()
}