/* 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 _JSEPSESSION_H_ #define _JSEPSESSION_H_ #include #include #include #include "mozilla/Attributes.h" #include "mozilla/Maybe.h" #include "mozilla/RefPtr.h" #include "mozilla/UniquePtr.h" #include "nsError.h" #include "jsep/JsepTransport.h" #include "sdp/Sdp.h" #include "jsep/JsepTransceiver.h" #include "mozilla/dom/PeerConnectionObserverEnumsBinding.h" namespace mozilla { // Forward declarations class JsepCodecDescription; enum JsepSignalingState { kJsepStateStable, kJsepStateHaveLocalOffer, kJsepStateHaveRemoteOffer, kJsepStateHaveLocalPranswer, kJsepStateHaveRemotePranswer, kJsepStateClosed }; enum JsepSdpType { kJsepSdpOffer, kJsepSdpAnswer, kJsepSdpPranswer, kJsepSdpRollback }; enum JsepDescriptionPendingOrCurrent { kJsepDescriptionCurrent, kJsepDescriptionPending, kJsepDescriptionPendingOrCurrent }; struct JsepOAOptions {}; struct JsepOfferOptions : public JsepOAOptions { Maybe mOfferToReceiveAudio; Maybe mOfferToReceiveVideo; Maybe mIceRestart; // currently ignored by JsepSession }; struct JsepAnswerOptions : public JsepOAOptions {}; enum JsepBundlePolicy { kBundleBalanced, kBundleMaxCompat, kBundleMaxBundle }; enum JsepMediaType { kNone = 0, kAudio, kVideo, kAudioVideo }; struct JsepExtmapMediaType { JsepMediaType mMediaType; SdpExtmapAttributeList::Extmap mExtmap; }; class JsepSession { public: explicit JsepSession(const std::string& name) : mName(name), mState(kJsepStateStable), mNegotiations(0) {} virtual ~JsepSession() {} virtual JsepSession* Clone() const = 0; virtual nsresult Init() = 0; // Accessors for basic properties. virtual const std::string& GetName() const { return mName; } virtual JsepSignalingState GetState() const { return mState; } virtual uint32_t GetNegotiations() const { return mNegotiations; } // Set up the ICE And DTLS data. virtual nsresult SetBundlePolicy(JsepBundlePolicy policy) = 0; virtual bool RemoteIsIceLite() const = 0; virtual std::vector GetIceOptions() const = 0; virtual nsresult AddDtlsFingerprint(const std::string& algorithm, const std::vector& value) = 0; virtual nsresult AddRtpExtension( JsepMediaType mediaType, const std::string& extensionName, SdpDirectionAttribute::Direction direction) = 0; virtual nsresult AddAudioRtpExtension( const std::string& extensionName, SdpDirectionAttribute::Direction direction) = 0; virtual nsresult AddVideoRtpExtension( const std::string& extensionName, SdpDirectionAttribute::Direction direction) = 0; virtual nsresult AddAudioVideoRtpExtension( const std::string& extensionName, SdpDirectionAttribute::Direction direction) = 0; // Kinda gross to be locking down the data structure type like this, but // returning by value is problematic due to the lack of stl move semantics in // our build config, since we can't use UniquePtr in the container. The // alternative is writing a raft of accessor functions that allow arbitrary // manipulation (which will be unwieldy), or allowing functors to be injected // that manipulate the data structure (still pretty unwieldy). virtual std::vector>& Codecs() = 0; template void ForEachCodec(UnaryFunction& function) { std::for_each(Codecs().begin(), Codecs().end(), function); for (auto& transceiver : GetTransceivers()) { transceiver.mSendTrack.ForEachCodec(function); transceiver.mRecvTrack.ForEachCodec(function); } } template void SortCodecs(BinaryPredicate& sorter) { std::stable_sort(Codecs().begin(), Codecs().end(), sorter); for (auto& transceiver : GetTransceivers()) { transceiver.mSendTrack.SortCodecs(sorter); transceiver.mRecvTrack.SortCodecs(sorter); } } // Would be nice to have this return a Maybe containing the return of // |aFunction|, but Maybe cannot contain a void. template bool ApplyToTransceiver(const std::string& aId, UnaryFunction&& aFunction) { for (auto& transceiver : GetTransceivers()) { if (transceiver.GetUuid() == aId) { std::forward(aFunction)(transceiver); return true; } } return false; } template void ForEachTransceiver(UnaryFunction&& aFunction) { for (auto& transceiver : GetTransceivers()) { std::forward(aFunction)(transceiver); } } template void ForEachTransceiver(UnaryFunction&& aFunction) const { for (const auto& transceiver : GetTransceivers()) { std::forward(aFunction)(transceiver); } } Maybe GetTransceiver(const std::string& aId) const { for (const auto& transceiver : GetTransceivers()) { if (transceiver.GetUuid() == aId) { return Some(transceiver); } } return Nothing(); } template Maybe FindTransceiver(MatchFunction&& aFunc) const { for (const auto& transceiver : GetTransceivers()) { if (std::forward(aFunc)(transceiver)) { return Some(transceiver); } } return Nothing(); } bool SetTransceiver(const JsepTransceiver& aNew) { return ApplyToTransceiver(aNew.GetUuid(), [aNew](JsepTransceiver& aOld) { aOld = aNew; }); } virtual void AddTransceiver(const JsepTransceiver& transceiver) = 0; class Result { public: Result() = default; MOZ_IMPLICIT Result(dom::PCError aError) : mError(Some(aError)) {} // TODO(bug 1527916): Need c'tor and members for handling RTCError. Maybe mError; }; // Basic JSEP operations. virtual Result CreateOffer(const JsepOfferOptions& options, std::string* offer) = 0; virtual Result CreateAnswer(const JsepAnswerOptions& options, std::string* answer) = 0; virtual std::string GetLocalDescription( JsepDescriptionPendingOrCurrent type) const = 0; virtual std::string GetRemoteDescription( JsepDescriptionPendingOrCurrent type) const = 0; virtual Result SetLocalDescription(JsepSdpType type, const std::string& sdp) = 0; virtual Result SetRemoteDescription(JsepSdpType type, const std::string& sdp) = 0; virtual Result AddRemoteIceCandidate(const std::string& candidate, const std::string& mid, const Maybe& level, const std::string& ufrag, std::string* transportId) = 0; virtual nsresult AddLocalIceCandidate(const std::string& candidate, const std::string& transportId, const std::string& ufrag, uint16_t* level, std::string* mid, bool* skipped) = 0; virtual nsresult UpdateDefaultCandidate( const std::string& defaultCandidateAddr, uint16_t defaultCandidatePort, const std::string& defaultRtcpCandidateAddr, uint16_t defaultRtcpCandidatePort, const std::string& transportId) = 0; virtual nsresult Close() = 0; // ICE controlling or controlled virtual bool IsIceControlling() const = 0; virtual Maybe IsPendingOfferer() const = 0; virtual Maybe IsCurrentOfferer() const = 0; virtual bool IsIceRestarting() const = 0; virtual std::set> GetLocalIceCredentials() const = 0; virtual const std::string GetLastError() const { return "Error"; } virtual const std::vector>& GetLastSdpParsingErrors() const = 0; static const char* GetStateStr(JsepSignalingState state) { static const char* states[] = {"stable", "have-local-offer", "have-remote-offer", "have-local-pranswer", "have-remote-pranswer", "closed"}; return states[state]; } virtual bool CheckNegotiationNeeded() const = 0; void CountTracksAndDatachannels( uint16_t (&receiving)[SdpMediaSection::kMediaTypes], uint16_t (&sending)[SdpMediaSection::kMediaTypes]) const { memset(receiving, 0, sizeof(receiving)); memset(sending, 0, sizeof(sending)); for (const auto& transceiver : GetTransceivers()) { if (transceiver.mRecvTrack.GetActive() || transceiver.GetMediaType() == SdpMediaSection::kApplication) { receiving[transceiver.mRecvTrack.GetMediaType()]++; } if (transceiver.mSendTrack.GetActive() || transceiver.GetMediaType() == SdpMediaSection::kApplication) { sending[transceiver.mSendTrack.GetMediaType()]++; } } } virtual void SetDefaultCodecs( const std::vector>& aPreferredCodecs) = 0; // See Bug 1642419, this can be removed when all sites are working with RTX. void SetRtxIsAllowed(bool aRtxIsAllowed) { mRtxIsAllowed = aRtxIsAllowed; } protected: friend class JsepSessionTest; // Returns transceivers in the order they were added. virtual std::vector& GetTransceivers() = 0; virtual const std::vector& GetTransceivers() const = 0; const std::string mName; JsepSignalingState mState; uint32_t mNegotiations; // See Bug 1642419, this can be removed when all sites are working with RTX. bool mRtxIsAllowed = true; }; } // namespace mozilla #endif