diff --git a/src/state/CallViewModel/localMember/Publisher.test.ts b/src/state/CallViewModel/localMember/Publisher.test.ts index 384ecff0..941b5956 100644 --- a/src/state/CallViewModel/localMember/Publisher.test.ts +++ b/src/state/CallViewModel/localMember/Publisher.test.ts @@ -149,9 +149,7 @@ describe("Publisher", () => { }); }); - describe("Bug fix", () => { - // There is a race condition when creating and publishing tracks while the mute state changes. // This race condition could cause tracks to be published even though they are muted at the // beginning of a call coming from lobby. @@ -162,7 +160,7 @@ describe("Bug fix", () => { // If in the middle of that process the mute state changes: // - the `setMicrophoneEnabled` will be no-op because it is not aware of our created track and can't see any pending publication // - If start publication is requested it will publish the track even though there was a mute request. - it.fails("wrongly publish tracks while muted", async () => { + it("wrongly publish tracks while muted", async () => { const audioEnabled$ = new BehaviorSubject(true); const muteStates = { audio: { diff --git a/src/state/CallViewModel/localMember/Publisher.ts b/src/state/CallViewModel/localMember/Publisher.ts index 326dedaf..6a1c5909 100644 --- a/src/state/CallViewModel/localMember/Publisher.ts +++ b/src/state/CallViewModel/localMember/Publisher.ts @@ -144,6 +144,7 @@ export class Publisher { this.logger.error("Failed to create tracks", error); }); } + // TODO why throw here? should we just do nothing? throw Error("audio and video is false"); } @@ -184,16 +185,32 @@ export class Publisher { for (const track of this.tracks$.value) { this.logger.info("publish ", this.tracks$.value.length, "tracks"); - // TODO: handle errors? Needs the signaling connection to be up, but it has some retries internally - // with a timeout. - await lkRoom.localParticipant.publishTrack(track).catch((error) => { - this.logger.error("Failed to publish track", error); - throw new FailToStartLivekitConnection( - error instanceof Error ? error.message : error, - ); - }); - this.logger.info("published track ", track.kind, track.id); + // XXXX: Patch: Check if the track has been muted manually before publishing + // This is only a patch, the proper way would be to use livekit high-level enabled/disabled APIs + // or only use the low level create/publish APIs and have our own pending publication protection. + // Maybe we could change the livekit api to pre-load tracks without publishing them yet? + // Are we sure this is needed at all? What are the gains? + const isEnabled = + track.kind === Track.Kind.Audio + ? this.muteStates.audio.enabled$.value + : this.muteStates.video.enabled$.value; + + if (!isEnabled) { + // TODO should we also drop it? + // I believe the high-level LiveKit APIs will recreate a track? + await track.mute(); + } else { + // TODO: handle errors? Needs the signaling connection to be up, but it has some retries internally + // with a timeout. + await lkRoom.localParticipant.publishTrack(track).catch((error) => { + this.logger.error("Failed to publish track", error); + throw new FailToStartLivekitConnection( + error instanceof Error ? error.message : error, + ); + }); + this.logger.info("published track ", track.kind, track.id); + } // TODO: check if the connection is still active? and break the loop if not? } this._publishing$.next(true);