mirror of https://github.com/OpenVidu/openvidu.git
ov-components: Uses device constraints for media tracks
Ensures correct audio and video device selection by applying `exact` or `ideal` constraints when creating or restarting media tracks. This improves device handling and avoids potential issues when switching between different audio or video devices.pull/860/head
parent
4617dfd797
commit
b2701311fb
|
|
@ -427,28 +427,28 @@ export class OpenViduService {
|
||||||
if (videoDeviceId === true) {
|
if (videoDeviceId === true) {
|
||||||
if (this.deviceService.hasVideoDeviceAvailable()) {
|
if (this.deviceService.hasVideoDeviceAvailable()) {
|
||||||
const selectedCamera = this.deviceService.getCameraSelected();
|
const selectedCamera = this.deviceService.getCameraSelected();
|
||||||
options.video = { deviceId: selectedCamera?.device || 'default' };
|
options.video = { deviceId: this.toDeviceConstraint(selectedCamera?.device) };
|
||||||
} else {
|
} else {
|
||||||
options.video = false;
|
options.video = false;
|
||||||
}
|
}
|
||||||
} else if (videoDeviceId === false) {
|
} else if (videoDeviceId === false) {
|
||||||
options.video = false;
|
options.video = false;
|
||||||
} else {
|
} else {
|
||||||
(options.video as VideoCaptureOptions).deviceId = videoDeviceId;
|
(options.video as VideoCaptureOptions).deviceId = this.toDeviceConstraint(videoDeviceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Audio device
|
// Audio device
|
||||||
if (audioDeviceId === true) {
|
if (audioDeviceId === true) {
|
||||||
if (this.deviceService.hasAudioDeviceAvailable()) {
|
if (this.deviceService.hasAudioDeviceAvailable()) {
|
||||||
const selectedMic = this.deviceService.getMicrophoneSelected();
|
const selectedMic = this.deviceService.getMicrophoneSelected();
|
||||||
(options.audio as AudioCaptureOptions).deviceId = selectedMic?.device || 'default';
|
(options.audio as AudioCaptureOptions).deviceId = this.toDeviceConstraint(selectedMic?.device);
|
||||||
} else {
|
} else {
|
||||||
options.audio = false;
|
options.audio = false;
|
||||||
}
|
}
|
||||||
} else if (audioDeviceId === false) {
|
} else if (audioDeviceId === false) {
|
||||||
options.audio = false;
|
options.audio = false;
|
||||||
} else {
|
} else {
|
||||||
(options.audio as AudioCaptureOptions).deviceId = audioDeviceId;
|
(options.audio as AudioCaptureOptions).deviceId = this.toDeviceConstraint(audioDeviceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
let newLocalTracks: LocalTrack[] = [];
|
let newLocalTracks: LocalTrack[] = [];
|
||||||
|
|
@ -518,6 +518,13 @@ export class OpenViduService {
|
||||||
return tracks;
|
return tracks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private toDeviceConstraint(deviceId?: string): ConstrainDOMString {
|
||||||
|
if (!deviceId || deviceId === 'default') {
|
||||||
|
return { ideal: 'default' };
|
||||||
|
}
|
||||||
|
return { exact: deviceId };
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
* As the Room is not created yet, we need to handle the media tracks with a temporary array of tracks.
|
* As the Room is not created yet, we need to handle the media tracks with a temporary array of tracks.
|
||||||
|
|
@ -588,13 +595,13 @@ export class OpenViduService {
|
||||||
*/
|
*/
|
||||||
async switchCamera(deviceId: string): Promise<void> {
|
async switchCamera(deviceId: string): Promise<void> {
|
||||||
const existingTrack = this.localTracks.find((t) => t.kind === Track.Kind.Video) as LocalVideoTrack | undefined;
|
const existingTrack = this.localTracks.find((t) => t.kind === Track.Kind.Video) as LocalVideoTrack | undefined;
|
||||||
|
const options: VideoCaptureOptions = { deviceId: this.toDeviceConstraint(deviceId) };
|
||||||
if (existingTrack) {
|
if (existingTrack) {
|
||||||
try {
|
try {
|
||||||
// restartTrack replaces the underlying MediaStreamTrack in-place.
|
// restartTrack replaces the underlying MediaStreamTrack in-place.
|
||||||
// LiveKit's setMediaStreamTrack will call processor.restart(newTrack) automatically
|
// LiveKit's setMediaStreamTrack will call processor.restart(newTrack) automatically
|
||||||
// if a background processor is attached, preserving the active effect.
|
// if a background processor is attached, preserving the active effect.
|
||||||
await existingTrack.restartTrack({ deviceId });
|
await existingTrack.restartTrack(options);
|
||||||
if (!this.deviceService.isCameraEnabled()) {
|
if (!this.deviceService.isCameraEnabled()) {
|
||||||
await existingTrack.mute();
|
await existingTrack.mute();
|
||||||
}
|
}
|
||||||
|
|
@ -608,7 +615,7 @@ export class OpenViduService {
|
||||||
|
|
||||||
// No existing track (edge case: camera was unavailable/unpublished) → create a fresh one
|
// No existing track (edge case: camera was unavailable/unpublished) → create a fresh one
|
||||||
try {
|
try {
|
||||||
const newVideoTracks = await createLocalTracks({ video: { deviceId } });
|
const newVideoTracks = await createLocalTracks({ video: options });
|
||||||
const videoTrack = newVideoTracks.find((t) => t.kind === Track.Kind.Video) as LocalVideoTrack | undefined;
|
const videoTrack = newVideoTracks.find((t) => t.kind === Track.Kind.Video) as LocalVideoTrack | undefined;
|
||||||
if (videoTrack) {
|
if (videoTrack) {
|
||||||
if (!this.deviceService.isCameraEnabled()) {
|
if (!this.deviceService.isCameraEnabled()) {
|
||||||
|
|
@ -679,15 +686,16 @@ export class OpenViduService {
|
||||||
*/
|
*/
|
||||||
async switchMicrophone(deviceId: string): Promise<void> {
|
async switchMicrophone(deviceId: string): Promise<void> {
|
||||||
const existingTrack = this.localTracks.find((t) => t.kind === Track.Kind.Audio) as LocalAudioTrack | undefined;
|
const existingTrack = this.localTracks.find((t) => t.kind === Track.Kind.Audio) as LocalAudioTrack | undefined;
|
||||||
|
const options: AudioCaptureOptions = {
|
||||||
if (existingTrack) {
|
deviceId: this.toDeviceConstraint(deviceId),
|
||||||
try {
|
|
||||||
await existingTrack.restartTrack({
|
|
||||||
deviceId,
|
|
||||||
echoCancellation: true,
|
echoCancellation: true,
|
||||||
noiseSuppression: true,
|
noiseSuppression: true,
|
||||||
autoGainControl: true
|
autoGainControl: true
|
||||||
});
|
};
|
||||||
|
|
||||||
|
if (existingTrack) {
|
||||||
|
try {
|
||||||
|
await existingTrack.restartTrack(options);
|
||||||
if (!this.deviceService.isMicrophoneEnabled()) {
|
if (!this.deviceService.isMicrophoneEnabled()) {
|
||||||
await existingTrack.mute();
|
await existingTrack.mute();
|
||||||
}
|
}
|
||||||
|
|
@ -701,14 +709,7 @@ export class OpenViduService {
|
||||||
|
|
||||||
// No existing track (edge case) → create a fresh one
|
// No existing track (edge case) → create a fresh one
|
||||||
try {
|
try {
|
||||||
const newAudioTracks = await createLocalTracks({
|
const newAudioTracks = await createLocalTracks(options as CreateLocalTracksOptions);
|
||||||
audio: {
|
|
||||||
deviceId,
|
|
||||||
echoCancellation: true,
|
|
||||||
noiseSuppression: true,
|
|
||||||
autoGainControl: true
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const audioTrack = newAudioTracks.find((t) => t.kind === Track.Kind.Audio);
|
const audioTrack = newAudioTracks.find((t) => t.kind === Track.Kind.Audio);
|
||||||
if (audioTrack) {
|
if (audioTrack) {
|
||||||
if (!this.deviceService.isMicrophoneEnabled()) {
|
if (!this.deviceService.isMicrophoneEnabled()) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue