linphonecall.c 55.3 KB
Newer Older
1 2 3

/*
linphone
4
Copyright (C) 2010  Belledonne Communications SARL
5 6 7 8 9 10 11 12 13 14 15 16 17 18
 (simon.morlat@linphone.org)

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 the Free Software Foundation; either version 2
of the License, or (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
19
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20
*/
21
#ifdef _WIN32
22 23
#include <time.h>
#endif
24 25 26
#include "linphone/core.h"
#include "linphone/sipsetup.h"
#include "linphone/lpconfig.h"
27
#include "private.h"
28
#include "conference_private.h"
29

30
#include <ortp/event.h>
31
#include <ortp/b64.h>
Yann Diorcet's avatar
Yann Diorcet committed
32
#include <math.h>
33

34 35 36
#include "mediastreamer2/mediastream.h"
#include "mediastreamer2/msvolume.h"
#include "mediastreamer2/msequalizer.h"
37
#include "mediastreamer2/msfileplayer.h"
38
#include "mediastreamer2/msjpegwriter.h"
39
#include "mediastreamer2/msogl.h"
40
#include "mediastreamer2/mseventqueue.h"
41
#include "mediastreamer2/mssndcard.h"
42
#include "mediastreamer2/msrtt4103.h"
43

44 45
#include <bctoolbox/defs.h>

46 47
// For migration purpose.
#include "address/address-p.h"
48
#include "c-wrapper/c-private-types.h"
49
#include "c-wrapper/c-tools.h"
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
#include "call/call.h"
#include "call/call-p.h"
#include "conference/params/media-session-params-p.h"

struct _LinphoneCall{
	belle_sip_object_t base;
	void *user_data;
	bctbx_list_t *callbacks; /* A list of LinphoneCallCbs object */
	LinphoneCallCbs *current_cbs; /* The current LinphoneCallCbs object used to call a callback */
	std::shared_ptr<LinphonePrivate::Call> call;
	LinphoneCallParams *currentParamsCache;
	LinphoneCallParams *paramsCache;
	LinphoneCallParams *remoteParamsCache;
	LinphoneAddress *remoteAddressCache;
	char *remoteContactCache;

	struct _LinphoneCore *core;
	LinphoneErrorInfo *ei;
	SalMediaDescription *localdesc;
	SalMediaDescription *resultdesc;
	struct _LinphoneCallLog *log;
	SalOp *op;
	SalOp *ping_op;
	LinphoneCallState transfer_state; /*idle if no transfer*/
	struct _AudioStream *audiostream;  /**/
	struct _VideoStream *videostream;
	struct _TextStream *textstream;
	MSAudioEndpoint *endpoint; /*used for conferencing*/
	char *refer_to;
	LinphoneCallParams *params;
	LinphoneCallParams *current_params;
	LinphoneCallParams *remote_params;
	LinphoneCallStats *audio_stats;
	LinphoneCallStats *video_stats;
	LinphoneCallStats *text_stats;
	LinphoneCall *referer; /*when this call is the result of a transfer, referer is set to the original call that caused the transfer*/
	LinphoneCall *transfer_target;/*if this call received a transfer request, then transfer_target points to the new call created to the refer target */
	LinphonePlayer *player;
	char *dtmf_sequence; /*DTMF sequence needed to be sent using #dtmfs_timer*/
	belle_sip_source_t *dtmfs_timer; /*DTMF timer needed to send a DTMF sequence*/
	LinphoneChatRoom *chat_room;
	LinphoneConference *conf_ref; /**> Point on the associated conference if this call is part of a conference. NULL instead. */
	bool_t refer_pending;
	bool_t defer_update;
	bool_t was_automatically_paused;
	bool_t paused_by_app;
	bool_t broken; /*set to TRUE when the call is in broken state due to network disconnection or transport */
	bool_t need_localip_refresh;
	bool_t reinvite_on_cancel_response_requested;
	bool_t non_op_error; /*set when the LinphoneErrorInfo was set at higher level than sal*/
};

BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneCall);
Simon Morlat's avatar
Simon Morlat committed
103

104

105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
typedef belle_sip_object_t_vptr_t LinphoneCallCbs_vptr_t;
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneCallCbs);
BELLE_SIP_INSTANCIATE_VPTR(LinphoneCallCbs, belle_sip_object_t,
	NULL, // destroy
	NULL, // clone
	NULL, // Marshall
	FALSE
);

LinphoneCallCbs *_linphone_call_cbs_new(void) {
	LinphoneCallCbs *obj = belle_sip_object_new(LinphoneCallCbs);
	return obj;
}

LinphoneCallCbs *linphone_call_cbs_ref(LinphoneCallCbs *cbs) {
	return (LinphoneCallCbs *)belle_sip_object_ref(cbs);
}

void linphone_call_cbs_unref(LinphoneCallCbs *cbs) {
	belle_sip_object_unref(cbs);
}

void *linphone_call_cbs_get_user_data(const LinphoneCallCbs *cbs) {
	return cbs->user_data;
}

void linphone_call_cbs_set_user_data(LinphoneCallCbs *cbs, void *user_data) {
	cbs->user_data = user_data;
}

LinphoneCallCbsDtmfReceivedCb linphone_call_cbs_get_dtmf_received(LinphoneCallCbs *cbs) {
	return cbs->dtmf_received_cb;
}

void linphone_call_cbs_set_dtmf_received(LinphoneCallCbs *cbs, LinphoneCallCbsDtmfReceivedCb cb) {
	cbs->dtmf_received_cb = cb;
}

LinphoneCallCbsEncryptionChangedCb linphone_call_cbs_get_encryption_changed(LinphoneCallCbs *cbs) {
	return cbs->encryption_changed_cb;
}

