call.h 11.9 KB
Newer Older
yanmorin's avatar
yanmorin committed
1
/*
2
 *  Copyright (C) 2004-2019 Savoir-faire Linux Inc.
3
 *
4
 *  Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
jpbl's avatar
jpbl committed
5
 *  Author: Yan Morin <yan.morin@savoirfairelinux.com>
6 7
 *  Author: Laurielle Lea <laurielle.lea@savoirfairelinux.com>
 *  Author: Guillaume Roguez <guillaume.roguez@savoirfairelinux.com>
yanmorin's avatar
yanmorin committed
8
 *
jpbl's avatar
jpbl committed
9 10
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
11
 *  the Free Software Foundation; either version 3 of the License, or
jpbl's avatar
jpbl committed
12
 *  (at your option) any later version.
yanmorin's avatar
yanmorin committed
13
 *
jpbl's avatar
jpbl committed
14 15 16 17
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
yanmorin's avatar
yanmorin committed
18
 *
jpbl's avatar
jpbl committed
19 20
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
21
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
jpbl's avatar
jpbl committed
22
 */
23

24
#pragma once
jpbl's avatar
jpbl committed
25

26 27 28 29
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

30 31
#include "logger.h"

32
#include "recordable.h"
33
#include "ip_utils.h"
34 35 36 37

#include <mutex>
#include <map>
#include <sstream>
38 39
#include <memory>
#include <vector>
40
#include <condition_variable>
41
#include <set>
42
#include <list>
Guillaume Roguez's avatar
Guillaume Roguez committed
43
#include <functional>
yanmorin's avatar
yanmorin committed
44

Adrien Béraud's avatar
Adrien Béraud committed
45
namespace jami {
46

47
class VoIPLink;
48
class Account;
49
struct AccountVideoCodecInfo;
50

51 52
template <class T> using CallMap = std::map<std::string, std::shared_ptr<T> >;

Julien Bonjean's avatar
Julien Bonjean committed
53 54
/*
 * @file call.h
55 56 57
 * @brief A call is the base class for protocol-based calls
 */

58
class Call : public Recordable, public std::enable_shared_from_this<Call> {
59
    public:
60 61
        using SubcallSet = std::set<std::shared_ptr<Call>, std::owner_less<std::shared_ptr<Call>>>;

62
        static const char * const DEFAULT_ID;
63 64

        /**
65 66
         * This determines if the call originated from the local user (OUTGOING)
         * or from some remote peer (INCOMING, MISSED).
67
         */
68
        enum class CallType : unsigned {INCOMING, OUTGOING, MISSED};
69 70 71 72

        /**
         * Tell where we're at with the call. The call gets Connected when we know
         * from the other end what happened with out call. A call can be 'Connected'
73
         * even if the call state is Busy, or Error.
74 75 76
         *
         * Audio should be transmitted when ConnectionState = Connected AND
         * CallState = Active.
77 78
         *
         * \note modify validStateTransition/getStateStr if this enum changes
79
         */
80 81 82
        enum class ConnectionState : unsigned {
            DISCONNECTED, TRYING, PROGRESSING, RINGING, CONNECTED, COUNT__
        };
83 84 85

        /**
         * The Call State.
86 87
         *
         * \note modify validStateTransition/getStateStr if this enum changes
88
         */
89
        enum class CallState : unsigned {
90
            INACTIVE, ACTIVE, HOLD, BUSY, PEER_BUSY, MERROR, OVER, COUNT__
91
        };
92 93 94

