]> sjero.net Git - linphone/blobdiff - coreapi/conference.c
important conference bugfixes
[linphone] / coreapi / conference.c
index d4abc1a91a05972dbb262ea88cfefb160cc24486..0d8ea39a0fdd0e6b44f76581961744a63d5e4ff7 100644 (file)
 
 #include "mediastreamer2/msvolume.h"
 
+/**
+ * @addtogroup conferencing
+ * @{
+**/
+
+
 static int convert_conference_to_call(LinphoneCore *lc);
 
 static void conference_check_init(LinphoneConference *ctx, int samplerate){
@@ -49,22 +55,38 @@ static void remove_local_endpoint(LinphoneConference *ctx){
        }
 }
 
+static int linphone_conference_get_size(LinphoneConference *conf){
+       if (conf->conf == NULL) {
+               return 0;
+       }
+       return ms_audio_conference_get_size(conf->conf) - (conf->record_endpoint ? 1 : 0);
+}
+
 static int remote_participants_count(LinphoneConference *ctx) {
-       if (!ctx->conf || ms_audio_conference_get_size(ctx->conf)==0) return 0;
-       if (!ctx->local_participant) return ms_audio_conference_get_size(ctx->conf);
-       return ms_audio_conference_get_size(ctx->conf) -1;
+       int count=linphone_conference_get_size(ctx);
+       if (count==0) return 0;
+       if (!ctx->local_participant) return count;
+       return count -1;
 }
 
 void linphone_core_conference_check_uninit(LinphoneCore *lc){
        LinphoneConference *ctx=&lc->conf_ctx;
        if (ctx->conf){
-               ms_message("conference_check_uninit(): nmembers=%i",ms_audio_conference_get_size(ctx->conf));
-               if (remote_participants_count(ctx)==1){
+               int remote_count=remote_participants_count(ctx);
+               ms_message("conference_check_uninit(): size=%i",linphone_conference_get_size(ctx));
+               if (remote_count==1){
                        convert_conference_to_call(lc);
                }
-               if (ms_audio_conference_get_size(ctx->conf)==1 && ctx->local_participant!=NULL){
-                       remove_local_endpoint(ctx);
+               if (remote_count==0){
+                       if (ctx->local_participant!=NULL)
+                               remove_local_endpoint(ctx);
+                       if (ctx->record_endpoint){
+                               ms_audio_conference_remove_member(ctx->conf,ctx->record_endpoint);
+                               ms_audio_endpoint_destroy(ctx->record_endpoint);
+                               ctx->record_endpoint=NULL;
+                       }
                }
+               
                if (ms_audio_conference_get_size(ctx->conf)==0){
                        ms_audio_conference_destroy(ctx->conf);
                        ctx->conf=NULL;
@@ -104,7 +126,7 @@ static RtpProfile *make_dummy_profile(int samplerate){
 static void add_local_endpoint(LinphoneConference *conf,LinphoneCore *lc){
        /*create a dummy audiostream in order to extract the local part of it */
        /* network address and ports have no meaning and are not used here. */
-       AudioStream *st=audio_stream_new(65000,FALSE);
+       AudioStream *st=audio_stream_new(65000,65001,FALSE);
        MSSndCard *playcard=lc->sound_conf.lsd_card ? 
                        lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard;
        MSSndCard *captcard=lc->sound_conf.capt_sndcard;
@@ -114,6 +136,7 @@ static void add_local_endpoint(LinphoneConference *conf,LinphoneCore *lc){
        audio_stream_start_full(st, conf->local_dummy_profile,
                                "127.0.0.1",
                                65000,
+                               "127.0.0.1",
                                65001,
                                0,
                                40,
@@ -130,6 +153,11 @@ static void add_local_endpoint(LinphoneConference *conf,LinphoneCore *lc){
        
 }
 
+/**
+ * Returns the sound volume (mic input) of the local participant of the conference.
+ * @param lc the linphone core
+ * @returns the measured input volume expressed in dbm0.
+ **/
 float linphone_core_get_conference_local_input_volume(LinphoneCore *lc){
        LinphoneConference *conf=&lc->conf_ctx;
        AudioStream *st=conf->local_participant;
@@ -142,8 +170,18 @@ float linphone_core_get_conference_local_input_volume(LinphoneCore *lc){
        return LINPHONE_VOLUME_DB_LOWEST;
 }
 
+/**
+ * Merge a call into a conference.
+ * @param lc the linphone core
+ * @param call an established call, either in LinphoneCallStreamsRunning or LinphoneCallPaused state.
+ * 
+ * If this is the first call that enters the conference, the virtual conference will be created automatically.
+ * If the local user was actively part of the call (ie not in paused state), then the local user is automatically entered into the conference.
+ * If the call was in paused state, then it is automatically resumed when entering into the conference.
+ * 
+ * @returns 0 if successful, -1 otherwise.
+**/
 int linphone_core_add_to_conference(LinphoneCore *lc, LinphoneCall *call){
-       LinphoneCallParams params;
        LinphoneConference *conf=&lc->conf_ctx;
        
        if (call->current_params.in_conference){
@@ -151,21 +189,25 @@ int linphone_core_add_to_conference(LinphoneCore *lc, LinphoneCall *call){
                return -1;
        }
        conference_check_init(&lc->conf_ctx, lp_config_get_int(lc->config, "sound","conference_rate",16000));
-       call->params.in_conference=TRUE;
-       call->params.has_video=FALSE;
-       call->params.media_encryption=LinphoneMediaEncryptionNone;
-       params=call->params;
-       if (call->state==LinphoneCallPaused)
+       
+       if (call->state==LinphoneCallPaused){
+               call->params.in_conference=TRUE;
+               call->params.has_video=FALSE;
                linphone_core_resume_call(lc,call);
-       else if (call->state==LinphoneCallStreamsRunning){
-               /*this will trigger a reINVITE that will later redraw the streams */
+       }else if (call->state==LinphoneCallStreamsRunning){
+               LinphoneCallParams *params=linphone_call_params_copy(linphone_call_get_current_params(call));
+               params->in_conference=TRUE;
+               params->has_video=FALSE;
+               
                if (call->audiostream || call->videostream){
                        linphone_call_stop_media_streams (call); /*free the audio & video local resources*/
                }
                if (call==lc->current_call){
                        lc->current_call=NULL;
                }
-               linphone_core_update_call(lc,call,&params);
+               /*this will trigger a reINVITE that will later redraw the streams */
+               linphone_core_update_call(lc,call,params);
+               linphone_call_params_destroy(params);
                add_local_endpoint(conf,lc);
        }else{
                ms_error("Call is in state %s, it cannot be added to the conference.",linphone_call_state_to_string(call->state));
@@ -192,16 +234,19 @@ static int remove_from_conference(LinphoneCore *lc, LinphoneCall *call, bool_t a
        ms_message("%s will be removed from conference", str);
        ms_free(str);
        if (active){
+               LinphoneCallParams *params=linphone_call_params_copy(linphone_call_get_current_params(call));
+               params->in_conference=FALSE;
                // reconnect local audio with this call
                if (linphone_core_is_in_conference(lc)){
                        ms_message("Leaving conference for reconnecting with unique call.");
                        linphone_core_leave_conference(lc);
                }
                ms_message("Updating call to actually remove from conference");
-               err=linphone_core_update_call(lc,call,&call->params);
+               err=linphone_core_update_call(lc,call,params);
+               linphone_call_params_destroy(params);
        } else{
                ms_message("Pausing call to actually remove from conference");
-               err=linphone_core_pause_call(lc,call);
+               err=_linphone_core_pause_call(lc,call);
        }
 
        return err;
@@ -228,7 +273,21 @@ static int convert_conference_to_call(LinphoneCore *lc){
        return err;
 }
 
-
+/**
+ * Remove a call from the conference.
+ * @param lc the linphone core
+ * @param call a call that has been previously merged into the conference.
+ * 
+ * After removing the remote participant belonging to the supplied call, the call becomes a normal call in paused state.
+ * If one single remote participant is left alone together with the local user in the conference after the removal, then the conference is
+ * automatically transformed into a simple call in StreamsRunning state.
+ * The conference's resources are then automatically destroyed.
+ * 
+ * In other words, unless linphone_core_leave_conference() is explicitely called, the last remote participant of a conference is automatically
+ * put in a simple call in running state.
+ * 
+ * @returns 0 if successful, -1 otherwise.
+ **/
 int linphone_core_remove_from_conference(LinphoneCore *lc, LinphoneCall *call){
        char * str=linphone_call_get_remote_address_as_string(call);
        ms_message("Removing call %s from the conference", str);
@@ -248,10 +307,21 @@ int linphone_core_remove_from_conference(LinphoneCore *lc, LinphoneCall *call){
        return err;
 }
 
+/**
+ * Indicates whether the local participant is part of the conference.
+ * @param lc the linphone core
+ * @returns TRUE if the local participant is in the conference, FALSE otherwise.
+**/
 bool_t linphone_core_is_in_conference(const LinphoneCore *lc){
        return lc->conf_ctx.local_participant!=NULL;
 }
 
+/**
+ * Moves the local participant out of the conference.
+ * @param lc the linphone core
+ * When the local participant is out of the conference, the remote participants can continue to talk normally.
+ * @returns 0 if successful, -1 otherwise.
+**/
 int linphone_core_leave_conference(LinphoneCore *lc){
        LinphoneConference *conf=&lc->conf_ctx;
        if (linphone_core_is_in_conference(lc))
@@ -259,19 +329,37 @@ int linphone_core_leave_conference(LinphoneCore *lc){
        return 0;
 }
 
-
+/**
+ * Moves the local participant inside the conference.
+ * @param lc the linphone core
+ * 
+ * Makes the local participant to join the conference. 
+ * Typically, the local participant is by default always part of the conference when joining an active call into a conference.
+ * However, by calling linphone_core_leave_conference() and linphone_core_enter_conference() the application can decide to temporarily
+ * move out and in the local participant from the conference.
+ * 
+ * @returns 0 if successful, -1 otherwise
+**/
 int linphone_core_enter_conference(LinphoneCore *lc){
        if (linphone_core_sound_resources_locked(lc)) {
                return -1;
        }
        if (lc->current_call != NULL) {
-               linphone_core_pause_call(lc, lc->current_call);
+               _linphone_core_pause_call(lc, lc->current_call);
        }
        LinphoneConference *conf=&lc->conf_ctx;
        if (conf->local_participant==NULL) add_local_endpoint(conf,lc);
        return 0;
 }
 
+/**
+ * Add all calls into a conference.
+ * @param lc the linphone core
+ * 
+ * Merge all established calls (either in LinphoneCallStreamsRunning or LinphoneCallPaused) into a conference.
+ * 
+ * @returns 0 if successful, -1 otherwise
+**/
 int linphone_core_add_all_to_conference(LinphoneCore *lc) {
        MSList *calls=lc->calls;
        while (calls) {
@@ -285,6 +373,14 @@ int linphone_core_add_all_to_conference(LinphoneCore *lc) {
        return 0;
 }
 
+/**
+ * Terminates the conference and the calls associated with it.
+ * @param lc the linphone core
+ * 
+ * All the calls that were merged to the conference are terminated, and the conference resources are destroyed.
+ * 
+ * @returns 0 if successful, -1 otherwise
+**/
 int linphone_core_terminate_conference(LinphoneCore *lc) {
        MSList *calls=lc->calls;
        while (calls) {
@@ -297,9 +393,50 @@ int linphone_core_terminate_conference(LinphoneCore *lc) {
        return 0;
 }
 
+/**
+ * Returns the number of participants to the conference, including the local participant.
+ * @param lc the linphone core
+ * 
+ * Typically, after merging two calls into the conference, there is total of 3 participants:
+ * the local participant (or local user), and two remote participants that were the destinations of the two previously establised calls.
+ * 
+ * @returns the number of participants to the conference
+**/
 int linphone_core_get_conference_size(LinphoneCore *lc) {
-       if (lc->conf_ctx.conf == NULL) {
-               return 0;
+       LinphoneConference *conf=&lc->conf_ctx;
+       return linphone_conference_get_size(conf);
+}
+
+
+int linphone_core_start_conference_recording(LinphoneCore *lc, const char *path){
+       LinphoneConference *conf=&lc->conf_ctx;
+       if (conf->conf == NULL) {
+               ms_warning("linphone_core_start_conference_recording(): no conference now.");
+               return -1;
+       }
+       if (conf->record_endpoint==NULL){
+               conf->record_endpoint=ms_audio_endpoint_new_recorder();
+               ms_audio_conference_add_member(conf->conf,conf->record_endpoint);
+       }
+       ms_audio_recorder_endpoint_start(conf->record_endpoint,path);
+       return 0;
+}
+
+int linphone_core_stop_conference_recording(LinphoneCore *lc){
+       LinphoneConference *conf=&lc->conf_ctx;
+       if (conf->conf == NULL) {
+               ms_warning("linphone_core_stop_conference_recording(): no conference now.");
+               return -1;
+       }
+       if (conf->record_endpoint==NULL){
+               ms_warning("linphone_core_stop_conference_recording(): no record active.");
+               return -1;
        }
-       return ms_audio_conference_get_size(lc->conf_ctx.conf);
+       ms_audio_recorder_endpoint_stop(conf->record_endpoint);
+       return 0;
 }
+
+/**
+ * @}
+**/
+