conference.cc 38.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
/*******************************************************************************
 *            conference.cc
 *
 *  Thu Nov 26, 2015
 *  Copyright  2015  Belledonne Communications
 *  Author: Linphone's team
 *  Email info@belledonne-communications.com
 ******************************************************************************/

/*
 *  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
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

26
#include <algorithm>
27
#include <list>
28
#include <string>
29 30 31 32 33 34 35 36 37
#include <typeinfo>

#include <mediastreamer2/msvolume.h>

#include "linphone/core.h"

#include "conference_private.h"

#include "c-wrapper/c-wrapper.h"
Ghislain MARY's avatar
Ghislain MARY committed
38 39 40
#include "call/call-p.h"
#include "conference/params/media-session-params-p.h"
#include "core/core-p.h"
41

42 43 44
// TODO: From coreapi. Remove me later.
#include "private.h"

45 46
using namespace std;

47
namespace Linphone {
48

49
template <typename _type>
50 51
inline list<_type> toStd(const bctbx_list_t *l){
	list<_type> ret;
52 53 54 55 56
	for(; l != NULL; l = l->next){
		ret.push_back(static_cast<_type>(l->data));
	}
	return ret;
}
57

58 59
class Conference {
public:
60 61
	class Participant {
	public:
62 63 64 65
		Participant(LinphoneCall *call) {
			m_uri = linphone_address_clone(linphone_call_get_remote_address(call));
			m_call = call;
		}
66

67 68
		~Participant() {
			linphone_address_unref(m_uri);
Ghislain MARY's avatar
Ghislain MARY committed
69 70
			if(m_call)
				_linphone_call_set_conf_ref(m_call, nullptr);
71
		}
72

73 74 75
		const LinphoneAddress *getUri() const {
			return m_uri;
		}
76

77 78 79
		LinphoneCall *getCall() const {
			return m_call;
		}
80

81
	private:
82
		Participant(const Participant &src);
83
		Participant &operator=(const Participant &src);
84

85 86 87
	private:
		LinphoneAddress *m_uri;
		LinphoneCall *m_call;
88

89
	friend class RemoteConference;
90
	};
91 92


93 94
	class Params {
	public:
95 96 97 98 99 100 101 102 103
		Params(const LinphoneCore *core = NULL) {
			m_enableVideo = false;
			if(core) {
				const LinphoneVideoPolicy *policy = linphone_core_get_video_policy(core);
				if(policy->automatically_initiate) m_enableVideo = true;
			}
			m_stateChangedCb = NULL;
			m_userData = NULL;
		}
104 105
		void enableVideo(bool enable) {m_enableVideo = enable;}
		bool videoRequested() const {return m_enableVideo;}
106
		void setStateChangedCallback(LinphoneConferenceStateChangedCb cb, void *userData) {
107
			m_stateChangedCb = cb;
108
			m_userData = userData;
109
		}
110 111
	private:
		bool m_enableVideo;
112
		LinphoneConferenceStateChangedCb m_stateChangedCb;
113
		void *m_userData;
114
		friend class Conference;
115
  };
116

Ghislain MARY's avatar
Ghislain MARY committed
117
	Conference(LinphoneCore *core, LinphoneConference *conf, const Params *params = NULL);
118 119
	virtual ~Conference() {}

120
	const Params &getCurrentParams() const {return m_currentParams;}
121

122
	virtual int inviteAddresses(const list<const LinphoneAddress*> &addresses, const LinphoneCallParams *params) = 0;
123 124 125
	virtual int addParticipant(LinphoneCall *call) = 0;
	virtual int removeParticipant(LinphoneCall *call) = 0;
	virtual int removeParticipant(const LinphoneAddress *uri) = 0;
126
	virtual int terminate() = 0;
127

128 129 130
	virtual int enter() = 0;
	virtual int leave() = 0;
	virtual bool isIn() const = 0;
131

132 133 134 135
	AudioStream *getAudioStream() const {return m_localParticipantStream;}
	int muteMicrophone(bool val);
	bool microphoneIsMuted() const {return m_isMuted;}
	float getInputVolume() const;
136

137
	virtual int getSize() const {return (int)m_participants.size() + (isIn()?1:0);}
138
	const list<Participant *> &getParticipants() const {return m_participants;}
139

140 141
	virtual int startRecording(const char *path) = 0;
	virtual int stopRecording() = 0;
142

143 144 145
	virtual void onCallStreamStarting(LinphoneCall *call, bool isPausedByRemote) {};
	virtual void onCallStreamStopping(LinphoneCall *call) {};
	virtual void onCallTerminating(LinphoneCall *call) {};
146

147
	LinphoneConferenceState getState() const {return m_state;}
148 149 150
	LinphoneCore *getCore()const{
		return m_core;
	}
151
	static const char *stateToString(LinphoneConferenceState state);
152

153 154 155 156 157 158
	void setID(const char *conferenceID) {
		m_conferenceID = conferenceID;
	}
	const char *getID() {
		return m_conferenceID.c_str();
	}
159

160
protected:
161
	void setState(LinphoneConferenceState state);
162 163
	Participant *findParticipant(const LinphoneCall *call) const;
	Participant *findParticipant(const LinphoneAddress *uri) const;
164

165
protected:
166
	string m_conferenceID;
167
	LinphoneCore *m_core;
168 169
	AudioStream *m_localParticipantStream;
	bool m_isMuted;
170
	list<Participant *> m_participants;
171
	Params m_currentParams;
172
	LinphoneConferenceState m_state;
173
  LinphoneConference *m_conference;
174 175 176 177
};

class LocalConference: public Conference {
public:
Ghislain MARY's avatar
Ghislain MARY committed
178
	LocalConference(LinphoneCore *core, LinphoneConference *conf, const Params *params = NULL);
179
	virtual ~LocalConference();
180

181 182 183 184 185 186 187 188 189 190 191 192
	virtual int inviteAddresses(const list<const LinphoneAddress*> &addresses, const LinphoneCallParams *params) override;
	virtual int addParticipant(LinphoneCall *call) override;
	virtual int removeParticipant(LinphoneCall *call) override;
	virtual int removeParticipant(const LinphoneAddress *uri) override;
	virtual int terminate() override;

	virtual int enter() override;
	virtual int leave() override;
	virtual bool isIn() const override {
		return m_localParticipantStream!=NULL;
	}
	virtual int getSize() const override;
193

194 195
	virtual int startRecording(const char *path) override;
	virtual int stopRecording() override;
196

197 198 199
	virtual void onCallStreamStarting(LinphoneCall *call, bool isPausedByRemote) override;
	virtual void onCallStreamStopping(LinphoneCall *call) override;
	virtual void onCallTerminating(LinphoneCall *call) override;
200

201 202 203 204 205 206 207 208 209 210 211 212
private:
	void addLocalEndpoint();
	int remoteParticipantsCount();
	void removeLocalEndpoint();
	int removeFromConference(LinphoneCall *call, bool_t active);
	int convertConferenceToCall();
	static RtpProfile *sMakeDummyProfile(int samplerate);

	MSAudioConference *m_conf;
	MSAudioEndpoint *m_localEndpoint;
	MSAudioEndpoint *m_recordEndpoint;
	RtpProfile *m_localDummyProfile;
Ghislain MARY's avatar
Ghislain MARY committed
213
	bool_t m_terminating;
214 215 216 217
};

class RemoteConference: public Conference {
public:
Ghislain MARY's avatar
Ghislain MARY committed
218
	RemoteConference(LinphoneCore *core, LinphoneConference *conf, const Params *params = NULL);
219
	virtual ~RemoteConference();
220

221 222 223 224 225 226 227
	virtual int inviteAddresses(const list<const LinphoneAddress*> &addresses, const LinphoneCallParams *params) override;
	virtual int addParticipant(LinphoneCall *call) override;
	virtual int removeParticipant(LinphoneCall *call) override {
		return -1;
	}
	virtual int removeParticipant(const LinphoneAddress *uri) override;
	virtual int terminate() override;
228

229 230 231
	virtual int enter() override;
	virtual int leave() override;
	virtual bool isIn() const override;
232

233 234 235 236 237 238
	virtual int startRecording (const char *path) override {
		return 0;
	}
	virtual int stopRecording() override {
		return 0;
	}
239 240

private:
241 242 243
	bool focusIsReady() const;
	bool transferToFocus(LinphoneCall *call);
	void reset();
244

245 246
	void onFocusCallSateChanged(LinphoneCallState state);
	void onPendingCallStateChanged(LinphoneCall *call, LinphoneCallState state);
247
	void onTransferingCallStateChanged(LinphoneCall *transfered, LinphoneCallState newCallState);
248

249 250
	static void callStateChangedCb(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *message);
	static void transferStateChanged(LinphoneCore *lc, LinphoneCall *transfered, LinphoneCallState new_call_state);
251

252 253 254
	const char *m_focusAddr;
	char *m_focusContact;
	LinphoneCall *m_focusCall;
255
	LinphoneCoreCbs *m_coreCbs;
256 257
	list<LinphoneCall *> m_pendingCalls;
	list<LinphoneCall *> m_transferingCalls;
258
};
259

260 261
};

262

263
using namespace Linphone;
264 265 266
using namespace std;


Ghislain MARY's avatar
Ghislain MARY committed
267
Conference::Conference(LinphoneCore *core, LinphoneConference *conf, const Conference::Params *params) :
268
	m_core(core),
Ghislain MARY's avatar
Ghislain MARY committed
269
	m_localParticipantStream(nullptr),
270 271
	m_isMuted(false),
	m_currentParams(),
Ghislain MARY's avatar
Ghislain MARY committed
272 273
	m_state(LinphoneConferenceStopped),
	m_conference(conf) {
Ghislain MARY's avatar
Ghislain MARY committed
274 275
	if (params)
		m_currentParams = *params;
276 277
}

Ghislain MARY's avatar
Ghislain MARY committed
278 279
int Conference::addParticipant (LinphoneCall *call) {
	Participant *p = new Participant(call);
280
	m_participants.push_back(p);
Ghislain MARY's avatar
Ghislain MARY committed
281
	_linphone_call_set_conf_ref(call, m_conference);
282 283 284
	return 0;
}

Ghislain MARY's avatar
Ghislain MARY committed
285
int Conference::removeParticipant (LinphoneCall *call) {
286
	Participant *p = findParticipant(call);
Ghislain MARY's avatar
Ghislain MARY committed
287 288
	if (!p)
		return -1;
289 290
	delete p;
	m_participants.remove(p);
291 292 293
	return 0;
}

Ghislain MARY's avatar
Ghislain MARY committed
294
int Conference::removeParticipant (const LinphoneAddress *uri) {
295
	Participant *p = findParticipant(uri);
Ghislain MARY's avatar
Ghislain MARY committed
296 297
	if (!p)
		return -1;
298 299
	delete p;
	m_participants.remove(p);
300 301 302
	return 0;
}

Ghislain MARY's avatar
Ghislain MARY committed
303 304
int Conference::terminate () {
	for (auto it = m_participants.begin(); it != m_participants.end(); it++)
305 306
		delete *it;
	m_participants.clear();
307 308 309
	return 0;
}

Ghislain MARY's avatar
Ghislain MARY committed
310 311
int Conference::muteMicrophone (bool val) {
	if (val)
312
		audio_stream_set_mic_gain(m_localParticipantStream, 0);
Ghislain MARY's avatar
Ghislain MARY committed
313
	else
314
		audio_stream_set_mic_gain_db(m_localParticipantStream, m_core->sound_conf.soft_mic_lev);
Ghislain MARY's avatar
Ghislain MARY committed
315
	if (linphone_core_get_rtp_no_xmit_on_audio_mute(m_core))
316
		audio_stream_mute_rtp(m_localParticipantStream, val);
Ghislain MARY's avatar
Ghislain MARY committed
317
	m_isMuted = val;
318 319 320
	return 0;
}

Ghislain MARY's avatar
Ghislain MARY committed
321 322 323 324 325
float Conference::getInputVolume () const {
	AudioStream *st = m_localParticipantStream;
	if (st && st->volsend && !m_isMuted) {
		float vol = 0;
		ms_filter_call_method(st->volsend, MS_VOLUME_GET, &vol);
326 327 328
		return vol;
	}
	return LINPHONE_VOLUME_DB_LOWEST;
329 330
}

Ghislain MARY's avatar
Ghislain MARY committed
331
const char *Conference::stateToString (LinphoneConferenceState state) {
332
	switch(state) {
Ghislain MARY's avatar
Ghislain MARY committed
333 334 335 336 337 338 339 340 341 342
		case LinphoneConferenceStopped:
			return "Stopped";
		case LinphoneConferenceStarting:
			return "Starting";
		case LinphoneConferenceRunning:
			return "Ready";
		case LinphoneConferenceStartingFailed:
			return "Starting failed";
		default:
			return "Invalid state";
343 344 345 346 347
	}
}



Ghislain MARY's avatar
Ghislain MARY committed
348 349
void Conference::setState (LinphoneConferenceState state) {
	if (m_state != state) {
350 351
		ms_message("Switching conference [%p] into state '%s'", this, stateToString(state));
		m_state = state;
Ghislain MARY's avatar
Ghislain MARY committed
352
		if (m_currentParams.m_stateChangedCb)
Ghislain MARY's avatar
Ghislain MARY committed
353
			m_currentParams.m_stateChangedCb(m_conference, state, m_currentParams.m_userData);
354 355 356
	}
}

Ghislain MARY's avatar
Ghislain MARY committed
357 358 359 360
Conference::Participant *Conference::findParticipant (const LinphoneCall *call) const {
	for (auto it = m_participants.begin(); it != m_participants.end(); it++) {
		if ((*it)->getCall() == call)
			return *it;
361
	}
Ghislain MARY's avatar
Ghislain MARY committed
362
	return nullptr;
363 364
}

Ghislain MARY's avatar
Ghislain MARY committed
365 366 367 368
Conference::Participant *Conference::findParticipant (const LinphoneAddress *uri) const {
	for (auto it = m_participants.begin(); it != m_participants.end(); it++) {
		if (linphone_address_equal((*it)->getUri(), uri))
			return *it;
369
	}
Ghislain MARY's avatar
Ghislain MARY committed
370
	return nullptr;
371 372
}

373

374 375


Ghislain MARY's avatar
Ghislain MARY committed
376
LocalConference::LocalConference (LinphoneCore *core, LinphoneConference *conf, const Conference::Params *params) :
Ghislain MARY's avatar
Ghislain MARY committed
377
	Conference(core, conf, params),
Ghislain MARY's avatar
Ghislain MARY committed
378 379 380 381 382
	m_conf(nullptr),
	m_localEndpoint(nullptr),
	m_recordEndpoint(nullptr),
	m_localDummyProfile(nullptr),
	m_terminating(FALSE) {
383
	MSAudioConferenceParams ms_conf_params;
Ghislain MARY's avatar
Ghislain MARY committed
384 385 386
	ms_conf_params.samplerate = lp_config_get_int(m_core->config, "sound", "conference_rate", 16000);
	m_conf = ms_audio_conference_new(&ms_conf_params, core->factory);
	m_state = LinphoneConferenceRunning;
387 388
}

389
LocalConference::~LocalConference() {
390 391
	terminate();
	ms_audio_conference_destroy(m_conf);
392 393
}

Ghislain MARY's avatar
Ghislain MARY committed
394 395 396 397 398
RtpProfile *LocalConference::sMakeDummyProfile (int samplerate) {
	RtpProfile *prof = rtp_profile_new("dummy");
	PayloadType *pt = payload_type_clone(&payload_type_l16_mono);
	pt->clock_rate = samplerate;
	rtp_profile_set_payload(prof, 0, pt);
399 400 401
	return prof;
}

Ghislain MARY's avatar
Ghislain MARY committed
402 403
void LocalConference::addLocalEndpoint () {
	/* Create a dummy audiostream in order to extract the local part of it */
