fix(voice): handle multiple transitions simultaneously (#11100)

* fix(voice): handle multiple transitions simultaneously

* fix: fix execute transition return

---------

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
This commit is contained in:
Snazzah
2025-12-12 10:49:37 -05:00
committed by GitHub
parent 5b4dbd541e
commit c4fc79a3cd

View File

@@ -105,9 +105,9 @@ export class DAVESession extends EventEmitter {
public lastTransitionId?: number | undefined;
/**
* The pending transition.
* The pending transitions, mapped by their ID and the protocol version.
*/
private pendingTransition?: VoiceDavePrepareTransitionData | undefined;
private pendingTransitions = new Map<number, number>();
/**
* Whether this session was downgraded previously.
@@ -210,7 +210,7 @@ export class DAVESession extends EventEmitter {
*/
public prepareTransition(data: VoiceDavePrepareTransitionData) {
this.emit('debug', `Preparing for transition (${data.transition_id}, v${data.protocol_version})`);
this.pendingTransition = data;
this.pendingTransitions.set(data.transition_id, data.protocol_version);
// When the included transition id is 0, the transition is for (re)initialization and it can be executed immediately.
if (data.transition_id === 0) {
@@ -230,15 +230,13 @@ export class DAVESession extends EventEmitter {
*/
public executeTransition(transitionId: number) {
this.emit('debug', `Executing transition (${transitionId})`);
if (!this.pendingTransition) {
if (!this.pendingTransitions.has(transitionId)) {
this.emit('debug', `Received execute transition, but we don't have a pending transition for ${transitionId}`);
return;
return false;
}
let transitioned = false;
if (transitionId === this.pendingTransition.transition_id) {
const oldVersion = this.protocolVersion;
this.protocolVersion = this.pendingTransition.protocol_version;
this.protocolVersion = this.pendingTransitions.get(transitionId)!;
// Handle upgrades & defer downgrades
if (oldVersion !== this.protocolVersion && this.protocolVersion === 0) {
@@ -251,19 +249,12 @@ export class DAVESession extends EventEmitter {
}
// In the future we'd want to signal to the DAVESession to transition also, but it only supports v1 at this time
transitioned = true;
this.reinitializing = false;
this.lastTransitionId = transitionId;
this.emit('debug', `Transition executed (v${oldVersion} -> v${this.protocolVersion}, id: ${transitionId})`);
} else {
this.emit(
'debug',
`Received execute transition for an unexpected transition id (expected: ${this.pendingTransition.transition_id}, actual: ${transitionId})`,
);
}
this.pendingTransition = undefined;
return transitioned;
this.pendingTransitions.delete(transitionId);
return true;
}
/**
@@ -328,7 +319,7 @@ export class DAVESession extends EventEmitter {
this.reinitializing = false;
this.lastTransitionId = transitionId;
} else {
this.pendingTransition = { transition_id: transitionId, protocol_version: this.protocolVersion };
this.pendingTransitions.set(transitionId, this.protocolVersion);
}
this.emit('debug', `MLS commit processed (transition id: ${transitionId})`);
@@ -355,7 +346,7 @@ export class DAVESession extends EventEmitter {
this.reinitializing = false;
this.lastTransitionId = transitionId;
} else {
this.pendingTransition = { transition_id: transitionId, protocol_version: this.protocolVersion };
this.pendingTransitions.set(transitionId, this.protocolVersion);
}
this.emit('debug', `MLS welcome processed (transition id: ${transitionId})`);
@@ -392,7 +383,7 @@ export class DAVESession extends EventEmitter {
this.consecutiveFailures = 0;
return buffer;
} catch (error) {
if (!this.reinitializing && !this.pendingTransition) {
if (!this.reinitializing && this.pendingTransitions.size === 0) {
this.consecutiveFailures++;
this.emit('debug', `Failed to decrypt a packet (${this.consecutiveFailures} consecutive fails)`);
if (this.consecutiveFailures > this.failureTolerance) {
@@ -401,11 +392,8 @@ export class DAVESession extends EventEmitter {
}
} else if (this.reinitializing) {
this.emit('debug', 'Failed to decrypt a packet (reinitializing session)');
} else if (this.pendingTransition) {
this.emit(
'debug',
`Failed to decrypt a packet (pending transition ${this.pendingTransition.transition_id} to v${this.pendingTransition.protocol_version})`,
);
} else if (this.pendingTransitions.size > 0) {
this.emit('debug', `Failed to decrypt a packet (${this.pendingTransitions.size} pending transition[s])`);
}
}