bugfix
This commit is contained in:
parent
00a7cc8dd3
commit
a8ef7eb1bd
@ -72,9 +72,10 @@ bricks.MediaRecorder = class extends bricks.Popup {
|
|||||||
this.mediaRecorder.onstop = async () => {
|
this.mediaRecorder.onstop = async () => {
|
||||||
console.log('onstop() called', this.normal_stop);
|
console.log('onstop() called', this.normal_stop);
|
||||||
if (!this.normal_stop) return;
|
if (!this.normal_stop) return;
|
||||||
const blob = new Blob(this.recordedChunks,
|
var blob = new Blob(this.recordedChunks,
|
||||||
{ type: this.mimetype });
|
{ type: this.mimetype });
|
||||||
// 1. 在本地播放
|
// 1. 在本地播放
|
||||||
|
blob = await this.blob_convert(blob);
|
||||||
const url = URL.createObjectURL(blob);
|
const url = URL.createObjectURL(blob);
|
||||||
// 2. 转成 File 对象
|
// 2. 转成 File 对象
|
||||||
if (this.mimetype == 'video/mp4'){
|
if (this.mimetype == 'video/mp4'){
|
||||||
@ -99,8 +100,8 @@ bricks.MediaRecorder = class extends bricks.Popup {
|
|||||||
this.dispatch('record_started')
|
this.dispatch('record_started')
|
||||||
console.log("Recording started...");
|
console.log("Recording started...");
|
||||||
}
|
}
|
||||||
file_name(){
|
async blob_convert(blob){
|
||||||
return 'noname';
|
return blob;
|
||||||
}
|
}
|
||||||
stop_recorder(){
|
stop_recorder(){
|
||||||
this.normal_stop = true;
|
this.normal_stop = true;
|
||||||
@ -147,11 +148,82 @@ bricks.SysAudioRecorder = class extends bricks.MediaRecorder {
|
|||||||
async open_recorder(){
|
async open_recorder(){
|
||||||
var options = {}
|
var options = {}
|
||||||
options.audio = true;
|
options.audio = true;
|
||||||
this.mimetype = 'audio/wav';
|
this.mimetype = 'audio/webm';
|
||||||
this.stream = await navigator.mediaDevices.getUserMedia(options);
|
this.stream = await navigator.mediaDevices.getUserMedia(options);
|
||||||
this.toggle_record.disabled(false);
|
this.toggle_record.disabled(false);
|
||||||
this.preview.disabled(true);
|
this.preview.disabled(true);
|
||||||
}
|
}
|
||||||
|
async blob_convert(webmBlob){
|
||||||
|
// 2. 解码 WebM → PCM
|
||||||
|
const arrayBuffer = await webmBlob.arrayBuffer();
|
||||||
|
const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
|
||||||
|
const decodedData = await audioCtx.decodeAudioData(arrayBuffer);
|
||||||
|
|
||||||
|
// 3. 转换为 WAV Blob
|
||||||
|
const wavBlob = this.encodeWAV(decodedData);
|
||||||
|
return wavBlob;
|
||||||
|
}
|
||||||
|
encodeWAV(audioBuffer) {
|
||||||
|
const numChannels = audioBuffer.numberOfChannels;
|
||||||
|
const sampleRate = audioBuffer.sampleRate;
|
||||||
|
const format = 1; // PCM
|
||||||
|
const bitDepth = 16;
|
||||||
|
|
||||||
|
// interleave channels
|
||||||
|
let result;
|
||||||
|
if (numChannels === 2) {
|
||||||
|
result = this.interleave(audioBuffer.getChannelData(0), audioBuffer.getChannelData(1));
|
||||||
|
} else {
|
||||||
|
result = audioBuffer.getChannelData(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// float → 16-bit PCM
|
||||||
|
const buffer = new ArrayBuffer(44 + result.length * 2);
|
||||||
|
const view = new DataView(buffer);
|
||||||
|
|
||||||
|
/* RIFF header */
|
||||||
|
this.writeString(view, 0, "RIFF");
|
||||||
|
view.setUint32(4, 36 + result.length * 2, true);
|
||||||
|
this.writeString(view, 8, "WAVE");
|
||||||
|
this.writeString(view, 12, "fmt ");
|
||||||
|
view.setUint32(16, 16, true);
|
||||||
|
view.setUint16(20, format, true);
|
||||||
|
view.setUint16(22, numChannels, true);
|
||||||
|
view.setUint32(24, sampleRate, true);
|
||||||
|
view.setUint32(28, sampleRate * numChannels * (bitDepth / 8), true);
|
||||||
|
view.setUint16(32, numChannels * (bitDepth / 8), true);
|
||||||
|
view.setUint16(34, bitDepth, true);
|
||||||
|
|
||||||
|
this.writeString(view, 36, "data");
|
||||||
|
view.setUint32(40, result.length * 2, true);
|
||||||
|
|
||||||
|
// PCM samples
|
||||||
|
let offset = 44;
|
||||||
|
for (let i = 0; i < result.length; i++, offset += 2) {
|
||||||
|
const s = Math.max(-1, Math.min(1, result[i]));
|
||||||
|
view.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true);
|
||||||
|
}
|
||||||
|
return new Blob([view], { type: "audio/wav" });
|
||||||
|
}
|
||||||
|
|
||||||
|
interleave(left, right) {
|
||||||
|
const length = left.length + right.length;
|
||||||
|
const result = new Float32Array(length);
|
||||||
|
|
||||||
|
let inputIndex = 0;
|
||||||
|
for (let i = 0; i < length;) {
|
||||||
|
result[i++] = left[inputIndex];
|
||||||
|
result[i++] = right[inputIndex];
|
||||||
|
inputIndex++;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
writeString(view, offset, string) {
|
||||||
|
for (let i = 0; i < string.length; i++) {
|
||||||
|
view.setUint8(offset + i, string.charCodeAt(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
bricks.SysVideoRecorder = class extends bricks.MediaRecorder {
|
bricks.SysVideoRecorder = class extends bricks.MediaRecorder {
|
||||||
async open_recorder(){
|
async open_recorder(){
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user