1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3  * You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 #ifndef _JSEPTRANSCEIVER_H_
6 #define _JSEPTRANSCEIVER_H_
7 
8 #include <string>
9 
10 #include "sdp/SdpAttribute.h"
11 #include "sdp/SdpMediaSection.h"
12 #include "sdp/Sdp.h"
13 #include "jsep/JsepTransport.h"
14 #include "jsep/JsepTrack.h"
15 
16 #include <mozilla/OwningNonNull.h>
17 #include "nsISupportsImpl.h"
18 #include "nsError.h"
19 
20 namespace mozilla {
21 
22 class JsepTransceiver {
23  private:
~JsepTransceiver()24   ~JsepTransceiver(){};
25 
26  public:
27   explicit JsepTransceiver(SdpMediaSection::MediaType type,
28                            SdpDirectionAttribute::Direction jsDirection =
29                                SdpDirectionAttribute::kSendrecv)
mJsDirection(jsDirection)30       : mJsDirection(jsDirection),
31         mSendTrack(type, sdp::kSend),
32         mRecvTrack(type, sdp::kRecv),
33         mLevel(SIZE_MAX),
34         mBundleLevel(SIZE_MAX),
35         mAddTrackMagic(false),
36         mWasCreatedBySetRemote(false),
37         mStopped(false),
38         mRemoved(false),
39         mNegotiated(false),
40         mCanRecycle(false) {}
41 
42   // Can't use default copy c'tor because of the refcount members. Ugh.
JsepTransceiver(const JsepTransceiver & orig)43   JsepTransceiver(const JsepTransceiver& orig)
44       : mJsDirection(orig.mJsDirection),
45         mSendTrack(orig.mSendTrack),
46         mRecvTrack(orig.mRecvTrack),
47         mTransport(orig.mTransport),
48         mMid(orig.mMid),
49         mLevel(orig.mLevel),
50         mBundleLevel(orig.mBundleLevel),
51         mAddTrackMagic(orig.mAddTrackMagic),
52         mWasCreatedBySetRemote(orig.mWasCreatedBySetRemote),
53         mStopped(orig.mStopped),
54         mRemoved(orig.mRemoved),
55         mNegotiated(orig.mNegotiated),
56         mCanRecycle(orig.mCanRecycle) {}
57 
58   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(JsepTransceiver);
59 
Rollback(JsepTransceiver & oldTransceiver,bool rollbackLevel)60   void Rollback(JsepTransceiver& oldTransceiver, bool rollbackLevel) {
61     MOZ_ASSERT(oldTransceiver.GetMediaType() == GetMediaType());
62     MOZ_ASSERT(!oldTransceiver.IsNegotiated() || !oldTransceiver.HasLevel() ||
63                !HasLevel() || oldTransceiver.GetLevel() == GetLevel());
64     mTransport = oldTransceiver.mTransport;
65     if (rollbackLevel) {
66       mLevel = oldTransceiver.mLevel;
67       mBundleLevel = oldTransceiver.mBundleLevel;
68     }
69     mRecvTrack = oldTransceiver.mRecvTrack;
70 
71     // Don't allow rollback to re-associate a transceiver.
72     if (!oldTransceiver.IsAssociated()) {
73       Disassociate();
74     }
75   }
76 
IsAssociated()77   bool IsAssociated() const { return !mMid.empty(); }
78 
GetMid()79   const std::string& GetMid() const {
80     MOZ_ASSERT(IsAssociated());
81     return mMid;
82   }
83 
Associate(const std::string & mid)84   void Associate(const std::string& mid) {
85     MOZ_ASSERT(HasLevel());
86     mMid = mid;
87   }
88 
Disassociate()89   void Disassociate() { mMid.clear(); }
90 
HasLevel()91   bool HasLevel() const { return mLevel != SIZE_MAX; }
92 
SetLevel(size_t level)93   void SetLevel(size_t level) {
94     MOZ_ASSERT(level != SIZE_MAX);
95     MOZ_ASSERT(!HasLevel());
96     MOZ_ASSERT(!IsStopped());
97 
98     mLevel = level;
99   }
100 
ClearLevel()101   void ClearLevel() {
102     MOZ_ASSERT(!IsAssociated());
103     mLevel = SIZE_MAX;
104     mBundleLevel = SIZE_MAX;
105   }
106 
GetLevel()107   size_t GetLevel() const {
108     MOZ_ASSERT(HasLevel());
109     return mLevel;
110   }
111 
Stop()112   void Stop() { mStopped = true; }
113 
IsStopped()114   bool IsStopped() const { return mStopped; }
115 
RestartDatachannelTransceiver()116   void RestartDatachannelTransceiver() {
117     MOZ_RELEASE_ASSERT(GetMediaType() == SdpMediaSection::kApplication);
118     mStopped = false;
119   }
120 
SetRemoved()121   void SetRemoved() { mRemoved = true; }
122 
IsRemoved()123   bool IsRemoved() const { return mRemoved; }
124 
HasBundleLevel()125   bool HasBundleLevel() const { return mBundleLevel != SIZE_MAX; }
126 
BundleLevel()127   size_t BundleLevel() const {
128     MOZ_ASSERT(HasBundleLevel());
129     return mBundleLevel;
130   }
131 
SetBundleLevel(size_t aBundleLevel)132   void SetBundleLevel(size_t aBundleLevel) {
133     MOZ_ASSERT(aBundleLevel != SIZE_MAX);
134     mBundleLevel = aBundleLevel;
135   }
136 
ClearBundleLevel()137   void ClearBundleLevel() { mBundleLevel = SIZE_MAX; }
138 
GetTransportLevel()139   size_t GetTransportLevel() const {
140     MOZ_ASSERT(HasLevel());
141     if (HasBundleLevel()) {
142       return BundleLevel();
143     }
144     return GetLevel();
145   }
146 
SetAddTrackMagic()147   void SetAddTrackMagic() { mAddTrackMagic = true; }
148 
HasAddTrackMagic()149   bool HasAddTrackMagic() const { return mAddTrackMagic; }
150 
SetCreatedBySetRemote()151   void SetCreatedBySetRemote() { mWasCreatedBySetRemote = true; }
152 
WasCreatedBySetRemote()153   bool WasCreatedBySetRemote() const { return mWasCreatedBySetRemote; }
154 
SetNegotiated()155   void SetNegotiated() {
156     MOZ_ASSERT(IsAssociated());
157     MOZ_ASSERT(HasLevel());
158     mNegotiated = true;
159   }
160 
IsNegotiated()161   bool IsNegotiated() const { return mNegotiated; }
162 
SetCanRecycle()163   void SetCanRecycle() { mCanRecycle = true; }
164 
CanRecycle()165   bool CanRecycle() const { return mCanRecycle; }
166 
167   // Convenience function
GetMediaType()168   SdpMediaSection::MediaType GetMediaType() const {
169     MOZ_ASSERT(mRecvTrack.GetMediaType() == mSendTrack.GetMediaType());
170     return mRecvTrack.GetMediaType();
171   }
172 
HasOwnTransport()173   bool HasOwnTransport() const {
174     if (mTransport.mComponents &&
175         (!HasBundleLevel() || (GetLevel() == BundleLevel()))) {
176       return true;
177     }
178     return false;
179   }
180 
181   // See Bug 1642419, this can be removed when all sites are working with RTX.
SetRtxIsAllowed(bool aRtxIsAllowed)182   void SetRtxIsAllowed(bool aRtxIsAllowed) {
183     mSendTrack.SetRtxIsAllowed(aRtxIsAllowed);
184     mRecvTrack.SetRtxIsAllowed(aRtxIsAllowed);
185   }
186 
187   // This is the direction JS wants. It might not actually happen.
188   SdpDirectionAttribute::Direction mJsDirection;
189 
190   JsepTrack mSendTrack;
191   JsepTrack mRecvTrack;
192   JsepTransport mTransport;
193 
194  private:
195   // Stuff that is not negotiated
196   std::string mMid;
197   size_t mLevel;  // SIZE_MAX if no level
198   // Is this track pair sharing a transport with another?
199   size_t mBundleLevel;  // SIZE_MAX if no bundle level
200   // The w3c and IETF specs have a lot of "magical" behavior that happens
201   // when addTrack is used. This was a deliberate design choice. Sadface.
202   bool mAddTrackMagic;
203   bool mWasCreatedBySetRemote;
204   bool mStopped;
205   bool mRemoved;
206   bool mNegotiated;
207   bool mCanRecycle;
208 };
209 
210 }  // namespace mozilla
211 
212 #endif  // _JSEPTRANSCEIVER_H_
213