vue实现录音功能js-audio-recorder带波浪图效果的示例

前言:

因为业务需要,现在将整理的录音功能资料记录下,使用插件js-audio-recorder

实现效果:可得到三种录音数据,pcm,wav,mp3 等

vue实现录音功能js-audio-recorder带波浪图效果的示例

vue实现录音功能js-audio-recorder带波浪图效果的示例

官方api入口:点我(网不好的童鞋可以看最下面的api截图)

官方案例入口:点我

官方源码git入口:点我

实现步骤:

一:安装插件 js-audio-recorder

1
cnpm i js-audio-recorder --s

二:安装将格式转换为mp3的插件 lamejs

1
cnpm install lamejs --s

三:附上实现源码:

提示:慎用自身的这个监听事件,可以拿到数据,但是每秒拿到的数据非常多

vue实现录音功能js-audio-recorder带波浪图效果的示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
<template>
  <div class="home" style="margin:1vw;">
    <Button type="success" @click="getPermission()" style="margin:1vw;">获取麦克风权限</Button>
    <br/>
    <Button type="info" @click="startRecorder()"  style="margin:1vw;">开始录音</Button>
    <Button type="info" @click="resumeRecorder()" style="margin:1vw;">继续录音</Button>
    <Button type="info" @click="pauseRecorder()" style="margin:1vw;">暂停录音</Button>
    <Button type="info" @click="stopRecorder()" style="margin:1vw;">结束录音</Button>
    <br/>
    <Button type="success" @click="playRecorder()" style="margin:1vw;">录音播放</Button>
    <Button type="success" @click="pausePlayRecorder()" style="margin:1vw;">暂停录音播放</Button>
    <Button type="success" @click="resumePlayRecorder()" style="margin:1vw;">恢复录音播放</Button>
    <Button type="success" @click="stopPlayRecorder()" style="margin:1vw;">停止录音播放</Button>
    <br/>
    <Button type="info" @click="getRecorder()" style="margin:1vw;">获取录音信息</Button>
    <Button type="info" @click="downPCM()" style="margin:1vw;">下载PCM</Button>
    <Button type="info" @click="downWAV()" style="margin:1vw;">下载WAV</Button>
    <Button type="info" @click="getMp3Data()" style="margin:1vw;">下载MP3</Button>
    <br/>
    <Button type="error" @click="destroyRecorder()" style="margin:1vw;">销毁录音</Button>
    <br/>
    <div style="width:100%;height:200px;border:1px solid red;">
      <canvas id="canvas"></canvas>
      <span style="padding: 0 10%;"></span>
      <canvas id="playChart"></canvas>
    </div>
  </div>
