sipvoiplink.cpp 112 KB
Newer Older
jpbl's avatar
jpbl committed
1
/*
2
 *  Copyright (C) 2004, 2005, 2006, 2008, 2009, 2010 Savoir-Faire Linux Inc.
3
4
 *
 *  Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
5
 *  Author: Yun Liu <yun.liu@savoirfairelinux.com>
6
 *  Author: Pierre-Luc Bacon <pierre-luc.bacon@savoirfairelinux.com>
7
 *  Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com>
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
13
14
15
16
17
18
19
20
21
 *  (at your option) any later version.
 *
 *  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.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22
23
24
25
26
27
28
29
30
31
32
 *
 *  Additional permission under GNU GPL version 3 section 7:
 *
 *  If you modify this program, or any covered work, by linking or
 *  combining it with the OpenSSL project's OpenSSL library (or a
 *  modified version of that library), containing parts covered by the
 *  terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
 *  grants you additional permission to convey the resulting work.
 *  Corresponding Source for a non-source form of such a combination
 *  shall include the source code for the parts of OpenSSL used as well
 *  as that of the covered work.
jpbl's avatar
jpbl committed
33
 */
Emmanuel Milou's avatar
Emmanuel Milou committed
34

35
36
37
38
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

jpbl's avatar
jpbl committed
39
#include "sipvoiplink.h"
40
41
42

#include "manager.h"

43
#include "sip/sdp.h"
yanmorin's avatar
   
yanmorin committed
44
#include "sipcall.h"
Emmanuel Milou's avatar
nothing    
Emmanuel Milou committed
45
#include "sipaccount.h"
46
#include "eventthread.h"
47
#include "SdesNegotiator.h"
48
49
50

#include "dbus/dbusmanager.h"
#include "dbus/callmanager.h"
51

52
#include "hooks/urlhook.h"
53
54
#include "im/InstantMessaging.h"

55
#include "audio/audiolayer.h"
56
#include "audio/audiortp/AudioRtpFactory.h"
57

58
#include "pjsip/sip_endpoint.h"
59
#include "pjsip/sip_transport_tls.h"
60
61
62
#include "pjsip/sip_transport_tls.h"
#include "pjsip/sip_uri.h"
#include <pjnath.h>
63

Emmanuel Milou's avatar
Emmanuel Milou committed
64
65
66
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <resolv.h>
67
#include <istream>
68
#include <utility> // for std::pair
Emmanuel Milou's avatar
Emmanuel Milou committed
69

70
71
72
73
74
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/if.h>

75
76
#include <map>

77
78
using namespace sfl;

79
80
namespace {
static const char * const invitationStateMap[] = {
81
82
83
84
85
86
87
    "PJSIP_INV_STATE_NULL",
    "PJSIP_INV_STATE_CALLING",
    "PJSIP_INV_STATE_INCOMING",
    "PJSIP_INV_STATE_EARLY",
    "PJSIP_INV_STATE_CONNECTING",
    "PJSIP_INV_STATE_CONFIRMED",
    "PJSIP_INV_STATE_DISCONNECTED"
pierre-luc's avatar
pierre-luc committed
88
};
Emmanuel Milou's avatar
Emmanuel Milou committed
89

90
static const char * const transactionStateMap[] = {
91
92
93
94
95
96
97
98
99
    "PJSIP_TSX_STATE_NULL" ,
    "PJSIP_TSX_STATE_CALLING",
    "PJSIP_TSX_STATE_TRYING",
    "PJSIP_TSX_STATE_PROCEEDING",
    "PJSIP_TSX_STATE_COMPLETED",
    "PJSIP_TSX_STATE_CONFIRMED",
    "PJSIP_TSX_STATE_TERMINATED",
    "PJSIP_TSX_STATE_DESTROYED",
    "PJSIP_TSX_STATE_MAX"
pierre-luc's avatar
pierre-luc committed
100
101
};

Emmanuel Milou's avatar
Emmanuel Milou committed
102
struct result {
103
104
105
    pj_status_t             status;
    pjsip_server_addresses  servers;
};
Alexandre Savard's avatar
Alexandre Savard committed
106

107
/** The default transport (5060) */
108
pjsip_transport *_localUDPTransport = NULL;
109
110

/** The local tls listener */
111
pjsip_tpfactory *_localTlsListener = NULL;
112

113
114
/** A map to retreive SFLphone internal call id
 *  Given a SIP call ID (usefull for transaction sucha as transfer)*/
115
std::map<std::string, std::string> transferCallID;
116

117
const pj_str_t STR_USER_AGENT = { (char*) "User-Agent", 10 };
118

Emmanuel Milou's avatar
Emmanuel Milou committed
119
/**************** EXTERN VARIABLES AND FUNCTIONS (callbacks) **************************/
jpbl's avatar
jpbl committed
120

121
122
123
124
125
126
/*
 * Retrieve the SDP of the peer contained in the offer
 *
 * @param rdata The request data
 * @param r_sdp The pjmedia_sdp_media to stock the remote SDP
 */
127
128
int getModId();

129
/**
130
131
132
133
 * Set audio (SDP) configuration for a call
 * localport, localip, localexternalport
 * @param call a SIPCall valid pointer
 */
Rafaël Carré's avatar
Rafaël Carré committed
134
void setCallMediaLocal (SIPCall* call, const std::string &localIP);
135

136
137
138
139
/**
 * Helper function to parser header from incoming sip messages
 */
std::string fetchHeaderValue (pjsip_msg *msg, std::string field);
140

Emmanuel Milou's avatar
Emmanuel Milou committed
141
142
143
/*
 *  The global pool factory
 */
144
pj_caching_pool pool_cache, *_cp = &pool_cache;
Emmanuel Milou's avatar
Emmanuel Milou committed
145
146
147
148

/*
 * The pool to allocate memory
 */
149
pj_pool_t *_pool;
Emmanuel Milou's avatar
Emmanuel Milou committed
150
151
152
153

/*
 *	The SIP endpoint
 */
154
pjsip_endpoint *_endpt;
Emmanuel Milou's avatar
Emmanuel Milou committed
155
156
157
158

/*
 *	The SIP module
 */
159
pjsip_module _mod_ua;
Emmanuel Milou's avatar
Emmanuel Milou committed
160
161
162
163

/*
 * Thread related
 */
164
165
166
pj_thread_t *thread;
pj_thread_desc desc;

Emmanuel Milou's avatar
Emmanuel Milou committed
167
168
169
/**
 * Get the number of voicemail waiting in a SIP message
 */
170
void setVoicemailInfo (const std::string &account, pjsip_msg_body *body);
171

Emmanuel Milou's avatar
Emmanuel Milou committed
172
173
/*
 * Session callback
174
 * Called after SDP offer/answer session has completed.
Emmanuel Milou's avatar
Emmanuel Milou committed
175
176
 *
 * @param	inv	A pointer on a pjsip_inv_session structure
177
 * @param	status	A pj_status_t structure
Emmanuel Milou's avatar
Emmanuel Milou committed
178
 */
179
180
181
182
183
184
void sdp_media_update_cb (pjsip_inv_session *inv, pj_status_t status UNUSED);


void sdp_request_offer_cb (pjsip_inv_session *inv, const pjmedia_sdp_session *offer);

void sdp_create_offer_cb (pjsip_inv_session *inv, pjmedia_sdp_session **p_offer);
Emmanuel Milou's avatar
Emmanuel Milou committed
185
186
187

/*
 * Session callback
188
 * Called when the invite session state has changed.
Emmanuel Milou's avatar
Emmanuel Milou committed
189
190
 *
 * @param	inv	A pointer on a pjsip_inv_session structure
191
 * @param	e	A pointer on a pjsip_event structure
Emmanuel Milou's avatar
Emmanuel Milou committed
192
 */
193
void invite_session_state_changed_cb (pjsip_inv_session *inv, pjsip_event *e);
Emmanuel Milou's avatar
Emmanuel Milou committed
194
195

/*
196
 * Called when the invite usage module has created a new dialog and invite
Emmanuel Milou's avatar
Emmanuel Milou committed
197
198
199
200
201
 * because of forked outgoing request.
 *
 * @param	inv	A pointer on a pjsip_inv_session structure
 * @param	e	A pointer on a pjsip_event structure
 */
202
void outgoing_request_forked_cb (pjsip_inv_session *inv, pjsip_event *e);
Emmanuel Milou's avatar
Emmanuel Milou committed
203
204
205
206
207
208
209
210
211
212

/*
 * Session callback
 * Called whenever any transactions within the session has changed their state.
 * Useful to monitor the progress of an outgoing request.
 *
 * @param	inv	A pointer on a pjsip_inv_session structure
 * @param	tsx	A pointer on a pjsip_transaction structure
 * @param	e	A pointer on a pjsip_event structure
 */
213
void transaction_state_changed_cb (pjsip_inv_session *inv, pjsip_transaction *tsx, pjsip_event *e);
Emmanuel Milou's avatar
Emmanuel Milou committed
214

Alexandre Savard's avatar
Alexandre Savard committed
215

Emmanuel Milou's avatar
Emmanuel Milou committed
216
217
218
/*
 * Registration callback
 */
219
void registration_cb (struct pjsip_regc_cbparam *param);
Emmanuel Milou's avatar
Emmanuel Milou committed
220

221
222
223
/*
 * DNS Callback used in workaround for bug #1852
 */
Emmanuel Milou's avatar
Emmanuel Milou committed
224
static void dns_cb (pj_status_t status, void *token, const struct pjsip_server_addresses *addr);
225

Emmanuel Milou's avatar
Emmanuel Milou committed
226
227
228
229
230
/*
 * Called to handle incoming requests outside dialogs
 * @param   rdata
 * @return  pj_bool_t
 */
231
pj_bool_t transaction_request_cb (pjsip_rx_data *rdata);
Emmanuel Milou's avatar
Emmanuel Milou committed
232
233
234
235
236
237

/*
 * Called to handle incoming response
 * @param	rdata
 * @return	pj_bool_t
 */
238
pj_bool_t transaction_response_cb (pjsip_rx_data *rdata UNUSED) ;
Emmanuel Milou's avatar
Emmanuel Milou committed
239

240
241
242
243
244
245
246
/**
 * Send a reINVITE inside an active dialog to modify its state
 * Local SDP session should be modified before calling this method
 * @param sip call
 */
int SIPSessionReinvite(SIPCall *);

Emmanuel Milou's avatar
Emmanuel Milou committed
247
248
249
/*
 * Transfer callbacks
 */
250
void transfer_client_cb (pjsip_evsub *sub, pjsip_event *event);
251
252
253
254
255
void transfer_server_cb (pjsip_evsub *sub, pjsip_event *event);

/**
 * Helper function to process refer function on call transfer
 */
256
void onCallTransfered (pjsip_inv_session *inv, pjsip_rx_data *rdata);
Emmanuel Milou's avatar
Emmanuel Milou committed
257

258
259
260
261
262
263
264
std::string loadSIPLocalIP()
{
    pj_sockaddr ip_addr;
    if (pj_gethostip (pj_AF_INET(), &ip_addr) == PJ_SUCCESS)
        return pj_inet_ntoa (ip_addr.ipv4.sin_addr);
    return "";
}
265
266
} // end anonymous namespace

Emmanuel Milou's avatar
Emmanuel Milou committed
267
268
/*************************************************************************************************/

269
SIPVoIPLink* SIPVoIPLink::instance_ = NULL;
Emmanuel Milou's avatar
Emmanuel Milou committed
270

271

272
273
SIPVoIPLink::SIPVoIPLink() :
    evThread_(new EventThread(this))
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
274
{
275
    srand (time (NULL));    // to get random number for RANDOM_PORT
Alexandre Savard's avatar
Alexandre Savard committed
276

277
278
    /* Initialize the pjsip library */
    pjsipInit();
yanmorin's avatar
   
yanmorin committed
279
}
jpbl's avatar
jpbl committed
280

Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
281
282
SIPVoIPLink::~SIPVoIPLink()
{
283
	delete evThread_;
284
	pjsipShutdown();
285
286
}

287
SIPVoIPLink* SIPVoIPLink::instance ()
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
288
{
289
290
    if (!instance_)
        instance_ = new SIPVoIPLink;
Emmanuel Milou's avatar
Emmanuel Milou committed
291

292
    return instance_;
yanmorin's avatar
   
yanmorin committed
293
294
}

295
void SIPVoIPLink::init() {}
Emmanuel Milou's avatar
Emmanuel Milou committed
296

297
void SIPVoIPLink::terminate() {}
jpbl's avatar
jpbl committed
298

