diff --git a/src/state/CallViewModel/CallViewModel.ts b/src/state/CallViewModel/CallViewModel.ts index ab45b07c..554060bf 100644 --- a/src/state/CallViewModel/CallViewModel.ts +++ b/src/state/CallViewModel/CallViewModel.ts @@ -527,12 +527,8 @@ export function createCallViewModel$( connectOptions$.value, ); }, - createPublisherFactory: ( - scope: ObservableScope, - connection: Connection, - ) => { + createPublisherFactory: (connection: Connection) => { return new Publisher( - scope, connection, mediaDevices, muteStates, diff --git a/src/state/CallViewModel/localMember/LocalMember.ts b/src/state/CallViewModel/localMember/LocalMember.ts index 6298979f..44b6c63b 100644 --- a/src/state/CallViewModel/localMember/LocalMember.ts +++ b/src/state/CallViewModel/localMember/LocalMember.ts @@ -40,7 +40,7 @@ import { type CallMembershipIdentityParts } from "matrix-js-sdk/lib/matrixrtc/En import { type Behavior } from "../../Behavior.ts"; import { type IConnectionManager } from "../remoteMembers/ConnectionManager.ts"; -import { ObservableScope } from "../../ObservableScope.ts"; +import { type ObservableScope } from "../../ObservableScope.ts"; import { type Publisher } from "./Publisher.ts"; import { type MuteStates } from "../../MuteStates.ts"; import { @@ -124,10 +124,7 @@ interface Props { scope: ObservableScope; muteStates: MuteStates; connectionManager: IConnectionManager; - createPublisherFactory: ( - scope: ObservableScope, - connection: Connection, - ) => Publisher; + createPublisherFactory: (connection: Connection) => Publisher; joinMatrixRTC: (transport: LivekitTransport) => void; homeserverConnected: HomeserverConnected; localTransport$: Behavior; @@ -318,13 +315,12 @@ export const createLocalMembership$ = ({ connection?.transport.livekit_service_url, ); if (connection !== null) { - const scope = new ObservableScope(); - const publisher = createPublisherFactory(scope, connection); + const publisher = createPublisherFactory(connection); publisher$.next(publisher); - // Clean-up callback + // Clean-up callback return Promise.resolve(async (): Promise => { - scope.end(); + await publisher.destroy(); }); } }); diff --git a/src/state/CallViewModel/localMember/LocalTransport.ts b/src/state/CallViewModel/localMember/LocalTransport.ts index 83b9d7c8..7e1c4155 100644 --- a/src/state/CallViewModel/localMember/LocalTransport.ts +++ b/src/state/CallViewModel/localMember/LocalTransport.ts @@ -16,7 +16,6 @@ import { MatrixError, type MatrixClient } from "matrix-js-sdk"; import { combineLatest, distinctUntilChanged, - first, from, map, of, diff --git a/src/state/CallViewModel/localMember/Publisher.ts b/src/state/CallViewModel/localMember/Publisher.ts index 06f40bde..c9c1c08c 100644 --- a/src/state/CallViewModel/localMember/Publisher.ts +++ b/src/state/CallViewModel/localMember/Publisher.ts @@ -32,7 +32,7 @@ import { import { getUrlParams } from "../../../UrlParams.ts"; import { observeTrackReference$ } from "../../MediaViewModel.ts"; import { type Connection } from "../remoteMembers/Connection.ts"; -import { type ObservableScope } from "../../ObservableScope.ts"; +import { ObservableScope } from "../../ObservableScope.ts"; /** * A wrapper for a Connection object. @@ -47,9 +47,10 @@ export class Publisher { */ public shouldPublish = false; + private readonly scope = new ObservableScope(); + /** * Creates a new Publisher. - * @param scope - The observable scope to use for managing the publisher. * @param connection - The connection to use for publishing. * @param devices - The media devices to use for audio and video input. * @param muteStates - The mute states for audio and video. @@ -57,7 +58,6 @@ export class Publisher { * @param logger - The logger to use for logging :D. */ public constructor( - private scope: ObservableScope, private connection: Pick, //setE2EEEnabled, devices: MediaDevices, private readonly muteStates: MuteStates, @@ -65,7 +65,6 @@ export class Publisher { private logger: Logger, ) { const { controlledAudioDevices } = getUrlParams(); - const room = connection.livekitRoom; room.setE2EEEnabled(room.options.e2ee !== undefined)?.catch((e: Error) => { @@ -73,27 +72,11 @@ export class Publisher { }); // Setup track processor syncing (blur) - this.observeTrackProcessors(scope, room, trackerProcessorState$); + this.observeTrackProcessors(this.scope, room, trackerProcessorState$); // Observe media device changes and update LiveKit active devices accordingly - this.observeMediaDevices(scope, devices, controlledAudioDevices); + this.observeMediaDevices(this.scope, devices, controlledAudioDevices); - this.workaroundRestartAudioInputTrackChrome(devices, scope); - this.scope.onEnd(() => { - muteStates.audio.unsetHandler(); - muteStates.video.unsetHandler(); - this.logger.info( - "Scope ended -> unset handler + stop publishing all tracks", - ); - - const stopAllMedia = async () => { - logger.info("onEnd: start stopping all media"); - await this.stopPublishing(); - logger.info("onEnd: stopped publishing"); - await this.stopTracks(); - logger.info("onEnd: stopped tracks"); - }; - void stopAllMedia(); - }); + this.workaroundRestartAudioInputTrackChrome(devices, this.scope); this.connection.livekitRoom.localParticipant.on( ParticipantEvent.LocalTrackPublished, @@ -101,6 +84,21 @@ export class Publisher { ); } + public async destroy(): Promise { + this.scope.end(); + this.logger.info("Scope ended -> unset handler"); + this.muteStates.audio.unsetHandler(); + this.muteStates.video.unsetHandler(); + + this.logger.info(`Start to stop tracks`); + try { + await this.stopTracks(); + this.logger.info(`Done to stop tracks`); + } catch (e) { + this.logger.error(`Failed to stop publishing: ${e}`); + } + } + // LiveKit will publish the tracks as soon as they are created // but we want to control when tracks are published. // We cannot just mute the tracks, even if this will effectively stop the publishing, diff --git a/src/state/CallViewModel/remoteMembers/Connection.ts b/src/state/CallViewModel/remoteMembers/Connection.ts index 4db96d9b..f649e931 100644 --- a/src/state/CallViewModel/remoteMembers/Connection.ts +++ b/src/state/CallViewModel/remoteMembers/Connection.ts @@ -275,7 +275,7 @@ export class Connection { "[Connection " + opts.transport.livekit_service_url + "]", ); this.logger.info( - `constructor: ${opts.transport.livekit_service_url} alias: ${opts.transport.livekit_alias} withSfuConfig?: ${sfuConfig})`, + `constructor: ${opts.transport.livekit_service_url} alias: ${opts.transport.livekit_alias} withSfuConfig?: ${opts.existingSFUConfig ? JSON.stringify(opts.existingSFUConfig) : "undefined"}`, ); const { transport, client, scope } = opts;