</template>
<script>
  import Recorder from 'js-audio-recorder'
  const lamejs = require('lamejs')
  const recorder = new Recorder({
    sampleBits: 16,                 // 采样位数,支持 8 或 16,默认是16
    sampleRate: 48000,              // 采样率,支持 11025、16000、22050、24000、44100、48000,根据浏览器默认值,我的chrome是48000
    numChannels: 1,                 // 声道,支持 1 或 2, 默认是1
    // compiling: false,(0.x版本中生效,1.x增加中)  // 是否边录边转换,默认是false
  })
  // 绑定事件-打印的是当前录音数据
  recorder.onprogress = function(params) {
    // console.log('--------------START---------------')
    // console.log('录音时长(秒)', params.duration);
    // console.log('录音大小(字节)', params.fileSize);
    // console.log('录音音量百分比(%)', params.vol);
    // console.log('当前录音的总数据([DataView, DataView...])', params.data);
    // console.log('--------------END---------------')
  }
  export default {
    name: 'home',
    data () {
      return {
        //波浪图-录音
        drawRecordId:null,
        oCanvas : null,
        ctx : null,
        //波浪图-播放
        drawPlayId:null,
        pCanvas : null,
        pCtx : null,
      }
    },
    mounted(){
      this.startCanvas();
    },
    methods: {
      /**
       * 波浪图配置
       * */
      startCanvas(){
        //录音波浪
        this.oCanvas = document.getElementById('canvas');
        this.ctx = this.oCanvas.getContext("2d");
        //播放波浪
        this.pCanvas = document.getElementById('playChart');
        this.pCtx = this.pCanvas.getContext("2d");
      },
      /**
       *  录音的具体操作功能
       * */
      // 开始录音
      startRecorder () {
        recorder.start().then(() => {
          this.drawRecord();//开始绘制图片
        }, (error) => {
          // 出错了
          console.log(`${error.name} : ${error.message}`);
        });
      },
      // 继续录音
      resumeRecorder () {
        recorder.resume()
      },
      // 暂停录音
      pauseRecorder () {
        recorder.pause();
        this.drawRecordId && cancelAnimationFrame(this.drawRecordId);
        this.drawRecordId = null;
      },
      // 结束录音
      stopRecorder () {
        recorder.stop()
        this.drawRecordId && cancelAnimationFrame(this.drawRecordId);
        this.drawRecordId = null;
      },
      // 录音播放
      playRecorder () {
        recorder.play();
        this.drawPlay();//绘制波浪图
      },
      // 暂停录音播放
      pausePlayRecorder () {
        recorder.pausePlay()
      },
      // 恢复录音播放
      resumePlayRecorder () {
        recorder.resumePlay();
        this.drawPlay();//绘制波浪图
      },
      // 停止录音播放
      stopPlayRecorder () {
        recorder.stopPlay();
      },
      // 销毁录音
      destroyRecorder () {
        recorder.destroy().then(function() {
          recorder = null;
          this.drawRecordId && cancelAnimationFrame(this.drawRecordId);
          this.drawRecordId = null;
        });
      },
      /**
       *  获取录音文件
       * */
      getRecorder(){
        let toltime = recorder.duration;//录音总时长
        let fileSize = recorder.fileSize;//录音总大小
        //录音结束,获取取录音数据
        let PCMBlob = recorder.getPCMBlob();//获取 PCM 数据
        let wav = recorder.getWAVBlob();//获取 WAV 数据
        let channel = recorder.getChannelData();//获取左声道和右声道音频数据
      },
      /**
       *  下载录音文件
       * */
      //下载pcm
      downPCM(){
        //这里传参进去的时文件名
        recorder.downloadPCM('新文件');
      },
      //下载wav
      downWAV(){
        //这里传参进去的时文件名
        recorder.downloadWAV('新文件');
      },
      /**
       *  获取麦克风权限
       * */
      getPermission(){
        Recorder.getPermission().then(() => {
          this.$Message.success('获取权限成功')
        }, (error) => {
          console.log(`${error.name} : ${error.message}`);
        });
      },
      /**
       * 文件格式转换 wav-map3
       * */
      getMp3Data(){
        const mp3Blob = this.convertToMp3(recorder.getWAV());
        recorder.download(mp3Blob, 'recorder', 'mp3');
      },
      convertToMp3(wavDataView) {
        // 获取wav头信息
        const wav = lamejs.WavHeader.readHeader(wavDataView); // 此处其实可以不用去读wav头信息,毕竟有对应的config配置
        const { channels, sampleRate } = wav;
        const mp3enc = new lamejs.Mp3Encoder(channels, sampleRate, 128);
        // 获取左右通道数据
        const result = recorder.getChannelData()
        const buffer = [];
        const leftData = result.left && new Int16Array(result.left.buffer, 0, result.left.byteLength / 2);
        const rightData = result.right && new Int16Array(result.right.buffer, 0, result.right.byteLength / 2);
        const remaining = leftData.length + (rightData ? rightData.length : 0);
        const maxSamples = 1152;
        for (let i = 0; i < remaining; i += maxSamples) {
          const left = leftData.subarray(i, i + maxSamples);
          let right = null;
          let mp3buf = null;
          if (channels === 2) {
            right = rightData.subarray(i, i + maxSamples);
            mp3buf = mp3enc.encodeBuffer(left, right);
          } else {
            mp3buf = mp3enc.encodeBuffer(left);
          }
          if (mp3buf.length > 0) {
            buffer.push(mp3buf);
          }
        }
        const enc = mp3enc.flush();
        if (enc.length > 0) {
          buffer.push(enc);
        }
        return new Blob(buffer, { type: 'audio/mp3' });
      },
      /**
       * 绘制波浪图-录音
       * */
      drawRecord () {
        // 用requestAnimationFrame稳定60fps绘制
        this.drawRecordId = requestAnimationFrame(this.drawRecord);
        // 实时获取音频大小数据
        let dataArray = recorder.getRecordAnalyseData(),
            bufferLength = dataArray.length;
        // 填充背景色
        this.ctx.fillStyle = 'rgb(200, 200, 200)';
        this.ctx.fillRect(0, 0, this.oCanvas.width, this.oCanvas.height);
        // 设定波形绘制颜色
        this.ctx.lineWidth = 2;
        this.ctx.strokeStyle = 'rgb(0, 0, 0)';
        this.ctx.beginPath();
        var sliceWidth = this.oCanvas.width * 1.0 / bufferLength, // 一个点占多少位置,共有bufferLength个点要绘制
                x = 0;          // 绘制点的x轴位置
        for (var i = 0; i < bufferLength; i++) {
          var v = dataArray[i] / 128.0;
          var y = v * this.oCanvas.height / 2;
          if (i === 0) {
            // 第一个点
            this.ctx.moveTo(x, y);
          } else {
            // 剩余的点
            this.ctx.lineTo(x, y);
          }
          // 依次平移,绘制所有点
          x += sliceWidth;
        }
        this.ctx.lineTo(this.oCanvas.width, this.oCanvas.height / 2);
        this.ctx.stroke();
      },
      /**
       * 绘制波浪图-播放
       * */
      drawPlay () {
        // 用requestAnimationFrame稳定60fps绘制
        this.drawPlayId = requestAnimationFrame(this.drawPlay);
        // 实时获取音频大小数据
        let dataArray = recorder.getPlayAnalyseData(),
                bufferLength = dataArray.length;
        // 填充背景色
        this.pCtx.fillStyle = 'rgb(200, 200, 200)';
        this.pCtx.fillRect(0, 0, this.pCanvas.width, this.pCanvas.height);
        // 设定波形绘制颜色
        this.pCtx.lineWidth = 2;
        this.pCtx.strokeStyle = 'rgb(0, 0, 0)';
        this.pCtx.beginPath();
        var sliceWidth = this.pCanvas.width * 1.0 / bufferLength, // 一个点占多少位置,共有bufferLength个点要绘制
                x = 0;          // 绘制点的x轴位置
        for (var i = 0; i < bufferLength; i++) {
          var v = dataArray[i] / 128.0;
          var y = v * this.pCanvas.height / 2;
          if (i === 0) {
            // 第一个点
            this.pCtx.moveTo(x, y);
          } else {
            // 剩余的点
            this.pCtx.lineTo(x, y);
          }
          // 依次平移,绘制所有点
          x += sliceWidth;
        }
        this.pCtx.lineTo(this.pCanvas.width, this.pCanvas.height / 2);
        this.pCtx.stroke();
      }
    },
  }
