Skip to content

Commit 81e68ab

Browse files
authored
Merge pull request #1622 from matrix-org/dbkr/candidate_retries
Better handling of send failures on VoIP events
2 parents 7963bb3 + eafecd3 commit 81e68ab

File tree

1 file changed

+46
-28
lines changed

1 file changed

+46
-28
lines changed

src/webrtc/call.ts

Lines changed: 46 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -886,7 +886,7 @@ export class MatrixCall extends EventEmitter {
886886
// Now we wait for the negotiationneeded event
887887
};
888888

889-
private sendAnswer() {
889+
private async sendAnswer() {
890890
const answerContent = {
891891
answer: {
892892
sdp: this.peerConn.localDescription.sdp,
@@ -908,12 +908,12 @@ export class MatrixCall extends EventEmitter {
908908
logger.info(`Discarding ${this.candidateSendQueue.length} candidates that will be sent in answer`);
909909
this.candidateSendQueue = [];
910910

911-
this.sendVoipEvent(EventType.CallAnswer, answerContent).then(() => {
911+
try {
912+
await this.sendVoipEvent(EventType.CallAnswer, answerContent);
912913
// If this isn't the first time we've tried to send the answer,
913914
// we may have candidates queued up, so send them now.
914915
this.inviteOrAnswerSent = true;
915-
this.sendCandidateQueue();
916-
}).catch((error) => {
916+
} catch (error) {
917917
// We've failed to answer: back to the ringing state
918918
this.setState(CallState.Ringing);
919919
this.client.cancelPendingEvent(error.event);
@@ -926,7 +926,11 @@ export class MatrixCall extends EventEmitter {
926926
}
927927
this.emit(CallEvent.Error, new CallError(code, message, error));
928928
throw error;
929-
});
929+
}
930+
931+
// error handler re-throws so this won't happen on error, but
932+
// we don't want the same error handling on the candidate queue
933+
this.sendCandidateQueue();
930934
}
931935

932936
private gotUserMediaForAnswer = async (stream: MediaStream) => {
@@ -1260,19 +1264,9 @@ export class MatrixCall extends EventEmitter {
12601264

12611265
try {
12621266
await this.sendVoipEvent(eventType, content);
1263-
this.sendCandidateQueue();
1264-
if (this.state === CallState.CreateOffer) {
1265-
this.inviteOrAnswerSent = true;
1266-
this.setState(CallState.InviteSent);
1267-
this.inviteTimeout = setTimeout(() => {
1268-
this.inviteTimeout = null;
1269-
if (this.state === CallState.InviteSent) {
1270-
this.hangup(CallErrorCode.InviteTimeout, false);
1271-
}
1272-
}, CALL_TIMEOUT_MS);
1273-
}
12741267
} catch (error) {
1275-
this.client.cancelPendingEvent(error.event);
1268+
logger.error("Failed to send invite", error);
1269+
if (error.event) this.client.cancelPendingEvent(error.event);
12761270

12771271
let code = CallErrorCode.SignallingFailed;
12781272
let message = "Signalling failed";
@@ -1287,6 +1281,22 @@ export class MatrixCall extends EventEmitter {
12871281

12881282
this.emit(CallEvent.Error, new CallError(code, message, error));
12891283
this.terminate(CallParty.Local, code, false);
1284+
1285+
// no need to carry on & send the candidate queue, but we also
1286+
// don't want to rethrow the error
1287+
return;
1288+
}
1289+
1290+
this.sendCandidateQueue();
1291+
if (this.state === CallState.CreateOffer) {
1292+
this.inviteOrAnswerSent = true;
1293+
this.setState(CallState.InviteSent);
1294+
this.inviteTimeout = setTimeout(() => {
1295+
this.inviteTimeout = null;
1296+
if (this.state === CallState.InviteSent) {
1297+
this.hangup(CallErrorCode.InviteTimeout, false);
1298+
}
1299+
}, CALL_TIMEOUT_MS);
12901300
}
12911301
};
12921302

@@ -1623,7 +1633,7 @@ export class MatrixCall extends EventEmitter {
16231633
}
16241634
}
16251635

1626-
private sendCandidateQueue() {
1636+
private async sendCandidateQueue() {
16271637
if (this.candidateSendQueue.length === 0) {
16281638
return;
16291639
}
@@ -1635,20 +1645,28 @@ export class MatrixCall extends EventEmitter {
16351645
candidates: cands,
16361646
};
16371647
logger.debug("Attempting to send " + cands.length + " candidates");
1638-
this.sendVoipEvent(EventType.CallCandidates, content).then(() => {
1639-
this.candidateSendTries = 0;
1640-
this.sendCandidateQueue();
1641-
}, (error) => {
1642-
for (let i = 0; i < cands.length; i++) {
1643-
this.candidateSendQueue.push(cands[i]);
1644-
}
1648+
try {
1649+
await this.sendVoipEvent(EventType.CallCandidates, content);
1650+
} catch (error) {
1651+
// don't retry this event: we'll send another one later as we might
1652+
// have more candidates by then.
1653+
if (error.event) this.client.cancelPendingEvent(error.event);
1654+
1655+
// put all the candidates we failed to send back in the queue
1656+
this.candidateSendQueue.push(...cands);
16451657

16461658
if (this.candidateSendTries > 5) {
16471659
logger.debug(
16481660
"Failed to send candidates on attempt " + this.candidateSendTries +
1649-
". Giving up for now.", error,
1661+
". Giving up on this call.", error,
16501662
);
1651-
this.candidateSendTries = 0;
1663+
1664+
const code = CallErrorCode.SignallingFailed;
1665+
const message = "Signalling failed";
1666+
1667+
this.emit(CallEvent.Error, new CallError(code, message, error));
1668+
this.hangup(code, false);
1669+
16521670
return;
16531671
}
16541672

@@ -1658,7 +1676,7 @@ export class MatrixCall extends EventEmitter {
16581676
setTimeout(() => {
16591677
this.sendCandidateQueue();
16601678
}, delayMs);
1661-
});
1679+
}
16621680
}
16631681

16641682
private async placeCallWithConstraints(constraints: MediaStreamConstraints) {

0 commit comments

Comments
 (0)