Handle call repair in CallSession and MediaSession classes.

This commit is contained in:
Ghislain MARY 2017-12-05 15:33:48 +01:00
parent 52f13d34d0
commit 008ec55b37
20 changed files with 358 additions and 259 deletions

View file

@ -54,34 +54,11 @@ using namespace LinphonePrivate;
static void register_failure(SalOp *op);
static LinphoneCall * look_for_broken_call_to_replace(LinphonePrivate::SalOp *h, LinphoneCore *lc) {
const bctbx_list_t *calls = linphone_core_get_calls(lc);
const bctbx_list_t *it = calls;
while (it != NULL) {
#if 0
LinphoneCall *replaced_call = NULL;
LinphoneCall *call = (LinphoneCall *)bctbx_list_get_data(it);
SalOp *replaced_op = sal_call_get_replaces(h);
if (replaced_op) replaced_call = (LinphoneCall*)sal_op_get_user_pointer(replaced_op);
if ((call->broken && sal_call_compare_op(h, call->op))
|| ((replaced_call == call) && (strcmp(sal_op_get_from(h), sal_op_get_from(replaced_op)) == 0) && (strcmp(sal_op_get_to(h), sal_op_get_to(replaced_op)) == 0))) {
return call;
}
#endif
it = bctbx_list_next(it);
}
return NULL;
}
static void call_received(SalCallOp *h) {
/* Look if this INVITE is for a call that has already been notified but broken because of network failure */
LinphoneCore *lc = reinterpret_cast<LinphoneCore *>(h->get_sal()->get_user_pointer());
LinphoneCall *replacedCall = look_for_broken_call_to_replace(h, lc);
if (replacedCall) {
linphone_call_replace_op(replacedCall, h);
if (L_GET_PRIVATE_FROM_C_OBJECT(lc)->inviteReplacesABrokenCall(h))
return;
}
LinphoneAddress *fromAddr = nullptr;
const char *pAssertedId = sal_custom_header_find(h->get_recv_custom_header(), "P-Asserted-Identity");
@ -314,13 +291,12 @@ static void call_released(SalOp *op) {
}
static void call_cancel_done(SalOp *op) {
#if 0
LinphoneCall *call = (LinphoneCall *)sal_op_get_user_pointer(op);
if (call->reinvite_on_cancel_response_requested == TRUE) {
call->reinvite_on_cancel_response_requested = FALSE;
linphone_call_reinvite_to_recover_from_connection_loss(call);
LinphonePrivate::CallSession *session = reinterpret_cast<LinphonePrivate::CallSession *>(op->get_user_pointer());
if (!session) {
ms_warning("Cancel done reported on already terminated CallSession");
return;
}
#endif
L_GET_PRIVATE(session)->cancelDone();
}
static void auth_failure(SalOp *op, SalAuthInfo* info) {

View file

@ -6140,39 +6140,15 @@ static void set_sip_network_reachable(LinphoneCore* lc,bool_t is_sip_reachable,
if (!lc->sip_network_reachable){
linphone_core_invalidate_friend_subscriptions(lc);
lc->sal->reset_transports();
/*mark all calls as broken, so that they can be either dropped immediately or restaured when network will be back*/
#if 0
bctbx_list_for_each(lc->calls, (MSIterateFunc) linphone_call_set_broken);
#endif
}
}
void linphone_core_repair_calls(LinphoneCore *lc){
#if 0
if (lc->calls && lp_config_get_int(lc->config, "sip", "repair_broken_calls", 1) && lc->media_network_reachable){
/*if we are registered and there were broken calls due to a past network disconnection, attempt to repair them*/
bctbx_list_for_each(lc->calls, (MSIterateFunc) linphone_call_repair_if_broken);
}
#endif
}
static void set_media_network_reachable(LinphoneCore* lc, bool_t is_media_reachable){
if (lc->media_network_reachable==is_media_reachable) return; // no change, ignore.
ms_message("Media network reachability state is now [%s]",is_media_reachable?"UP":"DOWN");
lc->media_network_reachable=is_media_reachable;
if (!lc->media_network_reachable){
/*mark all calls as broken, so that they can be either dropped immediately or restaured when network will be back*/
#if 0
bctbx_list_for_each(lc->calls, (MSIterateFunc) linphone_call_set_broken);
#endif
}else{
if (lp_config_get_int(lc->config, "net", "recreate_sockets_when_network_is_up", 0)){
#if 0
bctbx_list_for_each(lc->calls, (MSIterateFunc)linphone_call_refresh_sockets);
#endif
}
linphone_core_repair_calls(lc);
if (lc->media_network_reachable){
if (lc->bw_controller){
ms_bandwidth_controller_reset_state(lc->bw_controller);
}

View file

@ -54,9 +54,6 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const
LinphoneCallLog * linphone_call_log_new(LinphoneCallDir dir, LinphoneAddress *from, LinphoneAddress * to);
void linphone_call_set_transfer_state(LinphoneCall* call, LinphoneCallState state);
LinphonePlayer *linphone_call_build_player(LinphoneCall*call);
void linphone_call_refresh_sockets(LinphoneCall *call);
void linphone_call_replace_op(LinphoneCall *call, LinphonePrivate::SalOp *op);
void linphone_call_reinvite_to_recover_from_connection_loss(LinphoneCall *call);
LinphonePrivate::SalCallOp *linphone_call_get_op(const LinphoneCall *call);
LinphoneProxyConfig * linphone_call_get_dest_proxy(const LinphoneCall *call);
@ -335,9 +332,6 @@ LinphoneEcCalibratorStatus ec_calibrator_get_status(EcCalibrator *ecc);
void ec_calibrator_destroy(EcCalibrator *ecc);
void linphone_call_set_broken(LinphoneCall *call);
void linphone_call_repair_if_broken(LinphoneCall *call);
void linphone_core_repair_calls(LinphoneCore *lc);
int linphone_core_preempt_sound_resources(LinphoneCore *lc);
int _linphone_call_pause(LinphoneCall *call);

View file

@ -1310,10 +1310,8 @@ void linphone_proxy_config_set_state(LinphoneProxyConfig *cfg, LinphoneRegistrat
cfg->state=state;
}
if (lc){
if (lc)
linphone_core_notify_registration_state_changed(lc,cfg,state,message);
linphone_core_repair_calls(lc);
}
} else {
/*state already reported*/
}

View file

@ -18,6 +18,9 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "c-wrapper/c-wrapper.h"
#include "core/core-p.h"
#include "private.h"
#include "linphone/wrapper_utils.h"
@ -100,6 +103,7 @@ void linphone_core_notify_call_encryption_changed(LinphoneCore *lc, LinphoneCall
}
void linphone_core_notify_registration_state_changed(LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState cstate, const char *message){
L_GET_PRIVATE_FROM_C_OBJECT(lc)->notifyRegistrationStateChanged(cfg, cstate, message);
NOTIFY_IF_EXIST(registration_state_changed, lc,cfg,cstate,message);
cleanup_dead_vtable_refs(lc);
}
@ -239,6 +243,7 @@ void linphone_core_notify_configuring_status(LinphoneCore *lc, LinphoneConfiguri
}
void linphone_core_notify_network_reachable(LinphoneCore *lc, bool_t reachable) {
L_GET_PRIVATE_FROM_C_OBJECT(lc)->notifyNetworkReachable(!!reachable);
NOTIFY_IF_EXIST(network_reachable, lc,reachable);
cleanup_dead_vtable_refs(lc);
}

View file

@ -94,6 +94,7 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES
content/file-content.h
content/file-transfer-content.h
core/core-accessor.h
core/core-listener.h
core/core-p.h
core/core.h
core/paths/paths.h

View file

@ -319,188 +319,15 @@ int linphone_call_start_invite (LinphoneCall *call, const LinphoneAddress *desti
return 0;
}
void linphone_call_replace_op (LinphoneCall *call, LinphonePrivate::SalOp *op) {
#if 0
SalOp *oldop = call->op;
LinphoneCallState oldstate = linphone_call_get_state(call);
call->op = op;
sal_op_set_user_pointer(call->op, call);
sal_call_set_local_media_description(call->op, call->localdesc);
switch (linphone_call_get_state(call)) {
case LinphoneCallIncomingEarlyMedia:
case LinphoneCallIncomingReceived:
sal_call_notify_ringing(call->op, (linphone_call_get_state(call) == LinphoneCallIncomingEarlyMedia) ? TRUE : FALSE);
break;
case LinphoneCallConnected:
case LinphoneCallStreamsRunning:
sal_call_accept(call->op);
break;
default:
ms_warning("linphone_call_replace_op(): don't know what to do in state [%s]", linphone_call_state_to_string(call->state));
break;
}
switch (oldstate) {
case LinphoneCallIncomingEarlyMedia:
case LinphoneCallIncomingReceived:
sal_op_set_user_pointer(oldop, nullptr); /* To make the call does not get terminated by terminating this op. */
/* Do not terminate a forked INVITE */
if (sal_call_get_replaces(op)) {
sal_call_terminate(oldop);
} else {
sal_op_kill_dialog(oldop);
}
break;
case LinphoneCallConnected:
case LinphoneCallStreamsRunning:
sal_call_terminate(oldop);
sal_op_kill_dialog(oldop);
break;
default:
break;
}
sal_op_release(oldop);
#endif
}
// =============================================================================
// Private functions.
// =============================================================================
#if 0
static void linphone_call_repair_by_invite_with_replaces (LinphoneCall *call) {
const char *call_id = sal_op_get_call_id(call->op);
const char *from_tag = sal_call_get_local_tag(call->op);
const char *to_tag = sal_call_get_remote_tag(call->op);
sal_op_kill_dialog(call->op);
linphone_call_create_op(call);
sal_call_set_replaces(call->op, call_id, from_tag, to_tag);
linphone_call_start_invite(call, nullptr);
}
#endif
MediaStream *linphone_call_get_stream (LinphoneCall *call, LinphoneStreamType type) {
return L_GET_PRIVATE_FROM_C_OBJECT(call)->getMediaStream(type);
}
void linphone_call_set_broken (LinphoneCall *call) {
#if 0
switch(call->state){
/*for all the early states, we prefer to drop the call*/
case LinphoneCallOutgoingInit:
case LinphoneCallOutgoingProgress:
case LinphoneCallOutgoingRinging:
case LinphoneCallOutgoingEarlyMedia:
case LinphoneCallIncomingReceived:
case LinphoneCallIncomingEarlyMedia:
/*during the early states, the SAL layer reports the failure from the dialog or transaction layer,
* hence, there is nothing special to do*/
//break;
case LinphoneCallStreamsRunning:
case LinphoneCallUpdating:
case LinphoneCallPausing:
case LinphoneCallResuming:
case LinphoneCallPaused:
case LinphoneCallPausedByRemote:
case LinphoneCallUpdatedByRemote:
/*during these states, the dialog is established. A failure of a transaction is not expected to close it.
* Instead we have to repair the dialog by sending a reINVITE*/
call->broken = TRUE;
call->need_localip_refresh = TRUE;
break;
default:
ms_error("linphone_call_set_broken() unimplemented case.");
break;
}
#endif
}
void linphone_call_reinvite_to_recover_from_connection_loss (LinphoneCall *call) {
#if 0
LinphoneCallParams *params;
ms_message("LinphoneCall[%p] is going to be updated (reINVITE) in order to recover from lost connectivity", call);
if (call->ice_session){
ice_session_reset(call->ice_session, IR_Controlling);
}
params = linphone_core_create_call_params(call->core, call);
linphone_call_update(call, params);
linphone_call_params_unref(params);
#endif
}
void linphone_call_repair_if_broken (LinphoneCall *call) {
#if 0
SalErrorInfo sei;
if (!call->broken) return;
if (!call->core->media_network_reachable) return;
memset(&sei, 0, sizeof(sei));
/*Make sure that the proxy from which we received this call, or to which we routed this call is registered first*/
if (call->dest_proxy){
/*in all other cases, ie no proxy config, or a proxy config for which no registration was requested, we can start the
* call repair immediately.*/
if (linphone_proxy_config_register_enabled(call->dest_proxy)
&& linphone_proxy_config_get_state(call->dest_proxy) != LinphoneRegistrationOk) return;
}
switch (call->state){
case LinphoneCallUpdating:
case LinphoneCallPausing:
if (sal_call_dialog_request_pending(call->op)) {
/* Need to cancel first re-INVITE as described in section 5.5 of RFC 6141 */
sal_call_cancel_invite(call->op);
call->reinvite_on_cancel_response_requested = TRUE;
}
break;
case LinphoneCallStreamsRunning:
case LinphoneCallPaused:
case LinphoneCallPausedByRemote:
if (!sal_call_dialog_request_pending(call->op)) {
linphone_call_reinvite_to_recover_from_connection_loss(call);
}
break;
case LinphoneCallUpdatedByRemote:
if (sal_call_dialog_request_pending(call->op)) {
sal_error_info_set(&sei, SalReasonServiceUnavailable,"SIP", 0, nullptr, nullptr);
sal_call_decline_with_error_info(call->op, &sei,nullptr);
}
linphone_call_reinvite_to_recover_from_connection_loss(call);
break;
case LinphoneCallOutgoingInit:
case LinphoneCallOutgoingProgress:
sal_call_cancel_invite(call->op);
call->reinvite_on_cancel_response_requested = TRUE;
break;
case LinphoneCallOutgoingEarlyMedia:
case LinphoneCallOutgoingRinging:
linphone_call_repair_by_invite_with_replaces(call);
break;
case LinphoneCallIncomingEarlyMedia:
case LinphoneCallIncomingReceived:
/* Keep the call broken until a forked INVITE is received from the server. */
break;
default:
ms_warning("linphone_call_repair_if_broken(): don't know what to do in state [%s]", linphone_call_state_to_string(call->state));
call->broken = FALSE;
break;
}
sal_error_info_reset(&sei);
#endif
}
void linphone_call_refresh_sockets (LinphoneCall *call) {
#if 0
int i;
for (i=0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; ++i){
MSMediaStreamSessions *mss = &call->sessions[i];
if (mss->rtp_session){
rtp_session_refresh_sockets(mss->rtp_session);
}
}
#endif
}
LinphonePrivate::SalCallOp * linphone_call_get_op (const LinphoneCall *call) {
return L_GET_PRIVATE_FROM_C_OBJECT(call)->getOp();
}

View file

@ -29,7 +29,7 @@
LINPHONE_BEGIN_NAMESPACE
class CallSessionPrivate : public ObjectPrivate {
class CallSessionPrivate : public ObjectPrivate, public CoreListener {
public:
CallSessionPrivate () = default;
@ -43,16 +43,19 @@ public:
CallSessionParams *getCurrentParams () const { return currentParams; }
LinphoneProxyConfig * getDestProxy () const { return destProxy; }
SalCallOp * getOp () const { return op; }
bool isBroken () const { return broken; }
void setParams (CallSessionParams *csp);
virtual void abort (const std::string &errorMsg);
virtual void accepted ();
void ackBeingSent (LinphoneHeaders *headers);
virtual void ackReceived (LinphoneHeaders *headers);
void cancelDone ();
virtual bool failure ();
void infoReceived (SalBodyHandler *bodyHandler);
void pingReply ();
virtual void remoteRinging ();
void replaceOp (SalCallOp *newOp);
virtual void terminated ();
void updated (bool isUpdate);
void updatedByRemote ();
@ -77,6 +80,10 @@ protected:
void setContactOp ();
// CoreListener
void onNetworkReachable (bool reachable) override;
void onRegistrationStateChanged (LinphoneProxyConfig *cfg, LinphoneRegistrationState cstate, const std::string &message) override;
private:
void completeLog ();
void createOp ();
@ -84,6 +91,10 @@ private:
LinphoneAddress * getFixedContact () const;
virtual void reinviteToRecoverFromConnectionLoss ();
void repairByInviteWithReplaces ();
void repairIfBroken ();
protected:
CallSessionListener *listener = nullptr;
@ -107,9 +118,12 @@ protected:
bool pingReplied = false;
int pingTime = 0;
bool broken = false;
bool deferIncomingNotification = false;
bool deferUpdate = false;
bool needLocalIpRefresh = false;
bool nonOpError = false; /* Set when the LinphoneErrorInfo was set at higher level than sal */
bool reinviteOnCancelResponseRequested = false;
private:
L_DECLARE_PUBLIC(CallSession);

View file

@ -26,7 +26,7 @@
#include "conference/params/call-session-params-p.h"
#include "conference/session/call-session-p.h"
#include "conference/session/call-session.h"
#include "core/core.h"
#include "core/core-p.h"
#include "logger/logger.h"
@ -241,6 +241,13 @@ void CallSessionPrivate::ackReceived (LinphoneHeaders *headers) {
listener->onAckReceived(q->getSharedFromThis(), headers);
}
void CallSessionPrivate::cancelDone () {
if (reinviteOnCancelResponseRequested) {
reinviteOnCancelResponseRequested = false;
reinviteToRecoverFromConnectionLoss();
}
}
bool CallSessionPrivate::failure () {
L_Q();
const SalErrorInfo *ei = op->get_error_info();
@ -338,6 +345,47 @@ void CallSessionPrivate::remoteRinging () {
setState(LinphoneCallOutgoingRinging, "Remote ringing");
}
void CallSessionPrivate::replaceOp (SalCallOp *newOp) {
L_Q();
SalCallOp *oldOp = op;
LinphoneCallState oldState = state;
op = newOp;
op->set_user_pointer(q);
op->set_local_media_description(oldOp->get_local_media_description());
switch (state) {
case LinphoneCallIncomingEarlyMedia:
case LinphoneCallIncomingReceived:
op->notify_ringing((state == LinphoneCallIncomingEarlyMedia) ? true : false);
break;
case LinphoneCallConnected:
case LinphoneCallStreamsRunning:
op->accept();
break;
default:
lWarning() << "CallSessionPrivate::replaceOp(): don't know what to do in state [" << linphone_call_state_to_string(state) << "]";
break;
}
switch (oldState) {
case LinphoneCallIncomingEarlyMedia:
case LinphoneCallIncomingReceived:
op->set_user_pointer(nullptr); // In order for the call session to not get terminated by terminating this op
// Do not terminate a forked INVITE
if (op->get_replaces())
oldOp->terminate();
else
oldOp->kill_dialog();
break;
case LinphoneCallConnected:
case LinphoneCallStreamsRunning:
oldOp->terminate();
oldOp->kill_dialog();
break;
default:
break;
}
oldOp->release();
}
void CallSessionPrivate::terminated () {
switch (state) {
case LinphoneCallEnd:
@ -640,6 +688,45 @@ void CallSessionPrivate::setContactOp () {
// -----------------------------------------------------------------------------
void CallSessionPrivate::onNetworkReachable (bool reachable) {
if (reachable) {
repairIfBroken();
} else {
switch(state) {
// For all the early states, we prefer to drop the call
case LinphoneCallOutgoingInit:
case LinphoneCallOutgoingProgress:
case LinphoneCallOutgoingRinging:
case LinphoneCallOutgoingEarlyMedia:
case LinphoneCallIncomingReceived:
case LinphoneCallIncomingEarlyMedia:
// During the early states, the SAL layer reports the failure from the dialog or transaction layer,
// hence, there is nothing special to do
case LinphoneCallStreamsRunning:
case LinphoneCallUpdating:
case LinphoneCallPausing:
case LinphoneCallResuming:
case LinphoneCallPaused:
case LinphoneCallPausedByRemote:
case LinphoneCallUpdatedByRemote:
// During these states, the dialog is established. A failure of a transaction is not expected to close it.
// Instead we have to repair the dialog by sending a reINVITE
broken = true;
needLocalIpRefresh = true;
break;
default:
lError() << "CallSessionPrivate::onNetworkReachable(): unimplemented case";
break;
}
}
}
void CallSessionPrivate::onRegistrationStateChanged (LinphoneProxyConfig *cfg, LinphoneRegistrationState cstate, const std::string &message) {
repairIfBroken();
}
// -----------------------------------------------------------------------------
void CallSessionPrivate::completeLog () {
L_Q();
log->duration = computeDuration(); /* Store duration since connected */
@ -699,11 +786,96 @@ LinphoneAddress * CallSessionPrivate::getFixedContact () const {
return result;
}
// -----------------------------------------------------------------------------
void CallSessionPrivate::reinviteToRecoverFromConnectionLoss () {
L_Q();
lInfo() << "CallSession [" << q << "] is going to be updated (reINVITE) in order to recover from lost connectivity";
q->update(params);
}
void CallSessionPrivate::repairByInviteWithReplaces () {
L_Q();
const char *callId = op->get_call_id();
const char *fromTag = op->get_local_tag();
const char *toTag = op->get_remote_tag();
op->kill_dialog();
createOp();
op->set_replaces(callId, fromTag, toTag);
q->startInvite(nullptr);
}
void CallSessionPrivate::repairIfBroken () {
L_Q();
LinphoneCore *lc = q->getCore()->getCCore();
LinphoneConfig *config = linphone_core_get_config(lc);
if (!lp_config_get_int(config, "sip", "repair_broken_calls", 1) || !lc->media_network_reachable || !broken)
return;
// If we are registered and this session has been broken due to a past network disconnection,
// attempt to repair it
// Make sure that the proxy from which we received this call, or to which we routed this call is registered first
if (destProxy) {
// In all other cases, ie no proxy config, or a proxy config for which no registration was requested,
// we can start the call session repair immediately.
if (linphone_proxy_config_register_enabled(destProxy)
&& (linphone_proxy_config_get_state(destProxy) != LinphoneRegistrationOk))
return;
}
SalErrorInfo sei;
memset(&sei, 0, sizeof(sei));
switch (state) {
case LinphoneCallUpdating:
case LinphoneCallPausing:
if (op->dialog_request_pending()) {
// Need to cancel first re-INVITE as described in section 5.5 of RFC 6141
op->cancel_invite();
reinviteOnCancelResponseRequested = true;
}
break;
case LinphoneCallStreamsRunning:
case LinphoneCallPaused:
case LinphoneCallPausedByRemote:
if (!op->dialog_request_pending())
reinviteToRecoverFromConnectionLoss();
break;
case LinphoneCallUpdatedByRemote:
if (op->dialog_request_pending()) {
sal_error_info_set(&sei, SalReasonServiceUnavailable, "SIP", 0, nullptr, nullptr);
op->decline_with_error_info(&sei, nullptr);
}
reinviteToRecoverFromConnectionLoss();
break;
case LinphoneCallOutgoingInit:
case LinphoneCallOutgoingProgress:
op->cancel_invite();
reinviteOnCancelResponseRequested = true;
break;
case LinphoneCallOutgoingEarlyMedia:
case LinphoneCallOutgoingRinging:
repairByInviteWithReplaces();
break;
case LinphoneCallIncomingEarlyMedia:
case LinphoneCallIncomingReceived:
// Keep the call broken until a forked INVITE is received from the server
break;
default:
lWarning() << "CallSessionPrivate::repairIfBroken: don't know what to do in state ["
<< linphone_call_state_to_string(state);
broken = false;
break;
}
sal_error_info_reset(&sei);
}
// =============================================================================
CallSession::CallSession (const shared_ptr<Core> &core, const CallSessionParams *params, CallSessionListener *listener)
: Object(*new CallSessionPrivate), CoreAccessor(core) {
L_D();
getCore()->getPrivate()->registerListener(d);
d->listener = listener;
if (params)
d->setParams(new CallSessionParams(*params));
@ -713,11 +885,13 @@ CallSession::CallSession (const shared_ptr<Core> &core, const CallSessionParams
CallSession::CallSession (CallSessionPrivate &p, const shared_ptr<Core> &core) : Object(p), CoreAccessor(core) {
L_D();
getCore()->getPrivate()->registerListener(d);
d->init();
}
CallSession::~CallSession () {
L_D();
getCore()->getPrivate()->unregisterListener(d);
if (d->currentParams)
delete d->currentParams;
if (d->params)

View file

@ -25,6 +25,7 @@
#include "conference/conference.h"
#include "conference/params/call-session-params.h"
#include "conference/session/call-session-listener.h"
#include "core/core-listener.h"
#include "sal/call-op.h"
// =============================================================================
@ -41,6 +42,7 @@ class LINPHONE_PUBLIC CallSession : public Object, public CoreAccessor {
friend class ClientGroupChatRoom;
friend class ClientGroupChatRoomPrivate;
friend class Conference;
friend class CorePrivate;
friend class ServerGroupChatRoom;
friend class ServerGroupChatRoomPrivate;

View file

@ -87,6 +87,9 @@ public:
SalCallOp * getOp () const { return op; }
void setAudioMuted (bool value) { audioMuted = value; }
// CoreListener
void onNetworkReachable (bool reachable) override;
private:
static OrtpJitterBufferAlgorithm jitterBufferNameToAlgo (const std::string &name);
@ -235,6 +238,9 @@ private:
void accept (const MediaSessionParams *params);
LinphoneStatus acceptUpdate (const CallSessionParams *csp, LinphoneCallState nextState, const std::string &stateInfo) override;
void refreshSockets ();
void reinviteToRecoverFromConnectionLoss () override;
#ifdef VIDEO_ENABLED
void videoStreamEventCb (const MSFilter *f, const unsigned int eventId, const void *args);
#endif // ifdef VIDEO_ENABLED

View file

@ -539,6 +539,18 @@ int MediaSessionPrivate::getStreamIndex (MediaStream *ms) const {
// -----------------------------------------------------------------------------
void MediaSessionPrivate::onNetworkReachable (bool reachable) {
L_Q();
if (reachable) {
LinphoneConfig *config = linphone_core_get_config(q->getCore()->getCCore());
if (lp_config_get_int(config, "net", "recreate_sockets_when_network_is_up", 0))
refreshSockets();
}
CallSessionPrivate::onNetworkReachable(reachable);
}
// -----------------------------------------------------------------------------
OrtpJitterBufferAlgorithm MediaSessionPrivate::jitterBufferNameToAlgo (const string &name) {
if (name == "basic") return OrtpJitterBufferBasic;
if (name == "rls") return OrtpJitterBufferRecursiveLeastSquare;
@ -3693,9 +3705,7 @@ LinphoneStatus MediaSessionPrivate::pause () {
lError() << "No reason to pause this call, it is already paused or inactive";
return -1;
}
#if 0
call->broken = FALSE;
#endif
broken = false;
setState(LinphoneCallPausing, "Pausing call");
makeLocalMediaDescription();
op->set_local_media_description(localDesc);
@ -3945,6 +3955,24 @@ LinphoneStatus MediaSessionPrivate::acceptUpdate (const CallSessionParams *csp,
// -----------------------------------------------------------------------------
void MediaSessionPrivate::refreshSockets () {
for (int i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) {
MSMediaStreamSessions *mss = &sessions[i];
if (mss->rtp_session)
rtp_session_refresh_sockets(mss->rtp_session);
}
}
void MediaSessionPrivate::reinviteToRecoverFromConnectionLoss () {
L_Q();
lInfo() << "MediaSession [" << q << "] is going to be updated (reINVITE) in order to recover from lost connectivity";
if (iceAgent->hasSession())
iceAgent->resetSession(IR_Controlling);
q->update(getParams());
}
// -----------------------------------------------------------------------------
#ifdef VIDEO_ENABLED
void MediaSessionPrivate::videoStreamEventCb (const MSFilter *f, const unsigned int eventId, const void *args) {
L_Q();
@ -4261,9 +4289,7 @@ LinphoneStatus MediaSession::resume () {
lInfo() << "Resuming MediaSession " << this;
}
d->automaticallyPaused = false;
#if 0
call->broken = FALSE;
#endif
d->broken = false;
/* Stop playing music immediately. If remote side is a conference it
* prevents the participants to hear it while the 200OK comes back. */
if (d->audioStream)
@ -4389,9 +4415,7 @@ LinphoneStatus MediaSession::update (const MediaSessionParams *msp, const string
lWarning() << "CallSession::update() is given the current params, this is probably not what you intend to do!";
d->iceAgent->checkSession(IR_Controlling, true);
if (msp) {
#if 0
call->broken = FALSE;
#endif
d->broken = false;
d->setState(nextState, "Updating call");
d->setParams(new MediaSessionParams(*msp));
if (d->iceAgent->prepare(d->localDesc, false)) {

View file

@ -21,6 +21,7 @@
#include "core-p.h"
#include "call/call-p.h"
#include "conference/session/call-session-p.h"
#include "logger/logger.h"
// TODO: Remove me later.
@ -44,6 +45,35 @@ int CorePrivate::addCall (const shared_ptr<Call> &call) {
return 0;
}
bool CorePrivate::canWeAddCall () const {
L_Q();
if (q->getCallCount() < static_cast<unsigned int>(q->getCCore()->max_calls))
return true;
lInfo() << "Maximum amount of simultaneous calls reached!";
return false;
}
bool CorePrivate::inviteReplacesABrokenCall (SalCallOp *op) {
CallSession *replacedSession = nullptr;
SalCallOp *replacedOp = op->get_replaces();
if (replacedOp)
replacedSession = reinterpret_cast<CallSession *>(replacedOp->get_user_pointer());
for (const auto &call : calls) {
shared_ptr<CallSession> session = call->getPrivate()->getActiveSession();
if (session
&& ((session->getPrivate()->isBroken() && op->compare_op(session->getPrivate()->getOp()))
|| ((replacedSession == session.get())
&& (strcmp(op->get_from(), replacedOp->get_from()) == 0)
&& (strcmp(op->get_to(), replacedOp->get_to()) == 0)))
) {
session->getPrivate()->replaceOp(op);
return true;
}
}
return false;
}
bool CorePrivate::isAlreadyInCallWithAddress (const Address &addr) const {
for (const auto &call : calls) {
if (call->getRemoteAddress().weakEqual(addr))
@ -58,14 +88,6 @@ void CorePrivate::iterateCalls (time_t currentRealTime, bool oneSecondElapsed) c
}
}
bool CorePrivate::canWeAddCall () const {
L_Q();
if (q->getCallCount() < static_cast<unsigned int>(q->getCCore()->max_calls))
return true;
lInfo() << "Maximum amount of simultaneous calls reached!";
return false;
}
void CorePrivate::notifySoundcardUsage (bool used) {
L_Q();
MSSndCard *card = q->getCCore()->sound_conf.capt_sndcard;

39
src/core/core-listener.h Normal file
View file

@ -0,0 +1,39 @@
/*
* core-listener.h
* Copyright (C) 2010-2017 Belledonne Communications SARL
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _CORE_LISTENER_H_
#define _CORE_LISTENER_H_
#include "linphone/types.h"
// =============================================================================
LINPHONE_BEGIN_NAMESPACE
class CoreListener {
public:
virtual ~CoreListener () = default;
virtual void onNetworkReachable (bool reachable) {}
virtual void onRegistrationStateChanged (LinphoneProxyConfig *cfg, LinphoneRegistrationState cstate, const std::string &message) {}
};
LINPHONE_END_NAMESPACE
#endif // ifndef _CORE_LISTENER_H_

View file

@ -23,19 +23,28 @@
#include "core.h"
#include "db/main-db.h"
#include "object/object-p.h"
#include "sal/call-op.h"
// =============================================================================
LINPHONE_BEGIN_NAMESPACE
class CoreListener;
class CorePrivate : public ObjectPrivate {
public:
void init();
void uninit();
void init ();
void registerListener (CoreListener *listener);
void unregisterListener (CoreListener *listener);
void uninit ();
void notifyNetworkReachable (bool reachable);
void notifyRegistrationStateChanged (LinphoneProxyConfig *cfg, LinphoneRegistrationState state, const std::string &message);
int addCall (const std::shared_ptr<Call> &call);
bool canWeAddCall () const;
bool hasCalls () const { return !calls.empty(); }
bool inviteReplacesABrokenCall (SalCallOp *op);
bool isAlreadyInCallWithAddress (const Address &addr) const;
void iterateCalls (time_t currentRealTime, bool oneSecondElapsed) const;
void notifySoundcardUsage (bool used);
@ -50,6 +59,8 @@ public:
std::unique_ptr<MainDb> mainDb;
private:
std::list<CoreListener *> listeners;
std::list<std::shared_ptr<Call>> calls;
std::shared_ptr<Call> currentCall;

View file

@ -20,7 +20,8 @@
#include <mediastreamer2/mscommon.h>
#include "call/call.h"
#include "core-p.h"
#include "core/core-listener.h"
#include "core/core-p.h"
#include "logger/logger.h"
#include "paths/paths.h"
@ -59,6 +60,14 @@ void CorePrivate::init () {
insertChatRoom(chatRoom);
}
void CorePrivate::registerListener (CoreListener *listener) {
listeners.push_back(listener);
}
void CorePrivate::unregisterListener (CoreListener *listener) {
listeners.remove(listener);
}
void CorePrivate::uninit () {
L_Q();
while (!calls.empty()) {
@ -68,6 +77,18 @@ void CorePrivate::uninit () {
}
}
// -----------------------------------------------------------------------------
void CorePrivate::notifyNetworkReachable (bool reachable) {
for (const auto &listener : listeners)
listener->onNetworkReachable(reachable);
}
void CorePrivate::notifyRegistrationStateChanged (LinphoneProxyConfig *cfg, LinphoneRegistrationState state, const string &message) {
for (const auto &listener : listeners)
listener->onRegistrationStateChanged(cfg, state, message);
}
// =============================================================================
Core::Core () : Object(*new CorePrivate) {}

View file

@ -41,6 +41,7 @@ class IdentityAddress;
class LINPHONE_PUBLIC Core : public Object {
friend class CallPrivate;
friend class CallSession;
friend class ChatMessagePrivate;
friend class ChatRoom;
friend class ChatRoomPrivate;

View file

@ -177,6 +177,12 @@ void IceAgent::prepareIceForStream (MediaStream *ms, bool createChecklist) {
media_stream_set_ice_check_list(ms, cl);
}
void IceAgent::resetSession (IceRole role) {
if (!iceSession)
return;
ice_session_reset(iceSession, role);
}
void IceAgent::restartSession (IceRole role) {
if (!iceSession)
return;

View file

@ -59,6 +59,7 @@ public:
bool isControlling () const;
bool prepare (const SalMediaDescription *localDesc, bool incomingOffer);
void prepareIceForStream (MediaStream *ms, bool createChecklist);
void resetSession (IceRole role);
void restartSession (IceRole role);
void startConnectivityChecks ();
void stopIceForInactiveStreams (SalMediaDescription *desc);

View file

@ -30,6 +30,7 @@ public:
SalCallOp(Sal *sal): SalOp(sal) {}
~SalCallOp() override;
SalMediaDescription *get_local_media_description () const { return local_media; }
int set_local_media_description(SalMediaDescription *desc);
int set_local_body(const Content &body);
int set_local_body(const Content &&body);