void linphone_call_cbs_set_encryption_changed(LinphoneCallCbs *cbs, LinphoneCallCbsEncryptionChangedCb cb) {
	cbs->encryption_changed_cb = cb;
}

LinphoneCallCbsInfoMessageReceivedCb linphone_call_cbs_get_info_message_received(LinphoneCallCbs *cbs) {
	return cbs->info_message_received_cb;
}

void linphone_call_cbs_set_info_message_received(LinphoneCallCbs *cbs, LinphoneCallCbsInfoMessageReceivedCb cb) {
	cbs->info_message_received_cb = cb;
}

LinphoneCallCbsStateChangedCb linphone_call_cbs_get_state_changed(LinphoneCallCbs *cbs) {
	return cbs->state_changed_cb;
}

void linphone_call_cbs_set_state_changed(LinphoneCallCbs *cbs, LinphoneCallCbsStateChangedCb cb) {
	cbs->state_changed_cb = cb;
}

LinphoneCallCbsStatsUpdatedCb linphone_call_cbs_get_stats_updated(LinphoneCallCbs *cbs) {
	return cbs->stats_updated_cb;
}

void linphone_call_cbs_set_stats_updated(LinphoneCallCbs *cbs, LinphoneCallCbsStatsUpdatedCb cb) {
	cbs->stats_updated_cb = cb;
}

LinphoneCallCbsTransferStateChangedCb linphone_call_cbs_get_transfer_state_changed(LinphoneCallCbs *cbs) {
	return cbs->transfer_state_changed_cb;
}

void linphone_call_cbs_set_transfer_state_changed(LinphoneCallCbs *cbs, LinphoneCallCbsTransferStateChangedCb cb) {
	cbs->transfer_state_changed_cb = cb;
}

183 184 185 186 187 188 189 190
LinphoneCallCbsAckProcessingCb linphone_call_cbs_get_ack_processing(LinphoneCallCbs *cbs){
	return cbs->ack_processing;
}

void linphone_call_cbs_set_ack_processing(LinphoneCallCbs *cbs, LinphoneCallCbsAckProcessingCb cb){
	cbs->ack_processing = cb;
}

191

192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
bool_t linphone_call_state_is_early(LinphoneCallState state){
	switch (state){
		case LinphoneCallIdle:
		case LinphoneCallOutgoingInit:
		case LinphoneCallOutgoingEarlyMedia:
		case LinphoneCallOutgoingRinging:
		case LinphoneCallOutgoingProgress:
		case LinphoneCallIncomingReceived:
		case LinphoneCallIncomingEarlyMedia:
		case LinphoneCallEarlyUpdatedByRemote:
		case LinphoneCallEarlyUpdating:
			return TRUE;
		case LinphoneCallResuming:
		case LinphoneCallEnd:
		case LinphoneCallUpdating:
		case LinphoneCallRefered:
		case LinphoneCallPausing:
		case LinphoneCallPausedByRemote:
		case LinphoneCallPaused:
		case LinphoneCallConnected:
		case LinphoneCallError:
		case LinphoneCallUpdatedByRemote:
		case LinphoneCallReleased:
		case LinphoneCallStreamsRunning:
		break;
	}
	return FALSE;
}

221
MSWebCam *get_nowebcam_device(MSFactory* f){
222
#ifdef VIDEO_ENABLED
223
	return ms_web_cam_manager_get_cam(ms_factory_get_web_cam_manager(f),"StaticImage: Static picture");
224 225
#else
	return NULL;
Simon Morlat's avatar
Simon Morlat committed
226
#endif
227 228
}

229 230
LinphoneCore *linphone_call_get_core(const LinphoneCall *call) {
	return linphone_call_get_cpp_obj(call)->getCore();
231 232
}

233 234 235
const char * linphone_call_get_authentication_token(LinphoneCall *call) {
	std::string token = linphone_call_get_cpp_obj(call)->getAuthenticationToken();
	return token.empty() ? nullptr : token.c_str();
236 237
}

238 239
bool_t linphone_call_get_authentication_token_verified(const LinphoneCall *call) {
	return linphone_call_get_cpp_obj(call)->getAuthenticationTokenVerified();
240
}
Simon Morlat's avatar
Simon Morlat committed
241

242 243
void linphone_call_set_authentication_token_verified(LinphoneCall *call, bool_t verified) {
	linphone_call_get_cpp_obj(call)->setAuthenticationTokenVerified(verified);
244 245
}

246 247 248 249 250
bool_t is_payload_type_number_available(const bctbx_list_t *l, int number, const PayloadType *ignore){
	const bctbx_list_t *elem;
	for (elem=l; elem!=NULL; elem=elem->next){
		const PayloadType *pt=(PayloadType*)elem->data;
		if (pt!=ignore && payload_type_get_number(pt)==number) return FALSE;
251
	}
252
	return TRUE;
253 254
}

255
void linphone_call_update_local_media_description_from_ice_or_upnp(LinphoneCall *call){
256 257
}

258
void linphone_call_make_local_media_description(LinphoneCall *call) {
259 260
}

261 262 263 264 265 266 267 268 269 270 271
void linphone_call_create_op(LinphoneCall *call){
#if 0
	if (call->op) sal_op_release(call->op);
	call->op=sal_op_new(call->core->sal);
	sal_op_set_user_pointer(call->op,call);
	if (linphone_call_params_get_referer(call->params))
		sal_call_set_referer(call->op,linphone_call_params_get_referer(call->params)->op);
	linphone_configure_op(call->core,call->op,call->log->to,linphone_call_params_get_custom_headers(call->params),FALSE);
	if (linphone_call_params_get_privacy(call->params) != LinphonePrivacyDefault)
		sal_op_set_privacy(call->op,(SalPrivacyMask)linphone_call_params_get_privacy(call->params));
  /*else privacy might be set by proxy */
jehan's avatar
jehan committed
272
#endif
273 274
}

