缘起

因公司业务需要在网页录音功能,因为h5的api兼容限制不得想出一些解决方案,以下是总结。

首发

https://shudong.wang/10585.html

demo测试地址

https://wsdo.github.io/recording/

项目地址

https://github.com/wsdo/recording

Q&A

后续继续完善,有这个需求的朋友可以继续讨论

调查

  • 百度语音识别

感觉百度够强大,肯定有完美的解决方案,最终发现在移动端网页打开百度语音直接跳转让下载app(说明不支持)

  • 谷歌语音识别

在不支持的机型上面不显示语音识别按钮

兼容性

h5录音主要使用AudioContext 和 getUserMedia 兼容性还是很差的,尤其是在移动端。

AudioContext

getUserMedia

真机测试结果: (测试部分,旁边同事的手机和公司的测试机,和自己的手机)

可以使用的:(最新版本,常用)
pc safari 支持
ios Safari 支持
安卓
小米5 微信里面可以使用
小米5 Chrome 最新版可以使用
小米5 uc可以使用

不可以使用的
ios Chrome 到这出了问题 webkitAudioContext.createScriptProcessor
ios 微信里面不支持
小米5 自带浏览器不可以
华为自带浏览器不可以

解决方案

考虑到手机端微信里面使用场景比较多

  • 针对微信专门写一套解决方案,借用微信的jssdk 的api,这样可以解决大部分在微信里面使用的场景
  • 兼容的手机:正常使用
  • 不兼容的手机:提示 推荐浏览器

操作过程

先了解一下简介和历史吧

简介

长久以来,音频/视频捕获都是网络开发中的“圣杯”。
多年来,我们总是依赖于浏览器插件(Flash 或 Silverlight)实现这一点。快来看看吧!

现在轮到 HTML5 大显身手了。也许看起来不是很显眼,但是 HTML5 的崛起引发了对设备硬件访问的激增。
地理位置 (GPS)、Orientation API(加速计)、WebGL (GPU) 和 Web Audio API(视频硬件)都是很好的例子。
这些功能非常强大,展示了基于系统底层硬件功能之上的高级 JavaScript API。

本教程介绍了一种新 API:navigator.getUserMedia(),可让网络应用访问用户的相机和麦克风。

了解 getUserMedia() 的历史 (节选 Capturing Audio & Video in HTML5)

如果您还不知道,getUserMedia() 的历史可谓一段有趣的故事。

过去几年中出现过好几种“Media Capture API”的变体。很多人意识到,需要能够在网络上访问本地设备,但这要所有人合力开发出一种新的规范。局面一片混乱,以至于 W3C 最终决定成立一个工作组。他们只有一个目的:理清混乱的局面!设备 API 政策 (DAP) 工作组负责对过剩的提议进行统一和标准化。

我会试着总结一下 2011 所发生的事情…

第 1 轮:HTML 媒体捕获

HTML 媒体捕获是 DAP 在网络媒体捕获标准化上迈出的第一步。具体方法是超载 并为 accept 参数添加新值。

如果您要让用户通过网络摄像头拍摄自己的快照,就可以使用 capture=camera:

<input type="file" accept="image/*;capture=camera">

录制视频或音频也是类似的:

<input type="file" accept="video/*;capture=camcorder">
<input type="file" accept="audio/*;capture=microphone">

第 2 轮:设备元素

很多人认为 HTML 媒体捕获的局限性太大,因此一种新的规范应运而生,可以支持任何类型的(未来)设备。不出意料地,该设计需要新的 元素,也就是 getUserMedia() 的前身。

Opera 是第一批根据 元素创建视频捕获的初始实施的浏览器之一。不久之后(准确地说是同一天),WhatWG 决定废止 标记,以支持称为 navigator.getUserMedia() 的新兴 JavaScript API。一周后,Opera 推出的新版本中加入了对更新的 getUserMedia() 规范的支持。当年年底,Microsoft 也加入这一行列,发布了 IE9 实验室以支持新规范。

