Commit 08f0afbe authored by Simon Morlat's avatar Simon Morlat
Browse files

Fix conference crash, while it is converted to normal call, if the application...

Fix conference crash, while it is converted to normal call, if the application has no longer any reference to the LinphoneConference object.
parent 74ed1a64
......@@ -510,7 +510,8 @@ int LocalConference::addParticipant (LinphoneCall *call) {
return 0;
}
int LocalConference::removeFromConference (LinphoneCall *call, bool_t active) {
int LocalConference::removeFromConference (LinphoneCall *call, bool_t active_after_removed) {
bool noMediaRestartRequired = false;
/* Special handling for already terminated calls.*/
switch(linphone_call_get_state(call)){
case LinphoneCallEnd:
......@@ -523,8 +524,11 @@ int LocalConference::removeFromConference (LinphoneCall *call, bool_t active) {
}
if (!linphone_call_params_get_in_conference(linphone_call_get_current_params(call))) {
if (linphone_call_params_get_in_conference(linphone_call_get_params(call))) {
ms_warning("Not (yet) in conference, be patient");
return -1;
/* Another special case for calls that have not yet started their streams,
* they are not physically connected to the conference.
* */
ms_message("Call was not yet attached to the conference, it can be removed immediately.");
noMediaRestartRequired = true;
} else {
ms_error("Not in a conference");
return -1;
......@@ -534,11 +538,15 @@ int LocalConference::removeFromConference (LinphoneCall *call, bool_t active) {
const_cast<LinphonePrivate::MediaSessionParamsPrivate *>(
L_GET_PRIVATE(L_GET_CPP_PTR_FROM_C_OBJECT(call)->getParams()))->setInConference(false);
if (noMediaRestartRequired){
_linphone_call_set_conf_ref(call, nullptr);
return 0;
}
char *str = linphone_call_get_remote_address_as_string(call);
ms_message("%s will be removed from conference", str);
ms_free(str);
int err = 0;
if (active) {
if (active_after_removed) {
LinphoneCallParams *params = linphone_call_params_copy(linphone_call_get_current_params(call));
linphone_call_params_set_in_conference(params, FALSE);
// Reconnect local audio with this call
......@@ -707,14 +715,14 @@ void LocalConference::onCallStreamStopping (LinphoneCall *call) {
}
void LocalConference::participantUnplugged(LinphoneCall *call){
int remote_count = remoteParticipantsCount();
ms_message("conference_check_uninit(): size=%i", getSize());
int mixer_connected_remote_participants_count = ms_audio_conference_get_size(m_conf);
if (m_recordEndpoint) mixer_connected_remote_participants_count--;
if (m_localParticipantStream) mixer_connected_remote_participants_count--;
ms_message("participantUnplugged(): remote participant count still connected = %i", mixer_connected_remote_participants_count);
_linphone_call_set_conf_ref(call, nullptr);
if ((remote_count == 1) && !m_terminating){
if (m_currentParams->localParticipantEnabled()) convertConferenceToCall();
}
if (remote_count == 0) {
if (mixer_connected_remote_participants_count == 0) {
if (m_localParticipantStream){
removeLocalEndpoint();
linphone_core_soundcard_hint_check(m_core);
......
......@@ -484,6 +484,88 @@ static void simple_conference_from_scratch(void){
bctbx_list_free(lcs);
}
static void simple_conference_from_scratch_to_call(void){
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc");
LinphoneCoreManager* laure = linphone_core_manager_new( get_laure_rc());
LinphoneConference *conf;
LinphoneConferenceParams *conf_params;
LinphoneCall *pauline_call, *laure_call;
bctbx_list_t *participants = NULL;
bctbx_list_t *lcs = NULL;
lcs = bctbx_list_append(lcs, marie->lc);
lcs = bctbx_list_append(lcs, pauline->lc);
lcs = bctbx_list_append(lcs, laure->lc);
/*marie creates the conference*/
conf_params = linphone_core_create_conference_params(marie->lc);
linphone_conference_params_enable_video(conf_params, FALSE);
conf = linphone_core_create_conference_with_params(marie->lc, conf_params);
linphone_conference_params_unref(conf_params);
participants = bctbx_list_append(participants, pauline->identity);
participants = bctbx_list_append(participants, laure->identity);
linphone_conference_invite_participants(conf, participants, NULL);
linphone_conference_unref(conf); // the conference remains hold by the core.
BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallOutgoingProgress,2,2000));
BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallIncomingReceived,1,10000));
BC_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallIncomingReceived,1,10000));
pauline_call = linphone_core_get_current_call(pauline->lc);
laure_call = linphone_core_get_current_call(laure->lc);
BC_ASSERT_PTR_NOT_NULL(pauline_call);
BC_ASSERT_PTR_NOT_NULL(laure_call);
if (pauline_call && laure_call){
const bctbx_list_t *marie_calls, *it;
linphone_call_accept(pauline_call);
linphone_call_accept(laure_call);
BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallConnected,2,10000));
BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallStreamsRunning,2,3000));
BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallStreamsRunning,1,3000));
BC_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallStreamsRunning,1,3000));
/*make sure that the two calls from Marie's standpoint are in conference*/
marie_calls = linphone_core_get_calls(marie->lc);
BC_ASSERT_EQUAL((int)bctbx_list_size(marie_calls), 2, int, "%i");
for (it = marie_calls; it != NULL; it = it->next){
BC_ASSERT_TRUE(linphone_call_params_get_local_conference_mode(linphone_call_get_current_params((LinphoneCall*)it->data)) == TRUE);
}
/*wait a bit for the conference audio processing to run, despite we do not test it for the moment*/
wait_for_list(lcs,NULL,0,3000);
/* Now Laure leaves the conference. */
linphone_call_terminate(laure_call);
BC_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallEnd,1,10000));
BC_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallReleased,1,10000));
BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,5000));
/* The core will automatically reconnect Marie with Pauline with a simple call, and the conference is going to be destroyed. */
BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallStreamsRunning,3,5000));
BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallStreamsRunning,1,5000));
BC_ASSERT_PTR_NULL(linphone_core_get_conference(marie->lc));
/* Pauline ends the call. */
linphone_call_terminate(pauline_call);
BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,2,5000));
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_LinphoneCallReleased,2,1000));
BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallReleased,1,1000));
}
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
linphone_core_manager_destroy(laure);
bctbx_list_free(participants);
bctbx_list_free(lcs);
}
static void simple_conference_from_scratch_no_answer(void){
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc");
......@@ -1011,8 +1093,10 @@ static void eject_from_3_participants_conference(LinphoneCoreManager *marie, Lin
if(!is_remote_conf) BC_ASSERT_PTR_NULL(linphone_core_get_current_call(marie->lc));
if(!is_remote_conf) linphone_core_remove_from_conference(marie->lc, marie_call_pauline);
else {
if(!is_remote_conf) {
linphone_core_remove_from_conference(marie->lc, marie_call_pauline);
/* the removal will automatically transform the 1-1 conference back into a normal call. */
}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);
......@@ -1039,8 +1123,12 @@ static void eject_from_3_participants_conference(LinphoneCoreManager *marie, Lin
BC_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallEnd,1,10000));
} else {
linphone_core_terminate_conference(marie->lc);
/* Laure will by set "PausedByRemote" by the focus. It has to end the call explicitely.*/
linphone_call_terminate(linphone_core_get_current_call(laure->lc));
BC_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallEnd,initial_laure_stat.number_of_LinphoneCallEnd+2,3000));
BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,initial_marie_stat.number_of_LinphoneCallEnd+3,3000));
BC_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallReleased,initial_laure_stat.number_of_LinphoneCallReleased+2,3000));
BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallReleased,initial_marie_stat.number_of_LinphoneCallReleased+3,3000));
}
end:
bctbx_list_free(lcs);
......@@ -1343,6 +1431,7 @@ test_t multi_call_tests[] = {
TEST_NO_TAG("Incoming call accepted when outgoing call in outgoing ringing early media", incoming_call_accepted_when_outgoing_call_in_outgoing_ringing_early_media),
TEST_NO_TAG("Simple conference", simple_conference),
TEST_NO_TAG("Simple conference established from scratch", simple_conference_from_scratch),
TEST_NO_TAG("Simple conference established from scratch and finally transformed into a call", simple_conference_from_scratch_to_call),
TEST_NO_TAG("Simple conference established from scratch, but attendees do not answer", simple_conference_from_scratch_no_answer),
TEST_ONE_TAG("Simple conference with ICE", simple_conference_with_ice, "ICE"),
TEST_ONE_TAG("Simple ZRTP conference with ICE", simple_zrtp_conference_with_ice, "ICE"),
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment