九保すこひ@フリーランスエンジニア|累計300万PVのブログ運営中
さてさて、前々回、意外と簡単!音を感知して録画する監視カメラをつくるでは、Python
で大きな音を感知して録画するという機能をつくってみました。
ちなみになぜPython
で作ったかと言うと、記事の中でも書いたとおりJavaScript
で音量をチェックする方法が見つからなかったので仕方なく、、といった部分があったからでした。(もしご存知の方がいらっしゃったら、ぜひ教えてくださいm_ _m)
そして、この件の調査で知ることになったのですが、なんと、
ブラウザだけで録音をし、さらにそれをファイルとしてダウンロードすることができる
ようなので、今回はこの機能をご紹介したいと思います。
ぜひ皆さんのお役に立てると嬉しいです😊✨
開発環境: Vue 2.6
目次
前提として
今回の機能を実装するためには、マイクにアクセスする必要があります。そして、Google Chrome
からマイクにアクセスするためには、たとえローカル環境であってもHTTPS
接続が必須となっています。
そのため、まだHTTPS
接続を準備していない方は先にそちらを用意してから実行してください。なお、nginx
の場合は以下の記事を参考にしてみてください。
コピペでOK!ローカル環境にHTTPSを導入する(nginx編)
コードをつくっていく
今回は特にコードが短いので、基本コードの番号を各コードと入れ替えると完成する「学習雑誌の付録」形式でお届けします。
基本コード
ではまずは基本コードです。
このコードの中に書かれている①〜⑤の場所にこれから説明していくコードをセットしていってください。
<html> <head> <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" rel="stylesheet"> </head> <body class="p-3"> <h1 class="mb-3">JavaScriptで録音するサンプル</h1> <div id="app"> <!-- ③ 録音の開始/終了ボタンを設置する部分 --> </div> <script src="https://cdn.jsdelivr.net/npm/vue@2.6.0"></script> <script> new Vue({ el: '#app', data: { // ① 変数を宣言する部分 }, methods: { // ② 録音を開始/ストップする部分 // ④ 音声ファイルの拡張子を取得する部分 }, mounted() { // ⑤ マイクにアクセス } }); </script> </body> </html>
では実際にやっていきましょう!
変数を宣言する部分 ・・・ ①
これからいくつかメソッドなどを作っていきますが、その際に必要となってくる変数を以下のように定義しておきましょう。
// ① 変数を宣言する部分 status: 'init', // 状況 recorder: null, // 音声にアクセスする "MediaRecorder" のインスタンス audioData: [], // 入力された音声データ audioExtension: '' // 音声ファイルの拡張子
まずstatus
は、そのページの状況がわかるよう、以下3つの文字列が保持されることになります。
- init ・・・ ページが読み込まれたばかり
- ready ・・・ 録音が開始できる状態
- recording ・・・ 録音中
次にrecorder
とaudioData
ですが、手順としてはrecorder
を通して音声データを取得してaudioData
に格納、そしてそのデータを加工してファイル保存するという流れになります。
最後にaudioExtension
ですが、これは音声ファイルの拡張を自動抽出し保持しておくための変数です。というのも、Google Chrome
の音声ファイル形式はwebm
ですが、firefox
の場合はogg
となっているためです。
録音を開始/ストップする部分 ・・・ ②
続いて実際に録音を開始&ストップする部分(メソッド)です。
startRecording() { this.status = 'recording'; this.audioData = []; this.recorder.start(); }, stopRecording() { this.recorder.stop(); this.status = 'ready'; },
recorder
はMediaRecorder
のインスタンスですが、これは後ほどmounted()
の中で定義することになります。
そして、recorder
はシンプルにstart()
とstop()
メソッドを実行することで録音を開始/終了することができます。
なお、startRecording()
ではaudioData
を初期化していて、さらにそれぞれのメソッド内でstatus
を切り替えていることに注目してください。このstatus
の値は、次の項目で使うことになります。
録音の開始/終了ボタンを設置する部分 ・・・ ③
次に実際にブラウザ表示される録音の開始&終了ボタンです。
<button class="btn btn-danger" type="button" v-if="status=='ready'" @click="startRecording">録音を開始する</button> <button class="btn btn-primary" type="button" v-if="status=='recording'" @click="stopRecording">録音を終了する</button>
ここで重要なのが、v-if
の部分です。これは変数status
が変化したときに以下のようなにボタンを表示/非表示するためです。
- ready ・・・ 「録音を開始する」ボタンを表示
- recording ・・・ 「録音を終了する」ボタンを表示
そして、それぞれのクリックイベントで先ほどつくったstartRecording()
とstopRecording()
を実行しています。
音声ファイルの拡張子を取得する部分 ・・・ ④
続いて①の作業でつくった変数audioExtension
に格納することになる「音声ファイルの拡張子」を取得するメソッドをつくっておきましょう。(このメソッドは次の項目で使います)
getExtension(audioType) { let extension = 'wav'; const matches = audioType.match(/audio\/([^;]+)/); if(matches) { extension = matches[1]; } return '.'+ extension; }
音声ファイルの形式は、recorder
から取得できるのですが、中身は以下のようなものになっているため、正規表現で必要な部分を切り出して拡張子としています。
audio/webm;codecs=opus
マイクにアクセス ・・・ ⑤
では、最後に今回で一番重要な部分です。
navigator.mediaDevices.getUserMedia({ audio: true }) .then(stream => { this.recorder = new MediaRecorder(stream); this.recorder.addEventListener('dataavailable', e => { this.audioData.push(e.data); this.audioExtension = this.getExtension(e.data.type); }); this.recorder.addEventListener('stop', () => { const audioBlob = new Blob(this.audioData); const url = URL.createObjectURL(audioBlob); let a = document.createElement('a'); a.href = url; a.download = Math.floor(Date.now() / 1000) + this.audioExtension; document.body.appendChild(a); a.click(); }); this.status = 'ready'; });
この中ではまず最初に以下の部分でマイクにアクセスする処理を実行します。
navigator.mediaDevices.getUserMedia({ audio: true })
※ ここで、もしブラウザにマイクへのアクセスがまだ許可されていない場合は以下のようなポップアップが表示されることになります。
そして、許可されるとthen()
の中身が実行されます。
この中では、取得されたstream
を使ってMediaRecorder
のインスタンスを作り、変数recorder
として保持します。
さらに、そのrecorder
には2つのイベントをつけます。
1つめが、dataavailable
で、ここでは音声データを取得し、さらにそれを変数audioData
に格納しています。また、音声ファイルの拡張子も同じタイミングで取得することになります。
そして、もう一つのイベントがstop
で文字通り録音が終了したときに実行されるイベントになっています。
この中では音声データをBlob
化し、<a download="***">
タグのhref
として使用されます。そしてこの<a>
タグはページに追加されることになり、click()
メソッドを実行することで「クリックしたこと」になり、ファイルのダウンロードを実現しています。
テストしてみる
短いですが、実際に「エリーゼのために」の冒頭部分をスマホのアプリで演奏したものが以下になります。
※ webm
形式ですのでブラウザによっては再生できないのでご注意ください。
ダウンロードする
今回開発したソースコードを以下からダウンロードすることができます。なお、base.html
は基本コードで、complete.html
が完成版のコードになります。
おわりに
ということで、今回はブラウザだけで録音&ファイル保存する方法を紹介しました。
最近はブラウザとはいえども、ネイティブアプリのようなことができるようになってきているので、我々ウェブ開発をする人間からするとワクワクすることが多くなっています(笑)
この機能を応用すると、動画に声を吹き込む機能などもつくれるようになると思うので、ぜひみなさんのサイトでも活用してみてくださいね。
ではでは〜!
「気がつけばもう年末か・・・ホント早い😂」