299
void
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
300
301
SIPVoIPLink::getEvent()
{
302
    // We have to register the external thread so it could access the pjsip frameworks
303
304
    if (!pj_thread_is_registered())
        pj_thread_register (NULL, desc, &thread);
yanmorin's avatar
   
yanmorin committed
305

306
307
308
309
    // PJSIP polling
    pj_time_val timeout = {0, 10};

    pjsip_endpt_handle_events (_endpt, &timeout);
310

311
}
312

313
void SIPVoIPLink::sendRegister (Account *a)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
314
{
315
    pj_status_t status;
316
317
    pjsip_tx_data *tdata;
    pjsip_hdr hdr_list;
318

319
    SIPAccount *account = static_cast<SIPAccount*>(a);
Emmanuel Milou's avatar
Emmanuel Milou committed
320

321
    // Resolve hostname here and keep its
322
323
324
    // IP address for the whole time the
    // account is connected. This was a
    // workaround meant to help issue
325
326
    // #1852 that we hope should be fixed
    // soon.
Emmanuel Milou's avatar
Emmanuel Milou committed
327
    if (account->isResolveOnce()) {
328
        pjsip_host_info destination;
Emmanuel Milou's avatar
Emmanuel Milou committed
329

330
331
        struct result result;
        destination.type = PJSIP_TRANSPORT_UNSPECIFIED;
Emmanuel Milou's avatar
Emmanuel Milou committed
332
333
        destination.flag = pjsip_transport_get_flag_from_type (PJSIP_TRANSPORT_UNSPECIFIED);
        destination.addr.host = pj_str (const_cast<char*> ( (account->getHostname()).c_str()));
334
        destination.addr.port = 0;
Emmanuel Milou's avatar
Emmanuel Milou committed
335

336
        result.status = 0x12345678;
Emmanuel Milou's avatar
Emmanuel Milou committed
337
338
339

        pjsip_endpt_resolve (_endpt, _pool, &destination, &result, &dns_cb);

340
341
342
        /* The following magic number and construct are inspired from dns_test.c
         * in test-pjsip directory.
         */
Emmanuel Milou's avatar
Emmanuel Milou committed
343

344
345
        while (result.status == 0x12345678) {
            pj_time_val timeout = { 1, 0 };
Emmanuel Milou's avatar
Emmanuel Milou committed
346
            pjsip_endpt_handle_events (_endpt, &timeout);
Julien Bonjean's avatar
Julien Bonjean committed
347
            _debug ("status : %d", result.status);
348
        }
Emmanuel Milou's avatar
Emmanuel Milou committed
349
350
351
352

        if (result.status != PJ_SUCCESS) {
            _debug ("Failed to resolve hostname only once."
                    " Default resolver will be used on"
Julien Bonjean's avatar
Julien Bonjean committed
353
                    " hostname for all requests.");
354
        } else {
Julien Bonjean's avatar
Julien Bonjean committed
355
            _debug ("%d servers where obtained from name resolution.", result.servers.count);
356
            char addr_buf[80];
Emmanuel Milou's avatar
Emmanuel Milou committed
357
358
359

            pj_sockaddr_print ( (pj_sockaddr_t*) &result.servers.entry[0].addr, addr_buf, sizeof (addr_buf), 3);
            account->setHostname (addr_buf);
360
        }
Emmanuel Milou's avatar
Emmanuel Milou committed
361
    }
362

363

364
    // Create SIP transport or get existent SIP transport from internal map
365
    // according to account settings, if the transport could not be created but
366
367
    // one is already set in account, use this one (most likely this is the
    // transport we tried to create)
368
    acquireTransport (account);
Emmanuel Milou's avatar
Emmanuel Milou committed
369

370
    if (account->getAccountTransport()) {
371
372
373
374
        _debug ("Acquire transport in account registration: %s %s (refcnt=%d)",
                account->getAccountTransport()->obj_name,
                account->getAccountTransport()->info,
                (int) pj_atomic_get (account->getAccountTransport()->ref_cnt));
375
    }
376

377
378
379
    pjsip_regc *regc;
    {
        ost::MutexLock m(mutexSIP_);
Emmanuel Milou's avatar
Emmanuel Milou committed
380

381
382
383
        // Get the client registration information for this particular account
        regc = account->getRegistrationInfo();
        account->setRegister (true);
384

385
386
387
388
389
390
        // Set the expire value of the message from the config file
        std::istringstream stream (account->getRegistrationExpire());
        int expire_value;
        stream >> expire_value;
        if (!expire_value)
            expire_value = PJSIP_REGC_EXPIRATION_NOT_SPECIFIED;
391

392
393
        // Update the state of the voip link
        account->setRegistrationState (Trying);
394

395
396
397
        // Create the registration according to the account ID
        if (pjsip_regc_create (_endpt, (void *) account, &registration_cb, &regc) != PJ_SUCCESS)
            throw VoipLinkException("UserAgent: Unable to create regc structure.");
398

399
400
401
        // Creates URI
        std::string fromUri(account->getFromUri());
        std::string srvUri(account->getServerUri());
402

403
404
        std::string address(findLocalAddressFromUri(srvUri, account->getAccountTransport()));
        int port = findLocalPortFromUri(srvUri, account->getAccountTransport());
405

406
407
408
409
        std::stringstream ss;
        std::string portStr;
        ss << port;
        ss >> portStr;
410

411
        std::string contactUri(account->getContactHeader(address, portStr));
412

413
414
415
416
        _debug ("UserAgent: sendRegister: fromUri: %s serverUri: %s contactUri: %s",
                fromUri.c_str(),
                srvUri.c_str(),
                contactUri.c_str());
417

418
419
        pj_str_t pjFrom;
        pj_cstr (&pjFrom, fromUri.c_str());
420

421
422
        pj_str_t pjContact;
        pj_cstr (&pjContact, contactUri.c_str());
423

424
425
        pj_str_t pjSrv;
        pj_cstr (&pjSrv, srvUri.c_str());
426

427
428
429
        // Initializes registration
        if (pjsip_regc_init (regc, &pjSrv, &pjFrom, &pjFrom, 1, &pjContact, expire_value) != PJ_SUCCESS)
            throw VoipLinkException("Unable to initialize account registration structure");
430

431
432
433
434
435
        // Fill route set
        if (!account->getServiceRoute().empty()) {
            pjsip_route_hdr *route_set = createRouteSet(account, _pool);
            pjsip_regc_set_route_set (regc, route_set);
        }
436

437
438
439
        unsigned count = account->getCredentialCount();
        pjsip_cred_info *info = account->getCredInfo();
        pjsip_regc_set_credentials (regc, count, info);
440

441
442
        // Add User-Agent Header
        pj_list_init (&hdr_list);
jpbl's avatar
jpbl committed
443

444
445
446
        const std::string agent(account->getUserAgentName());
        pj_str_t useragent = pj_str ((char*)agent.c_str());
        pjsip_generic_string_hdr *h = pjsip_generic_string_hdr_create (_pool, &STR_USER_AGENT, &useragent);
447

448
449
        pj_list_push_back (&hdr_list, (pjsip_hdr*) h);
        pjsip_regc_add_headers (regc, &hdr_list);
450

451
452
        if (pjsip_regc_register (regc, PJ_TRUE, &tdata) != PJ_SUCCESS)
            throw VoipLinkException("Unable to initialize transaction data for account registration");
jpbl's avatar
jpbl committed
453

454
        pjsip_tpselector *tp = initTransportSelector (account->getAccountTransport(), _pool);
Emmanuel Milou's avatar
Emmanuel Milou committed
455

456
457
        // pjsip_regc_set_transport increments transport ref count by one
        status = pjsip_regc_set_transport (regc, tp);
458

459
460
461
462
        if (account->getAccountTransport()) {
            // decrease transport's ref count, counter icrementation is
            // managed when acquiring transport
            pjsip_transport_dec_ref (account->getAccountTransport ());
Emmanuel Milou's avatar
Emmanuel Milou committed
463

464
465
466
467
468
            _debug ("UserAgent: After setting the transport in account registration using transport: %s %s (refcnt=%d)",
                    account->getAccountTransport()->obj_name,
                    account->getAccountTransport()->info,
                    (int) pj_atomic_get (account->getAccountTransport()->ref_cnt));
        }
469

470
471
        if (status != PJ_SUCCESS)
            throw VoipLinkException("Unable to set transport");
472

473
474
475
        // Send registration request
        // pjsip_regc_send increment the transport ref count by one,
        status = pjsip_regc_send (regc, tdata);
476

477
478
479
480
481
482
        if (account->getAccountTransport()) {
            // Decrease transport's ref count, since coresponding reference counter decrementation
            // is performed in pjsip_regc_destroy. This function is never called in SFLphone as the
            // regc data structure is permanently associated to the account at first registration.
            pjsip_transport_dec_ref (account->getAccountTransport ());
        }
483

484
485
        if (status != PJ_SUCCESS)
            throw VoipLinkException("Unable to send account registration request");
486

487
    }
488

489
490
    account->setRegistrationInfo (regc);

491
492
    pjsip_transport *transport = account->getAccountTransport();
    if (transport)
493
        _debug ("Sent account registration using transport: %s %s (refcnt=%d)",
494
                transport->obj_name, transport->info, (int) pj_atomic_get(transport->ref_cnt));
495
496
}