</script>
<style lang='less' scoped>
</style>

到这里,代码就结束了,上面每个方法都有很详细的注释,就不累赘了

整理api:(有代理的可以看官网,这里是摘取官网的api)

1,使用

安装

npm 方式

推荐使用npm安装的方式:

安装:

1
npm i js-audio-recorder

调用:

1
2
import Recorder from 'js-audio-recorder';
let recorder = new Recorder();

script 标签方式

1
2
<script type="text/javascript" src="./dist/recorder.js"></script>
let recorder = new Recorder();

2,属性

实例初始化

可以配置输出数据参数,

1
2
3
4
5
6
let recorder = new Recorder({
    sampleBits: 16,                 // 采样位数,支持 8 或 16,默认是16
    sampleRate: 16000,              // 采样率,支持 11025、16000、22050、24000、44100、48000,根据浏览器默认值,我的chrome是48000
    numChannels: 1,                 // 声道,支持 1 或 2, 默认是1
    // compiling: false,(0.x版本中生效,1.x增加中)  // 是否边录边转换,默认是false
});

返回: recorder实例。

sampleBits

采样位数。

sampleRate

采样率。

numChannels

声道数。

compiling

(0.x版本中生效,最新目前不支持)

是否边录音边转换。

获取数据方法:

回调方式

1
2
3
recorder.onprogress = function(params) {
    console.log(params.data);       // 当前获取到到音频数据
}

data,DataView型数组,格式如 [DataView, DataView, DataView …] 。

主动获取

