HTML5录音控件
最近的项目又需要用到录音,年前有过调研,再次翻出来使用,这里做一个记录。
HTML5提供了录音支持,因此可以方便使用HTML5来录音,来实现录音、语音识别等功能,语音开发必备。但是ES标准提供的API并不人性化,不方便使用,并且不提供保存为wav的功能,开发起来费劲啊!!
github寻找轮子,发现Recorder.js,基本上可以满足需求了,良好的封装,支持导出wav,但是存在:
- wav采样率不可调整
- recorder创建麻烦,需要自己初始化getUserMedia
- 无实时数据回调,不方便绘制波形
- 。。。
改造轮子
创建recorder工具方法
提供创建recorder工具函数,封装audio接口:
static createRecorder(callback,config){
window.AudioContext = window.AudioContext || window.webkitAudioContext;
window.URL = window.URL || window.webkitURL;
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
if (navigator.getUserMedia) {
navigator.getUserMedia(
{ audio: true } //只启用音频
, function (stream) {
var audio_context = new AudioContext;
var input = audio_context.createMediaStreamSource(stream);
var rec = new Recorder(input, config);
callback(rec);
}
, function (error) {
switch (error.code || error.name) {
case 'PERMISSION_DENIED':
case 'PermissionDeniedError':
throwError('用户拒绝提供信息。');
break;
case 'NOT_SUPPORTED_ERROR':
case 'NotSupportedError':
throwError('浏览器不支持硬件设备。');
break;
case 'MANDATORY_UNSATISFIED_ERROR':
case 'MandatoryUnsatisfiedError':
throwError('无法发现指定的硬件设备。');
break;
default:
throwError('无法打开麦克风。异常信息:' + (error.code || error.name));
break;
}
});
} else {
throwError('当前浏览器不支持录音功能。'); return;
}
}
采样率
H5录制的默认是44k的,文件大,不方便传输,因此需要进行重新采样,一般采用插值取点方法:
以下代码主要来自stackoverflow:
/**
* 转换采样率
* @param data
* @param newSampleRate 目标采样率
* @param oldSampleRate 原始数据采样率
* @returns {any[]|Array}
*/
function interpolateArray(data, newSampleRate, oldSampleRate) {
var fitCount = Math.round(data.length * (newSampleRate / oldSampleRate));
var newData = new Array();
var springFactor = new Number((data.length - 1) / (fitCount - 1));
newData[0] = data[0]; // for new allocation
for (var i = 1; i < fitCount - 1; i++) {
var tmp = i * springFactor;
var before = new Number(Math.floor(tmp)).toFixed();
var after = new Number(Math.ceil(tmp)).toFixed();
var atPoint = tmp - before;
newData[i] = this.linearInterpolate(data[before], data[after], atPoint);
}
newData[fitCount - 1] = data[data.length - 1]; // for new allocation
return newData;
}
function linearInterpolate(before, after, atPoint) {
return before + (after - before) * atPoint;
}
修改导出wav函数exportWAV,增加采样率选项:
/**
* 导出wav
* @param type
* @param desiredSamplingRate 期望的采样率
*/
function exportWAV(type,desiredSamplingRate) {
// 默认为16k
desiredSamplingRate = desiredSamplingRate || 16000;
var buffers = [];
for (var channel = 0; channel < numChannels; channel++) {
var buffer = mergeBuffers(recBuffers[channel], recLength);
// 需要转换采样率
if (desiredSamplingRate!=sampleRate) {
// 插值去点
buffer = interpolateArray(buffer, desiredSamplingRate, sampleRate);
}
buffers.push(buffer);
}
var interleaved = numChannels === 2 ? interleave(buffers[0], buffers[1]) : buffers[0];
var dataview = encodeWAV(interleaved,desiredSamplingRate);
var audioBlob = new Blob([dataview], { type: type });
self.postMessage({ command: 'exportWAV', data: audioBlob });
}
实时录音数据回调
为了方便绘制音量、波形图,需要获取到实时数据:
config新增一个回调函数onaudioprocess:
config = {
bufferLen: 4096,
numChannels: 1, // 默认单声道
mimeType: 'audio/wav',
onaudioprocess:null
};
修改录音数据处理函数:
this.node.onaudioprocess = (e) => {
if (!this.recording) return;
var buffer = [];
for (var channel = 0; channel < this.config.numChannels; channel++) {
buffer.push(e.inputBuffer.getChannelData(channel));
}
// 发送给worker
this.worker.postMessage({
command: 'record',
buffer: buffer
});
// 数据回调
if(this.config.onaudioprocess){
this.config.onaudioprocess(buffer[0]);
}
};
这样,在创建recorder时,配置onaudioprocess就可以获取到实时数据了
实时数据编码
编码计算耗时,需要放到worker执行:
接口函数新增encode,发送消息给worker,让worker执行:
encode(cb,buffer,sampleRate) {
cb = cb || this.config.callback;
if (!cb) throw new Error('Callback not set');
this.callbacks.encode.push(cb);
this.worker.postMessage({ command: 'encode',buffer:buffer,sampleRate:sampleRate});
}
worker里新增encode函数,处理encode请求,完成后执行回调
self.onmessage = function (e) {
switch (e.data.command) {
case 'encode':
encode(e.data.buffer,e.data.sampleRate);
break;
}
};
encode(cb,buffer,sampleRate) {
cb = cb || this.config.callback;
if (!cb) throw new Error('Callback not set');
this.callbacks.encode.push(cb);
this.worker.postMessage({ command: 'encode',buffer:buffer,sampleRate:sampleRate});
}
wav上传
增加一个上传函数:
exportWAVAndUpload(url, callback) {
var _url = url;
exportWAV(function(blob){
var fd = new FormData();
fd.append("audioData", blob);
var xhr = new XMLHttpRequest();
if (callback) {
xhr.upload.addEventListener("progress", function (e) {
callback('uploading', e);
}, false);
xhr.addEventListener("load", function (e) {
callback('ok', e);
}, false);
xhr.addEventListener("error", function (e) {
callback('error', e);
}, false);
xhr.addEventListener("abort", function (e) {
callback('cancel', e);
}, false);
}
xhr.open("POST", url);
xhr.send(fd);
})
}
完整代码
=点击下载
发现新轮子
今天再次看这个项目,发现这个项目已经不维护了,
Note: This repository is not being actively maintained due to lack of time and interest. If you maintain or know of a good fork, please let me know so I can direct future visitors to it. In the meantime, if this library isn't working, you can find a list of popular forks here: http://forked.yannick.io/mattdiamond/recorderjs.
作者推荐https://github.com/chris-rudmin/Recorderjs,提供更多的功能:
- bitRate (optional) Specifies the target bitrate in bits/sec. The encoder selects an application-specific default when this is not specified.
-
bufferLength - (optional) The length of the buffer that the internal JavaScriptNode uses to capture the audio. Can be tweaked if experiencing performance issues. Defaults to
4096
. -
encoderApplication - (optional) Specifies the encoder application. Supported values are
2048
- Voice,2049
- Full Band Audio,2051
- Restricted Low Delay. Defaults to2049
. -
encoderComplexity - (optional) Value between 0 and 10 which determines latency and processing for resampling.
0
is fastest with lowest complexity.10
is slowest with highest complexity. The encoder selects a default when this is not specified. -
encoderFrameSize (optional) Specifies the frame size in ms used for encoding. Defaults to
20
. -
encoderPath - (optional) Path to encoderWorker.min.js worker script. Defaults to
encoderWorker.min.js
-
encoderSampleRate - (optional) Specifies the sample rate to encode at. Defaults to
48000
. Supported values are8000
,12000
,16000
,24000
or48000
. -
leaveStreamOpen - (optional) Keep the stream around when trying to
stop
recording, so you can re-start
without re-initStream
. Defaults tofalse
. -
maxBuffersPerPage - (optional) Specifies the maximum number of buffers to use before generating an Ogg page. This can be used to lower the streaming latency. The lower the value the more overhead the ogg stream will incur. Defaults to
40
. -
monitorGain - (optional) Sets the gain of the monitoring output. Gain is an a-weighted value between
0
and1
. Defaults to0
-
numberOfChannels - (optional) The number of channels to record.
1
= mono,2
= stereo. Defaults to1
. Maximum2
channels are supported. -
originalSampleRateOverride - (optional) Override the ogg opus 'input sample rate' field. Google Speech API requires this field to be
16000
. -
resampleQuality - (optional) Value between 0 and 10 which determines latency and processing for resampling.
0
is fastest with lowest quality.10
is slowest with highest quality. Defaults to3
. -
streamPages - (optional)
dataAvailable
event will fire after each encoded page. Defaults tofalse
.
推荐使用
作者:Jadepeng 出处:jqpeng的技术记事本--http://www.cnblogs.com/xiaoqi 您的支持是对博主最大的鼓励,感谢您的认真阅读。 本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
- Git 简单命令,木有高深内容
- 基础篇章:React Native之 ScrollView 的讲解
- 常用 Git 命令清单
- 如何将配置spring文件指定名字,指定位置
- 基础篇章:React Native 之 TextInput 的讲解
- Linux下 标准错误输出重定向
- CentOs6.5 修改主机名
- 基础篇章:React Native 之 View 和 Text 的讲解
- CentOs7.3 修改主机名
- 基础篇章:React Native之Flexbox的讲解(Height and Width)
- PDF.js专题
- CentOs7.3 编译安装 Nginx 1.9.9
- 基础篇章:关于 React Native 之 RefreshControl 组件的讲解
- CentOs7.3 安装 JDK1.8
- HTML 教程
- HTML 简介
- html div 标签介绍
- html span 标签介绍
- html a 超链接标签
- HTML Br换行标签介绍
- HTML P段落标签介绍
- HTML br与p标签区别
- Html H 标题标签
- html px em pt长度单位
- HTML form 标签
- HTML radio 单选框
- HTML B 加粗标签
- HTML strong加粗粗体标签
- HTML em 强调标签
- HTML i 斜体标签
- HTML u下划线标签
- HTML s 删除线标签
- Html img 图片标签
- Html上标注sup与下标注sub标签
- HTML nobr 禁止换行标签
- HTML hr 水平线标签
- HTML label 标签
- HTML input 标签
- HTML textarea 标签
- HTML select下拉列表标签
- HTML checkbox 多选框
- HTML font color 标签
- HTML iframe 框架标签
- HTML Table 表格
- HTML dl dt dd 标签
- HTML ol li有序列表标签
- HTML ul li 无序列表标签
- HTML 注释
- CSS 教程
- CSS 简介
- CSS 语法
- CSS Id 和 Class选择器
- CSS 样式的创建
- CSS background 背景介绍
- CSS 文本样式
- CSS font 字体
- CSS A 链接
- CSS ul ol列表样式
- CSS TABLE 样式
- CSS 框模型
- CSS border 边框
- CSS Outlines 轮廓
- CSS 外边距 Margin
- CSS Padding 内边距
- CSS 分组和嵌套选择器
- CSS 尺寸 (Dimension)
- CSS Display 属性
- CSS Position 定位
- CSS Float 浮动
- CSS 水平对齐(Horizontal Align)
- CSS 组合选择符
- CSS 伪类
- CSS 伪元素
- CSS 导航栏
- CSS 下拉菜单
- CSS 图片廊
- CSS 图像透明/不透明
- CSS sprite 图像拼合技术
- CSS 媒体类型
- CSS 属性选择器
- CSS 实例
- Tiny85哒哒哒哒
- Tiny85哒哒哒
- Julia机器核心编程.多重分配
- 常用注解使用总结系列: @Order 注解
- Fake伪造数据集
- @EnableDiscoveryClient 注解如何实现服务注册与发现
- idea连接docker实现一键部署
- redis的过期策略和内存淘汰机制
- Redis主从复制原理总结
- redis cluster 的核心原理分析:gossip 通信、jedis smart 定位、主备切换
- SpringBoot自动装配原理解析
- 什么是CICD?
- Zabbix 5.0 LTS新功能一览
- 获取电脑真实的IP地址,忽略虚拟机等IP地址的干扰
- K8S系列之K8S集群之Master节点部署