<device type="media" onchange="update(this.data)"></device>
<video autoplay></video>
<script>function update(stream) {document.querySelector('video').src = stream.url;}
</script>

很遗憾,已发布的浏览器中没有任何一款曾经包含 。我猜这是一个不太需要担心的 API。但是 确实有两大优点:一是语义方面,二是可以轻松进行扩展,而不仅仅是支持音频/视频设备。

现在深吸一口气。这玩意儿速度飞快!

第 3 轮:WebRTC 这就是今天讨论的重点了

元素最终还是像渡渡鸟一样销声匿迹了。

依靠 WebRTC(网络即时通信)的大力协助,最近几个月寻找合适捕获 API 的步伐加快了很多。该规范由 W3C WebRTC 工作组负责监管。Google、Opera、Mozilla 和其他一些公司目前正致力于在自己的浏览器中实施该 API。

getUserMedia() 与 WebRTC 相关,因为它是通向这组 API 的门户。它提供了访问用户本地相机/麦克风媒体流的手段。

支持:

在 Chrome 浏览器 18.0.1008 和更高版本中,可在 about:flags 下启用 WebRTC。

实战 (尽量实现多浏览器兼容)

思路

主要使用 AudioContext 和 getUserMedia 这个api 来操作

AudioContext

AudioContext接口表示由音频模块连接而成的音频处理图,每个模块对应一个AudioNode。AudioContext可以控制它所包含的节点的创建,以及音频处理、解码操作的执行。做任何事情之前都要先创建AudioContext对象,因为一切都发生在这个环境之中。

可以来这里了解
https://developer.mozilla.org/zh-CN/docs/Web/API/AudioContext

getUserMedia

MediaDevices.getUserMedia() 会提示用户给予使用媒体输入的许可,媒体输入会产生一个MediaStream,里面包含了请求的媒体类型的轨道。此流可以包含一个视频轨道(来自硬件或者虚拟视频源,比如相机、视频采集设备和屏幕共享服务等等)、一个音频轨道(同样来自硬件或虚拟音频源,比如麦克风、A/D转换器等等),也可能是其它轨道类型。

它返回一个 Promise 对象,成功后会resolve回调一个 MediaStream 对象。若用户拒绝了使用权限,或者需要的媒体源不可用,promise会reject回调一个 PermissionDeniedError 或者 NotFoundError 。

可以来这里了解
https://developer.mozilla.org/zh-CN/docs/Web/API/MediaDevices/getUserMedia

兼容浏览器

引入 adapter (在旧的浏览器中使用新的API)

<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>

这是一个使用 navigator.mediaDevices.getUserMedia()的例子,带一个polyfill以适应旧的浏览器。 要注意的是这个polyfill并不能修正一些约束语法上的遗留差异,这表示约束在某些浏览器上可能不会很好地运行。推荐使用处理了约束的 adapter.js polyfill 来替代。
https://github.com/webrtc/adapter

