Merge pull request #3353 from element-hq/toger5/device-permissions-request-possible-fix
Skip unnecassary media devices permissions requests (video feed flicker when opening settings)
This commit is contained in:
@@ -184,6 +184,16 @@ export const LobbyView: FC<Props> = ({
|
|||||||
null) as LocalVideoTrack | null,
|
null) as LocalVideoTrack | null,
|
||||||
[tracks],
|
[tracks],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (videoTrack && videoInputId === undefined) {
|
||||||
|
// If we have a video track but no videoInputId,
|
||||||
|
// we have to update the available devices. So that we select the first
|
||||||
|
// available video input device as the default instead of the `""` id.
|
||||||
|
devices.requestDeviceNames();
|
||||||
|
}
|
||||||
|
}, [devices, videoInputId, videoTrack]);
|
||||||
|
|
||||||
useTrackProcessorSync(videoTrack);
|
useTrackProcessorSync(videoTrack);
|
||||||
const showSwitchCamera = useShowSwitchCamera(
|
const showSwitchCamera = useShowSwitchCamera(
|
||||||
useObservable(
|
useObservable(
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import {
|
|||||||
type Observable,
|
type Observable,
|
||||||
} from "rxjs";
|
} from "rxjs";
|
||||||
import { createMediaDeviceObserver } from "@livekit/components-core";
|
import { createMediaDeviceObserver } from "@livekit/components-core";
|
||||||
import { logger } from "matrix-js-sdk/lib/logger";
|
import { logger as rootLogger } from "matrix-js-sdk/lib/logger";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
audioInput as audioInputSetting,
|
audioInput as audioInputSetting,
|
||||||
@@ -33,10 +33,12 @@ import {
|
|||||||
} from "../controls";
|
} from "../controls";
|
||||||
import { getUrlParams } from "../UrlParams";
|
import { getUrlParams } from "../UrlParams";
|
||||||
import { platform } from "../Platform";
|
import { platform } from "../Platform";
|
||||||
|
import { switchWhen } from "../utils/observable";
|
||||||
|
|
||||||
// This hardcoded id is used in EX ios! It can only be changed in coordination with
|
// This hardcoded id is used in EX ios! It can only be changed in coordination with
|
||||||
// the ios swift team.
|
// the ios swift team.
|
||||||
const EARPIECE_CONFIG_ID = "earpiece-id";
|
const EARPIECE_CONFIG_ID = "earpiece-id";
|
||||||
|
const logger = rootLogger.getChild("[MediaDevices]");
|
||||||
|
|
||||||
export type DeviceLabel =
|
export type DeviceLabel =
|
||||||
| { type: "name"; name: string }
|
| { type: "name"; name: string }
|
||||||
@@ -96,13 +98,25 @@ function availableRawDevices$(
|
|||||||
usingNames$: Observable<boolean>,
|
usingNames$: Observable<boolean>,
|
||||||
scope: ObservableScope,
|
scope: ObservableScope,
|
||||||
): Observable<MediaDeviceInfo[]> {
|
): Observable<MediaDeviceInfo[]> {
|
||||||
|
const logError = (e: Error): void =>
|
||||||
|
logger.error("Error creating MediaDeviceObserver", e);
|
||||||
|
const devices$ = createMediaDeviceObserver(kind, logError, false);
|
||||||
|
const devicesWithNames$ = createMediaDeviceObserver(kind, logError, true);
|
||||||
|
|
||||||
return usingNames$.pipe(
|
return usingNames$.pipe(
|
||||||
switchMap((usingNames) =>
|
switchMap((withNames) =>
|
||||||
createMediaDeviceObserver(
|
withNames
|
||||||
kind,
|
? // It might be that there is already a media stream running somewhere,
|
||||||
(e) => logger.error("Error creating MediaDeviceObserver", e),
|
// and so we can do without requesting a second one. Only switch to the
|
||||||
usingNames,
|
// device observer that explicitly requests the names if we see that
|
||||||
),
|
// names are in fact missing from the initial device enumeration.
|
||||||
|
devices$.pipe(
|
||||||
|
switchWhen(
|
||||||
|
(devices, i) => i === 0 && devices.every((d) => !d.label),
|
||||||
|
devicesWithNames$,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: devices$,
|
||||||
),
|
),
|
||||||
startWith([]),
|
startWith([]),
|
||||||
scope.state(),
|
scope.state(),
|
||||||
@@ -181,7 +195,11 @@ class AudioInput implements MediaDevice<DeviceLabel, SelectedAudioInputDevice> {
|
|||||||
public constructor(
|
public constructor(
|
||||||
private readonly usingNames$: Observable<boolean>,
|
private readonly usingNames$: Observable<boolean>,
|
||||||
private readonly scope: ObservableScope,
|
private readonly scope: ObservableScope,
|
||||||
) {}
|
) {
|
||||||
|
this.available$.subscribe((available) => {
|
||||||
|
logger.info("[audio-input] available devices:", available);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class AudioOutput
|
class AudioOutput
|
||||||
@@ -232,7 +250,11 @@ class AudioOutput
|
|||||||
public constructor(
|
public constructor(
|
||||||
private readonly usingNames$: Observable<boolean>,
|
private readonly usingNames$: Observable<boolean>,
|
||||||
private readonly scope: ObservableScope,
|
private readonly scope: ObservableScope,
|
||||||
) {}
|
) {
|
||||||
|
this.available$.subscribe((available) => {
|
||||||
|
logger.info("[audio-output] available devices:", available);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ControlledAudioOutput
|
class ControlledAudioOutput
|
||||||
@@ -298,6 +320,9 @@ class ControlledAudioOutput
|
|||||||
window.controls.onOutputDeviceSelect?.(device.id);
|
window.controls.onOutputDeviceSelect?.(device.id);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
this.available$.subscribe((available) => {
|
||||||
|
logger.info("[controlled-output] available devices:", available);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -323,7 +348,12 @@ class VideoInput implements MediaDevice<DeviceLabel, SelectedDevice> {
|
|||||||
public constructor(
|
public constructor(
|
||||||
private readonly usingNames$: Observable<boolean>,
|
private readonly usingNames$: Observable<boolean>,
|
||||||
private readonly scope: ObservableScope,
|
private readonly scope: ObservableScope,
|
||||||
) {}
|
) {
|
||||||
|
// This also has the purpose of subscribing to the available devices
|
||||||
|
this.available$.subscribe((available) => {
|
||||||
|
logger.info("[video-input] available devices:", available);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class MediaDevices {
|
export class MediaDevices {
|
||||||
|
|||||||
@@ -5,7 +5,17 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
|||||||
Please see LICENSE in the repository root for full details.
|
Please see LICENSE in the repository root for full details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { type Observable, defer, finalize, scan, startWith, tap } from "rxjs";
|
import {
|
||||||
|
type Observable,
|
||||||
|
concat,
|
||||||
|
defer,
|
||||||
|
finalize,
|
||||||
|
map,
|
||||||
|
scan,
|
||||||
|
startWith,
|
||||||
|
takeWhile,
|
||||||
|
tap,
|
||||||
|
} from "rxjs";
|
||||||
|
|
||||||
const nothing = Symbol("nothing");
|
const nothing = Symbol("nothing");
|
||||||
|
|
||||||
@@ -39,6 +49,29 @@ export function accumulate<State, Event>(
|
|||||||
events$.pipe(scan(update, initial), startWith(initial));
|
events$.pipe(scan(update, initial), startWith(initial));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const switchSymbol = Symbol("switch");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RxJS operator which behaves like the input Observable (A) until it emits a
|
||||||
|
* value satisfying the given predicate, then behaves like Observable B.
|
||||||
|
*
|
||||||
|
* The switch is immediate; the value that triggers the switch will not be
|
||||||
|
* present in the output.
|
||||||
|
*/
|
||||||
|
export function switchWhen<A, B>(
|
||||||
|
predicate: (a: A, index: number) => boolean,
|
||||||
|
b$: Observable<B>,
|
||||||
|
) {
|
||||||
|
return (a$: Observable<A>): Observable<A | B> =>
|
||||||
|
concat(
|
||||||
|
a$.pipe(
|
||||||
|
map((a, index) => (predicate(a, index) ? switchSymbol : a)),
|
||||||
|
takeWhile((a) => a !== switchSymbol),
|
||||||
|
) as Observable<A>,
|
||||||
|
b$,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads the current value of a state Observable without reacting to future
|
* Reads the current value of a state Observable without reacting to future
|
||||||
* changes.
|
* changes.
|
||||||
|
|||||||
Reference in New Issue
Block a user