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,