/ 老的浏览器可能根本没有实现 mediaDevices,所以我们可以先设置一个空的对象
if (navigator.mediaDevices === undefined) {navigator.mediaDevices = {};
}// 一些浏览器部分支持 mediaDevices。我们不能直接给对象设置 getUserMedia
// 因为这样可能会覆盖已有的属性。这里我们只会在没有getUserMedia属性的时候添加它。
if (navigator.mediaDevices.getUserMedia === undefined) {navigator.mediaDevices.getUserMedia = function(constraints) {// 首先,如果有getUserMedia的话,就获得它var getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia;// 一些浏览器根本没实现它 - 那么就返回一个error到promise的reject来保持一个统一的接口if (!getUserMedia) {return Promise.reject(new Error('getUserMedia is not implemented in this browser'));}// 否则,为老的navigator.getUserMedia方法包裹一个Promisereturn new Promise(function(resolve, reject) {getUserMedia.call(navigator, constraints, resolve, reject);});}
}navigator.mediaDevices.getUserMedia({ audio: true, video: true })
.then(function(stream) {var video = document.querySelector('video');// 旧的浏览器可能没有srcObjectif ("srcObject" in video) {video.srcObject = stream;} else {// 防止再新的浏览器里使用它,应为它已经不再支持了video.src = window.URL.createObjectURL(stream);}video.onloadedmetadata = function(e) {video.play();};
})
.catch(function(err) {console.log(err.name + ": " + err.message);
});

检测AudioContext

function audioContextCheck() {if (typeof window.AudioContext !== "undefined") {console.log('AudioContext');return new window.AudioContext();} else if (typeof webkitAudioContext !== "undefined") {console.log('webkitAudioContext');return new window.webkitAudioContext();} else if (typeof window.mozAudioContext !== "undefined") {console.log('mozAudioContext');return new window.mozAudioContext();} else {console.log('NONE OF THEM!');}
}

or

var context;
window.addEventListener('load', init, false);
function init() {try {// Fix up for prefixingwindow.AudioContext = window.AudioContext || window.webkitAudioContext;context = new AudioContext();}catch (e) {alert('Web Audio API is not supported in this browser');}
}

检测getUserMedia

function hasGetUserMedia() {// Note: Opera builds are unprefixed.return !!(navigator.getUserMedia || navigator.webkitGetUserMedia ||navigator.mozGetUserMedia || navigator.msGetUserMedia);
}if (hasGetUserMedia()) {// Good to go!
} else {alert('getUserMedia() is not supported in your browser');
}

兼容写法

var AudioContext = window.AudioContext || window.webkitAudioContext;

开始录音

Storage.ctx = new AudioContext();if (Storage.ctx.createJavaScriptNode) {jsAudioNode = Storage.ctx.createJavaScriptNode(bufferSize, numberOfAudioChannels, numberOfAudioChannels);} else if (Storage.ctx.createScriptProcessor) {jsAudioNode = Storage.ctx.createScriptProcessor(bufferSize, numberOfAudioChannels, numberOfAudioChannels);
} else {alert('WebAudio API has no support on this browser.')throw 'WebAudio API has no support on this browser.';
}jsAudioNode.connect(Storage.ctx.destination);

核心

navigator.mediaDevices.getUserMedia({ audio: true })  // 只处理音频.then(onMicrophoneCaptured).catch(onMicrophoneCaptureError);

处理 Safari 兼容

safari 不支持Buffer 的方式 改为下面这种

URL.createObjectURL(new Blob([_function.toString(),';this.onmessage =  function (e) {' + _function.name + '(e.data);}'], {type: 'application/javascript'}));

利用worker 处理异步

function processInWebWorker(_function) {var workerURL = URL.createObjectURL(new Blob([_function.toString(),';this.onmessage =  function (e) {' + _function.name + '(e.data);}'], {type: 'application/javascript'}));var worker = new Worker(workerURL);worker.workerURL = workerURL;return worker;
}

在html5网页中录音解决方案相关推荐

  1. 怎么把html的网页做成视频,html5网页中怎么加入视频?怎么为网页添加视频?

    相信很多小伙伴会在各种网页和 app 中观看各种视频,那么今天我们就来说说怎么在html5网页中怎么加入视频?和怎么为网页添加视频吧! 1.首先,我们在开发工具中新建一个 .html 文件,输入下面代 ...

  2. #HTML5网页中的文本与图像

    HTML5网页中的文本与图像 无序列表 首先欢迎大家来看我信息安全小萌新的博客!下面我会和大家分享我对于HTML5的学习经验,今天我很想的是HTML5网页中的文本与图像处理问题. 我先放一个案例,通过 ...

  3. html5网页中加入播放器,6 个 HTML5 的多媒体播放器

    是 HTML5 中新引入的标签,用来在 Web 网页中嵌入视频播放功能,无需 Flash 和其他嵌入式插件的支持,是浏览器内建的功能,不过 旨在一些高级浏览器中支持,例如Firefox, Safari ...

  4. html5网页中加入播放器,向网页中添加 HTML5 视频控件

    爱学习,爱生活,爱编程--希望能帮到你!更多>>> 如何开始使用 采用它的最基本形式,使用 HTML5  video 元素向网页中添加视频播放器是通过一行 HTML 完成的. 添加  ...

  5. 在HTML5网页中写法正确的是,跟永哥学HTML5(4):正确使用HTML5的header、hgroup和section...

    在上一章HTML5新增语义化元素的使用中我们讲解了 1.只在需要的时候使用header和hgroup 写不需要写的标签当然是毫无意义的.不幸的是,我经常看到header和hgroup被无意义的滥用. ...

  6. 网页设计html加音频,HTML5网页中如何嵌入音频,视频?

    <HTML5的视频播放控制技术> 介绍了 本文主要介绍在HTML5 中如何嵌入音频,视频? 在HTML5 中如何嵌入音频? HTML5 支持 MP3.Wav 和 Ogg 格式的音频,代码示 ...

  7. html5网页中加入播放器,10款jquery+html5实现的网页播放器

    1.3D版HTML5模拟衣服拖拽动画效果 这是一款3D版HTML5模拟衣服拖拽动画效果源码,是一款非常具有创意而且很好玩的HTML5动画.运行本例源码可见衣服布料呈3D环形显示,可以用鼠标左键来拖拽衣 ...

  8. html5网页中加入播放器,如何嵌入HTML5视频播放器?

    Javascript代码: document.onreadystatechange = function () { if (document.readyState == "complete& ...

  9. html5怎么加网页外边框,在HTML5网页中添加CSS边框更改定位

    当我在 HTML 5文档中添加边框时,我遇到了移动页面元素的问题. 我期望包含的标题元素(灰色)出现在屏幕的顶部,但它似乎从内部div(红色)获取边距.但是,如果我在标题中添加一个边框,它会出现在我预 ...

  10. html5网页中的表格教程,javascript程序设计_达内javascript教程-达内web前端培训

    JavaScript基础 - 输出星星 var oT1 = document.getElementById('txt1'); var oT2 = document.getElementById('tx ...

最新文章

  1. PostgreSQL — Prepared Statement 预编译
  2. poj-1284(Primitive Roots)(欧拉函数运用)
  3. C++ : 矩阵初等行变换,化成最简矩阵
  4. Android开源工具库
  5. push_back和emplace_back的区别
  6. 关于远程终端不能登录问题解决!
  7. 计算机网络带宽是什么意思,网络带宽是怎么计算的?
  8. C++中函数重载、缺省参数及命名空间
  9. 系统学习机器学习之特征工程(二)--离散型特征编码方式:LabelEncoder、one-hot与哑变量*
  10. DNS如何查找IP?
  11. VC++6.0与VS2010的区别
  12. 【转载】【原创】贵在,难在,成在
  13. mac本 安装淘宝镜像
  14. 梯度消失和梯度爆炸原因,表现,解决方案
  15. mysql1026_mysql 启动错误1026
  16. [Error]The app delegate must implement the window property if it wants to use a main storyboard file
  17. 使用 Suspense 改善 Vue 3 中的用户体验
  18. Linux云计算-02_CentOS Linux 7.X系统管理
  19. Zotero BookxNote
  20. MFC基础知识与课程设计思路

热门文章

  1. NOI题库 小学奥数
  2. 计算机网络习题——循环冗余校验
  3. Serializer对象
  4. java写qq机器人插件_情迁QQ机器人JS插件/使用开发教程
  5. HTML实现页面跳转的几种方法
  6. 深度学习目标检测之SSD网络(超级详细)
  7. 解决ubuntu下firefox浏览器无法观看视频
  8. iOS开发入门学习路线
  9. wps纸张大小设置成A4_pdf两页合并一页a4,只需这招轻松搞定
  10. 微信朋友圈分享详细步骤html,微信如何转发朋友圈图文(朋友圈转发图文教程分享)...