apphouse
Version:
Component library for React that uses observable state management and theme-able components.
172 lines (159 loc) • 5.21 kB
text/typescript
import { action, computed, makeObservable, observable } from "mobx";
import { Recorder } from "./Recorder";
import Microphone from "./Microphone";
import Visualizer from "./Visualizer";
import AudioSource from "./AudioSource";
import Player from "./Player";
import Speech, { GrammarItemType } from "./Speech";
interface NonMatchedMemos {
text: string;
url: string;
}
export default class SpeechRecognitionRecorder extends Speech {
matchingId?: string;
recorder: Recorder;
microphone: Microphone;
audioSource: AudioSource;
recordedAudioBlob: Blob | undefined;
recordedAudioUrl: string;
visualizer: Visualizer;
player: Player;
voiceMemos: Record<string, string[]>;
otherMemos: NonMatchedMemos[];
spokenText?: string;
visualizerId: string;
constructor(grammar: GrammarItemType[], visualizerId: string) {
super(grammar);
this.audioSource = new AudioSource();
this.matchingId = undefined;
this.microphone = new Microphone();
this.otherMemos = [];
this.player = new Player();
if (typeof window != "undefined") {
this.recordedAudioBlob = new Blob();
} else {
this.recordedAudioBlob = undefined;
}
this.recordedAudioUrl = "";
this.recorder = new Recorder(this.onRecordingComplete);
this.spokenText = undefined;
this.visualizer = new Visualizer();
this.visualizerId = visualizerId;
this.voiceMemos = {};
makeObservable(this, {
audioSource: observable,
currentVoiceMemos: computed,
matchingId: observable,
onRecordingComplete: action,
onResult: action,
otherMemos: observable,
recordedAudioBlob: observable,
recordedAudioUrl: observable,
recorder: observable,
setRecordedAudioUrl: action,
spokenText: observable,
startRecording: action,
stopRecording: action,
visualizer: observable,
visualizerId: observable,
voiceMemos: observable,
});
}
get currentVoiceMemos() {
return this.voiceMemos;
}
get audioUrl() {
return this.recordedAudioUrl;
}
init = () => {
this.recorder.init(this.microphone.stream);
};
setRecordedAudioUrl = (url: string) => {
this.recordedAudioUrl = url;
};
onRecordingComplete = (audio: Blob) => {
this.recordedAudioBlob = audio;
const url = URL.createObjectURL(audio);
this.setRecordedAudioUrl(url);
if (this.matchingId) {
if (this.voiceMemos[this.matchingId]) {
this.voiceMemos[this.matchingId] = [
...this.voiceMemos[this.matchingId],
url,
];
} else {
this.voiceMemos[this.matchingId] = [url];
}
} else {
if (this.spokenText) {
this.otherMemos = [
...this.otherMemos,
{ text: this.spokenText, url },
];
}
}
};
start = () => {
this.recognition.onresult = this.onResult;
this.recognition.start();
this.startRecording();
};
startRecording = () => {
const started = this.microphone.startStream();
if (started) {
started.then(() => {
this.audioSource.initContext();
if (this.microphone.isReady) {
console.log("Microphone is ready");
const stream = this.microphone.stream;
if (stream) {
const source = this.audioSource.initWithStream(stream);
source.then(() => {
if (
this.audioSource.analyzer &&
this.audioSource.hasSource
) {
this.recorder.init(stream);
this.recorder.start();
const canvas = document.getElementById(
this.visualizerId,
) as HTMLCanvasElement;
if (canvas) {
this.visualizer.setCanvas(canvas);
this.visualizer.visualizeFreqBar(
this.audioSource.analyzer,
);
}
}
});
}
}
});
}
};
onResult = (event: any) => {
// The SpeechRecognitionEvent results property returns a SpeechRecognitionResultList object
// The SpeechRecognitionResultList object contains SpeechRecognitionResult objects.
// It has a getter so it can be accessed like an array
// The first [0] returns the SpeechRecognitionResult at the last position.
// Each SpeechRecognitionResult object contains SpeechRecognitionAlternative objects that contain individual results.
// These also have getters so they can be accessed like arrays.
// The second [0] returns the SpeechRecognitionAlternative at position 0.
// We then return the transcript property of the SpeechRecognitionAlternative object
var result = Speech.cleanKey(event.results[0][0].transcript);
console.log({ result });
let matchingId;
this.spokenText = result;
if (this.gramar[result]) {
matchingId = this.gramar[result].id;
}
this.stopRecording(matchingId);
if (result)
console.log("Confidence: " + event.results[0][0].confidence);
};
stopRecording = (matchedItemId?: string) => {
this.matchingId = matchedItemId;
this.recorder.stop();
this.microphone.stopStreaming();
};
}