404
	/* network address and ports have no meaning and are not used here. */
Ghislain MARY's avatar
Ghislain MARY committed
405 406 407 408 409 410 411
	AudioStream *st = audio_stream_new(m_core->factory, 65000, 65001, FALSE);
	MSSndCard *playcard = m_core->sound_conf.lsd_card
		? m_core->sound_conf.lsd_card
		: m_core->sound_conf.play_sndcard;
	MSSndCard *captcard = m_core->sound_conf.capt_sndcard;
	const MSAudioConferenceParams *params = ms_audio_conference_get_params(m_conf);
	m_localDummyProfile = sMakeDummyProfile(params->samplerate);
412 413 414 415 416 417 418
	audio_stream_start_full(st, m_localDummyProfile,
				"127.0.0.1",
				65000,
				"127.0.0.1",
				65001,
				0,
				40,
Ghislain MARY's avatar
Ghislain MARY committed
419 420
				nullptr,
				nullptr,
421 422 423 424
				playcard,
				captcard,
				linphone_core_echo_cancellation_enabled(m_core)
				);
Ghislain MARY's avatar
Ghislain MARY committed
425 426 427 428 429
	_post_configure_audio_stream(st, m_core, FALSE);
	m_localParticipantStream = st;
	m_localEndpoint = ms_audio_endpoint_get_from_stream(st, FALSE);
	ms_message("Conference: adding local endpoint");
	ms_audio_conference_add_member(m_conf, m_localEndpoint);
