forked from mirrors/linphone-iphone
Merge branch 'dev_conference_rfc4579'
This commit is contained in:
commit
38dfb9ab6f
34 changed files with 1670 additions and 554 deletions
|
|
@ -47,7 +47,7 @@ LOCAL_SRC_FILES := \
|
|||
call_params.c \
|
||||
chat.c \
|
||||
chat_file_transfer.c \
|
||||
conference.c \
|
||||
conference.cc \
|
||||
content.c \
|
||||
ec-calibrator.c \
|
||||
enum.c \
|
||||
|
|
|
|||
|
|
@ -2452,7 +2452,7 @@ static void lpc_display_call_states(LinphoneCore *lc){
|
|||
const char *flag;
|
||||
bool_t in_conference;
|
||||
call=(LinphoneCall*)elem->data;
|
||||
in_conference=linphone_call_params_get_local_conference_mode(linphone_call_get_current_params(call));
|
||||
in_conference=(linphone_call_get_conference(call) != NULL);
|
||||
tmp=linphone_call_get_remote_address_as_string (call);
|
||||
flag=in_conference ? "conferencing" : "";
|
||||
flag=linphone_call_has_transfer_pending(call) ? "transfer pending" : flag;
|
||||
|
|
|
|||
|
|
@ -75,7 +75,6 @@ set(LINPHONE_SOURCE_FILES_C
|
|||
call_params.c
|
||||
chat.c
|
||||
chat_file_transfer.c
|
||||
conference.c
|
||||
contactprovider.c
|
||||
content.c
|
||||
dict.c
|
||||
|
|
@ -115,7 +114,7 @@ set(LINPHONE_SOURCE_FILES_C
|
|||
xmlrpc.c
|
||||
vtables.c
|
||||
)
|
||||
set(LINPHONE_SOURCE_FILES_CXX )
|
||||
set(LINPHONE_SOURCE_FILES_CXX conference.cc)
|
||||
|
||||
set(LINPHONE_SOURCE_FILES_OBJC)
|
||||
if (IOS)
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ liblinphone_la_SOURCES=\
|
|||
call_params.c \
|
||||
chat.c \
|
||||
chat_file_transfer.c \
|
||||
conference.c \
|
||||
conference.cc \
|
||||
contactprovider.c contactprovider.h contact_providers_priv.h \
|
||||
content.c \
|
||||
dict.c \
|
||||
|
|
|
|||
|
|
@ -129,6 +129,20 @@ LinphoneTransportType linphone_address_get_transport(const LinphoneAddress *uri)
|
|||
return (LinphoneTransportType)sal_address_get_transport(uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of the method parameter
|
||||
**/
|
||||
void linphone_address_set_method_param(LinphoneAddress *addr, const char *method) {
|
||||
sal_address_set_method_param(addr, method);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of the method parameter
|
||||
**/
|
||||
const char *linphone_address_get_method_param(const LinphoneAddress *addr) {
|
||||
return sal_address_get_method_param(addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes address's tags and uri headers so that it is displayable to the user.
|
||||
**/
|
||||
|
|
|
|||
|
|
@ -114,6 +114,15 @@ const char* sal_address_get_transport_name(const SalAddress* addr){
|
|||
return NULL;
|
||||
}
|
||||
|
||||
const char *sal_address_get_method_param(const SalAddress *addr) {
|
||||
belle_sip_header_address_t* header_addr = BELLE_SIP_HEADER_ADDRESS(addr);
|
||||
belle_sip_uri_t* uri = belle_sip_header_address_get_uri(header_addr);
|
||||
if (uri) {
|
||||
return belle_sip_uri_get_method_param(uri);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void sal_address_set_display_name(SalAddress *addr, const char *display_name){
|
||||
belle_sip_header_address_t* header_addr = BELLE_SIP_HEADER_ADDRESS(addr);
|
||||
belle_sip_header_address_set_displayname(header_addr,display_name);
|
||||
|
|
@ -213,6 +222,10 @@ void sal_address_set_transport_name(SalAddress* addr,const char *transport){
|
|||
SAL_ADDRESS_SET(addr,transport_param,transport);
|
||||
}
|
||||
|
||||
void sal_address_set_method_param(SalAddress *addr, const char *method) {
|
||||
SAL_ADDRESS_SET(addr, method_param, method);
|
||||
}
|
||||
|
||||
SalAddress *sal_address_ref(SalAddress *addr){
|
||||
return (SalAddress*)belle_sip_object_ref(BELLE_SIP_HEADER_ADDRESS(addr));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ static void sal_op_set_referred_by(SalOp* op,belle_sip_header_referred_by_t* ref
|
|||
|
||||
int sal_call_refer_to(SalOp *op, belle_sip_header_refer_to_t* refer_to, belle_sip_header_referred_by_t* referred_by){
|
||||
char* tmp;
|
||||
belle_sip_request_t* req=op->dialog?belle_sip_dialog_create_request(op->dialog,"REFER"):NULL; /*cannot create request if dialog not set yet*/
|
||||
belle_sip_request_t* req=op->dialog?belle_sip_dialog_create_request(op->dialog,"REFER"):sal_op_build_request(op, "REFER");
|
||||
if (!req) {
|
||||
tmp=belle_sip_uri_to_string(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(refer_to)));
|
||||
ms_error("Cannot refer to [%s] for op [%p]",tmp,op);
|
||||
|
|
|
|||
|
|
@ -125,6 +125,10 @@ LINPHONE_PUBLIC const char *linphone_call_params_get_custom_header(const Linphon
|
|||
|
||||
/**
|
||||
* Tell whether the call is part of the locally managed conference.
|
||||
* @warning If a conference server is used to manage conferences,
|
||||
* that function does not return TRUE even if the conference is running.<br/>
|
||||
* If you want to test whether the conference is running, you should test
|
||||
* whether linphone_core_get_conference() return a non-null pointer.
|
||||
* @param[in] cp LinphoneCallParams object
|
||||
* @return A boolean value telling whether the call is part of the locally managed conference.
|
||||
**/
|
||||
|
|
|
|||
|
|
@ -1065,7 +1065,15 @@ static void dtmf_received(SalOp *op, char dtmf){
|
|||
static void refer_received(Sal *sal, SalOp *op, const char *referto){
|
||||
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal);
|
||||
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
|
||||
if (call){
|
||||
LinphoneAddress *refer_to_addr = linphone_address_new(referto);
|
||||
char method[20] = "";
|
||||
|
||||
if(refer_to_addr) {
|
||||
const char *tmp = linphone_address_get_method_param(refer_to_addr);
|
||||
if(tmp) strncpy(method, tmp, sizeof(method));
|
||||
linphone_address_destroy(refer_to_addr);
|
||||
}
|
||||
if (call && (strlen(method) == 0 || strcmp(method, "INVITE") == 0)) {
|
||||
if (call->refer_to!=NULL){
|
||||
ms_free(call->refer_to);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,430 +0,0 @@
|
|||
/***************************************************************************
|
||||
* conference.c
|
||||
*
|
||||
* Mon Sep 12, 2011
|
||||
* Copyright 2011 Belledonne Communications
|
||||
* Author: Simon Morlat
|
||||
* Email simon dot morlat at linphone dot 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
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "private.h"
|
||||
#include "lpconfig.h"
|
||||
|
||||
#include "mediastreamer2/msvolume.h"
|
||||
|
||||
/**
|
||||
* @addtogroup conferencing
|
||||
* @{
|
||||
**/
|
||||
|
||||
|
||||
static int convert_conference_to_call(LinphoneCore *lc);
|
||||
|
||||
static void conference_check_init(LinphoneConference *ctx, int samplerate){
|
||||
if (ctx->conf==NULL){
|
||||
MSAudioConferenceParams params;
|
||||
params.samplerate=samplerate;
|
||||
ctx->conf=ms_audio_conference_new(¶ms);
|
||||
ctx->terminated=FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void remove_local_endpoint(LinphoneConference *ctx){
|
||||
if (ctx->local_endpoint){
|
||||
ms_audio_conference_remove_member(ctx->conf,ctx->local_endpoint);
|
||||
ms_audio_endpoint_release_from_stream(ctx->local_endpoint);
|
||||
ctx->local_endpoint=NULL;
|
||||
audio_stream_stop(ctx->local_participant);
|
||||
ctx->local_participant=NULL;
|
||||
rtp_profile_destroy(ctx->local_dummy_profile);
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
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){
|
||||
int remote_count=remote_participants_count(ctx);
|
||||
ms_message("conference_check_uninit(): size=%i",linphone_conference_get_size(ctx));
|
||||
if (remote_count==1 && !ctx->terminated){
|
||||
convert_conference_to_call(lc);
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void linphone_call_add_to_conf(LinphoneCall *call, bool_t muted){
|
||||
LinphoneCore *lc=call->core;
|
||||
LinphoneConference *conf=&lc->conf_ctx;
|
||||
MSAudioEndpoint *ep;
|
||||
call->params->has_video = FALSE;
|
||||
call->camera_enabled = FALSE;
|
||||
ep=ms_audio_endpoint_get_from_stream(call->audiostream,TRUE);
|
||||
ms_audio_conference_add_member(conf->conf,ep);
|
||||
ms_audio_conference_mute_member(conf->conf,ep,muted);
|
||||
call->endpoint=ep;
|
||||
}
|
||||
|
||||
void linphone_call_remove_from_conf(LinphoneCall *call){
|
||||
LinphoneCore *lc=call->core;
|
||||
LinphoneConference *conf=&lc->conf_ctx;
|
||||
|
||||
ms_audio_conference_remove_member(conf->conf,call->endpoint);
|
||||
ms_audio_endpoint_release_from_stream(call->endpoint);
|
||||
call->endpoint=NULL;
|
||||
}
|
||||
|
||||
static RtpProfile *make_dummy_profile(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);
|
||||
return prof;
|
||||
}
|
||||
|
||||
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,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;
|
||||
const MSAudioConferenceParams *params=ms_audio_conference_get_params(conf->conf);
|
||||
conf->local_dummy_profile=make_dummy_profile(params->samplerate);
|
||||
|
||||
audio_stream_start_full(st, conf->local_dummy_profile,
|
||||
"127.0.0.1",
|
||||
65000,
|
||||
"127.0.0.1",
|
||||
65001,
|
||||
0,
|
||||
40,
|
||||
NULL,
|
||||
NULL,
|
||||
playcard,
|
||||
captcard,
|
||||
linphone_core_echo_cancellation_enabled(lc)
|
||||
);
|
||||
_post_configure_audio_stream(st,lc,FALSE);
|
||||
conf->local_participant=st;
|
||||
conf->local_endpoint=ms_audio_endpoint_get_from_stream(st,FALSE);
|
||||
ms_audio_conference_add_member(conf->conf,conf->local_endpoint);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sound volume (mic input) of the local participant of the conference.
|
||||
* @param lc the linphone core
|
||||
* @return 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;
|
||||
if (st && st->volsend && !conf->local_muted){
|
||||
float vol=0;
|
||||
ms_filter_call_method(st->volsend,MS_VOLUME_GET,&vol);
|
||||
return vol;
|
||||
|
||||
}
|
||||
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.
|
||||
*
|
||||
* @return 0 if successful, -1 otherwise.
|
||||
**/
|
||||
int linphone_core_add_to_conference(LinphoneCore *lc, LinphoneCall *call){
|
||||
LinphoneConference *conf=&lc->conf_ctx;
|
||||
|
||||
if (call->current_params->in_conference){
|
||||
ms_error("Already in conference");
|
||||
return -1;
|
||||
}
|
||||
conference_check_init(&lc->conf_ctx, lp_config_get_int(lc->config, "sound","conference_rate",16000));
|
||||
|
||||
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){
|
||||
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*/
|
||||
linphone_call_init_media_streams(call);
|
||||
}
|
||||
if (call==lc->current_call){
|
||||
lc->current_call=NULL;
|
||||
}
|
||||
/*this will trigger a reINVITE that will later redraw the streams */
|
||||
/*FIXME probably a bit too much to just redraw 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));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int remove_from_conference(LinphoneCore *lc, LinphoneCall *call, bool_t active){
|
||||
int err=0;
|
||||
char *str;
|
||||
|
||||
if (!call->current_params->in_conference){
|
||||
if (call->params->in_conference){
|
||||
ms_warning("Not (yet) in conference, be patient");
|
||||
return -1;
|
||||
}else{
|
||||
ms_error("Not in a conference.");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
call->params->in_conference=FALSE;
|
||||
|
||||
str=linphone_call_get_remote_address_as_string(call);
|
||||
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,params);
|
||||
linphone_call_params_destroy(params);
|
||||
} else{
|
||||
ms_message("Pausing call to actually remove from conference");
|
||||
err=_linphone_core_pause_call(lc,call);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static int convert_conference_to_call(LinphoneCore *lc){
|
||||
int err=0;
|
||||
MSList *calls=lc->calls;
|
||||
|
||||
if (remote_participants_count(&lc->conf_ctx)!=1){
|
||||
ms_error("No unique call remaining in conference.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (calls) {
|
||||
LinphoneCall *rc=(LinphoneCall*)calls->data;
|
||||
calls=calls->next;
|
||||
if (rc->params->in_conference) { // not using current_param
|
||||
bool_t active_after_removed=linphone_core_is_in_conference(lc);
|
||||
err=remove_from_conference(lc, rc, active_after_removed);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int linphone_core_remove_from_conference(LinphoneCore *lc, LinphoneCall *call){
|
||||
int err;
|
||||
char * str=linphone_call_get_remote_address_as_string(call);
|
||||
ms_message("Removing call %s from the conference", str);
|
||||
ms_free(str);
|
||||
err=remove_from_conference(lc,call, FALSE);
|
||||
if (err){
|
||||
ms_error("Error removing participant from conference.");
|
||||
return err;
|
||||
}
|
||||
|
||||
if (remote_participants_count(&lc->conf_ctx)==1){
|
||||
ms_message("conference size is 1: need to be converted to plain call");
|
||||
err=convert_conference_to_call(lc);
|
||||
} else {
|
||||
ms_message("the conference need not to be converted as size is %i", remote_participants_count(&lc->conf_ctx));
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
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.
|
||||
* @return 0 if successful, -1 otherwise.
|
||||
**/
|
||||
int linphone_core_leave_conference(LinphoneCore *lc){
|
||||
LinphoneConference *conf=&lc->conf_ctx;
|
||||
if (linphone_core_is_in_conference(lc))
|
||||
remove_local_endpoint(conf);
|
||||
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.
|
||||
*
|
||||
* @return 0 if successful, -1 otherwise
|
||||
**/
|
||||
int linphone_core_enter_conference(LinphoneCore *lc){
|
||||
LinphoneConference *conf;
|
||||
if (linphone_core_sound_resources_locked(lc)) {
|
||||
return -1;
|
||||
}
|
||||
if (lc->current_call != NULL) {
|
||||
_linphone_core_pause_call(lc, lc->current_call);
|
||||
}
|
||||
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.
|
||||
*
|
||||
* @return 0 if successful, -1 otherwise
|
||||
**/
|
||||
int linphone_core_add_all_to_conference(LinphoneCore *lc) {
|
||||
MSList *calls=lc->calls;
|
||||
while (calls) {
|
||||
LinphoneCall *call=(LinphoneCall*)calls->data;
|
||||
calls=calls->next;
|
||||
if (!call->current_params->in_conference) {
|
||||
linphone_core_add_to_conference(lc, call);
|
||||
}
|
||||
}
|
||||
linphone_core_enter_conference(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.
|
||||
*
|
||||
* @return 0 if successful, -1 otherwise
|
||||
**/
|
||||
int linphone_core_terminate_conference(LinphoneCore *lc) {
|
||||
MSList *calls=lc->calls;
|
||||
LinphoneConference *conf=&lc->conf_ctx;
|
||||
conf->terminated=TRUE;
|
||||
|
||||
while (calls) {
|
||||
LinphoneCall *call=(LinphoneCall*)calls->data;
|
||||
calls=calls->next;
|
||||
if (call->current_params->in_conference) {
|
||||
linphone_core_terminate_call(lc, call);
|
||||
}
|
||||
}
|
||||
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.
|
||||
*
|
||||
* @return the number of participants to the conference
|
||||
**/
|
||||
int linphone_core_get_conference_size(LinphoneCore *lc) {
|
||||
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;
|
||||
}
|
||||
ms_audio_recorder_endpoint_stop(conf->record_endpoint);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
**/
|
||||
|
||||
883
coreapi/conference.cc
Normal file
883
coreapi/conference.cc
Normal file
|
|
@ -0,0 +1,883 @@
|
|||
/*******************************************************************************
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "private.h"
|
||||
#include "conference.h"
|
||||
#include <mediastreamer2/msvolume.h>
|
||||
#include <typeinfo>
|
||||
#include <list>
|
||||
#include <algorithm>
|
||||
|
||||
namespace Linphone {
|
||||
|
||||
class Participant {
|
||||
public:
|
||||
Participant(LinphoneCall *call);
|
||||
Participant(const Participant &src);
|
||||
~Participant();
|
||||
bool operator==(const Participant &src) const;
|
||||
const LinphoneAddress *getUri() const {return m_uri;}
|
||||
LinphoneCall *getCall() const {return m_call;}
|
||||
void setCall(LinphoneCall *call) {m_call = call;}
|
||||
|
||||
private:
|
||||
LinphoneAddress *m_uri;
|
||||
LinphoneCall *m_call;
|
||||
};
|
||||
|
||||
class Conference {
|
||||
public:
|
||||
Conference(LinphoneCore *core);
|
||||
virtual ~Conference() {};
|
||||
|
||||
virtual int addParticipant(LinphoneCall *call) = 0;
|
||||
virtual int removeParticipant(LinphoneCall *call) = 0;
|
||||
virtual int removeParticipant(const LinphoneAddress *uri) = 0;
|
||||
virtual int terminate() = 0;
|
||||
|
||||
virtual int enter() = 0;
|
||||
virtual int leave() = 0;
|
||||
virtual bool isIn() const = 0;
|
||||
|
||||
AudioStream *getAudioStream() const {return m_localParticipantStream;}
|
||||
int muteMicrophone(bool val);
|
||||
bool microphoneIsMuted() const {return m_isMuted;}
|
||||
float getInputVolume() const;
|
||||
|
||||
virtual int getParticipantCount() const {return m_participants.size();}
|
||||
const std::list<Participant> &getParticipants() const {return m_participants;}
|
||||
|
||||
virtual int startRecording(const char *path) = 0;
|
||||
virtual int stopRecording() = 0;
|
||||
|
||||
virtual void onCallStreamStarting(LinphoneCall *call, bool isPausedByRemote) {};
|
||||
virtual void onCallStreamStopping(LinphoneCall *call) {};
|
||||
virtual void onCallTerminating(LinphoneCall *call) {};
|
||||
|
||||
protected:
|
||||
Participant *find_participant(const LinphoneAddress *uri);
|
||||
|
||||
LinphoneCore *m_core;
|
||||
AudioStream *m_localParticipantStream;
|
||||
bool m_isMuted;
|
||||
std::list<Participant> m_participants;
|
||||
};
|
||||
|
||||
class LocalConference: public Conference {
|
||||
public:
|
||||
LocalConference(LinphoneCore *core);
|
||||
virtual ~LocalConference();
|
||||
|
||||
virtual int addParticipant(LinphoneCall *call);
|
||||
virtual int removeParticipant(LinphoneCall *call);
|
||||
virtual int removeParticipant(const LinphoneAddress *uri);
|
||||
virtual int terminate();
|
||||
|
||||
virtual int enter();
|
||||
virtual int leave();
|
||||
virtual bool isIn() const {return m_localParticipantStream!=NULL;}
|
||||
virtual int getParticipantCount() const;
|
||||
|
||||
virtual int startRecording(const char *path);
|
||||
virtual int stopRecording();
|
||||
|
||||
void onCallStreamStarting(LinphoneCall *call, bool isPausedByRemote);
|
||||
void onCallStreamStopping(LinphoneCall *call);
|
||||
void onCallTerminating(LinphoneCall *call);
|
||||
|
||||
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;
|
||||
bool_t m_terminated;
|
||||
};
|
||||
|
||||
class RemoteConference: public Conference {
|
||||
public:
|
||||
RemoteConference(LinphoneCore *core);
|
||||
virtual ~RemoteConference();
|
||||
|
||||
virtual int addParticipant(LinphoneCall *call);
|
||||
virtual int removeParticipant(LinphoneCall *call) {return -1;}
|
||||
virtual int removeParticipant(const LinphoneAddress *uri);
|
||||
virtual int terminate();
|
||||
|
||||
virtual int enter();
|
||||
virtual int leave();
|
||||
virtual bool isIn() const;
|
||||
|
||||
virtual int startRecording(const char *path) {return 0;}
|
||||
virtual int stopRecording() {return 0;}
|
||||
|
||||
private:
|
||||
enum State {
|
||||
NotConnectedToFocus,
|
||||
ConnectingToFocus,
|
||||
ConnectedToFocus,
|
||||
};
|
||||
static const char *stateToString(State state);
|
||||
|
||||
void onFocusCallSateChanged(LinphoneCallState state);
|
||||
void onPendingCallStateChanged(LinphoneCall *call, LinphoneCallState state);
|
||||
|
||||
static void callStateChangedCb(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *message);
|
||||
static void transferStateChanged(LinphoneCore *lc, LinphoneCall *transfered, LinphoneCallState new_call_state);
|
||||
|
||||
const char *m_focusAddr;
|
||||
char *m_focusContact;
|
||||
LinphoneCall *m_focusCall;
|
||||
State m_state;
|
||||
LinphoneCoreVTable *m_vtable;
|
||||
MSList *m_pendingCalls;
|
||||
MSList *m_transferingCalls;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
using namespace Linphone;
|
||||
using namespace std;
|
||||
|
||||
|
||||
Participant::Participant(LinphoneCall *call) {
|
||||
m_uri = linphone_address_clone(linphone_call_get_remote_address(call));
|
||||
m_call = linphone_call_ref(call);
|
||||
}
|
||||
|
||||
Participant::Participant(const Participant &src) {
|
||||
m_uri = linphone_address_clone(src.m_uri);
|
||||
m_call = src.m_call ? linphone_call_ref(src.m_call) : NULL;
|
||||
}
|
||||
|
||||
Participant::~Participant() {
|
||||
linphone_address_unref(m_uri);
|
||||
if(m_call) linphone_call_unref(m_call);
|
||||
}
|
||||
|
||||
bool Participant::operator==(const Participant &src) const {
|
||||
return linphone_address_equal(m_uri, src.m_uri);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Conference::Conference(LinphoneCore *core) :
|
||||
m_core(core),
|
||||
m_localParticipantStream(NULL),
|
||||
m_isMuted(false) {
|
||||
}
|
||||
|
||||
int Conference::addParticipant(LinphoneCall *call) {
|
||||
Participant participant(call);
|
||||
m_participants.push_back(participant);
|
||||
call->conf_ref = (LinphoneConference *)this;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Conference::removeParticipant(LinphoneCall *call) {
|
||||
Participant participant(call);
|
||||
m_participants.remove(participant);
|
||||
call->conf_ref = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Conference::removeParticipant(const LinphoneAddress *uri) {
|
||||
Participant *participant = find_participant(uri);
|
||||
if(participant == NULL) return -1;
|
||||
LinphoneCall *call = participant->getCall();
|
||||
if(call) call->conf_ref = NULL;
|
||||
m_participants.remove(Participant(*participant));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Conference::muteMicrophone(bool val) {
|
||||
if (val) {
|
||||
audio_stream_set_mic_gain(m_localParticipantStream, 0);
|
||||
} else {
|
||||
audio_stream_set_mic_gain_db(m_localParticipantStream, m_core->sound_conf.soft_mic_lev);
|
||||
}
|
||||
if ( linphone_core_get_rtp_no_xmit_on_audio_mute(m_core) ){
|
||||
audio_stream_mute_rtp(m_localParticipantStream, val);
|
||||
}
|
||||
m_isMuted=val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
return vol;
|
||||
|
||||
}
|
||||
return LINPHONE_VOLUME_DB_LOWEST;
|
||||
}
|
||||
|
||||
Participant *Conference::find_participant(const LinphoneAddress *uri) {
|
||||
list<Participant>::iterator it = m_participants.begin();
|
||||
while(it!=m_participants.end()) {
|
||||
if(linphone_address_equal(uri, it->getUri())) break;
|
||||
it++;
|
||||
}
|
||||
if(it == m_participants.end()) return NULL;
|
||||
else return &*it;
|
||||
}
|
||||
|
||||
|
||||
|
||||
LocalConference::LocalConference(LinphoneCore *core): Conference(core),
|
||||
m_conf(NULL),
|
||||
m_localEndpoint(NULL),
|
||||
m_recordEndpoint(NULL),
|
||||
m_localDummyProfile(NULL),
|
||||
m_terminated(FALSE) {
|
||||
MSAudioConferenceParams params;
|
||||
params.samplerate = lp_config_get_int(m_core->config, "sound","conference_rate",16000);
|
||||
m_conf=ms_audio_conference_new(¶ms);
|
||||
}
|
||||
|
||||
LocalConference::~LocalConference() {
|
||||
if(m_conf) terminate();
|
||||
}
|
||||
|
||||
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);
|
||||
return prof;
|
||||
}
|
||||
|
||||
void LocalConference::addLocalEndpoint() {
|
||||
/*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,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);
|
||||
|
||||
audio_stream_start_full(st, m_localDummyProfile,
|
||||
"127.0.0.1",
|
||||
65000,
|
||||
"127.0.0.1",
|
||||
65001,
|
||||
0,
|
||||
40,
|
||||
NULL,
|
||||
NULL,
|
||||
playcard,
|
||||
captcard,
|
||||
linphone_core_echo_cancellation_enabled(m_core)
|
||||
);
|
||||
_post_configure_audio_stream(st,m_core,FALSE);
|
||||
m_localParticipantStream=st;
|
||||
m_localEndpoint=ms_audio_endpoint_get_from_stream(st,FALSE);
|
||||
ms_audio_conference_add_member(m_conf,m_localEndpoint);
|
||||
}
|
||||
|
||||
int LocalConference::addParticipant(LinphoneCall *call) {
|
||||
if (call->current_params->in_conference){
|
||||
ms_error("Already in conference");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (call->state==LinphoneCallPaused){
|
||||
call->params->in_conference=TRUE;
|
||||
call->params->has_video=FALSE;
|
||||
linphone_core_resume_call(m_core,call);
|
||||
}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*/
|
||||
linphone_call_init_media_streams(call);
|
||||
}
|
||||
if (call==m_core->current_call){
|
||||
m_core->current_call=NULL;
|
||||
}
|
||||
/*this will trigger a reINVITE that will later redraw the streams */
|
||||
/*FIXME probably a bit too much to just redraw streams !*/
|
||||
linphone_core_update_call(m_core,call,params);
|
||||
linphone_call_params_destroy(params);
|
||||
addLocalEndpoint();
|
||||
}else{
|
||||
ms_error("Call is in state %s, it cannot be added to the conference.",linphone_call_state_to_string(call->state));
|
||||
return -1;
|
||||
}
|
||||
Conference::addParticipant(call);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LocalConference::removeFromConference(LinphoneCall *call, bool_t active){
|
||||
int err=0;
|
||||
char *str;
|
||||
|
||||
if (!call->current_params->in_conference){
|
||||
if (call->params->in_conference){
|
||||
ms_warning("Not (yet) in conference, be patient");
|
||||
return -1;
|
||||
}else{
|
||||
ms_error("Not in a conference.");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
call->params->in_conference=FALSE;
|
||||
Conference::removeParticipant(call);
|
||||
|
||||
str=linphone_call_get_remote_address_as_string(call);
|
||||
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 (isIn()){
|
||||
ms_message("Leaving conference for reconnecting with unique call.");
|
||||
leave();
|
||||
}
|
||||
ms_message("Updating call to actually remove from conference");
|
||||
err=linphone_core_update_call(m_core,call,params);
|
||||
linphone_call_params_destroy(params);
|
||||
} else{
|
||||
ms_message("Pausing call to actually remove from conference");
|
||||
err=_linphone_core_pause_call(m_core,call);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int LocalConference::remoteParticipantsCount() {
|
||||
int count=getParticipantCount();
|
||||
if (count==0) return 0;
|
||||
if (!m_localParticipantStream) return count;
|
||||
return count -1;
|
||||
}
|
||||
|
||||
int LocalConference::convertConferenceToCall(){
|
||||
int err=0;
|
||||
MSList *calls=m_core->calls;
|
||||
|
||||
if (remoteParticipantsCount()!=1){
|
||||
ms_error("No unique call remaining in conference.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (calls) {
|
||||
LinphoneCall *rc=(LinphoneCall*)calls->data;
|
||||
calls=calls->next;
|
||||
if (rc->params->in_conference) { // not using current_param
|
||||
bool_t active_after_removed=isIn();
|
||||
err=removeFromConference(rc, active_after_removed);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int LocalConference::removeParticipant(LinphoneCall *call) {
|
||||
int err;
|
||||
char * str=linphone_call_get_remote_address_as_string(call);
|
||||
ms_message("Removing call %s from the conference", str);
|
||||
ms_free(str);
|
||||
err=removeFromConference(call, FALSE);
|
||||
if (err){
|
||||
ms_error("Error removing participant from conference.");
|
||||
return err;
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int LocalConference::removeParticipant(const LinphoneAddress *uri) {
|
||||
Participant *participant = find_participant(uri);
|
||||
if(participant == NULL) return -1;
|
||||
LinphoneCall *call = participant->getCall();
|
||||
if(call == NULL) return -1;
|
||||
return removeParticipant(call);
|
||||
}
|
||||
|
||||
int LocalConference::terminate() {
|
||||
MSList *calls=m_core->calls;
|
||||
m_terminated=TRUE;
|
||||
|
||||
while (calls) {
|
||||
LinphoneCall *call=(LinphoneCall*)calls->data;
|
||||
calls=calls->next;
|
||||
if (call->current_params->in_conference) {
|
||||
linphone_core_terminate_call(m_core, call);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LocalConference::enter() {
|
||||
if (linphone_core_sound_resources_locked(m_core)) {
|
||||
return -1;
|
||||
}
|
||||
if (m_core->current_call != NULL) {
|
||||
_linphone_core_pause_call(m_core, m_core->current_call);
|
||||
}
|
||||
if (m_localParticipantStream==NULL) addLocalEndpoint();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void LocalConference::removeLocalEndpoint(){
|
||||
if (m_localEndpoint){
|
||||
ms_audio_conference_remove_member(m_conf,m_localEndpoint);
|
||||
ms_audio_endpoint_release_from_stream(m_localEndpoint);
|
||||
m_localEndpoint=NULL;
|
||||
audio_stream_stop(m_localParticipantStream);
|
||||
m_localParticipantStream=NULL;
|
||||
rtp_profile_destroy(m_localDummyProfile);
|
||||
}
|
||||
}
|
||||
|
||||
int LocalConference::leave() {
|
||||
if (isIn())
|
||||
removeLocalEndpoint();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LocalConference::getParticipantCount() const {
|
||||
if (m_conf == NULL) {
|
||||
return 0;
|
||||
}
|
||||
return ms_audio_conference_get_size(m_conf) - (m_recordEndpoint ? 1 : 0);
|
||||
}
|
||||
|
||||
int LocalConference::startRecording(const char *path) {
|
||||
if (m_conf == NULL) {
|
||||
ms_warning("linphone_core_start_conference_recording(): no conference now.");
|
||||
return -1;
|
||||
}
|
||||
if (m_recordEndpoint==NULL){
|
||||
m_recordEndpoint=ms_audio_endpoint_new_recorder();
|
||||
ms_audio_conference_add_member(m_conf,m_recordEndpoint);
|
||||
}
|
||||
ms_audio_recorder_endpoint_start(m_recordEndpoint,path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LocalConference::stopRecording() {
|
||||
if (m_conf == NULL) {
|
||||
ms_warning("linphone_core_stop_conference_recording(): no conference now.");
|
||||
return -1;
|
||||
}
|
||||
if (m_recordEndpoint==NULL){
|
||||
ms_warning("linphone_core_stop_conference_recording(): no record active.");
|
||||
return -1;
|
||||
}
|
||||
ms_audio_recorder_endpoint_stop(m_recordEndpoint);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void LocalConference::onCallStreamStarting(LinphoneCall *call, bool isPausedByRemote) {
|
||||
call->params->has_video = FALSE;
|
||||
call->camera_enabled = FALSE;
|
||||
MSAudioEndpoint *ep=ms_audio_endpoint_get_from_stream(call->audiostream,TRUE);
|
||||
ms_audio_conference_add_member(m_conf,ep);
|
||||
ms_audio_conference_mute_member(m_conf,ep,isPausedByRemote);
|
||||
call->endpoint=ep;
|
||||
}
|
||||
|
||||
void LocalConference::onCallStreamStopping(LinphoneCall *call) {
|
||||
ms_audio_conference_remove_member(m_conf,call->endpoint);
|
||||
ms_audio_endpoint_release_from_stream(call->endpoint);
|
||||
call->endpoint=NULL;
|
||||
}
|
||||
|
||||
void LocalConference::onCallTerminating(LinphoneCall *call) {
|
||||
int remote_count=remoteParticipantsCount();
|
||||
ms_message("conference_check_uninit(): size=%i", getParticipantCount());
|
||||
if (remote_count==1 && !m_terminated){
|
||||
convertConferenceToCall();
|
||||
}
|
||||
if (remote_count==0){
|
||||
if (m_localParticipantStream)
|
||||
removeLocalEndpoint();
|
||||
if (m_recordEndpoint){
|
||||
ms_audio_conference_remove_member(m_conf, m_recordEndpoint);
|
||||
ms_audio_endpoint_destroy(m_recordEndpoint);
|
||||
}
|
||||
}
|
||||
if (ms_audio_conference_get_size(m_conf)==0){
|
||||
ms_audio_conference_destroy(m_conf);
|
||||
m_core->conf_ctx = NULL;
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
RemoteConference::RemoteConference(LinphoneCore *core):
|
||||
Conference(core),
|
||||
m_focusAddr(NULL),
|
||||
m_focusContact(NULL),
|
||||
m_focusCall(NULL),
|
||||
m_state(NotConnectedToFocus),
|
||||
m_vtable(NULL),
|
||||
m_pendingCalls(NULL),
|
||||
m_transferingCalls(NULL) {
|
||||
m_focusAddr = lp_config_get_string(m_core->config, "misc", "conference_focus_addr", "");
|
||||
m_vtable = linphone_core_v_table_new();
|
||||
m_vtable->call_state_changed = callStateChangedCb;
|
||||
m_vtable->transfer_state_changed = transferStateChanged;
|
||||
linphone_core_v_table_set_user_data(m_vtable, this);
|
||||
_linphone_core_add_listener(m_core, m_vtable, FALSE, TRUE);
|
||||
}
|
||||
|
||||
RemoteConference::~RemoteConference() {
|
||||
if(m_state == ConnectedToFocus) terminate();
|
||||
linphone_core_remove_listener(m_core, m_vtable);
|
||||
linphone_core_v_table_destroy(m_vtable);
|
||||
}
|
||||
|
||||
int RemoteConference::addParticipant(LinphoneCall *call) {
|
||||
LinphoneAddress *addr;
|
||||
|
||||
switch(m_state) {
|
||||
case NotConnectedToFocus:
|
||||
Conference::addParticipant(call);
|
||||
ms_message("Calling the conference focus (%s)", m_focusAddr);
|
||||
addr = linphone_address_new(m_focusAddr);
|
||||
if(addr) {
|
||||
m_focusCall = linphone_call_ref(linphone_core_invite_address(m_core, addr));
|
||||
m_localParticipantStream = m_focusCall->audiostream;
|
||||
m_pendingCalls = ms_list_append(m_pendingCalls, linphone_call_ref(call));
|
||||
m_state = ConnectingToFocus;
|
||||
linphone_address_unref(addr);
|
||||
addParticipant(m_focusCall);
|
||||
return 0;
|
||||
} else return -1;
|
||||
|
||||
case ConnectingToFocus:
|
||||
Conference::addParticipant(call);
|
||||
m_pendingCalls = ms_list_append(m_pendingCalls, linphone_call_ref(call));
|
||||
return 0;
|
||||
|
||||
case ConnectedToFocus:
|
||||
Conference::addParticipant(call);
|
||||
m_transferingCalls = ms_list_append(m_transferingCalls, linphone_call_ref(call));
|
||||
linphone_core_transfer_call(m_core, call, m_focusContact);
|
||||
return 0;
|
||||
|
||||
default:
|
||||
ms_error("Could not add call %p to the conference. Bad conference state (%s)", call, stateToString(m_state));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int RemoteConference::removeParticipant(const LinphoneAddress *uri) {
|
||||
char *tmp, *refer_to;
|
||||
int res;
|
||||
|
||||
switch(m_state) {
|
||||
case ConnectedToFocus:
|
||||
tmp = linphone_address_as_string_uri_only(uri);
|
||||
refer_to = ms_strdup_printf("%s;method=BYE", tmp);
|
||||
res = sal_call_refer(m_focusCall->op, refer_to);
|
||||
ms_free(tmp);
|
||||
ms_free(refer_to);
|
||||
|
||||
if(res == 0) return Conference::removeParticipant(uri);
|
||||
else return -1;
|
||||
|
||||
default:
|
||||
ms_error("Cannot remove %s from conference: Bad conference state (%s)", linphone_address_as_string(uri), stateToString(m_state));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int RemoteConference::terminate() {
|
||||
switch(m_state) {
|
||||
case ConnectingToFocus:
|
||||
case ConnectedToFocus:
|
||||
Conference::removeParticipant(m_focusCall);
|
||||
linphone_core_terminate_call(m_core, m_focusCall);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int RemoteConference::enter() {
|
||||
if(m_state != ConnectedToFocus) {
|
||||
ms_error("Could not enter in the conference: bad conference state (%s)", stateToString(m_state));
|
||||
return -1;
|
||||
}
|
||||
LinphoneCallState callState = linphone_call_get_state(m_focusCall);
|
||||
switch(callState) {
|
||||
case LinphoneCallStreamsRunning: break;
|
||||
case LinphoneCallPaused:
|
||||
linphone_core_resume_call(m_core, m_focusCall);
|
||||
break;
|
||||
default:
|
||||
ms_error("Could not join the conference: bad focus call state (%s)", linphone_call_state_to_string(callState));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int RemoteConference::leave() {
|
||||
if(m_state != ConnectedToFocus) {
|
||||
ms_error("Could not leave the conference: bad conference state (%s)", stateToString(m_state));
|
||||
return -1;
|
||||
}
|
||||
LinphoneCallState callState = linphone_call_get_state(m_focusCall);
|
||||
switch(callState) {
|
||||
case LinphoneCallPaused: break;
|
||||
case LinphoneCallStreamsRunning:
|
||||
linphone_core_pause_call(m_core, m_focusCall);
|
||||
break;
|
||||
default:
|
||||
ms_error("Could not leave the conference: bad focus call state (%s)", linphone_call_state_to_string(callState));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool RemoteConference::isIn() const {
|
||||
if(m_state != ConnectedToFocus) return false;
|
||||
LinphoneCallState callState = linphone_call_get_state(m_focusCall);
|
||||
return callState == LinphoneCallStreamsRunning;
|
||||
}
|
||||
|
||||
const char *RemoteConference::stateToString(RemoteConference::State state) {
|
||||
switch(state) {
|
||||
case NotConnectedToFocus: return "NotConnectedToFocus";
|
||||
case ConnectingToFocus: return "ConnectingToFocus";
|
||||
case ConnectedToFocus: return "ConnectedToFocus";
|
||||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
void RemoteConference::onFocusCallSateChanged(LinphoneCallState state) {
|
||||
MSList *it;
|
||||
|
||||
switch (state) {
|
||||
case LinphoneCallConnected:
|
||||
m_state = ConnectedToFocus;
|
||||
m_focusContact = ms_strdup(linphone_call_get_remote_contact(m_focusCall));
|
||||
it = m_pendingCalls;
|
||||
while (it) {
|
||||
LinphoneCall *pendingCall = (LinphoneCall *)it->data;
|
||||
LinphoneCallState pendingCallState = linphone_call_get_state(pendingCall);
|
||||
if(pendingCallState == LinphoneCallStreamsRunning || pendingCallState == LinphoneCallPaused) {
|
||||
MSList *current_elem = it;
|
||||
it = it->next;
|
||||
m_pendingCalls = ms_list_remove_link(m_pendingCalls, current_elem);
|
||||
m_transferingCalls = ms_list_append(m_transferingCalls, pendingCall);
|
||||
linphone_core_transfer_call(m_core, pendingCall, m_focusContact);
|
||||
} else {
|
||||
it = it->next;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case LinphoneCallError:
|
||||
case LinphoneCallEnd:
|
||||
Conference::removeParticipant(m_focusCall);
|
||||
m_state = NotConnectedToFocus;
|
||||
linphone_call_unref(m_focusCall);
|
||||
m_focusCall = NULL;
|
||||
m_localParticipantStream = NULL;
|
||||
if(m_focusContact) {
|
||||
ms_free(m_focusContact);
|
||||
m_focusContact = NULL;
|
||||
}
|
||||
m_pendingCalls = ms_list_free_with_data(m_pendingCalls, (void (*)(void *))linphone_call_unref);
|
||||
m_transferingCalls = ms_list_free_with_data(m_transferingCalls, (void (*)(void *))linphone_call_unref);
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
void RemoteConference::onPendingCallStateChanged(LinphoneCall *call, LinphoneCallState state) {
|
||||
switch(state) {
|
||||
case LinphoneCallStreamsRunning:
|
||||
case LinphoneCallPaused:
|
||||
if(m_state == ConnectedToFocus) {
|
||||
m_pendingCalls = ms_list_remove(m_pendingCalls, call);
|
||||
m_transferingCalls = ms_list_append(m_transferingCalls, call);
|
||||
linphone_core_transfer_call(m_core, call, m_focusContact);
|
||||
}
|
||||
break;
|
||||
|
||||
case LinphoneCallError:
|
||||
case LinphoneCallEnd:
|
||||
Conference::removeParticipant(call);
|
||||
m_pendingCalls = ms_list_remove(m_pendingCalls, call);
|
||||
linphone_call_unref(call);
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
void RemoteConference::callStateChangedCb(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *message) {
|
||||
LinphoneCoreVTable *vtable = linphone_core_get_current_vtable(lc);
|
||||
RemoteConference *conf = (RemoteConference *)linphone_core_v_table_get_user_data(vtable);
|
||||
if (call == conf->m_focusCall) {
|
||||
conf->onFocusCallSateChanged(cstate);
|
||||
} else if(ms_list_find(conf->m_pendingCalls, call)) {
|
||||
conf->onPendingCallStateChanged(call, cstate);
|
||||
}
|
||||
}
|
||||
|
||||
void RemoteConference::transferStateChanged(LinphoneCore *lc, LinphoneCall *transfered, LinphoneCallState new_call_state) {
|
||||
LinphoneCoreVTable *vtable = linphone_core_get_current_vtable(lc);
|
||||
RemoteConference *conf = (RemoteConference *)linphone_core_v_table_get_user_data(vtable);
|
||||
if (ms_list_find(conf->m_transferingCalls, transfered)) {
|
||||
switch (new_call_state) {
|
||||
case LinphoneCallConnected:
|
||||
case LinphoneCallError:
|
||||
conf->m_transferingCalls = ms_list_remove(conf->m_transferingCalls, transfered);
|
||||
linphone_call_unref(transfered);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
LinphoneConference *linphone_local_conference_new(LinphoneCore *core) {
|
||||
return (LinphoneConference *) new LocalConference(core);
|
||||
}
|
||||
|
||||
LinphoneConference *linphone_remote_conference_new(LinphoneCore *core) {
|
||||
return (LinphoneConference *) new RemoteConference(core);
|
||||
}
|
||||
|
||||
void linphone_conference_free(LinphoneConference *obj) {
|
||||
delete (Conference *)obj;
|
||||
}
|
||||
|
||||
int linphone_conference_add_participant(LinphoneConference *obj, LinphoneCall *call) {
|
||||
return ((Conference *)obj)->addParticipant(call);
|
||||
}
|
||||
|
||||
int linphone_conference_remove_participant(LinphoneConference *obj, const LinphoneAddress *uri) {
|
||||
return ((Conference *)obj)->removeParticipant(uri);
|
||||
}
|
||||
|
||||
int linphone_conference_remove_participant_with_call(LinphoneConference *obj, LinphoneCall *call) {
|
||||
return ((Conference *)obj)->removeParticipant(call);
|
||||
}
|
||||
|
||||
int linphone_conference_terminate(LinphoneConference *obj) {
|
||||
return ((Conference *)obj)->terminate();
|
||||
}
|
||||
|
||||
int linphone_conference_enter(LinphoneConference *obj) {
|
||||
return ((Conference *)obj)->enter();
|
||||
}
|
||||
|
||||
int linphone_conference_leave(LinphoneConference *obj) {
|
||||
return ((Conference *)obj)->leave();
|
||||
}
|
||||
|
||||
bool_t linphone_conference_is_in(const LinphoneConference *obj) {
|
||||
return ((Conference *)obj)->isIn() ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
AudioStream *linphone_conference_get_audio_stream(const LinphoneConference *obj) {
|
||||
return ((Conference *)obj)->getAudioStream();
|
||||
}
|
||||
|
||||
int linphone_conference_mute_microphone(LinphoneConference *obj, bool_t val) {
|
||||
return ((Conference *)obj)->muteMicrophone(val);
|
||||
}
|
||||
|
||||
bool_t linphone_conference_microphone_is_muted(const LinphoneConference *obj) {
|
||||
return ((Conference *)obj)->microphoneIsMuted();
|
||||
}
|
||||
|
||||
float linphone_conference_get_input_volume(const LinphoneConference *obj) {
|
||||
return ((Conference *)obj)->getInputVolume();
|
||||
}
|
||||
|
||||
int linphone_conference_get_participant_count(const LinphoneConference *obj) {
|
||||
return ((Conference *)obj)->getParticipantCount();
|
||||
}
|
||||
|
||||
MSList *linphone_conference_get_participants(const LinphoneConference *obj) {
|
||||
const list<Participant> participants = ((Conference *)obj)->getParticipants();
|
||||
MSList *participants_list = NULL;
|
||||
for(list<Participant>::const_iterator it=participants.begin();it!=participants.end();it++) {
|
||||
LinphoneAddress *uri = linphone_address_clone(it->getUri());
|
||||
participants_list = ms_list_append(participants_list, uri);
|
||||
}
|
||||
return participants_list;
|
||||
}
|
||||
|
||||
int linphone_conference_start_recording(LinphoneConference *obj, const char *path) {
|
||||
return ((Conference *)obj)->startRecording(path);
|
||||
}
|
||||
|
||||
int linphone_conference_stop_recording(LinphoneConference *obj) {
|
||||
return ((Conference *)obj)->stopRecording();
|
||||
}
|
||||
|
||||
void linphone_conference_on_call_stream_starting(LinphoneConference *obj, LinphoneCall *call, bool_t is_paused_by_remote) {
|
||||
((Conference *)obj)->onCallStreamStarting(call, is_paused_by_remote);
|
||||
}
|
||||
|
||||
void linphone_conference_on_call_stream_stopping(LinphoneConference *obj, LinphoneCall *call) {
|
||||
((Conference *)obj)->onCallStreamStopping(call);
|
||||
}
|
||||
|
||||
void linphone_conference_on_call_terminating(LinphoneConference *obj, LinphoneCall *call) {
|
||||
((Conference *)obj)->onCallTerminating(call);
|
||||
}
|
||||
|
||||
bool_t linphone_conference_check_class(LinphoneConference *obj, LinphoneConferenceClass _class) {
|
||||
switch(_class) {
|
||||
case LinphoneConferenceClassLocal: return typeid(obj) == typeid(LocalConference);
|
||||
case LinphoneConferenceClassRemote: return typeid(obj) == typeid(RemoteConference);
|
||||
default: return FALSE;
|
||||
}
|
||||
}
|
||||
68
coreapi/conference.h
Normal file
68
coreapi/conference.h
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/*******************************************************************************
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef CONFERENCE_H
|
||||
#define CONFERENCE_H
|
||||
|
||||
#include "linphonecore.h"
|
||||
|
||||
typedef struct _LinphoneConference LinphoneConference;
|
||||
|
||||
typedef enum {
|
||||
LinphoneConferenceClassLocal,
|
||||
LinphoneConferenceClassRemote
|
||||
} LinphoneConferenceClass;
|
||||
|
||||
LinphoneConference *linphone_local_conference_new(LinphoneCore *core);
|
||||
LinphoneConference *linphone_remote_conference_new(LinphoneCore *core);
|
||||
void linphone_conference_free(LinphoneConference *obj);
|
||||
|
||||
int linphone_conference_add_participant(LinphoneConference *obj, LinphoneCall *call);
|
||||
int linphone_conference_remove_participant_with_call(LinphoneConference *obj, LinphoneCall *call);
|
||||
int linphone_conference_remove_participant(LinphoneConference *obj, const LinphoneAddress *uri);
|
||||
int linphone_conference_terminate(LinphoneConference *obj);
|
||||
|
||||
int linphone_conference_enter(LinphoneConference *obj);
|
||||
int linphone_conference_leave(LinphoneConference *obj);
|
||||
bool_t linphone_conference_is_in(const LinphoneConference *obj);
|
||||
AudioStream *linphone_conference_get_audio_stream(const LinphoneConference *obj);
|
||||
|
||||
int linphone_conference_mute_microphone(LinphoneConference *obj, bool_t val);
|
||||
bool_t linphone_conference_microphone_is_muted(const LinphoneConference *obj);
|
||||
float linphone_conference_get_input_volume(const LinphoneConference *obj);
|
||||
|
||||
int linphone_conference_get_participant_count(const LinphoneConference *obj);
|
||||
MSList *linphone_conference_get_participants(const LinphoneConference *obj);
|
||||
|
||||
int linphone_conference_start_recording(LinphoneConference *obj, const char *path);
|
||||
int linphone_conference_stop_recording(LinphoneConference *obj);
|
||||
|
||||
void linphone_conference_on_call_stream_starting(LinphoneConference *obj, LinphoneCall *call, bool_t is_paused_by_remote);
|
||||
void linphone_conference_on_call_stream_stopping(LinphoneConference *obj, LinphoneCall *call);
|
||||
void linphone_conference_on_call_terminating(LinphoneConference *obj, LinphoneCall *call);
|
||||
|
||||
bool_t linphone_conference_check_class(LinphoneConference *obj, LinphoneConferenceClass _class);
|
||||
|
||||
#endif // CONFERENCE_H
|
||||
|
|
@ -1433,7 +1433,7 @@ static void linphone_call_set_terminated(LinphoneCall *call){
|
|||
if (linphone_core_del_call(lc,call) != 0){
|
||||
ms_error("Could not remove the call from the list !!!");
|
||||
}
|
||||
linphone_core_conference_check_uninit(lc);
|
||||
if(lc->conf_ctx) linphone_conference_on_call_terminating(lc->conf_ctx, call);
|
||||
if (call->ringing_beep){
|
||||
linphone_core_stop_dtmf(lc);
|
||||
call->ringing_beep=FALSE;
|
||||
|
|
@ -3108,7 +3108,7 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, LinphoneCallSta
|
|||
if (call->params->in_conference){
|
||||
/*transform the graph to connect it to the conference filter */
|
||||
mute = stream->dir==SalStreamRecvOnly;
|
||||
linphone_call_add_to_conf(call, mute);
|
||||
linphone_conference_on_call_stream_starting(lc->conf_ctx, call, mute);
|
||||
}
|
||||
call->current_params->in_conference=call->params->in_conference;
|
||||
call->current_params->low_bandwidth=call->params->low_bandwidth;
|
||||
|
|
@ -3600,6 +3600,7 @@ static void update_rtp_stats(LinphoneCall *call, int stream_index) {
|
|||
}
|
||||
|
||||
static void linphone_call_stop_audio_stream(LinphoneCall *call) {
|
||||
LinphoneCore *lc = call->core;
|
||||
if (call->audiostream!=NULL) {
|
||||
linphone_reporting_update_media_info(call, LINPHONE_CALL_STATS_AUDIO);
|
||||
media_stream_reclaim_sessions(&call->audiostream->ms,&call->sessions[call->main_audio_stream_index]);
|
||||
|
|
@ -3615,7 +3616,7 @@ static void linphone_call_stop_audio_stream(LinphoneCall *call) {
|
|||
audio_stream_get_local_rtp_stats(call->audiostream,&call->log->local_stats);
|
||||
linphone_call_log_fill_stats (call->log,(MediaStream*)call->audiostream);
|
||||
if (call->endpoint){
|
||||
linphone_call_remove_from_conf(call);
|
||||
linphone_conference_on_call_stream_stopping(lc->conf_ctx, call);
|
||||
}
|
||||
update_rtp_stats(call, call->main_audio_stream_index);
|
||||
audio_stream_stop(call->audiostream);
|
||||
|
|
@ -4544,6 +4545,10 @@ bool_t linphone_call_is_in_conference(const LinphoneCall *call) {
|
|||
return call->params->in_conference;
|
||||
}
|
||||
|
||||
LinphoneConference *linphone_call_get_conference(const LinphoneCall *call) {
|
||||
return call->conf_ref;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a zoom of the video displayed during a call.
|
||||
* @param call the call.
|
||||
|
|
@ -4876,4 +4881,3 @@ void linphone_call_refresh_sockets(LinphoneCall *call){
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1698,7 +1698,7 @@ static void linphone_core_init(LinphoneCore * lc, const LinphoneCoreVTable *vtab
|
|||
internal_vtable->notify_received = linphone_core_internal_notify_received;
|
||||
_linphone_core_add_listener(lc, internal_vtable, TRUE);
|
||||
memcpy(local_vtable,vtable,sizeof(LinphoneCoreVTable));
|
||||
_linphone_core_add_listener(lc, local_vtable, TRUE);
|
||||
_linphone_core_add_listener(lc, local_vtable, TRUE, TRUE);
|
||||
|
||||
linphone_core_set_state(lc,LinphoneGlobalStartup,"Starting up");
|
||||
ortp_init();
|
||||
|
|
@ -4890,8 +4890,7 @@ void linphone_core_enable_mic(LinphoneCore *lc, bool_t enable) {
|
|||
const MSList *elem;
|
||||
|
||||
if (linphone_core_is_in_conference(lc)){
|
||||
lc->conf_ctx.local_muted=!enable;
|
||||
linphone_core_mute_audio_stream(lc, lc->conf_ctx.local_participant, !enable);
|
||||
linphone_conference_mute_microphone(lc->conf_ctx, !enable);
|
||||
}
|
||||
list = linphone_core_get_calls(lc);
|
||||
for (elem = list; elem != NULL; elem = elem->next) {
|
||||
|
|
@ -4904,7 +4903,7 @@ void linphone_core_enable_mic(LinphoneCore *lc, bool_t enable) {
|
|||
bool_t linphone_core_mic_enabled(LinphoneCore *lc) {
|
||||
LinphoneCall *call=linphone_core_get_current_call(lc);
|
||||
if (linphone_core_is_in_conference(lc)){
|
||||
return !lc->conf_ctx.local_muted;
|
||||
return linphone_conference_microphone_is_muted(lc->conf_ctx);
|
||||
}else if (call==NULL){
|
||||
ms_warning("%s(): No current call!", __FUNCTION__);
|
||||
return TRUE;
|
||||
|
|
@ -5925,7 +5924,7 @@ static MSFilter *get_audio_resource(LinphoneCore *lc, LinphoneAudioResourceType
|
|||
if (call){
|
||||
stream=call->audiostream;
|
||||
}else if (linphone_core_is_in_conference(lc)){
|
||||
stream=lc->conf_ctx.local_participant;
|
||||
stream=linphone_conference_get_audio_stream(lc->conf_ctx);
|
||||
}
|
||||
if (stream){
|
||||
if (rtype==LinphoneToneGenerator) return stream->dtmfgen;
|
||||
|
|
@ -7434,3 +7433,84 @@ const char *linphone_stream_type_to_string(const LinphoneStreamType type) {
|
|||
LinphoneRingtonePlayer *linphone_core_get_ringtoneplayer(LinphoneCore *lc) {
|
||||
return lc->ringtoneplayer;
|
||||
}
|
||||
|
||||
int linphone_core_add_to_conference(LinphoneCore *lc, LinphoneCall *call) {
|
||||
const char *conf_method_name;
|
||||
if(lc->conf_ctx == NULL) {
|
||||
conf_method_name = lp_config_get_string(lc->config, "misc", "conference_type", "local");
|
||||
if(strcasecmp(conf_method_name, "local") == 0) {
|
||||
lc->conf_ctx = linphone_local_conference_new(lc);
|
||||
} else if(strcasecmp(conf_method_name, "remote") == 0) {
|
||||
lc->conf_ctx = linphone_remote_conference_new(lc);
|
||||
} else {
|
||||
ms_error("'%s' is not a valid conference method", conf_method_name);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return linphone_conference_add_participant(lc->conf_ctx, call);
|
||||
}
|
||||
|
||||
int linphone_core_add_all_to_conference(LinphoneCore *lc) {
|
||||
MSList *calls=lc->calls;
|
||||
while (calls) {
|
||||
LinphoneCall *call=(LinphoneCall*)calls->data;
|
||||
calls=calls->next;
|
||||
linphone_core_add_to_conference(lc, call);
|
||||
}
|
||||
if(lc->conf_ctx && linphone_conference_check_class(lc->conf_ctx, LinphoneConferenceClassLocal)) {
|
||||
linphone_core_enter_conference(lc);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int linphone_core_remove_from_conference(LinphoneCore *lc, LinphoneCall *call) {
|
||||
if(lc->conf_ctx) return linphone_conference_remove_participant_with_call(lc->conf_ctx, call);
|
||||
else return -1;
|
||||
}
|
||||
|
||||
int linphone_core_terminate_conference(LinphoneCore *lc) {
|
||||
if(lc->conf_ctx == NULL) return -1;
|
||||
linphone_conference_terminate(lc->conf_ctx);
|
||||
linphone_conference_free(lc->conf_ctx);
|
||||
lc->conf_ctx = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int linphone_core_enter_conference(LinphoneCore *lc) {
|
||||
if(lc->conf_ctx) return linphone_conference_enter(lc->conf_ctx);
|
||||
else return -1;
|
||||
}
|
||||
|
||||
int linphone_core_leave_conference(LinphoneCore *lc) {
|
||||
if(lc->conf_ctx) return linphone_conference_leave(lc->conf_ctx);
|
||||
else return -1;
|
||||
}
|
||||
|
||||
bool_t linphone_core_is_in_conference(const LinphoneCore *lc) {
|
||||
if(lc->conf_ctx) return linphone_conference_is_in(lc->conf_ctx);
|
||||
else return FALSE;
|
||||
}
|
||||
|
||||
int linphone_core_get_conference_size(LinphoneCore *lc) {
|
||||
if(lc->conf_ctx) return linphone_conference_get_participant_count(lc->conf_ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
float linphone_core_get_conference_local_input_volume(LinphoneCore *lc) {
|
||||
if(lc->conf_ctx) return linphone_conference_get_input_volume(lc->conf_ctx);
|
||||
else return -1.0;
|
||||
}
|
||||
|
||||
int linphone_core_start_conference_recording(LinphoneCore *lc, const char *path) {
|
||||
if(lc->conf_ctx) return linphone_conference_start_recording(lc->conf_ctx, path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int linphone_core_stop_conference_recording(LinphoneCore *lc) {
|
||||
if(lc->conf_ctx) return linphone_conference_stop_recording(lc->conf_ctx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
LinphoneConference *linphone_core_get_conference(LinphoneCore *lc) {
|
||||
return lc->conf_ctx;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -139,6 +139,13 @@ enum _LinphoneStreamType {
|
|||
* @ingroup initializing
|
||||
**/
|
||||
typedef enum _LinphoneStreamType LinphoneStreamType;
|
||||
|
||||
/**
|
||||
* Internal object of LinphoneCore representing a conference
|
||||
* @ingroup call_control
|
||||
*/
|
||||
typedef struct _LinphoneConference LinphoneConference;
|
||||
|
||||
/**
|
||||
* Function returning a human readable value for LinphoneStreamType.
|
||||
* @ingroup initializing
|
||||
|
|
@ -441,6 +448,8 @@ LINPHONE_PUBLIC void linphone_address_set_secure(LinphoneAddress *addr, bool_t e
|
|||
LINPHONE_PUBLIC bool_t linphone_address_is_sip(const LinphoneAddress *uri);
|
||||
LINPHONE_PUBLIC LinphoneTransportType linphone_address_get_transport(const LinphoneAddress *uri);
|
||||
LINPHONE_PUBLIC void linphone_address_set_transport(LinphoneAddress *uri,LinphoneTransportType type);
|
||||
LINPHONE_PUBLIC const char *linphone_address_get_method_param(const LinphoneAddress *addr);
|
||||
LINPHONE_PUBLIC void linphone_address_set_method_param(LinphoneAddress *addr, const char *method);
|
||||
LINPHONE_PUBLIC char *linphone_address_as_string(const LinphoneAddress *u);
|
||||
LINPHONE_PUBLIC char *linphone_address_as_string_uri_only(const LinphoneAddress *u);
|
||||
LINPHONE_PUBLIC bool_t linphone_address_weak_equal(const LinphoneAddress *a1, const LinphoneAddress *a2);
|
||||
|
|
@ -888,10 +897,19 @@ LINPHONE_PUBLIC void linphone_call_set_native_video_window_id(LinphoneCall *call
|
|||
* @param call #LinphoneCall
|
||||
* @return TRUE if part of a conference.
|
||||
*
|
||||
* @deprecated Use linphone_call_params_get_local_conference_mode(linphone_call_get_current_params(call)) instead.
|
||||
* @deprecated Use linphone_call_get_conference() instead.
|
||||
* @ingroup call_control
|
||||
*/
|
||||
LINPHONE_PUBLIC LINPHONE_DEPRECATED bool_t linphone_call_is_in_conference(const LinphoneCall *call);
|
||||
|
||||
/**
|
||||
* Return the associated conference object
|
||||
* @param call #LinphoneCall
|
||||
* @return A pointer on #LinphoneConference or NULL if the call is not part
|
||||
* of any conference.
|
||||
* @ingroup call_control
|
||||
*/
|
||||
LINPHONE_PUBLIC LinphoneConference *linphone_call_get_conference(const LinphoneCall *call);
|
||||
/**
|
||||
* Enables or disable echo cancellation for this call
|
||||
* @param call
|
||||
|
|
@ -3806,7 +3824,27 @@ LINPHONE_PUBLIC const char *linphone_core_get_user_certificates_path(LinphoneCor
|
|||
*/
|
||||
LINPHONE_PUBLIC LinphoneCall* linphone_core_find_call_from_uri(const LinphoneCore *lc, const char *uri);
|
||||
|
||||
/**
|
||||
* @addtogroup call_control
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Add a participant to the conference. If no conference is going on
|
||||
* a new internal conference context is created and the participant is
|
||||
* added to it.
|
||||
* @param lc #LinphoneCore
|
||||
* @param call The current call with the participant to add
|
||||
* @return 0 if succeeded. Negative number if failed
|
||||
*/
|
||||
LINPHONE_PUBLIC int linphone_core_add_to_conference(LinphoneCore *lc, LinphoneCall *call);
|
||||
/**
|
||||
* Add all current calls into the conference. If no conference is running
|
||||
* a new internal conference context is created and all current calls
|
||||
* are added to it.
|
||||
* @param lc #LinphoneCore
|
||||
* @return 0 if succeeded. Negative number if failed
|
||||
*/
|
||||
LINPHONE_PUBLIC int linphone_core_add_all_to_conference(LinphoneCore *lc);
|
||||
/**
|
||||
* Remove a call from the conference.
|
||||
|
|
@ -3826,18 +3864,84 @@ LINPHONE_PUBLIC int linphone_core_add_all_to_conference(LinphoneCore *lc);
|
|||
LINPHONE_PUBLIC int linphone_core_remove_from_conference(LinphoneCore *lc, LinphoneCall *call);
|
||||
/**
|
||||
* Indicates whether the local participant is part of a conference.
|
||||
* @warning That function automatically fails in the case of conferences using a
|
||||
* conferencet server (focus). If you use such a conference, you should use
|
||||
* linphone_conference_remove_participant() instead.
|
||||
* @param lc the linphone core
|
||||
* @return TRUE if the local participant is in a conference, FALSE otherwise.
|
||||
**/
|
||||
*/
|
||||
LINPHONE_PUBLIC bool_t linphone_core_is_in_conference(const LinphoneCore *lc);
|
||||
/**
|
||||
* Join the local participant to the running conference
|
||||
* @param lc #LinphoneCore
|
||||
* @return 0 if succeeded. Negative number if failed
|
||||
*/
|
||||
LINPHONE_PUBLIC int linphone_core_enter_conference(LinphoneCore *lc);
|
||||
/**
|
||||
* Make the local participant leave the running conference
|
||||
* @param lc #LinphoneCore
|
||||
* @return 0 if succeeded. Negative number if failed
|
||||
*/
|
||||
LINPHONE_PUBLIC int linphone_core_leave_conference(LinphoneCore *lc);
|
||||
/**
|
||||
* Get the set input volume of the local participant
|
||||
* @param lc #LinphoneCore
|
||||
* @return A value inside [0.0 ; 1.0]
|
||||
*/
|
||||
LINPHONE_PUBLIC float linphone_core_get_conference_local_input_volume(LinphoneCore *lc);
|
||||
|
||||
/**
|
||||
* Terminate the running conference. If it is a local conference, all calls
|
||||
* inside it will become back separate calls and will be put in #LinphoneCallPaused state.
|
||||
* If it is a conference involving a focus server, all calls inside the conference
|
||||
* will be terminated.
|
||||
* @param lc #LinphoneCore
|
||||
* @return 0 if succeeded. Negative number if failed
|
||||
*/
|
||||
LINPHONE_PUBLIC int linphone_core_terminate_conference(LinphoneCore *lc);
|
||||
/**
|
||||
* Get the number of remote participant in the running conference
|
||||
* @param lc #LinphoneCore
|
||||
* @return The number of remote participant
|
||||
*/
|
||||
LINPHONE_PUBLIC int linphone_core_get_conference_size(LinphoneCore *lc);
|
||||
/**
|
||||
* Start recording the running conference
|
||||
* @param lc #LinphoneCore
|
||||
* @param path Path to the file where the recording will be written
|
||||
* @return 0 if succeeded. Negative number if failed
|
||||
*/
|
||||
LINPHONE_PUBLIC int linphone_core_start_conference_recording(LinphoneCore *lc, const char *path);
|
||||
/**
|
||||
* Stop recording the running conference
|
||||
* @param #LinphoneCore
|
||||
* @return 0 if succeeded. Negative number if failed
|
||||
*/
|
||||
LINPHONE_PUBLIC int linphone_core_stop_conference_recording(LinphoneCore *lc);
|
||||
/**
|
||||
* Get a pointer on the internal conference object.
|
||||
* @param lc #LinphoneCore
|
||||
* @return A pointer on #LinphoneConference or NULL if no conference are going on
|
||||
*/
|
||||
LINPHONE_PUBLIC LinphoneConference *linphone_core_get_conference(LinphoneCore *lc);
|
||||
/**
|
||||
* Get URIs of all participants of one conference
|
||||
* @param obj A #LinphoneConference
|
||||
* @return A #MSList containing URIs of all participant. That list must be
|
||||
* freed after utilisation and each URI must be unref with linphone_address_unref()
|
||||
*/
|
||||
LINPHONE_PUBLIC MSList *linphone_conference_get_participants(const LinphoneConference *obj);
|
||||
/**
|
||||
* Remove a participant from a conference
|
||||
* @param obj A #LinphoneConference
|
||||
* @param uri SIP URI of the participant to remove
|
||||
* @return 0 if succeeded, -1 if failed
|
||||
*/
|
||||
LINPHONE_PUBLIC int linphone_conference_remove_participant(LinphoneConference *obj, const LinphoneAddress *uri);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get the maximum number of simultaneous calls Linphone core can manage at a time. All new call above this limit are declined with a busy answer
|
||||
* @ingroup initializing
|
||||
|
|
|
|||
|
|
@ -1311,7 +1311,7 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_removeListener(JNIEnv* e
|
|||
VTableReference *ref=(VTableReference*)(iterator->data);
|
||||
LinphoneCoreVTable *vTable = ref->valid ? ref->vtable : NULL;
|
||||
iterator = iterator->next; //Because linphone_core_remove_listener may change the list
|
||||
if (vTable) {
|
||||
if (vTable && !ref->internal) {
|
||||
LinphoneCoreData *data = (LinphoneCoreData*) linphone_core_v_table_get_user_data(vTable);
|
||||
if (data && env->IsSameObject(data->listener, jlistener)) {
|
||||
linphone_core_remove_listener(core, vTable);
|
||||
|
|
@ -4315,6 +4315,14 @@ extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_getConferenceSize(JNIEnv
|
|||
return (jint)linphone_core_get_conference_size((LinphoneCore *) pCore);
|
||||
}
|
||||
|
||||
extern "C" jobject Jave_org_linphone_core_LinphoneCoreImpl_getConference(JNIEnv *env, jobject thiz, jlong pCore) {
|
||||
jclass conference_class = env->FindClass("org/linphone/core/LinphoneConference");
|
||||
jmethodID conference_constructor = env->GetMethodID(conference_class, "<init>", "(J)");
|
||||
LinphoneConference *conf = linphone_core_get_conference((LinphoneCore *)pCore);
|
||||
if(conf) return env->NewObject(conference_class, conference_constructor, conf);
|
||||
else return NULL;
|
||||
}
|
||||
|
||||
extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_startConferenceRecording(JNIEnv *env,jobject thiz,jlong pCore, jstring jpath){
|
||||
int err=-1;
|
||||
if (jpath){
|
||||
|
|
@ -4449,6 +4457,14 @@ extern "C" void Java_org_linphone_core_LinphoneCallImpl_setAuthenticationTokenVe
|
|||
linphone_call_set_authentication_token_verified(call, verified);
|
||||
}
|
||||
|
||||
extern "C" jobject Java_org_linphnoe_core_LinphoneCallImpl_getConference(JNIEnv *env, jobject thiz, jlong ptr) {
|
||||
jclass conference_class = env->FindClass("org/linphone/core/LinphoneConference");
|
||||
jmethodID conference_constructor = env->GetMethodID(conference_class, "<init>", "(J)");
|
||||
LinphoneConference *conf = linphone_call_get_conference((LinphoneCall *)ptr);
|
||||
if(conf) return env->NewObject(conference_class, conference_constructor, conf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
extern "C" jfloat Java_org_linphone_core_LinphoneCallImpl_getPlayVolume(JNIEnv* env, jobject thiz, jlong ptr) {
|
||||
LinphoneCall *call = (LinphoneCall *) ptr;
|
||||
return (jfloat)linphone_call_get_play_volume(call);
|
||||
|
|
@ -6730,3 +6746,26 @@ JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneCoreImpl_getNortpTimeout(J
|
|||
|
||||
|
||||
|
||||
JNIEXPORT jobject JNICALL Java_org_linphone_core_LinphoneConferenceImpl_getParticipants(JNIEnv *env, jobject thiz, jlong pconference) {
|
||||
MSList *participants, *it;
|
||||
jclass addr_class = env->FindClass("org/linphone/core/LinphoneAddressImpl");
|
||||
jclass addr_list_class = env->FindClass("[Lorg/linphone/core/LinphoneAddressImpl;");
|
||||
jmethodID addr_constructor = env->GetMethodID(addr_class, "<init>", "(J)");
|
||||
jmethodID addr_list_constructor = env->GetMethodID(addr_list_class, "<init>", "(V)");
|
||||
jmethodID addr_list_append = env->GetMethodID(addr_list_class, "add", "(Lorg/linphone/core/LinphoneAddressImpl;)Z");
|
||||
jobject jaddr_list = env->NewObject(addr_list_class, addr_list_constructor);
|
||||
|
||||
participants = linphone_conference_get_participants((LinphoneConference *)pconference);
|
||||
for(it = participants; it; it = ms_list_next(it)) {
|
||||
LinphoneAddress *addr = (LinphoneAddress *)it->data;
|
||||
jobject jaddr = env->NewObject(addr_class, addr_constructor, addr);
|
||||
env->CallBooleanMethod(jaddr_list, addr_list_append, jaddr);
|
||||
}
|
||||
return jaddr_list;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneConferenteImpl_removeParticipant(JNIEnv *env, jobject thiz, jlong pconference, jobject uri) {
|
||||
jfieldID native_ptr_attr = env->GetFieldID(env->GetObjectClass(uri), "nativePtr", "J");
|
||||
LinphoneAddress *addr = (LinphoneAddress *)env->GetLongField(uri, native_ptr_attr);
|
||||
return linphone_conference_remove_participant((LinphoneConference *)pconference, addr);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ extern "C" {
|
|||
#include "friendlist.h"
|
||||
#include "linphone_tunnel.h"
|
||||
#include "linphonecore_utils.h"
|
||||
#include "conference.h"
|
||||
#include "sal/sal.h"
|
||||
#include "sipsetup.h"
|
||||
#include "quality_reporting.h"
|
||||
|
|
@ -345,6 +346,8 @@ struct _LinphoneCall{
|
|||
|
||||
bool_t paused_by_app;
|
||||
bool_t broken; /*set to TRUE when the call is in broken state due to network disconnection or transport */
|
||||
|
||||
LinphoneConference *conf_ref; /**> Point on the associated conference if this call is part of a conference. NULL instead. */
|
||||
};
|
||||
|
||||
BELLE_SIP_DECLARE_VPTR(LinphoneCall);
|
||||
|
|
@ -820,16 +823,6 @@ typedef struct autoreplier_config
|
|||
const char *message; /* the path of the file to be played */
|
||||
}autoreplier_config_t;
|
||||
|
||||
struct _LinphoneConference{
|
||||
MSAudioConference *conf;
|
||||
AudioStream *local_participant;
|
||||
MSAudioEndpoint *local_endpoint;
|
||||
MSAudioEndpoint *record_endpoint;
|
||||
RtpProfile *local_dummy_profile;
|
||||
bool_t local_muted;
|
||||
bool_t terminated;
|
||||
};
|
||||
|
||||
|
||||
typedef struct _LinphoneToneDescription{
|
||||
LinphoneReason reason;
|
||||
|
|
@ -844,7 +837,6 @@ void linphone_core_play_call_error_tone(LinphoneCore *lc, LinphoneReason reason)
|
|||
void _linphone_core_set_tone(LinphoneCore *lc, LinphoneReason reason, LinphoneToneID id, const char *audiofile);
|
||||
const char *linphone_core_get_tone_file(const LinphoneCore *lc, LinphoneToneID id);
|
||||
int _linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params, LinphoneCallState next_state, const char *state_info);
|
||||
typedef struct _LinphoneConference LinphoneConference;
|
||||
|
||||
typedef struct _LinphoneTaskList{
|
||||
MSList *hooks;
|
||||
|
|
@ -906,7 +898,7 @@ struct _LinphoneCore
|
|||
time_t netup_time; /*time when network went reachable */
|
||||
struct _EcCalibrator *ecc;
|
||||
LinphoneTaskList hooks; /*tasks periodically executed in linphone_core_iterate()*/
|
||||
LinphoneConference conf_ctx;
|
||||
LinphoneConference *conf_ctx;
|
||||
char* zrtp_secrets_cache;
|
||||
char* user_certificates_path;
|
||||
LinphoneVideoPolicy video_policy;
|
||||
|
|
@ -1040,13 +1032,6 @@ int _linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call);
|
|||
|
||||
/*conferencing subsystem*/
|
||||
void _post_configure_audio_stream(AudioStream *st, LinphoneCore *lc, bool_t muted);
|
||||
/* When a conference participant pause the conference he may send a music.
|
||||
* We don't want to hear that music or to send it to the other participants.
|
||||
* Use muted=yes to handle this case.
|
||||
*/
|
||||
void linphone_call_add_to_conf(LinphoneCall *call, bool_t muted);
|
||||
void linphone_call_remove_from_conf(LinphoneCall *call);
|
||||
void linphone_core_conference_check_uninit(LinphoneCore *lc);
|
||||
bool_t linphone_core_sound_resources_available(LinphoneCore *lc);
|
||||
void linphone_core_notify_refer_state(LinphoneCore *lc, LinphoneCall *referer, LinphoneCall *newcall);
|
||||
unsigned int linphone_core_get_audio_features(LinphoneCore *lc);
|
||||
|
|
@ -1420,17 +1405,18 @@ struct _VTableReference{
|
|||
LinphoneCoreVTable *vtable;
|
||||
bool_t valid;
|
||||
bool_t autorelease;
|
||||
bool_t internal;
|
||||
};
|
||||
|
||||
typedef struct _VTableReference VTableReference;
|
||||
|
||||
void v_table_reference_destroy(VTableReference *ref);
|
||||
|
||||
void _linphone_core_add_listener(LinphoneCore *lc, LinphoneCoreVTable *vtable, bool_t autorelease);
|
||||
|
||||
LINPHONE_PUBLIC void linphone_core_v_table_set_internal(LinphoneCoreVTable *table, bool_t internal);
|
||||
bool_t linphone_core_v_table_is_internal(LinphoneCoreVTable *table);
|
||||
|
||||
void _linphone_core_add_listener(LinphoneCore *lc, LinphoneCoreVTable *vtable, bool_t autorelease, bool_t internal);
|
||||
|
||||
#ifdef VIDEO_ENABLED
|
||||
LINPHONE_PUBLIC MSWebCam *linphone_call_get_video_device(const LinphoneCall *call);
|
||||
MSWebCam *get_nowebcam_device(void);
|
||||
|
|
|
|||
|
|
@ -272,10 +272,11 @@ void linphone_core_notify_log_collection_upload_progress_indication(LinphoneCore
|
|||
cleanup_dead_vtable_refs(lc);
|
||||
}
|
||||
|
||||
static VTableReference * v_table_reference_new(LinphoneCoreVTable *vtable, bool_t autorelease){
|
||||
static VTableReference * v_table_reference_new(LinphoneCoreVTable *vtable, bool_t autorelease, bool_t internal){
|
||||
VTableReference *ref=ms_new0(VTableReference,1);
|
||||
ref->valid=1;
|
||||
ref->autorelease=autorelease;
|
||||
ref->internal = internal;
|
||||
ref->vtable=vtable;
|
||||
return ref;
|
||||
}
|
||||
|
|
@ -285,13 +286,13 @@ void v_table_reference_destroy(VTableReference *ref){
|
|||
ms_free(ref);
|
||||
}
|
||||
|
||||
void _linphone_core_add_listener(LinphoneCore *lc, LinphoneCoreVTable *vtable, bool_t autorelease) {
|
||||
void _linphone_core_add_listener(LinphoneCore *lc, LinphoneCoreVTable *vtable, bool_t autorelease, bool_t internal) {
|
||||
ms_message("Vtable [%p] registered on core [%p]",lc,vtable);
|
||||
lc->vtable_refs=ms_list_append(lc->vtable_refs,v_table_reference_new(vtable, autorelease));
|
||||
lc->vtable_refs=ms_list_append(lc->vtable_refs,v_table_reference_new(vtable, autorelease, internal));
|
||||
}
|
||||
|
||||
void linphone_core_add_listener(LinphoneCore *lc, LinphoneCoreVTable *vtable){
|
||||
_linphone_core_add_listener(lc, vtable, FALSE);
|
||||
_linphone_core_add_listener(lc, vtable, FALSE, FALSE);
|
||||
}
|
||||
|
||||
void linphone_core_remove_listener(LinphoneCore *lc, const LinphoneCoreVTable *vtable) {
|
||||
|
|
|
|||
|
|
@ -178,4 +178,6 @@ void linphone_gtk_unset_from_conference(LinphoneCall *call){
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
bool_t linphone_gtk_call_is_in_conference_view(LinphoneCall *call) {
|
||||
return (find_conferencee_from_call(call) != NULL);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -509,11 +509,10 @@ void linphone_gtk_remove_in_call_view(LinphoneCall *call){
|
|||
GtkWidget *w=(GtkWidget*)linphone_call_get_user_pointer (call);
|
||||
GtkWidget *main_window=linphone_gtk_get_main_window ();
|
||||
GtkWidget *nb=linphone_gtk_get_widget(main_window,"viewswitch");
|
||||
gboolean in_conf=linphone_call_params_get_local_conference_mode(linphone_call_get_current_params(call));
|
||||
int idx;
|
||||
g_return_if_fail(w!=NULL);
|
||||
idx=gtk_notebook_page_num(GTK_NOTEBOOK(nb),w);
|
||||
if (in_conf){
|
||||
if (linphone_gtk_call_is_in_conference_view(call)){
|
||||
linphone_gtk_unset_from_conference(call);
|
||||
}
|
||||
linphone_call_set_user_pointer (call,NULL);
|
||||
|
|
@ -776,7 +775,7 @@ void linphone_gtk_in_call_view_set_in_call(LinphoneCall *call){
|
|||
GtkWidget *callee=linphone_gtk_get_widget(callview,"in_call_uri");
|
||||
GtkWidget *duration=linphone_gtk_get_widget(callview,"in_call_duration");
|
||||
guint taskid=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(callview),"taskid"));
|
||||
gboolean in_conf=linphone_call_params_get_local_conference_mode(linphone_call_get_current_params(call));
|
||||
gboolean in_conf=(linphone_call_get_conference(call) != NULL);
|
||||
GtkWidget *call_stats=(GtkWidget*)g_object_get_data(G_OBJECT(callview),"call_stats");
|
||||
|
||||
linphone_gtk_in_call_show_video(call);
|
||||
|
|
@ -854,7 +853,7 @@ void linphone_gtk_in_call_view_terminate(LinphoneCall *call, const char *error_m
|
|||
video_window=(GtkWidget*)g_object_get_data(G_OBJECT(callview),"video_window");
|
||||
status=linphone_gtk_get_widget(callview,"in_call_status");
|
||||
taskid=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(callview),"taskid"));
|
||||
in_conf=linphone_call_params_get_local_conference_mode(linphone_call_get_current_params(call));
|
||||
in_conf=(linphone_call_get_conference(call) != NULL);
|
||||
if (video_window) gtk_widget_destroy(video_window);
|
||||
if (status==NULL) return;
|
||||
if (error_msg==NULL)
|
||||
|
|
|
|||
|
|
@ -198,6 +198,7 @@ LINPHONE_PUBLIC void linphone_gtk_enable_transfer_button(LinphoneCore *lc, gbool
|
|||
LINPHONE_PUBLIC void linphone_gtk_enable_conference_button(LinphoneCore *lc, gboolean value);
|
||||
LINPHONE_PUBLIC void linphone_gtk_set_in_conference(LinphoneCall *call);
|
||||
LINPHONE_PUBLIC void linphone_gtk_unset_from_conference(LinphoneCall *call);
|
||||
LINPHONE_PUBLIC bool_t linphone_gtk_call_is_in_conference_view(LinphoneCall *call);
|
||||
LINPHONE_PUBLIC void linphone_gtk_terminate_conference_participant(LinphoneCall *call);
|
||||
LINPHONE_PUBLIC void linphone_gtk_in_call_view_show_encryption(LinphoneCall *call);
|
||||
LINPHONE_PUBLIC void linphone_gtk_in_call_view_hide_encryption(LinphoneCall *call);
|
||||
|
|
|
|||
25
gtk/main.c
25
gtk/main.c
|
|
@ -814,7 +814,7 @@ static void linphone_gtk_update_call_buttons(LinphoneCall *call){
|
|||
conf_frame=(GtkWidget *)g_object_get_data(G_OBJECT(mw),"conf_frame");
|
||||
if(conf_frame==NULL){
|
||||
linphone_gtk_enable_transfer_button(lc,call_list_size>1);
|
||||
linphone_gtk_enable_conference_button(lc,call_list_size>1);
|
||||
linphone_gtk_enable_conference_button(lc,call_list_size>0);
|
||||
} else {
|
||||
linphone_gtk_enable_transfer_button(lc,FALSE);
|
||||
linphone_gtk_enable_conference_button(lc,FALSE);
|
||||
|
|
@ -1929,13 +1929,22 @@ void linphone_gtk_log_handler(OrtpLogLevel lev, const char *fmt, va_list args){
|
|||
|
||||
|
||||
void linphone_gtk_refer_received(LinphoneCore *lc, const char *refer_to){
|
||||
GtkEntry * uri_bar =GTK_ENTRY(linphone_gtk_get_widget(
|
||||
linphone_gtk_get_main_window(), "uribar"));
|
||||
char *text;
|
||||
linphone_gtk_notify(NULL,NULL,(text=ms_strdup_printf(_("We are transferred to %s"),refer_to)));
|
||||
g_free(text);
|
||||
gtk_entry_set_text(uri_bar, refer_to);
|
||||
linphone_gtk_start_call(linphone_gtk_get_main_window());
|
||||
char method[20] = "";
|
||||
LinphoneAddress *addr = linphone_address_new(refer_to);
|
||||
if(addr) {
|
||||
const char *tmp = linphone_address_get_method_param(addr);
|
||||
strncpy(method, tmp, sizeof(20));
|
||||
linphone_address_destroy(addr);
|
||||
}
|
||||
if(strlen(method) == 0 || strcmp(method, "INVITE") == 0) {
|
||||
GtkEntry * uri_bar =GTK_ENTRY(linphone_gtk_get_widget(
|
||||
linphone_gtk_get_main_window(), "uribar"));
|
||||
char *text;
|
||||
linphone_gtk_notify(NULL,NULL,(text=ms_strdup_printf(_("We are transferred to %s"),refer_to)));
|
||||
g_free(text);
|
||||
gtk_entry_set_text(uri_bar, refer_to);
|
||||
linphone_gtk_start_call(linphone_gtk_get_main_window());
|
||||
}
|
||||
}
|
||||
|
||||
static void linphone_gtk_check_soundcards(void){
|
||||
|
|
|
|||
|
|
@ -106,6 +106,7 @@ void sal_address_set_secure(SalAddress *addr, bool_t enabled);
|
|||
|
||||
SalTransport sal_address_get_transport(const SalAddress* addr);
|
||||
const char* sal_address_get_transport_name(const SalAddress* addr);
|
||||
const char *sal_address_get_method_param(const SalAddress *addr);
|
||||
|
||||
void sal_address_set_display_name(SalAddress *addr, const char *display_name);
|
||||
void sal_address_set_username(SalAddress *addr, const char *username);
|
||||
|
|
@ -118,6 +119,7 @@ void sal_address_destroy(SalAddress *u);
|
|||
void sal_address_set_param(SalAddress *u,const char* name,const char* value);
|
||||
void sal_address_set_transport(SalAddress* addr,SalTransport transport);
|
||||
void sal_address_set_transport_name(SalAddress* addr,const char* transport);
|
||||
void sal_address_set_method_param(SalAddress *addr, const char *method);
|
||||
void sal_address_set_params(SalAddress *addr, const char *params);
|
||||
void sal_address_set_uri_params(SalAddress *addr, const char *params);
|
||||
bool_t sal_address_is_ipv6(const SalAddress *addr);
|
||||
|
|
|
|||
|
|
@ -273,8 +273,17 @@ public interface LinphoneCall {
|
|||
* @param verified true when displayed SAS is correct
|
||||
*/
|
||||
void setAuthenticationTokenVerified(boolean verified);
|
||||
|
||||
|
||||
/**
|
||||
* Checks wether the call is part of a conferece.
|
||||
* @return A boolean
|
||||
*/
|
||||
boolean isInConference();
|
||||
/**
|
||||
* Get the pointer on the C conference instance associated to that call.
|
||||
* @return A positive value if the call is part of a conference, 0 if not.
|
||||
*/
|
||||
long getConference();
|
||||
|
||||
/**
|
||||
* Indicates whether an operation is in progress at the media side.
|
||||
|
|
|
|||
39
java/common/org/linphone/core/LinphoneConference.java
Normal file
39
java/common/org/linphone/core/LinphoneConference.java
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
LinphoneConference.java
|
||||
Copyright (C) 2015 Belledonne Communications, Grenoble, France
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
package org.linphone.core;
|
||||
|
||||
import org.linphone.core.LinphoneAddress;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Interface to manipulate a running conference
|
||||
*/
|
||||
public interface LinphoneConference {
|
||||
/**
|
||||
* Get the URIs of all participants of the conference
|
||||
*/
|
||||
public List<LinphoneAddress> getParticipants();
|
||||
/**
|
||||
* Remove a participant from the conference
|
||||
* @param uri The URI of the participant to remove
|
||||
* @return 0 if succeed, -1 if not.
|
||||
*/
|
||||
public int removeParticipant(LinphoneAddress uri);
|
||||
}
|
||||
|
|
@ -1417,6 +1417,13 @@ public interface LinphoneCore {
|
|||
* @returns the number of participants to the conference
|
||||
**/
|
||||
int getConferenceSize();
|
||||
/**
|
||||
* Return the value of the C pointer on the conference instance.
|
||||
*
|
||||
* That function can be used to test whether a conference is running.
|
||||
* @return A positive value if a conference is running, 0 if not.
|
||||
**/
|
||||
LinphoneConference getConference();
|
||||
|
||||
/**
|
||||
* Request recording of the conference into a supplied file path.
|
||||
|
|
|
|||
|
|
@ -165,8 +165,11 @@ class LinphoneCallImpl implements LinphoneCall {
|
|||
}
|
||||
|
||||
public boolean isInConference() {
|
||||
LinphoneCallParamsImpl params = new LinphoneCallParamsImpl(getCurrentParamsCopy(nativePtr));
|
||||
return params.localConferenceMode();
|
||||
return getConference() != 0;
|
||||
}
|
||||
private native long getConference(long nativePtr);
|
||||
public long getConference() {
|
||||
return getConference(nativePtr);
|
||||
}
|
||||
|
||||
public boolean mediaInProgress() { return mediaInProgress(nativePtr);}
|
||||
|
|
|
|||
42
java/impl/org/linphone/core/LinphoneConferenceImpl.java
Normal file
42
java/impl/org/linphone/core/LinphoneConferenceImpl.java
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
LinphoneConferenceImpl.java
|
||||
Copyright (C) 2015 Belledonne Communications, Grenoble, France
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
package org.linphone.core;
|
||||
|
||||
import org.linphone.core.LinphoneConference;
|
||||
import java.util.List;
|
||||
|
||||
public class LinphoneConferenceImpl implements LinphoneConference {
|
||||
private final long nativePtr;
|
||||
|
||||
|
||||
private LinphoneConferenceImpl(long nativePtr) {
|
||||
this.nativePtr = nativePtr;
|
||||
}
|
||||
|
||||
private native List<LinphoneAddress> getParticipants(long nativePtr);
|
||||
public List<LinphoneAddress> getParticipants() {
|
||||
return getParticipants(nativePtr);
|
||||
}
|
||||
|
||||
private native int removeParticipant(long nativePtr, LinphoneAddress uri);
|
||||
public int removeParticipant(LinphoneAddress uri) {
|
||||
return removeParticipant(nativePtr, uri);
|
||||
}
|
||||
}
|
||||
|
|
@ -721,6 +721,10 @@ class LinphoneCoreImpl implements LinphoneCore {
|
|||
public synchronized int getConferenceSize() {
|
||||
return getConferenceSize(nativePtr);
|
||||
}
|
||||
private native LinphoneConference getConference(long nativePtr);
|
||||
public synchronized LinphoneConference getConference() {
|
||||
return getConference(nativePtr);
|
||||
}
|
||||
private native int getCallsNb(long nativePtr);
|
||||
public synchronized int getCallsNb() {
|
||||
return getCallsNb(nativePtr);
|
||||
|
|
|
|||
|
|
@ -723,7 +723,7 @@ static void call_with_ipv6(void) {
|
|||
|
||||
static void file_transfer_message_rcs_to_external_body_client(void) {
|
||||
if (transport_supported(LinphoneTransportTls)) {
|
||||
LinphoneCoreManager* marie = linphone_core_manager_init( "marie_rc");
|
||||
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
|
||||
LinphoneChatRoom* chat_room;
|
||||
LinphoneChatMessage* message;
|
||||
LinphoneChatMessageCbs *cbs;
|
||||
|
|
@ -732,13 +732,13 @@ static void file_transfer_message_rcs_to_external_body_client(void) {
|
|||
size_t file_size;
|
||||
char *send_filepath = bc_tester_res("images/nowebcamCIF.jpg");
|
||||
char *receive_filepath = bc_tester_file("receive_file.dump");
|
||||
LinphoneCoreManager* pauline = linphone_core_manager_init( "pauline_rc");
|
||||
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc");
|
||||
|
||||
linphone_proxy_config_set_custom_header(marie->lc->default_proxy, "Accept", "application/sdp");
|
||||
linphone_core_manager_start(marie, "marie_rc", TRUE);
|
||||
linphone_core_manager_start(marie, TRUE);
|
||||
|
||||
linphone_proxy_config_set_custom_header(pauline->lc->default_proxy, "Accept", "application/sdp, text/plain, application/vnd.gsma.rcs-ft-http+xml");
|
||||
linphone_core_manager_start(pauline, "pauline_rc", TRUE);
|
||||
linphone_core_manager_start(pauline, TRUE);
|
||||
|
||||
reset_counters(&marie->stat);
|
||||
reset_counters(&pauline->stat);
|
||||
|
|
@ -823,14 +823,14 @@ void send_file_transfer_message_using_external_body_url(LinphoneCoreManager *mar
|
|||
|
||||
static void file_transfer_message_external_body_to_external_body_client(void) {
|
||||
if (transport_supported(LinphoneTransportTls)) {
|
||||
LinphoneCoreManager* marie = linphone_core_manager_init( "marie_rc");
|
||||
LinphoneCoreManager* pauline = linphone_core_manager_init( "pauline_rc");
|
||||
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
|
||||
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc");
|
||||
|
||||
linphone_proxy_config_set_custom_header(marie->lc->default_proxy, "Accept", "application/sdp");
|
||||
linphone_core_manager_start(marie, "marie_rc", TRUE);
|
||||
linphone_core_manager_start(marie, TRUE);
|
||||
|
||||
linphone_proxy_config_set_custom_header(pauline->lc->default_proxy, "Accept", "application/sdp");
|
||||
linphone_core_manager_start(pauline, "pauline_rc", TRUE);
|
||||
linphone_core_manager_start(pauline, TRUE);
|
||||
|
||||
reset_counters(&marie->stat);
|
||||
reset_counters(&pauline->stat);
|
||||
|
|
@ -847,14 +847,14 @@ static void file_transfer_message_external_body_to_external_body_client(void) {
|
|||
|
||||
static void file_transfer_message_external_body_to_rcs_client(void) {
|
||||
if (transport_supported(LinphoneTransportTls)) {
|
||||
LinphoneCoreManager* marie = linphone_core_manager_init( "marie_rc");
|
||||
LinphoneCoreManager* pauline = linphone_core_manager_init( "pauline_rc");
|
||||
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
|
||||
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc");
|
||||
|
||||
linphone_proxy_config_set_custom_header(marie->lc->default_proxy, "Accept", "application/sdp");
|
||||
linphone_core_manager_start(marie, "marie_rc", TRUE);
|
||||
linphone_core_manager_start(marie, TRUE);
|
||||
|
||||
linphone_proxy_config_set_custom_header(pauline->lc->default_proxy, "Accept", "application/sdp, text/plain, application/vnd.gsma.rcs-ft-http+xml");
|
||||
linphone_core_manager_start(pauline, "pauline_rc", TRUE);
|
||||
linphone_core_manager_start(pauline, TRUE);
|
||||
|
||||
reset_counters(&marie->stat);
|
||||
reset_counters(&pauline->stat);
|
||||
|
|
|
|||
|
|
@ -256,6 +256,12 @@ typedef struct _LinphoneCoreManager {
|
|||
int number_of_cunit_error_at_creation;
|
||||
} LinphoneCoreManager;
|
||||
|
||||
typedef struct _LinphoneConferenceServer {
|
||||
LinphoneCoreManager base;
|
||||
LinphoneCall *first_call;
|
||||
LinphoneCoreVTable *vtable;
|
||||
} LinphoneConferenceServer;
|
||||
|
||||
typedef struct _LinphoneCallTestParams {
|
||||
LinphoneCallParams *base;
|
||||
bool_t sdp_removal;
|
||||
|
|
@ -265,11 +271,12 @@ typedef struct _LinphoneCallTestParams {
|
|||
|
||||
void liblinphone_tester_add_suites(void);
|
||||
|
||||
LinphoneCoreManager* linphone_core_manager_init(const char* rc_file);
|
||||
void linphone_core_manager_start(LinphoneCoreManager *mgr, const char* rc_file, int check_for_proxies);
|
||||
void linphone_core_manager_init(LinphoneCoreManager *mgr, const char* rc_file);
|
||||
void linphone_core_manager_start(LinphoneCoreManager *mgr, int check_for_proxies);
|
||||
LinphoneCoreManager* linphone_core_manager_new2(const char* rc_file, int check_for_proxies);
|
||||
LinphoneCoreManager* linphone_core_manager_new(const char* rc_file);
|
||||
void linphone_core_manager_stop(LinphoneCoreManager *mgr);
|
||||
void linphone_core_manager_uninit(LinphoneCoreManager *mgr);
|
||||
void linphone_core_manager_destroy(LinphoneCoreManager* mgr);
|
||||
|
||||
void reset_counters( stats* counters);
|
||||
|
|
@ -356,6 +363,9 @@ void liblinphone_tester_uninit(void);
|
|||
int liblinphone_tester_set_log_file(const char *filename);
|
||||
bool_t check_ice(LinphoneCoreManager* caller, LinphoneCoreManager* callee, LinphoneIceState state);
|
||||
|
||||
LinphoneConferenceServer* linphone_conference_server_new(const char *rc_file);
|
||||
void linphone_conference_server_destroy(LinphoneConferenceServer *conf_srv);
|
||||
|
||||
extern const char *liblinphone_tester_mire_id;
|
||||
|
||||
FILE *sip_start(const char *senario, const char* dest_username, LinphoneAddress* dest_addres);
|
||||
|
|
|
|||
|
|
@ -177,8 +177,7 @@ static void incoming_call_accepted_when_outgoing_call_in_outgoing_ringing_early_
|
|||
incoming_call_accepted_when_outgoing_call_in_state(LinphoneCallOutgoingEarlyMedia);
|
||||
}
|
||||
|
||||
static void simple_conference_base(LinphoneCoreManager* marie, LinphoneCoreManager* pauline, LinphoneCoreManager* laure) {
|
||||
|
||||
static void simple_conference_base(LinphoneCoreManager* marie, LinphoneCoreManager* pauline, LinphoneCoreManager* laure, LinphoneCoreManager *focus) {
|
||||
stats initial_marie_stat;
|
||||
stats initial_pauline_stat;
|
||||
stats initial_laure_stat;
|
||||
|
|
@ -187,9 +186,14 @@ static void simple_conference_base(LinphoneCoreManager* marie, LinphoneCoreManag
|
|||
LinphoneCall* pauline_called_by_marie;
|
||||
LinphoneCall* marie_call_laure;
|
||||
const MSList* calls;
|
||||
bool_t is_remote_conf;
|
||||
MSList* lcs=ms_list_append(NULL,marie->lc);
|
||||
lcs=ms_list_append(lcs,pauline->lc);
|
||||
lcs=ms_list_append(lcs,laure->lc);
|
||||
if(focus) lcs=ms_list_append(lcs,focus->lc);
|
||||
|
||||
is_remote_conf = (strcmp(lp_config_get_string(marie->lc->config, "misc", "conference_type", "local"), "remote") == 0);
|
||||
if(is_remote_conf) BC_ASSERT_PTR_NOT_NULL(focus);
|
||||
|
||||
BC_ASSERT_TRUE(call(marie,pauline));
|
||||
marie_call_pauline=linphone_core_get_current_call(marie->lc);
|
||||
|
|
@ -205,12 +209,23 @@ static void simple_conference_base(LinphoneCoreManager* marie, LinphoneCoreManag
|
|||
|
||||
BC_ASSERT_PTR_NOT_NULL_FATAL(marie_call_laure);
|
||||
linphone_core_add_to_conference(marie->lc,marie_call_laure);
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallUpdating,initial_marie_stat.number_of_LinphoneCallUpdating+1,5000));
|
||||
if(!is_remote_conf) {
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallUpdating,initial_marie_stat.number_of_LinphoneCallUpdating+1,5000));
|
||||
} else {
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallStreamsRunning,initial_marie_stat.number_of_LinphoneCallStreamsRunning+1,5000));
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneTransferCallConnected,initial_marie_stat.number_of_LinphoneTransferCallConnected+1,5000));
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,initial_marie_stat.number_of_LinphoneCallEnd+1,5000));
|
||||
}
|
||||
|
||||
linphone_core_add_to_conference(marie->lc,marie_call_pauline);
|
||||
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallResuming,initial_marie_stat.number_of_LinphoneCallResuming+1,2000));
|
||||
|
||||
if(!is_remote_conf) {
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallResuming,initial_marie_stat.number_of_LinphoneCallResuming+1,2000));
|
||||
} else {
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneTransferCallConnected,initial_marie_stat.number_of_LinphoneTransferCallConnected+2,5000));
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,initial_marie_stat.number_of_LinphoneCallEnd+2,5000));
|
||||
}
|
||||
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallStreamsRunning,initial_pauline_stat.number_of_LinphoneCallStreamsRunning+1,5000));
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallStreamsRunning,initial_laure_stat.number_of_LinphoneCallStreamsRunning+1,2000));
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallStreamsRunning,initial_marie_stat.number_of_LinphoneCallStreamsRunning+2,3000));
|
||||
|
|
@ -218,7 +233,11 @@ static void simple_conference_base(LinphoneCoreManager* marie, LinphoneCoreManag
|
|||
BC_ASSERT_TRUE(linphone_core_is_in_conference(marie->lc));
|
||||
BC_ASSERT_EQUAL(linphone_core_get_conference_size(marie->lc),3, int, "%d");
|
||||
|
||||
BC_ASSERT_PTR_NULL(linphone_core_get_current_call(marie->lc));
|
||||
if(!is_remote_conf) {
|
||||
BC_ASSERT_PTR_NULL(linphone_core_get_current_call(marie->lc));
|
||||
} else {
|
||||
BC_ASSERT_PTR_NOT_NULL(linphone_core_get_current_call(marie->lc));
|
||||
}
|
||||
BC_ASSERT_PTR_NOT_NULL(linphone_core_get_current_call(pauline->lc));
|
||||
BC_ASSERT_PTR_NOT_NULL(linphone_core_get_current_call(laure->lc));
|
||||
|
||||
|
|
@ -241,9 +260,9 @@ static void simple_conference_base(LinphoneCoreManager* marie, LinphoneCoreManag
|
|||
|
||||
linphone_core_terminate_conference(marie->lc);
|
||||
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,10000));
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,10000));
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallEnd,1,10000));
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,is_remote_conf?2:1,10000));
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,is_remote_conf?3:1,10000));
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallEnd,is_remote_conf?2:1,10000));
|
||||
|
||||
ms_list_free(lcs);
|
||||
}
|
||||
|
|
@ -252,7 +271,7 @@ static void simple_conference(void) {
|
|||
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
|
||||
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc");
|
||||
LinphoneCoreManager* laure = linphone_core_manager_new( "laure_rc");
|
||||
simple_conference_base(marie,pauline,laure);
|
||||
simple_conference_base(marie,pauline,laure, NULL);
|
||||
linphone_core_manager_destroy(marie);
|
||||
linphone_core_manager_destroy(pauline);
|
||||
linphone_core_manager_destroy(laure);
|
||||
|
|
@ -299,7 +318,7 @@ static void simple_encrypted_conference_with_ice(LinphoneMediaEncryption mode) {
|
|||
linphone_core_set_media_encryption(pauline->lc,mode);
|
||||
linphone_core_set_media_encryption(laure->lc,mode);
|
||||
|
||||
simple_conference_base(marie,pauline,laure);
|
||||
simple_conference_base(marie,pauline,laure,NULL);
|
||||
} else {
|
||||
ms_warning("No [%s] support available",linphone_media_encryption_to_string(mode));
|
||||
BC_PASS("Passed");
|
||||
|
|
@ -546,11 +565,7 @@ static void call_transfer_existing_call_outgoing_call(void) {
|
|||
ms_list_free(lcs);
|
||||
}
|
||||
|
||||
static void eject_from_3_participants_conference(void) {
|
||||
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
|
||||
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc");
|
||||
LinphoneCoreManager* laure = linphone_core_manager_new( "laure_rc");
|
||||
|
||||
static void eject_from_3_participants_conference(LinphoneCoreManager *marie, LinphoneCoreManager *pauline, LinphoneCoreManager *laure, LinphoneCoreManager *focus) {
|
||||
stats initial_marie_stat;
|
||||
stats initial_pauline_stat;
|
||||
stats initial_laure_stat;
|
||||
|
|
@ -558,10 +573,15 @@ static void eject_from_3_participants_conference(void) {
|
|||
LinphoneCall* marie_call_pauline;
|
||||
LinphoneCall* pauline_called_by_marie;
|
||||
LinphoneCall* marie_call_laure;
|
||||
bool_t is_remote_conf;
|
||||
MSList* lcs=ms_list_append(NULL,marie->lc);
|
||||
lcs=ms_list_append(lcs,pauline->lc);
|
||||
lcs=ms_list_append(lcs,laure->lc);
|
||||
if(focus) lcs=ms_list_append(lcs,focus->lc);
|
||||
|
||||
is_remote_conf = (strcmp(lp_config_get_string(marie->lc->config, "misc", "conference_type", "local"), "remote") == 0);
|
||||
if(is_remote_conf) BC_ASSERT_PTR_NOT_NULL(focus);
|
||||
|
||||
BC_ASSERT_TRUE(call(marie,pauline));
|
||||
marie_call_pauline=linphone_core_get_current_call(marie->lc);
|
||||
pauline_called_by_marie=linphone_core_get_current_call(pauline->lc);
|
||||
|
|
@ -577,11 +597,24 @@ static void eject_from_3_participants_conference(void) {
|
|||
BC_ASSERT_PTR_NOT_NULL_FATAL(marie_call_laure);
|
||||
|
||||
linphone_core_add_to_conference(marie->lc,marie_call_laure);
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallUpdating,initial_marie_stat.number_of_LinphoneCallUpdating+1,5000));
|
||||
|
||||
if(!is_remote_conf) BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallUpdating,initial_marie_stat.number_of_LinphoneCallUpdating+1,5000));
|
||||
else {
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneTransferCallConnected,initial_marie_stat.number_of_LinphoneTransferCallConnected+1,5000));
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,initial_marie_stat.number_of_LinphoneCallEnd+1,5000));
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallEnd,initial_laure_stat.number_of_LinphoneCallEnd+1,5000));
|
||||
}
|
||||
|
||||
BC_ASSERT_PTR_NOT_NULL(linphone_core_get_conference(marie->lc));
|
||||
|
||||
linphone_core_add_to_conference(marie->lc,marie_call_pauline);
|
||||
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallResuming,initial_marie_stat.number_of_LinphoneCallResuming+1,2000));
|
||||
if(!is_remote_conf) BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallResuming,initial_marie_stat.number_of_LinphoneCallResuming+1,2000));
|
||||
else {
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneTransferCallConnected,initial_marie_stat.number_of_LinphoneTransferCallConnected+2,5000));
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,initial_marie_stat.number_of_LinphoneCallEnd+2,5000));
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,initial_pauline_stat.number_of_LinphoneCallEnd+1,5000));
|
||||
}
|
||||
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallStreamsRunning,initial_pauline_stat.number_of_LinphoneCallStreamsRunning+1,5000));
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallStreamsRunning,initial_laure_stat.number_of_LinphoneCallStreamsRunning+1,2000));
|
||||
|
|
@ -590,25 +623,49 @@ static void eject_from_3_participants_conference(void) {
|
|||
BC_ASSERT_TRUE(linphone_core_is_in_conference(marie->lc));
|
||||
BC_ASSERT_EQUAL(linphone_core_get_conference_size(marie->lc),3, int, "%d");
|
||||
|
||||
BC_ASSERT_PTR_NULL(linphone_core_get_current_call(marie->lc));
|
||||
if(!is_remote_conf) BC_ASSERT_PTR_NULL(linphone_core_get_current_call(marie->lc));
|
||||
|
||||
linphone_core_remove_from_conference(marie->lc, marie_call_pauline);
|
||||
if(!is_remote_conf) linphone_core_remove_from_conference(marie->lc, marie_call_pauline);
|
||||
else {
|
||||
LinphoneConference *conference = linphone_core_get_conference(marie->lc);
|
||||
const LinphoneAddress *uri = linphone_call_get_remote_address(marie_call_pauline);
|
||||
linphone_conference_remove_participant(conference, uri);
|
||||
}
|
||||
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallPausedByRemote,1,10000));
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallStreamsRunning,3,10000));
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallStreamsRunning,5,10000));
|
||||
BC_ASSERT_PTR_NOT_NULL(linphone_core_get_current_call(marie->lc));
|
||||
BC_ASSERT_EQUAL(ms_list_size(linphone_core_get_calls(marie->lc)), 2, int, "%d");
|
||||
BC_ASSERT_PTR_NOT_NULL(linphone_core_get_current_call(pauline->lc));
|
||||
BC_ASSERT_PTR_NOT_NULL(linphone_core_get_current_call(laure->lc));
|
||||
end_call(laure, marie);
|
||||
end_call(pauline, marie);
|
||||
if(!is_remote_conf) {
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallPausedByRemote,1,10000));
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallStreamsRunning,3,10000));
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallStreamsRunning,5,10000));
|
||||
BC_ASSERT_PTR_NOT_NULL(linphone_core_get_current_call(marie->lc));
|
||||
BC_ASSERT_EQUAL(ms_list_size(linphone_core_get_calls(marie->lc)), 2, int, "%d");
|
||||
BC_ASSERT_PTR_NOT_NULL(linphone_core_get_current_call(pauline->lc));
|
||||
BC_ASSERT_PTR_NOT_NULL(linphone_core_get_current_call(laure->lc));
|
||||
} else {
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,initial_pauline_stat.number_of_LinphoneCallEnd+2,5000));
|
||||
}
|
||||
|
||||
if(!is_remote_conf) {
|
||||
end_call(laure, marie);
|
||||
end_call(pauline, marie);
|
||||
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,10000));
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,10000));
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallEnd,1,10000));
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,10000));
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,10000));
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallEnd,1,10000));
|
||||
} else {
|
||||
linphone_core_terminate_conference(marie->lc);
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallEnd,initial_laure_stat.number_of_LinphoneCallEnd+2,3000));
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,initial_marie_stat.number_of_LinphoneCallEnd+3,3000));
|
||||
}
|
||||
|
||||
ms_list_free(lcs);
|
||||
}
|
||||
|
||||
static void eject_from_3_participants_local_conference(void) {
|
||||
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
|
||||
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc");
|
||||
LinphoneCoreManager* laure = linphone_core_manager_new( "laure_rc");
|
||||
|
||||
eject_from_3_participants_conference(marie, pauline, laure, NULL);
|
||||
|
||||
linphone_core_manager_destroy(marie);
|
||||
linphone_core_manager_destroy(pauline);
|
||||
|
|
@ -695,22 +752,87 @@ static void eject_from_4_participants_conference(void) {
|
|||
linphone_core_manager_destroy(laure);
|
||||
linphone_core_manager_destroy(michelle);
|
||||
}
|
||||
|
||||
|
||||
void simple_remote_conference(void) {
|
||||
LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc");
|
||||
LinphoneCoreManager *pauline = linphone_core_manager_new("pauline_tcp_rc");
|
||||
LinphoneCoreManager *laure = linphone_core_manager_new("laure_rc");
|
||||
LinphoneConferenceServer *focus = linphone_conference_server_new("conference_focus_rc");
|
||||
LpConfig *marie_config = linphone_core_get_config(marie->lc);
|
||||
LinphoneProxyConfig *focus_proxy_config = linphone_core_get_default_proxy_config(((LinphoneCoreManager *)focus)->lc);
|
||||
LinphoneProxyConfig *laure_proxy_config = linphone_core_get_default_proxy_config(((LinphoneCoreManager *)laure)->lc);
|
||||
const char *laure_proxy_uri = linphone_proxy_config_get_server_addr(laure_proxy_config);
|
||||
const char *focus_uri = linphone_proxy_config_get_identity(focus_proxy_config);
|
||||
int laure_n_register = laure->stat.number_of_LinphoneRegistrationOk;
|
||||
MSList *lcs = NULL;
|
||||
|
||||
lp_config_set_string(marie_config, "misc", "conference_type", "remote");
|
||||
lp_config_set_string(marie_config, "misc", "conference_focus_addr", focus_uri);
|
||||
|
||||
linphone_proxy_config_edit(laure_proxy_config);
|
||||
linphone_proxy_config_set_route(laure_proxy_config, laure_proxy_uri);
|
||||
linphone_proxy_config_done(laure_proxy_config);
|
||||
lcs = ms_list_append(lcs, laure->lc);
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneRegistrationOk, laure_n_register+1, 5000));
|
||||
ms_list_free(lcs);
|
||||
|
||||
simple_conference_base(marie, pauline, laure, (LinphoneCoreManager *)focus);
|
||||
|
||||
linphone_core_manager_destroy(marie);
|
||||
linphone_core_manager_destroy(pauline);
|
||||
linphone_core_manager_destroy(laure);
|
||||
linphone_conference_server_destroy(focus);
|
||||
}
|
||||
|
||||
void eject_from_3_participants_remote_conference(void) {
|
||||
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
|
||||
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc");
|
||||
LinphoneCoreManager* laure = linphone_core_manager_new( "laure_rc");
|
||||
LinphoneConferenceServer *focus = linphone_conference_server_new("conference_focus_rc");
|
||||
LpConfig *marie_config = linphone_core_get_config(marie->lc);
|
||||
LinphoneProxyConfig *focus_proxy_config = linphone_core_get_default_proxy_config(((LinphoneCoreManager *)focus)->lc);
|
||||
LinphoneProxyConfig *laure_proxy_config = linphone_core_get_default_proxy_config(((LinphoneCoreManager *)laure)->lc);
|
||||
const char *laure_proxy_uri = linphone_proxy_config_get_server_addr(laure_proxy_config);
|
||||
const char *focus_uri = linphone_proxy_config_get_identity(focus_proxy_config);
|
||||
int laure_n_register = laure->stat.number_of_LinphoneRegistrationOk;
|
||||
MSList *lcs = NULL;
|
||||
|
||||
lp_config_set_string(marie_config, "misc", "conference_type", "remote");
|
||||
lp_config_set_string(marie_config, "misc", "conference_focus_addr", focus_uri);
|
||||
|
||||
linphone_proxy_config_edit(laure_proxy_config);
|
||||
linphone_proxy_config_set_route(laure_proxy_config, laure_proxy_uri);
|
||||
linphone_proxy_config_done(laure_proxy_config);
|
||||
lcs = ms_list_append(lcs, laure->lc);
|
||||
BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneRegistrationOk, laure_n_register+1, 5000));
|
||||
ms_list_free(lcs);
|
||||
|
||||
eject_from_3_participants_conference(marie, pauline, laure, (LinphoneCoreManager *)focus);
|
||||
|
||||
linphone_core_manager_destroy(marie);
|
||||
linphone_core_manager_destroy(pauline);
|
||||
linphone_core_manager_destroy(laure);
|
||||
linphone_conference_server_destroy(focus);
|
||||
}
|
||||
|
||||
test_t multi_call_tests[] = {
|
||||
{ "Call waiting indication", call_waiting_indication },
|
||||
{ "Call waiting indication with privacy", call_waiting_indication_with_privacy },
|
||||
{ "Incoming call accepted when outgoing call in progress",incoming_call_accepted_when_outgoing_call_in_progress},
|
||||
{ "Incoming call accepted when outgoing call in outgoing ringing",incoming_call_accepted_when_outgoing_call_in_outgoing_ringing},
|
||||
{ "Incoming call accepted when outgoing call in outgoing ringing early media",incoming_call_accepted_when_outgoing_call_in_outgoing_ringing_early_media},
|
||||
{ "Incoming call accepted when outgoing call in progress", incoming_call_accepted_when_outgoing_call_in_progress},
|
||||
{ "Incoming call accepted when outgoing call in outgoing ringing", incoming_call_accepted_when_outgoing_call_in_outgoing_ringing},
|
||||
{ "Incoming call accepted when outgoing call in outgoing ringing early media", incoming_call_accepted_when_outgoing_call_in_outgoing_ringing_early_media},
|
||||
{ "Simple conference", simple_conference },
|
||||
{ "Simple conference with ICE",simple_conference_with_ice},
|
||||
{ "Simple conference with ICE", simple_conference_with_ice},
|
||||
{ "Simple ZRTP conference with ICE",simple_zrtp_conference_with_ice},
|
||||
{ "Eject from 3 participants conference", eject_from_3_participants_local_conference },
|
||||
{ "Eject from 4 participants conference", eject_from_4_participants_conference },
|
||||
{ "Simple call transfer", simple_call_transfer },
|
||||
{ "Unattended call transfer", unattended_call_transfer },
|
||||
{ "Unattended call transfer with error", unattended_call_transfer_with_error },
|
||||
{ "Call transfer existing call outgoing call", call_transfer_existing_call_outgoing_call },
|
||||
{ "Eject from 3 participants conference", eject_from_3_participants_conference },
|
||||
{ "Eject from 4 participants conference", eject_from_4_participants_conference },
|
||||
{ "Simple remote conference", simple_remote_conference },
|
||||
{ "Eject from 3 participants in remote conference", eject_from_3_participants_remote_conference }
|
||||
};
|
||||
|
||||
test_suite_t multi_call_test_suite = {"Multi call", NULL, NULL, liblinphone_tester_before_each, liblinphone_tester_after_each,
|
||||
|
|
|
|||
26
tester/rcfiles/conference_focus_rc
Normal file
26
tester/rcfiles/conference_focus_rc
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
[sip]
|
||||
default_proxy=0
|
||||
sip_port=-1
|
||||
sip_tcp_port=-1
|
||||
sip_dtls_port=-1
|
||||
sip_tls_port=-1
|
||||
|
||||
[rtp]
|
||||
audio_rtp_port=18070-28000
|
||||
text_rtp_port=39000-49000
|
||||
video_rtp_port=28070-38000
|
||||
|
||||
[proxy_0]
|
||||
reg_proxy=sip.example.org;transport=tcp
|
||||
reg_route=sip.example.org;transport=tcp;lr
|
||||
reg_identity="Focus" <sip:focus@sip.example.org>
|
||||
reg_expires=3600
|
||||
reg_sendregister=1
|
||||
publish=0
|
||||
|
||||
[auth_info_0]
|
||||
username=focus
|
||||
userid=focus
|
||||
passwd=secret
|
||||
realm=sip.example.org
|
||||
|
||||
|
|
@ -260,8 +260,7 @@ static void display_status(LinphoneCore *lc, const char *status){
|
|||
ms_message("display_status(): %s",status);
|
||||
}
|
||||
|
||||
LinphoneCoreManager* linphone_core_manager_init(const char* rc_file) {
|
||||
LinphoneCoreManager* mgr= ms_new0(LinphoneCoreManager,1);
|
||||
void linphone_core_manager_init(LinphoneCoreManager *mgr, const char* rc_file) {
|
||||
char *rc_path = NULL;
|
||||
char *hellopath = bc_tester_res("sounds/hello8000.wav");
|
||||
mgr->number_of_cunit_error_at_creation = CU_get_number_of_failures();
|
||||
|
|
@ -330,16 +329,14 @@ LinphoneCoreManager* linphone_core_manager_init(const char* rc_file) {
|
|||
linphone_core_set_user_certificates_path(mgr->lc,bc_tester_get_writable_dir_prefix());
|
||||
|
||||
if (rc_path) ms_free(rc_path);
|
||||
|
||||
return mgr;
|
||||
}
|
||||
|
||||
void linphone_core_manager_start(LinphoneCoreManager *mgr, const char* rc_file, int check_for_proxies) {
|
||||
void linphone_core_manager_start(LinphoneCoreManager *mgr, int check_for_proxies) {
|
||||
LinphoneProxyConfig* proxy;
|
||||
int proxy_count;
|
||||
|
||||
/*BC_ASSERT_EQUAL(ms_list_size(linphone_core_get_proxy_config_list(lc)),proxy_count, int, "%d");*/
|
||||
if (check_for_proxies && rc_file) /**/
|
||||
if (check_for_proxies) /**/
|
||||
proxy_count=ms_list_size(linphone_core_get_proxy_config_list(mgr->lc));
|
||||
else
|
||||
proxy_count=0;
|
||||
|
|
@ -363,14 +360,16 @@ void linphone_core_manager_start(LinphoneCoreManager *mgr, const char* rc_file,
|
|||
}
|
||||
|
||||
LinphoneCoreManager* linphone_core_manager_new( const char* rc_file) {
|
||||
LinphoneCoreManager *manager = linphone_core_manager_init(rc_file);
|
||||
linphone_core_manager_start(manager, rc_file, TRUE);
|
||||
LinphoneCoreManager *manager = ms_new0(LinphoneCoreManager, 1);
|
||||
linphone_core_manager_init(manager, rc_file);
|
||||
linphone_core_manager_start(manager, TRUE);
|
||||
return manager;
|
||||
}
|
||||
|
||||
LinphoneCoreManager* linphone_core_manager_new2( const char* rc_file, int check_for_proxies) {
|
||||
LinphoneCoreManager *manager = linphone_core_manager_init(rc_file);
|
||||
linphone_core_manager_start(manager, rc_file, check_for_proxies);
|
||||
LinphoneCoreManager *manager = ms_new0(LinphoneCoreManager, 1);
|
||||
linphone_core_manager_init(manager, rc_file);
|
||||
linphone_core_manager_start(manager, check_for_proxies);
|
||||
return manager;
|
||||
}
|
||||
|
||||
|
|
@ -381,7 +380,7 @@ void linphone_core_manager_stop(LinphoneCoreManager *mgr){
|
|||
}
|
||||
}
|
||||
|
||||
void linphone_core_manager_destroy(LinphoneCoreManager* mgr) {
|
||||
void linphone_core_manager_uninit(LinphoneCoreManager *mgr) {
|
||||
if (mgr->stat.last_received_chat_message) {
|
||||
linphone_chat_message_unref(mgr->stat.last_received_chat_message);
|
||||
}
|
||||
|
|
@ -406,8 +405,12 @@ void linphone_core_manager_destroy(LinphoneCoreManager* mgr) {
|
|||
if (mgr->identity) {
|
||||
linphone_address_destroy(mgr->identity);
|
||||
}
|
||||
|
||||
manager_count--;
|
||||
}
|
||||
|
||||
void linphone_core_manager_destroy(LinphoneCoreManager* mgr) {
|
||||
linphone_core_manager_uninit(mgr);
|
||||
ms_free(mgr);
|
||||
}
|
||||
|
||||
|
|
@ -668,4 +671,69 @@ bool_t check_ice(LinphoneCoreManager* caller, LinphoneCoreManager* callee, Linph
|
|||
return video_enabled ? (realtime_text_enabled ? text_success && audio_success && video_success : audio_success && video_success) : realtime_text_enabled ? text_success && audio_success : audio_success;
|
||||
}
|
||||
|
||||
void linphone_conference_server_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *msg) {
|
||||
LinphoneCoreVTable *vtable = linphone_core_get_current_vtable(lc);
|
||||
LinphoneConferenceServer *conf_srv = (LinphoneConferenceServer *)vtable->user_data;
|
||||
|
||||
switch(cstate) {
|
||||
case LinphoneCallIncomingReceived:
|
||||
linphone_core_accept_call(lc, call);
|
||||
break;
|
||||
|
||||
case LinphoneCallStreamsRunning:
|
||||
if(linphone_call_get_conference(call) == NULL) {
|
||||
linphone_core_add_to_conference(lc, call);
|
||||
linphone_core_leave_conference(lc);
|
||||
if(conf_srv->first_call == NULL) conf_srv->first_call = linphone_call_ref(call);
|
||||
}
|
||||
break;
|
||||
|
||||
case LinphoneCallEnd:
|
||||
if(call == conf_srv->first_call) {
|
||||
linphone_core_terminate_conference(lc);
|
||||
linphone_call_unref(call);
|
||||
conf_srv->first_call = NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
void linphone_conference_server_refer_received(LinphoneCore *core, const char *refer_to) {
|
||||
char method[20];
|
||||
LinphoneAddress *refer_to_addr = linphone_address_new(refer_to);
|
||||
char *uri;
|
||||
LinphoneCall *call;
|
||||
|
||||
if(refer_to_addr == NULL) return;
|
||||
strncpy(method, linphone_address_get_method_param(refer_to_addr), sizeof(method));
|
||||
if(strcmp(method, "BYE") == 0) {
|
||||
linphone_address_clean(refer_to_addr);
|
||||
uri = linphone_address_as_string_uri_only(refer_to_addr);
|
||||
call = linphone_core_find_call_from_uri(core, uri);
|
||||
if(call) linphone_core_terminate_call(core, call);
|
||||
ms_free(uri);
|
||||
}
|
||||
linphone_address_destroy(refer_to_addr);
|
||||
}
|
||||
|
||||
LinphoneConferenceServer* linphone_conference_server_new(const char *rc_file) {
|
||||
LinphoneConferenceServer *conf_srv = (LinphoneConferenceServer *)ms_new0(LinphoneConferenceServer, 1);
|
||||
LinphoneCoreManager *lm = (LinphoneCoreManager *)conf_srv;
|
||||
|
||||
conf_srv->vtable = linphone_core_v_table_new();
|
||||
conf_srv->vtable->call_state_changed = linphone_conference_server_call_state_changed;
|
||||
conf_srv->vtable->refer_received = linphone_conference_server_refer_received;
|
||||
conf_srv->vtable->user_data = conf_srv;
|
||||
linphone_core_manager_init(lm, rc_file);
|
||||
linphone_core_add_listener(lm->lc, conf_srv->vtable);
|
||||
linphone_core_manager_start(lm, TRUE);
|
||||
return conf_srv;
|
||||
}
|
||||
|
||||
void linphone_conference_server_destroy(LinphoneConferenceServer *conf_srv) {
|
||||
linphone_core_manager_uninit((LinphoneCoreManager *)conf_srv);
|
||||
linphone_core_v_table_destroy(conf_srv->vtable);
|
||||
ms_free(conf_srv);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue