因公司業務須要在網頁錄音功能,由於h5的api兼容限制不得想出一些解決方案,如下是總結。
https://shudong.wang/10585.htmljavascript
https://wsdo.github.io/recording/html
https://github.com/wsdo/recordingjava
後續繼續完善,有這個需求的朋友能夠繼續討論
百度語音識別ios
感受百度夠強大,確定有完美的解決方案,最終發如今移動端網頁打開百度語音直接跳轉讓下載app(說明不支持)
谷歌語音識別git
在不支持的機型上面不顯示語音識別按鈕
h5錄音主要使用AudioContext 和 getUserMedia 兼容性仍是不好的,尤爲是在移動端。AudioContextgithub
getUserMedia
可使用的:(最新版本,經常使用)web
pc safari 支持 ios Safari 支持 安卓 小米5 微信裏面可使用 小米5 Chrome 最新版可使用 小米5 uc可使用
不可使用的
ios Chrome 到這出了問題 webkitAudioContext.createScriptProcessor
ios 微信裏面不支持
小米5 自帶瀏覽器不能夠
華爲自帶瀏覽器不能夠api
考慮到手機端微信裏面使用場景比較多
先了解一下簡介和歷史吧
長久以來,音頻/視頻捕獲都是網絡開發中的「聖盃」。
多年來,咱們老是依賴於瀏覽器插件(Flash 或 Silverlight)實現這一點。快來看看吧!promise
如今輪到 HTML5 大顯身手了。也許看起來不是很顯眼,可是 HTML5 的崛起引起了對設備硬件訪問的激增。
地理位置 (GPS)、Orientation API(加速計)、WebGL (GPU) 和 Web Audio API(視頻硬件)都是很好的例子。
這些功能很是強大,展現了基於系統底層硬件功能之上的高級 JavaScript API。瀏覽器
本教程介紹了一種新 API:navigator.getUserMedia(),可以讓網絡應用訪問用戶的相機和麥克風。
若是您還不知道,getUserMedia() 的歷史可謂一段有趣的故事。
過去幾年中出現過好幾種「Media Capture API」的變體。不少人意識到,須要可以在網絡上訪問本地設備,但這要全部人協力開發出一種新的規範。局面一片混亂,以致於 W3C 最終決定成立一個工做組。他們只有一個目的:理清混亂的局面!設備 API 政策 (DAP) 工做組負責對過剩的提議進行統一和標準化。
我會試着總結一下 2011 所發生的事情...
HTML 媒體捕獲是 DAP 在網絡媒體捕獲標準化上邁出的第一步。具體方法是超載 <input type="file"> 併爲 accept 參數添加新值。
若是您要讓用戶經過網絡攝像頭拍攝本身的快照,就可使用 capture=camera:
<input type="file" accept="image/*;capture=camera">
錄製視頻或音頻也是相似的:
<input type="file" accept="video/*;capture=camcorder"> <input type="file" accept="audio/*;capture=microphone">
不少人認爲 HTML 媒體捕獲的侷限性太大,所以一種新的規範應運而生,能夠支持任何類型的(將來)設備。不出意料地,該設計須要新的 <device> 元素,也就是 getUserMedia() 的前身。
Opera 是第一批根據 <device> 元素建立視頻捕獲的初始實施的瀏覽器之一。不久以後(準確地說是同一天),WhatWG 決定廢止 <device> 標記,以支持稱爲 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>
很遺憾,已發佈的瀏覽器中沒有任何一款曾經包含 <device>。我猜這是一個不太須要擔憂的 API。可是 <device> 確實有兩大優勢:一是語義方面,二是能夠輕鬆進行擴展,而不只僅是支持音頻/視頻設備。
如今深吸一口氣。這玩意兒速度飛快!
<device> 元素最終仍是像渡渡鳥同樣銷聲匿跡了。
依靠 WebRTC(網絡即時通訊)的大力協助,最近幾個月尋找合適捕獲 API 的步伐加快了不少。該規範由 W3C WebRTC 工做組負責監管。Google、Opera、Mozilla 和其餘一些公司目前正致力於在本身的瀏覽器中實施該 API。
getUserMedia() 與 WebRTC 相關,由於它是通向這組 API 的門戶。它提供了訪問用戶本地相機/麥克風媒體流的手段。
支持:
在 Chrome 瀏覽器 18.0.1008 和更高版本中,可在 about:flags 下啓用 WebRTC。
主要使用 AudioContext 和 getUserMedia 這個api 來操做
AudioContext接口表示由音頻模塊鏈接而成的音頻處理圖,每一個模塊對應一個AudioNode。AudioContext能夠控制它所包含的節點的建立,以及音頻處理、解碼操做的執行。作任何事情以前都要先建立AudioContext對象,由於一切都發生在這個環境之中。
能夠來這裏瞭解
https://developer.mozilla.org...
MediaDevices.getUserMedia() 會提示用戶給予使用媒體輸入的許可,媒體輸入會產生一個MediaStream,裏面包含了請求的媒體類型的軌道。此流能夠包含一個視頻軌道(來自硬件或者虛擬視頻源,好比相機、視頻採集設備和屏幕共享服務等等)、一個音頻軌道(一樣來自硬件或虛擬音頻源,好比麥克風、A/D轉換器等等),也多是其它軌道類型。它返回一個 Promise 對象,成功後會resolve回調一個 MediaStream 對象。若用戶拒絕了使用權限,或者須要的媒體源不可用,promise會reject回調一個 PermissionDeniedError 或者 NotFoundError 。
能夠來這裏瞭解
https://developer.mozilla.org...
<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
這是一個使用 navigator.mediaDevices.getUserMedia()的例子,帶一個polyfill以適應舊的瀏覽器。 要注意的是這個polyfill並不能修正一些約束語法上的遺留差別,這表示約束在某些瀏覽器上可能不會很好地運行。推薦使用處理了約束的 adapter.js polyfill 來替代。
https://github.com/webrtc/ada...
/ 老的瀏覽器可能根本沒有實現 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方法包裹一個Promise return 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'); // 舊的瀏覽器可能沒有srcObject if ("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); });
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 prefixing window.AudioContext = window.AudioContext || window.webkitAudioContext; context = new AudioContext(); } catch (e) { alert('Web Audio API is not supported in this browser'); } }
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 不支持Buffer 的方式 改成下面這種
URL.createObjectURL(new Blob([_function.toString(), ';this.onmessage = function (e) {' + _function.name + '(e.data);}' ], { type: 'application/javascript' }));
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; }