server.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. package webrtc
  2. import (
  3. "github.com/AlexxIT/go2rtc/pkg/core"
  4. "github.com/pion/sdp/v3"
  5. "github.com/pion/webrtc/v3"
  6. )
  7. func (c *Conn) SetOffer(offer string) (err error) {
  8. c.offer = offer
  9. sd := &sdp.SessionDescription{}
  10. if err = sd.Unmarshal([]byte(offer)); err != nil {
  11. return
  12. }
  13. // create transceivers with opposite direction
  14. for _, md := range sd.MediaDescriptions {
  15. var mid string
  16. var tr *webrtc.RTPTransceiver
  17. for _, attr := range md.Attributes {
  18. switch attr.Key {
  19. case core.DirectionSendRecv:
  20. tr, _ = c.pc.AddTransceiverFromTrack(NewTrack(md.MediaName.Media))
  21. case core.DirectionSendonly:
  22. tr, _ = c.pc.AddTransceiverFromKind(
  23. webrtc.NewRTPCodecType(md.MediaName.Media),
  24. webrtc.RTPTransceiverInit{Direction: webrtc.RTPTransceiverDirectionRecvonly},
  25. )
  26. case core.DirectionRecvonly:
  27. tr, _ = c.pc.AddTransceiverFromTrack(
  28. NewTrack(md.MediaName.Media),
  29. webrtc.RTPTransceiverInit{Direction: webrtc.RTPTransceiverDirectionSendonly},
  30. )
  31. case "mid":
  32. mid = attr.Value
  33. }
  34. }
  35. if mid != "" && tr != nil {
  36. _ = tr.SetMid(mid)
  37. }
  38. }
  39. c.Medias = UnmarshalMedias(sd.MediaDescriptions)
  40. return
  41. }
  42. func (c *Conn) GetAnswer() (answer string, err error) {
  43. // we need to process remote offer after we create transeivers
  44. desc := webrtc.SessionDescription{Type: webrtc.SDPTypeOffer, SDP: c.offer}
  45. if err = c.pc.SetRemoteDescription(desc); err != nil {
  46. return "", err
  47. }
  48. // disable transceivers if we don't have track, make direction=inactive
  49. transeivers:
  50. for _, tr := range c.pc.GetTransceivers() {
  51. for _, sender := range c.Senders {
  52. if sender.Media.ID == tr.Mid() {
  53. continue transeivers
  54. }
  55. }
  56. switch tr.Direction() {
  57. case webrtc.RTPTransceiverDirectionSendrecv:
  58. _ = tr.Sender().Stop()
  59. case webrtc.RTPTransceiverDirectionSendonly:
  60. _ = tr.Stop()
  61. }
  62. }
  63. if desc, err = c.pc.CreateAnswer(nil); err != nil {
  64. return
  65. }
  66. if err = c.pc.SetLocalDescription(desc); err != nil {
  67. return
  68. }
  69. return c.pc.LocalDescription().SDP, nil
  70. }
  71. // GetCompleteAnswer - get SDP answer with candidates inside
  72. func (c *Conn) GetCompleteAnswer(candidates []string, filter func(*webrtc.ICECandidate) bool) (string, error) {
  73. var done = make(chan struct{})
  74. c.pc.OnICECandidate(func(candidate *webrtc.ICECandidate) {
  75. if candidate != nil {
  76. if filter == nil || filter(candidate) {
  77. candidates = append(candidates, candidate.ToJSON().Candidate)
  78. }
  79. } else {
  80. done <- struct{}{}
  81. }
  82. })
  83. answer, err := c.GetAnswer()
  84. if err != nil {
  85. return "", err
  86. }
  87. <-done
  88. sd := &sdp.SessionDescription{}
  89. if err = sd.Unmarshal([]byte(answer)); err != nil {
  90. return "", err
  91. }
  92. md := sd.MediaDescriptions[0]
  93. for _, candidate := range candidates {
  94. md.WithPropertyAttribute(candidate)
  95. }
  96. b, err := sd.Marshal()
  97. if err != nil {
  98. return "", err
  99. }
  100. return string(b), nil
  101. }