不就那个事吗 發表於 2019-6-1 23:58:00

JavaScript 实现页面中录音功能

<table class="d-block">
<tbody class="d-block">
    <tr class="d-block">
      <td class="d-block comment-body markdown-bodyjs-comment-body">
<p>页面中实现录音需要使用浏览器提供的 Media​Recorder API,所以前提是需要浏览器支持 MediaStream Recording 相关的功能。</p>
<p>以下代码默认工作在 Chrome 环境中。</p>
<h2>准备页面</h2>
<p>首先准备一个页面,其中内容很简单,一个录音按钮,一个用于播放的 <code>&lt;audio&gt;</code> 标签。</p>
<div class="highlight highlight-text-html-basic"><pre>&lt;!DOCTYPE html&gt;
&lt;<span class="pl-ent">html</span> <span class="pl-e">lang</span>=<span class="pl-s"><span class="pl-pds">"</span>en<span class="pl-pds">"</span></span>&gt;
&lt;<span class="pl-ent">head</span>&gt;
    &lt;<span class="pl-ent">meta</span> <span class="pl-e">charset</span>=<span class="pl-s"><span class="pl-pds">"</span>UTF-8<span class="pl-pds">"</span></span>&gt;
    &lt;<span class="pl-ent">meta</span> <span class="pl-e">name</span>=<span class="pl-s"><span class="pl-pds">"</span>viewport<span class="pl-pds">"</span></span> <span class="pl-e">content</span>=<span class="pl-s"><span class="pl-pds">"</span>width=device-width, initial-scale=1.0<span class="pl-pds">"</span></span>&gt;
    &lt;<span class="pl-ent">meta</span> <span class="pl-e">http-equiv</span>=<span class="pl-s"><span class="pl-pds">"</span>X-UA-Compatible<span class="pl-pds">"</span></span> <span class="pl-e">content</span>=<span class="pl-s"><span class="pl-pds">"</span>ie=edge<span class="pl-pds">"</span></span>&gt;
    &lt;<span class="pl-ent">title</span>&gt;audio record&lt;/<span class="pl-ent">title</span>&gt;
&lt;/<span class="pl-ent">head</span>&gt;
&lt;<span class="pl-ent">body</span>&gt;
    &lt;<span class="pl-ent">div</span> <span class="pl-e">class</span>=<span class="pl-s"><span class="pl-pds">"</span>app<span class="pl-pds">"</span></span>&gt;
      &lt;<span class="pl-ent">button</span> <span class="pl-e">class</span>=<span class="pl-s"><span class="pl-pds">"</span>record-btn<span class="pl-pds">"</span></span>&gt;record&lt;/<span class="pl-ent">button</span>&gt;
      &lt;<span class="pl-ent">audio</span> <span class="pl-e">controls</span> <span class="pl-e">class</span>=<span class="pl-s"><span class="pl-pds">"</span>audio-player<span class="pl-pds">"</span></span>&gt;&lt;/<span class="pl-ent">audio</span>&gt;
    &lt;/<span class="pl-ent">div</span>&gt;
    &lt;<span class="pl-ent">script</span> <span class="pl-e">src</span>=<span class="pl-s"><span class="pl-pds">"</span>./recorder.js<span class="pl-pds">"</span></span>&gt;&lt;/<span class="pl-ent">script</span>&gt;