275
static void linphone_call_destroy(LinphoneCall *obj);
276

277
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneCall);
278

279 280 281 282 283 284
BELLE_SIP_INSTANCIATE_VPTR(LinphoneCall, belle_sip_object_t,
	(belle_sip_object_destroy_t)linphone_call_destroy,
	NULL, // clone
	NULL, // marshal
	FALSE
);
285

286 287 288 289 290 291 292 293 294
LinphoneCall * linphone_call_new_outgoing(LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to, const LinphoneCallParams *params, LinphoneProxyConfig *cfg){
	LinphoneCall *call = belle_sip_object_new(LinphoneCall);
	call->currentParamsCache = linphone_call_params_new_for_wrapper();
	call->paramsCache = linphone_call_params_new_for_wrapper();
	call->remoteParamsCache = linphone_call_params_new_for_wrapper();
	call->remoteAddressCache = linphone_address_new(nullptr);
	call->call = std::make_shared<LinphonePrivate::Call>(call, lc, LinphoneCallOutgoing, *L_GET_CPP_PTR_FROM_C_STRUCT(from, Address), *L_GET_CPP_PTR_FROM_C_STRUCT(to, Address), cfg, nullptr, linphone_call_params_get_cpp_obj(params));
	return call;
}
295

296 297 298 299 300 301 302 303 304
LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to, SalOp *op) {
	LinphoneCall *call = belle_sip_object_new(LinphoneCall);
	call->currentParamsCache = linphone_call_params_new_for_wrapper();
	call->paramsCache = linphone_call_params_new_for_wrapper();
	call->remoteParamsCache = linphone_call_params_new_for_wrapper();
	call->remoteAddressCache = linphone_address_new(nullptr);
	call->call = std::make_shared<LinphonePrivate::Call>(call, lc, LinphoneCallIncoming, *L_GET_CPP_PTR_FROM_C_STRUCT(from, Address), *L_GET_CPP_PTR_FROM_C_STRUCT(to, Address), nullptr, op, nullptr);
	L_GET_PRIVATE(linphone_call_get_cpp_obj(call).get())->initiateIncoming();
	return call;
305 306
}

307 308
static void linphone_call_free_media_resources(LinphoneCall *call){
}
309

310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356
const char *linphone_call_state_to_string(LinphoneCallState cs){
	switch (cs){
		case LinphoneCallIdle:
			return "LinphoneCallIdle";
		case LinphoneCallIncomingReceived:
			return "LinphoneCallIncomingReceived";
		case LinphoneCallOutgoingInit:
			return "LinphoneCallOutgoingInit";
		case LinphoneCallOutgoingProgress:
			return "LinphoneCallOutgoingProgress";
		case LinphoneCallOutgoingRinging:
			return "LinphoneCallOutgoingRinging";
		case LinphoneCallOutgoingEarlyMedia:
			return "LinphoneCallOutgoingEarlyMedia";
		case LinphoneCallConnected:
			return "LinphoneCallConnected";
		case LinphoneCallStreamsRunning:
			return "LinphoneCallStreamsRunning";
		case LinphoneCallPausing:
			return "LinphoneCallPausing";
		case LinphoneCallPaused:
			return "LinphoneCallPaused";
		case LinphoneCallResuming:
			return "LinphoneCallResuming";
		case LinphoneCallRefered:
			return "LinphoneCallRefered";
		case LinphoneCallError:
			return "LinphoneCallError";
		case LinphoneCallEnd:
			return "LinphoneCallEnd";
		case LinphoneCallPausedByRemote:
			return "LinphoneCallPausedByRemote";
		case LinphoneCallUpdatedByRemote:
			return "LinphoneCallUpdatedByRemote";
		case LinphoneCallIncomingEarlyMedia:
			return "LinphoneCallIncomingEarlyMedia";
		case LinphoneCallUpdating:
			return "LinphoneCallUpdating";
		case LinphoneCallReleased:
			return "LinphoneCallReleased";
		case LinphoneCallEarlyUpdatedByRemote:
			return "LinphoneCallEarlyUpdatedByRemote";
		case LinphoneCallEarlyUpdating:
			return "LinphoneCallEarlyUpdating";
	}
	return "undefined state";
}
357

358
void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const char *message){
359 360
}

