/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef _JSEPTRANSCEIVER_H_ #define _JSEPTRANSCEIVER_H_ #include #include "sdp/SdpAttribute.h" #include "sdp/SdpMediaSection.h" #include "sdp/Sdp.h" #include "jsep/JsepTransport.h" #include "jsep/JsepTrack.h" #include "nsError.h" namespace mozilla { class JsepUuidGenerator { public: virtual ~JsepUuidGenerator() = default; virtual bool Generate(std::string* id) = 0; virtual JsepUuidGenerator* Clone() const = 0; }; class JsepTransceiver { public: explicit JsepTransceiver(SdpMediaSection::MediaType type, JsepUuidGenerator& aUuidGen, SdpDirectionAttribute::Direction jsDirection = SdpDirectionAttribute::kSendrecv) : mJsDirection(jsDirection), mSendTrack(type, sdp::kSend), mRecvTrack(type, sdp::kRecv), mLevel(SIZE_MAX), mBundleLevel(SIZE_MAX), mAddTrackMagic(false), mOnlyExistsBecauseOfSetRemote(false), mStopped(false), mRemoved(false), mNegotiated(false), mCanRecycle(false) { if (!aUuidGen.Generate(&mUuid)) { MOZ_CRASH(); } } JsepTransceiver(const JsepTransceiver& orig) = default; JsepTransceiver(JsepTransceiver&& orig) = default; JsepTransceiver& operator=(const JsepTransceiver& aRhs) = default; JsepTransceiver& operator=(JsepTransceiver&& aRhs) = default; ~JsepTransceiver() = default; void Rollback(JsepTransceiver& oldTransceiver, bool aRemote) { MOZ_ASSERT(oldTransceiver.GetMediaType() == GetMediaType()); MOZ_ASSERT(!oldTransceiver.IsNegotiated() || !oldTransceiver.HasLevel() || !HasLevel() || oldTransceiver.GetLevel() == GetLevel()); mTransport = oldTransceiver.mTransport; if (aRemote) { mLevel = oldTransceiver.mLevel; mBundleLevel = oldTransceiver.mBundleLevel; mSendTrack = oldTransceiver.mSendTrack; } mRecvTrack = oldTransceiver.mRecvTrack; // Don't allow rollback to re-associate a transceiver. if (!oldTransceiver.IsAssociated()) { Disassociate(); } } bool IsAssociated() const { return !mMid.empty(); } const std::string& GetMid() const { MOZ_ASSERT(IsAssociated()); return mMid; } void Associate(const std::string& mid) { MOZ_ASSERT(HasLevel()); mMid = mid; } void Disassociate() { mMid.clear(); } bool HasLevel() const { return mLevel != SIZE_MAX; } void SetLevel(size_t level) { MOZ_ASSERT(level != SIZE_MAX); MOZ_ASSERT(!HasLevel()); MOZ_ASSERT(!IsStopped()); mLevel = level; } void ClearLevel() { MOZ_ASSERT(!IsAssociated()); mLevel = SIZE_MAX; mBundleLevel = SIZE_MAX; } size_t GetLevel() const { MOZ_ASSERT(HasLevel()); return mLevel; } void Stop() { mStopped = true; } bool IsStopped() const { return mStopped; } void RestartDatachannelTransceiver() { MOZ_RELEASE_ASSERT(GetMediaType() == SdpMediaSection::kApplication); mStopped = false; mCanRecycle = false; } void SetRemoved() { mRemoved = true; } bool IsRemoved() const { return mRemoved; } bool HasBundleLevel() const { return mBundleLevel != SIZE_MAX; } size_t BundleLevel() const { MOZ_ASSERT(HasBundleLevel()); return mBundleLevel; } void SetBundleLevel(size_t aBundleLevel) { MOZ_ASSERT(aBundleLevel != SIZE_MAX); mBundleLevel = aBundleLevel; } void ClearBundleLevel() { mBundleLevel = SIZE_MAX; } size_t GetTransportLevel() const { MOZ_ASSERT(HasLevel()); if (HasBundleLevel()) { return BundleLevel(); } return GetLevel(); } void SetAddTrackMagic() { mAddTrackMagic = true; } bool HasAddTrackMagic() const { return mAddTrackMagic; } void SetOnlyExistsBecauseOfSetRemote(bool aValue) { mOnlyExistsBecauseOfSetRemote = aValue; } bool OnlyExistsBecauseOfSetRemote() const { return mOnlyExistsBecauseOfSetRemote; } void SetNegotiated() { MOZ_ASSERT(IsAssociated()); MOZ_ASSERT(HasLevel()); mNegotiated = true; } bool IsNegotiated() const { return mNegotiated; } void SetCanRecycle() { mCanRecycle = true; } bool CanRecycle() const { return mCanRecycle; } const std::string& GetUuid() const { return mUuid; } // Convenience function SdpMediaSection::MediaType GetMediaType() const { MOZ_ASSERT(mRecvTrack.GetMediaType() == mSendTrack.GetMediaType()); return mRecvTrack.GetMediaType(); } bool HasTransport() const { return mTransport.mComponents != 0; } bool HasOwnTransport() const { if (HasTransport() && (!HasBundleLevel() || (GetLevel() == BundleLevel()))) { return true; } return false; } // See Bug 1642419, this can be removed when all sites are working with RTX. void SetRtxIsAllowed(bool aRtxIsAllowed) { mSendTrack.SetRtxIsAllowed(aRtxIsAllowed); mRecvTrack.SetRtxIsAllowed(aRtxIsAllowed); } // This is the direction JS wants. It might not actually happen. SdpDirectionAttribute::Direction mJsDirection; JsepTrack mSendTrack; JsepTrack mRecvTrack; JsepTransport mTransport; private: std::string mUuid; // Stuff that is not negotiated std::string mMid; size_t mLevel; // SIZE_MAX if no level // Is this track pair sharing a transport with another? size_t mBundleLevel; // SIZE_MAX if no bundle level // The w3c and IETF specs have a lot of "magical" behavior that happens // when addTrack is used to create a transceiver. This was a deliberate // design choice. Sadface. bool mAddTrackMagic; bool mOnlyExistsBecauseOfSetRemote; bool mStopped; bool mRemoved; bool mNegotiated; bool mCanRecycle; }; } // namespace mozilla #endif // _JSEPTRANSCEIVER_H_