Skip to content

Commit

Permalink
Fixed some scenarios where an answered call keeps ringing.
Browse files Browse the repository at this point in the history
- Avoid updating the state of an ended call
- Invalidate the expiration timer once the call has been answered or declined elsewhere
  • Loading branch information
nimau committed Feb 3, 2023
1 parent fef497b commit 54c717f
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 39 deletions.
99 changes: 60 additions & 39 deletions MatrixSDK/VoIP/MXCall.m
Original file line number Diff line number Diff line change
Expand Up @@ -835,13 +835,7 @@ - (void)setState:(MXCallState)state reason:(MXEvent *)event
else if (MXCallStateInviteSent == state)
{
// Start the life expiration timer for the sent invitation
inviteExpirationTimer = [[NSTimer alloc] initWithFireDate:[NSDate dateWithTimeIntervalSinceNow:callManager.inviteLifetime / 1000]
interval:0
target:self
selector:@selector(expireCallInvite)
userInfo:nil
repeats:NO];
[[NSRunLoop mainRunLoop] addTimer:inviteExpirationTimer forMode:NSDefaultRunLoopMode];
[self startInviteExpirationTimer];
}

_state = state;
Expand Down Expand Up @@ -1180,17 +1174,35 @@ - (void)handleCallInvite:(MXEvent *)event
[self didEncounterError:error reason:MXCallHangupReasonUserMediaFailed];
}];

// Start expiration timer
self->inviteExpirationTimer = [[NSTimer alloc] initWithFireDate:[NSDate dateWithTimeIntervalSinceNow:self->callInviteEventContent.lifetime / 1000]
interval:0
target:self
selector:@selector(expireCallInvite)
userInfo:nil
repeats:NO];
[[NSRunLoop mainRunLoop] addTimer:self->inviteExpirationTimer forMode:NSDefaultRunLoopMode];
// Start an expiration timer
[self startInviteExpirationTimer];
}];
}

- (void)startInviteExpirationTimer {
if (inviteExpirationTimer)
{
return;
}

// Start expiration timer
inviteExpirationTimer = [[NSTimer alloc] initWithFireDate:[NSDate dateWithTimeIntervalSinceNow:callInviteEventContent.lifetime / 1000]
interval:0
target:self
selector:@selector(expireCallInvite)
userInfo:nil
repeats:NO];
[[NSRunLoop mainRunLoop] addTimer:inviteExpirationTimer forMode:NSDefaultRunLoopMode];
}

- (void)invalidateInviteExpirationTimer {
if (inviteExpirationTimer)
{
[inviteExpirationTimer invalidate];
inviteExpirationTimer = nil;
}
}

- (void)handleCallAnswer:(MXEvent *)event
{
MXLogDebug(@"[MXCall][%@] handleCallAnswer", _callId)
Expand All @@ -1200,6 +1212,12 @@ - (void)handleCallAnswer:(MXEvent *)event
return;
}

if (_state == MXCallStateEnded) {
// this call is already ended
MXLogDebug(@"[MXCall][%@] handleCallAnswer: this call is already ended", _callId);
return;
}

// Listen to answer event only for call we are making, not receiving
if (!_isIncoming)
{
Expand All @@ -1213,11 +1231,7 @@ - (void)handleCallAnswer:(MXEvent *)event
MXCallAnswerEventContent *content = [MXCallAnswerEventContent modelFromJSON:event.content];

// The peer accepted our outgoing call
if (inviteExpirationTimer)
{
[inviteExpirationTimer invalidate];
inviteExpirationTimer = nil;
}
[self invalidateInviteExpirationTimer];

// mark this as the selected one
self.selectedAnswer = event;
Expand Down Expand Up @@ -1287,6 +1301,12 @@ - (void)handleCallSelectAnswer:(MXEvent *)event
return;
}

if (_state == MXCallStateEnded) {
// this call is already ended
MXLogDebug(@"[MXCall][%@] handleCallAnswer: this call is already ended", _callId);
return;
}

if (_isIncoming)
{
MXCallSelectAnswerEventContent *content = [MXCallSelectAnswerEventContent modelFromJSON:event.content];
Expand Down Expand Up @@ -1353,11 +1373,7 @@ - (void)handleCallReject:(MXEvent *)event
}

// The peer rejected our outgoing call
if (inviteExpirationTimer)
{
[inviteExpirationTimer invalidate];
inviteExpirationTimer = nil;
}
[self invalidateInviteExpirationTimer];

if (_state != MXCallStateEnded)
{
Expand Down Expand Up @@ -1598,11 +1614,7 @@ - (NSString *)description

- (void)terminateWithReason:(MXEvent *)event
{
if (inviteExpirationTimer)
{
[inviteExpirationTimer invalidate];
inviteExpirationTimer = nil;
}
[self invalidateInviteExpirationTimer];

// Do not refresh TURN servers config anymore
[localIceGatheringTimer invalidate];
Expand Down Expand Up @@ -1711,14 +1723,17 @@ - (void)expireCallInvite
[callStackCall end];
}

// Send the notif that the call expired to the app
[self setState:MXCallStateInviteExpired reason:nil];

// Set appropriate call end reason
_endReason = MXCallEndReasonMissed;

// And set the final state: MXCallStateEnded
[self setState:MXCallStateEnded reason:nil];
// If the call is not aleady ended
if (_state != MXCallStateEnded) {
// Send the notif that the call expired to the app
[self setState:MXCallStateInviteExpired reason:nil];

// Set appropriate call end reason
_endReason = MXCallEndReasonMissed;

// And set the final state: MXCallStateEnded
[self setState:MXCallStateEnded reason:nil];
}

// The call manager can now ignore this call
[callManager removeCall:self];
Expand All @@ -1729,6 +1744,9 @@ - (void)onCallAnsweredElsewhere
{
MXLogDebug(@"[MXCall][%@] onCallAnsweredElsewhere", _callId)

// The call has been accepted elsewhere
[self invalidateInviteExpirationTimer];

// Send the notif that the call has been answered from another device to the app
[self setState:MXCallStateAnsweredElseWhere reason:nil];

Expand All @@ -1746,7 +1764,10 @@ - (void)onCallDeclinedElsewhere
{
MXLogDebug(@"[MXCall][%@] onCallDeclinedElsewhere", _callId)

// Send the notif that the call has been answered from another device to the app
// The call has been declined from another device
[self invalidateInviteExpirationTimer];

// Send the notif that the call has been declined from another device to the app
[self setState:MXCallStateAnsweredElseWhere reason:nil];

// Set appropriate call end reason
Expand Down
1 change: 1 addition & 0 deletions changelog.d/pr-1710.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix some scenarios where an answered call continues to ring

0 comments on commit 54c717f

Please sign in to comment.