430 431
}

Ghislain MARY's avatar
Ghislain MARY committed
432
int LocalConference::inviteAddresses (const list<const LinphoneAddress *> &addresses, const LinphoneCallParams *params) {
433
	for (const auto &address : addresses) {
Ghislain MARY's avatar
Ghislain MARY committed
434
		LinphoneCall *call = linphone_core_get_call_by_remote_address2(m_core, address);
435
		if (!call) {
Ghislain MARY's avatar
Ghislain MARY committed
436 437 438 439 440
			/* Start a new call by indicating that it has to be put into the conference directly */
			LinphoneCallParams *new_params = params
				? linphone_call_params_copy(params)
				: linphone_core_create_call_params(m_core, nullptr);
			/* Toggle this flag so the call is immediately added to the conference upon acceptance */
441
			linphone_call_params_set_in_conference(new_params, TRUE);
Ghislain MARY's avatar
Ghislain MARY committed
442 443
			/* Turn off video as it is not supported for conferencing at this time */
			linphone_call_params_enable_video(new_params, FALSE);
444
			call = linphone_core_invite_address_with_params(m_core, address, new_params);
Ghislain MARY's avatar
Ghislain MARY committed
445
			if (!call)
446 447
				ms_error("LocalConference::inviteAddresses(): could not invite participant");
			linphone_call_params_unref(new_params);
Ghislain MARY's avatar
Ghislain MARY committed
448 449
		} else {
			/* There is already a call to this address, so simply join it to the local conference if not already done */
450
			if (!linphone_call_params_get_in_conference(linphone_call_get_current_params(call)))
451 452
				addParticipant(call);
		}
Ghislain MARY's avatar
Ghislain MARY committed
453 454 455
		/* If the local participant is not yet created, created it and it to the conference */
		if (!m_localEndpoint)
			addLocalEndpoint();
456 457 458 459
	}
	return 0;
}

Ghislain MARY's avatar
Ghislain MARY committed
460 461
int LocalConference::addParticipant (LinphoneCall *call) {
	if (linphone_call_params_get_in_conference(linphone_call_get_current_params(call))) {
462 463 464 465
		ms_error("Already in conference");
		return -1;
	}

Ghislain MARY's avatar
Ghislain MARY committed
466 467 468 469 470
	if (linphone_call_get_state(call) == LinphoneCallPaused) {
		const_cast<LinphonePrivate::MediaSessionParamsPrivate *>(
			L_GET_PRIVATE(L_GET_CPP_PTR_FROM_C_OBJECT(call)->getParams()))->setInConference(true);
		const_cast<LinphonePrivate::MediaSessionParams *>(
			L_GET_CPP_PTR_FROM_C_OBJECT(call)->getParams())->enableVideo(false);
471
		linphone_call_resume(call);
Ghislain MARY's avatar
Ghislain MARY committed
472
	} else if (linphone_call_get_state(call) == LinphoneCallStreamsRunning) {
473
		LinphoneCallParams *params = linphone_core_create_call_params(m_core, call);
474 475
		linphone_call_params_set_in_conference(params, TRUE);
		linphone_call_params_enable_video(params, FALSE);
476

Ghislain MARY's avatar
Ghislain MARY committed
477 478 479
		if (L_GET_PRIVATE_FROM_C_OBJECT(call)->getMediaStream(LinphoneStreamTypeAudio)
			|| L_GET_PRIVATE_FROM_C_OBJECT(call)->getMediaStream(LinphoneStreamTypeVideo)) {
			linphone_call_stop_media_streams(call); /* Free the audio & video local resources */
480 481
			linphone_call_init_media_streams(call);
		}
Ghislain MARY's avatar
Ghislain MARY committed
482 483 484 485 486
		if (call == linphone_core_get_current_call(m_core))
			L_GET_PRIVATE_FROM_C_OBJECT(m_core)->setCurrentCall(nullptr);
		/* This will trigger a reINVITE that will later redraw the streams */
		/* FIXME: probably a bit too much to just redraw streams! */
		linphone_call_update(call, params);
Simon Morlat's avatar
Simon Morlat committed
487
		linphone_call_params_unref(params);
488
		addLocalEndpoint();
Ghislain MARY's avatar
Ghislain MARY committed
489 490 491
	} else {
		ms_error("Call is in state %s, it cannot be added to the conference",
			linphone_call_state_to_string(linphone_call_get_state(call)));
492 493 494 495 496
		return -1;
	}
	return 0;
}

Ghislain MARY's avatar
Ghislain MARY committed
497 498 499
int LocalConference::removeFromConference (LinphoneCall *call, bool_t active) {
	if (!linphone_call_params_get_in_conference(linphone_call_get_current_params(call))) {
		if (linphone_call_params_get_in_conference(linphone_call_get_params(call))) {
500 501
			ms_warning("Not (yet) in conference, be patient");
			return -1;
Ghislain MARY's avatar
Ghislain MARY committed
502 503
		} else {
			ms_error("Not in a conference");
504 505 506
			return -1;
		}
	}
Ghislain MARY's avatar
Ghislain MARY committed
507 508
	const_cast<LinphonePrivate::MediaSessionParamsPrivate *>(
		L_GET_PRIVATE(L_GET_CPP_PTR_FROM_C_OBJECT(call)->getParams()))->setInConference(false);
509

Ghislain MARY's avatar
Ghislain MARY committed
510
	char *str = linphone_call_get_remote_address_as_string(call);
511 512
	ms_message("%s will be removed from conference", str);
	ms_free(str);
Ghislain MARY's avatar
Ghislain MARY committed
513 514 515
	int err = 0;
	if (active) {
		LinphoneCallParams *params = linphone_call_params_copy(linphone_call_get_current_params(call));
516
		linphone_call_params_set_in_conference(params, FALSE);
Ghislain MARY's avatar
Ghislain MARY committed
517
		// Reconnect local audio with this call
518
		if (isIn()){
Ghislain MARY's avatar
Ghislain MARY committed
519
			ms_message("Leaving conference for reconnecting with unique call");
520
			leave();
521 522
		}
		ms_message("Updating call to actually remove from conference");
Ghislain MARY's avatar
Ghislain MARY committed
523
		err = linphone_call_update(call, params);
Simon Morlat's avatar
Simon Morlat committed
524
		linphone_call_params_unref(params);
Ghislain MARY's avatar
Ghislain MARY committed
525
	} else {
526
		ms_message("Pausing call to actually remove from conference");
Ghislain MARY's avatar
Ghislain MARY committed
527
		err = _linphone_call_pause(call);
528 529 530 531
	}
	return err;
}

Ghislain MARY's avatar
Ghislain MARY committed
532 533 534 535 536 537 538
int LocalConference::remoteParticipantsCount () {
	int count = getSize();
	if (count == 0)
		return 0;
	if (!m_localParticipantStream)
		return count;
	return count - 1;
539 540
}

Ghislain MARY's avatar
Ghislain MARY committed
541 542 543
int LocalConference::convertConferenceToCall () {
	if (remoteParticipantsCount() != 1) {
		ms_error("No unique call remaining in conference");
544 545 546
		return -1;
	}

Ghislain MARY's avatar
Ghislain MARY committed
547 548 549 550 551 552
	list<shared_ptr<LinphonePrivate::Call>> calls = L_GET_CPP_PTR_FROM_C_OBJECT(m_core)->getCalls();
	for (auto it = calls.begin(); it != calls.end(); it++) {
		shared_ptr<LinphonePrivate::Call> call(*it);
		if (L_GET_PRIVATE(call->getParams())->getInConference()) {
			bool_t active_after_removed = isIn();
			return removeFromConference(L_GET_C_BACK_PTR(call), active_after_removed);
553 554
		}
	}
Ghislain MARY's avatar
Ghislain MARY committed
555
	return 0;
556 557
}

Ghislain MARY's avatar
Ghislain MARY committed
558 559
int LocalConference::removeParticipant (LinphoneCall *call) {
	char *str = linphone_call_get_remote_address_as_string(call);
560 561
	ms_message("Removing call %s from the conference", str);
	ms_free(str);
Ghislain MARY's avatar
Ghislain MARY committed
562 563 564
	int err = removeFromConference(call, FALSE);
	if (err) {
		ms_error("Error removing participant from conference");
565 566 567
		return err;
	}

Ghislain MARY's avatar
Ghislain MARY committed
568 569 570 571 572
	if (remoteParticipantsCount() == 1) {
		ms_message("Conference size is 1: need to be converted to plain call");
		err = convertConferenceToCall();
	} else
		ms_message("The conference need not to be converted as size is %i", remoteParticipantsCount());
573 574 575
	return err;
}

Ghislain MARY's avatar
Ghislain MARY committed
576
int LocalConference::removeParticipant (const LinphoneAddress *uri) {
577
	const Participant *participant = findParticipant(uri);
Ghislain MARY's avatar
Ghislain MARY committed
578 579
	if (!participant)
		return -1;
580
	LinphoneCall *call = participant->getCall();
Ghislain MARY's avatar
Ghislain MARY committed
581 582
	if (!call)
		return -1;
583 584 585
	return removeParticipant(call);
}

Ghislain MARY's avatar
Ghislain MARY committed
586 587
int LocalConference::terminate () {
	m_terminating = TRUE;
588

Ghislain MARY's avatar
Ghislain MARY committed
589 590 591 592 593
	list<shared_ptr<LinphonePrivate::Call>> calls = L_GET_CPP_PTR_FROM_C_OBJECT(m_core)->getCalls();
	for (auto it = calls.begin(); it != calls.end(); it++) {
		shared_ptr<LinphonePrivate::Call> call(*it);
		if (L_GET_PRIVATE(call->getCurrentParams())->getInConference())
			call->terminate();
594
	}
595

596
	Conference::terminate();
597
	m_terminating = FALSE;
598 599 600
	return 0;
}

Ghislain MARY's avatar
Ghislain MARY committed
601 602
int LocalConference::enter () {
	if (linphone_core_sound_resources_locked(m_core))
603
		return -1;
Ghislain MARY's avatar
Ghislain MARY committed
604 605 606 607
	if (linphone_core_get_current_call(m_core))
		_linphone_call_pause(linphone_core_get_current_call(m_core));
	if (!m_localParticipantStream)
		addLocalEndpoint();
608 609 610
	return 0;
}

