From b4452da58d5ad1b078f5d306fa53d31defa964c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grisez?= Date: Mon, 1 Feb 2016 11:26:35 +0100 Subject: [PATCH] Release the reference on the focus call when thatone fails --- coreapi/conference.cc | 219 +++++++++++++++++++++++------------ coreapi/conference.h | 12 +- coreapi/conference_private.h | 37 ++++++ coreapi/linphonecore.c | 28 ++++- tester/liblinphone_tester.h | 3 +- tester/multi_call_tester.c | 61 ++++++++-- tester/tester.c | 21 +++- 7 files changed, 288 insertions(+), 93 deletions(-) diff --git a/coreapi/conference.cc b/coreapi/conference.cc index 50dd57c2d..a59608b43 100644 --- a/coreapi/conference.cc +++ b/coreapi/conference.cc @@ -32,31 +32,39 @@ 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: + 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 Params { public: Params(const LinphoneCore *core = NULL); void enableVideo(bool enable) {m_enableVideo = enable;} bool videoRequested() const {return m_enableVideo;} + void setStateChangedCallback(LinphoneConferenceStateChangedCb cb, void *user_data) { + m_state_changed_cb=cb; + m_user_data=user_data; + } private: bool m_enableVideo; + LinphoneConferenceStateChangedCb m_state_changed_cb; + void *m_user_data; + + friend class Conference; }; Conference(LinphoneCore *core, const Params *params = NULL); @@ -88,14 +96,19 @@ public: virtual void onCallStreamStopping(LinphoneCall *call) {}; virtual void onCallTerminating(LinphoneCall *call) {}; + LinphoneConferenceState getState() const {return m_state;} + static const char *stateToString(LinphoneConferenceState state); + protected: const Participant *findParticipant(const LinphoneAddress* uri) const; + void setState(LinphoneConferenceState state); LinphoneCore *m_core; AudioStream *m_localParticipantStream; bool m_isMuted; std::list m_participants; Params m_currentParams; + LinphoneConferenceState m_state; }; class LocalConference: public Conference { @@ -153,12 +166,9 @@ public: virtual int stopRecording() {return 0;} private: - enum State { - NotConnectedToFocus, - ConnectingToFocus, - ConnectedToFocus, - }; - static const char *stateToString(State state); + bool focusIsReady() const; + bool transferToFocus(LinphoneCall *call); + void reset(); void onFocusCallSateChanged(LinphoneCallState state); void onPendingCallStateChanged(LinphoneCall *call, LinphoneCallState state); @@ -170,10 +180,10 @@ private: const char *m_focusAddr; char *m_focusContact; LinphoneCall *m_focusCall; - State m_state; LinphoneCoreVTable *m_vtable; MSList *m_pendingCalls; MSList *m_transferingCalls; + bool m_isTerminating; }; }; @@ -183,22 +193,22 @@ using namespace Linphone; using namespace std; -Participant::Participant(LinphoneCall *call) { +Conference::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) { +Conference::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() { +Conference::Participant::~Participant() { linphone_address_unref(m_uri); if(m_call) linphone_call_unref(m_call); } -bool Participant::operator==(const Participant &src) const { +bool Conference::Participant::operator==(const Participant &src) const { return linphone_address_equal(m_uri, src.m_uri); } @@ -216,7 +226,9 @@ Conference::Params::Params(const LinphoneCore *core): m_enableVideo(false) { Conference::Conference(LinphoneCore *core, const Conference::Params *params): m_core(core), m_localParticipantStream(NULL), - m_isMuted(false) { + m_isMuted(false), + m_currentParams(), + m_state(LinphoneConferenceStopped) { if(params) m_currentParams = *params; } @@ -275,7 +287,19 @@ float Conference::getInputVolume() const { return LINPHONE_VOLUME_DB_LOWEST; } -const Participant *Conference::findParticipant(const LinphoneAddress *uri) const { +const char *Conference::stateToString(LinphoneConferenceState state) { + switch(state) { + case LinphoneConferenceStopped: return "Stopped"; + case LinphoneConferenceStarting: return "Starting"; + case LinphoneConferenceReady: return "Ready"; + case LinphoneConferenceStartingFailed: return "Startig failed"; + default: return "Invalid state"; + } +} + + + +const Conference::Participant *Conference::findParticipant(const LinphoneAddress *uri) const { list::const_iterator it = m_participants.begin(); while(it!=m_participants.end()) { if(linphone_address_equal(uri, it->getUri())) break; @@ -285,6 +309,17 @@ const Participant *Conference::findParticipant(const LinphoneAddress *uri) const else return &*it; } +void Conference::setState(LinphoneConferenceState state) { + if(m_state != state) { + ms_message("Switching conference [%p] into state '%s'", this, stateToString(state)); + m_state = state; + if(m_currentParams.m_state_changed_cb) { + m_currentParams.m_state_changed_cb((LinphoneConference *)this, state, m_currentParams.m_user_data); + } + } +} + + LocalConference::LocalConference(LinphoneCore *core, const Conference::Params *params): @@ -298,7 +333,7 @@ LocalConference::LocalConference(LinphoneCore *core, const Conference::Params *p MSAudioConferenceParams ms_conf_params; ms_conf_params.samplerate = lp_config_get_int(m_core->config, "sound","conference_rate",16000); m_conf=ms_audio_conference_new(&ms_conf_params, core->factory); - + m_state=LinphoneConferenceReady; } LocalConference::~LocalConference() { @@ -587,10 +622,10 @@ RemoteConference::RemoteConference(LinphoneCore *core, const Conference::Params m_focusAddr(NULL), m_focusContact(NULL), m_focusCall(NULL), - m_state(NotConnectedToFocus), m_vtable(NULL), m_pendingCalls(NULL), - m_transferingCalls(NULL) { + m_transferingCalls(NULL), + m_isTerminating(false) { 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; @@ -600,7 +635,7 @@ RemoteConference::RemoteConference(LinphoneCore *core, const Conference::Params } RemoteConference::~RemoteConference() { - if(m_state == ConnectedToFocus) terminate(); + terminate(); linphone_core_remove_listener(m_core, m_vtable); linphone_core_v_table_destroy(m_vtable); } @@ -610,34 +645,38 @@ int RemoteConference::addParticipant(LinphoneCall *call) { LinphoneCallParams *params; switch(m_state) { - case NotConnectedToFocus: + case LinphoneConferenceStopped: + case LinphoneConferenceStartingFailed: Conference::addParticipant(call); ms_message("Calling the conference focus (%s)", m_focusAddr); addr = linphone_address_new(m_focusAddr); if(addr) { params = linphone_core_create_call_params(m_core, NULL); linphone_call_params_enable_video(params, m_currentParams.videoRequested()); - m_focusCall = linphone_call_ref(linphone_core_invite_address_with_params(m_core, addr, params)); + m_focusCall = linphone_core_invite_address_with_params(m_core, addr, params); m_focusCall->conf_ref = (LinphoneConference *)this; m_localParticipantStream = m_focusCall->audiostream; m_pendingCalls = ms_list_append(m_pendingCalls, call); - m_state = ConnectingToFocus; LinphoneCallLog *callLog = linphone_call_get_call_log(m_focusCall); callLog->was_conference = TRUE; linphone_address_unref(addr); linphone_call_params_unref(params); + setState(LinphoneConferenceStarting); return 0; } else return -1; - case ConnectingToFocus: + case LinphoneConferenceStarting: Conference::addParticipant(call); - m_pendingCalls = ms_list_append(m_pendingCalls, call); + if(focusIsReady()) { + transferToFocus(call); + } else { + m_pendingCalls = ms_list_append(m_pendingCalls, call); + } return 0; - case ConnectedToFocus: + case LinphoneConferenceReady: Conference::addParticipant(call); - m_transferingCalls = ms_list_append(m_transferingCalls, call); - linphone_core_transfer_call(m_core, call, m_focusContact); + transferToFocus(call); return 0; default: @@ -651,15 +690,21 @@ int RemoteConference::removeParticipant(const LinphoneAddress *uri) { int res; switch(m_state) { - case ConnectedToFocus: + case LinphoneConferenceReady: 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; + if(res == 0) { + return Conference::removeParticipant(uri); + } else { + char *tmp = linphone_address_as_string(uri); + ms_error("Conference: could not remove participant '%s': REFER with BYE has failed", tmp); + ms_free(tmp); + return -1; + } default: ms_error("Cannot remove %s from conference: Bad conference state (%s)", linphone_address_as_string(uri), stateToString(m_state)); @@ -668,20 +713,25 @@ int RemoteConference::removeParticipant(const LinphoneAddress *uri) { } int RemoteConference::terminate() { + m_isTerminating = true; switch(m_state) { - case ConnectingToFocus: - case ConnectedToFocus: + case LinphoneConferenceReady: + case LinphoneConferenceStarting: linphone_core_terminate_call(m_core, m_focusCall); + reset(); + Conference::terminate(); + setState(LinphoneConferenceStopped); break; + default: break; } - Conference::terminate(); + m_isTerminating = false; return 0; } int RemoteConference::enter() { - if(m_state != ConnectedToFocus) { + if(m_state != LinphoneConferenceReady) { ms_error("Could not enter in the conference: bad conference state (%s)", stateToString(m_state)); return -1; } @@ -699,7 +749,7 @@ int RemoteConference::enter() { } int RemoteConference::leave() { - if(m_state != ConnectedToFocus) { + if(m_state != LinphoneConferenceReady) { ms_error("Could not leave the conference: bad conference state (%s)", stateToString(m_state)); return -1; } @@ -717,26 +767,45 @@ int RemoteConference::leave() { } bool RemoteConference::isIn() const { - if(m_state != ConnectedToFocus) return false; + if(m_state != LinphoneConferenceReady) 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"; +bool RemoteConference::focusIsReady() const { + LinphoneCallState focusState; + if(m_focusCall == NULL) return false; + focusState = linphone_call_get_state(m_focusCall); + return focusState == LinphoneCallStreamsRunning || focusState == LinphoneCallPaused; +} + +bool RemoteConference::transferToFocus(LinphoneCall *call) { + if(linphone_core_transfer_call(m_core, call, m_focusContact) == 0) { + m_transferingCalls = ms_list_append(m_transferingCalls, call); + return true; + } else { + ms_error("Conference: could not transfer call [%p] to %s", call, m_focusContact); + return false; } } +void RemoteConference::reset() { + m_localParticipantStream = NULL; + m_focusAddr = NULL; + if(m_focusContact) { + ms_free(m_focusContact); + m_focusContact = NULL; + } + m_focusCall = NULL; + m_pendingCalls = ms_list_free(m_pendingCalls); + m_transferingCalls = ms_list_free(m_transferingCalls); +} + 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) { @@ -746,27 +815,21 @@ void RemoteConference::onFocusCallSateChanged(LinphoneCallState state) { 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); + transferToFocus(pendingCall); } else { it = it->next; } } + setState(LinphoneConferenceReady); break; case LinphoneCallError: + reset(); + setState(LinphoneConferenceStartingFailed); + break; + case LinphoneCallEnd: - 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(m_pendingCalls); - m_transferingCalls = ms_list_free(m_transferingCalls); - Conference::terminate(); + if(!m_isTerminating) terminate(); break; default: break; @@ -777,7 +840,7 @@ void RemoteConference::onPendingCallStateChanged(LinphoneCall *call, LinphoneCal switch(state) { case LinphoneCallStreamsRunning: case LinphoneCallPaused: - if(m_state == ConnectedToFocus) { + if(m_state == LinphoneConferenceReady) { 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); @@ -827,6 +890,10 @@ void RemoteConference::transferStateChanged(LinphoneCore *lc, LinphoneCall *tran +const char *linphone_conference_state_to_string(LinphoneConferenceState state) { + return Conference::stateToString(state); +} + LinphoneConferenceParams *linphone_conference_params_new(const LinphoneCore *core) { return (LinphoneConferenceParams *)new Conference::Params(core); } @@ -847,6 +914,10 @@ bool_t linphone_conference_params_video_requested(const LinphoneConferenceParams return ((Conference::Params *)params)->videoRequested(); } +void linphone_conference_params_set_state_changed_callback(LinphoneConferenceParams *params, LinphoneConferenceStateChangedCb cb, void *user_data) { + ((Conference::Params *)params)->setStateChangedCallback(cb, user_data); +} + LinphoneConference *linphone_local_conference_new(LinphoneCore *core) { @@ -869,6 +940,10 @@ void linphone_conference_free(LinphoneConference *obj) { delete (Conference *)obj; } +LinphoneConferenceState linphone_conference_get_state(const LinphoneConference *obj) { + return ((Conference *)obj)->getState(); +} + int linphone_conference_add_participant(LinphoneConference *obj, LinphoneCall *call) { return ((Conference *)obj)->addParticipant(call); } @@ -918,9 +993,9 @@ int linphone_conference_get_size(const LinphoneConference *obj) { } MSList *linphone_conference_get_participants(const LinphoneConference *obj) { - const list &participants = ((Conference *)obj)->getParticipants(); + const list &participants = ((Conference *)obj)->getParticipants(); MSList *participants_list = NULL; - for(list::const_iterator it=participants.begin();it!=participants.end();it++) { + 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); } diff --git a/coreapi/conference.h b/coreapi/conference.h index a043a8a33..cc9762bf1 100644 --- a/coreapi/conference.h +++ b/coreapi/conference.h @@ -37,11 +37,18 @@ extern "C" { * @{ */ +/** + * LinphoneConference class + */ +typedef struct _LinphoneConference LinphoneConference; /** * Parameters for initialization of conferences */ typedef struct _LinphoneCorferenceParams LinphoneConferenceParams; + + + /** * Create a #LinphoneConferenceParams with default parameters set. * @param core #LinphoneCore to use to find out the default parameters. Can be NULL. @@ -73,10 +80,7 @@ LINPHONE_PUBLIC bool_t linphone_conference_params_video_requested(const Linphone -/** - * LinphoneConference class - */ -typedef struct _LinphoneConference LinphoneConference; + /** * Remove a participant from a conference diff --git a/coreapi/conference_private.h b/coreapi/conference_private.h index 3147cfd9a..bc203f794 100644 --- a/coreapi/conference_private.h +++ b/coreapi/conference_private.h @@ -37,11 +37,48 @@ typedef enum { LinphoneConferenceClassRemote } LinphoneConferenceClass; +/** + * List of states used by #LinphoneConference + */ +typedef enum { + LinphoneConferenceStopped, /*< Initial state */ + LinphoneConferenceStarting, /*< A participant has been added but the conference is not running yet */ + LinphoneConferenceReady, /*< The conference is running */ + LinphoneConferenceStartingFailed /*< A participant has been added but the initialization of the conference has failed */ +} LinphoneConferenceState; +/** + * Type of the funtion to pass as callback to linphone_conference_params_set_state_changed_callback() + * @param conference The conference instance which the state has changed + * @param new_state The new state of the conferenece + * @param user_data Pointer pass to user_data while linphone_conference_params_set_state_changed_callback() was being called + */ +typedef void (*LinphoneConferenceStateChangedCb)(LinphoneConference *conference, LinphoneConferenceState new_state, void *user_data); + + +/** + * A function to converte a #LinphoneConferenceState into a string + */ +const char *linphone_conference_state_to_string(LinphoneConferenceState state); + + +/** + * Set a callback which will be called when the state of the conferenec is switching + * @param params A #LinphoneConferenceParams object + * @param cb The callback to call + * @param user_data Pointer to pass to the user_data parameter of #LinphoneConferenceStateChangedCb + */ +void linphone_conference_params_set_state_changed_callback(LinphoneConferenceParams *params, LinphoneConferenceStateChangedCb cb, void *user_data); + + LinphoneConference *linphone_local_conference_new(LinphoneCore *core); LinphoneConference *linphone_local_conference_new_with_params(LinphoneCore *core, const LinphoneConferenceParams *params); LinphoneConference *linphone_remote_conference_new(LinphoneCore *core); LinphoneConference *linphone_remote_conference_new_with_params(LinphoneCore *core, const LinphoneConferenceParams *params); void linphone_conference_free(LinphoneConference *obj); +/** + * Get the state of a conference + */ +LinphoneConferenceState linphone_conference_get_state(const LinphoneConference *obj); int linphone_conference_add_participant(LinphoneConference *obj, LinphoneCall *call); int linphone_conference_remove_participant_with_call(LinphoneConference *obj, LinphoneCall *call); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 95efd2a1d..f1deb704d 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -7461,18 +7461,30 @@ LinphoneRingtonePlayer *linphone_core_get_ringtoneplayer(LinphoneCore *lc) { return lc->ringtoneplayer; } +static void linphone_core_conference_state_changed(LinphoneConference *conf, LinphoneConferenceState cstate, void *user_data) { + LinphoneCore *lc = (LinphoneCore *)user_data; + if(cstate == LinphoneConferenceStartingFailed || cstate == LinphoneConferenceStopped) { + linphone_conference_free(lc->conf_ctx); + lc->conf_ctx = NULL; + } +} + LinphoneConference *linphone_core_create_conference_with_params(LinphoneCore *lc, const LinphoneConferenceParams *params) { const char *conf_method_name; if(lc->conf_ctx == NULL) { + LinphoneConferenceParams *params2 = linphone_conference_params_clone(params); + linphone_conference_params_set_state_changed_callback(params2, linphone_core_conference_state_changed, lc); 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_with_params(lc, params); + lc->conf_ctx = linphone_local_conference_new_with_params(lc, params2); } else if(strcasecmp(conf_method_name, "remote") == 0) { - lc->conf_ctx = linphone_remote_conference_new_with_params(lc, params); + lc->conf_ctx = linphone_remote_conference_new_with_params(lc, params2); } else { ms_error("'%s' is not a valid conference method", conf_method_name); + linphone_conference_params_free(params2); return NULL; } + linphone_conference_params_free(params2); } else { ms_error("Could not create a conference: a conference instance already exists"); return NULL; @@ -7482,7 +7494,12 @@ LinphoneConference *linphone_core_create_conference_with_params(LinphoneCore *lc int linphone_core_add_to_conference(LinphoneCore *lc, LinphoneCall *call) { LinphoneConference *conference = linphone_core_get_conference(lc); - if(conference == NULL) conference = linphone_core_create_conference_with_params(lc, NULL); + if(conference == NULL) { + LinphoneConferenceParams *params = linphone_conference_params_new(lc); + linphone_conference_params_set_state_changed_callback(params, linphone_core_conference_state_changed, lc); + conference = linphone_core_create_conference_with_params(lc, params); + linphone_conference_params_free(params); + } if(conference) return linphone_conference_add_participant(lc->conf_ctx, call); else return -1; } @@ -7508,7 +7525,10 @@ int linphone_core_remove_from_conference(LinphoneCore *lc, LinphoneCall *call) { } int linphone_core_terminate_conference(LinphoneCore *lc) { - if(lc->conf_ctx == NULL) return -1; + if(lc->conf_ctx == NULL) { + ms_error("Could not terminate conference: no conference context"); + return -1; + } linphone_conference_terminate(lc->conf_ctx); linphone_conference_free(lc->conf_ctx); lc->conf_ctx = NULL; diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index ee1b2eec8..9c9898983 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -258,6 +258,7 @@ typedef struct _LinphoneConferenceServer { LinphoneCoreManager base; LinphoneCall *first_call; LinphoneCoreVTable *vtable; + LinphoneRegistrationState reg_state; } LinphoneConferenceServer; typedef struct _LinphoneCallTestParams { @@ -361,7 +362,7 @@ 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); +LinphoneConferenceServer* linphone_conference_server_new(const char *rc_file, bool_t do_registration); void linphone_conference_server_destroy(LinphoneConferenceServer *conf_srv); extern const char *liblinphone_tester_mire_id; diff --git a/tester/multi_call_tester.c b/tester/multi_call_tester.c index 58474c041..a7f00e855 100644 --- a/tester/multi_call_tester.c +++ b/tester/multi_call_tester.c @@ -188,6 +188,7 @@ static void simple_conference_base(LinphoneCoreManager* marie, LinphoneCoreManag LinphoneConference *conference; const MSList* calls; bool_t is_remote_conf; + bool_t focus_is_up = (focus && ((LinphoneConferenceServer *)focus)->reg_state == LinphoneRegistrationOk); MSList* lcs=ms_list_append(NULL,marie->lc); lcs=ms_list_append(lcs,pauline->lc); lcs=ms_list_append(lcs,laure->lc); @@ -213,9 +214,21 @@ static void simple_conference_base(LinphoneCoreManager* marie, LinphoneCoreManag 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)); + if(focus_is_up) { + 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)); + } else { + BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallError, initial_marie_stat.number_of_LinphoneCallError+1, 5000)); + BC_ASSERT_PTR_NULL(linphone_core_get_conference(marie->lc)); + BC_ASSERT_EQUAL(linphone_core_terminate_conference(marie->lc), -1, int, "%d"); + linphone_core_terminate_call(marie->lc, marie_call_pauline); + linphone_core_terminate_call(marie->lc, marie_call_laure); + BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallEnd, initial_marie_stat.number_of_LinphoneCallEnd+2, 10000)); + 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, &laure->stat.number_of_LinphoneCallEnd, initial_laure_stat.number_of_LinphoneCallEnd+1, 5000)); + goto end; + } } linphone_core_add_to_conference(marie->lc,marie_call_pauline); @@ -267,11 +280,11 @@ 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,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)); - + +end: ms_list_free(lcs); } @@ -766,7 +779,38 @@ 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"); + LinphoneConferenceServer *focus = linphone_conference_server_new("conference_focus_rc", TRUE); + 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 simple_remote_conference_shut_down_focus(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", FALSE); 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); @@ -797,7 +841,7 @@ 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"); + LinphoneConferenceServer *focus = linphone_conference_server_new("conference_focus_rc", TRUE); 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); @@ -840,7 +884,8 @@ test_t multi_call_tests[] = { TEST_NO_TAG("Unattended call transfer with error", unattended_call_transfer_with_error), TEST_NO_TAG("Call transfer existing call outgoing call", call_transfer_existing_call_outgoing_call), TEST_NO_TAG("Simple remote conference", simple_remote_conference), - TEST_NO_TAG("Eject from 3 participants in remote conference", eject_from_3_participants_remote_conference) + TEST_NO_TAG("Simple remote conference with shut down focus", simple_remote_conference_shut_down_focus), + TEST_NO_TAG("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, diff --git a/tester/tester.c b/tester/tester.c index 510f5d3b4..7abe6829f 100644 --- a/tester/tester.c +++ b/tester/tester.c @@ -667,7 +667,7 @@ 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) { +static 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; @@ -696,7 +696,7 @@ void linphone_conference_server_call_state_changed(LinphoneCore *lc, LinphoneCal } } -void linphone_conference_server_refer_received(LinphoneCore *core, const char *refer_to) { +static 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; @@ -714,17 +714,30 @@ void linphone_conference_server_refer_received(LinphoneCore *core, const char *r linphone_address_destroy(refer_to_addr); } -LinphoneConferenceServer* linphone_conference_server_new(const char *rc_file) { +static void linphone_conference_server_registration_state_changed(LinphoneCore *core, + LinphoneProxyConfig *cfg, + LinphoneRegistrationState cstate, + const char *message) { + LinphoneCoreVTable *vtable = linphone_core_get_current_vtable(core); + LinphoneConferenceServer *m = (LinphoneConferenceServer *)linphone_core_v_table_get_user_data(vtable); + if(cfg == linphone_core_get_default_proxy_config(core)) { + m->reg_state = cstate; + } +} + +LinphoneConferenceServer* linphone_conference_server_new(const char *rc_file, bool_t do_registration) { 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->registration_state_changed = linphone_conference_server_registration_state_changed; conf_srv->vtable->user_data = conf_srv; + conf_srv->reg_state = LinphoneRegistrationNone; linphone_core_manager_init(lm, rc_file); linphone_core_add_listener(lm->lc, conf_srv->vtable); - linphone_core_manager_start(lm, TRUE); + linphone_core_manager_start(lm, do_registration); return conf_srv; }