signalingstate.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. package webrtc
  2. import (
  3. "fmt"
  4. "sync/atomic"
  5. "github.com/pion/webrtc/v3/pkg/rtcerr"
  6. )
  7. type stateChangeOp int
  8. const (
  9. stateChangeOpSetLocal stateChangeOp = iota + 1
  10. stateChangeOpSetRemote
  11. )
  12. func (op stateChangeOp) String() string {
  13. switch op {
  14. case stateChangeOpSetLocal:
  15. return "SetLocal"
  16. case stateChangeOpSetRemote:
  17. return "SetRemote"
  18. default:
  19. return "Unknown State Change Operation"
  20. }
  21. }
  22. // SignalingState indicates the signaling state of the offer/answer process.
  23. type SignalingState int32
  24. const (
  25. // SignalingStateStable indicates there is no offer/answer exchange in
  26. // progress. This is also the initial state, in which case the local and
  27. // remote descriptions are nil.
  28. SignalingStateStable SignalingState = iota + 1
  29. // SignalingStateHaveLocalOffer indicates that a local description, of
  30. // type "offer", has been successfully applied.
  31. SignalingStateHaveLocalOffer
  32. // SignalingStateHaveRemoteOffer indicates that a remote description, of
  33. // type "offer", has been successfully applied.
  34. SignalingStateHaveRemoteOffer
  35. // SignalingStateHaveLocalPranswer indicates that a remote description
  36. // of type "offer" has been successfully applied and a local description
  37. // of type "pranswer" has been successfully applied.
  38. SignalingStateHaveLocalPranswer
  39. // SignalingStateHaveRemotePranswer indicates that a local description
  40. // of type "offer" has been successfully applied and a remote description
  41. // of type "pranswer" has been successfully applied.
  42. SignalingStateHaveRemotePranswer
  43. // SignalingStateClosed indicates The PeerConnection has been closed.
  44. SignalingStateClosed
  45. )
  46. // This is done this way because of a linter.
  47. const (
  48. signalingStateStableStr = "stable"
  49. signalingStateHaveLocalOfferStr = "have-local-offer"
  50. signalingStateHaveRemoteOfferStr = "have-remote-offer"
  51. signalingStateHaveLocalPranswerStr = "have-local-pranswer"
  52. signalingStateHaveRemotePranswerStr = "have-remote-pranswer"
  53. signalingStateClosedStr = "closed"
  54. )
  55. func newSignalingState(raw string) SignalingState {
  56. switch raw {
  57. case signalingStateStableStr:
  58. return SignalingStateStable
  59. case signalingStateHaveLocalOfferStr:
  60. return SignalingStateHaveLocalOffer
  61. case signalingStateHaveRemoteOfferStr:
  62. return SignalingStateHaveRemoteOffer
  63. case signalingStateHaveLocalPranswerStr:
  64. return SignalingStateHaveLocalPranswer
  65. case signalingStateHaveRemotePranswerStr:
  66. return SignalingStateHaveRemotePranswer
  67. case signalingStateClosedStr:
  68. return SignalingStateClosed
  69. default:
  70. return SignalingState(Unknown)
  71. }
  72. }
  73. func (t SignalingState) String() string {
  74. switch t {
  75. case SignalingStateStable:
  76. return signalingStateStableStr
  77. case SignalingStateHaveLocalOffer:
  78. return signalingStateHaveLocalOfferStr
  79. case SignalingStateHaveRemoteOffer:
  80. return signalingStateHaveRemoteOfferStr
  81. case SignalingStateHaveLocalPranswer:
  82. return signalingStateHaveLocalPranswerStr
  83. case SignalingStateHaveRemotePranswer:
  84. return signalingStateHaveRemotePranswerStr
  85. case SignalingStateClosed:
  86. return signalingStateClosedStr
  87. default:
  88. return ErrUnknownType.Error()
  89. }
  90. }
  91. // Get thread safe read value
  92. func (t *SignalingState) Get() SignalingState {
  93. return SignalingState(atomic.LoadInt32((*int32)(t)))
  94. }
  95. // Set thread safe write value
  96. func (t *SignalingState) Set(state SignalingState) {
  97. atomic.StoreInt32((*int32)(t), int32(state))
  98. }
  99. func checkNextSignalingState(cur, next SignalingState, op stateChangeOp, sdpType SDPType) (SignalingState, error) { // nolint:gocognit
  100. // Special case for rollbacks
  101. if sdpType == SDPTypeRollback && cur == SignalingStateStable {
  102. return cur, &rtcerr.InvalidModificationError{
  103. Err: errSignalingStateCannotRollback,
  104. }
  105. }
  106. // 4.3.1 valid state transitions
  107. switch cur { // nolint:exhaustive
  108. case SignalingStateStable:
  109. switch op {
  110. case stateChangeOpSetLocal:
  111. // stable->SetLocal(offer)->have-local-offer
  112. if sdpType == SDPTypeOffer && next == SignalingStateHaveLocalOffer {
  113. return next, nil
  114. }
  115. case stateChangeOpSetRemote:
  116. // stable->SetRemote(offer)->have-remote-offer
  117. if sdpType == SDPTypeOffer && next == SignalingStateHaveRemoteOffer {
  118. return next, nil
  119. }
  120. }
  121. case SignalingStateHaveLocalOffer:
  122. if op == stateChangeOpSetRemote {
  123. switch sdpType { // nolint:exhaustive
  124. // have-local-offer->SetRemote(answer)->stable
  125. case SDPTypeAnswer:
  126. if next == SignalingStateStable {
  127. return next, nil
  128. }
  129. // have-local-offer->SetRemote(pranswer)->have-remote-pranswer
  130. case SDPTypePranswer:
  131. if next == SignalingStateHaveRemotePranswer {
  132. return next, nil
  133. }
  134. }
  135. }
  136. case SignalingStateHaveRemotePranswer:
  137. if op == stateChangeOpSetRemote && sdpType == SDPTypeAnswer {
  138. // have-remote-pranswer->SetRemote(answer)->stable
  139. if next == SignalingStateStable {
  140. return next, nil
  141. }
  142. }
  143. case SignalingStateHaveRemoteOffer:
  144. if op == stateChangeOpSetLocal {
  145. switch sdpType { // nolint:exhaustive
  146. // have-remote-offer->SetLocal(answer)->stable
  147. case SDPTypeAnswer:
  148. if next == SignalingStateStable {
  149. return next, nil
  150. }
  151. // have-remote-offer->SetLocal(pranswer)->have-local-pranswer
  152. case SDPTypePranswer:
  153. if next == SignalingStateHaveLocalPranswer {
  154. return next, nil
  155. }
  156. }
  157. }
  158. case SignalingStateHaveLocalPranswer:
  159. if op == stateChangeOpSetLocal && sdpType == SDPTypeAnswer {
  160. // have-local-pranswer->SetLocal(answer)->stable
  161. if next == SignalingStateStable {
  162. return next, nil
  163. }
  164. }
  165. }
  166. return cur, &rtcerr.InvalidModificationError{
  167. Err: fmt.Errorf("%w: %s->%s(%s)->%s", errSignalingStateProposedTransitionInvalid, cur, op, sdpType, next),
  168. }
  169. }