361 362 363 364 365 366
static void linphone_call_destroy(LinphoneCall *obj) {
	ms_message("Call [%p] freed.", obj);
	obj->call = nullptr;
	if (obj->currentParamsCache) {
		linphone_call_params_unref(obj->currentParamsCache);
		obj->currentParamsCache = nullptr;
Simon Morlat's avatar
Simon Morlat committed
367
	}
368 369 370
	if (obj->paramsCache) {
		linphone_call_params_unref(obj->paramsCache);
		obj->paramsCache = nullptr;
Simon Morlat's avatar
Simon Morlat committed
371
	}
372 373 374
	if (obj->remoteParamsCache) {
		linphone_call_params_unref(obj->remoteParamsCache);
		obj->remoteParamsCache = nullptr;
Simon Morlat's avatar
Simon Morlat committed
375
	}
376 377 378
	if (obj->remoteAddressCache) {
		linphone_address_unref(obj->remoteAddressCache);
		obj->remoteAddressCache = nullptr;
379
	}
380 381 382
	bctbx_list_free_with_data(obj->callbacks, (bctbx_list_free_func)linphone_call_cbs_unref);
	if (obj->audiostream || obj->videostream){
		linphone_call_free_media_resources(obj);
383
	}
384 385 386
	if (obj->audio_stats) {
		linphone_call_stats_unref(obj->audio_stats);
		obj->audio_stats = NULL;
387
	}
388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443
	if (obj->video_stats) {
		linphone_call_stats_unref(obj->video_stats);
		obj->video_stats = NULL;
	}
	if (obj->text_stats) {
		linphone_call_stats_unref(obj->text_stats);
		obj->text_stats = NULL;
	}
	if (obj->op!=NULL) {
		sal_op_release(obj->op);
		obj->op=NULL;
	}
	if (obj->resultdesc!=NULL) {
		sal_media_description_unref(obj->resultdesc);
		obj->resultdesc=NULL;
	}
	if (obj->localdesc!=NULL) {
		sal_media_description_unref(obj->localdesc);
		obj->localdesc=NULL;
	}
	if (obj->ping_op) {
		sal_op_release(obj->ping_op);
		obj->ping_op=NULL;
	}
	if (obj->refer_to){
		ms_free(obj->refer_to);
		obj->refer_to=NULL;
	}
	if (obj->referer){
		linphone_call_unref(obj->referer);
		obj->referer=NULL;
	}
	if (obj->transfer_target){
		linphone_call_unref(obj->transfer_target);
		obj->transfer_target=NULL;
	}
	if (obj->log) {
		linphone_call_log_unref(obj->log);
		obj->log=NULL;
	}
	if (obj->dtmfs_timer) {
		linphone_call_cancel_dtmfs(obj);
	}
	if (obj->params){
		linphone_call_params_unref(obj->params);
		obj->params=NULL;
	}
	if (obj->current_params){
		linphone_call_params_unref(obj->current_params);
		obj->current_params=NULL;
	}
	if (obj->remote_params != NULL) {
		linphone_call_params_unref(obj->remote_params);
		obj->remote_params=NULL;
	}
	if (obj->ei) linphone_error_info_unref(obj->ei);
444
}
445

446 447 448 449
LinphoneCall * linphone_call_ref(LinphoneCall *obj){
	belle_sip_object_ref(obj);
	return obj;
}
450

451 452 453
void linphone_call_unref(LinphoneCall *obj){
	belle_sip_object_unref(obj);
}
454

455 456 457 458
const LinphoneCallParams * linphone_call_get_current_params(LinphoneCall *call){
	call->currentParamsCache->msp = linphone_call_get_cpp_obj(call)->getCurrentParams();
	return call->currentParamsCache;
}
459

460 461 462 463 464 465
const LinphoneCallParams * linphone_call_get_remote_params(LinphoneCall *call) {
	call->remoteParamsCache->msp = linphone_call_get_cpp_obj(call)->getRemoteParams();
	if (call->remoteParamsCache->msp)
		return call->remoteParamsCache;
	return nullptr;
}
466

467 468 469 470
const LinphoneAddress * linphone_call_get_remote_address(const LinphoneCall *call) {
	std::shared_ptr<LinphonePrivate::Address> addr = std::make_shared<LinphonePrivate::Address>(linphone_call_get_cpp_obj(call)->getRemoteAddress());
	L_SET_CPP_PTR_FROM_C_STRUCT(call->remoteAddressCache, addr);
	return call->remoteAddressCache;
471 472
}

473 474 475 476 477 478
const LinphoneAddress * linphone_call_get_to_address(const LinphoneCall *call){
#if 0
  return (const LinphoneAddress *)sal_op_get_to_address(call->op);
#else
	return nullptr;
#endif
479 480
}

481 482 483 484 485 486
const char *linphone_call_get_to_header(const LinphoneCall *call, const char *name){
#if 0
	return sal_custom_header_find(sal_op_get_recv_custom_header(call->op),name);
#else
	return nullptr;
#endif
487 488
}

489 490
char * linphone_call_get_remote_address_as_string(const LinphoneCall *call) {
	return ms_strdup(linphone_call_get_cpp_obj(call)->getRemoteAddressAsString().c_str());
491 492
}

493 494 495 496 497 498 499
const LinphoneAddress * linphone_call_get_diversion_address(const LinphoneCall *call){
#if 0
	return call->op?(const LinphoneAddress *)sal_op_get_diversion_address(call->op):NULL;
#else
	return nullptr;
#endif
}
500

501 502 503
LinphoneCallState linphone_call_get_state(const LinphoneCall *call) {
	return linphone_call_get_cpp_obj(call)->getState();
}
504

505 506 507
LinphoneReason linphone_call_get_reason(const LinphoneCall *call) {
	return linphone_call_get_cpp_obj(call)->getReason();
}
508

509 510 511
const LinphoneErrorInfo * linphone_call_get_error_info(const LinphoneCall *call) {
	return linphone_call_get_cpp_obj(call)->getErrorInfo();
}
512

513 514 515
void *linphone_call_get_user_data(const LinphoneCall *call) {
	return call->user_data;
}
516

517 518
void linphone_call_set_user_data(LinphoneCall *call, void *user_pointer) {
	call->user_data = user_pointer;
519 520
}

521 522
LinphoneCallLog *linphone_call_get_call_log(const LinphoneCall *call){
	return linphone_call_get_cpp_obj(call)->getLog();
523 524
}

525 526 527
const char *linphone_call_get_refer_to(const LinphoneCall *call){
#if 0
	return call->refer_to;
528
#else
529
	return nullptr;
530 531 532
#endif
}

533 534 535 536 537
LinphoneCall *linphone_call_get_transferer_call(const LinphoneCall *call){
#if 0
	return call->referer;
#else
	return nullptr;
jehan's avatar
jehan committed
538
#endif
539 540
}

541 542 543 544 545
LinphoneCall *linphone_call_get_transfer_target_call(const LinphoneCall *call){
#if 0
	return call->transfer_target;
#else
	return nullptr;
546
#endif
Simon Morlat's avatar
Simon Morlat committed
547 548
}

