Skip to content

Commit

Permalink
Switch active device if previously selected device becomes unavailable (
Browse files Browse the repository at this point in the history
#1237)

* Switch active audiooutput device if previously selected device becomes unavailable

* Better track active devices

* type only import

* Create dirty-kids-give.md
  • Loading branch information
lukasIO authored Sep 3, 2024
1 parent c9bee16 commit b81fdb9
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 3 deletions.
5 changes: 5 additions & 0 deletions .changeset/dirty-kids-give.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"livekit-client": patch
---

Switch active device if previously selected device becomes unavailable
37 changes: 34 additions & 3 deletions src/room/Room.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ import type { ConnectionQuality } from './participant/Participant';
import RemoteParticipant from './participant/RemoteParticipant';
import CriticalTimers from './timers';
import LocalAudioTrack from './track/LocalAudioTrack';
import type LocalTrack from './track/LocalTrack';
import LocalTrackPublication from './track/LocalTrackPublication';
import LocalVideoTrack from './track/LocalVideoTrack';
import type RemoteTrack from './track/RemoteTrack';
Expand Down Expand Up @@ -1073,7 +1074,8 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
let success = true;
const deviceConstraint = exact ? { exact: deviceId } : deviceId;
if (kind === 'audioinput') {
const prevDeviceId = this.options.audioCaptureDefaults!.deviceId;
const prevDeviceId =
this.getActiveDevice(kind) ?? this.options.audioCaptureDefaults!.deviceId;
this.options.audioCaptureDefaults!.deviceId = deviceConstraint;
deviceHasChanged = prevDeviceId !== deviceConstraint;
const tracks = Array.from(this.localParticipant.audioTrackPublications.values()).filter(
Expand All @@ -1088,7 +1090,8 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
throw e;
}
} else if (kind === 'videoinput') {
const prevDeviceId = this.options.videoCaptureDefaults!.deviceId;
const prevDeviceId =
this.getActiveDevice(kind) ?? this.options.videoCaptureDefaults!.deviceId;
this.options.videoCaptureDefaults!.deviceId = deviceConstraint;
deviceHasChanged = prevDeviceId !== deviceConstraint;
const tracks = Array.from(this.localParticipant.videoTrackPublications.values()).filter(
Expand All @@ -1115,7 +1118,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
(await DeviceManager.getInstance().normalizeDeviceId('audiooutput', deviceId)) ?? '';
}
this.options.audioOutput ??= {};
const prevDeviceId = this.options.audioOutput.deviceId;
const prevDeviceId = this.getActiveDevice(kind) ?? this.options.audioOutput.deviceId;
this.options.audioOutput.deviceId = deviceId;
deviceHasChanged = prevDeviceId !== deviceConstraint;

Expand Down Expand Up @@ -1600,6 +1603,19 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
};

private handleDeviceChange = async () => {
const availableDevices = await DeviceManager.getInstance().getDevices();
const kinds: MediaDeviceKind[] = ['audioinput', 'videoinput', 'audiooutput'];
for (let kind of kinds) {
// switch to first available device if previously active device is not available any more
const devicesOfKind = availableDevices.filter((d) => d.kind === kind);
if (
devicesOfKind.length > 0 &&
!devicesOfKind.find((deviceInfo) => deviceInfo.deviceId === this.getActiveDevice(kind))
) {
await this.switchActiveDevice(kind, devicesOfKind[0].deviceId);
}
}

this.emit(RoomEvent.MediaDevicesChanged);
};

Expand Down Expand Up @@ -1923,6 +1939,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)

private onLocalTrackPublished = async (pub: LocalTrackPublication) => {
pub.track?.on(TrackEvent.TrackProcessorUpdate, this.onTrackProcessorUpdate);
pub.track?.on(TrackEvent.Restarted, this.onLocalTrackRestarted);
pub.track?.getProcessor()?.onPublish?.(this);

this.emit(RoomEvent.LocalTrackPublished, pub, this.localParticipant);
Expand All @@ -1947,9 +1964,23 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)

private onLocalTrackUnpublished = (pub: LocalTrackPublication) => {
pub.track?.off(TrackEvent.TrackProcessorUpdate, this.onTrackProcessorUpdate);
pub.track?.off(TrackEvent.Restarted, this.onLocalTrackRestarted);
this.emit(RoomEvent.LocalTrackUnpublished, pub, this.localParticipant);
};

private onLocalTrackRestarted = async (track: LocalTrack) => {
const deviceId = await track.getDeviceId();
const deviceKind = sourceToKind(track.source);
if (
deviceKind &&
deviceId &&
deviceId !== this.localParticipant.activeDeviceMap.get(deviceKind)
) {
this.localParticipant.activeDeviceMap.set(deviceKind, deviceId);
this.emit(RoomEvent.ActiveDeviceChanged, deviceKind, deviceId);
}
};

private onLocalConnectionQualityChanged = (quality: ConnectionQuality) => {
this.emit(RoomEvent.ConnectionQualityChanged, quality, this.localParticipant);
};
Expand Down

0 comments on commit b81fdb9

Please sign in to comment.