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 % 13 13
Test Date: 2026-06-13 09:18:46 Functions: 100.0 % 10 10

            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 <memory>
      40              : #include <optional>
      41              : 
      42              : extern "C" {
      43              : #include <pjsip/sip_config.h>
      44              : struct pjsip_evsub;
      45              : struct pjsip_inv_session;
      46              : struct pjmedia_sdp_session;
      47              : struct pj_ice_sess_cand;
      48              : struct pjsip_rx_data;
      49              : }
      50              : 
      51              : namespace dhtnet {
      52              : class IceSocket;
      53              : namespace upnp {
      54              : class Controller;
      55              : }
      56              : } // namespace dhtnet
      57              : 
      58              : namespace jami {
      59              : 
      60              : class Sdp;
      61              : class SIPAccountBase;
      62              : class SipTransport;
      63              : class AudioRtpSession;
      64              : 
      65              : using IceCandidate = pj_ice_sess_cand;
      66              : 
      67              : /**
      68              :  * @file sipcall.h
      69              :  * @brief SIPCall are SIP implementation of a normal Call
      70              :  */
      71              : class SIPCall : public Call
      72              : {
      73              : private:
      74              :     using clock = std::chrono::steady_clock;
      75              :     using time_point = clock::time_point;
      76              : 
      77              :     NON_COPYABLE(SIPCall);
      78              : 
      79              : public:
      80              :     static constexpr LinkType LINK_TYPE = LinkType::SIP;
      81              : 
      82              :     struct RtpStream
      83              :     {
      84              :         std::shared_ptr<RtpSession> rtpSession_ {};
      85              :         std::shared_ptr<MediaAttribute> mediaAttribute_ {};
      86              :         std::shared_ptr<MediaAttribute> remoteMediaAttribute_;
      87              :         std::unique_ptr<dhtnet::IceSocket> rtpSocket_;
      88              :         std::unique_ptr<dhtnet::IceSocket> rtcpSocket_;
      89              :     };
      90              : 
      91              :     /**
      92              :      * Destructor
      93              :      */
      94              :     ~SIPCall();
      95              : 
      96              :     /**
      97              :      * Constructor
      98              :      * @param id The call identifier
      99              :      * @param type The type of the call (incoming/outgoing)
     100              :      * @param mediaList A list of medias to include in the call
     101              :      */
     102              :     SIPCall(const std::shared_ptr<SIPAccountBase>& account,
     103              :             const std::string& id,
     104              :             Call::CallType type,
     105              :             const std::vector<libjami::MediaMap>& mediaList);
     106              : 
     107              :     // Inherited from Call class
     108          757 :     LinkType getLinkType() const override { return LINK_TYPE; }
     109              : 
     110              :     // Override of Call class
     111              : private:
     112              :     void merge(Call& call) override; // not public - only called by Call
     113              : 
     114              : public:
     115              :     void answer(const std::vector<libjami::MediaMap>& mediaList) override;
     116              :     bool checkMediaChangeRequest(const std::vector<libjami::MediaMap>& remoteMediaList) override;
     117              :     void handleMediaChangeRequest(const std::vector<libjami::MediaMap>& remoteMediaList) override;
     118              :     void answerMediaChangeRequest(const std::vector<libjami::MediaMap>& mediaList, bool isRemote = false) override;
     119              :     void hangup(int code) override;
     120              :     void refuse() override;
     121              :     void transfer(const std::string& to) override;
     122              :     bool attendedTransfer(const std::string& to) override;
     123              :     bool hold(OnReadyCb&& cb) override;
     124              :     bool resume(OnReadyCb&& cb) override;
     125              :     void switchInput(const std::string& resource = {}) override;
     126              :     void peerHungup() override;
     127              :     void carryingDTMFdigits(char code) override;
     128              :     bool requestMediaChange(const std::vector<libjami::MediaMap>& mediaList) override;
     129              :     std::vector<libjami::MediaMap> currentMediaList() const override;
     130              :     void sendTextMessage(const std::map<std::string, std::string>& messages, const std::string& from) override;
     131              :     void removeCall(int code = 0) override;
     132              :     void muteMedia(const std::string& mediaType, bool isMuted) override;
     133              :     std::vector<MediaAttribute> getMediaAttributeList() const override;
     134              :     std::map<std::string, bool> getAudioStreams() const override;
     135              :     std::map<std::string, bool> getRemoteAudioStreams() const override;
     136              :     void restartMediaSender() override;
     137              :     std::shared_ptr<SystemCodecInfo> getAudioCodec() const override;
     138              :     std::shared_ptr<SystemCodecInfo> getVideoCodec() const override;
     139              :     void sendKeyframe(int streamIdx = -1) override;
     140              :     bool isIceEnabled() const override;
     141              :     std::map<std::string, std::string> getDetails() const override;
     142              :     void enterConference(std::shared_ptr<Conference> conference) override;
     143              :     void exitConference() override;
     144              : #ifdef ENABLE_VIDEO
     145              :     std::mutex sinksMtx_;
     146              :     void createSinks(ConfInfo& infos) override;
     147              :     std::map<std::string, std::shared_ptr<video::SinkClient>> callSinksMap_ {};
     148              :     std::map<std::string, std::string> local2RemoteSinks_ {};
     149              : #endif
     150              :     bool hasVideo() const override;
     151              : 
     152              :     // TODO: cleanup this (used by conference + Call::getDetails() (and clients can use this))
     153              :     bool isCaptureDeviceMuted(const MediaType& mediaType) const override;
     154         1948 :     bool isSrtpEnabled() const { return srtpEnabled_; }
     155              :     // End of override of Call class
     156              : 
     157              :     // Override of Recordable class
     158              :     bool toggleRecording() override;
     159              :     // End of override of Recordable class
     160              : 
     161              :     // Override PeerRecorder
     162              :     void peerRecording(bool state) override;
     163              :     void peerMuted(bool state, int streamIdx) override;
     164              :     void peerVoice(bool state) override;
     165              :     // end override PeerRecorder
     166              : 
     167              :     void monitor() const override;
     168              : 
     169              :     /**
     170              :      * Set peer's User-Agent found in the message header
     171              :      */
     172              :     void setPeerUaVersion(std::string_view ua);
     173              : 
     174              :     /**
     175              :      * Set peer's allowed methods
     176              :      */
     177              :     void setPeerAllowMethods(std::vector<std::string> methods);
     178              : 
     179              :     /**
     180              :      * Check if a SIP method is allowed by peer
     181              :      */
     182              :     bool isSipMethodAllowedByPeer(const std::string_view method) const;
     183              : 
     184              :     /**
     185              :      * Return the SDP's manager of this call
     186              :      */
     187          665 :     Sdp& getSDP() { return *sdp_; }
     188              : 
     189              :     // Implementation of events reported by SipVoipLink.
     190              :     /**
     191              :      * Call is in ringing state on peer's side
     192              :      */
     193              :     void onPeerRinging();
     194              :     /**
     195              :      * Peer answered the call
     196              :      */
     197              :     void onAnswered();
     198              :     /**
     199              :      * Called to report server/internal errors
     200              :      * @param code Optional SIP response code (see RFC3261)
     201              :      */
     202              :     void onFailure(int code = 0);
     203              :     /**
     204              :      * Peer answered busy
     205              :      */
     206              :     void onBusyHere();
     207              :     /**
     208              :      * Peer closed the connection
     209              :      */
     210              :     void onClosed();
     211              : 
     212              :     pj_status_t onReceiveReinvite(const pjmedia_sdp_session* offer, pjsip_rx_data* rdata);
     213              :     void onReceiveOfferIn200OK(const pjmedia_sdp_session* offer);
     214              : 
     215              :     /**
     216              :      * Called when the media negotiation (SDP offer/answer) has
     217              :      * completed.
     218              :      */
     219              :     void onMediaNegotiationComplete();
     220              :     // End fo SiPVoipLink events
     221              : 
     222              :     const std::string& getContactHeader() const;
     223              : 
     224              :     void setSipTransport(const std::shared_ptr<SipTransport>& transport, const std::string& contactHdr = {});
     225              : 
     226          568 :     SipTransport* getTransport() { return sipTransport_.get(); }
     227              : 
     228              :     void sendSIPInfo(std::string_view body, std::string_view subtype);
     229              : 
     230              :     void requestKeyframe(int streamIdx = -1);
     231              : 
     232              :     void updateRecState(bool state) override;
     233              : 
     234              :     std::shared_ptr<SIPAccountBase> getSIPAccount() const;
     235              : 
     236              :     bool remoteHasValidIceAttributes() const;
     237              :     void addLocalIceAttributes();
     238              : 
     239         1991 :     std::shared_ptr<dhtnet::IceTransport> getIceMedia() const
     240              :     {
     241         1991 :         std::lock_guard lk(transportMtx_);
     242         3982 :         return reinvIceMedia_ ? reinvIceMedia_ : iceMedia_;
     243         1991 :     };
     244              : 
     245              :     // Set ICE instance. Must be called only for sub-calls
     246              :     void setIceMedia(std::shared_ptr<dhtnet::IceTransport> ice, bool isReinvite = false);
     247              : 
     248              :     // Switch to re-invite ICE media if needed
     249              :     void switchToIceReinviteIfNeeded();
     250              : 
     251              :     /**
     252              :      * Setup ICE locally to answer to an ICE offer. The ICE session has
     253              :      * the controlled role (slave)
     254              :      */
     255              :     void setupIceResponse(bool isReinvite = false);
     256              : 
     257              :     void terminateSipSession(int status);
     258              : 
     259              :     /**
     260              :      * The invite session to be reused in case of transfer
     261              :      */
     262              :     struct InvSessionDeleter
     263              :     {
     264              :         void operator()(pjsip_inv_session*) const noexcept;
     265              :     };
     266              : 
     267              : #ifdef ENABLE_VIDEO
     268              :     void setRotation(int streamIdx, int rotation);
     269              : #endif
     270              :     // Get the list of current RTP sessions
     271              :     std::vector<std::shared_ptr<RtpSession>> getRtpSessionList(MediaType type = MediaType::MEDIA_ALL) const;
     272              :     static size_t getActiveMediaStreamCount(const std::vector<MediaAttribute>& mediaAttrList);
     273              :     void setActiveMediaStream(const std::string& accountUri,
     274              :                               const std::string& deviceId,
     275              :                               const std::string& streamId,
     276              :                               const bool& state);
     277              : 
     278            1 :     void setPeerRegisteredName(const std::string& name) { peerRegisteredName_ = name; }
     279              : 
     280          307 :     void setPeerUri(const std::string& peerUri) { peerUri_ = peerUri; }
     281              : 
     282           68 :     std::string_view peerUri() const { return peerUri_; }
     283              : 
     284              :     // Create a new ICE media session. If we already have an instance,
     285              :     // it will be destroyed first.
     286              :     bool createIceMediaTransport(bool isReinvite);
     287              : 
     288              :     // Initialize the ICE session.
     289              :     // The initialization is performed asynchronously, i.e, the instance
     290              :     // may not be ready to use when this method returns.
     291              :     bool initIceMediaTransport(bool master, std::optional<dhtnet::IceTransportOptions> options = std::nullopt);
     292              : 
     293              :     std::vector<std::string> getLocalIceCandidates(unsigned compId) const;
     294              : 
     295              :     void setInviteSession(pjsip_inv_session* inviteSession = nullptr);
     296              : 
     297              :     std::unique_ptr<pjsip_inv_session, InvSessionDeleter> inviteSession_;
     298              : 
     299              :     inline std::weak_ptr<const SIPCall> weak() const { return std::weak_ptr<const SIPCall>(shared()); }
     300         2841 :     inline std::weak_ptr<SIPCall> weak() { return std::weak_ptr<SIPCall>(shared()); }
     301              :     /**
     302              :      * Announce to the client that medias are successfully negotiated
     303              :      */
     304              :     void reportMediaNegotiationStatus();
     305              : 
     306              :     const std::vector<RtpStream>& getRtpStreams() const { return rtpStreams_; }
     307              : 
     308              : private:
     309              :     void generateMediaPorts();
     310              : 
     311              :     void openPortsUPnP();
     312              : 
     313              :     bool isIceRunning() const;
     314              : 
     315              :     std::unique_ptr<dhtnet::IceSocket> newIceSocket(unsigned compId);
     316              : 
     317              :     void deinitRecorder();
     318              : 
     319              :     void rtpSetupSuccess();
     320              : 
     321              :     void setupVoiceCallback(const std::shared_ptr<RtpSession>& rtpSession);
     322              : 
     323              :     void sendMuteState(bool state);
     324              :     void sendVoiceActivity(std::string_view streamId, bool state);
     325              : 
     326              :     void resetTransport(std::shared_ptr<dhtnet::IceTransport>&& transport);
     327              : 
     328              :     /**
     329              :      * Send device orientation through SIP INFO
     330              :      * @param streamIdx  The stream to rotate
     331              :      * @param rotation   Device orientation (0/90/180/270) (counterclockwise)
     332              :      */
     333              :     void setVideoOrientation(int streamIdx, int rotation);
     334              : 
     335              :     mutable std::mutex transportMtx_ {};
     336              : 
     337              : #ifdef ENABLE_PLUGIN
     338              :     /**
     339              :      * Call Streams and some typedefs
     340              :      */
     341              :     using AVMediaStream = Observable<std::shared_ptr<MediaFrame>>;
     342              :     using MediaStreamSubject = PublishMapSubject<std::shared_ptr<MediaFrame>, AVFrame*>;
     343              : 
     344              :     /**
     345              :      * @brief createCallAVStream
     346              :      * Creates a call AV stream like video input, video receive, audio input or audio receive
     347              :      * @param StreamData The type of the stream (audio/video, input/output,
     348              :      * @param streamSource
     349              :      * @param mediaStreamSubject
     350              :      */
     351              :     void createCallAVStream(const StreamData& StreamData,
     352              :                             AVMediaStream& streamSource,
     353              :                             const std::shared_ptr<MediaStreamSubject>& mediaStreamSubject);
     354              :     /**
     355              :      * @brief createCallAVStreams
     356              :      * Creates all Call AV Streams (2 if audio, 4 if audio video)
     357              :      */
     358              :     void createCallAVStreams();
     359              : 
     360              :     /**
     361              :      * @brief Detach all plugins from call streams;
     362              :      */
     363              :     void clearCallAVStreams();
     364              : 
     365              :     std::mutex avStreamsMtx_ {};
     366              :     std::map<std::string, std::shared_ptr<MediaStreamSubject>> callAVStreams;
     367              : #endif // ENABLE_PLUGIN
     368              : 
     369              :     void setCallMediaLocal();
     370              :     void startIceMedia();
     371              :     void onIceNegoSucceed();
     372              :     void setupNegotiatedMedia();
     373              :     void startAllMedia();
     374              :     void stopAllMedia();
     375              : 
     376              :     /**
     377              :      * Transfer method used for both type of transfer
     378              :      */
     379              :     bool transferCommon(const pj_str_t* dst);
     380              : 
     381              :     bool internalResume(const std::function<void()>& SDPUpdateFunc);
     382              : 
     383              :     bool hold();
     384              : 
     385              :     bool resume();
     386              : 
     387              :     // Update the attributes of a media stream
     388              :     void updateMediaStream(const MediaAttribute& newMediaAttr, size_t streamIdx);
     389              :     bool updateAllMediaStreams(const std::vector<MediaAttribute>& mediaAttrList, bool isRemote);
     390              :     // Check if a SIP re-invite must be sent to negotiate the new media
     391              :     bool isReinviteRequired(const std::vector<MediaAttribute>& mediaAttrList);
     392              :     // Check if a new ICE media session is needed when performing a re-invite
     393              :     bool isNewIceMediaRequired(const std::vector<MediaAttribute>& mediaAttrList);
     394              :     void requestReinvite(const std::vector<MediaAttribute>& mediaAttrList, bool needNewIce);
     395              :     int SIPSessionReinvite(const std::vector<MediaAttribute>& mediaAttrList, bool needNewIce);
     396              :     int SIPSessionReinvite();
     397              :     // Add a media stream to the call.
     398              :     void addMediaStream(const MediaAttribute& mediaAttr);
     399              :     // Init media streams
     400              :     size_t initMediaStreams(const std::vector<MediaAttribute>& mediaAttrList);
     401              :     // Create a new stream from SDP description.
     402              :     void createRtpSession(RtpStream& rtpStream);
     403              :     // Configure the RTP session from SDP description.
     404              :     void configureRtpSession(const std::shared_ptr<RtpSession>& rtpSession,
     405              :                              const std::shared_ptr<MediaAttribute>& mediaAttr,
     406              :                              const MediaDescription& localMedia,
     407              :                              const MediaDescription& remoteMedia);
     408              :     // Find the stream index with the matching label
     409              :     int findRtpStreamIndex(const std::string& label) const;
     410              : 
     411              :     std::vector<IceCandidate> getAllRemoteCandidates(dhtnet::IceTransport& transport) const;
     412              : 
     413              :     inline std::shared_ptr<const SIPCall> shared() const
     414              :     {
     415              :         return std::static_pointer_cast<const SIPCall>(shared_from_this());
     416              :     }
     417         2841 :     inline std::shared_ptr<SIPCall> shared() { return std::static_pointer_cast<SIPCall>(shared_from_this()); }
     418              : 
     419              :     // Peer's User-Agent.
     420              :     std::string peerUserAgent_ {};
     421              :     // Flag to indicate if the peer's Daemon version supports multi-stream.
     422              :     bool peerSupportMultiStream_ {false};
     423              :     // Flag to indicate if the peer's Daemon version supports multi-stream.
     424              :     bool peerSupportMultiAudioStream_ {false};
     425              :     // Flag to indicate if the peer's Daemon version can negotiate more than 2 ICE medias
     426              :     bool peerSupportMultiIce_ {false};
     427              : 
     428              :     // Flag to indicate if the peer's Daemon version supports re-invite
     429              :     // without ICE renegotiation.
     430              :     bool peerSupportReuseIceInReinv_ {false};
     431              : 
     432              :     // Peer's allowed methods.
     433              :     std::vector<std::string> peerAllowedMethods_;
     434              : 
     435              :     // Vector holding the current RTP sessions.
     436              :     std::vector<RtpStream> rtpStreams_;
     437              : 
     438              :     /**
     439              :      * Hold the transport used for SIP communication.
     440              :      * Will be different from the account registration transport for
     441              :      * non-IP2IP calls.
     442              :      */
     443              :     std::shared_ptr<SipTransport> sipTransport_ {};
     444              : 
     445              :     /**
     446              :      * The SDP session
     447              :      */
     448              :     std::unique_ptr<Sdp> sdp_ {};
     449              :     bool peerHold_ {false};
     450              : 
     451              :     bool isWaitingForIceAndMedia_ {false};
     452              :     enum class Request : uint8_t { Hold, Resume, SwitchInput, NoRequest };
     453              :     Request remainingRequest_ {Request::NoRequest};
     454              : 
     455              :     std::string peerRegisteredName_ {};
     456              : 
     457              :     std::string contactHeader_ {};
     458              : 
     459              :     std::shared_ptr<dhtnet::upnp::Controller> upnp_;
     460              : 
     461              :     /** Local audio port, as seen by me. */
     462              :     unsigned int localAudioPort_ {0};
     463              :     /** Local video port, as seen by me. */
     464              :     unsigned int localVideoPort_ {0};
     465              : 
     466              :     bool mediaRestartRequired_ {true};
     467              :     bool enableIce_ {true};
     468              :     bool srtpEnabled_ {false};
     469              :     bool rtcpMuxEnabled_ {false};
     470              : 
     471              :     // ICE media transport
     472              :     std::shared_ptr<dhtnet::IceTransport> iceMedia_;
     473              :     // Re-invite (temporary) ICE media transport.
     474              :     std::shared_ptr<dhtnet::IceTransport> reinvIceMedia_;
     475              : 
     476              :     std::string peerUri_ {};
     477              : 
     478              :     bool readyToRecord_ {false};
     479              :     bool pendingRecord_ {false};
     480              : 
     481              :     time_point lastKeyFrameReq_ {time_point::min()};
     482              : 
     483              :     OnReadyCb holdCb_ {};
     484              :     OnReadyCb resumeCb_ {};
     485              : 
     486              :     std::atomic_bool waitForIceInit_ {false};
     487              : 
     488              :     void detachAudioFromConference();
     489              : 
     490              :     std::mutex mediaStateMutex_;
     491              : #ifdef ENABLE_VIDEO
     492              :     int rotation_ {0};
     493              : #endif
     494              : 
     495              :     std::string mediaPlayerId_ {};
     496              : };
     497              : 
     498              : // Helpers
     499              : 
     500              : /**
     501              :  * Obtain a shared smart pointer of instance
     502              :  */
     503              : inline std::shared_ptr<SIPCall>
     504              : getPtr(SIPCall& call)
     505              : {
     506              :     return std::static_pointer_cast<SIPCall>(call.shared_from_this());
     507              : }
     508              : 
     509              : } // namespace jami
        

Generated by: LCOV version 2.0-1