Ghislain MARY's avatar
Ghislain MARY committed
611 612 613
void LocalConference::removeLocalEndpoint () {
	if (m_localEndpoint) {
		ms_audio_conference_remove_member(m_conf, m_localEndpoint);
614
		ms_audio_endpoint_release_from_stream(m_localEndpoint);
Ghislain MARY's avatar
Ghislain MARY committed
615
		m_localEndpoint = nullptr;
616
		audio_stream_stop(m_localParticipantStream);
Ghislain MARY's avatar
Ghislain MARY committed
617
		m_localParticipantStream = nullptr;
618 619 620 621
		rtp_profile_destroy(m_localDummyProfile);
	}
}

Ghislain MARY's avatar
Ghislain MARY committed
622
int LocalConference::leave () {
623
	if (isIn())
624 625 626 627
		removeLocalEndpoint();
	return 0;
}

Ghislain MARY's avatar
Ghislain MARY committed
628 629
int LocalConference::getSize () const {
	if (!m_conf)
630 631 632 633
		return 0;
	return ms_audio_conference_get_size(m_conf) - (m_recordEndpoint ? 1 : 0);
}

Ghislain MARY's avatar
Ghislain MARY committed
634 635 636
int LocalConference::startRecording (const char *path) {
	if (!m_conf) {
		ms_warning("linphone_core_start_conference_recording(): no conference now");
637 638
		return -1;
	}
Ghislain MARY's avatar
Ghislain MARY committed
639 640 641
	if (!m_recordEndpoint) {
		m_recordEndpoint = ms_audio_endpoint_new_recorder(m_core->factory);
		ms_audio_conference_add_member(m_conf, m_recordEndpoint);
642
	}
Ghislain MARY's avatar
Ghislain MARY committed
643
	ms_audio_recorder_endpoint_start(m_recordEndpoint, path);
644 645 646
	return 0;
}

Ghislain MARY's avatar
Ghislain MARY committed
647 648 649
int LocalConference::stopRecording () {
	if (!m_conf) {
		ms_warning("linphone_core_stop_conference_recording(): no conference now");
650 651
		return -1;
	}
Ghislain MARY's avatar
Ghislain MARY committed
652 653
	if (!m_recordEndpoint) {
		ms_warning("linphone_core_stop_conference_recording(): no record active");
654 655 656 657 658 659
		return -1;
	}
	ms_audio_recorder_endpoint_stop(m_recordEndpoint);
	return 0;
}

Ghislain MARY's avatar
Ghislain MARY committed
660 661 662 663 664 665 666 667 668 669 670 671
void LocalConference::onCallStreamStarting (LinphoneCall *call, bool isPausedByRemote) {
	const_cast<LinphonePrivate::MediaSessionParams *>(
		L_GET_CPP_PTR_FROM_C_OBJECT(call)->getParams())->enableVideo(false);
	L_GET_CPP_PTR_FROM_C_OBJECT(call)->enableCamera(false);
	ms_message("LocalConference::onCallStreamStarting(): joining AudioStream [%p] of call [%p] into conference",
		L_GET_PRIVATE_FROM_C_OBJECT(call)->getMediaStream(LinphoneStreamTypeAudio), call);
	MSAudioEndpoint *ep = ms_audio_endpoint_get_from_stream(
		reinterpret_cast<AudioStream *>(L_GET_PRIVATE_FROM_C_OBJECT(call)->getMediaStream(LinphoneStreamTypeAudio)),
		TRUE);
	ms_audio_conference_add_member(m_conf, ep);
	ms_audio_conference_mute_member(m_conf, ep, isPausedByRemote);
	_linphone_call_set_endpoint(call, ep);
672
	setState(LinphoneConferenceRunning);
673
	Conference::addParticipant(call);
674 675
}

Ghislain MARY's avatar
Ghislain MARY committed
676 677 678 679
void LocalConference::onCallStreamStopping (LinphoneCall *call) {
	ms_audio_conference_remove_member(m_conf, _linphone_call_get_endpoint(call));
	ms_audio_endpoint_release_from_stream(_linphone_call_get_endpoint(call));
	_linphone_call_set_endpoint(call, nullptr);
680
	Conference::removeParticipant(call);
681 682
}

Ghislain MARY's avatar
Ghislain MARY committed
683 684
void LocalConference::onCallTerminating (LinphoneCall *call) {
	int remote_count = remoteParticipantsCount();
685
	ms_message("conference_check_uninit(): size=%i", getSize());
Ghislain MARY's avatar
Ghislain MARY committed
686
	if ((remote_count == 1) && !m_terminating)
687
		convertConferenceToCall();
Ghislain MARY's avatar
Ghislain MARY committed
688
	if (remote_count == 0) {
689
		if (m_localParticipantStream)
690
			removeLocalEndpoint();
Ghislain MARY's avatar
Ghislain MARY committed
691
		if (m_recordEndpoint) {
692 693 694
			ms_audio_conference_remove_member(m_conf, m_recordEndpoint);
			ms_audio_endpoint_destroy(m_recordEndpoint);
		}
695
		setState(LinphoneConferenceStopped);
696 697 698
	}
}

699 700


Ghislain MARY's avatar
Ghislain MARY committed
701 702 703 704 705 706
RemoteConference::RemoteConference (LinphoneCore *core, LinphoneConference *conf, const Conference::Params *params) :
	Conference(core, conf, params) {
	m_focusAddr = nullptr;
	m_focusContact = nullptr;
	m_focusCall = nullptr;
	m_coreCbs = nullptr;
707
	m_focusAddr = lp_config_get_string(m_core->config, "misc", "conference_focus_addr", "");
708 709 710 711 712
	m_coreCbs = linphone_factory_create_core_cbs(linphone_factory_get());
	linphone_core_cbs_set_call_state_changed(m_coreCbs, callStateChangedCb);
	linphone_core_cbs_set_transfer_state_changed(m_coreCbs, transferStateChanged);
	linphone_core_cbs_set_user_data(m_coreCbs, this);
	_linphone_core_add_callbacks(m_core, m_coreCbs, TRUE);
713 714
}

Ghislain MARY's avatar
Ghislain MARY committed
715
RemoteConference::~RemoteConference () {
716
	terminate();
717 718
	linphone_core_remove_callbacks(m_core, m_coreCbs);
	linphone_core_cbs_unref(m_coreCbs);
719 720
}

Ghislain MARY's avatar
Ghislain MARY committed
721
int RemoteConference::inviteAddresses (const list<const LinphoneAddress *> &addresses, const LinphoneCallParams *params) {
722 723 724 725
	ms_error("RemoteConference::inviteAddresses() not implemented");
	return -1;
}

Ghislain MARY's avatar
Ghislain MARY committed
726
int RemoteConference::addParticipant (LinphoneCall *call) {
727
	LinphoneAddress *addr;
728
	LinphoneCallParams *params;
Ghislain MARY's avatar
Ghislain MARY committed
729 730
	LinphoneCallLog *callLog;
	switch (m_state) {
731 732
		case LinphoneConferenceStopped:
		case LinphoneConferenceStartingFailed:
733
			Conference::addParticipant(call);
734 735
			ms_message("Calling the conference focus (%s)", m_focusAddr);
			addr = linphone_address_new(m_focusAddr);
Ghislain MARY's avatar
Ghislain MARY committed
736 737 738 739 740 741 742 743 744 745 746 747 748 749
			if (!addr)
				return -1;
			params = linphone_core_create_call_params(m_core, nullptr);
			linphone_call_params_enable_video(params, m_currentParams.videoRequested());
			m_focusCall = linphone_core_invite_address_with_params(m_core, addr, params);
			m_localParticipantStream = reinterpret_cast<AudioStream *>(
				L_GET_PRIVATE_FROM_C_OBJECT(m_focusCall)->getMediaStream(LinphoneStreamTypeAudio));
			m_pendingCalls.push_back(call);
			callLog = linphone_call_get_call_log(m_focusCall);
			callLog->was_conference = TRUE;
			linphone_address_unref(addr);
			linphone_call_params_unref(params);
			setState(LinphoneConferenceStarting);
			return 0;
750
		case LinphoneConferenceStarting:
751
			Conference::addParticipant(call);
Ghislain MARY's avatar
Ghislain MARY committed
752
			if(focusIsReady())
753
				transferToFocus(call);
Ghislain MARY's avatar
Ghislain MARY committed
754
			else
755
				m_pendingCalls.push_back(call);
756
			return 0;
757
		case LinphoneConferenceRunning:
758
			Conference::addParticipant(call);
759
			transferToFocus(call);
760 761 762 763 764 765 766
			return 0;
		default:
			ms_error("Could not add call %p to the conference. Bad conference state (%s)", call, stateToString(m_state));
			return -1;
	}
}

Ghislain MARY's avatar
Ghislain MARY committed
767
int RemoteConference::removeParticipant (const LinphoneAddress *uri) {
768 769
	char *refer_to;
	LinphoneAddress *refer_to_addr;
770
	int res;
771

Ghislain MARY's avatar
Ghislain MARY committed
772
	switch (m_state) {
773
		case LinphoneConferenceRunning:
Ghislain MARY's avatar
Ghislain MARY committed
774
			if(!findParticipant(uri)) {
775 776 777 778 779 780 781 782 783
				char *tmp = linphone_address_as_string(uri);
				ms_error("Conference: could not remove participant '%s': not in the participants list", tmp);
				ms_free(tmp);
				return -1;
			}
			refer_to_addr = linphone_address_clone(uri);
			linphone_address_set_method_param(refer_to_addr, "BYE");
			refer_to = linphone_address_as_string(refer_to_addr);
			linphone_address_unref(refer_to_addr);
784
			res = linphone_call_get_op(m_focusCall)->refer(refer_to);
785
			ms_free(refer_to);
Ghislain MARY's avatar
Ghislain MARY committed
786
			if (res == 0)
787
				return Conference::removeParticipant(uri);
Ghislain MARY's avatar
Ghislain MARY committed
788
			else {
789 790 791 792 793
				char *tmp = linphone_address_as_string(uri);
				ms_error("Conference: could not remove participant '%s': REFER with BYE has failed", tmp);
				ms_free(tmp);
				return -1;
			}
794
		default:
Ghislain MARY's avatar
Ghislain MARY committed
795 796
			ms_error("Cannot remove %s from conference: Bad conference state (%s)",
				linphone_address_as_string(uri), stateToString(m_state));
797 798 799 800
			return -1;
	}
}

Ghislain MARY's avatar
Ghislain MARY committed
801 802
int RemoteConference::terminate () {
	switch (m_state) {
803
		case LinphoneConferenceRunning:
804
		case LinphoneConferenceStarting:
805
			linphone_call_terminate(m_focusCall);
806
			break;
Ghislain MARY's avatar
Ghislain MARY committed
807 808
		default:
			break;
809 810 811 812
	}
	return 0;
}

Ghislain MARY's avatar
Ghislain MARY committed
813 814
int RemoteConference::enter () {
	if (m_state != LinphoneConferenceRunning) {
François Grisez's avatar
François Grisez committed
815
		ms_error("Could not enter in the conference: bad conference state (%s)", stateToString(m_state));
816 817 818
		return -1;
	}
	LinphoneCallState callState = linphone_call_get_state(m_focusCall);
Ghislain MARY's avatar
Ghislain MARY committed
819 820 821
	switch (callState) {
		case LinphoneCallStreamsRunning:
			break;
822
		case LinphoneCallPaused:
823
			linphone_call_resume(m_focusCall);
824 825
			break;
		default:
Ghislain MARY's avatar
Ghislain MARY committed
826 827
			ms_error("Could not join the conference: bad focus call state (%s)",
				linphone_call_state_to_string(callState));
828 829 830 831 832
			return -1;
	}
	return 0;
}

Ghislain MARY's avatar
Ghislain MARY committed
833 834
int RemoteConference::leave () {
	if (m_state != LinphoneConferenceRunning) {
François Grisez's avatar
François Grisez committed
835
		ms_error("Could not leave the conference: bad conference state (%s)", stateToString(m_state));
836 837 838
		return -1;
	}
	LinphoneCallState callState = linphone_call_get_state(m_focusCall);
Ghislain MARY's avatar
Ghislain MARY committed
839 840 841
	switch (callState) {
		case LinphoneCallPaused:
			break;
842
		case LinphoneCallStreamsRunning:
843
			linphone_call_pause(m_focusCall);
844 845
			break;
		default:
Ghislain MARY's avatar
Ghislain MARY committed
846 847
			ms_error("Could not leave the conference: bad focus call state (%s)",
				linphone_call_state_to_string(callState));
848 849 850 851 852
			return -1;
	}
	return 0;
}

Ghislain MARY's avatar
Ghislain MARY committed
853 854 855
bool RemoteConference::isIn () const {
	if (m_state != LinphoneConferenceRunning)
		return false;
856 857 858 859
	LinphoneCallState callState = linphone_call_get_state(m_focusCall);
	return callState == LinphoneCallStreamsRunning;
}

Ghislain MARY's avatar
Ghislain MARY committed
860
bool RemoteConference::focusIsReady () const {
861
	LinphoneCallState focusState;
Ghislain MARY's avatar
Ghislain MARY committed
862 863
	if (!m_focusCall)
		return false;
864
	focusState = linphone_call_get_state(m_focusCall);
Ghislain MARY's avatar
Ghislain MARY committed
865
	return (focusState == LinphoneCallStreamsRunning) || (focusState == LinphoneCallPaused);
866 867
}

Ghislain MARY's avatar
Ghislain MARY committed
868 869
bool RemoteConference::transferToFocus (LinphoneCall *call) {
	if (linphone_call_transfer(call, m_focusContact) == 0) {
870
		m_transferingCalls.push_back(call);
871 872 873 874
		return true;
	} else {
		ms_error("Conference: could not transfer call [%p] to %s", call, m_focusContact);
		return false;
875 876 877
	}
}

Ghislain MARY's avatar
Ghislain MARY committed
878 879 880
void RemoteConference::reset () {
	m_localParticipantStream = nullptr;
	m_focusAddr = nullptr;
881 882
	if(m_focusContact) {
		ms_free(m_focusContact);
Ghislain MARY's avatar
Ghislain MARY committed
883
		m_focusContact = nullptr;
884
	}
Ghislain MARY's avatar
Ghislain MARY committed
885
	m_focusCall = nullptr;
886 887
	m_pendingCalls.clear();
	m_transferingCalls.clear();
888 889
}

Ghislain MARY's avatar
Ghislain MARY committed
890
void RemoteConference::onFocusCallSateChanged (LinphoneCallState state) {
891
	list<LinphoneCall *>::iterator it;
892
	switch (state) {
893 894
		case LinphoneCallConnected:
			m_focusContact = ms_strdup(linphone_call_get_remote_contact(m_focusCall));
895 896 897
			it = m_pendingCalls.begin();
			while (it != m_pendingCalls.end()) {
				LinphoneCall *pendingCall = *it;
898
				LinphoneCallState pendingCallState = linphone_call_get_state(pendingCall);
Ghislain MARY's avatar
Ghislain MARY committed
899
				if ((pendingCallState == LinphoneCallStreamsRunning) || (pendingCallState == LinphoneCallPaused)) {
900
					it = m_pendingCalls.erase(it);
901
					transferToFocus(pendingCall);
Ghislain MARY's avatar
Ghislain MARY committed
902
				} else
903
					it++;
904
			}
905
			setState(LinphoneConferenceRunning);
906 907
			break;
		case LinphoneCallError:
908
			reset();
909
			Conference::terminate();
910 911
			setState(LinphoneConferenceStartingFailed);
			break;
912
		case LinphoneCallEnd:
913 914 915
			reset();
			Conference::terminate();
			setState(LinphoneConferenceStopped);
916
			break;
Ghislain MARY's avatar
Ghislain MARY committed
917 918
		default:
			break;
919
	}
920 921
}

Ghislain MARY's avatar
Ghislain MARY committed
922 923 924 925 926
void RemoteConference::onPendingCallStateChanged (LinphoneCall *call, LinphoneCallState state) {
	switch (state) {
		case LinphoneCallStreamsRunning:
		case LinphoneCallPaused:
			if (m_state == LinphoneConferenceRunning) {
927
				m_pendingCalls.remove(call);
Ghislain MARY's avatar
Ghislain MARY committed
928 929 930 931 932 933 934 935 936 937 938 939 940 941
				m_transferingCalls.push_back(call);
				linphone_call_transfer(call, m_focusContact);
			}
			break;
		case LinphoneCallError:
		case LinphoneCallEnd:
			m_pendingCalls.remove(call);
			Conference::removeParticipant(call);
			if ((m_participants.size() + m_pendingCalls.size() + m_transferingCalls.size()) == 0)
				terminate();
			break;
		default:
			break;
	}
942 943
}

Ghislain MARY's avatar
Ghislain MARY committed
944
void RemoteConference::onTransferingCallStateChanged (LinphoneCall* transfered, LinphoneCallState newCallState) {
945 946
	switch (newCallState) {
		case LinphoneCallConnected:
947
			m_transferingCalls.push_back(transfered);
Ghislain MARY's avatar
Ghislain MARY committed
948
			findParticipant(transfered)->m_call = nullptr;
949
			break;
950
		case LinphoneCallError:
951 952
			m_transferingCalls.remove(transfered);
			Conference::removeParticipant(transfered);
Ghislain MARY's avatar
Ghislain MARY committed
953
			if ((m_participants.size() + m_pendingCalls.size() + m_transferingCalls.size()) == 0)
954
				terminate();
955 956 957 958 959 960
			break;
		default:
			break;
	}
}

Ghislain MARY's avatar
Ghislain MARY committed
961
void RemoteConference::callStateChangedCb (LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *message) {
962
	LinphoneCoreVTable *vtable = linphone_core_get_current_vtable(lc);
963
	RemoteConference *conf = (RemoteConference *)linphone_core_v_table_get_user_data(vtable);
Ghislain MARY's avatar
Ghislain MARY committed
964
	if (call == conf->m_focusCall)
965
		conf->onFocusCallSateChanged(cstate);
Ghislain MARY's avatar
Ghislain MARY committed
966
	else {
967
		list<LinphoneCall *>::iterator it = find(conf->m_pendingCalls.begin(), conf->m_pendingCalls.end(), call);
Ghislain MARY's avatar
Ghislain MARY committed
968
		if (it != conf->m_pendingCalls.end())
969
			conf->onPendingCallStateChanged(call, cstate);
970 971 972
	}
}

Ghislain MARY's avatar
Ghislain MARY committed
973
void RemoteConference::transferStateChanged (LinphoneCore *lc, LinphoneCall *transfered, LinphoneCallState new_call_state) {
974
	LinphoneCoreVTable *vtable = linphone_core_get_current_vtable(lc);
975
	RemoteConference *conf = (RemoteConference *)linphone_core_v_table_get_user_data(vtable);
976
	list<LinphoneCall *>::iterator it = find(conf->m_transferingCalls.begin(), conf->m_transferingCalls.end(), transfered);
Ghislain MARY's avatar
Ghislain MARY committed
977
	if (it != conf->m_transferingCalls.end())
978
		conf->onTransferingCallStateChanged(transfered, new_call_state);
979 980 981 982
}



Ghislain MARY's avatar
Ghislain MARY committed
983
const char *linphone_conference_state_to_string (LinphoneConferenceState state) {
984 985 986
	return Conference::stateToString(state);
}

987 988 989 990 991 992 993 994 995 996

struct _LinphoneConferenceParams {
	::belle_sip_object_t base;
	Conference::Params *params;
};

static void _linphone_conference_params_uninit(LinphoneConferenceParams *params);
static void _linphone_conference_params_clone(LinphoneConferenceParams *params, const LinphoneConferenceParams *orig);

BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneConferenceParams);
Ghislain MARY's avatar
Ghislain MARY committed
997
BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneConferenceParams);
998 999 1000 1001 1002 1003 1004
BELLE_SIP_INSTANCIATE_VPTR(LinphoneConferenceParams, belle_sip_object_t,
	_linphone_conference_params_uninit, // uninit
	_linphone_conference_params_clone, // clone
	NULL, // marshal
	FALSE // unown
);

Ghislain MARY's avatar
Ghislain MARY committed
1005
LinphoneConferenceParams *linphone_conference_params_new (const LinphoneCore *core) {
1006 1007 1008 1009 1010
	LinphoneConferenceParams *obj = belle_sip_object_new(LinphoneConferenceParams);
	obj->params = new Conference::Params(core);
	return obj;
}