497
void SIPVoIPLink::sendUnregister (Account *a)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
498
{
499
    SIPAccount *account = dynamic_cast<SIPAccount *>(a);
500

501
    // If an transport is attached to this account, detach it and decrease reference counter
502
503
504
505
506
    if (account->getAccountTransport()) {
        _debug ("Sent account unregistration using transport: %s %s (refcnt=%d)",
                account->getAccountTransport()->obj_name,
                account->getAccountTransport()->info,
                (int) pj_atomic_get (account->getAccountTransport()->ref_cnt));
507
508
509
510

    }

    // This may occurs if account failed to register and is in state INVALID
511
512
    if (!account->isRegister()) {
        account->setRegistrationState (Unregistered);
513
        return;
514
515
    }

516
    pjsip_regc *regc = account->getRegistrationInfo();
517
    if (!regc)
518
519
    	throw VoipLinkException("Registration structure is NULL");

520
    pjsip_tx_data *tdata = NULL;
521
    if (pjsip_regc_unregister (regc, &tdata) != PJ_SUCCESS)
522
    	throw VoipLinkException("Unable to unregister sip account");
523

524
    if (pjsip_regc_send (regc, tdata) != PJ_SUCCESS)
525
    	throw VoipLinkException("Unable to send request to unregister sip account");
526

527
    account->setRegister (false);
jpbl's avatar
jpbl committed
528
529
}

