/** * Copyright (c) 2019 Paul-Louis Ageneau * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef RTC_PEER_CONNECTION_H #define RTC_PEER_CONNECTION_H #include "candidate.hpp" #include "configuration.hpp" #include "datachannel.hpp" #include "description.hpp" #include "include.hpp" #include "init.hpp" #include "message.hpp" #include "reliability.hpp" #include "rtc.hpp" #include "track.hpp" #include #include #include #include #include #include #include #include namespace rtc { class Certificate; class Processor; class IceTransport; class DtlsTransport; class SctpTransport; using certificate_ptr = std::shared_ptr; using future_certificate_ptr = std::shared_future; struct DataChannelInit { Reliability reliability = {}; bool negotiated = false; std::optional id = nullopt; string protocol = ""; }; class PeerConnection final : public std::enable_shared_from_this { public: enum class State : int { New = RTC_NEW, Connecting = RTC_CONNECTING, Connected = RTC_CONNECTED, Disconnected = RTC_DISCONNECTED, Failed = RTC_FAILED, Closed = RTC_CLOSED }; enum class GatheringState : int { New = RTC_GATHERING_NEW, InProgress = RTC_GATHERING_INPROGRESS, Complete = RTC_GATHERING_COMPLETE }; enum class SignalingState : int { Stable = RTC_SIGNALING_STABLE, HaveLocalOffer = RTC_SIGNALING_HAVE_LOCAL_OFFER, HaveRemoteOffer = RTC_SIGNALING_HAVE_REMOTE_OFFER, HaveLocalPranswer = RTC_SIGNALING_HAVE_LOCAL_PRANSWER, HaveRemotePranswer = RTC_SIGNALING_HAVE_REMOTE_PRANSWER, } rtcSignalingState; PeerConnection(); PeerConnection(const Configuration &config); ~PeerConnection(); void close(); const Configuration *config() const; State state() const; GatheringState gatheringState() const; SignalingState signalingState() const; bool hasLocalDescription() const; bool hasRemoteDescription() const; bool hasMedia() const; std::optional localDescription() const; std::optional remoteDescription() const; std::optional localAddress() const; std::optional remoteAddress() const; bool getSelectedCandidatePair(Candidate *local, Candidate *remote); void setLocalDescription(Description::Type type = Description::Type::Unspec); void setRemoteDescription(Description description); void addRemoteCandidate(Candidate candidate); std::shared_ptr addDataChannel(string label, DataChannelInit init = {}); // Equivalent to calling addDataChannel() and setLocalDescription() std::shared_ptr createDataChannel(string label, DataChannelInit init = {}); void onDataChannel(std::function dataChannel)> callback); void onLocalDescription(std::function callback); void onLocalCandidate(std::function callback); void onStateChange(std::function callback); void onGatheringStateChange(std::function callback); void onSignalingStateChange(std::function callback); // Stats void clearStats(); size_t bytesSent(); size_t bytesReceived(); std::optional rtt(); // Track media support requires compiling with libSRTP std::shared_ptr addTrack(Description::Media description); void onTrack(std::function track)> callback); private: std::shared_ptr initIceTransport(Description::Role role); std::shared_ptr initDtlsTransport(); std::shared_ptr initSctpTransport(); void closeTransports(); void endLocalCandidates(); bool checkFingerprint(const std::string &fingerprint) const; void forwardMessage(message_ptr message); void forwardMedia(message_ptr message); void forwardBufferedAmount(uint16_t stream, size_t amount); std::optional getMidFromSsrc(uint32_t ssrc); std::shared_ptr emplaceDataChannel(Description::Role role, string label, DataChannelInit init); std::shared_ptr findDataChannel(uint16_t stream); void iterateDataChannels(std::function channel)> func); void openDataChannels(); void closeDataChannels(); void remoteCloseDataChannels(); void incomingTrack(Description::Media description); void openTracks(); void validateRemoteDescription(const Description &description); void processLocalDescription(Description description); void processLocalCandidate(Candidate candidate); void processRemoteDescription(Description description); void processRemoteCandidate(Candidate candidate); void triggerDataChannel(std::weak_ptr weakDataChannel); void triggerTrack(std::shared_ptr track); bool changeState(State state); bool changeGatheringState(GatheringState state); bool changeSignalingState(SignalingState state); void resetCallbacks(); void outgoingMedia(message_ptr message); const init_token mInitToken = Init::Token(); const Configuration mConfig; const future_certificate_ptr mCertificate; const std::unique_ptr mProcessor; std::optional mLocalDescription, mRemoteDescription; std::optional mCurrentLocalDescription; mutable std::mutex mLocalDescriptionMutex, mRemoteDescriptionMutex; std::shared_ptr mIceTransport; std::shared_ptr mDtlsTransport; std::shared_ptr mSctpTransport; std::unordered_map> mDataChannels; // by stream ID std::unordered_map> mTracks; // by mid std::vector> mTrackLines; // by SDP order std::shared_mutex mDataChannelsMutex, mTracksMutex; std::unordered_map mMidFromSsrc; // cache std::atomic mState; std::atomic mGatheringState; std::atomic mSignalingState; std::atomic mNegotiationNeeded; synchronized_callback> mDataChannelCallback; synchronized_callback mLocalDescriptionCallback; synchronized_callback mLocalCandidateCallback; synchronized_callback mStateChangeCallback; synchronized_callback mGatheringStateChangeCallback; synchronized_callback mSignalingStateChangeCallback; synchronized_callback> mTrackCallback; }; } // namespace rtc std::ostream &operator<<(std::ostream &out, rtc::PeerConnection::State state); std::ostream &operator<<(std::ostream &out, rtc::PeerConnection::GatheringState state); std::ostream &operator<<(std::ostream &out, rtc::PeerConnection::SignalingState state); #endif