main.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. // SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
  2. // SPDX-License-Identifier: MIT
  3. // trickle-ice demonstrates Pion WebRTC's Trickle ICE APIs. ICE is the subsystem WebRTC uses to establish connectivity.
  4. package main
  5. import (
  6. "encoding/json"
  7. "fmt"
  8. "net/http"
  9. "time"
  10. "github.com/pion/webrtc/v3"
  11. "golang.org/x/net/websocket"
  12. )
  13. // websocketServer is called for every new inbound WebSocket
  14. func websocketServer(ws *websocket.Conn) { // nolint:gocognit
  15. // Create a new RTCPeerConnection
  16. peerConnection, err := webrtc.NewPeerConnection(webrtc.Configuration{})
  17. if err != nil {
  18. panic(err)
  19. }
  20. // When Pion gathers a new ICE Candidate send it to the client. This is how
  21. // ice trickle is implemented. Everytime we have a new candidate available we send
  22. // it as soon as it is ready. We don't wait to emit a Offer/Answer until they are
  23. // all available
  24. peerConnection.OnICECandidate(func(c *webrtc.ICECandidate) {
  25. if c == nil {
  26. return
  27. }
  28. outbound, marshalErr := json.Marshal(c.ToJSON())
  29. if marshalErr != nil {
  30. panic(marshalErr)
  31. }
  32. if _, err = ws.Write(outbound); err != nil {
  33. panic(err)
  34. }
  35. })
  36. // Set the handler for ICE connection state
  37. // This will notify you when the peer has connected/disconnected
  38. peerConnection.OnICEConnectionStateChange(func(connectionState webrtc.ICEConnectionState) {
  39. fmt.Printf("ICE Connection State has changed: %s\n", connectionState.String())
  40. })
  41. // Send the current time via a DataChannel to the remote peer every 3 seconds
  42. peerConnection.OnDataChannel(func(d *webrtc.DataChannel) {
  43. d.OnOpen(func() {
  44. for range time.Tick(time.Second * 3) {
  45. if err = d.SendText(time.Now().String()); err != nil {
  46. panic(err)
  47. }
  48. }
  49. })
  50. })
  51. buf := make([]byte, 1500)
  52. for {
  53. // Read each inbound WebSocket Message
  54. n, err := ws.Read(buf)
  55. if err != nil {
  56. panic(err)
  57. }
  58. // Unmarshal each inbound WebSocket message
  59. var (
  60. candidate webrtc.ICECandidateInit
  61. offer webrtc.SessionDescription
  62. )
  63. switch {
  64. // Attempt to unmarshal as a SessionDescription. If the SDP field is empty
  65. // assume it is not one.
  66. case json.Unmarshal(buf[:n], &offer) == nil && offer.SDP != "":
  67. if err = peerConnection.SetRemoteDescription(offer); err != nil {
  68. panic(err)
  69. }
  70. answer, answerErr := peerConnection.CreateAnswer(nil)
  71. if answerErr != nil {
  72. panic(answerErr)
  73. }
  74. if err = peerConnection.SetLocalDescription(answer); err != nil {
  75. panic(err)
  76. }
  77. outbound, marshalErr := json.Marshal(answer)
  78. if marshalErr != nil {
  79. panic(marshalErr)
  80. }
  81. if _, err = ws.Write(outbound); err != nil {
  82. panic(err)
  83. }
  84. // Attempt to unmarshal as a ICECandidateInit. If the candidate field is empty
  85. // assume it is not one.
  86. case json.Unmarshal(buf[:n], &candidate) == nil && candidate.Candidate != "":
  87. if err = peerConnection.AddICECandidate(candidate); err != nil {
  88. panic(err)
  89. }
  90. default:
  91. panic("Unknown message")
  92. }
  93. }
  94. }
  95. func main() {
  96. http.Handle("/", http.FileServer(http.Dir(".")))
  97. http.Handle("/websocket", websocket.Handler(websocketServer))
  98. fmt.Println("Open http://localhost:8080 to access this demo")
  99. // nolint: gosec
  100. panic(http.ListenAndServe(":8080", nil))
  101. }