Ghislain MARY's avatar
Ghislain MARY committed
1011
static void _linphone_conference_params_uninit (LinphoneConferenceParams *params) {
1012 1013 1014
	delete params->params;
}

Ghislain MARY's avatar
Ghislain MARY committed
1015
LinphoneConferenceParams *linphone_conference_params_ref (LinphoneConferenceParams *params) {
1016 1017 1018
	return (LinphoneConferenceParams *)belle_sip_object_ref(params);
}

Ghislain MARY's avatar
Ghislain MARY committed
1019
void linphone_conference_params_unref (LinphoneConferenceParams *params) {
1020
	belle_sip_object_unref(params);
1021 1022
}

Ghislain MARY's avatar
Ghislain MARY committed
1023
void linphone_conference_params_free (LinphoneConferenceParams *params) {
1024 1025 1026
	linphone_conference_params_unref(params);
}

Ghislain MARY's avatar
Ghislain MARY committed
1027
static void _linphone_conference_params_clone (LinphoneConferenceParams *params, const LinphoneConferenceParams *orig) {
1028
	params->params = new Conference::Params(*orig->params);
1029 1030
}

Ghislain MARY's avatar
Ghislain MARY committed
1031
LinphoneConferenceParams *linphone_conference_params_clone (const LinphoneConferenceParams *params) {
1032
	return (LinphoneConferenceParams *)belle_sip_object_clone((const belle_sip_object_t *)params);
1033 1034
}

Ghislain MARY's avatar
Ghislain MARY committed
1035
void linphone_conference_params_enable_video (LinphoneConferenceParams *params, bool_t enable) {
1036
	params->params->enableVideo(enable ? true : false);
1037 1038
}

Ghislain MARY's avatar
Ghislain MARY committed
1039
bool_t linphone_conference_params_video_requested (const LinphoneConferenceParams *params) {
1040
	return params->params->videoRequested() ? TRUE : FALSE;
1041 1042
}

Ghislain MARY's avatar
Ghislain MARY committed
1043
void linphone_conference_params_set_state_changed_callback (LinphoneConferenceParams *params, LinphoneConferenceStateChangedCb cb, void *user_data) {
1044
	params->params->setStateChangedCallback(cb, user_data);
1045 1046
}

1047

1048 1049 1050 1051 1052
struct _LinphoneConference {
	belle_sip_object_t base;
	Conference *conf;
};

Ghislain MARY's avatar
Ghislain MARY committed
1053
static void _linphone_conference_uninit (LinphoneConference *conf);
1054 1055

BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneConference);
Ghislain MARY's avatar
Ghislain MARY committed
1056
BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneConference);
1057 1058 1059 1060 1061 1062
BELLE_SIP_INSTANCIATE_VPTR(LinphoneConference, belle_sip_object_t,
	_linphone_conference_uninit, // uninit
	NULL, // clone
	NULL, // marshal
	FALSE // unown
);
1063

Ghislain MARY's avatar
Ghislain MARY committed
1064
LinphoneConference *linphone_local_conference_new (LinphoneCore *core) {
1065
	LinphoneConference *conf = belle_sip_object_new(LinphoneConference);
Ghislain MARY's avatar
Ghislain MARY committed
1066
	conf->conf = new LocalConference(core, conf);
1067
	return conf;
1068 1069
}

Ghislain MARY's avatar
Ghislain MARY committed
1070
LinphoneConference *linphone_local_conference_new_with_params (LinphoneCore *core, const LinphoneConferenceParams *params) {
1071
	LinphoneConference *conf = belle_sip_object_new(LinphoneConference);
Ghislain MARY's avatar
Ghislain MARY committed
1072
	conf->conf = new LocalConference(core, conf, params->params);
1073
	return conf;
1074 1075
}

Ghislain MARY's avatar
Ghislain MARY committed
1076
LinphoneConference *linphone_remote_conference_new (LinphoneCore *core) {
1077
	LinphoneConference *conf = belle_sip_object_new(LinphoneConference);
Ghislain MARY's avatar
Ghislain MARY committed
1078
	conf->conf = new RemoteConference(core, conf);
1079
	return conf;
1080 1081
}

Ghislain MARY's avatar
Ghislain MARY committed
1082
LinphoneConference *linphone_remote_conference_new_with_params (LinphoneCore *core, const LinphoneConferenceParams *params) {
1083
	LinphoneConference *conf = belle_sip_object_new(LinphoneConference);
Ghislain MARY's avatar
Ghislain MARY committed
1084
	conf->conf = new RemoteConference(core, conf, params->params);
1085 1086 1087
	return conf;
}

Ghislain MARY's avatar
Ghislain MARY committed
1088
static void _linphone_conference_uninit (LinphoneConference *conf) {
1089 1090 1091
	delete conf->conf;
}

Ghislain MARY's avatar
Ghislain MARY committed
1092
LinphoneConference *linphone_conference_ref (LinphoneConference *conf) {
1093
	return (LinphoneConference *)belle_sip_object_ref(conf);
1094 1095
}

Ghislain MARY's avatar
Ghislain MARY committed
1096
void linphone_conference_unref (LinphoneConference *conf) {
1097
	belle_sip_object_unref(conf);
1098 1099
}

Ghislain MARY's avatar
Ghislain MARY committed
1100
LinphoneConferenceState linphone_conference_get_state (const LinphoneConference *obj) {
1101
	return obj->conf->getState();
1102 1103
}

Ghislain MARY's avatar
Ghislain MARY committed
1104
int linphone_conference_add_participant (LinphoneConference *obj, LinphoneCall *call) {
1105
	return obj->conf->addParticipant(call);
1106 1107
}

Ghislain MARY's avatar
Ghislain MARY committed
1108
LinphoneStatus linphone_conference_remove_participant (LinphoneConference *obj, const LinphoneAddress *uri) {
1109
	return obj->conf->removeParticipant(uri);
1110 1111
}

Ghislain MARY's avatar
Ghislain MARY committed
1112
int linphone_conference_remove_participant_with_call (LinphoneConference *obj, LinphoneCall *call) {
1113
	return obj->conf->removeParticipant(call);
1114 1115
}

Ghislain MARY's avatar
Ghislain MARY committed
1116
int linphone_conference_terminate (LinphoneConference *obj) {
1117
	return obj->conf->terminate();
1118 1119
}

Ghislain MARY's avatar
Ghislain MARY committed
1120
int linphone_conference_enter (LinphoneConference *obj) {
1121
	return obj->conf->enter();
1122 1123
}

Ghislain MARY's avatar
Ghislain MARY committed
1124
int linphone_conference_leave (LinphoneConference *obj) {
1125
	return obj->conf->leave();
1126 1127
}

Ghislain MARY's avatar
Ghislain MARY committed
1128
bool_t linphone_conference_is_in (const LinphoneConference *obj) {