1
2
getWholeData();     // [DataView, DataView, DataView ...]
getNextData();      // [DataView, DataView, DataView ...]

getWholeData() 的值和onprogress回调中的data数据一致。

getNextData() 获取的是前一次 getNextData() 之后的值,他只是data数据的一小部分。

实例属性

duration

获取录音的总时长。

1
console.log(recorder.duration);

fileSize

录音文件大小(单位:字节)。

1
console.log(recorder.fileSize);

3,操作

start()

开始录音。

返回: Promise。

1
2
3
4
5
6
recorder.start().then(() => {
    // 开始录音
}, (error) => {
    // 出错了
    console.log(`${error.name} : ${error.message}`);
});

pause()

录音暂停。

返回: void

1
recorder.pause();

resume()

继续录音。

返回: void。

1
recorder.resume()

stop()

结束录音。

返回: void。

1
recorder.stop();

play()

录音播放。

返回: void。

1
recorder.play();

getPlayTime()

获取音频已经播的时长。

返回: number。

1
recorder.getPlayTime();

pausePlay()

暂停录音播放。

返回: void。

1
recorder.pausePlay();

resumePlay()

恢复录音播发。

返回: void。

1
recorder.resumePlay();

stopPlay()

停止播放。

返回: void。

1
recorder.stopPlay();

destroy()

销毁实例。

返回: Promise。

1
2
3
4
// 销毁录音实例,置为null释放资源,fn为回调函数,
recorder.destroy().then(function() {
    recorder = null;
});

音频数据

录音结束,获取取录音数据

getPCMBlob()

获取 PCM 数据,在录音结束后使用。

返回: Blob

注:使用该方法会默认调用 stop() 方法。

1
recorder.getPCMBlob();

getWAVBlob()

获取 WAV 数据,在录音结束后使用

返回: Blob

注:使用该方法会默认调用 stop() 方法。

1
recorder.getWAVBlob();

getChannelData()

获取左声道和右声道音频数据。

1
recorder.getChannelData();

录音结束,下载录音文件

downloadPCM([ filename ])

下载 PCM 格式

  • fileName String 重命名文件
  • 返回: Blob

注:使用该方法会默认调用 stop() 方法。

1
recorder.downloadPCM(fileName ?);

downloadWAV([ filename ])

下载 WAV 格式

  • fileName String 重命名文件
  • 返回: Blob

注:使用该方法会默认调用 stop() 方法。

录音中,获取录音数据

(0.x版本中生效,最新目前不支持)

该方式为边录边转换,建议在 compiling 为 true 时使用。

getWholeData()

获取已经录音的所有数据。若没有开启边录边转(compiling为false),则返回是空数组。

返回: Array, 数组中是DataView数据

定时获取所有数据:

1
2
3
setInterval(() => {
    recorder.getWholeData();
}, 1000)

getNextData()

获取前一次 getNextData() 之后的数据。若没有开启边录边转(compiling为false),则返回是空数组。

  • 返回: Array, 数组中是DataView数据

定时获取新增数据:

1
2
3
4
setInterval(() => {
    recorder.getNextData();
}, 1000)
// 实时录音,则可将该数据返回给服务端。

录音波形显示

getRecordAnalyseData()

返回的是一个1024长的,0-255大小的Uint8Array类型。用户可以根据这些数据自定义录音波形。此接口获取的是录音时的。

1
let dataArray = recorder.getRecordAnalyseData();

getPlayAnalyseData()

返回数据同 getRecordAnalyseData(),该方法获取的是播放时的。

1
let dataArray = recorder.getPlayAnalyseData();

播放外部

Player.play(blob)

播放外部音频,格式由浏览器的audio支持的类型决定。

1
Player.play(/* 放入arraybuffer数据 */);

其他

录音权限

未给予录音权限的页面在开始录音时需要再次点击允许录音,才能真正地录音,存在丢失开始这一段录音的情况,增加方法以便用户提前获取麦克风权限。

getPermission()

获取麦克风权限。

返回:promise。

1
2
3
4
5
Recorder.getPermission().then(() => {
    console.log('给权限了');
}, (error) => {
    console.log(`${error.name} : ${error.message}`);
});

此处then回调与start的一致。

4,Event

js-audio-recorder 支持的事件回调。

onprocess(duration)

用于获取录音时长。

不推荐使用,用onprogress代替。

