More work on audio recording

Issue #95. Use a post processing step to fix chromium bug of not having a valid cues section in the metadata (=browser did not know length of audio!). Also, set more constraints in the call to getUserMedia to fix Android problem of really sh*tty audio in the default mode (More info on github.com slash processing/p5.js-sound/issues/346
This commit is contained in:
N-Pex 2021-03-24 10:45:35 +01:00
parent b6ac6ec881
commit b8aeb02b50
3 changed files with 833 additions and 140 deletions

884
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -24,6 +24,7 @@
"raw-loader": "^4.0.2",
"recordrtc": "^5.6.2",
"roboto-fontface": "*",
"ts-ebml": "^2.0.2",
"v-emoji-picker": "^2.3.1",
"vue": "^2.6.11",
"vue-clipboard2": "^0.3.1",

View file

@ -147,6 +147,7 @@ import util from "../plugins/utils";
import VoiceRecorderLock from "./VoiceRecorderLock";
require("md-gum-polyfill");
import RecordRTC from "recordrtc";
import {Decoder, tools, Reader} from 'ts-ebml';
export default {
name: "VoiceRecorder",
@ -321,15 +322,23 @@ export default {
},
startRecording() {
var constraints = {
audio: {
channelCount: 1,
sampleRate: 16000,
echoCancellation: false,
autoGainControl: true,
noiseSuppression: true,
volume: 1.0,
},
video: false,
};
navigator.mediaDevices
.getUserMedia({
video: false,
audio: true,
})
.getUserMedia(constraints)
.then((stream) => {
this.recorder = RecordRTC(stream, {
type: "audio",
mimeType: "audio/webm"
mimeType: "audio/webm",
});
this.recorder.startRecording();
this.state = State.RECORDING;
@ -373,27 +382,29 @@ export default {
this.recordingTime = String.fromCharCode(160); // nbsp;
},
send() {
//console.log("Send:", this.recordedFile);
this.$emit("file", { file: this.recordedFile });
// const player = new Audio(URL.createObjectURL(file));
// player.play();
},
getFile(send) {
this.recorder.stopRecording(function ()
{
const blob = this.recorder.getBlob();
this.recordedFile = new File(
[blob],
util.formatRecordStartTime(this.recordStartedAt) + ".webm",
{
type: blob.type,
lastModified: Date.now()
}
);
if (send) {
this.send();
}
}.bind(this));
this.recorder.stopRecording(
function () {
this.correctMetadata(this.recorder.getBlob()).then((blob) => {
this.recordedFile = new File(
[blob],
util.formatRecordStartTime(this.recordStartedAt) + ".webm",
{
type: blob.type,
lastModified: Date.now(),
}
);
//const player = new Audio(URL.createObjectURL(this.recordedFile));
//player.play();
if (send) {
//console.log("send");
this.send();
}
});
}.bind(this)
);
},
startRecordTimer() {
this.stopRecordTimer();
@ -411,6 +422,37 @@ export default {
this.recordTimer = null;
}
},
/*
* There is an issue with browsers not setting correct metadata in the generated webm file.
* See here: https://bugs.chromium.org/p/chromium/issues/detail?id=642012
* Use es-embl to try to update the cues section.
*/
async correctMetadata(blob) {
try {
const decoder = new Decoder();
const reader = new Reader();
reader.logging = true;
reader.logGroup = "Raw WebM file";
reader.drop_default_duration = false;
const webMBuf = await blob.arrayBuffer();
const elms = decoder.decode(webMBuf);
elms.forEach((elm) => {
reader.read(elm);
});
reader.stop();
const refinedMetadataBuf = tools.makeMetadataSeekable(
reader.metadatas,
reader.duration,
reader.cues
);
const body = webMBuf.slice(reader.metadataSize);
return new Blob([refinedMetadataBuf, body], { type: blob.type });
} catch (err) {
console.err(err);
return blob;
}
},
},
};
</script>