FEATURE: improved the mediaStore code to disable tracks instead of deleting them
This commit is contained in:
parent
1e20466f74
commit
52fe79df47
6 changed files with 112 additions and 239 deletions
|
@ -324,14 +324,11 @@ export type LocalStreamStoreValue = StreamSuccessValue | StreamErrorValue;
|
|||
interface StreamSuccessValue {
|
||||
type: "success";
|
||||
stream: MediaStream | null;
|
||||
// The constraints that we got (and not the one that have been requested)
|
||||
constraints: MediaStreamConstraints;
|
||||
}
|
||||
|
||||
interface StreamErrorValue {
|
||||
type: "error";
|
||||
error: Error;
|
||||
constraints: MediaStreamConstraints;
|
||||
}
|
||||
|
||||
let currentStream: MediaStream | null = null;
|
||||
|
@ -339,10 +336,13 @@ let currentStream: MediaStream | null = null;
|
|||
/**
|
||||
* Stops the camera from filming
|
||||
*/
|
||||
function stopCamera(): void {
|
||||
function applyCameraConstraints(currentStream: MediaStream | null, constraints: MediaTrackConstraints | boolean): void {
|
||||
if (currentStream) {
|
||||
for (const track of currentStream.getVideoTracks()) {
|
||||
track.stop();
|
||||
track.enabled = constraints !== false;
|
||||
if (constraints && constraints !== true) {
|
||||
track.applyConstraints(constraints);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -350,10 +350,16 @@ function stopCamera(): void {
|
|||
/**
|
||||
* Stops the microphone from listening
|
||||
*/
|
||||
function stopMicrophone(): void {
|
||||
function applyMicrophoneConstraints(
|
||||
currentStream: MediaStream | null,
|
||||
constraints: MediaTrackConstraints | boolean
|
||||
): void {
|
||||
if (currentStream) {
|
||||
for (const track of currentStream.getAudioTracks()) {
|
||||
track.stop();
|
||||
track.enabled = constraints !== false;
|
||||
if (constraints && constraints !== true) {
|
||||
track.applyConstraints(constraints);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -372,122 +378,96 @@ export const localStreamStore = derived<Readable<MediaStreamConstraints>, LocalS
|
|||
set({
|
||||
type: "error",
|
||||
error: new Error("Unable to access your camera or microphone. You need to use a HTTPS connection."),
|
||||
constraints,
|
||||
});
|
||||
return;
|
||||
} else if (isIOS()) {
|
||||
set({
|
||||
type: "error",
|
||||
error: new WebviewOnOldIOS(),
|
||||
constraints,
|
||||
});
|
||||
return;
|
||||
} else {
|
||||
set({
|
||||
type: "error",
|
||||
error: new BrowserTooOldError(),
|
||||
constraints,
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (constraints.audio === false) {
|
||||
stopMicrophone();
|
||||
}
|
||||
if (constraints.video === false) {
|
||||
stopCamera();
|
||||
}
|
||||
applyMicrophoneConstraints(currentStream, constraints.audio || false);
|
||||
applyCameraConstraints(currentStream, constraints.video || false);
|
||||
|
||||
if (constraints.audio === false && constraints.video === false) {
|
||||
currentStream = null;
|
||||
if (currentStream === null) {
|
||||
// we need to assign a first value to the stream because getUserMedia is async
|
||||
set({
|
||||
type: "success",
|
||||
stream: null,
|
||||
constraints,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
stopMicrophone();
|
||||
stopCamera();
|
||||
currentStream = await navigator.mediaDevices.getUserMedia(constraints);
|
||||
set({
|
||||
type: "success",
|
||||
stream: currentStream,
|
||||
constraints,
|
||||
});
|
||||
return;
|
||||
} catch (e) {
|
||||
if (constraints.video !== false) {
|
||||
console.info(
|
||||
"Error. Unable to get microphone and/or camera access. Trying audio only.",
|
||||
$mediaStreamConstraintsStore,
|
||||
e
|
||||
);
|
||||
// TODO: does it make sense to pop this error when retrying?
|
||||
set({
|
||||
type: "error",
|
||||
error: e,
|
||||
constraints,
|
||||
});
|
||||
// Let's try without video constraints
|
||||
requestedCameraState.disableWebcam();
|
||||
} else {
|
||||
console.info(
|
||||
"Error. Unable to get microphone and/or camera access.",
|
||||
$mediaStreamConstraintsStore,
|
||||
e
|
||||
);
|
||||
set({
|
||||
type: "error",
|
||||
error: e,
|
||||
constraints,
|
||||
});
|
||||
}
|
||||
|
||||
/*constraints.video = false;
|
||||
if (constraints.audio === false) {
|
||||
console.info("Error. Unable to get microphone and/or camera access.", $mediaStreamConstraintsStore, e);
|
||||
set({
|
||||
type: 'error',
|
||||
error: e,
|
||||
constraints
|
||||
});
|
||||
// Let's make as if the user did not ask.
|
||||
requestedCameraState.disableWebcam();
|
||||
} else {
|
||||
console.info("Error. Unable to get microphone and/or camera access. Trying audio only.", $mediaStreamConstraintsStore, e);
|
||||
(async () => {
|
||||
try {
|
||||
currentStream = await navigator.mediaDevices.getUserMedia(constraints);
|
||||
set({
|
||||
type: 'success',
|
||||
type: "success",
|
||||
stream: currentStream,
|
||||
constraints
|
||||
});
|
||||
return;
|
||||
} catch (e2) {
|
||||
console.info("Error. Unable to get microphone fallback access.", $mediaStreamConstraintsStore, e2);
|
||||
set({
|
||||
type: 'error',
|
||||
error: e,
|
||||
constraints
|
||||
});
|
||||
} catch (e) {
|
||||
if (constraints.video !== false) {
|
||||
console.info(
|
||||
"Error. Unable to get microphone and/or camera access. Trying audio only.",
|
||||
$mediaStreamConstraintsStore,
|
||||
e
|
||||
);
|
||||
// TODO: does it make sense to pop this error when retrying?
|
||||
set({
|
||||
type: "error",
|
||||
error: e,
|
||||
});
|
||||
// Let's try without video constraints
|
||||
requestedCameraState.disableWebcam();
|
||||
} else {
|
||||
console.info(
|
||||
"Error. Unable to get microphone and/or camera access.",
|
||||
$mediaStreamConstraintsStore,
|
||||
e
|
||||
);
|
||||
set({
|
||||
type: "error",
|
||||
error: e,
|
||||
});
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
})();
|
||||
})();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export interface ObtainedMediaStreamConstraints {
|
||||
video: boolean;
|
||||
audio: boolean;
|
||||
}
|
||||
|
||||
let obtainedMediaConstraint: ObtainedMediaStreamConstraints = {
|
||||
audio: false,
|
||||
video: false,
|
||||
};
|
||||
/**
|
||||
* A store containing the real active media constrained (not the one requested by the user, but the one we got from the system)
|
||||
* A store containing the actual states of audio and video (activated or deactivated)
|
||||
*/
|
||||
export const obtainedMediaConstraintStore = derived(localStreamStore, ($localStreamStore) => {
|
||||
return $localStreamStore.constraints;
|
||||
});
|
||||
export const obtainedMediaConstraintStore = derived<Readable<MediaStreamConstraints>, ObtainedMediaStreamConstraints>(
|
||||
mediaStreamConstraintsStore,
|
||||
($mediaStreamConstraintsStore, set) => {
|
||||
const newObtainedMediaConstraint = {
|
||||
video: !!$mediaStreamConstraintsStore.video,
|
||||
audio: !!$mediaStreamConstraintsStore.audio,
|
||||
};
|
||||
if (newObtainedMediaConstraint !== obtainedMediaConstraint) {
|
||||
obtainedMediaConstraint = newObtainedMediaConstraint;
|
||||
set(obtainedMediaConstraint);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Device list
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue