icecandidate.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. package webrtc
  2. import (
  3. "fmt"
  4. "github.com/pion/ice/v2"
  5. )
  6. // ICECandidate represents a ice candidate
  7. type ICECandidate struct {
  8. statsID string
  9. Foundation string `json:"foundation"`
  10. Priority uint32 `json:"priority"`
  11. Address string `json:"address"`
  12. Protocol ICEProtocol `json:"protocol"`
  13. Port uint16 `json:"port"`
  14. Typ ICECandidateType `json:"type"`
  15. Component uint16 `json:"component"`
  16. RelatedAddress string `json:"relatedAddress"`
  17. RelatedPort uint16 `json:"relatedPort"`
  18. TCPType string `json:"tcpType"`
  19. }
  20. // Conversion for package ice
  21. func newICECandidatesFromICE(iceCandidates []ice.Candidate) ([]ICECandidate, error) {
  22. candidates := []ICECandidate{}
  23. for _, i := range iceCandidates {
  24. c, err := newICECandidateFromICE(i)
  25. if err != nil {
  26. return nil, err
  27. }
  28. candidates = append(candidates, c)
  29. }
  30. return candidates, nil
  31. }
  32. func newICECandidateFromICE(i ice.Candidate) (ICECandidate, error) {
  33. typ, err := convertTypeFromICE(i.Type())
  34. if err != nil {
  35. return ICECandidate{}, err
  36. }
  37. protocol, err := NewICEProtocol(i.NetworkType().NetworkShort())
  38. if err != nil {
  39. return ICECandidate{}, err
  40. }
  41. c := ICECandidate{
  42. statsID: i.ID(),
  43. Foundation: i.Foundation(),
  44. Priority: i.Priority(),
  45. Address: i.Address(),
  46. Protocol: protocol,
  47. Port: uint16(i.Port()),
  48. Component: i.Component(),
  49. Typ: typ,
  50. TCPType: i.TCPType().String(),
  51. }
  52. if i.RelatedAddress() != nil {
  53. c.RelatedAddress = i.RelatedAddress().Address
  54. c.RelatedPort = uint16(i.RelatedAddress().Port)
  55. }
  56. return c, nil
  57. }
  58. func (c ICECandidate) toICE() (ice.Candidate, error) {
  59. candidateID := c.statsID
  60. switch c.Typ {
  61. case ICECandidateTypeHost:
  62. config := ice.CandidateHostConfig{
  63. CandidateID: candidateID,
  64. Network: c.Protocol.String(),
  65. Address: c.Address,
  66. Port: int(c.Port),
  67. Component: c.Component,
  68. TCPType: ice.NewTCPType(c.TCPType),
  69. Foundation: c.Foundation,
  70. Priority: c.Priority,
  71. }
  72. return ice.NewCandidateHost(&config)
  73. case ICECandidateTypeSrflx:
  74. config := ice.CandidateServerReflexiveConfig{
  75. CandidateID: candidateID,
  76. Network: c.Protocol.String(),
  77. Address: c.Address,
  78. Port: int(c.Port),
  79. Component: c.Component,
  80. Foundation: c.Foundation,
  81. Priority: c.Priority,
  82. RelAddr: c.RelatedAddress,
  83. RelPort: int(c.RelatedPort),
  84. }
  85. return ice.NewCandidateServerReflexive(&config)
  86. case ICECandidateTypePrflx:
  87. config := ice.CandidatePeerReflexiveConfig{
  88. CandidateID: candidateID,
  89. Network: c.Protocol.String(),
  90. Address: c.Address,
  91. Port: int(c.Port),
  92. Component: c.Component,
  93. Foundation: c.Foundation,
  94. Priority: c.Priority,
  95. RelAddr: c.RelatedAddress,
  96. RelPort: int(c.RelatedPort),
  97. }
  98. return ice.NewCandidatePeerReflexive(&config)
  99. case ICECandidateTypeRelay:
  100. config := ice.CandidateRelayConfig{
  101. CandidateID: candidateID,
  102. Network: c.Protocol.String(),
  103. Address: c.Address,
  104. Port: int(c.Port),
  105. Component: c.Component,
  106. Foundation: c.Foundation,
  107. Priority: c.Priority,
  108. RelAddr: c.RelatedAddress,
  109. RelPort: int(c.RelatedPort),
  110. }
  111. return ice.NewCandidateRelay(&config)
  112. default:
  113. return nil, fmt.Errorf("%w: %s", errICECandidateTypeUnknown, c.Typ)
  114. }
  115. }
  116. func convertTypeFromICE(t ice.CandidateType) (ICECandidateType, error) {
  117. switch t {
  118. case ice.CandidateTypeHost:
  119. return ICECandidateTypeHost, nil
  120. case ice.CandidateTypeServerReflexive:
  121. return ICECandidateTypeSrflx, nil
  122. case ice.CandidateTypePeerReflexive:
  123. return ICECandidateTypePrflx, nil
  124. case ice.CandidateTypeRelay:
  125. return ICECandidateTypeRelay, nil
  126. default:
  127. return ICECandidateType(t), fmt.Errorf("%w: %s", errICECandidateTypeUnknown, t)
  128. }
  129. }
  130. func (c ICECandidate) String() string {
  131. ic, err := c.toICE()
  132. if err != nil {
  133. return fmt.Sprintf("%#v failed to convert to ICE: %s", c, err)
  134. }
  135. return ic.String()
  136. }
  137. // ToJSON returns an ICECandidateInit
  138. // as indicated by the spec https://w3c.github.io/webrtc-pc/#dom-rtcicecandidate-tojson
  139. func (c ICECandidate) ToJSON() ICECandidateInit {
  140. zeroVal := uint16(0)
  141. emptyStr := ""
  142. candidateStr := ""
  143. candidate, err := c.toICE()
  144. if err == nil {
  145. candidateStr = candidate.Marshal()
  146. }
  147. return ICECandidateInit{
  148. Candidate: fmt.Sprintf("candidate:%s", candidateStr),
  149. SDPMid: &emptyStr,
  150. SDPMLineIndex: &zeroVal,
  151. }
  152. }