LCOV - code coverage report
Current view: top level - src/sip - sipcall.h (source / functions) Coverage Total Hit
Test: jami-coverage-filtered.info Lines: 100.0 % 24 24
Test Date: 2026-11-09 10:41:14 Functions: 100.0 % 15 15

            Line data    Source code
       1              : /*
       2              :  * Copyright (C) 2004-2026 Savoir-faire Linux Inc.
       3              :  *
       4              :  * This program is free software: you can redistribute it and/or modify
       5              :  * it under the terms of the GNU General Public License as published by
       6              :  * the Free Software Foundation, either version 3 of the License, or
       7              :  * (at your option) any later version.
       8              :  *
       9              :  * This program is distributed in the hope that it will be useful,
      10              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
      12              :  * GNU General Public License for more details.
      13              :  *
      14              :  * You should have received a copy of the GNU General Public License
      15              :  * along with this program. If not, see <https://www.gnu.org/licenses/>.
      16              :  */
      17              : 
      18              : #pragma once
      19              : 
      20              : #ifdef HAVE_CONFIG_H
      21              : #include "config.h"
      22              : #endif
      23              : 
      24              : #include "call.h"
      25              : #include <dhtnet/ice_transport.h>
      26              : #include "media/media_codec.h" // for MediaType enum
      27              : #include "sip/sdp.h"
      28              : 
      29              : #include "media/rtp_session.h"
      30              : #ifdef ENABLE_VIDEO
      31              : #include "media/video/video_receive_thread.h"
      32              : #include "media/video/video_rtp_session.h"
      33              : #endif
      34              : #ifdef ENABLE_PLUGIN
      35              : #include "plugin/streamdata.h"
      36              : #endif
      37              : #include "noncopyable.h"
      38              : 
      39              : #include <asio/steady_timer.hpp>
      40              : #include <atomic>
      41              : #include <cstdint>
      42              : #include <memory>
      43              : #include <optional>
      44              : 
      45              : extern "C" {
      46              : #include <pjsip/sip_config.h>
      47              : struct pjsip_evsub;
      48              : struct pjsip_inv_session;
      49              : struct pjmedia_sdp_session;
      50              : struct pj_ice_sess_cand;
      51              : struct pjsip_rx_data;
      52              : }
      53              : 
      54              : namespace dhtnet {
      55              : class IceSocket;
      56              : namespace upnp {
      57              : class Controller;
      58              : }
      59              : } // namespace dhtnet
      60              : 
      61              : namespace jami {
      62              : 
      63              : class Sdp;
      64              : class SIPAccountBase;
      65              : class SipTransport;
      66              : class AudioRtpSession;
      67              : 
      68              : namespace test {
      69              : class HandoverTest;
      70              : }
      71              : 
      72              : using IceCandidate = pj_ice_sess_cand;
      73              : 
      74              : /**
      75              :  * @file sipcall.h
      76              :  * @brief SIPCall are SIP implementation of a normal Call
      77              :  */
      78              : class SIPCall : public Call
      79              : {
      80              : private:
      81              :     using clock = std::chrono::steady_clock;
      82              :     using time_point = clock::time_point;
      83              : 
      84              :     NON_COPYABLE(SIPCall);
      85              : 
      86              : public:
      87              :     static constexpr LinkType LINK_TYPE = LinkType::SIP;
      88              : 
      89              :     struct RtpStream
      90              :     {
      91              :         std::shared_ptr<RtpSession> rtpSession_ {};
      92              :         std::shared_ptr<MediaAttribute> mediaAttribute_ {};
      93              :         std::shared_ptr<MediaAttribute> remoteMediaAttribute_;
      94              :         std::unique_ptr<dhtnet::IceSocket> rtpSocket_;
      95              :         std::unique_ptr<dhtnet::IceSocket> rtcpSocket_;
      96              :     };
      97              : 
      98              :     /**
      99              :      * Destructor
     100              :      */
     101              :     ~SIPCall();
     102              : 
     103              :     /**
     104              :      * Constructor
     105              :      * @param id The call identifier
     106              :      * @param type The type of the call (incoming/outgoing)
     107              :      * @param mediaList A list of medias to include in the call
     108              :      */
     109              :     SIPCall(const std::shared_ptr<SIPAccountBase>& account,
     110              :             const std::string& id,
     111              :             Call::CallType type,
     112              :             const std::vector<libjami::MediaMap>& mediaList);
     113              : 
     114              :     // Inherited from Call class
     115          851 :     LinkType getLinkType() const override { return LINK_TYPE; }
     116              : 
     117              :     // Override of Call class
     118              : private:
     119              :     void merge(Call& call) override; // not public - only called by Call
     120              : 
     121              : public:
     122              :     void answer(const std::vector<libjami::MediaMap>& mediaList) override;
     123              :     bool checkMediaChangeRequest(const std::vector<libjami::MediaMap>& remoteMediaList) override;
     124              :     void handleMediaChangeRequest(const std::vector<libjami::MediaMap>& remoteMediaList) override;
     125              :     void answerMediaChangeRequest(const std::vector<libjami::MediaMap>& mediaList, bool isRemote = false) override;
     126              :     void hangup(int code) override;
     127              :     void refuse() override;
     128              :     void transfer(const std::string& to) override;
     129              :     bool attendedTransfer(const std::string& to) override;
     130              :     bool hold(OnReadyCb&& cb) override;
     131              :     bool resume(OnReadyCb&& cb) override;
     132              :     void switchInput(const std::string& resource = {}) override;
     133              :     void peerHungup() override;
     134              :     void carryingDTMFdigits(char code) override;
     135              :     bool requestMediaChange(const std::vector<libjami::MediaMap>& mediaList) override;
     136              :     std::vector<libjami::MediaMap> currentMediaList() const override;
     137              :     void sendTextMessage(const std::map<std::string, std::string>& messages, const std::string& from) override;
     138              :     void removeCall(int code = 0) override;
     139              :     void muteMedia(const std::string& mediaType, bool isMuted) override;
     140              :     std::vector<MediaAttribute> getMediaAttributeList() const override;
     141              :     std::map<std::string, bool> getAudioStreams() const override;
     142              :     std::map<std::string, bool> getRemoteAudioStreams() const override;
     143              :     void restartMediaSender() override;
     144              :     std::shared_ptr<SystemCodecInfo> getAudioCodec() const override;
     145              :     std::shared_ptr<SystemCodecInfo> getVideoCodec() const override;
     146              :     void sendKeyframe(int streamIdx = -1) override;
     147              :     bool isIceEnabled() const override;
     148              :     std::map<std::string, std::string> getDetails() const override;
     149              :     void enterConference(std::shared_ptr<Conference> conference) override;
     150              :     void exitConference() override;
     151              : #ifdef ENABLE_VIDEO
     152              :     std::mutex sinksMtx_;
     153              :     void createSinks(ConfInfo& infos) override;
     154              :     std::map<std::string, std::shared_ptr<video::SinkClient>> callSinksMap_ {};
     155              :     std::map<std::string, std::string> local2RemoteSinks_ {};
     156              : #endif
     157              :     bool hasVideo() const override;
     158              : 
     159              :     // TODO: cleanup this (used by conference + Call::getDetails() (and clients can use this))
     160              :     bool isCaptureDeviceMuted(const MediaType& mediaType) const override;
     161         2352 :     bool isSrtpEnabled() const { return srtpEnabled_; }
     162              :     // End of override of Call class
     163              : 
     164              :     // Override of Recordable class
     165              :     bool toggleRecording() override;
     166              :     // End of override of Recordable class
     167              : 
     168              :     // Override PeerRecorder
     169              :     void peerRecording(bool state) override;
     170              :     void peerMuted(bool state, int streamIdx) override;
     171              :     void peerVoice(bool state) override;
     172              :     // end override PeerRecorder
     173              : 
     174              :     void monitor() const override;
     175              : 
     176              :     /**
     177              :      * Set peer's User-Agent found in the message header
     178              :      */
     179              :     void setPeerUaVersion(std::string_view ua);
     180              : 
     181              :     /**
     182              :      * Set peer's allowed methods
     183              :      */
     184              :     void setPeerAllowMethods(std::vector<std::string> methods);
     185              : 
     186              :     /**
     187              :      * Check if a SIP method is allowed by peer
     188              :      */
     189              :     bool isSipMethodAllowedByPeer(const std::string_view method) const;
     190              : 
     191              :     /**
     192              :      * Return the SDP's manager of this call
     193              :      */
     194          757 :     Sdp& getSDP() { return *sdp_; }
     195              : 
     196              :     // Implementation of events reported by SipVoipLink.
     197              :     /**
     198              :      * Call is in ringing state on peer's side
     199              :      */
     200              :     void onPeerRinging();
     201              :     /**
     202              :      * Peer answered the call
     203              :      */
     204              :     void onAnswered();
     205              :     /**
     206              :      * Called to report server/internal errors
     207              :      * @param code Optional SIP response code (see RFC3261)
     208              :      */
     209              :     void onFailure(int code = 0);
     210              :     /**
     211              :      * Peer answered busy
     212              :      */
     213              :     void onBusyHere();
     214              :     /**
     215              :      * Peer closed the connection
     216              :      */
     217              :     void onClosed();
     218              : 
     219              :     pj_status_t onReceiveReinvite(const pjmedia_sdp_session* offer, pjsip_rx_data* rdata);
     220              :     void onReceiveOfferIn200OK(const pjmedia_sdp_session* offer);
     221              : 
     222              :     /**
     223              :      * Called when the media negotiation (SDP offer/answer) has
     224              :      * completed.
     225              :      */
     226              :     void onMediaNegotiationComplete();
     227              :     // End fo SiPVoipLink events
     228              : 
     229              :     const std::string& getContactHeader() const;
     230              : 
     231              :     void setSipTransport(const std::shared_ptr<SipTransport>& transport, const std::string& contactHdr = {});
     232              : 
     233          856 :     SipTransport* getTransport() { return sipTransport_.get(); }
     234              : 
     235              :     // Account of the peer authenticated by the SIP channel, empty without one.
     236              :     std::string getPeerAccountId() const;
     237              : 
     238          197 :     void setPeerHandoverSupported(bool supported) { peerSupportsHandover_.store(supported); }
     239         2358 :     bool peerSupportsHandover() const { return peerSupportsHandover_.load(); }
     240              :     bool isRetiredSipTransport(const pjsip_transport* transport) const;
     241              :     // Handover requests filtered before dialog processing: stale re-INVITEs
     242              :     // get 491, malformed ones 400, and the caller answers recovery probes.
     243              :     enum class HandoverRequest { Pass, Probe, Stale, Invalid };
     244              :     static HandoverRequest classifyHandoverRequest(const pjsip_rx_data* rdata, bool caller, std::uint64_t generation);
     245           80 :     std::uint64_t recoveryGeneration() const { return recoveryGeneration_.load(); }
     246              :     bool isCurrentMediaNegotiation() const;
     247              :     void retryRecoveryOffer(std::uint64_t generation);
     248              : 
     249              :     bool beginCallRecovery(bool newNetwork = false);
     250          124 :     bool isRecovering() const
     251              :     {
     252          124 :         std::lock_guard lk {callMutex_};
     253          248 :         return recovering_;
     254          124 :     }
     255           18 :     bool needsNewSipChannel() const
     256              :     {
     257           18 :         std::lock_guard lk {callMutex_};
     258           36 :         return recovering_ and waitingForRecoveryChannel_;
     259           18 :     }
     260              :     std::optional<std::uint64_t> startRecoveryAttempt(bool force = false);
     261              :     bool finishRecoveryAttempt(std::uint64_t attempt);
     262              :     bool useRecoveredTransport(const std::shared_ptr<SipTransport>& transport,
     263              :                                const std::string& contact,
     264              :                                std::optional<std::uint64_t> attempt);
     265              :     // Caller only: move the dialog to the channel of the callee's recovery probe.
     266              :     void followPeerTransport(const std::shared_ptr<SipTransport>& transport, const std::string& contact,
     267              :                              std::uint64_t generation, std::uint64_t request);
     268              :     void onInviteTransactionEnded();
     269              : 
     270              :     void sendSIPInfo(std::string_view body, std::string_view subtype);
     271              : 
     272              :     void requestKeyframe(int streamIdx = -1);
     273              : 
     274              :     void updateRecState(bool state) override;
     275              : 
     276              :     std::shared_ptr<SIPAccountBase> getSIPAccount() const;
     277              : 
     278              :     bool remoteHasValidIceAttributes() const;
     279              :     void addLocalIceAttributes();
     280              : 
     281         3332 :     std::shared_ptr<dhtnet::IceTransport> getIceMedia() const
     282              :     {
     283         3332 :         std::lock_guard lk(transportMtx_);
     284         6664 :         return reinvIceMedia_ ? reinvIceMedia_ : iceMedia_;
     285         3332 :     };
     286              : 
     287              :     // Set ICE instance. Must be called only for sub-calls
     288              :     void setIceMedia(std::shared_ptr<dhtnet::IceTransport> ice, bool isReinvite = false);
     289              : 
     290              :     // Switch to re-invite ICE media if needed
     291              :     void switchToIceReinviteIfNeeded();
     292              : 
     293              :     /**
     294              :      * Setup ICE locally to answer to an ICE offer. The ICE session has
     295              :      * the controlled role (slave)
     296              :      */
     297              :     void setupIceResponse(bool isReinvite = false, bool withoutUpnpWait = false);
     298              : 
     299              :     void terminateSipSession(int status);
     300              : 
     301              :     /**
     302              :      * The invite session to be reused in case of transfer
     303              :      */
     304              :     struct InvSessionDeleter
     305              :     {
     306              :         void operator()(pjsip_inv_session*) const noexcept;
     307              :     };
     308              : 
     309              : #ifdef ENABLE_VIDEO
     310              :     void setRotation(int streamIdx, int rotation);
     311              : #endif
     312              :     // Get the list of current RTP sessions
     313              :     std::vector<std::shared_ptr<RtpSession>> getRtpSessionList(MediaType type = MediaType::MEDIA_ALL) const;
     314              :     static size_t getActiveMediaStreamCount(const std::vector<MediaAttribute>& mediaAttrList);
     315              :     void setActiveMediaStream(const std::string& accountUri,
     316              :                               const std::string& deviceId,
     317              :                               const std::string& streamId,
     318              :                               const bool& state);
     319              : 
     320            1 :     void setPeerRegisteredName(const std::string& name) { peerRegisteredName_ = name; }
     321              : 
     322          343 :     void setPeerUri(const std::string& peerUri) { peerUri_ = peerUri; }
     323              : 
     324           75 :     std::string_view peerUri() const { return peerUri_; }
     325              : 
     326              :     // Create a new ICE media session. If we already have an instance,
     327              :     // it will be destroyed first.
     328              :     bool createIceMediaTransport(bool isReinvite);
     329              : 
     330              :     // Initialize the ICE session.
     331              :     // The initialization is performed asynchronously, i.e, the instance
     332              :     // may not be ready to use when this method returns.
     333              :     bool initIceMediaTransport(bool master, std::optional<dhtnet::IceTransportOptions> options = std::nullopt);
     334              : 
     335              :     std::vector<std::string> getLocalIceCandidates(unsigned compId) const;
     336              : 
     337              :     void setInviteSession(pjsip_inv_session* inviteSession = nullptr);
     338              : 
     339              :     std::unique_ptr<pjsip_inv_session, InvSessionDeleter> inviteSession_;
     340              : 
     341              :     inline std::weak_ptr<const SIPCall> weak() const { return std::weak_ptr<const SIPCall>(shared()); }
     342         3706 :     inline std::weak_ptr<SIPCall> weak() { return std::weak_ptr<SIPCall>(shared()); }
     343              :     /**
     344              :      * Announce to the client that medias are successfully negotiated
     345              :      */
     346              :     void reportMediaNegotiationStatus();
     347              : 
     348              :     const std::vector<RtpStream>& getRtpStreams() const { return rtpStreams_; }
     349              : 
     350              : private:
     351              :     friend class test::HandoverTest;
     352              : 
     353              :     void stopCallRecovery();
     354              :     void startRecoveryLocked();
     355              :     bool rebindSipDialogLocked(const std::shared_ptr<SipTransport>& transport, const std::string& contact);
     356              :     // Callee only: move the dialog to the channel of the caller's recovery offer.
     357              :     bool adoptRecoveryOfferLocked(const std::shared_ptr<SipTransport>& transport,
     358              :                                   const std::string& contact,
     359              :                                   std::uint64_t generation);
     360              :     // Requires callMutex_ and the dialog lock.
     361              :     bool isPendingReinviteLocked(pj_int32_t cseq) const;
     362              :     // Answers only the matching pending re-INVITE when a CSeq is supplied.
     363              :     void rejectPendingReinviteLocked(std::optional<pj_int32_t> cseq = std::nullopt);
     364              :     void requestIceRestart(const std::shared_ptr<SipTransport>& transport);
     365              :     void sendRecoveryProbeLocked(const std::shared_ptr<SipTransport>& transport);
     366              :     void scheduleRecoveryProbeLocked();
     367              :     void restartIceAfterRecovery(dhtnet::IceTransportOptions&& options,
     368              :                                  std::optional<std::uint64_t> generation = std::nullopt);
     369              :     void completeRecoveryIfReadyLocked();
     370              :     bool isReinviteBusyLocked() const;
     371              :     void drainPendingRequests();
     372              :     // Returns the client callback to run with the result, if any, so that
     373              :     // callers holding callMutex_ can run it once released.
     374              :     std::function<void()> processRemainingRequest();
     375              : 
     376              :     void generateMediaPorts();
     377              : 
     378              :     void openPortsUPnP();
     379              : 
     380              :     bool isIceRunning() const;
     381              : 
     382              :     std::unique_ptr<dhtnet::IceSocket> newIceSocket(unsigned compId);
     383              : 
     384              :     void deinitRecorder();
     385              : 
     386              :     void updateRecordingMediaState(bool readyToRecord);
     387              : 
     388              :     void rtpSetupSuccess();
     389              : 
     390              :     void setupVoiceCallback(const std::shared_ptr<RtpSession>& rtpSession);
     391              : 
     392              :     void sendMuteState(bool state);
     393              :     void sendVoiceActivity(std::string_view streamId, bool state);
     394              : 
     395              :     void resetTransport(std::shared_ptr<dhtnet::IceTransport>&& transport);
     396              : 
     397              :     /**
     398              :      * Send device orientation through SIP INFO
     399              :      * @param streamIdx  The stream to rotate
     400              :      * @param rotation   Device orientation (0/90/180/270) (counterclockwise)
     401              :      */
     402              :     void setVideoOrientation(int streamIdx, int rotation);
     403              : 
     404              :     mutable std::mutex transportMtx_ {};
     405              : 
     406              : #ifdef ENABLE_PLUGIN
     407              :     /**
     408              :      * Call Streams and some typedefs
     409              :      */
     410              :     using AVMediaStream = Observable<std::shared_ptr<MediaFrame>>;
     411              :     using MediaStreamSubject = PublishMapSubject<std::shared_ptr<MediaFrame>, AVFrame*>;
     412              : 
     413              :     /**
     414              :      * @brief createCallAVStream
     415              :      * Creates a call AV stream like video input, video receive, audio input or audio receive
     416              :      * @param StreamData The type of the stream (audio/video, input/output,
     417              :      * @param streamSource
     418              :      * @param mediaStreamSubject
     419              :      */
     420              :     void createCallAVStream(const StreamData& StreamData,
     421              :                             AVMediaStream& streamSource,
     422              :                             const std::shared_ptr<MediaStreamSubject>& mediaStreamSubject);
     423              :     /**
     424              :      * @brief createCallAVStreams
     425              :      * Creates all Call AV Streams (2 if audio, 4 if audio video)
     426              :      */
     427              :     void createCallAVStreams();
     428              : 
     429              :     /**
     430              :      * @brief Detach all plugins from call streams;
     431              :      */
     432              :     void clearCallAVStreams();
     433              : 
     434              :     std::mutex avStreamsMtx_ {};
     435              :     std::map<std::string, std::shared_ptr<MediaStreamSubject>> callAVStreams;
     436              : #endif // ENABLE_PLUGIN
     437              : 
     438              :     void setCallMediaLocal();
     439              :     void startIceMedia();
     440              :     void onIceInitDone(const std::shared_ptr<dhtnet::IceTransport>& initializedIce, bool ok,
     441              :                        std::optional<std::uint64_t> generation = std::nullopt);
     442              :     void onIceNegoDone(const std::shared_ptr<dhtnet::IceTransport>& negotiatedIce, bool ok,
     443              :                        std::optional<std::uint64_t> generation = std::nullopt);
     444              :     void onIceNegoSucceed(const std::shared_ptr<dhtnet::IceTransport>& negotiatedIce, bool fromSubcall = false);
     445              :     void setupNegotiatedMedia();
     446              :     void startAllMedia();
     447              :     void stopAllMedia();
     448              : 
     449              :     /**
     450              :      * Transfer method used for both type of transfer
     451              :      */
     452              :     bool transferCommon(const pj_str_t* dst);
     453              : 
     454              :     bool internalResume(const std::function<void()>& SDPUpdateFunc);
     455              : 
     456              :     bool hold();
     457              : 
     458              :     bool resume();
     459              : 
     460              :     // Update the attributes of a media stream
     461              :     void updateMediaStream(const MediaAttribute& newMediaAttr, size_t streamIdx);
     462              :     bool updateAllMediaStreams(const std::vector<MediaAttribute>& mediaAttrList, bool isRemote);
     463              :     // Check if a SIP re-invite must be sent to negotiate the new media
     464              :     bool isReinviteRequired(const std::vector<MediaAttribute>& mediaAttrList);
     465              :     // Check if a new ICE media session is needed when performing a re-invite
     466              :     bool isNewIceMediaRequired(const std::vector<MediaAttribute>& mediaAttrList);
     467              :     void requestReinvite(const std::vector<MediaAttribute>& mediaAttrList, bool needNewIce);
     468              :     int SIPSessionReinvite(const std::vector<MediaAttribute>& mediaAttrList,
     469              :                            bool needNewIce,
     470              :                            std::optional<dhtnet::IceTransportOptions> iceOptions = std::nullopt,
     471              :                            bool recoveryOffer = false);
     472              :     int SIPSessionReinvite();
     473              :     // Add a media stream to the call.
     474              :     void addMediaStream(const MediaAttribute& mediaAttr);
     475              :     // Init media streams
     476              :     size_t initMediaStreams(const std::vector<MediaAttribute>& mediaAttrList);
     477              :     // Create a new stream from SDP description.
     478              :     void createRtpSession(RtpStream& rtpStream);
     479              :     // Configure the RTP session from SDP description.
     480              :     void configureRtpSession(const std::shared_ptr<RtpSession>& rtpSession,
     481              :                              const std::shared_ptr<MediaAttribute>& mediaAttr,
     482              :                              const MediaDescription& localMedia,
     483              :                              const MediaDescription& remoteMedia);
     484              :     // Find the stream index with the matching label
     485              :     int findRtpStreamIndex(const std::string& label) const;
     486              : 
     487              :     std::vector<IceCandidate> getAllRemoteCandidates(dhtnet::IceTransport& transport) const;
     488              : 
     489              :     inline std::shared_ptr<const SIPCall> shared() const
     490              :     {
     491              :         return std::static_pointer_cast<const SIPCall>(shared_from_this());
     492              :     }
     493         3932 :     inline std::shared_ptr<SIPCall> shared() { return std::static_pointer_cast<SIPCall>(shared_from_this()); }
     494              : 
     495              :     // Peer's User-Agent.
     496              :     std::string peerUserAgent_ {};
     497              :     // Flag to indicate if the peer's Daemon version supports multi-stream.
     498              :     bool peerSupportMultiStream_ {false};
     499              :     // Flag to indicate if the peer's Daemon version supports multi-stream.
     500              :     bool peerSupportMultiAudioStream_ {false};
     501              :     // Flag to indicate if the peer's Daemon version can negotiate more than 2 ICE medias
     502              :     bool peerSupportMultiIce_ {false};
     503              : 
     504              :     // Flag to indicate if the peer's Daemon version supports re-invite
     505              :     // without ICE renegotiation.
     506              :     bool peerSupportReuseIceInReinv_ {false};
     507              :     std::atomic_bool peerSupportsHandover_ {false};
     508              :     // Set when the peer sent its re-INVITE on a new channel after a network change.
     509              :     std::atomic_bool peerMovedInReinvite_ {false};
     510              :     std::atomic_bool recovering_ {false};
     511              :     bool waitingForRecoveryChannel_ {false};
     512              :     bool recoveryAttemptPending_ {false};
     513              :     std::uint64_t recoveryAttempt_ {0};
     514              :     bool recoveryRestartPending_ {false};
     515              :     std::unique_ptr<asio::steady_timer> recoveryTimer_;
     516              :     struct RecoveryNegotiation
     517              :     {
     518              :         enum class Phase { IcePending, MediaReady };
     519              :         std::uint64_t generation;
     520              :         std::weak_ptr<SipTransport> transport;
     521              :         std::shared_ptr<dhtnet::IceTransport> ice;
     522              :         Phase phase {Phase::IcePending};
     523              :     };
     524              :     std::optional<RecoveryNegotiation> recoveryNegotiation_;
     525              :     // Channels left for a newer one, which the dialog must not follow back.
     526              :     std::vector<std::weak_ptr<SipTransport>> abandonedTransports_;
     527              :     // Issued by the caller, adopted by the callee with the recovery offer.
     528              :     // Written under callMutex_, read lock-free by request admission.
     529              :     std::atomic<std::uint64_t> recoveryGeneration_ {0};
     530              :     std::uint64_t recoveryRequest_ {0};
     531              :     std::uint64_t lastPeerRecoveryRequest_ {0};
     532              :     std::uint64_t recoveryEpisode_ {0};
     533              :     std::atomic<std::uint64_t> mediaNegotiationGeneration_ {0};
     534              :     std::shared_ptr<SipTransport> recoveryCandidate_;
     535              :     // Media change requested during a recovery, sent once it is over.
     536              :     std::optional<std::vector<libjami::MediaMap>> pendingMediaChange_;
     537              : 
     538              :     // Peer's allowed methods. Set under the pjsip dialog lock, so not guarded by callMutex_.
     539              :     mutable std::mutex peerAllowedMethodsMutex_;
     540              :     std::vector<std::string> peerAllowedMethods_;
     541              : 
     542              :     // Vector holding the current RTP sessions.
     543              :     std::vector<RtpStream> rtpStreams_;
     544              : 
     545              :     /**
     546              :      * Hold the transport used for SIP communication.
     547              :      * Will be different from the account registration transport for
     548              :      * non-IP2IP calls.
     549              :      */
     550              :     std::shared_ptr<SipTransport> sipTransport_ {};
     551              : 
     552              :     /**
     553              :      * The SDP session
     554              :      */
     555              :     std::unique_ptr<Sdp> sdp_ {};
     556              :     bool peerHold_ {false};
     557              : 
     558              :     bool isWaitingForIceAndMedia_ {false};
     559              :     enum class Request : uint8_t { Hold, Resume, SwitchInput, NoRequest };
     560              :     Request remainingRequest_ {Request::NoRequest};
     561              : 
     562              :     std::string peerRegisteredName_ {};
     563              : 
     564              :     std::string contactHeader_ {};
     565              : 
     566              :     std::shared_ptr<dhtnet::upnp::Controller> upnp_;
     567              : 
     568              :     /** Local audio port, as seen by me. */
     569              :     unsigned int localAudioPort_ {0};
     570              :     /** Local video port, as seen by me. */
     571              :     unsigned int localVideoPort_ {0};
     572              : 
     573              :     bool mediaRestartRequired_ {true};
     574              :     bool enableIce_ {true};
     575              :     bool srtpEnabled_ {false};
     576              :     bool rtcpMuxEnabled_ {false};
     577              : 
     578              :     // ICE media transport
     579              :     std::shared_ptr<dhtnet::IceTransport> iceMedia_;
     580              :     // Re-invite (temporary) ICE media transport.
     581              :     std::shared_ptr<dhtnet::IceTransport> reinvIceMedia_;
     582              : 
     583              :     std::string peerUri_ {};
     584              : 
     585              :     bool readyToRecord_ {false};
     586              :     bool pendingRecord_ {false};
     587              : 
     588              :     time_point lastKeyFrameReq_ {time_point::min()};
     589              : 
     590              :     OnReadyCb holdCb_ {};
     591              :     OnReadyCb resumeCb_ {};
     592              : 
     593              :     std::atomic_bool waitForIceInit_ {false};
     594              : 
     595              :     void detachAudioFromConference();
     596              : 
     597              :     std::mutex mediaStateMutex_;
     598              : #ifdef ENABLE_VIDEO
     599              :     int rotation_ {0};
     600              : #endif
     601              : 
     602              :     std::string mediaPlayerId_ {};
     603              : };
     604              : 
     605              : // Helpers
     606              : 
     607              : /**
     608              :  * Obtain a shared smart pointer of instance
     609              :  */
     610              : inline std::shared_ptr<SIPCall>
     611              : getPtr(SIPCall& call)
     612              : {
     613              :     return std::static_pointer_cast<SIPCall>(call.shared_from_this());
     614              : }
     615              : 
     616              : } // namespace jami
        

Generated by: LCOV version 2.0-1