Skip to content

Commit 1b40749

Browse files
committed
refactor: unify acquireMedia
1 parent 911e65a commit 1b40749

2 files changed

Lines changed: 68 additions & 66 deletions

File tree

frontend/src/composables/useMeetingLogic.js

Lines changed: 56 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -185,13 +185,9 @@ export function useMeetingLogic(meetingState, meetingId, options = {}) {
185185

186186
const getFreshMicTrack = async () => {
187187
try {
188-
const constraints = {
189-
audio: selectedMicId.value
190-
? { deviceId: { exact: selectedMicId.value } }
191-
: true,
192-
};
193-
const freshStream =
194-
await navigator.mediaDevices.getUserMedia(constraints);
188+
const { stream: freshStream } = await acquireUserMedia(false, true, {
189+
micDeviceId: selectedMicId.value || null,
190+
});
195191
const freshTrack = freshStream.getAudioTracks()[0];
196192

197193
if (!freshTrack) {
@@ -311,7 +307,12 @@ export function useMeetingLogic(meetingState, meetingId, options = {}) {
311307

312308
const buildMediaConstraints = async (videoEnabled, audioEnabled) => {
313309
const constraints = {};
314-
const deviceIds = {};
310+
311+
const audioConstraints = {
312+
echoCancellation: true,
313+
noiseSuppression: true,
314+
autoGainControl: true,
315+
};
315316

316317
if (videoEnabled) {
317318
constraints.video = {
@@ -326,26 +327,59 @@ export function useMeetingLogic(meetingState, meetingId, options = {}) {
326327
);
327328
if (validCameraId) {
328329
constraints.video.deviceId = { exact: validCameraId };
329-
deviceIds.camera = validCameraId;
330330
}
331331
// If no valid device ID, let browser use its default
332332
}
333333

334334
if (audioEnabled) {
335-
constraints.audio = {};
335+
constraints.audio = { ...audioConstraints };
336336

337337
const validMicId = await getValidDeviceId(
338338
selectedMicId.value,
339339
"microphone",
340340
);
341341
if (validMicId) {
342342
constraints.audio.deviceId = { exact: validMicId };
343-
deviceIds.microphone = validMicId;
344343
}
345344
// If no valid device ID, let browser use its default
346345
}
347346

348-
return { constraints, deviceIds };
347+
return constraints;
348+
};
349+
350+
const acquireUserMedia = async (
351+
videoEnabled,
352+
audioEnabled,
353+
deviceOverrides = {},
354+
) => {
355+
const constraints = await buildMediaConstraints(videoEnabled, audioEnabled);
356+
357+
if (videoEnabled && Object.hasOwn(deviceOverrides, "cameraDeviceId")) {
358+
const validCameraId = await getValidDeviceId(
359+
deviceOverrides.cameraDeviceId,
360+
"camera",
361+
);
362+
if (validCameraId && constraints.video) {
363+
constraints.video.deviceId = { exact: validCameraId };
364+
} else if (constraints.video?.deviceId) {
365+
constraints.video.deviceId = undefined;
366+
}
367+
}
368+
369+
if (audioEnabled && Object.hasOwn(deviceOverrides, "micDeviceId")) {
370+
const validMicId = await getValidDeviceId(
371+
deviceOverrides.micDeviceId,
372+
"microphone",
373+
);
374+
if (validMicId && constraints.audio) {
375+
constraints.audio.deviceId = { exact: validMicId };
376+
} else if (constraints.audio?.deviceId) {
377+
constraints.audio.deviceId = undefined;
378+
}
379+
}
380+
381+
const stream = await navigator.mediaDevices.getUserMedia(constraints);
382+
return { stream, constraints };
349383
};
350384

351385
/**
@@ -382,12 +416,10 @@ export function useMeetingLogic(meetingState, meetingId, options = {}) {
382416
meetingState.setMediaState(prefMicEnabled.value, prefCameraEnabled.value);
383417

384418
if (meetingState.isCameraOn.value || meetingState.isMicOn.value) {
385-
const { constraints, deviceIds } = await buildMediaConstraints(
419+
const { stream } = await acquireUserMedia(
386420
meetingState.isCameraOn.value,
387421
meetingState.isMicOn.value,
388422
);
389-
390-
const stream = await navigator.mediaDevices.getUserMedia(constraints);
391423
meetingState.localStream.value = stream;
392424
// Clear any stale connection error on successful media acquisition
393425
if (meetingState.connectionError.value) {
@@ -437,11 +469,11 @@ export function useMeetingLogic(meetingState, meetingId, options = {}) {
437469
// Turning mic ON
438470
if (!stream) {
439471
try {
440-
const { constraints, deviceIds } = await buildMediaConstraints(
472+
const { stream: nextStream } = await acquireUserMedia(
441473
meetingState.isCameraOn.value,
442474
enable,
443475
);
444-
stream = await navigator.mediaDevices.getUserMedia(constraints);
476+
stream = nextStream;
445477
meetingState.localStream.value = stream;
446478
meetingState.cameraPermissionGranted.value = true;
447479
meetingState.microphonePermissionGranted.value = true;
@@ -462,12 +494,7 @@ export function useMeetingLogic(meetingState, meetingId, options = {}) {
462494
const hasAudio = stream.getAudioTracks().length > 0;
463495
if (!hasAudio) {
464496
try {
465-
const { constraints, deviceIds } = await buildMediaConstraints(
466-
false,
467-
true,
468-
);
469-
const audioOnly =
470-
await navigator.mediaDevices.getUserMedia(constraints);
497+
const { stream: audioOnly } = await acquireUserMedia(false, true);
471498
const newTrack = audioOnly.getAudioTracks()[0];
472499
if (newTrack) {
473500
stream.addTrack(newTrack);
@@ -491,12 +518,10 @@ export function useMeetingLogic(meetingState, meetingId, options = {}) {
491518
if (at.readyState === "ended") {
492519
// Track was stopped, get a new one
493520
try {
494-
const { constraints, deviceIds } = await buildMediaConstraints(
521+
const { stream: audioOnly } = await acquireUserMedia(
495522
false,
496523
true,
497524
);
498-
const audioOnly =
499-
await navigator.mediaDevices.getUserMedia(constraints);
500525
const newTrack = audioOnly.getAudioTracks()[0];
501526
if (newTrack) {
502527
stream.removeTrack(at);
@@ -629,11 +654,11 @@ export function useMeetingLogic(meetingState, meetingId, options = {}) {
629654
if (!stream) {
630655
// No existing stream: request both video and current audio state
631656
try {
632-
const { constraints, deviceIds } = await buildMediaConstraints(
657+
const { stream: nextStream } = await acquireUserMedia(
633658
true,
634659
meetingState.isMicOn.value,
635660
);
636-
stream = await navigator.mediaDevices.getUserMedia(constraints);
661+
stream = nextStream;
637662
meetingState.localStream.value = stream;
638663
meetingState.cameraPermissionGranted.value = true;
639664
if (meetingState.isMicOn.value) {
@@ -656,12 +681,7 @@ export function useMeetingLogic(meetingState, meetingId, options = {}) {
656681
const hasVideo = stream.getVideoTracks().length > 0;
657682
if (!hasVideo) {
658683
try {
659-
const { constraints, deviceIds } = await buildMediaConstraints(
660-
true,
661-
false,
662-
);
663-
const videoOnly =
664-
await navigator.mediaDevices.getUserMedia(constraints);
684+
const { stream: videoOnly } = await acquireUserMedia(true, false);
665685
const newTrack = videoOnly.getVideoTracks()[0];
666686
if (newTrack) {
667687
stream.addTrack(newTrack);
@@ -694,12 +714,10 @@ export function useMeetingLogic(meetingState, meetingId, options = {}) {
694714
if (vt.readyState === "ended") {
695715
// Track was stopped, get a new one
696716
try {
697-
const { constraints, deviceIds } = await buildMediaConstraints(
717+
const { stream: videoOnly } = await acquireUserMedia(
698718
true,
699719
false,
700720
);
701-
const videoOnly =
702-
await navigator.mediaDevices.getUserMedia(constraints);
703721
const newTrack = videoOnly.getVideoTracks()[0];
704722
if (newTrack) {
705723
stream.removeTrack(vt);
@@ -2232,6 +2250,7 @@ export function useMeetingLogic(meetingState, meetingId, options = {}) {
22322250

22332251
// Methods - Media
22342252
initializeCamera,
2253+
acquireUserMedia,
22352254
toggleMicrophone,
22362255
toggleCamera,
22372256
toggleScreenShare,

frontend/src/pages/Meeting.vue

Lines changed: 12 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,7 @@ const meetingDoc = getMeetingDoc(meetingId.value);
223223
// Meeting logic composable
224224
const {
225225
initializeCamera,
226+
acquireUserMedia,
226227
joinMeetingRoom,
227228
toggleMicrophone,
228229
toggleCamera,
@@ -617,35 +618,17 @@ const handleDeviceChanged = async (event) => {
617618
}
618619
}
619620
620-
const constraints = {};
621-
622-
if (meetingState.isCameraOn.value) {
623-
constraints.video = {};
624-
// Use the deviceId from the event if it's a camera change, otherwise use current selection
625-
const cameraDeviceId =
626-
event.type === "camera" ? event.deviceId : selectedCameraId.value;
627-
if (
628-
cameraDeviceId &&
629-
deviceManager.isDeviceAvailable(cameraDeviceId, "camera")
630-
) {
631-
constraints.video.deviceId = { exact: cameraDeviceId };
632-
}
633-
}
634-
635-
if (meetingState.isMicOn.value) {
636-
constraints.audio = {};
637-
const micDeviceId =
638-
event.type === "microphone" ? event.deviceId : selectedMicId.value;
639-
if (
640-
micDeviceId &&
641-
deviceManager.isDeviceAvailable(micDeviceId, "microphone")
642-
) {
643-
constraints.audio.deviceId = { exact: micDeviceId };
644-
}
645-
}
646-
647-
// use new device
648-
const newStream = await navigator.mediaDevices.getUserMedia(constraints);
621+
// Use selected devices unless this event overrides a specific one
622+
const cameraDeviceId =
623+
event.type === "camera" ? event.deviceId : selectedCameraId.value;
624+
const micDeviceId =
625+
event.type === "microphone" ? event.deviceId : selectedMicId.value;
626+
627+
const { stream: newStream } = await acquireUserMedia(
628+
meetingState.isCameraOn.value,
629+
meetingState.isMicOn.value,
630+
{ cameraDeviceId, micDeviceId },
631+
);
649632
meetingState.localStream.value = newStream;
650633
651634
if (meetingState.localVideo) {

0 commit comments

Comments
 (0)