549 550
LinphoneCallDir linphone_call_get_dir(const LinphoneCall *call) {
	return linphone_call_log_get_dir(linphone_call_get_log(call));
551
}
552

553 554 555 556
const char *linphone_call_get_remote_user_agent(LinphoneCall *call){
#if 0
	if (call->op){
		return sal_op_get_remote_ua (call->op);
Guillaume BIENKOWSKI's avatar
Guillaume BIENKOWSKI committed
557
	}
558 559 560
	return NULL;
#else
	return nullptr;
Simon Morlat's avatar
Simon Morlat committed
561 562
#endif
}
563

564 565 566 567 568 569 570 571
const char * linphone_call_get_remote_contact(LinphoneCall *call) {
	std::string contact = linphone_call_get_cpp_obj(call)->getRemoteContact();
	if (contact.empty())
		return nullptr;
	if (call->remoteContactCache)
		bctbx_free(call->remoteContactCache);
	call->remoteContactCache = bctbx_strdup(contact.c_str());
	return call->remoteContactCache;
572 573
}

574 575 576 577 578
bool_t linphone_call_has_transfer_pending(const LinphoneCall *call){
#if 0
	return call->refer_pending;
#else
	return FALSE;
579
#endif
580
}
581

582 583
int linphone_call_get_duration(const LinphoneCall *call) {
	return linphone_call_get_cpp_obj(call)->getDuration();
584 585
}

586 587 588 589 590
LinphoneCall *linphone_call_get_replaced_call(LinphoneCall *call){
#if 0
	SalOp *op=sal_call_get_replaces(call->op);
	if (op){
		return (LinphoneCall*)sal_op_get_user_pointer(op);
591
	}
592 593 594
	return NULL;
#else
	return nullptr;
595 596 597
#endif
}

598 599
void linphone_call_enable_camera(LinphoneCall *call, bool_t enable) {
	linphone_call_get_cpp_obj(call)->enableCamera(enable);
600 601
}

602 603 604
void linphone_call_send_vfu_request(LinphoneCall *call) {
	linphone_call_get_cpp_obj(call)->sendVfuRequest();
}
605

606 607 608
LinphoneStatus linphone_call_take_video_snapshot(LinphoneCall *call, const char *file) {
	return linphone_call_get_cpp_obj(call)->takeVideoSnapshot(file ? file : "");
}
609

610 611 612
LinphoneStatus linphone_call_take_preview_snapshot(LinphoneCall *call, const char *file) {
	return linphone_call_get_cpp_obj(call)->takePreviewSnapshot(file ? file : "");
}
jehan's avatar
jehan committed
613

614 615 616
bool_t linphone_call_camera_enabled (const LinphoneCall *call) {
	return linphone_call_get_cpp_obj(call)->cameraEnabled();
}
617

618 619 620 621 622 623 624 625 626 627 628 629 630 631
/**
 * @ingroup call_control
 * @return string value of LinphonePrivacy enum
 **/
const char* linphone_privacy_to_string(LinphonePrivacy privacy) {
	switch(privacy) {
	case LinphonePrivacyDefault: return "LinphonePrivacyDefault";
	case LinphonePrivacyUser: return "LinphonePrivacyUser";
	case LinphonePrivacyHeader: return "LinphonePrivacyHeader";
	case LinphonePrivacySession: return "LinphonePrivacySession";
	case LinphonePrivacyId: return "LinphonePrivacyId";
	case LinphonePrivacyNone: return "LinphonePrivacyNone";
	case LinphonePrivacyCritical: return "LinphonePrivacyCritical";
	default: return "Unknown privacy mode";
632 633 634
	}
}

635 636
void linphone_call_set_next_video_frame_decoded_callback(LinphoneCall *call, LinphoneCallCbFunc cb, void* user_data) {
	linphone_call_get_cpp_obj(call)->setNextVideoFrameDecodedCallback(cb, user_data);
637 638
}

639
void linphone_call_init_media_streams(LinphoneCall *call){
640 641
}

642 643 644 645 646 647
static int dtmf_tab[16]={'0','1','2','3','4','5','6','7','8','9','*','#','A','B','C','D'};

static void linphone_core_dtmf_received(LinphoneCall *call, int dtmf){
	if (dtmf<0 || dtmf>15){
		ms_warning("Bad dtmf value %i",dtmf);
		return;
Yann Diorcet's avatar
Yann Diorcet committed
648
	}
649
	linphone_call_notify_dtmf_received(call, dtmf_tab[dtmf]);
650 651
}

652 653 654 655
void set_playback_gain_db(AudioStream *st, float gain){
	if (st->volrecv){
		ms_filter_call_method(st->volrecv,MS_VOLUME_SET_DB_GAIN,&gain);
	}else ms_warning("Could not apply playback gain: gain control wasn't activated.");
656 657
}

658 659
/*This function is not static because used internally in linphone-daemon project*/
void _post_configure_audio_stream(AudioStream *st, LinphoneCore *lc, bool_t muted){
660 661
}

662 663 664 665
static void setup_ring_player(LinphoneCore *lc, LinphoneCall *call){
	int pause_time=3000;
	audio_stream_play(call->audiostream,lc->sound_conf.ringback_tone);
	ms_filter_call_method(call->audiostream->soundread,MS_FILE_PLAYER_LOOP,&pause_time);
666
}
667

668 669 670 671 672
static bool_t linphone_call_sound_resources_available(LinphoneCall *call){
	LinphoneCore *lc=call->core;
	LinphoneCall *current=linphone_core_get_current_call(lc);
	return !linphone_core_is_in_conference(lc) &&
		(current==NULL || current==call);
673 674
}

675
void linphone_call_delete_upnp_session(LinphoneCall *call){
676 677
}

