main.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. // SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
  2. // SPDX-License-Identifier: MIT
  3. //go:build !js
  4. // +build !js
  5. // ortc demonstrates Pion WebRTC's ORTC capabilities.
  6. package main
  7. import (
  8. "flag"
  9. "fmt"
  10. "time"
  11. "github.com/pion/webrtc/v3"
  12. "github.com/pion/webrtc/v3/examples/internal/signal"
  13. )
  14. func main() {
  15. isOffer := flag.Bool("offer", false, "Act as the offerer if set")
  16. flag.Parse()
  17. // Everything below is the Pion WebRTC (ORTC) API! Thanks for using it ❤️.
  18. // Prepare ICE gathering options
  19. iceOptions := webrtc.ICEGatherOptions{
  20. ICEServers: []webrtc.ICEServer{
  21. {URLs: []string{"stun:stun.l.google.com:19302"}},
  22. },
  23. }
  24. // Create an API object
  25. api := webrtc.NewAPI()
  26. // Create the ICE gatherer
  27. gatherer, err := api.NewICEGatherer(iceOptions)
  28. if err != nil {
  29. panic(err)
  30. }
  31. // Construct the ICE transport
  32. ice := api.NewICETransport(gatherer)
  33. // Construct the DTLS transport
  34. dtls, err := api.NewDTLSTransport(ice, nil)
  35. if err != nil {
  36. panic(err)
  37. }
  38. // Construct the SCTP transport
  39. sctp := api.NewSCTPTransport(dtls)
  40. // Handle incoming data channels
  41. sctp.OnDataChannel(func(channel *webrtc.DataChannel) {
  42. fmt.Printf("New DataChannel %s %d\n", channel.Label(), channel.ID())
  43. // Register the handlers
  44. channel.OnOpen(handleOnOpen(channel))
  45. channel.OnMessage(func(msg webrtc.DataChannelMessage) {
  46. fmt.Printf("Message from DataChannel '%s': '%s'\n", channel.Label(), string(msg.Data))
  47. })
  48. })
  49. gatherFinished := make(chan struct{})
  50. gatherer.OnLocalCandidate(func(i *webrtc.ICECandidate) {
  51. if i == nil {
  52. close(gatherFinished)
  53. }
  54. })
  55. // Gather candidates
  56. err = gatherer.Gather()
  57. if err != nil {
  58. panic(err)
  59. }
  60. <-gatherFinished
  61. iceCandidates, err := gatherer.GetLocalCandidates()
  62. if err != nil {
  63. panic(err)
  64. }
  65. iceParams, err := gatherer.GetLocalParameters()
  66. if err != nil {
  67. panic(err)
  68. }
  69. dtlsParams, err := dtls.GetLocalParameters()
  70. if err != nil {
  71. panic(err)
  72. }
  73. sctpCapabilities := sctp.GetCapabilities()
  74. s := Signal{
  75. ICECandidates: iceCandidates,
  76. ICEParameters: iceParams,
  77. DTLSParameters: dtlsParams,
  78. SCTPCapabilities: sctpCapabilities,
  79. }
  80. // Exchange the information
  81. fmt.Println(signal.Encode(s))
  82. remoteSignal := Signal{}
  83. signal.Decode(signal.MustReadStdin(), &remoteSignal)
  84. iceRole := webrtc.ICERoleControlled
  85. if *isOffer {
  86. iceRole = webrtc.ICERoleControlling
  87. }
  88. err = ice.SetRemoteCandidates(remoteSignal.ICECandidates)
  89. if err != nil {
  90. panic(err)
  91. }
  92. // Start the ICE transport
  93. err = ice.Start(nil, remoteSignal.ICEParameters, &iceRole)
  94. if err != nil {
  95. panic(err)
  96. }
  97. // Start the DTLS transport
  98. err = dtls.Start(remoteSignal.DTLSParameters)
  99. if err != nil {
  100. panic(err)
  101. }
  102. // Start the SCTP transport
  103. err = sctp.Start(remoteSignal.SCTPCapabilities)
  104. if err != nil {
  105. panic(err)
  106. }
  107. // Construct the data channel as the offerer
  108. if *isOffer {
  109. var id uint16 = 1
  110. dcParams := &webrtc.DataChannelParameters{
  111. Label: "Foo",
  112. ID: &id,
  113. }
  114. var channel *webrtc.DataChannel
  115. channel, err = api.NewDataChannel(sctp, dcParams)
  116. if err != nil {
  117. panic(err)
  118. }
  119. // Register the handlers
  120. // channel.OnOpen(handleOnOpen(channel)) // TODO: OnOpen on handle ChannelAck
  121. go handleOnOpen(channel)() // Temporary alternative
  122. channel.OnMessage(func(msg webrtc.DataChannelMessage) {
  123. fmt.Printf("Message from DataChannel '%s': '%s'\n", channel.Label(), string(msg.Data))
  124. })
  125. }
  126. select {}
  127. }
  128. // Signal is used to exchange signaling info.
  129. // This is not part of the ORTC spec. You are free
  130. // to exchange this information any way you want.
  131. type Signal struct {
  132. ICECandidates []webrtc.ICECandidate `json:"iceCandidates"`
  133. ICEParameters webrtc.ICEParameters `json:"iceParameters"`
  134. DTLSParameters webrtc.DTLSParameters `json:"dtlsParameters"`
  135. SCTPCapabilities webrtc.SCTPCapabilities `json:"sctpCapabilities"`
  136. }
  137. func handleOnOpen(channel *webrtc.DataChannel) func() {
  138. return func() {
  139. fmt.Printf("Data channel '%s'-'%d' open. Random messages will now be sent to any connected DataChannels every 5 seconds\n", channel.Label(), channel.ID())
  140. for range time.NewTicker(5 * time.Second).C {
  141. message := signal.RandSeq(15)
  142. fmt.Printf("Sending '%s' \n", message)
  143. err := channel.SendText(message)
  144. if err != nil {
  145. panic(err)
  146. }
  147. }
  148. }
  149. }