&lt;/<span class="pl-ent">body</span>&gt;
&lt;/<span class="pl-ent">html</span>&gt;</pre></div>
<h2>获取录音权限</h2>
<p>因为录音需要使用设备的话筒,所以第一步应该是向用户索要录音的权限。这是通过 Media​Devices​.get​User​Media()<br>
来完成的,其用法为:</p>
<div class="highlight highlight-source-js"><pre><span class="pl-k">var</span> promise <span class="pl-k">=</span> <span class="pl-c1">navigator</span>.<span class="pl-smi">mediaDevices</span>.<span class="pl-en">getUserMedia</span>(constraints);</pre></div>
<p>其中 <code>constraints</code> 为需要获取的权限列表,这里只需要指定音频 <code>audio</code> 即可。</p>
<p>其返回是个 Promise,因为用户何时进行授权是不确定的。通过在 Promise 的回调中进行授权成功或失败的处理。</p>
<p>在使用前需要判断浏览器是否已经支持相应的 API,此时得到如下的代码:</p>
<div class="highlight highlight-source-js"><pre><span class="pl-k">if</span> (<span class="pl-c1">navigator</span>.<span class="pl-smi">mediaDevices</span>.<span class="pl-smi">getUserMedia</span>) {
<span class="pl-k">const</span> <span class="pl-c1">constraints</span> <span class="pl-k">=</span> { audio<span class="pl-k">:</span> <span class="pl-c1">true</span> };
<span class="pl-c1">navigator</span>.<span class="pl-smi">mediaDevices</span>.<span class="pl-en">getUserMedia</span>(constraints).<span class="pl-c1">then</span>(
    <span class="pl-smi">stream</span> <span class="pl-k">=&gt;</span> {
      <span class="pl-en">console</span>.<span class="pl-c1">log</span>(<span class="pl-s"><span class="pl-pds">"</span>授权成功!<span class="pl-pds">"</span></span>);
    },
    () <span class="pl-k">=&gt;</span> {
      <span class="pl-en">console</span>.<span class="pl-c1">error</span>(<span class="pl-s"><span class="pl-pds">"</span>授权失败!<span class="pl-pds">"</span></span>);
    }
);
} <span class="pl-k">else</span> {
<span class="pl-en">console</span>.<span class="pl-c1">error</span>(<span class="pl-s"><span class="pl-pds">"</span>浏览器不支持 getUserMedia<span class="pl-pds">"</span></span>);
}</pre></div>
<p>其中成功回调里得到的入参 <code>stream</code> 为 <code>MediaStream</code> 对象。</p>
<p>此时运行后可看到浏览器展示出了让用户授权使用麦克风的提示。</p>
<p><img src="https://user-images.githubusercontent.com/3783096/58750750-a484c100-84c8-11e9-9785-94746d98dbd5.png" alt="向用户索要麦克风使用权限" style="max-width: 100%"></p>
<p align="center">向用户索要麦克风使用权限</p>
<h2>创建录音实例</h2>
<p>将上一步获取到的 <code>MediaStream</code> 传入 Media​Recorder 的构造器创建一个录音器的实例。</p>
<div class="highlight highlight-source-js"><pre><span class="pl-k">var</span> mediaRecorder <span class="pl-k">=</span> <span class="pl-k">new</span> <span class="pl-en">MediaRecorder</span>(stream);</pre></div>
<h2>启动录音</h2>
<p>通过监听页面中录音按钮的点击来启动录音。</p>
<div class="highlight highlight-source-js"><pre><span class="pl-k">const</span> <span class="pl-c1">recordBtn</span> <span class="pl-k">=</span> <span class="pl-c1">document</span>.<span class="pl-c1">querySelector</span>(<span class="pl-s"><span class="pl-pds">"</span>.record-btn<span class="pl-pds">"</span></span>);
<span class="pl-k">const</span> <span class="pl-c1">mediaRecorder</span> <span class="pl-k">=</span> <span class="pl-k">new</span> <span class="pl-en">MediaRecorder</span>(stream);
<span class="pl-smi">recordBtn</span>.<span class="pl-en">onclick</span> <span class="pl-k">=</span> () <span class="pl-k">=&gt;</span> {
<span class="pl-smi">mediaRecorder</span>.<span class="pl-c1">start</span>();
<span class="pl-en">console</span>.<span class="pl-c1">log</span>(<span class="pl-s"><span class="pl-pds">"</span>录音中...<span class="pl-pds">"</span></span>);
};</pre></div>
<p><code>MediaRecorder</code> 实例上有个 <code>state</code> 状态,可用来判断录音器当前的活动状态,总共有三种值:</p>
<ul>
<li><code>inactive</code>:处于休息状态,要么是没开始,要么是开始后已经停止。</li>
<li><code>recording</code>:录音中</li>
<li><code>paused</code>:已经开始,但被暂停了,不是停止也没有被恢复。</li>
</ul>
<p>所以通过这个状态,我们可以实现再次点击按钮时,结束录音。</p>
<div class="highlight highlight-source-js"><pre><span class="pl-smi">recordBtn</span>.<span class="pl-en">onclick</span> <span class="pl-k">=</span> () <span class="pl-k">=&gt;</span> {
<span class="pl-k">if</span> (<span class="pl-smi">mediaRecorder</span>.<span class="pl-smi">state</span> <span class="pl-k">===</span> <span class="pl-s"><span class="pl-pds">"</span>recording<span class="pl-pds">"</span></span>) {
    <span class="pl-smi">mediaRecorder</span>.<span class="pl-c1">stop</span>();
    <span class="pl-smi">recordBtn</span>.<span class="pl-smi">textContent</span> <span class="pl-k">=</span> <span class="pl-s"><span class="pl-pds">"</span>record<span class="pl-pds">"</span></span>;
    <span class="pl-en">console</span>.<span class="pl-c1">log</span>(<span class="pl-s"><span class="pl-pds">"</span>录音结束<span class="pl-pds">"</span></span>);
} <span class="pl-k">else</span> {
    <span class="pl-smi">mediaRecorder</span>.<span class="pl-c1">start</span>();
    <span class="pl-en">console</span>.<span class="pl-c1">log</span>(<span class="pl-s"><span class="pl-pds">"</span>录音中...<span class="pl-pds">"</span></span>);
    <span class="pl-smi">recordBtn</span>.<span class="pl-smi">textContent</span> <span class="pl-k">=</span> <span class="pl-s"><span class="pl-pds">"</span>stop<span class="pl-pds">"</span></span>;
}
<span class="pl-en">console</span>.<span class="pl-c1">log</span>(<span class="pl-s"><span class="pl-pds">"</span>录音器状态:<span class="pl-pds">"</span></span>, <span class="pl-smi">mediaRecorder</span>.<span class="pl-smi">state</span>);
};</pre></div>
<h2>音频数据的获取</h2>
<p>上面按钮处理来自用户的交互,只负责启动或停止录音。音频的数据还是从 Media​Recorder 实例上通过监听其相应的事件来完成的。</p>
<p>当录音开始时,会触发其 <code>MediaRecorder.ondataavailable</code> 事件,从该事件回调的入参为 <code>BlobEvent</code>,从它身上取到 <code>event.data</code> 便是我们需要的音频数据。因为数据是一段一段产生的,所以需要暂存到一个数组中。</p>
<div class="highlight highlight-source-js"><pre><span class="pl-k">const</span> <span class="pl-c1">chunks</span> <span class="pl-k">=</span> [];
<span class="pl-smi">mediaRecorder</span>.<span class="pl-en">ondataavailable</span> <span class="pl-k">=</span> <span class="pl-k">function</span>(<span class="pl-smi">e</span>) {
<span class="pl-smi">chunks</span>.<span class="pl-c1">push</span>(<span class="pl-smi">e</span>.<span class="pl-c1">data</span>);
};</pre></div>
<p>目前为止完成的代码应该是这样的:</p>
<details>
<summary>
recorder.js
</summary>
<div class="highlight highlight-source-js"><pre><span class="pl-k">const</span> <span class="pl-c1">recordBtn</span> <span class="pl-k">=</span> <span class="pl-c1">document</span>.<span class="pl-c1">querySelector</span>(<span class="pl-s"><span class="pl-pds">"</span>.record-btn<span class="pl-pds">"</span></span>);
<span class="pl-k">const</span> <span class="pl-c1">playBtn</span> <span class="pl-k">=</span> <span class="pl-c1">document</span>.<span class="pl-c1">querySelector</span>(<span class="pl-s"><span class="pl-pds">"</span>.play-btn<span class="pl-pds">"</span></span>);
<p><span class="pl-k">if</span> (<span class="pl-c1">navigator</span>.<span class="pl-smi">mediaDevices</span>.<span class="pl-smi">getUserMedia</span>) {<br>
<span class="pl-k">var</span> chunks <span class="pl-k">=</span> [];<br>
<span class="pl-k">const</span> <span class="pl-c1">constraints</span> <span class="pl-k">=</span> { audio<span class="pl-k">:</span> <span class="pl-c1">true</span> };<br>
<span class="pl-c1">navigator</span>.<span class="pl-smi">mediaDevices</span>.<span class="pl-en">getUserMedia</span>(constraints).<span class="pl-c1">then</span>(<br>
<span class="pl-smi">stream</span> <span class="pl-k">=&gt;</span> {<br>
<span class="pl-en">console</span>.<span class="pl-c1">log</span>(<span class="pl-s"><span class="pl-pds">"</span>授权成功!<span class="pl-pds">"</span></span>);</p>
<pre><code>&lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-c1"&gt;mediaRecorder&lt;/span&gt; &lt;span class="pl-k"&gt;=&lt;/span&gt; &lt;span class="pl-k"&gt;new&lt;/span&gt; &lt;span class="pl-en"&gt;MediaRecorder&lt;/span&gt;(stream);

&lt;span class="pl-smi"&gt;recordBtn&lt;/span&gt;.&lt;span class="pl-en"&gt;onclick&lt;/span&gt; &lt;span class="pl-k"&gt;=&lt;/span&gt; () &lt;span class="pl-k"&gt;=&amp;gt;&lt;/span&gt; {
    &lt;span class="pl-k"&gt;if&lt;/span&gt; (&lt;span class="pl-smi"&gt;mediaRecorder&lt;/span&gt;.&lt;span class="pl-smi"&gt;state&lt;/span&gt; &lt;span class="pl-k"&gt;===&lt;/span&gt; &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;recording&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;) {
      &lt;span class="pl-smi"&gt;mediaRecorder&lt;/span&gt;.&lt;span class="pl-c1"&gt;stop&lt;/span&gt;();
      &lt;span class="pl-smi"&gt;recordBtn&lt;/span&gt;.&lt;span class="pl-smi"&gt;textContent&lt;/span&gt; &lt;span class="pl-k"&gt;=&lt;/span&gt; &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;record&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;;
      &lt;span class="pl-en"&gt;console&lt;/span&gt;.&lt;span class="pl-c1"&gt;log&lt;/span&gt;(&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;录音结束&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;);
    } &lt;span class="pl-k"&gt;else&lt;/span&gt; {
      &lt;span class="pl-smi"&gt;mediaRecorder&lt;/span&gt;.&lt;span class="pl-c1"&gt;start&lt;/span&gt;();
      &lt;span class="pl-en"&gt;console&lt;/span&gt;.&lt;span class="pl-c1"&gt;log&lt;/span&gt;(&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;录音中...&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;);
      &lt;span class="pl-smi"&gt;recordBtn&lt;/span&gt;.&lt;span class="pl-smi"&gt;textContent&lt;/span&gt; &lt;span class="pl-k"&gt;=&lt;/span&gt; &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;stop&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;;
    }
    &lt;span class="pl-en"&gt;console&lt;/span&gt;.&lt;span class="pl-c1"&gt;log&lt;/span&gt;(&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;录音器状态:&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;, &lt;span class="pl-smi"&gt;mediaRecorder&lt;/span&gt;.&lt;span class="pl-smi"&gt;state&lt;/span&gt;);
};

&lt;span class="pl-smi"&gt;mediaRecorder&lt;/span&gt;.&lt;span class="pl-en"&gt;ondataavailable&lt;/span&gt; &lt;span class="pl-k"&gt;=&lt;/span&gt; &lt;span class="pl-k"&gt;function&lt;/span&gt;(&lt;span class="pl-smi"&gt;e&lt;/span&gt;) {
    &lt;span class="pl-smi"&gt;chunks&lt;/span&gt;.&lt;span class="pl-c1"&gt;push&lt;/span&gt;(&lt;span class="pl-smi"&gt;e&lt;/span&gt;.&lt;span class="pl-c1"&gt;data&lt;/span&gt;);
};
},
() &lt;span class="pl-k"&gt;=&amp;gt;&lt;/span&gt; {
&lt;span class="pl-en"&gt;console&lt;/span&gt;.&lt;span class="pl-c1"&gt;error&lt;/span&gt;(&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;授权失败!&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;);
}
</code></pre>
<p>);<br>
} <span class="pl-k">else</span> {<br>
<span class="pl-en">console</span>.<span class="pl-c1">error</span>(<span class="pl-s"><span class="pl-pds">"</span>浏览器不支持 getUserMedia<span class="pl-pds">"</span></span>);<br>
}</p></pre></div><p></p>
</details>
<p><img src="https://user-images.githubusercontent.com/3783096/58750759-c0886280-84c8-11e9-9c8f-154a1fafc959.gif" alt="录音状态的查看" style="max-width: 100%"></p>
<p align="center">录音状态的查看</p>
<h2>录音结束及音频的播放</h2>
<p>通过监听 <code>MediaRecorder.onstop</code> 事件,将收集好的音频数据创建成 Blob 对象,然后 通过 <code>URL.createObjectURL</code> 创建成 HTML 中 <code>&lt;audio&gt;</code> 标签可使用的资源链接。</p>
<div class="highlight highlight-source-js"><pre><span class="pl-smi">mediaRecorder</span>.<span class="pl-en">onstop</span> <span class="pl-k">=</span> <span class="pl-smi">e</span> <span class="pl-k">=&gt;</span> {
<span class="pl-k">var</span> blob <span class="pl-k">=</span> <span class="pl-k">new</span> <span class="pl-en">Blob</span>(chunks, { type<span class="pl-k">:</span> <span class="pl-s"><span class="pl-pds">"</span>audio/ogg; codecs=opus<span class="pl-pds">"</span></span> });
chunks <span class="pl-k">=</span> [];
<span class="pl-k">var</span> audioURL <span class="pl-k">=</span> <span class="pl-c1">window</span>.<span class="pl-c1">URL</span>.<span class="pl-en">createObjectURL</span>(blob);
<span class="pl-smi">audio</span>.<span class="pl-smi">src</span> <span class="pl-k">=</span> audioURL;
};</pre></div>
<p>其中,在使用完收到到的音频数据后,将 <code>chunks</code> 置空方便下次录音时使用。</p>
<p>目前为止完成的代码应该是这样的:</p>
<details>
<summary>
recorder.js
</summary>
<div class="highlight highlight-source-js"><pre><span class="pl-k">const</span> <span class="pl-c1">recordBtn</span> <span class="pl-k">=</span> <span class="pl-c1">document</span>.<span class="pl-c1">querySelector</span>(<span class="pl-s"><span class="pl-pds">"</span>.record-btn<span class="pl-pds">"</span></span>);
<span class="pl-k">const</span> <span class="pl-c1">player</span> <span class="pl-k">=</span> <span class="pl-c1">document</span>.<span class="pl-c1">querySelector</span>(<span class="pl-s"><span class="pl-pds">"</span>.audio-player<span class="pl-pds">"</span></span>);
<p><span class="pl-k">if</span> (<span class="pl-c1">navigator</span>.<span class="pl-smi">mediaDevices</span>.<span class="pl-smi">getUserMedia</span>) {<br>
<span class="pl-k">var</span> chunks <span class="pl-k">=</span> [];<br>
<span class="pl-k">const</span> <span class="pl-c1">constraints</span> <span class="pl-k">=</span> { audio<span class="pl-k">:</span> <span class="pl-c1">true</span> };<br>
<span class="pl-c1">navigator</span>.<span class="pl-smi">mediaDevices</span>.<span class="pl-en">getUserMedia</span>(constraints).<span class="pl-c1">then</span>(<br>
<span class="pl-smi">stream</span> <span class="pl-k">=&gt;</span> {<br>
<span class="pl-en">console</span>.<span class="pl-c1">log</span>(<span class="pl-s"><span class="pl-pds">"</span>授权成功!<span class="pl-pds">"</span></span>);</p>
<pre><code>&lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-c1"&gt;mediaRecorder&lt;/span&gt; &lt;span class="pl-k"&gt;=&lt;/span&gt; &lt;span class="pl-k"&gt;new&lt;/span&gt; &lt;span class="pl-en"&gt;MediaRecorder&lt;/span&gt;(stream);

&lt;span class="pl-smi"&gt;recordBtn&lt;/span&gt;.&lt;span class="pl-en"&gt;onclick&lt;/span&gt; &lt;span class="pl-k"&gt;=&lt;/span&gt; () &lt;span class="pl-k"&gt;=&amp;gt;&lt;/span&gt; {
    &lt;span class="pl-k"&gt;if&lt;/span&gt; (&lt;span class="pl-smi"&gt;mediaRecorder&lt;/span&gt;.&lt;span class="pl-smi"&gt;state&lt;/span&gt; &lt;span class="pl-k"&gt;===&lt;/span&gt; &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;recording&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;) {
      &lt;span class="pl-smi"&gt;mediaRecorder&lt;/span&gt;.&lt;span class="pl-c1"&gt;stop&lt;/span&gt;();
      &lt;span class="pl-smi"&gt;recordBtn&lt;/span&gt;.&lt;span class="pl-smi"&gt;textContent&lt;/span&gt; &lt;span class="pl-k"&gt;=&lt;/span&gt; &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;record&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;;
      &lt;span class="pl-en"&gt;console&lt;/span&gt;.&lt;span class="pl-c1"&gt;log&lt;/span&gt;(&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;录音结束&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;);
    } &lt;span class="pl-k"&gt;else&lt;/span&gt; {
      &lt;span class="pl-smi"&gt;mediaRecorder&lt;/span&gt;.&lt;span class="pl-c1"&gt;start&lt;/span&gt;();
      &lt;span class="pl-en"&gt;console&lt;/span&gt;.&lt;span class="pl-c1"&gt;log&lt;/span&gt;(&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;录音中...&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;);
      &lt;span class="pl-smi"&gt;recordBtn&lt;/span&gt;.&lt;span class="pl-smi"&gt;textContent&lt;/span&gt; &lt;span class="pl-k"&gt;=&lt;/span&gt; &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;stop&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;;
    }
    &lt;span class="pl-en"&gt;console&lt;/span&gt;.&lt;span class="pl-c1"&gt;log&lt;/span&gt;(&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;录音器状态:&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;, &lt;span class="pl-smi"&gt;mediaRecorder&lt;/span&gt;.&lt;span class="pl-smi"&gt;state&lt;/span&gt;);
};

&lt;span class="pl-smi"&gt;mediaRecorder&lt;/span&gt;.&lt;span class="pl-en"&gt;ondataavailable&lt;/span&gt; &lt;span class="pl-k"&gt;=&lt;/span&gt; &lt;span class="pl-smi"&gt;e&lt;/span&gt; &lt;span class="pl-k"&gt;=&amp;gt;&lt;/span&gt; {
    &lt;span class="pl-smi"&gt;chunks&lt;/span&gt;.&lt;span class="pl-c1"&gt;push&lt;/span&gt;(&lt;span class="pl-smi"&gt;e&lt;/span&gt;.&lt;span class="pl-c1"&gt;data&lt;/span&gt;);
};

&lt;span class="pl-smi"&gt;mediaRecorder&lt;/span&gt;.&lt;span class="pl-en"&gt;onstop&lt;/span&gt; &lt;span class="pl-k"&gt;=&lt;/span&gt; &lt;span class="pl-smi"&gt;e&lt;/span&gt; &lt;span class="pl-k"&gt;=&amp;gt;&lt;/span&gt; {
    &lt;span class="pl-k"&gt;var&lt;/span&gt; blob &lt;span class="pl-k"&gt;=&lt;/span&gt; &lt;span class="pl-k"&gt;new&lt;/span&gt; &lt;span class="pl-en"&gt;Blob&lt;/span&gt;(chunks, { type&lt;span class="pl-k"&gt;:&lt;/span&gt; &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;audio/ogg; codecs=opus&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt; });
    chunks &lt;span class="pl-k"&gt;=&lt;/span&gt; [];
    &lt;span class="pl-k"&gt;var&lt;/span&gt; audioURL &lt;span class="pl-k"&gt;=&lt;/span&gt; &lt;span class="pl-c1"&gt;window&lt;/span&gt;.&lt;span class="pl-c1"&gt;URL&lt;/span&gt;.&lt;span class="pl-en"&gt;createObjectURL&lt;/span&gt;(blob);
    &lt;span class="pl-smi"&gt;player&lt;/span&gt;.&lt;span class="pl-smi"&gt;src&lt;/span&gt; &lt;span class="pl-k"&gt;=&lt;/span&gt; audioURL;
};
},
() &lt;span class="pl-k"&gt;=&amp;gt;&lt;/span&gt; {
&lt;span class="pl-en"&gt;console&lt;/span&gt;.&lt;span class="pl-c1"&gt;error&lt;/span&gt;(&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;授权失败!&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;);
}
</code></pre>
<p>);<br>
} <span class="pl-k">else</span> {<br>
<span class="pl-en">console</span>.<span class="pl-c1">error</span>(<span class="pl-s"><span class="pl-pds">"</span>浏览器不支持 getUserMedia<span class="pl-pds">"</span></span>);<br>
}</p></pre></div><p></p>
</details>
<h2>运行</h2>
<p>完成上面步骤后,实现了一个简单的录音功能,可通过此地址在线体验。完整的代码可在仓库 wayou/audio-recorder 中获取到。</p>
<h2>相关资源</h2>
<ul>
<li>Media​Recorder</li>
<li><code>MediaRecorder.onstop</code></li>
<li><code>URL.createObjectURL</code></li>
</ul>
      </td>
    </tr>
</tbody>
</table>

</div>
<div id="MySignature" role="contentinfo">
    <div>
<img src="https://licensebuttons.net/l/by-nc-sa/3.0/88x31.png" style="vertical-align: middle">
<strong>CC BY-NC-SA 署名-非商业性使用-相同方式共享</strong>
</div><br><br>
来源:https://www.cnblogs.com/Wayou/p/js_audio_recorder.html
頁: [1]
查看完整版本: JavaScript 实现页面中录音功能