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