530
Call *SIPVoIPLink::newOutgoingCall (const std::string& id, const std::string& toUrl)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
531
{
532
    // Create a new SIP call
533
    SIPCall* call = new SIPCall (id, Call::Outgoing, _cp);
Yun Liu's avatar
Yun Liu committed
534

535
    // Find the account associated to this call
536
    SIPAccount *account = dynamic_cast<SIPAccount *> (Manager::instance().getAccount (Manager::instance().getAccountFromCall (id)));
537
538
539
540
541
    if (account == NULL) {
    	_error ("UserAgent: Error: Could not retrieving account to make call with");
    	call->setConnectionState (Call::Disconnected);
    	call->setState (Call::Error);
    	delete call;
542
543
    	// TODO: We should investigate how we could get rid of this error and create a IP2IP call instead
    	throw VoipLinkException("Could not get account for this call");
544
    }
Emmanuel Milou's avatar
Emmanuel Milou committed
545

546
547
    // If toUri is not a well formated sip URI, use account information to process it
    std::string toUri;
548
    if((toUrl.find("sip:") != std::string::npos) or
549
550
551
    		toUrl.find("sips:") != std::string::npos) {
    	toUri = toUrl;
    }
552
    else
553
        toUri = account->getToUri (toUrl);
554

555
    call->setPeerNumber (toUri);
556
    _debug ("UserAgent: New outgoing call %s to %s", id.c_str(), toUri.c_str());
557

558
    std::string localAddr(getInterfaceAddrFromName (account->getLocalInterface ()));
559
    _debug ("UserAgent: Local address for thi call: %s", localAddr.c_str());
560

561
    if (localAddr == "0.0.0.0")
562
    	localAddr = loadSIPLocalIP();
563

564
    setCallMediaLocal (call, localAddr);
Emmanuel Milou's avatar
Emmanuel Milou committed
565

566
    // May use the published address as well
567
568
    std::string addrSdp = account->isStunEnabled() ?
        account->getPublishedAddress() :
569
        getInterfaceAddrFromName(account->getLocalInterface());
570

571
    if (addrSdp == "0.0.0.0")
572
		addrSdp = loadSIPLocalIP();
Emmanuel Milou's avatar
Emmanuel Milou committed
573

574
575
576
    // Initialize the session using ULAW as default codec in case of early media
    // The session should be ready to receive media once the first INVITE is sent, before
    // the session initialization is completed
577
    sfl::Codec* audiocodec = Manager::instance().getAudioCodecFactory().instantiateCodec (PAYLOAD_CODEC_ULAW);
578
579
    if (audiocodec == NULL) {
    	_error ("UserAgent: Could not instantiate codec");
580
581
    	delete call;
    	throw VoipLinkException ("Could not instantiate codec for early media");
582
    }
583

584
585
	try {
		_info ("UserAgent: Creating new rtp session");
586
587
588
		call->getAudioRtp()->initAudioRtpConfig ();
		call->getAudioRtp()->initAudioSymmetricRtpSession ();
		call->getAudioRtp()->initLocalCryptoInfo ();
589
		_info ("UserAgent: Start audio rtp session");
590
		call->getAudioRtp()->start (static_cast<sfl::AudioCodec *>(audiocodec));
591
	} catch (...) {
592
        delete call;
593
		throw VoipLinkException ("Could not start rtp session for early media");
594
	}
595

596
597
	// init file name according to peer phone number
	call->initRecFileName (toUrl);
598

599
	// Building the local SDP offer
600
	call->getLocalSDP()->setLocalIP (addrSdp);
601
	if (call->getLocalSDP()->createOffer(account->getActiveCodecs()) != PJ_SUCCESS) {
602
		delete call;
603
		throw VoipLinkException ("Could not create local sdp offer for new call");
604
	}
605

606
	if (SIPStartCall(call)) {
607
608
609
610
611
		call->setConnectionState (Call::Progressing);
		call->setState (Call::Active);
		addCall (call);
	} else {
		delete call;
612
		throw VoipLinkException("Could not send outgoing INVITE request for new call");
613
	}
jpbl's avatar
jpbl committed
614

615
	return call;
616
}
617