678
void linphone_call_stop_media_streams(LinphoneCall *call){
679 680
}

jehan's avatar
jehan committed
681
void linphone_call_enable_echo_cancellation(LinphoneCall *call, bool_t enable) {
682
	linphone_call_get_cpp_obj(call)->enableEchoCancellation(enable);
jehan's avatar
jehan committed
683
}
684

685 686
bool_t linphone_call_echo_cancellation_enabled(const LinphoneCall *call) {
	return linphone_call_get_cpp_obj(call)->echoCancellationEnabled();
jehan's avatar
jehan committed
687 688
}

689 690
void linphone_call_enable_echo_limiter(LinphoneCall *call, bool_t val) {
	linphone_call_get_cpp_obj(call)->enableEchoLimiter(val);
jehan's avatar
jehan committed
691 692
}

693 694
bool_t linphone_call_echo_limiter_enabled(const LinphoneCall *call) {
	return linphone_call_get_cpp_obj(call)->echoLimiterEnabled();
jehan's avatar
jehan committed
695 696
}

697 698
float linphone_call_get_play_volume(const LinphoneCall *call) {
	return linphone_call_get_cpp_obj(call)->getPlayVolume();
Simon Morlat's avatar
Simon Morlat committed
699 700
}

701 702
float linphone_call_get_record_volume(const LinphoneCall *call) {
	return linphone_call_get_cpp_obj(call)->getRecordVolume();
Simon Morlat's avatar
Simon Morlat committed
703 704
}

705
float linphone_call_get_speaker_volume_gain(const LinphoneCall *call) {
706
	return linphone_call_get_cpp_obj(call)->getSpeakerVolumeGain();
707 708
}

709
void linphone_call_set_speaker_volume_gain(LinphoneCall *call, float volume) {
710
	linphone_call_get_cpp_obj(call)->setSpeakerVolumeGain(volume);
711 712
}

713
float linphone_call_get_microphone_volume_gain(const LinphoneCall *call) {
714
	return linphone_call_get_cpp_obj(call)->getMicrophoneVolumeGain();
715 716
}

717
void linphone_call_set_microphone_volume_gain(LinphoneCall *call, float volume) {
718
	linphone_call_get_cpp_obj(call)->setMicrophoneVolumeGain(volume);
719
}
720

721 722
float linphone_call_get_current_quality(const LinphoneCall *call) {
	return linphone_call_get_cpp_obj(call)->getCurrentQuality();
723 724
}

725 726
float linphone_call_get_average_quality(const LinphoneCall *call) {
	return linphone_call_get_cpp_obj(call)->getAverageQuality();
727 728
}

729
void linphone_call_stats_update(LinphoneCallStats *stats, MediaStream *stream) {
730 731
	PayloadType *pt;
	RtpSession *session = stream->sessions.rtp_session;
732
	const MSQualityIndicator *qi = media_stream_get_quality_indicator(stream);
733 734 735 736
	if (qi) {
		stats->local_late_rate=ms_quality_indicator_get_local_late_rate(qi);
		stats->local_loss_rate=ms_quality_indicator_get_local_loss_rate(qi);
	}
737
	media_stream_get_local_rtp_stats(stream, &stats->rtp_stats);
738 739
	pt = rtp_profile_get_payload(rtp_session_get_profile(session), rtp_session_get_send_payload_type(session));
	stats->clockrate = pt ? pt->clock_rate : 8000;
740 741
}

742 743
MediaStream * linphone_call_get_stream(LinphoneCall *call, LinphoneStreamType type) {
	return L_GET_PRIVATE(linphone_call_get_cpp_obj(call).get())->getMediaStream(type);
Simon Morlat's avatar
Simon Morlat committed
744 745
}

746
void _linphone_call_stats_clone(LinphoneCallStats *dst, const LinphoneCallStats *src) {
747 748 749 750 751 752 753 754 755 756 757
	/*
	 * Save the belle_sip_object_t part, copy the entire structure and restore the belle_sip_object_t part
	 */
	belle_sip_object_t tmp = dst->base;
	memcpy(dst, src, sizeof(LinphoneCallStats));
	dst->base = tmp;

	dst->received_rtcp = NULL;
	dst->sent_rtcp = NULL;
}

758 759
LinphoneCallStats *linphone_call_get_stats(LinphoneCall *call, LinphoneStreamType type) {
	return linphone_call_get_cpp_obj(call)->getStats(type);
760 761
}

762
LinphoneCallStats *linphone_call_get_audio_stats(LinphoneCall *call) {
763
	return linphone_call_get_cpp_obj(call)->getAudioStats();
764 765
}

766
LinphoneCallStats *linphone_call_get_video_stats(LinphoneCall *call) {
767
	return linphone_call_get_cpp_obj(call)->getVideoStats();
768 769
}

770
LinphoneCallStats *linphone_call_get_text_stats(LinphoneCall *call) {
771
	return linphone_call_get_cpp_obj(call)->getTextStats();
Simon Morlat's avatar
Simon Morlat committed
772 773
}

774 775
bool_t linphone_call_media_in_progress(const LinphoneCall *call) {
	return linphone_call_get_cpp_obj(call)->mediaInProgress();
Simon Morlat's avatar
Simon Morlat committed
776 777
}

778 779 780 781 782 783
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneCallStats);

BELLE_SIP_INSTANCIATE_VPTR(LinphoneCallStats, belle_sip_object_t,
	NULL, // destroy
	_linphone_call_stats_clone, // clone
	NULL, // marshal
784
	TRUE
785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807
);

LinphoneCallStats *linphone_call_stats_new() {
	LinphoneCallStats *stats = belle_sip_object_new(LinphoneCallStats);
	return stats;
}

