mirror of
https://git.quad4.io/RNS-Things/MeshChatX.git
synced 2026-05-10 18:26:55 +00:00
feat(microphone): update audio recording error handling and update worklet import method
This commit is contained in:
@@ -5167,12 +5167,33 @@ export default {
|
||||
},
|
||||
buildAudioRecordingFailureMessage() {
|
||||
if (!navigator?.mediaDevices || typeof navigator.mediaDevices.getUserMedia !== "function") {
|
||||
return `${this.$t("messages.failed_start_recording")} (microphone API unavailable in this webview context)`;
|
||||
return `${this.$t("messages.failed_start_recording")}. ${this.$t("messages.failed_start_recording_help_mediadevices")}`;
|
||||
}
|
||||
if (typeof MediaRecorder !== "function") {
|
||||
return `${this.$t("messages.failed_start_recording")} (MediaRecorder not supported on this device)`;
|
||||
const AudioContextCtor = globalThis.AudioContext || globalThis.webkitAudioContext;
|
||||
if (typeof AudioContextCtor !== "function") {
|
||||
return `${this.$t("messages.failed_start_recording")}. ${this.$t("messages.failed_start_recording_help_web_audio")}`;
|
||||
}
|
||||
return this.$t("messages.failed_start_recording");
|
||||
let probe = null;
|
||||
try {
|
||||
probe = new AudioContextCtor();
|
||||
if (!probe.audioWorklet || typeof probe.audioWorklet.addModule !== "function") {
|
||||
return `${this.$t("messages.failed_start_recording")}. ${this.$t("messages.failed_start_recording_help_audio_worklet")}`;
|
||||
}
|
||||
} catch {
|
||||
return `${this.$t("messages.failed_start_recording")}. ${this.$t("messages.failed_start_recording_help_web_audio")}`;
|
||||
} finally {
|
||||
try {
|
||||
if (probe && typeof probe.close === "function") {
|
||||
const closed = probe.close();
|
||||
if (closed && typeof closed.catch === "function") {
|
||||
void closed.catch(() => {});
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
return `${this.$t("messages.failed_start_recording")}. ${this.$t("messages.failed_start_recording_help_permission")}`;
|
||||
},
|
||||
removeFileAttachment: function (file) {
|
||||
this.newMessageFiles = this.newMessageFiles.filter((newMessageFile) => {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* encode the audio to OGG/Opus using LXST's OpusFileSink without relying
|
||||
* on ffmpeg or any browser MediaRecorder container output.
|
||||
*/
|
||||
import microphoneRecorderWorkletUrl from "./MicrophoneRecorder.worklet.js?url";
|
||||
import microphoneRecorderWorkletSource from "./MicrophoneRecorder.worklet.js?raw";
|
||||
|
||||
class MicrophoneRecorder {
|
||||
constructor() {
|
||||
@@ -18,6 +18,7 @@ class MicrophoneRecorder {
|
||||
this.pcmChunks = [];
|
||||
this.sampleRate = 0;
|
||||
this.channels = 1;
|
||||
this._workletBlobUrl = null;
|
||||
}
|
||||
|
||||
cleanupMediaStream() {
|
||||
@@ -57,6 +58,14 @@ class MicrophoneRecorder {
|
||||
} catch {
|
||||
// ignore disconnect failures
|
||||
}
|
||||
if (this._workletBlobUrl) {
|
||||
try {
|
||||
URL.revokeObjectURL(this._workletBlobUrl);
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
this._workletBlobUrl = null;
|
||||
}
|
||||
if (this.audioContext && typeof this.audioContext.close === "function") {
|
||||
try {
|
||||
const closeResult = this.audioContext.close();
|
||||
@@ -110,7 +119,21 @@ class MicrophoneRecorder {
|
||||
return false;
|
||||
}
|
||||
|
||||
await this.audioContext.audioWorklet.addModule(microphoneRecorderWorkletUrl);
|
||||
const workletBlob = new Blob([microphoneRecorderWorkletSource], {
|
||||
type: "application/javascript",
|
||||
});
|
||||
this._workletBlobUrl = URL.createObjectURL(workletBlob);
|
||||
try {
|
||||
await this.audioContext.audioWorklet.addModule(this._workletBlobUrl);
|
||||
} catch {
|
||||
try {
|
||||
URL.revokeObjectURL(this._workletBlobUrl);
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
this._workletBlobUrl = null;
|
||||
throw new Error("AudioWorklet addModule failed");
|
||||
}
|
||||
this.processorNode = new AudioWorkletNode(this.audioContext, "microphone-pcm-float", {
|
||||
numberOfInputs: 1,
|
||||
numberOfOutputs: 1,
|
||||
|
||||
@@ -133,6 +133,7 @@ describe("MicrophoneRecorder", () => {
|
||||
|
||||
expect(audio.ctx.createMediaStreamSource).toHaveBeenCalledTimes(1);
|
||||
expect(audio.ctx.audioWorklet.addModule).toHaveBeenCalledTimes(1);
|
||||
expect(audio.ctx.audioWorklet.addModule.mock.calls[0][0]).toMatch(/^blob:/);
|
||||
expect(globalThis.AudioWorkletNode).toHaveBeenCalledWith(
|
||||
audio.ctx,
|
||||
"microphone-pcm-float",
|
||||
|
||||
Reference in New Issue
Block a user