618
void
619
SIPVoIPLink::answer (Call *c)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
620
{
621
    pjsip_tx_data *tdata;
622

623
    _debug ("UserAgent: Answering call");
624

625
    SIPCall *call = dynamic_cast<SIPCall*>(c);
jpbl's avatar
jpbl committed
626

627
    pjsip_inv_session *inv_session = call->getInvSession();
628

629
630
631
632
	_debug ("UserAgent: SDP negotiation success! : call %s ", call->getCallId().c_str());
	// Create and send a 200(OK) response
	if (pjsip_inv_answer (inv_session, PJSIP_SC_OK, NULL, NULL, &tdata) != PJ_SUCCESS)
		throw VoipLinkException("Could not init invite request answer (200 OK)");
633

634
635
	if (pjsip_inv_send_msg (inv_session, tdata) != PJ_SUCCESS)
		throw VoipLinkException("Could not send invite request answer (200 OK)");
Emmanuel Milou's avatar
Emmanuel Milou committed
636

637
638
	call->setConnectionState (Call::Connected);
	call->setState (Call::Active);
Yun Liu's avatar
Yun Liu committed
639
640
}

641
void
642
SIPVoIPLink::hangup (const std::string& id)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
643
{
644
    SIPCall* call = getSIPCall(id);
645

646
    std::string account_id(Manager::instance().getAccountFromCall(id));
647
    SIPAccount *account = dynamic_cast<SIPAccount *> (Manager::instance().getAccount (account_id));
648
    if (account == NULL)
649
650
    	throw VoipLinkException("Could not find account for this call");

651
    pjsip_inv_session *inv = call->getInvSession();
652
    if (inv == NULL)
653
    	throw VoipLinkException("No invite session for this call");
654

655
    // Looks for sip routes
656
    if (not (account->getServiceRoute().empty())) {
657
        pjsip_route_hdr *route_set = createRouteSet(account, inv->pool);
658
659
        pjsip_dlg_set_route_set (inv->dlg, route_set);
    }
660

661
    pjsip_tx_data *tdata = NULL;
662
    // User hangup current call. Notify peer
663
664
    if (pjsip_inv_end_session (inv, 404, NULL, &tdata) != PJ_SUCCESS || !tdata)
        return;
665

666
667
    if (pjsip_inv_send_msg (inv, tdata) != PJ_SUCCESS)
        return;
668

669
670
    // Make sure user data is NULL in callbacks
    inv->mod_data[getModId()] = NULL;
671

672
    // Release RTP thread
673
    try {
674
        if (Manager::instance().isCurrentCall (id))
675
676
            call->getAudioRtp()->stop();
    }
677
    catch (...) {
678
    	throw VoipLinkException("Could not stop audio rtp session");
679
680
681
    }

    removeCall (id);
alexandresavard's avatar
alexandresavard committed
682
683
}

