Published
Edited
May 26, 2022
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
mutable a = "?"
Insert cell
//viewof mediaRecorder = Inputs.button(a, {
reduce: async () => {
try {
// Request mic permission
let userMedia = await navigator.mediaDevices.getUserMedia({
audio: true
});
// Instantiate recorder
return new MediaRecorder(userMedia);
} catch (error) {
// Mic permission not granted
return error.message;
}
}
})
Insert cell
Insert cell
mutable mediaRecorder = null
Insert cell
<audio src=${URL
Insert cell
dataChunks = []
Insert cell
mediaRecorder.addEventListener("dataavailable", (data) => dataChunks.push(data))
Insert cell
url = //URL.createObjectURL(new Blob(null, { type: "audio/ogg; codecs=opus" }))
Insert cell
mediaRecorder.stream.getAudioTracks()
Insert cell
mediaRecorder.state
Insert cell
mediaRecorder.mimeType
Insert cell
// https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia
// https://github.com/mdn/web-dictaphone/blob/gh-pages/scripts/app.js

// Start recording
viewof recordButton = {
let label,
reduce,
localMediaRecorder,
{ state } = mediaRecorder || {};
const RECORDING = "recording",
INACTIVE = "inactive",
ACTIVE = "active";

// ?? is nullish coalescing operator
if (state ?? true) {
label = "Grant mic access";
reduce = async () => {
try {
// Request mic permission
let userMedia = await navigator.mediaDevices.getUserMedia({
audio: true
});
// Instantiate recorder
mutable mediaRecorder = await new MediaRecorder(userMedia, {
mimeType: "audio/mp4"
});
} catch (error) {
// Mic permission not granted
return error.message;
}
};
}

if (state === RECORDING) {
label = "Stop Recording";
reduce = async () => await mediaRecorder.stop();
}

if (state === INACTIVE) {
label = "Start Recording";
reduce = async () => await mediaRecorder.start();
}

return Inputs.button(label, {
value: null,
reduce: async () => {
reduce();
mutable mediaRecorder = mediaRecorder;

return state;
}
});
}

// because start() mutates the mediaRecorder instance itself, we need to juggle status() and sync considerations... ergo the input deferred try catch
// without diving deep, ideally, start() would return the stream that was started
// i try to mitigate risk when dealing with OOP by writing my thoughts out, otherwise it's easy to lose a piece of state in my mental model of the app
Insert cell
tick = Promises.tick(1000)
Insert cell
recording = {
tick;
return mediaRecorder.state
}
Insert cell
//mediaRecorder.state
Insert cell
## Resources
https://github.com/coqui-ai/TTS
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more