Improve error recovery when starting a recording
This helps return the microphone access to the user.
This commit is contained in:
parent
b5c25498c8
commit
b61fe2f8e6
2 changed files with 89 additions and 68 deletions
|
@ -73,7 +73,9 @@ class ConsoleLogger {
|
||||||
|
|
||||||
// Convert objects and errors to helpful things
|
// Convert objects and errors to helpful things
|
||||||
args = args.map((arg) => {
|
args = args.map((arg) => {
|
||||||
if (arg instanceof Error) {
|
if (arg instanceof DOMException) {
|
||||||
|
return arg.message + ` (${arg.name} | ${arg.code}) ` + (arg.stack ? `\n${arg.stack}` : '');
|
||||||
|
} else if (arg instanceof Error) {
|
||||||
return arg.message + (arg.stack ? `\n${arg.stack}` : '');
|
return arg.message + (arg.stack ? `\n${arg.stack}` : '');
|
||||||
} else if (typeof (arg) === 'object') {
|
} else if (typeof (arg) === 'object') {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -90,6 +90,7 @@ export class VoiceRecording extends EventEmitter implements IDestroyable {
|
||||||
}
|
}
|
||||||
|
|
||||||
private async makeRecorder() {
|
private async makeRecorder() {
|
||||||
|
try {
|
||||||
this.recorderStream = await navigator.mediaDevices.getUserMedia({
|
this.recorderStream = await navigator.mediaDevices.getUserMedia({
|
||||||
audio: {
|
audio: {
|
||||||
channelCount: CHANNELS,
|
channelCount: CHANNELS,
|
||||||
|
@ -114,6 +115,7 @@ export class VoiceRecording extends EventEmitter implements IDestroyable {
|
||||||
// web audio API prefers this be done async to avoid holding the main thread with math.
|
// web audio API prefers this be done async to avoid holding the main thread with math.
|
||||||
const mxRecorderWorkletPath = document.body.dataset.vectorRecorderWorkletScript;
|
const mxRecorderWorkletPath = document.body.dataset.vectorRecorderWorkletScript;
|
||||||
if (!mxRecorderWorkletPath) {
|
if (!mxRecorderWorkletPath) {
|
||||||
|
// noinspection ExceptionCaughtLocallyJS
|
||||||
throw new Error("Unable to create recorder: no worklet script registered");
|
throw new Error("Unable to create recorder: no worklet script registered");
|
||||||
}
|
}
|
||||||
await this.recorderContext.audioWorklet.addModule(mxRecorderWorkletPath);
|
await this.recorderContext.audioWorklet.addModule(mxRecorderWorkletPath);
|
||||||
|
@ -162,6 +164,23 @@ export class VoiceRecording extends EventEmitter implements IDestroyable {
|
||||||
newBuf.set(buf, this.buffer.length);
|
newBuf.set(buf, this.buffer.length);
|
||||||
this.buffer = newBuf;
|
this.buffer = newBuf;
|
||||||
};
|
};
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Error starting recording: ", e);
|
||||||
|
if (e instanceof DOMException) { // Unhelpful DOMExceptions are common - parse them sanely
|
||||||
|
console.error(`${e.name} (${e.code}): ${e.message}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up as best as possible
|
||||||
|
if (this.recorderStream) this.recorderStream.getTracks().forEach(t => t.stop());
|
||||||
|
if (this.recorderSource) this.recorderSource.disconnect();
|
||||||
|
if (this.recorder) this.recorder.close();
|
||||||
|
if (this.recorderContext) {
|
||||||
|
// noinspection ES6MissingAwait - not important that we wait
|
||||||
|
this.recorderContext.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
throw e; // rethrow so upstream can handle it
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private get audioBuffer(): Uint8Array {
|
private get audioBuffer(): Uint8Array {
|
||||||
|
|
Loading…
Reference in a new issue