Commit b4452da5 authored by François Grisez's avatar François Grisez
Browse files

Release the reference on the focus call when thatone fails

parent ca8d64d5
...@@ -32,31 +32,39 @@ ...@@ -32,31 +32,39 @@
namespace Linphone { 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 { class Conference {
public: 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 { class Params {
public: public:
Params(const LinphoneCore *core = NULL); Params(const LinphoneCore *core = NULL);
void enableVideo(bool enable) {m_enableVideo = enable;} void enableVideo(bool enable) {m_enableVideo = enable;}
bool videoRequested() const {return m_enableVideo;} bool videoRequested() const {return m_enableVideo;}
void setStateChangedCallback(LinphoneConferenceStateChangedCb cb, void *user_data) {
m_state_changed_cb=cb;
m_user_data=user_data;
}
private: private:
bool m_enableVideo; bool m_enableVideo;
LinphoneConferenceStateChangedCb m_state_changed_cb;
void *m_user_data;
friend class Conference;
}; };
Conference(LinphoneCore *core, const Params *params = NULL); Conference(LinphoneCore *core, const Params *params = NULL);
...@@ -88,14 +96,19 @@ public: ...@@ -88,14 +96,19 @@ public:
virtual void onCallStreamStopping(LinphoneCall *call) {}; virtual void onCallStreamStopping(LinphoneCall *call) {};
virtual void onCallTerminating(LinphoneCall *call) {}; virtual void onCallTerminating(LinphoneCall *call) {};
LinphoneConferenceState getState() const {return m_state;}
static const char *stateToString(LinphoneConferenceState state);
protected: protected:
const Participant *findParticipant(const LinphoneAddress* uri) const; const Participant *findParticipant(const LinphoneAddress* uri) const;
void setState(LinphoneConferenceState state);
LinphoneCore *m_core; LinphoneCore *m_core;
AudioStream *m_localParticipantStream; AudioStream *m_localParticipantStream;
bool m_isMuted; bool m_isMuted;
std::list<Participant> m_participants; std::list<Participant> m_participants;
Params m_currentParams; Params m_currentParams;
LinphoneConferenceState m_state;
}; };
class LocalConference: public Conference { class LocalConference: public Conference {
...@@ -153,12 +166,9 @@ public: ...@@ -153,12 +166,9 @@ public:
virtual int stopRecording() {return 0;} virtual int stopRecording() {return 0;}
private: private:
enum State { bool focusIsReady() const;
NotConnectedToFocus, bool transferToFocus(LinphoneCall *call);
ConnectingToFocus, void reset();
ConnectedToFocus,
};
static const char *stateToString(State state);
void onFocusCallSateChanged(LinphoneCallState state); void onFocusCallSateChanged(LinphoneCallState state);
void onPendingCallStateChanged(LinphoneCall *call, LinphoneCallState state); void onPendingCallStateChanged(LinphoneCall *call, LinphoneCallState state);
...@@ -170,10 +180,10 @@ private: ...@@ -170,10 +180,10 @@ private:
const char *m_focusAddr; const char *m_focusAddr;
char *m_focusContact; char *m_focusContact;
LinphoneCall *m_focusCall; LinphoneCall *m_focusCall;
State m_state;
LinphoneCoreVTable *m_vtable; LinphoneCoreVTable *m_vtable;
MSList *m_pendingCalls; MSList *m_pendingCalls;
MSList *m_transferingCalls; MSList *m_transferingCalls;
bool m_isTerminating;
}; };
}; };
...@@ -183,22 +193,22 @@ using namespace Linphone; ...@@ -183,22 +193,22 @@ using namespace Linphone;
using namespace std; using namespace std;
Participant::Participant(LinphoneCall *call) { Conference::Participant::Participant(LinphoneCall *call) {
m_uri = linphone_address_clone(linphone_call_get_remote_address(call)); m_uri = linphone_address_clone(linphone_call_get_remote_address(call));
m_call = linphone_call_ref(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_uri = linphone_address_clone(src.m_uri);
m_call = src.m_call ? linphone_call_ref(src.m_call) : NULL; m_call = src.m_call ? linphone_call_ref(src.m_call) : NULL;
} }
Participant::~Participant() { Conference::Participant::~Participant() {
linphone_address_unref(m_uri); linphone_address_unref(m_uri);
if(m_call) linphone_call_unref(m_call); 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); return linphone_address_equal(m_uri, src.m_uri);
} }
...@@ -216,7 +226,9 @@ Conference::Params::Params(const LinphoneCore *core): m_enableVideo(false) { ...@@ -216,7 +226,9 @@ Conference::Params::Params(const LinphoneCore *core): m_enableVideo(false) {
Conference::Conference(LinphoneCore *core, const Conference::Params *params): Conference::Conference(LinphoneCore *core, const Conference::Params *params):
m_core(core), m_core(core),
m_localParticipantStream(NULL), m_localParticipantStream(NULL),
m_isMuted(false) { m_isMuted(false),
m_currentParams(),
m_state(LinphoneConferenceStopped) {
if(params) m_currentParams = *params; if(params) m_currentParams = *params;
} }
...@@ -275,7 +287,19 @@ float Conference::getInputVolume() const { ...@@ -275,7 +287,19 @@ float Conference::getInputVolume() const {
return LINPHONE_VOLUME_DB_LOWEST; 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<Participant>::const_iterator it = m_participants.begin(); list<Participant>::const_iterator it = m_participants.begin();
while(it!=m_participants.end()) { while(it!=m_participants.end()) {
if(linphone_address_equal(uri, it->getUri())) break; if(linphone_address_equal(uri, it->getUri())) break;
...@@ -285,6 +309,17 @@ const Participant *Conference::findParticipant(const LinphoneAddress *uri) const ...@@ -285,6 +309,17 @@ const Participant *Conference::findParticipant(const LinphoneAddress *uri) const
else return &*it; 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): LocalConference::LocalConference(LinphoneCore *core, const Conference::Params *params):
...@@ -298,7 +333,7 @@ LocalConference::LocalConference(LinphoneCore *core, const Conference::Params *p ...@@ -298,7 +333,7 @@ LocalConference::LocalConference(LinphoneCore *core, const Conference::Params *p
MSAudioConferenceParams ms_conf_params; MSAudioConferenceParams ms_conf_params;
ms_conf_params.samplerate = lp_config_get_int(m_core->config, "sound","conference_rate",16000); 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_conf=ms_audio_conference_new(&ms_conf_params, core->factory);
m_state=LinphoneConferenceReady;
} }
LocalConference::~LocalConference() { LocalConference::~LocalConference() {
...@@ -587,10 +622,10 @@ RemoteConference::RemoteConference(LinphoneCore *core, const Conference::Params ...@@ -587,10 +622,10 @@ RemoteConference::RemoteConference(LinphoneCore *core, const Conference::Params
m_focusAddr(NULL), m_focusAddr(NULL),
m_focusContact(NULL), m_focusContact(NULL),
m_focusCall(NULL), m_focusCall(NULL),
m_state(NotConnectedToFocus),
m_vtable(NULL), m_vtable(NULL),
m_pendingCalls(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_focusAddr = lp_config_get_string(m_core->config, "misc", "conference_focus_addr", "");
m_vtable = linphone_core_v_table_new(); m_vtable = linphone_core_v_table_new();
m_vtable->call_state_changed = callStateChangedCb; m_vtable->call_state_changed = callStateChangedCb;
...@@ -600,7 +635,7 @@ RemoteConference::RemoteConference(LinphoneCore *core, const Conference::Params ...@@ -600,7 +635,7 @@ RemoteConference::RemoteConference(LinphoneCore *core, const Conference::Params
} }
RemoteConference::~RemoteConference() { RemoteConference::~RemoteConference() {
if(m_state == ConnectedToFocus) terminate(); terminate();
linphone_core_remove_listener(m_core, m_vtable); linphone_core_remove_listener(m_core, m_vtable);
linphone_core_v_table_destroy(m_vtable); linphone_core_v_table_destroy(m_vtable);
} }
...@@ -610,34 +645,38 @@ int RemoteConference::addParticipant(LinphoneCall *call) { ...@@ -610,34 +645,38 @@ int RemoteConference::addParticipant(LinphoneCall *call) {
LinphoneCallParams *params; LinphoneCallParams *params;
switch(m_state) { switch(m_state) {
case NotConnectedToFocus: case LinphoneConferenceStopped:
case LinphoneConferenceStartingFailed:
Conference::addParticipant(call); Conference::addParticipant(call);
ms_message("Calling the conference focus (%s)", m_focusAddr); ms_message("Calling the conference focus (%s)", m_focusAddr);
addr = linphone_address_new(m_focusAddr); addr = linphone_address_new(m_focusAddr);
if(addr) { if(addr) {
params = linphone_core_create_call_params(m_core, NULL); params = linphone_core_create_call_params(m_core, NULL);
linphone_call_params_enable_video(params, m_currentParams.videoRequested()); 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_focusCall->conf_ref = (LinphoneConference *)this;
m_localParticipantStream = m_focusCall->audiostream; m_localParticipantStream = m_focusCall->audiostream;
m_pendingCalls = ms_list_append(m_pendingCalls, call); m_pendingCalls = ms_list_append(m_pendingCalls, call);
m_state = ConnectingToFocus;
LinphoneCallLog *callLog = linphone_call_get_call_log(m_focusCall); LinphoneCallLog *callLog = linphone_call_get_call_log(m_focusCall);
callLog->was_conference = TRUE; callLog->was_conference = TRUE;
linphone_address_unref(addr); linphone_address_unref(addr);
linphone_call_params_unref(params); linphone_call_params_unref(params);
setState(LinphoneConferenceStarting);
return 0; return 0;
} else return -1; } else return -1;
case ConnectingToFocus: case LinphoneConferenceStarting:
Conference::addParticipant(call); 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; return 0;
case ConnectedToFocus: case LinphoneConferenceReady:
Conference::addParticipant(call); Conference::addParticipant(call);
m_transferingCalls = ms_list_append(m_transferingCalls, call); transferToFocus(call);
linphone_core_transfer_call(m_core, call, m_focusContact);
return 0; return 0;
default: default:
...@@ -651,15 +690,21 @@ int RemoteConference::removeParticipant(const LinphoneAddress *uri) { ...@@ -651,15 +690,21 @@ int RemoteConference::removeParticipant(const LinphoneAddress *uri) {
int res; int res;
switch(m_state) { switch(m_state) {
case ConnectedToFocus: case LinphoneConferenceReady:
tmp = linphone_address_as_string_uri_only(uri); tmp = linphone_address_as_string_uri_only(uri);
refer_to = ms_strdup_printf("%s;method=BYE", tmp); refer_to = ms_strdup_printf("%s;method=BYE", tmp);
res = sal_call_refer(m_focusCall->op, refer_to); res = sal_call_refer(m_focusCall->op, refer_to);
ms_free(tmp); ms_free(tmp);
ms_free(refer_to); ms_free(refer_to);
if(res == 0) return Conference::removeParticipant(uri); if(res == 0) {
else return -1; 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: default:
ms_error("Cannot remove %s from conference: Bad conference state (%s)", linphone_address_as_string(uri), stateToString(m_state)); 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) { ...@@ -668,20 +713,25 @@ int RemoteConference::removeParticipant(const LinphoneAddress *uri) {
} }
int RemoteConference::terminate() { int RemoteConference::terminate() {
m_isTerminating = true;
switch(m_state) { switch(m_state) {
case ConnectingToFocus: case LinphoneConferenceReady:
case ConnectedToFocus: case LinphoneConferenceStarting:
linphone_core_terminate_call(m_core, m_focusCall); linphone_core_terminate_call(m_core, m_focusCall);
reset();
Conference::terminate();
setState(LinphoneConferenceStopped);
break; break;
default: default:
break; break;
} }
Conference::terminate(); m_isTerminating = false;
return 0; return 0;
} }
int RemoteConference::enter() { 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)); ms_error("Could not enter in the conference: bad conference state (%s)", stateToString(m_state));
return -1; return -1;
} }
...@@ -699,7 +749,7 @@ int RemoteConference::enter() { ...@@ -699,7 +749,7 @@ int RemoteConference::enter() {
} }
int RemoteConference::leave() { 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)); ms_error("Could not leave the conference: bad conference state (%s)", stateToString(m_state));
return -1; return -1;
} }
...@@ -717,26 +767,45 @@ int RemoteConference::leave() { ...@@ -717,26 +767,45 @@ int RemoteConference::leave() {
} }
bool RemoteConference::isIn() const { bool RemoteConference::isIn() const {
if(m_state != ConnectedToFocus) return false; if(m_state != LinphoneConferenceReady) return false;
LinphoneCallState callState = linphone_call_get_state(m_focusCall); LinphoneCallState callState = linphone_call_get_state(m_focusCall);
return callState == LinphoneCallStreamsRunning; return callState == LinphoneCallStreamsRunning;
} }
const char *RemoteConference::stateToString(RemoteConference::State state) { bool RemoteConference::focusIsReady() const {
switch(state) { LinphoneCallState focusState;
case NotConnectedToFocus: return "NotConnectedToFocus"; if(m_focusCall == NULL) return false;
case ConnectingToFocus: return "ConnectingToFocus"; focusState = linphone_call_get_state(m_focusCall);
case ConnectedToFocus: return "ConnectedToFocus"; return focusState == LinphoneCallStreamsRunning || focusState == LinphoneCallPaused;
default: return "Unknown"; }
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) { void RemoteConference::onFocusCallSateChanged(LinphoneCallState state) {
MSList *it; MSList *it;
switch (state) { switch (state) {
case LinphoneCallConnected: case LinphoneCallConnected:
m_state = ConnectedToFocus;
m_focusContact = ms_strdup(linphone_call_get_remote_contact(m_focusCall)); m_focusContact = ms_strdup(linphone_call_get_remote_contact(m_focusCall));
it = m_pendingCalls; it = m_pendingCalls;
while (it) { while (it) {
...@@ -746,27 +815,21 @@ void RemoteConference::onFocusCallSateChanged(LinphoneCallState state) { ...@@ -746,27 +815,21 @@ void RemoteConference::onFocusCallSateChanged(LinphoneCallState state) {
MSList *current_elem = it; MSList *current_elem = it;
it = it->next; it = it->next;
m_pendingCalls = ms_list_remove_link(m_pendingCalls, current_elem); m_pendingCalls = ms_list_remove_link(m_pendingCalls, current_elem);
m_transferingCalls = ms_list_append(m_transferingCalls, pendingCall); transferToFocus(pendingCall);
linphone_core_transfer_call(m_core, pendingCall, m_focusContact);
} else { } else {
it = it->next; it = it->next;
} }
} }
setState(LinphoneConferenceReady);
break; break;
case LinphoneCallError: case LinphoneCallError:
reset();
setState(LinphoneConferenceStartingFailed);
break;
case LinphoneCallEnd: case LinphoneCallEnd:
m_state = NotConnectedToFocus; if(!m_isTerminating) terminate();
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();
break; break;
default: break; default: break;
...@@ -777,7 +840,7 @@ void RemoteConference::onPendingCallStateChanged(LinphoneCall *call, LinphoneCal ...@@ -777,7 +840,7 @@ void RemoteConference::onPendingCallStateChanged(LinphoneCall *call, LinphoneCal
switch(state) { switch(state) {
case LinphoneCallStreamsRunning: case LinphoneCallStreamsRunning:
case LinphoneCallPaused: case LinphoneCallPaused:
if(m_state == ConnectedToFocus) { if(m_state == LinphoneConferenceReady) {
m_pendingCalls = ms_list_remove(m_pendingCalls, call); m_pendingCalls = ms_list_remove(m_pendingCalls, call);
m_transferingCalls = ms_list_append(m_transferingCalls, call); m_transferingCalls = ms_list_append(m_transferingCalls, call);
linphone_core_transfer_call(m_core, call, m_focusContact); linphone_core_transfer_call(m_core, call, m_focusContact);
...@@ -827,6 +890,10 @@ void RemoteConference::transferStateChanged(LinphoneCore *lc, LinphoneCall *tran ...@@ -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) { LinphoneConferenceParams *linphone_conference_params_new(const LinphoneCore *core) {
return (LinphoneConferenceParams *)new Conference::Params(core); return (LinphoneConferenceParams *)new Conference::Params(core);
} }
...@@ -847,6 +914,10 @@ bool_t linphone_conference_params_video_requested(const LinphoneConferenceParams ...@@ -847,6 +914,10 @@ bool_t linphone_conference_params_video_requested(const LinphoneConferenceParams
return ((Conference::Params *)params)->videoRequested(); 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) { LinphoneConference *linphone_local_conference_new(LinphoneCore *core) {
...@@ -869,6 +940,10 @@ void linphone_conference_free(LinphoneConference *obj) { ...@@ -869,6 +940,10 @@ void linphone_conference_free(LinphoneConference *obj) {
delete (Conference *)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) { int linphone_conference_add_participant(LinphoneConference *obj, LinphoneCall *call) {
return ((Conference *)obj)->addParticipant(call); return ((Conference *)obj)->addParticipant(call);
} }
...@@ -918,9 +993,9 @@ int linphone_conference_get_size(const LinphoneConference *obj) { ...@@ -918,9 +993,9 @@ int linphone_conference_get_size(const LinphoneConference *obj) {
} }
MSList *linphone_conference_get_participants(const LinphoneConference *obj) { MSList *linphone_conference_get_participants(const LinphoneConference *obj) {
const list<Participant> &participants = ((Conference *)obj)->getParticipants(); const list<Conference::Participant> &participants = ((Conference *)obj)->getParticipants();
MSList *participants_list = NULL; MSList *participants_list = NULL;
for(list<Participant>::const_iterator it=participants.begin();it!=participants.end();it++) { for(list<Conference::Participant>::const_iterator it=participants.begin();it!=participants.end();it++) {