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:
parent
b6ac6ec881
commit
b8aeb02b50
3 changed files with 833 additions and 140 deletions
884
package-lock.json
generated
884
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -24,6 +24,7 @@
|
||||||
"raw-loader": "^4.0.2",
|
"raw-loader": "^4.0.2",
|
||||||
"recordrtc": "^5.6.2",
|
"recordrtc": "^5.6.2",
|
||||||
"roboto-fontface": "*",
|
"roboto-fontface": "*",
|
||||||
|
"ts-ebml": "^2.0.2",
|
||||||
"v-emoji-picker": "^2.3.1",
|
"v-emoji-picker": "^2.3.1",
|
||||||
"vue": "^2.6.11",
|
"vue": "^2.6.11",
|
||||||
"vue-clipboard2": "^0.3.1",
|
"vue-clipboard2": "^0.3.1",
|
||||||
|
|
|
||||||
|
|
@ -147,6 +147,7 @@ import util from "../plugins/utils";
|
||||||
import VoiceRecorderLock from "./VoiceRecorderLock";
|
import VoiceRecorderLock from "./VoiceRecorderLock";
|
||||||
require("md-gum-polyfill");
|
require("md-gum-polyfill");
|
||||||
import RecordRTC from "recordrtc";
|
import RecordRTC from "recordrtc";
|
||||||
|
import {Decoder, tools, Reader} from 'ts-ebml';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "VoiceRecorder",
|
name: "VoiceRecorder",
|
||||||
|
|
@ -321,15 +322,23 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
startRecording() {
|
startRecording() {
|
||||||
|
var constraints = {
|
||||||
|
audio: {
|
||||||
|
channelCount: 1,
|
||||||
|
sampleRate: 16000,
|
||||||
|
echoCancellation: false,
|
||||||
|
autoGainControl: true,
|
||||||
|
noiseSuppression: true,
|
||||||
|
volume: 1.0,
|
||||||
|
},
|
||||||
|
video: false,
|
||||||
|
};
|
||||||
navigator.mediaDevices
|
navigator.mediaDevices
|
||||||
.getUserMedia({
|
.getUserMedia(constraints)
|
||||||
video: false,
|
|
||||||
audio: true,
|
|
||||||
})
|
|
||||||
.then((stream) => {
|
.then((stream) => {
|
||||||
this.recorder = RecordRTC(stream, {
|
this.recorder = RecordRTC(stream, {
|
||||||
type: "audio",
|
type: "audio",
|
||||||
mimeType: "audio/webm"
|
mimeType: "audio/webm",
|
||||||
});
|
});
|
||||||
this.recorder.startRecording();
|
this.recorder.startRecording();
|
||||||
this.state = State.RECORDING;
|
this.state = State.RECORDING;
|
||||||
|
|
@ -373,27 +382,29 @@ export default {
|
||||||
this.recordingTime = String.fromCharCode(160); // nbsp;
|
this.recordingTime = String.fromCharCode(160); // nbsp;
|
||||||
},
|
},
|
||||||
send() {
|
send() {
|
||||||
//console.log("Send:", this.recordedFile);
|
|
||||||
this.$emit("file", { file: this.recordedFile });
|
this.$emit("file", { file: this.recordedFile });
|
||||||
// const player = new Audio(URL.createObjectURL(file));
|
|
||||||
// player.play();
|
|
||||||
},
|
},
|
||||||
getFile(send) {
|
getFile(send) {
|
||||||
this.recorder.stopRecording(function ()
|
this.recorder.stopRecording(
|
||||||
{
|
function () {
|
||||||
const blob = this.recorder.getBlob();
|
this.correctMetadata(this.recorder.getBlob()).then((blob) => {
|
||||||
this.recordedFile = new File(
|
this.recordedFile = new File(
|
||||||
[blob],
|
[blob],
|
||||||
util.formatRecordStartTime(this.recordStartedAt) + ".webm",
|
util.formatRecordStartTime(this.recordStartedAt) + ".webm",
|
||||||
{
|
{
|
||||||
type: blob.type,
|
type: blob.type,
|
||||||
lastModified: Date.now()
|
lastModified: Date.now(),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if (send) {
|
//const player = new Audio(URL.createObjectURL(this.recordedFile));
|
||||||
this.send();
|
//player.play();
|
||||||
}
|
if (send) {
|
||||||
}.bind(this));
|
//console.log("send");
|
||||||
|
this.send();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}.bind(this)
|
||||||
|
);
|
||||||
},
|
},
|
||||||
startRecordTimer() {
|
startRecordTimer() {
|
||||||
this.stopRecordTimer();
|
this.stopRecordTimer();
|
||||||
|
|
@ -411,6 +422,37 @@ export default {
|
||||||
this.recordTimer = null;
|
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>
|
</script>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue