import { UINode } from "./node"; export class AudioRecorder extends UINode { private audioElement: HTMLAudioElement; private mediaRecorder: MediaRecorder | null; private audioChunks: Blob[]; private stream: MediaStream | null; private recording?: Blob; public constructor(title: string) { super(title); this.audioElement = document.createElement("audio"); this.mediaRecorder = null; this.audioChunks = []; this.stream = null; this.audioElement.setAttribute("controls", "true"); this.audioElement.setAttribute("aria-label", title); this.element.appendChild(this.audioElement); this.setRole("audio-recorder"); } public async startRecording() { try { this.stream = await navigator.mediaDevices.getUserMedia({ audio: { autoGainControl: true, channelCount: 2, echoCancellation: false, noiseSuppression: false } }); this.mediaRecorder = new MediaRecorder(this.stream); this.mediaRecorder.ondataavailable = (event) => { this.audioChunks.push(event.data); }; this.mediaRecorder.onstop = () => { const audioBlob = new Blob(this.audioChunks, { type: 'audio/webm' }); this.recording = audioBlob; this.audioChunks = []; const audioUrl = URL.createObjectURL(audioBlob); this.audioElement.src = audioUrl; this.triggerRecordingComplete(audioUrl); }; this.mediaRecorder.start(); } catch (error) { console.error("Error accessing microphone:", error); } } public stopRecording() { if (this.mediaRecorder && this.mediaRecorder.state !== "inactive") { this.mediaRecorder.stop(); } if (this.stream) { this.stream.getTracks().forEach(track => track.stop()); this.stream = null; } } public getElement(): HTMLElement { return this.element; } public onRecordingComplete(callback: (audioUrl: string) => void) { this.element.addEventListener("recording-complete", (event: Event) => { const customEvent = event as CustomEvent; callback(customEvent.detail.audioUrl); }); return this; } protected triggerRecordingComplete(audioUrl: string) { const event = new CustomEvent("recording-complete", { detail: { audioUrl } }); this.element.dispatchEvent(event); return this; } public getRecording() { return this.recording; } }