From c03e2c4bde96db0b127c412d2ba627540d809b5b Mon Sep 17 00:00:00 2001 From: Timo Date: Mon, 23 Jun 2025 13:57:52 +0200 Subject: [PATCH] simple subject instead of derived observable --- src/state/MediaDevices.ts | 50 +++++++++++++++--------------------- src/state/ObservableScope.ts | 12 --------- 2 files changed, 20 insertions(+), 42 deletions(-) diff --git a/src/state/MediaDevices.ts b/src/state/MediaDevices.ts index 47b24939..a5b2b94f 100644 --- a/src/state/MediaDevices.ts +++ b/src/state/MediaDevices.ts @@ -8,7 +8,6 @@ Please see LICENSE in the repository root for full details. import { combineLatest, filter, - identity, map, merge, of, @@ -95,15 +94,16 @@ export const iosDeviceMenu$ = function availableRawDevices$( kind: MediaDeviceKind, - recomputeDevicesWithPermissions$: Observable, + updateAvailableDeviceRequests$: Observable, scope: ObservableScope, ): Observable { - return recomputeDevicesWithPermissions$.pipe( - switchMap((recomputeDevicesWithPermissions) => + return updateAvailableDeviceRequests$.pipe( + startWith(false), + switchMap((withPermissions) => createMediaDeviceObserver( kind, (e) => logger.error("Error creating MediaDeviceObserver", e), - recomputeDevicesWithPermissions, + withPermissions, ), ), startWith([]), @@ -149,7 +149,7 @@ class AudioInput implements MediaDevice { private readonly availableRaw$: Observable = availableRawDevices$( "audioinput", - this.recomputeDevicesWithPermissions$, + this.updateAvailableDeviceRequests$, this.scope, ); @@ -185,7 +185,7 @@ class AudioInput implements MediaDevice { } public constructor( - private readonly recomputeDevicesWithPermissions$: Observable, + private readonly updateAvailableDeviceRequests$: Observable, private readonly scope: ObservableScope, ) { this.available$.subscribe((available) => { @@ -199,7 +199,7 @@ class AudioOutput { public readonly available$ = availableRawDevices$( "audiooutput", - this.recomputeDevicesWithPermissions$, + this.updateAvailableDeviceRequests$, this.scope, ).pipe( map((availableRaw) => { @@ -240,7 +240,7 @@ class AudioOutput } public constructor( - private readonly recomputeDevicesWithPermissions$: Observable, + private readonly updateAvailableDeviceRequests$: Observable, private readonly scope: ObservableScope, ) { this.available$.subscribe((available) => { @@ -321,7 +321,7 @@ class ControlledAudioOutput class VideoInput implements MediaDevice { public readonly available$ = availableRawDevices$( "videoinput", - this.recomputeDevicesWithPermissions$, + this.updateAvailableDeviceRequests$, this.scope, ).pipe(map(buildDeviceMap)); @@ -338,7 +338,7 @@ class VideoInput implements MediaDevice { } public constructor( - private readonly recomputeDevicesWithPermissions$: Observable, + private readonly updateAvailableDeviceRequests$: Observable, private readonly scope: ObservableScope, ) { // This also has the purpose of subscribing to the available devices @@ -349,7 +349,7 @@ class VideoInput implements MediaDevice { } export class MediaDevices { - private readonly requests$ = new Subject(); + private readonly updateAvailableDeviceRequests$ = new Subject(); /** * Requests that the media devices be populated with the names of each * available device, rather than numbered identifiers. This may invoke a @@ -364,41 +364,31 @@ export class MediaDevices { // we only actually update the requests$ subject if there are no // devices with a label, because otherwise we already have the permission // to access the devices. - this.requests$.next(!result.some((device) => device.label)); + this.updateAvailableDeviceRequests$.next( + !result.some((device) => device.label), + ); }); } - // Start using device names as soon as requested. This will cause LiveKit to - // briefly request device permissions and acquire media streams for each - // device type while calling `enumerateDevices`, which is what browsers want - // you to do to receive device names in lieu of a more explicit permissions - // API. This flag never resets to false, because once permissions are granted - // the first time, the user won't be prompted again until reload of the page. - private readonly recomputeDevicesWithPermissions$ = this.requests$.pipe( - startWith(false), - identity, - this.scope.stateNonDistinct(), - ); - public readonly audioInput: MediaDevice< DeviceLabel, SelectedAudioInputDevice - > = new AudioInput(this.recomputeDevicesWithPermissions$, this.scope); + > = new AudioInput(this.updateAvailableDeviceRequests$, this.scope); public readonly audioOutput: MediaDevice< AudioOutputDeviceLabel, SelectedAudioOutputDevice > = getUrlParams().controlledAudioDevices ? new ControlledAudioOutput(this.scope) - : new AudioOutput(this.recomputeDevicesWithPermissions$, this.scope); + : new AudioOutput(this.updateAvailableDeviceRequests$, this.scope); public readonly videoInput: MediaDevice = - new VideoInput(this.recomputeDevicesWithPermissions$, this.scope); + new VideoInput(this.updateAvailableDeviceRequests$, this.scope); public constructor(private readonly scope: ObservableScope) { - this.recomputeDevicesWithPermissions$.subscribe((recompute) => { + this.updateAvailableDeviceRequests$.subscribe((recompute) => { logger.info( - "[MediaDevices] recomputeDevicesWithPermissions$ changed:", + "[MediaDevices] updateAvailableDeviceRequests$ changed:", recompute, ); }); diff --git a/src/state/ObservableScope.ts b/src/state/ObservableScope.ts index e69c46f0..727082cf 100644 --- a/src/state/ObservableScope.ts +++ b/src/state/ObservableScope.ts @@ -38,9 +38,6 @@ export class ObservableScope { shareReplay({ bufferSize: 1, refCount: false }), ); - private readonly stateNonDistinctImpl: MonoTypeOperator = (o$) => - o$.pipe(this.bind(), shareReplay({ bufferSize: 1, refCount: false })); - /** * Transforms an Observable into a hot state Observable which replays its * latest value upon subscription, skips updates with identical values, and @@ -50,15 +47,6 @@ export class ObservableScope { return this.stateImpl; } - /** - * Transforms an Observable into a hot state Observable which replays its - * latest value upon subscription, skips updates with identical values, and - * is bound to this scope. - */ - public stateNonDistinct(): MonoTypeOperator { - return this.stateNonDistinctImpl; - } - /** * Ends the scope, causing any bound Observables to complete. */