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 allocationfor (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 allocationreturn newData;}function linearInterpolate(before, after, atPoint) {return before + (after - before) * atPoint;}

修改导出wav函数exportWAV,增加采样率选项:

            /*** 导出wav* @param type* @param desiredSamplingRate 期望的采样率*/function exportWAV(type,desiredSamplingRate) {// 默认为16kdesiredSamplingRate = 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));}// 发送给workerthis.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 to 2049.
  • 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 are 8000, 12000, 16000, 24000 or 48000.
  • leaveStreamOpen - (optional) Keep the stream around when trying to stop recording, so you can re-start without re-initStream. Defaults to false.
  • 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 and 1. Defaults to 0
  • numberOfChannels - (optional) The number of channels to record. 1 = mono, 2 = stereo. Defaults to 1. Maximum 2 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 to 3.
  • streamPages - (optional) dataAvailable event will fire after each encoded page. Defaults to false.

推荐使用


作者:Jadepeng
出处:jqpeng的技术记事本--http://www.cnblogs.com/xiaoqi
您的支持是对博主最大的鼓励,感谢您的认真阅读。
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

转载于:https://www.cnblogs.com/xiaoqi/p/6993912.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/269191.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

关闭 MFC 界面程序控制台输出窗口

MFC 界面控制台界面窗口&#xff0c;在运行程序的时候会弹出来&#xff0c; 为了调试可以显示输出 printf 或 cout 信息&#xff0c;要关闭的话在程序入口处添加freeconsole() 函数进行设置。 避免多个窗口显示影响操作 CMainFrame::CMainFrame() {// TODO: 在此添加成员初始化…

SVN更新的时候报断言失败解决办法

解决办法&#xff1a;没啥好方法&#xff0c;重新检出代码就好使了。 转载于:https://www.cnblogs.com/yuanchaoyong/p/6999496.html

高德 ASIC 256 模组快门状态实时获取方案

1、快门状态命令 这个状态是由 ASIC 程序操作快门后记录的&#xff0c;如果是断电下的意外振动关闭是无法记录的 2、快门状态获取解决办法 根据快门闭合后的特征: 1) 温度均匀&#xff0c; 目标物体温度基本等于快门温度 2) 图像无轮廓线条和角点 3、快门状态实时检测线程 实…

C#委托

委托是一种引用方法的类型。委托定义出它想要代表的方法的原型&#xff0c;然后它可以和任何符合它所定义的方法的原型相关联。但使用委托时就犹如你在调用一个方法。委托使你动态的调用方法变成可能。而动态调用方法的意义就在于你可以在任意的地方插入任意的代码//using Syst…

JS 倒计时插件

剩余时间 <span class"djtime"><i id"t_h"></i><span>:</span><i id"t_m"></i><span>:</span><i id"t_s"></i></span></span> <script type"…

c++ 简单抽象工厂实现方法

实现基类 Shape实现 Shape 基类子类 两个实现创建子类对象的工厂类 #include <iostream> #include <map> using namespace std; class Shape //接口 { public:Shape() {cout << "Shape" << endl;}virtual ~Shape(){cout << "~Sh…

mysql使用 BETWEEN AND 查询

例子&#xff1a;查询1000到1020区间的数据 BETWEEN AND

在观念上进行大的转变

第二代 google排名搜索引擎虽然比第一代在搜索速度、针对多种语言信息的扩展等方面有所改进&#xff0c;在以自然语言为查询语言方面也做了一些探索。然而&#xff0c;随着Internet的强势发展&#xff0c;网上庞大的数字化信息和人们获取所需信息能力之间的矛盾日益突出。IDC在…

PHP 执行系统外部命令 system() exec() passthru()

PHP中调用外部命令&#xff0c;可以用如下三种方法来实现&#xff1a;方法一&#xff1a;用PHP提供的专门函数&#xff08;四个&#xff09;&#xff1a;PHP提供4个专门的执行外部命令的函数&#xff1a;exec(), system(), passthru(), shell_exec()1&#xff09;exec()原型: s…

mysql使用IS NULL查询null值

mysql使用IS NULL查询null值

Huawei S8512

用户不能在同一单板上同时设置组播抑制功能和广播抑制功能&#xff0c;即一旦某单板有端口设置为广播抑制&#xff0c;该单板其他端口也不能设置组播抑制&#xff0c;反之亦然。只有单板所有端口均设置为广播抑制或组播抑制的默认抑制值时&#xff0c;端口才能修改为不同抑制功…

Python---时间函数

在Python中日期和时间可能涉及多个不同的数据类型和函数&#xff0c;本文将简要介绍一下。 一. 三种不同的数据类型 1. 时间戳&#xff1a;Unix纪元时间戳&#xff08;time模块中使用&#xff09;是一个浮点值或整型值&#xff0c;表示子1970年1月1日午夜0点&#xff08;UTC&am…

click 模拟单击一个对象

document.all.LABELID.click()

Spring Security 入门(1-9)国际化的使用

转载于:https://www.cnblogs.com/lexiaofei/p/7016222.html

asp存储过程使用大全

1&#xff0c;调用没有参数的存储过程<%set connserver.CreateObject("adodb.connection")set cmdserver.CreateObject("adodb.command")strconn"dsnpubs;uidsa;pwd"conn.Open strconnset cmd.ActiveConnectionconncmd.CommandText"{cal…

html5 文档元素 header footer h1h2h4

文档元素: 用于在页面的大布局, 区分各个主体和概念. 让整体清晰, 元素有语义, 进一步代替div 具体划分图示: (参考) <hgroup> <section> <nav> <article> 里面又是一个可以添加<header\section\footer>的一整套的标签, 麻雀虽小五脏俱全 &l…