From 3d66a425d5bcd5dd55895fdab6585c80bfd7bea5 Mon Sep 17 00:00:00 2001 From: Conroy Whitney Date: Tue, 19 Nov 2024 13:13:29 -0500 Subject: [PATCH 1/2] Catch `InvalidStateError: RTCPeerConnection is closed` exception --- src/room/track/LocalTrack.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/room/track/LocalTrack.ts b/src/room/track/LocalTrack.ts index 25fe029a34..e7162a5b4d 100644 --- a/src/room/track/LocalTrack.ts +++ b/src/room/track/LocalTrack.ts @@ -172,7 +172,17 @@ export default abstract class LocalTrack< } } if (this.sender) { - await this.sender.replaceTrack(processedTrack ?? newTrack); + try { + await this.sender.replaceTrack(processedTrack ?? newTrack); + } catch (e) { + this.log.error('failed to replace track on sender', { + ...this.logContext, + error: e, + newTrack: newTrack, + processedTrack: processedTrack, + sender: this.sender + }); + } } // if `newTrack` is different from the existing track, stop the // older track just before replacing it From 1c7d3154513d6342e7a2e04dbe0b827b63a4abc7 Mon Sep 17 00:00:00 2001 From: Conroy Whitney Date: Tue, 19 Nov 2024 19:48:46 -0500 Subject: [PATCH 2/2] Add additional debug logging around `replaceTrack` --- src/room/track/LocalTrack.ts | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/src/room/track/LocalTrack.ts b/src/room/track/LocalTrack.ts index e7162a5b4d..23e8525b87 100644 --- a/src/room/track/LocalTrack.ts +++ b/src/room/track/LocalTrack.ts @@ -125,6 +125,7 @@ export default abstract class LocalTrack< return; } if (this._mediaStreamTrack) { + this.log.debug('replacing MediaStreamTrack', { ...this.logContext, mediaStreamTrack: this._mediaStreamTrack }); // detach this.attachedElements.forEach((el) => { detachTrack(this._mediaStreamTrack, el); @@ -133,6 +134,8 @@ export default abstract class LocalTrack< this._mediaStreamTrack.removeEventListener('ended', this.handleEnded); this._mediaStreamTrack.removeEventListener('mute', this.handleTrackMuteEvent); this._mediaStreamTrack.removeEventListener('unmute', this.handleTrackUnmuteEvent); + } else { + this.log.debug('setting MediaStreamTrack for the first time', this.logContext); } this.mediaStream = new MediaStream([newTrack]); @@ -172,16 +175,32 @@ export default abstract class LocalTrack< } } if (this.sender) { + const currentTrack = this._mediaStreamTrack; + const replacementTrack = processedTrack ?? newTrack; + const trackLogContext = { + ...this.logContext, + currentTrack, + newTrack, + processedTrack, + replacementTrack, + sender: this.sender + }; + + if (replacementTrack.readyState == "ended") { + this.log.warn('track is ended, not replacing track on sender', trackLogContext); + return; + } + try { - await this.sender.replaceTrack(processedTrack ?? newTrack); - } catch (e) { - this.log.error('failed to replace track on sender', { - ...this.logContext, + await this.sender.replaceTrack(replacementTrack); + this.log.debug('successfully replaced track on sender', trackLogContext); + } catch (e: any) { + const errorMessage = `failed to replace track on sender: ${e.message}`; + this.log.error(errorMessage, { + ...trackLogContext, error: e, - newTrack: newTrack, - processedTrack: processedTrack, - sender: this.sender }); + throw new TrackInvalidError(errorMessage); } } // if `newTrack` is different from the existing track, stop the