        virtual ~Call();

95
        /**
96
         * Return a reference on the call id
97 98
         * @return call id
         */
99
        const std::string& getCallId() const {
100
            return id_;
Julien Bonjean's avatar
Julien Bonjean committed
101
        }
102

Julien Bonjean's avatar
Julien Bonjean committed
103
        /**
104 105 106
         * Return a reference on the conference id
         * @return call id
         */
107
        const std::string& getConfId() const {
108
            return confID_;
Julien Bonjean's avatar
Julien Bonjean committed
109
        }
110

111
        void setConfId(const std::string &id) {
112
            confID_ = id;
Julien Bonjean's avatar
Julien Bonjean committed
113
        }
114

115
        Account& getAccount() const { return account_; }
116
        const std::string& getAccountId() const;
117

118 119
        CallType getCallType() const {
            return type_;
120 121
        }

122 123
        virtual const char* getLinkType() const = 0;

Julien Bonjean's avatar
Julien Bonjean committed
124
        /**
125 126 127 128
         * Set the peer number (destination on outgoing)
         * not protected by mutex (when created)
         * @param number peer number
         */
129
        void setPeerNumber(const std::string& number) {
130
            peerNumber_ = number;
Julien Bonjean's avatar
Julien Bonjean committed
131
        }
132

Julien Bonjean's avatar
Julien Bonjean committed
133
        /**
134 135 136 137
         * Get the peer number (destination on outgoing)
         * not protected by mutex (when created)
         * @return std::string The peer number
         */
138 139
        std::string getPeerNumber() const {
            return peerNumber_;
Julien Bonjean's avatar
Julien Bonjean committed
140
        }
141

Julien Bonjean's avatar
Julien Bonjean committed
142
        /**
143 144 145 146
         * Set the display name (caller in ingoing)
         * not protected by mutex (when created)
         * @return std::string The peer display name
         */
147 148
        void setPeerDisplayName(const std::string& name) {
            peerDisplayName_ = name;
Julien Bonjean's avatar
Julien Bonjean committed
149
        }
150

Julien Bonjean's avatar
Julien Bonjean committed
151
        /**
152 153 154 155
         * Get the peer display name (caller in ingoing)
         * not protected by mutex (when created)
         * @return std::string The peer name
         */
156 157
        const std::string& getPeerDisplayName() const {
            return peerDisplayName_;
Julien Bonjean's avatar
Julien Bonjean committed
158
        }
159

160 161
        /**
         * Tell if the call is incoming
162
         * @return true if yes false otherwise
163
         */
164
        bool isIncoming() const {
165
            return type_ == CallType::INCOMING;
Julien Bonjean's avatar
Julien Bonjean committed
166
        }
167 168 169

        /**
         * Set the state of the call (protected by mutex)
170 171 172
         * @param call_state The call state
         * @param cnx_state The call connection state
         * @param code Optionnal state dependent error code (used to report more information)
173
         * @return true if the requested state change was valid, false otherwise
174
         */
175 176 177
        bool setState(CallState call_state, signed code=0);
        bool setState(CallState call_state, ConnectionState cnx_state, signed code=0);
        bool setState(ConnectionState cnx_state, signed code=0);
178

Julien Bonjean's avatar
Julien Bonjean committed
179
        /**
180 181 182
         * Get the call state of the call (protected by mutex)
         * @return CallState  The call state
         */
183
        CallState getState() const;
Julien Bonjean's avatar
Julien Bonjean committed
184

185 186 187 188 189 190
        /**
         * Get the connection state of the call (protected by mutex)
         * @return ConnectionState The connection state
         */
        ConnectionState getConnectionState() const;

191
        std::string getStateStr() const;
192

193 194
        void setIPToIP(bool IPToIP) {
            isIPToIP_ = IPToIP;
Julien Bonjean's avatar
Julien Bonjean committed
195 196
        }

197
        virtual std::map<std::string, std::string> getDetails() const;
198
        static std::map<std::string, std::string> getNullDetails();
199

200 201 202 203 204
        /**
         * Answer the call
         */
        virtual void answer() = 0;

205 206 207 208 209 210
        /**
         * Hang up the call
         * @param reason
         */
        virtual void hangup(int reason) = 0;

211 212 213 214 215
        /**
         * Refuse incoming call
         */
        virtual void refuse() = 0;

216 217 218 219 220 221 222 223 224 225 226 227 228
        /**
         * Transfer a call to specified URI
         * @param to The recipient of the call
         */
        virtual void transfer(const std::string &to) = 0;

        /**
         * Attended transfer
         * @param The target call id
         * @return True on success
         */
        virtual bool attendedTransfer(const std::string& to) = 0;

229 230 231 232
        /**
         * Put a call on hold
         * @return bool True on success
         */
233
        virtual bool onhold() = 0;
234 235 236 237 238

        /**
         * Resume a call from hold state
         * @return bool True on success
         */
239
        virtual bool offhold() = 0;
240

241 242
        virtual void sendKeyframe() = 0;

243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262
        /**
         * Peer has hung up a call
         */
        virtual void peerHungup();

        virtual void removeCall();

        using StateListener = std::function<void(CallState, int)>;

        template<class T>
        void addStateListener(T&& list) {
            stateChangedListeners_.emplace_back(std::forward<T>(list));
        }

        /**
         * Attach subcall to this instance.
         * If this subcall is answered, this subcall and this instance will be merged using merge().
         */
        void addSubCall(Call& call);

263 264 265 266
        ///
        /// Return true if this call instance is a subcall (internal call for multi-device handling)
        ///
        bool isSubcall() const {
267 268
            std::lock_guard<std::recursive_mutex> lk {callMutex_};
            return parent_ != nullptr;
269 270
        }

271 272 273 274 275
    public: // media management
        virtual bool toggleRecording();

