为啥是尝试——由于如今我也没搞明白前端使用blob二进制储存音频究竟是个什么解析规则,网上实在找不到参考资料,彻底是本身一点一点试出来的,下面说我是怎么试的以及试出来的结果。javascript
三个<audio>标签,分别用来录音,正放和倒放,两个<button>分别用来开始录音和结束录音。html
首先我将二进制的blob转为了无符号Uint8Array数组,而后:前端
我天真的觉得把这个数组倒过来,而后再转回Blob,而后就能够播放了!java
结果固然是——门都没有!!!web
我发现我把他截取了数组前面的一部分,依然能够播放,可是单独放后面的,不可。数组
获得结论,这个数组前面有一段固定得长度用来表示这个是个音频文件(还有单声道呀,或者什么什么得,我也不太懂),而后我就对比了两个录音片断,你们公共的长度是多少呢——91(90以前两个音频数组都是是同样的),可是公共长度只是音频头(不循环的部分)的一部分,音频头是截止到160的(长度为161)ide
答:我也不知道ui
答:从161位开始的【163,65,X,129】,我发现这个东西在后面重复出现了,并且出现下一个这个的间隔等于X+259,那么我就大胆推测——这个就是表明声音的一个最小单位的开始。spa
咱们倒置的最小单位是以【163,65,X,129.......】开头的数组段(其中X是这段数组的长度),10个数组段播放时间是0.48s,可是16个数组段播放时间是从0.78s到0.9s不等,因此说并非一个代码块记录了固定多少毫秒的时间(这不是我定义的,用官方方法把blob音频转为数组而后他就这样,我也没什么办法)插件
而后我就开始,在保留代码头的状况下,把从一个【163,65,X,129】到另外一个【163,65,X,129】之间的代码做为最小单位S,而后在保持最小单位S内的代码顺序不变,将全部最小单位的排序顺序倒置了(从S_1,S_2,S_3,.....,S_n变成S_n,S_n-1,.....,S_1)
而后结果固然是——仍是不行。
而后我将每一个都倒放变成了把5个S看成一个总体,再倒放,成功了!我本身读的123456变成了654321!可是那个音频条不能拖动,一直是在最后一秒。以下图这样播完4s。
这我能忍么!确定不能,音频条不能拖动是个什么玩应儿!而后我把数组的前一半倒置了,后一半不倒置,结果点击播放那一刻,6秒的音频是从3s开始的,持续了3s(一直显示0:03),音频正常播放到了6s(由于后三秒没倒置),那么我以为,应该是有个东西记录了时间。那么咱们往下看,发现了一些规律(输出的分别是,X,【163,65,X,129】中65的位置,后面接着的四位),直觉告诉我,这个递增的两位,就是记录了时间!
而后我就循环将每一段的这两位更改成递增,播放时即是从零秒开始的,逐渐增长直到最后一秒,如今的代码,有的能够倒放,有的不行(8s的原音频倒放后变成了4s或者5s反正就是变短了),缘由还未知,因此写着未完成。。。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script>
let recorder
function start() {
let videoTarget = document.getElementById('audio')
navigator.mediaDevices.getUserMedia({audio: true, video: false})
.then((stream) => {
recorder = new MediaRecorder(stream)
videoTarget.srcObject = stream
//s用来标记这是否找到了代码头
let s = 0
recorder.ondataavailable = (event) => {
let blob = event.data
let videoTarget2 = document.getElementById('audio2')
let videoTarget3 = document.getElementById('audio3')
let a = blob.stream().getReader()
a.read().then(({ done, value }) => {
let newValue = [] //用来存放倒置后的新数组
let r = 0 //r表明指针记录新数组插入元素的位置
let b = 0 //b用来记录这是第几个S(S是咱们上面提到的最小音频单位)
for(i = 0; i < value.length; i++) {
if(value[i] === 163){
//s=1表示进入戒备状态
s = 1
} else if(s === 1 && value[i] === 65) {
//在戒备状态的条件下value[i] === 65说明的确是开始了新的一段最小单位的音频
b === 5 ? (r = 162,b = 0) : b++
//这里b===5是能够改的,我定的是5个S做为一个总体倒置,由于每一个S持续时间过短了,一个S一倒置放出来的音频效果不好
//r=162是将指针移到162也就是出去音频头最先开始循环的位置,这样咱们就完成了倒置,打完5个S就把指针移回最开始继续打
} else {
//value[i] !== 65说明只是凑巧,并非找到了代码头,咱们再将s标示置为0
s = 0
}
//在指针位置插入元素
newValue.splice(r, 0, value[i])
//指针后移
r++
}
b = 0
//咱们如今获得的数组就是第三次尝试时的到的数组,播放时一直显示最后一秒
newValue.splice(r, 0, 163)
//删掉最后一个元素是由于上面指针后移操做会使数组最后多一个163(戒备状态那个判断用到的163)
newValue.pop()
//而后咱们就要将音频最小单位S的代码头后面两位变成0 0, 0 60,0 120....
for(i = 0; i < newValue.length; i++) {
if(newValue[i] == 163){
s = 1
} else if(s == 1 && newValue[i] == 65) {
//获得的规律是每次后面加60,可是若是超过了256就要进位,前面加1
newValue[i+3] = parseInt(b * 60 / 256)
newValue[i+4] = b * 60 % 256
b++
console.log(i, newValue[i+3], newValue[i+4])
} else {
s = 0
}
}
console.log(newValue)
console.log(value)
//而后再将新数组转成blob赋给audio就可播放了
newValue = new Uint8Array(newValue)
let blob2 = new Blob([newValue], {type: 'audio/webm;codecs=opus'})
videoTarget2.src = window.URL.createObjectURL(blob2)
let blob3 = new Blob([value], {type: 'audio/webm;codecs=opus'})
videoTarget3.src = window.URL.createObjectURL(blob3)
})
}
recorder.start()
});
}
function stop() {
document.getElementById('audio').pause()
recorder.stop()
}
</script>
</head>
<body>
<audio id="audio" controls autoplay></audio>录音(不用点它去点开始和结束)
<audio id="audio2" controls autoplay></audio>倒放
<audio id="audio3" controls></audio>正放
<input onclick="start()" type="button" value="开始" />
<input onclick="stop()" type="button" value="结束" />
</body>
</html>
复制代码