]> sjero.net Git - linphone/blob - coreapi/conference.c
Merge branch 'master' into dev_ice
[linphone] / coreapi / conference.c
1 /***************************************************************************
2  *            conference.c
3  *
4  *  Mon Sep 12, 2011
5  *  Copyright  2011  Belledonne Communications
6  *  Author: Simon Morlat
7  *  Email simon dot morlat at linphone dot org
8  ****************************************************************************/
9
10 /*
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.
15  *
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.
20  *
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.
24  */
25  
26 #include "private.h"
27 #include "lpconfig.h"
28
29 #include "mediastreamer2/msvolume.h"
30
31 static int convert_conference_to_call(LinphoneCore *lc);
32
33 static void conference_check_init(LinphoneConference *ctx, int samplerate){
34         if (ctx->conf==NULL){
35                 MSAudioConferenceParams params;
36                 params.samplerate=samplerate;
37                 ctx->conf=ms_audio_conference_new(&params);
38         }
39 }
40
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);
49         }
50 }
51
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;
56 }
57
58 void linphone_core_conference_check_uninit(LinphoneCore *lc){
59         LinphoneConference *ctx=&lc->conf_ctx;
60         if (ctx->conf){
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);
64                 }
65                 if (ms_audio_conference_get_size(ctx->conf)==1 && ctx->local_participant!=NULL){
66                         remove_local_endpoint(ctx);
67                 }
68                 if (ms_audio_conference_get_size(ctx->conf)==0){
69                         ms_audio_conference_destroy(ctx->conf);
70                         ctx->conf=NULL;
71                 }
72         }
73 }
74
75 void linphone_call_add_to_conf(LinphoneCall *call, bool_t muted){
76         LinphoneCore *lc=call->core;
77         LinphoneConference *conf=&lc->conf_ctx;
78         MSAudioEndpoint *ep;
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);
84         call->endpoint=ep;
85 }
86
87 void linphone_call_remove_from_conf(LinphoneCall *call){
88         LinphoneCore *lc=call->core;
89         LinphoneConference *conf=&lc->conf_ctx;
90         
91         ms_audio_conference_remove_member(conf->conf,call->endpoint);
92         ms_audio_endpoint_release_from_stream(call->endpoint);
93         call->endpoint=NULL;
94 }
95
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);
101         return prof;
102 }
103
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,65001,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);
113         
114         audio_stream_start_full(st, conf->local_dummy_profile,
115                                 "127.0.0.1",
116                                 65000,
117                                 "127.0.0.1",
118                                 65001,
119                                 0,
120                                 40,
121                                 NULL,
122                                 NULL,
123                                 playcard,
124                                 captcard,
125                                 linphone_core_echo_cancellation_enabled(lc)
126                                 );
127         _post_configure_audio_stream(st,lc,FALSE);
128         conf->local_participant=st;
129         conf->local_endpoint=ms_audio_endpoint_get_from_stream(st,FALSE);
130         ms_audio_conference_add_member(conf->conf,conf->local_endpoint);
131         
132 }
133
134 float linphone_core_get_conference_local_input_volume(LinphoneCore *lc){
135         LinphoneConference *conf=&lc->conf_ctx;
136         AudioStream *st=conf->local_participant;
137         if (st && st->volsend && !conf->local_muted){
138                 float vol=0;
139                 ms_filter_call_method(st->volsend,MS_VOLUME_GET,&vol);
140                 return vol;
141                 
142         }
143         return LINPHONE_VOLUME_DB_LOWEST;
144 }
145
146 int linphone_core_add_to_conference(LinphoneCore *lc, LinphoneCall *call){
147         LinphoneCallParams params;
148         LinphoneConference *conf=&lc->conf_ctx;
149         
150         if (call->current_params.in_conference){
151                 ms_error("Already in conference");
152                 return -1;
153         }
154         conference_check_init(&lc->conf_ctx, lp_config_get_int(lc->config, "sound","conference_rate",16000));
155         call->params.in_conference=TRUE;
156         call->params.has_video=FALSE;
157         call->params.media_encryption=LinphoneMediaEncryptionNone;
158         params=call->params;
159         if (call->state==LinphoneCallPaused)
160                 linphone_core_resume_call(lc,call);
161         else if (call->state==LinphoneCallStreamsRunning){
162                 /*this will trigger a reINVITE that will later redraw the streams */
163                 if (call->audiostream || call->videostream){
164                         linphone_call_stop_media_streams (call); /*free the audio & video local resources*/
165                 }
166                 if (call==lc->current_call){
167                         lc->current_call=NULL;
168                 }
169                 linphone_core_update_call(lc,call,&params);
170                 add_local_endpoint(conf,lc);
171         }else{
172                 ms_error("Call is in state %s, it cannot be added to the conference.",linphone_call_state_to_string(call->state));
173                 return -1;
174         }
175         return 0;
176 }
177
178 static int remove_from_conference(LinphoneCore *lc, LinphoneCall *call, bool_t active){
179         int err=0;
180
181         if (!call->current_params.in_conference){
182                 if (call->params.in_conference){
183                         ms_warning("Not (yet) in conference, be patient");
184                         return -1;
185                 }else{
186                         ms_error("Not in a conference.");
187                         return -1;
188                 }
189         }
190         call->params.in_conference=FALSE;
191
192         char *str=linphone_call_get_remote_address_as_string(call);
193         ms_message("%s will be removed from conference", str);
194         ms_free(str);
195         if (active){
196                 // reconnect local audio with this call
197                 if (linphone_core_is_in_conference(lc)){
198                         ms_message("Leaving conference for reconnecting with unique call.");
199                         linphone_core_leave_conference(lc);
200                 }
201                 ms_message("Updating call to actually remove from conference");
202                 err=linphone_core_update_call(lc,call,&call->params);
203         } else{
204                 ms_message("Pausing call to actually remove from conference");
205                 err=linphone_core_pause_call(lc,call);
206         }
207
208         return err;
209 }
210
211 static int convert_conference_to_call(LinphoneCore *lc){
212         int err=0;
213         MSList *calls=lc->calls;
214
215         if (remote_participants_count(&lc->conf_ctx)!=1){
216                 ms_error("No unique call remaining in conference.");
217                 return -1;
218         }
219
220         while (calls) {
221                 LinphoneCall *rc=(LinphoneCall*)calls->data;
222                 calls=calls->next;
223                 if (rc->params.in_conference) { // not using current_param
224                         bool_t active_after_removed=linphone_core_is_in_conference(lc);
225                         err=remove_from_conference(lc, rc, active_after_removed);
226                         break;
227                 }
228         }
229         return err;
230 }
231
232
233 int linphone_core_remove_from_conference(LinphoneCore *lc, LinphoneCall *call){
234         char * str=linphone_call_get_remote_address_as_string(call);
235         ms_message("Removing call %s from the conference", str);
236         ms_free(str);
237         int err=remove_from_conference(lc,call, FALSE);
238         if (err){
239                 ms_error("Error removing participant from conference.");
240                 return err;
241         }
242
243         if (remote_participants_count(&lc->conf_ctx)==1){
244                 ms_message("conference size is 1: need to be converted to plain call");
245                 err=convert_conference_to_call(lc);
246         } else {
247                 ms_message("the conference need not to be converted as size is %i", remote_participants_count(&lc->conf_ctx));
248         }
249         return err;
250 }
251
252 bool_t linphone_core_is_in_conference(const LinphoneCore *lc){
253         return lc->conf_ctx.local_participant!=NULL;
254 }
255
256 int linphone_core_leave_conference(LinphoneCore *lc){
257         LinphoneConference *conf=&lc->conf_ctx;
258         if (linphone_core_is_in_conference(lc))
259                 remove_local_endpoint(conf);
260         return 0;
261 }
262
263
264 int linphone_core_enter_conference(LinphoneCore *lc){
265         if (linphone_core_sound_resources_locked(lc)) {
266                 return -1;
267         }
268         if (lc->current_call != NULL) {
269                 linphone_core_pause_call(lc, lc->current_call);
270         }
271         LinphoneConference *conf=&lc->conf_ctx;
272         if (conf->local_participant==NULL) add_local_endpoint(conf,lc);
273         return 0;
274 }
275
276 int linphone_core_add_all_to_conference(LinphoneCore *lc) {
277         MSList *calls=lc->calls;
278         while (calls) {
279                 LinphoneCall *call=(LinphoneCall*)calls->data;
280                 calls=calls->next;
281                 if (!call->current_params.in_conference) {
282                         linphone_core_add_to_conference(lc, call);
283                 }
284         }
285         linphone_core_enter_conference(lc);
286         return 0;
287 }
288
289 int linphone_core_terminate_conference(LinphoneCore *lc) {
290         MSList *calls=lc->calls;
291         while (calls) {
292                 LinphoneCall *call=(LinphoneCall*)calls->data;
293                 calls=calls->next;
294                 if (call->current_params.in_conference) {
295                         linphone_core_terminate_call(lc, call);
296                 }
297         }
298         return 0;
299 }
300
301 int linphone_core_get_conference_size(LinphoneCore *lc) {
302         if (lc->conf_ctx.conf == NULL) {
303                 return 0;
304         }
305         return ms_audio_conference_get_size(lc->conf_ctx.conf);
306 }