        virtual void switchInput(const std::string&) {};

276 277 278 279 280 281 282
        /**
         * mute/unmute a media of a call
         * @param mediaType type of media
         * @param isMuted true for muting, false for unmuting
         */
        virtual void muteMedia(const std::string& mediaType, bool isMuted)  = 0;

283 284 285 286 287 288
        /**
         * Send DTMF
         * @param code  The char code
         */
        virtual void carryingDTMFdigits(char code) = 0;

289 290 291
        /**
         * Send a message to a call identified by its callid
         *
292
         * @param A list of mimetype/payload pairs
293 294
         * @param The sender of this message (could be another participant of a conference)
         */
295
        virtual void sendTextMessage(const std::map<std::string, std::string>& messages,
296 297
                                     const std::string &from) = 0;

298

299
        void onTextMessage(std::map<std::string, std::string>&& messages);
300

301 302 303 304 305
        virtual std::shared_ptr<AccountCodecInfo> getAudioCodec() const {
            return {};
        }
        virtual std::shared_ptr<AccountCodecInfo> getVideoCodec() const {
            return {};
306 307
        }

308
        virtual void restartMediaSender() = 0;
309

310 311 312 313
        /**
         * Update call details after creation.
         * @param details to update
         *
314
         * \note No warranty to update any details, only some details can be modified.
315 316 317 318
         *       See the implementation for more ... details :-).
         */
        void updateDetails(const std::map<std::string, std::string>& details);

319
    protected:
320 321
        virtual void merge(Call& scall);

322 323 324 325
        /**
         * Constructor of a call
         * @param id Unique identifier of the call
         * @param type set definitely this call as incoming/outgoing
326
         * @param details volatile details to customize the call creation
327
         */
328 329
        Call(Account& account, const std::string& id, Call::CallType type,
             const std::map<std::string, std::string>& details = {});
330

331 332
        // TODO all these members are not protected against multi-thread access

333 334
        bool isAudioMuted_{false};
        bool isVideoMuted_{false};
335

336 337
        ///< MultiDevice: parent call, nullptr otherwise. Access protected by callMutex_.
        mutable std::shared_ptr<Call> parent_;
338 339 340 341 342 343 344 345

        ///< MultiDevice: list of attached subcall
        SubcallSet subcalls_;

        using MsgList = std::list<std::pair<std::map<std::string, std::string>, std::string>>;

        ///< MultiDevice: message waiting to be sent (need a valid subcall)
        MsgList pendingOutMessages_;
346

347 348 349
        /** Protect every attribute that can be changed by two threads */
        mutable std::recursive_mutex callMutex_ {};

350
    private:
351
        bool validStateTransition(CallState newState);
352

353 354
        void checkPendingIM();

355 356
        void checkAudio();

357 358 359 360
        void subcallStateChanged(Call&, Call::CallState, Call::ConnectionState);

        SubcallSet safePopSubcalls();

361 362
        std::vector<std::function<void(CallState, ConnectionState, int)>> stateChangedListeners_ {};

363
        /** Unique ID of the call */
364
        std::string id_;
365

Julien Bonjean's avatar
Julien Bonjean committed
366
        /** Unique conference ID, used exclusively in case of a conferece */
367
        std::string confID_ {};
368

369
        /** Type of the call */
370
        CallType type_;
371

372
        /** Associate account ID */
373
        Account& account_;
374

375
        /** Disconnected/Progressing/Trying/Ringing/Connected */
376
        ConnectionState connectionState_ {ConnectionState::DISCONNECTED};
377

378
        /** Inactive/Active/Hold/Busy/Error */
379
        CallState callState_ {CallState::INACTIVE};
380 381

        /** Direct IP-to-IP or classic call */
382
        bool isIPToIP_ {false};
383 384

        /** Number of the peer */
385
        std::string peerNumber_ {};
386

387 388
        /** Peer Display Name */
        std::string peerDisplayName_ {};
389

390
        time_t timestamp_start_ {0};
391 392 393

        ///< MultiDevice: message received by subcall to merged yet
        MsgList pendingInMessages_;
jpbl's avatar
jpbl committed
394 395
};

396 397 398 399 400 401 402 403 404 405
// Helpers

/**
 * Obtain a shared smart pointer of instance
 */
inline std::shared_ptr<Call> getPtr(Call& call)
{
    return call.shared_from_this();
}

Adrien Béraud's avatar
Adrien Béraud committed
406
} // namespace jami