From 6e655d74304f3215db6702c8b762ba0ceb03014b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grisez?= Date: Fri, 18 Dec 2015 18:08:20 +0100 Subject: [PATCH] Add the ability to remove a participant from a remote conference That new feature has not been tested yet neither with Telefonica's server nor in liblinphone tester. That one does not still work because the LinphoneCore instance simulating the conference server does not handle REFER with BYE requests. --- coreapi/bellesip_sal/sal_op_call_transfer.c | 2 +- coreapi/conference.cc | 339 +++++++++++++------- coreapi/conference.h | 13 +- coreapi/linphonecore.c | 10 +- coreapi/linphonecore.h | 25 +- tester/multi_call_tester.c | 117 +++++-- 6 files changed, 357 insertions(+), 149 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_call_transfer.c b/coreapi/bellesip_sal/sal_op_call_transfer.c index 84e529091..ffc4b945a 100644 --- a/coreapi/bellesip_sal/sal_op_call_transfer.c +++ b/coreapi/bellesip_sal/sal_op_call_transfer.c @@ -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); diff --git a/coreapi/conference.cc b/coreapi/conference.cc index 19140773b..d917d7e01 100644 --- a/coreapi/conference.cc +++ b/coreapi/conference.cc @@ -27,15 +27,34 @@ #include "conference.h" #include #include +#include +#include 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 addCall(LinphoneCall *call) = 0; - virtual int removeCall(LinphoneCall *call) = 0; + 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; @@ -47,7 +66,8 @@ public: bool microphoneIsMuted() const {return m_isMuted;} float getInputVolume() const; - virtual int getParticipantCount() const = 0; + virtual int getParticipantCount() const {return m_participants.size();} + const std::list &getParticipants() const {return m_participants;} virtual int startRecording(const char *path) = 0; virtual int stopRecording() = 0; @@ -57,63 +77,22 @@ public: virtual void onCallTerminating(LinphoneCall *call) {}; protected: + Participant *find_participant(const LinphoneAddress *uri); + LinphoneCore *m_core; AudioStream *m_localParticipantStream; bool m_isMuted; -}; + std::list m_participants; }; -using namespace Linphone; - -Conference::Conference(LinphoneCore *core) : - m_core(core), - m_localParticipantStream(NULL), - m_isMuted(false) { -} - -int Conference::addCall(LinphoneCall *call) { - call->conf_ref = (LinphoneConference *)this; - return 0; -} - -int Conference::removeCall(LinphoneCall *call) { - call->conf_ref = NULL; - 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; -} - - -namespace Linphone { class LocalConference: public Conference { public: LocalConference(LinphoneCore *core); virtual ~LocalConference(); - virtual int addCall(LinphoneCall *call); - virtual int removeCall(LinphoneCall *call); + virtual int addParticipant(LinphoneCall *call); + virtual int removeParticipant(LinphoneCall *call); + virtual int removeParticipant(const LinphoneAddress *uri); virtual int terminate(); virtual int enter(); @@ -142,8 +121,140 @@ private: 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::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), @@ -196,7 +307,7 @@ void LocalConference::addLocalEndpoint() { ms_audio_conference_add_member(m_conf,m_localEndpoint); } -int LocalConference::addCall(LinphoneCall *call) { +int LocalConference::addParticipant(LinphoneCall *call) { if (call->current_params->in_conference){ ms_error("Already in conference"); return -1; @@ -227,7 +338,7 @@ int LocalConference::addCall(LinphoneCall *call) { ms_error("Call is in state %s, it cannot be added to the conference.",linphone_call_state_to_string(call->state)); return -1; } - Conference::addCall(call); + Conference::addParticipant(call); return 0; } @@ -245,7 +356,7 @@ int LocalConference::removeFromConference(LinphoneCall *call, bool_t active){ } } call->params->in_conference=FALSE; - Conference::removeCall(call); + Conference::removeParticipant(call); str=linphone_call_get_remote_address_as_string(call); ms_message("%s will be removed from conference", str); @@ -296,7 +407,7 @@ int LocalConference::convertConferenceToCall(){ return err; } -int LocalConference::removeCall(LinphoneCall *call) { +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); @@ -316,6 +427,14 @@ int LocalConference::removeCall(LinphoneCall *call) { 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; @@ -427,47 +546,7 @@ void LocalConference::onCallTerminating(LinphoneCall *call) { } } -namespace Linphone { -class RemoteConference: public Conference { -public: - RemoteConference(LinphoneCore *core); - virtual ~RemoteConference(); - - virtual int addCall(LinphoneCall *call); - virtual int removeCall(LinphoneCall *call) {return 0;} - virtual int terminate(); - - virtual int enter(); - virtual int leave(); - virtual bool isIn() const; - virtual int getParticipantCount() const {return -1;} - - 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; -}; -}; RemoteConference::RemoteConference(LinphoneCore *core): Conference(core), @@ -492,12 +571,12 @@ RemoteConference::~RemoteConference() { linphone_core_v_table_destroy(m_vtable); } -int RemoteConference::addCall(LinphoneCall *call) { +int RemoteConference::addParticipant(LinphoneCall *call) { LinphoneAddress *addr; switch(m_state) { case NotConnectedToFocus: - Conference::addCall(call); + Conference::addParticipant(call); ms_message("Calling the conference focus (%s)", m_focusAddr); addr = linphone_address_new(m_focusAddr); if(addr) { @@ -506,16 +585,17 @@ int RemoteConference::addCall(LinphoneCall *call) { 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::addCall(call); + Conference::addParticipant(call); m_pendingCalls = ms_list_append(m_pendingCalls, linphone_call_ref(call)); return 0; case ConnectedToFocus: - Conference::addCall(call); + 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; @@ -526,11 +606,39 @@ int RemoteConference::addCall(LinphoneCall *call) { } } +int RemoteConference::removeParticipant(const LinphoneAddress *uri) { + SalOp *op; + const char *from; + LinphoneAddress *refer_to; + int res; + + switch(m_state) { + case ConnectedToFocus: + op = sal_op_new(m_core->sal); + + from = sal_op_get_from(m_focusCall->op); + sal_op_set_from(op, from); + sal_op_set_to(op, m_focusContact); + + refer_to = linphone_address_clone(uri); + linphone_address_set_header(refer_to, "method", "BYE"); + res = sal_call_refer(op, linphone_address_as_string(refer_to)); + linphone_address_unref(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::removeCall(m_focusCall); + Conference::removeParticipant(m_focusCall); linphone_core_terminate_call(m_core, m_focusCall); break; default: @@ -615,7 +723,7 @@ void RemoteConference::onFocusCallSateChanged(LinphoneCallState state) { case LinphoneCallError: case LinphoneCallEnd: - Conference::removeCall(m_focusCall); + Conference::removeParticipant(m_focusCall); m_state = NotConnectedToFocus; linphone_call_unref(m_focusCall); m_focusCall = NULL; @@ -645,7 +753,7 @@ void RemoteConference::onPendingCallStateChanged(LinphoneCall *call, LinphoneCal case LinphoneCallError: case LinphoneCallEnd: - Conference::removeCall(call); + Conference::removeParticipant(call); m_pendingCalls = ms_list_remove(m_pendingCalls, call); linphone_call_unref(call); break; @@ -683,7 +791,6 @@ void RemoteConference::transferStateChanged(LinphoneCore *lc, LinphoneCall *tran - LinphoneConference *linphone_local_conference_new(LinphoneCore *core) { return (LinphoneConference *) new LocalConference(core); } @@ -696,27 +803,31 @@ void linphone_conference_free(LinphoneConference *obj) { delete (Conference *)obj; } -int linphone_conference_add_call(LinphoneConference *obj, LinphoneCall *call) { - return ((Conference *)obj)->addCall(call); +int linphone_conference_add_participant(LinphoneConference *obj, LinphoneCall *call) { + return ((Conference *)obj)->addParticipant(call); } -int linphone_conference_remove_call(LinphoneConference *obj, LinphoneCall *call) { - return ((Conference *)obj)->removeCall(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_add_local_participant(LinphoneConference *obj) { +int linphone_conference_enter(LinphoneConference *obj) { return ((Conference *)obj)->enter(); } -int linphone_conference_remove_local_participant(LinphoneConference *obj) { +int linphone_conference_leave(LinphoneConference *obj) { return ((Conference *)obj)->leave(); } -bool_t linphone_conference_local_participant_is_in(const LinphoneConference *obj) { +bool_t linphone_conference_is_in(const LinphoneConference *obj) { return ((Conference *)obj)->isIn() ? TRUE : FALSE; } @@ -740,6 +851,16 @@ int linphone_conference_get_participant_count(const LinphoneConference *obj) { return ((Conference *)obj)->getParticipantCount(); } +MSList *linphone_conference_get_participants(const LinphoneConference *obj) { + const list participants = ((Conference *)obj)->getParticipants(); + MSList *participants_list = NULL; + for(list::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); } diff --git a/coreapi/conference.h b/coreapi/conference.h index aee2ffa8f..b2996ea89 100644 --- a/coreapi/conference.h +++ b/coreapi/conference.h @@ -39,19 +39,22 @@ LinphoneConference *linphone_local_conference_new(LinphoneCore *core); LinphoneConference *linphone_remote_conference_new(LinphoneCore *core); void linphone_conference_free(LinphoneConference *obj); -int linphone_conference_add_call(LinphoneConference *obj, LinphoneCall *call); -int linphone_conference_remove_call(LinphoneConference *obj, LinphoneCall *call); +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_add_local_participant(LinphoneConference *obj); -int linphone_conference_remove_local_participant(LinphoneConference *obj); -bool_t linphone_conference_local_participant_is_in(const 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); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index b544a005b..880271658 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -7410,7 +7410,7 @@ int linphone_core_add_to_conference(LinphoneCore *lc, LinphoneCall *call) { return -1; } } - return linphone_conference_add_call(lc->conf_ctx, call); + return linphone_conference_add_participant(lc->conf_ctx, call); } int linphone_core_add_all_to_conference(LinphoneCore *lc) { @@ -7427,7 +7427,7 @@ int linphone_core_add_all_to_conference(LinphoneCore *lc) { } int linphone_core_remove_from_conference(LinphoneCore *lc, LinphoneCall *call) { - if(lc->conf_ctx) return linphone_conference_remove_call(lc->conf_ctx, call); + if(lc->conf_ctx) return linphone_conference_remove_participant_with_call(lc->conf_ctx, call); else return -1; } @@ -7440,17 +7440,17 @@ int linphone_core_terminate_conference(LinphoneCore *lc) { } int linphone_core_enter_conference(LinphoneCore *lc) { - if(lc->conf_ctx) return linphone_conference_add_local_participant(lc->conf_ctx); + 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_remove_local_participant(lc->conf_ctx); + 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_local_participant_is_in(lc->conf_ctx); + if(lc->conf_ctx) return linphone_conference_is_in(lc->conf_ctx); else return FALSE; } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index a3d3425bd..97b89a089 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -3858,6 +3858,9 @@ 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. */ @@ -3909,11 +3912,25 @@ LINPHONE_PUBLIC int linphone_core_start_conference_recording(LinphoneCore *lc, c */ 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 -*/ + * 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); /** * @} diff --git a/tester/multi_call_tester.c b/tester/multi_call_tester.c index de6899892..8ded2285d 100644 --- a/tester/multi_call_tester.c +++ b/tester/multi_call_tester.c @@ -178,7 +178,6 @@ static void incoming_call_accepted_when_outgoing_call_in_outgoing_ringing_early_ } 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; @@ -232,7 +231,7 @@ static void simple_conference_base(LinphoneCoreManager* marie, LinphoneCoreManag BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallStreamsRunning,initial_marie_stat.number_of_LinphoneCallStreamsRunning+2,3000)); BC_ASSERT_TRUE(linphone_core_is_in_conference(marie->lc)); - BC_ASSERT_EQUAL(linphone_core_get_conference_size(marie->lc),is_remote_conf?-1:3, int, "%d"); + BC_ASSERT_EQUAL(linphone_core_get_conference_size(marie->lc),3, int, "%d"); if(!is_remote_conf) { BC_ASSERT_PTR_NULL(linphone_core_get_current_call(marie->lc)); @@ -566,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; @@ -578,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); @@ -597,11 +597,22 @@ 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_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_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)); @@ -610,25 +621,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+1,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+1,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); @@ -748,6 +783,37 @@ void simple_remote_conference(void) { 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 }, @@ -757,13 +823,14 @@ test_t multi_call_tests[] = { { "Simple conference", simple_conference }, { "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_conference }, + { "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 }, - { "Simple remote conference", simple_remote_conference } + { "Simple remote conference", simple_remote_conference }, + { "Eject from 3 participants 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,