1
2
3
recorder.onprocess = function(duration) {
    console.log(duration);
}

onprogress(duration)

目前支持获取以下数据:

  • 录音时长(duration)。
  • 录音大小(fileSize)。
  • 录音音量百分比(vol)。
  • 所有的录音数据(data)。
1
2
3
4
5
6
recorder.onprogress = function(params) {
    console.log('录音时长(秒)', params.duration);
    console.log('录音大小(字节)', params.fileSize);
    console.log('录音音量百分比(%)', params.vol);
    // console.log('当前录音的总数据([DataView, DataView...])', params.data);
}

onplay

录音播放开始回调。

1
2
3
recorder.onplay = () => {
    console.log('onplay')
}

onpauseplay

录音播放暂停回调。

1
2
3
recorder.onpauseplay = () => {
    console.log('onpauseplay')
}

onresumeplay

录音播放恢复回调。

1
2
3
recorder.onresumeplay = () => {
    console.log('onresumeplay')
}

onstopplay

录音播放停止回调。

1
2
3
recorder.onstopplay = () => {
    console.log('onstopplay')
}

onplayend

录音播放完成回调。

1
2
3
recorder.onplayend = () => {
    console.log('onplayend')
}

5,应用

语音识别

recorder上可以测试,注意选择16000采样率,16采样位数,单声道录音。

6,PlayerPlayer 播放类

1
import Player from './player/player';

用于协助播放录音文件,包括,开始、暂停、恢复、停止等功能。所支持的格式由浏览器的audio支持的类型决定。可单独使用。

Player.play([arraybuffer])

播放外部的音频。所支持的格式由浏览器的audio支持的类型决定。

实际是调用了decodeAudioData实现音频播放。

1
Recorder.play(/* 放入arraybuffer数据 */);

Player.pausePlay()

暂停播放。

Player.resumePlay()

恢复播放。

Player.stopPlay()

停止播放。

Player.addPlayEnd(fn)

增加播放完成回调函数。

Player.getPlayTime()

获取播放时间。

Player.getAnalyseData()

获取回放录音的波形数据。

7,其他音频格式

MP3

将pcm(wav)音频文件转化为mp3格式。

注:使用16采样位数。

利用lamejs进行转换,使用情况见demo,例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
function convertToMp3(wavDataView) {
    // 获取wav头信息
    const wav = lamejs.WavHeader.readHeader(wavDataView); // 此处其实可以不用去读wav头信息,毕竟有对应的config配置
    const { channels, sampleRate } = wav;
    const mp3enc = new lamejs.Mp3Encoder(channels, sampleRate, 128);
    // 获取左右通道数据
    const result = recorder.getChannelData()
    const buffer = [];
 
    const leftData = result.left && new Int16Array(result.left.buffer, 0, result.left.byteLength / 2);
    const rightData = result.right && new Int16Array(result.right.buffer, 0, result.right.byteLength / 2);
    const remaining = leftData.length + (rightData ? rightData.length : 0);
 
    const maxSamples = 1152;
    for (let i = 0; i < remaining; i += maxSamples) {
        const left = leftData.subarray(i, i + maxSamples);
        let right = null;
        let mp3buf = null;
 
        if (channels === 2) {
            right = rightData.subarray(i, i + maxSamples);
            mp3buf = mp3enc.encodeBuffer(left, right);
        } else {
            mp3buf = mp3enc.encodeBuffer(left);
        }
 
        if (mp3buf.length > 0) {
            buffer.push(mp3buf);
        }
    }
 
    const enc = mp3enc.flush();
 
    if (enc.length > 0) {
        buffer.push(enc);
    }
 
    return new Blob(buffer, { type: 'audio/mp3' });
}

安装lamejs

1
npm install lamejs

到此这篇关于vue实现录音功能js-audio-recorder带波浪图效果的示例的文章就介绍到这了,更多相关vue js-audio-recorder录音内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

源地址:vue实现录音功能js-audio-recorder带波浪图效果的示例_vue.js_脚本之家 (jb51.net)

给TA打赏
共{{data.count}}人
人已打赏
vue

The engine “node“ is incompatible with this module.

2022-11-9 15:06:43

vue

盘点 6 个开源的音乐播放器!

2022-11-11 12:31:59

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索