jsep.go 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. package sdp
  2. import (
  3. "fmt"
  4. "net/url"
  5. "strconv"
  6. "time"
  7. )
  8. // Constants for SDP attributes used in JSEP
  9. const (
  10. AttrKeyCandidate = "candidate"
  11. AttrKeyEndOfCandidates = "end-of-candidates"
  12. AttrKeyIdentity = "identity"
  13. AttrKeyGroup = "group"
  14. AttrKeySSRC = "ssrc"
  15. AttrKeySSRCGroup = "ssrc-group"
  16. AttrKeyMsid = "msid"
  17. AttrKeyMsidSemantic = "msid-semantic"
  18. AttrKeyConnectionSetup = "setup"
  19. AttrKeyMID = "mid"
  20. AttrKeyICELite = "ice-lite"
  21. AttrKeyRTCPMux = "rtcp-mux"
  22. AttrKeyRTCPRsize = "rtcp-rsize"
  23. AttrKeyInactive = "inactive"
  24. AttrKeyRecvOnly = "recvonly"
  25. AttrKeySendOnly = "sendonly"
  26. AttrKeySendRecv = "sendrecv"
  27. AttrKeyExtMap = "extmap"
  28. AttrKeyExtMapAllowMixed = "extmap-allow-mixed"
  29. )
  30. // Constants for semantic tokens used in JSEP
  31. const (
  32. SemanticTokenLipSynchronization = "LS"
  33. SemanticTokenFlowIdentification = "FID"
  34. SemanticTokenForwardErrorCorrection = "FEC"
  35. SemanticTokenWebRTCMediaStreams = "WMS"
  36. )
  37. // Constants for extmap key
  38. const (
  39. ExtMapValueTransportCC = 3
  40. )
  41. func extMapURI() map[int]string {
  42. return map[int]string{
  43. ExtMapValueTransportCC: "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01",
  44. }
  45. }
  46. // API to match draft-ietf-rtcweb-jsep
  47. // Move to webrtc or its own package?
  48. // NewJSEPSessionDescription creates a new SessionDescription with
  49. // some settings that are required by the JSEP spec.
  50. //
  51. // Note: Since v2.4.0, session ID has been fixed to use crypto random according to
  52. // JSEP spec, so that NewJSEPSessionDescription now returns error as a second
  53. // return value.
  54. func NewJSEPSessionDescription(identity bool) (*SessionDescription, error) {
  55. sid, err := newSessionID()
  56. if err != nil {
  57. return nil, err
  58. }
  59. d := &SessionDescription{
  60. Version: 0,
  61. Origin: Origin{
  62. Username: "-",
  63. SessionID: sid,
  64. SessionVersion: uint64(time.Now().Unix()),
  65. NetworkType: "IN",
  66. AddressType: "IP4",
  67. UnicastAddress: "0.0.0.0",
  68. },
  69. SessionName: "-",
  70. TimeDescriptions: []TimeDescription{
  71. {
  72. Timing: Timing{
  73. StartTime: 0,
  74. StopTime: 0,
  75. },
  76. RepeatTimes: nil,
  77. },
  78. },
  79. Attributes: []Attribute{
  80. // "Attribute(ice-options:trickle)", // TODO: implement trickle ICE
  81. },
  82. }
  83. if identity {
  84. d.WithPropertyAttribute(AttrKeyIdentity)
  85. }
  86. return d, nil
  87. }
  88. // WithPropertyAttribute adds a property attribute 'a=key' to the session description
  89. func (s *SessionDescription) WithPropertyAttribute(key string) *SessionDescription {
  90. s.Attributes = append(s.Attributes, NewPropertyAttribute(key))
  91. return s
  92. }
  93. // WithValueAttribute adds a value attribute 'a=key:value' to the session description
  94. func (s *SessionDescription) WithValueAttribute(key, value string) *SessionDescription {
  95. s.Attributes = append(s.Attributes, NewAttribute(key, value))
  96. return s
  97. }
  98. // WithFingerprint adds a fingerprint to the session description
  99. func (s *SessionDescription) WithFingerprint(algorithm, value string) *SessionDescription {
  100. return s.WithValueAttribute("fingerprint", algorithm+" "+value)
  101. }
  102. // WithMedia adds a media description to the session description
  103. func (s *SessionDescription) WithMedia(md *MediaDescription) *SessionDescription {
  104. s.MediaDescriptions = append(s.MediaDescriptions, md)
  105. return s
  106. }
  107. // NewJSEPMediaDescription creates a new MediaName with
  108. // some settings that are required by the JSEP spec.
  109. func NewJSEPMediaDescription(codecType string, codecPrefs []string) *MediaDescription {
  110. return &MediaDescription{
  111. MediaName: MediaName{
  112. Media: codecType,
  113. Port: RangedPort{Value: 9},
  114. Protos: []string{"UDP", "TLS", "RTP", "SAVPF"},
  115. },
  116. ConnectionInformation: &ConnectionInformation{
  117. NetworkType: "IN",
  118. AddressType: "IP4",
  119. Address: &Address{
  120. Address: "0.0.0.0",
  121. },
  122. },
  123. }
  124. }
  125. // WithPropertyAttribute adds a property attribute 'a=key' to the media description
  126. func (d *MediaDescription) WithPropertyAttribute(key string) *MediaDescription {
  127. d.Attributes = append(d.Attributes, NewPropertyAttribute(key))
  128. return d
  129. }
  130. // WithValueAttribute adds a value attribute 'a=key:value' to the media description
  131. func (d *MediaDescription) WithValueAttribute(key, value string) *MediaDescription {
  132. d.Attributes = append(d.Attributes, NewAttribute(key, value))
  133. return d
  134. }
  135. // WithFingerprint adds a fingerprint to the media description
  136. func (d *MediaDescription) WithFingerprint(algorithm, value string) *MediaDescription {
  137. return d.WithValueAttribute("fingerprint", algorithm+" "+value)
  138. }
  139. // WithICECredentials adds ICE credentials to the media description
  140. func (d *MediaDescription) WithICECredentials(username, password string) *MediaDescription {
  141. return d.
  142. WithValueAttribute("ice-ufrag", username).
  143. WithValueAttribute("ice-pwd", password)
  144. }
  145. // WithCodec adds codec information to the media description
  146. func (d *MediaDescription) WithCodec(payloadType uint8, name string, clockrate uint32, channels uint16, fmtp string) *MediaDescription {
  147. d.MediaName.Formats = append(d.MediaName.Formats, strconv.Itoa(int(payloadType)))
  148. rtpmap := fmt.Sprintf("%d %s/%d", payloadType, name, clockrate)
  149. if channels > 0 {
  150. rtpmap += fmt.Sprintf("/%d", channels)
  151. }
  152. d.WithValueAttribute("rtpmap", rtpmap)
  153. if fmtp != "" {
  154. d.WithValueAttribute("fmtp", fmt.Sprintf("%d %s", payloadType, fmtp))
  155. }
  156. return d
  157. }
  158. // WithMediaSource adds media source information to the media description
  159. func (d *MediaDescription) WithMediaSource(ssrc uint32, cname, streamLabel, label string) *MediaDescription {
  160. return d.
  161. WithValueAttribute("ssrc", fmt.Sprintf("%d cname:%s", ssrc, cname)). // Deprecated but not phased out?
  162. WithValueAttribute("ssrc", fmt.Sprintf("%d msid:%s %s", ssrc, streamLabel, label)).
  163. WithValueAttribute("ssrc", fmt.Sprintf("%d mslabel:%s", ssrc, streamLabel)). // Deprecated but not phased out?
  164. WithValueAttribute("ssrc", fmt.Sprintf("%d label:%s", ssrc, label)) // Deprecated but not phased out?
  165. }
  166. // WithCandidate adds an ICE candidate to the media description
  167. // Deprecated: use WithICECandidate instead
  168. func (d *MediaDescription) WithCandidate(value string) *MediaDescription {
  169. return d.WithValueAttribute("candidate", value)
  170. }
  171. // WithExtMap adds an extmap to the media description
  172. func (d *MediaDescription) WithExtMap(e ExtMap) *MediaDescription {
  173. return d.WithPropertyAttribute(e.Marshal())
  174. }
  175. // WithTransportCCExtMap adds an extmap to the media description
  176. func (d *MediaDescription) WithTransportCCExtMap() *MediaDescription {
  177. uri, _ := url.Parse(extMapURI()[ExtMapValueTransportCC])
  178. e := ExtMap{
  179. Value: ExtMapValueTransportCC,
  180. URI: uri,
  181. }
  182. return d.WithExtMap(e)
  183. }