1 /***************************************************************************
5 * Copyright 2011 Belledonne Communications
7 * Email simon dot morlat at linphone dot org
8 ****************************************************************************/
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29 #include "mediastreamer2/msvolume.h"
31 static int convert_conference_to_call(LinphoneCore *lc);
33 static void conference_check_init(LinphoneConference *ctx, int samplerate){
35 MSAudioConferenceParams params;
36 params.samplerate=samplerate;
37 ctx->conf=ms_audio_conference_new(¶ms);
41 static void remove_local_endpoint(LinphoneConference *ctx){
42 if (ctx->local_endpoint){
43 ms_audio_conference_remove_member(ctx->conf,ctx->local_endpoint);
44 ms_audio_endpoint_release_from_stream(ctx->local_endpoint);
45 ctx->local_endpoint=NULL;
46 audio_stream_stop(ctx->local_participant);
47 ctx->local_participant=NULL;
48 rtp_profile_destroy(ctx->local_dummy_profile);
52 static int remote_participants_count(LinphoneConference *ctx) {
53 if (!ctx->conf || ms_audio_conference_get_size(ctx->conf)==0) return 0;
54 if (!ctx->local_participant) return ms_audio_conference_get_size(ctx->conf);
55 return ms_audio_conference_get_size(ctx->conf) -1;
58 void linphone_core_conference_check_uninit(LinphoneCore *lc){
59 LinphoneConference *ctx=&lc->conf_ctx;
61 ms_message("conference_check_uninit(): nmembers=%i",ms_audio_conference_get_size(ctx->conf));
62 if (remote_participants_count(ctx)==1){
63 convert_conference_to_call(lc);
65 if (ms_audio_conference_get_size(ctx->conf)==1 && ctx->local_participant!=NULL){
66 remove_local_endpoint(ctx);
68 if (ms_audio_conference_get_size(ctx->conf)==0){
69 ms_audio_conference_destroy(ctx->conf);
75 void linphone_call_add_to_conf(LinphoneCall *call, bool_t muted){
76 LinphoneCore *lc=call->core;
77 LinphoneConference *conf=&lc->conf_ctx;
79 call->params.has_video = FALSE;
80 call->camera_active = FALSE;
81 ep=ms_audio_endpoint_get_from_stream(call->audiostream,TRUE);
82 ms_audio_conference_add_member(conf->conf,ep);
83 ms_audio_conference_mute_member(conf->conf,ep,muted);
87 void linphone_call_remove_from_conf(LinphoneCall *call){
88 LinphoneCore *lc=call->core;
89 LinphoneConference *conf=&lc->conf_ctx;
91 ms_audio_conference_remove_member(conf->conf,call->endpoint);
92 ms_audio_endpoint_release_from_stream(call->endpoint);
96 static RtpProfile *make_dummy_profile(int samplerate){
97 RtpProfile *prof=rtp_profile_new("dummy");
98 PayloadType *pt=payload_type_clone(&payload_type_l16_mono);
99 pt->clock_rate=samplerate;
100 rtp_profile_set_payload(prof,0,pt);
104 static void add_local_endpoint(LinphoneConference *conf,LinphoneCore *lc){
105 /*create a dummy audiostream in order to extract the local part of it */
106 /* network address and ports have no meaning and are not used here. */
107 AudioStream *st=audio_stream_new(65000,FALSE);
108 MSSndCard *playcard=lc->sound_conf.lsd_card ?
109 lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard;
110 MSSndCard *captcard=lc->sound_conf.capt_sndcard;
111 const MSAudioConferenceParams *params=ms_audio_conference_get_params(conf->conf);
112 conf->local_dummy_profile=make_dummy_profile(params->samplerate);
114 audio_stream_start_full(st, conf->local_dummy_profile,
124 linphone_core_echo_cancellation_enabled(lc)
126 _post_configure_audio_stream(st,lc,FALSE);
127 conf->local_participant=st;
128 conf->local_endpoint=ms_audio_endpoint_get_from_stream(st,FALSE);
129 ms_audio_conference_add_member(conf->conf,conf->local_endpoint);
133 float linphone_core_get_conference_local_input_volume(LinphoneCore *lc){
134 LinphoneConference *conf=&lc->conf_ctx;
135 AudioStream *st=conf->local_participant;
136 if (st && st->volsend && !conf->local_muted){
138 ms_filter_call_method(st->volsend,MS_VOLUME_GET,&vol);
142 return LINPHONE_VOLUME_DB_LOWEST;
145 int linphone_core_add_to_conference(LinphoneCore *lc, LinphoneCall *call){
146 LinphoneCallParams params;
147 LinphoneConference *conf=&lc->conf_ctx;
149 if (call->current_params.in_conference){
150 ms_error("Already in conference");
153 conference_check_init(&lc->conf_ctx, lp_config_get_int(lc->config, "sound","conference_rate",16000));
154 call->params.in_conference=TRUE;
155 call->params.has_video=FALSE;
156 call->params.media_encryption=LinphoneMediaEncryptionNone;
158 if (call->state==LinphoneCallPaused)
159 linphone_core_resume_call(lc,call);
160 else if (call->state==LinphoneCallStreamsRunning){
161 /*this will trigger a reINVITE that will later redraw the streams */
162 if (call->audiostream || call->videostream){
163 linphone_call_stop_media_streams (call); /*free the audio & video local resources*/
165 if (call==lc->current_call){
166 lc->current_call=NULL;
168 linphone_core_update_call(lc,call,¶ms);
169 add_local_endpoint(conf,lc);
171 ms_error("Call is in state %s, it cannot be added to the conference.",linphone_call_state_to_string(call->state));
177 static int remove_from_conference(LinphoneCore *lc, LinphoneCall *call, bool_t active){
180 if (!call->current_params.in_conference){
181 if (call->params.in_conference){
182 ms_warning("Not (yet) in conference, be patient");
185 ms_error("Not in a conference.");
189 call->params.in_conference=FALSE;
191 char *str=linphone_call_get_remote_address_as_string(call);
192 ms_message("%s will be removed from conference", str);
195 // reconnect local audio with this call
196 if (linphone_core_is_in_conference(lc)){
197 ms_message("Leaving conference for reconnecting with unique call.");
198 linphone_core_leave_conference(lc);
200 ms_message("Updating call to actually remove from conference");
201 err=linphone_core_update_call(lc,call,&call->params);
203 ms_message("Pausing call to actually remove from conference");
204 err=linphone_core_pause_call(lc,call);
210 static int convert_conference_to_call(LinphoneCore *lc){
212 MSList *calls=lc->calls;
214 if (remote_participants_count(&lc->conf_ctx)!=1){
215 ms_error("No unique call remaining in conference.");
220 LinphoneCall *rc=(LinphoneCall*)calls->data;
222 if (rc->params.in_conference) { // not using current_param
223 bool_t active_after_removed=linphone_core_is_in_conference(lc);
224 err=remove_from_conference(lc, rc, active_after_removed);
232 int linphone_core_remove_from_conference(LinphoneCore *lc, LinphoneCall *call){
233 char * str=linphone_call_get_remote_address_as_string(call);
234 ms_message("Removing call %s from the conference", str);
236 int err=remove_from_conference(lc,call, FALSE);
238 ms_error("Error removing participant from conference.");
242 if (remote_participants_count(&lc->conf_ctx)==1){
243 ms_message("conference size is 1: need to be converted to plain call");
244 err=convert_conference_to_call(lc);
246 ms_message("the conference need not to be converted as size is %i", remote_participants_count(&lc->conf_ctx));
251 bool_t linphone_core_is_in_conference(const LinphoneCore *lc){
252 return lc->conf_ctx.local_participant!=NULL;
255 int linphone_core_leave_conference(LinphoneCore *lc){
256 LinphoneConference *conf=&lc->conf_ctx;
257 if (linphone_core_is_in_conference(lc))
258 remove_local_endpoint(conf);
263 int linphone_core_enter_conference(LinphoneCore *lc){
264 if (linphone_core_sound_resources_locked(lc)) {
267 if (lc->current_call != NULL) {
268 linphone_core_pause_call(lc, lc->current_call);
270 LinphoneConference *conf=&lc->conf_ctx;
271 if (conf->local_participant==NULL) add_local_endpoint(conf,lc);
275 int linphone_core_add_all_to_conference(LinphoneCore *lc) {
276 MSList *calls=lc->calls;
278 LinphoneCall *call=(LinphoneCall*)calls->data;
280 if (!call->current_params.in_conference) {
281 linphone_core_add_to_conference(lc, call);
284 linphone_core_enter_conference(lc);
288 int linphone_core_terminate_conference(LinphoneCore *lc) {
289 MSList *calls=lc->calls;
291 LinphoneCall *call=(LinphoneCall*)calls->data;
293 if (call->current_params.in_conference) {
294 linphone_core_terminate_call(lc, call);
300 int linphone_core_get_conference_size(LinphoneCore *lc) {
301 return ms_audio_conference_get_size(lc->conf_ctx.conf);