LinphoneCallStats* linphone_call_stats_ref(LinphoneCallStats* stats) {
	return (LinphoneCallStats*) belle_sip_object_ref(stats);
}

void linphone_call_stats_unref(LinphoneCallStats* stats) {
	belle_sip_object_unref(stats);
}

void *linphone_call_stats_get_user_data(const LinphoneCallStats *stats) {
	return stats->user_data;
}

void linphone_call_stats_set_user_data(LinphoneCallStats *stats, void *data) {
	stats->user_data = data;
}

808 809 810 811
LinphoneStreamType linphone_call_stats_get_type(const LinphoneCallStats *stats) {
	return stats->type;
}

812
float linphone_call_stats_get_sender_loss_rate(const LinphoneCallStats *stats) {
813 814 815 816 817 818 819
	const report_block_t *srb = NULL;

	if (!stats || !stats->sent_rtcp)
		return 0.0;
	/* Perform msgpullup() to prevent crashes in rtcp_is_SR() or rtcp_is_RR() if the RTCP packet is composed of several mblk_t structure */
	if (stats->sent_rtcp->b_cont != NULL)
		msgpullup(stats->sent_rtcp, -1);
820

821 822 823 824 825 826 827 828
	do{
		if (rtcp_is_SR(stats->sent_rtcp))
			srb = rtcp_SR_get_report_block(stats->sent_rtcp, 0);
		else if (rtcp_is_RR(stats->sent_rtcp))
			srb = rtcp_RR_get_report_block(stats->sent_rtcp, 0);
		if (srb) break;
	}while (rtcp_next_packet(stats->sent_rtcp));
	rtcp_rewind(stats->sent_rtcp);
829 830
	if (!srb)
		return 0.0;
831
	return 100.0f * report_block_get_fraction_lost(srb) / 256.0f;
832 833
}

834
float linphone_call_stats_get_receiver_loss_rate(const LinphoneCallStats *stats) {
835 836 837 838 839 840 841
	const report_block_t *rrb = NULL;

	if (!stats || !stats->received_rtcp)
		return 0.0;
	/* Perform msgpullup() to prevent crashes in rtcp_is_SR() or rtcp_is_RR() if the RTCP packet is composed of several mblk_t structure */
	if (stats->received_rtcp->b_cont != NULL)
		msgpullup(stats->received_rtcp, -1);
842

843 844 845 846 847 848
	do{
		if (rtcp_is_RR(stats->received_rtcp))
			rrb = rtcp_RR_get_report_block(stats->received_rtcp, 0);
		else if (rtcp_is_SR(stats->received_rtcp))
			rrb = rtcp_SR_get_report_block(stats->received_rtcp, 0);
		if (rrb) break;
849 850
	}while (rtcp_next_packet(stats->received_rtcp));
	rtcp_rewind(stats->received_rtcp);
851 852
	if (!rrb)
		return 0.0;
853
	return 100.0f * report_block_get_fraction_lost(rrb) / 256.0f;
854 855
}

856 857 858 859 860 861 862 863
float linphone_call_stats_get_local_loss_rate(const LinphoneCallStats *stats) {
	return stats->local_loss_rate;
}

float linphone_call_stats_get_local_late_rate(const LinphoneCallStats *stats) {
	return stats->local_late_rate;
}

864
float linphone_call_stats_get_sender_interarrival_jitter(const LinphoneCallStats *stats) {
865
	const report_block_t *srb = NULL;
866

867
	if (!stats || !stats->sent_rtcp)
868 869 870 871 872 873 874 875 876 877
		return 0.0;
	/* Perform msgpullup() to prevent crashes in rtcp_is_SR() or rtcp_is_RR() if the RTCP packet is composed of several mblk_t structure */
	if (stats->sent_rtcp->b_cont != NULL)
		msgpullup(stats->sent_rtcp, -1);
	if (rtcp_is_SR(stats->sent_rtcp))
		srb = rtcp_SR_get_report_block(stats->sent_rtcp, 0);
	else if (rtcp_is_RR(stats->sent_rtcp))
		srb = rtcp_RR_get_report_block(stats->sent_rtcp, 0);
	if (!srb)
		return 0.0;
878
	if (stats->clockrate == 0)
879
		return 0.0;
880
	return (float)report_block_get_interarrival_jitter(srb) / (float)stats->clockrate;
881 882
}

883
float linphone_call_stats_get_receiver_interarrival_jitter(const LinphoneCallStats *stats) {
884 885
	const report_block_t *rrb = NULL;

886
	if (!stats || !stats->received_rtcp)
887 888 889 890 891 892 893 894 895 896
		return 0.0;
	/* Perform msgpullup() to prevent crashes in rtcp_is_SR() or rtcp_is_RR() if the RTCP packet is composed of several mblk_t structure */
	if (stats->received_rtcp->b_cont != NULL)
		msgpullup(stats->received_rtcp, -1);
	if (rtcp_is_SR(stats->received_rtcp))
		rrb = rtcp_SR_get_report_block(stats->received_rtcp, 0);
	else if (rtcp_is_RR(stats->received_rtcp))
		rrb = rtcp_RR_get_report_block(stats->received_rtcp, 0);
	if (!rrb)
		return 0.0;
897
	if (stats->clockrate == 0)
898
		return 0.0;
899
	return (float)report_block_get_interarrival_jitter(rrb) / (float)stats->clockrate;
900 901
}

902 903
const rtp_stats_t *linphone_call_stats_get_rtp_stats(const LinphoneCallStats *stats) {
	return &stats->rtp_stats;
904 905
}

906 907
uint64_t linphone_call_stats_get_late_packets_cumulative_number(const LinphoneCallStats *stats) {
	return linphone_call_stats_get_rtp_stats(stats)->outoftime;
908 909
}