684
void
685
SIPVoIPLink::peerHungup (const std::string& id)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
686
{
687
    _info ("UserAgent: Peer hungup");
688

689
    SIPCall* call = getSIPCall(id);
Alexandre Savard's avatar
Alexandre Savard committed
690

691
    // User hangup current call. Notify peer
692
693
694
    pjsip_tx_data *tdata = NULL;
    if (pjsip_inv_end_session (call->getInvSession(), 404, NULL, &tdata) != PJ_SUCCESS || !tdata)
        return;
695

696
697
    if (pjsip_inv_send_msg (call->getInvSession(), tdata) != PJ_SUCCESS)
        return;
698

699
    // Make sure user data is NULL in callbacks
700
701
702
    call->getInvSession()->mod_data[getModId() ] = NULL;

    // Release RTP thread
703
704
705
706
707
708
    try {
        if (Manager::instance().isCurrentCall (id)) {
            _debug ("UserAgent: Stopping AudioRTP for hangup");
            call->getAudioRtp()->stop();
        }
    }
709
    catch (...) {
710
    	throw VoipLinkException("Could not stop audio rtp session");
711
712
713
    }

    removeCall (id);
714
715
}

716
void
717
SIPVoIPLink::cancel (const std::string& id)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
718
{
719
    _info ("UserAgent: Cancel call %s", id.c_str());
720

721
    removeCall (id);
722
723
}

724

725
bool
726
SIPVoIPLink::onhold (const std::string& id)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
727
{
728
    SIPCall *call = getSIPCall(id);
729
730
731

    // Stop sound
    call->setState (Call::Hold);
732
733
734
735
736
737
738

    try {
        call->getAudioRtp()->stop();
    }
    catch (...) {
    	throw VoipLinkException("Could not stop audio rtp session");
    }
739

740
    _debug ("UserAgent: Stopping RTP session for on hold action");
741

742
743
	Sdp *sdpSession = call->getLocalSDP();
    if (!sdpSession)
744
    	throw VoipLinkException("Could not find sdp session");
745
746
747

    sdpSession->removeAttributeFromLocalAudioMedia("sendrecv");
    sdpSession->removeAttributeFromLocalAudioMedia("sendonly");
748

749
750
751
    sdpSession->addAttributeToLocalAudioMedia("sendonly");

    // Create re-INVITE with new offer
752
    return SIPSessionReinvite (call) == PJ_SUCCESS;
753
754
755
}

bool
756
SIPVoIPLink::offhold (const std::string& id)
757
{
758
    _debug ("UserAgent: retrive call from hold status");
759

760
    SIPCall *call = getSIPCall (id);
761

762
	Sdp *sdpSession = call->getLocalSDP();
763
    if (sdpSession == NULL)
764
    	throw VoipLinkException("Could not find sdp session");
765

766
767
768
769
770
771
772
773
    try {
        // Retreive previously selected codec
        AudioCodecType pl;
        sfl::Codec *sessionMedia = sdpSession->getSessionMedia();
        if (sessionMedia == NULL) {
    	    _warn("UserAgent: Session media not yet initialized, using default (ULAW)");
    	    pl = PAYLOAD_CODEC_ULAW;
        }
774
        else
775
    	    pl = (AudioCodecType) sessionMedia->getPayloadType();
776

777
        _debug ("UserAgent: Payload from session media %d", pl);
778

779

780
        // Create a new instance for this codec
781
        sfl::Codec* audiocodec = Manager::instance().getAudioCodecFactory().instantiateCodec (pl);
782
        if (audiocodec == NULL)
783
    	    throw VoipLinkException("Could not instantiate codec");