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
|