910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925
float linphone_call_stats_get_download_bandwidth(const LinphoneCallStats *stats) {
	return stats->download_bandwidth;
}

float linphone_call_stats_get_upload_bandwidth(const LinphoneCallStats *stats) {
	return stats->upload_bandwidth;
}

LinphoneIceState linphone_call_stats_get_ice_state(const LinphoneCallStats *stats) {
	return stats->ice_state;
}

LinphoneUpnpState linphone_call_stats_get_upnp_state(const LinphoneCallStats *stats) {
	return stats->upnp_state;
}

926 927 928 929 930 931 932 933
LinphoneAddressFamily linphone_call_stats_get_ip_family_of_remote(const LinphoneCallStats *stats) {
	return (LinphoneAddressFamily)stats->rtp_remote_family;
}

float linphone_call_stats_get_jitter_buffer_size_ms(const LinphoneCallStats *stats) {
	return stats->jitter_stats.jitter_buffer_size_ms;
}

934 935 936 937
float linphone_call_stats_get_round_trip_delay(const LinphoneCallStats *stats) {
	return stats->round_trip_delay;
}

938 939
void linphone_call_start_recording(LinphoneCall *call) {
	linphone_call_get_cpp_obj(call)->startRecording();
940 941
}

942 943
void linphone_call_stop_recording(LinphoneCall *call) {
	linphone_call_get_cpp_obj(call)->stopRecording();
944 945
}

946
static void linphone_call_lost(LinphoneCall *call){
947 948
	LinphoneCore *lc = call->core;
	char *temp = NULL;
949
	char *from = NULL;
Simon Morlat's avatar
Simon Morlat committed
950 951

	from = linphone_call_get_remote_address_as_string(call);
952
	temp = ms_strdup_printf("Media connectivity with %s is lost, call is going to be closed.", from ? from : "?");
Simon Morlat's avatar
Simon Morlat committed
953
	if (from) ms_free(from);
954
	ms_message("LinphoneCall [%p]: %s", call, temp);
955
	linphone_core_notify_display_warning(lc, temp);
956
	call->non_op_error = TRUE;
957
	linphone_error_info_set(call->ei,NULL, LinphoneReasonIOError, 503, "Media lost", NULL);
958
	linphone_call_terminate(call);
959
	linphone_core_play_named_tone(lc, LinphoneToneCallLost);
960
	ms_free(temp);
961 962
}

Simon Morlat's avatar
Simon Morlat committed
963
/*do not change the prototype of this function, it is also used internally in linphone-daemon.*/
Simon Morlat's avatar
Simon Morlat committed
964 965 966
void linphone_call_stats_fill(LinphoneCallStats *stats, MediaStream *ms, OrtpEvent *ev){
	OrtpEventType evt=ortp_event_get_type(ev);
	OrtpEventData *evd=ortp_event_get_data(ev);
967

Simon Morlat's avatar
Simon Morlat committed
968 969 970 971 972
	if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) {
		stats->round_trip_delay = rtp_session_get_round_trip_propagation(ms->sessions.rtp_session);
		if(stats->received_rtcp != NULL)
			freemsg(stats->received_rtcp);
		stats->received_rtcp = evd->packet;
Simon Morlat's avatar
Simon Morlat committed
973
		stats->rtcp_received_via_mux = evd->info.socket_type == OrtpRTPSocket;
Simon Morlat's avatar
Simon Morlat committed
974 975
		evd->packet = NULL;
		stats->updated = LINPHONE_CALL_STATS_RECEIVED_RTCP_UPDATE;
976
		linphone_call_stats_update(stats,ms);
Simon Morlat's avatar
Simon Morlat committed
977 978 979 980 981 982 983
	} else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) {
		memcpy(&stats->jitter_stats, rtp_session_get_jitter_stats(ms->sessions.rtp_session), sizeof(jitter_stats_t));
		if (stats->sent_rtcp != NULL)
			freemsg(stats->sent_rtcp);
		stats->sent_rtcp = evd->packet;
		evd->packet = NULL;
		stats->updated = LINPHONE_CALL_STATS_SENT_RTCP_UPDATE;
984
		linphone_call_stats_update(stats,ms);
Simon Morlat's avatar
Simon Morlat committed
985 986 987
	}
}

Simon Morlat's avatar
Simon Morlat committed
988 989 990 991 992 993 994 995 996 997 998
void linphone_call_stats_uninit(LinphoneCallStats *stats){
	if (stats->received_rtcp) {
		freemsg(stats->received_rtcp);
		stats->received_rtcp=NULL;
	}
	if (stats->sent_rtcp){
		freemsg(stats->sent_rtcp);
		stats->sent_rtcp=NULL;
	}
}

999
LinphoneCallState linphone_call_get_transfer_state(LinphoneCall *call) {
1000
#if 0
1001
	return call->transfer_state;
1002 1003 1004
#else
	return LinphoneCallIdle;
#endif
1005 1006 1007
}

void linphone_call_set_transfer_state(LinphoneCall* call, LinphoneCallState state) {
1008
#if 0
1009
	if (state != call->transfer_state) {
jehan's avatar
jehan committed
1010
		ms_message("Transfer state for call [%p] changed  from [%s] to [%s]",call
Simon Morlat's avatar
Simon Morlat committed
1011 1012
						,linphone_call_state_to_string(call->transfer_state)
						,linphone_call_state_to_string(state));
1013
		call->transfer_state = state;
1014
		linphone_call_notify_transfer_state_changed(call, state);
1015
	}
1016
#endif
1017
}
1018

jehan's avatar
jehan committed
1019
bool_t linphone_call_is_in_conference(const LinphoneCall *call) {
1020
#if 0
1021
	return linphone_call_params_get_in_conference(call->params);