MediaRecorder APIを使って録音アプリをつくろう

MediaRecorder APIは、動画や音声のようなメディアストリームを記録するためのAPIです。 音声データ処理などの知識がなくても簡単に利用することができます。

サンプル

ブラウザで録音し、kintoneに保存します。

フォーム設定

コード

HTML(カスタマイズビュー : 録音)

\<linkrel="stylesheet"href="//your-domain/path/sample.css"\>\<divid="new"\>\<p\>新規\</p\>\<divid="recorder"class="default"\>\<aid="startButton"\>開始\</a\>\<aid="pauseButton"\>一時停止\</a\>\<aid="resumeButton"\>再開\</a\>\<aid="stopButton"\>停止\</a\>\<audioid="player"controls\>\</audio\>\<aid="deleteButton"\>削除\</a\>\<aid="saveButton"\>保存\</a\>\</div\>\<divid="unableRecord"\>\<p\>録音できません。マイクが無効になっているか、ブラウザが録音機能に対応していません。\</p\>\</div\>\</div\>\<divid="saved"\>\<p\>保存済み\</p\>\<table\>\<thead\>\<tr\>\<th\>作成日時\</th\>\<th\>録音\</th\>\</tr\>\</thead\>\<tbody\>\</tbody\>\</table\>\</div\>\<script type="text/html"id="saved-tbody-template"\>\<tr\>\<td\>\<%=created%\>\</td\>\<td\>\<audiosrc="\<%= file %\>"controls\>\</td\>\</tr\>\</script\>

※モバイル版に対応するため、カスタマイズビューのHTMLからCSSを読み込んでいます。 パソコン表示のみ行う場合は、通常通り「JavaScript / CSSでカスタマイズ > PC用のCSSファイル」からの読み込みで問題ありません。

JavaScript

本サンプルでは、lodash及びMoment.jsを利用しています。Cybozu CDNからご利用ください。 先にlodash.min.jsとmoment.min.jsを読み込んだ後、下記sample.jsを読み込みます。

・sample.js

(function(){"use strict";kintone.events.on(['app.record.index.show','mobile.app.record.index.show',],function(event){if(event.viewName!=='録音')return;kintone.api(kintone.api.url('/k/v1/records',true),'GET',{app:(event.type==='app.record.index.show')?kintone.app.getId():kintone.mobile.app.getId()}).then(function(response){kintone.Promise.all(response.records.map(function(record){returnnewkintone.Promise(function(resolve){varxhr=newXMLHttpRequest();xhr.open('GET','/k/v1/file.json?fileKey='+record.音声.value[0].fileKey);xhr.setRequestHeader('X-Requested-With','XMLHttpRequest');xhr.responseType='blob';xhr.addEventListener('load',function(){resolve({created:moment(record.作成日時.value).format('YYYY-MM-DD HH:mm'),file:(window.URL||window.webkitURL).createObjectURL(xhr.response)});});xhr.send();});})).then(function(rows){document.querySelector('#saved tbody').innerHTML=rows.reduce(function(html,row){returnhtml+\_.template(document.getElementById("saved-tbody-template").innerHTML)({created:row.created,file:row.file});},'');});});if(!navigator.mediaDevices){document.getElementById('new').className='unable';return;}navigator.mediaDevices.getUserMedia({audio:true,video:false}).then(function(stream){varrecorder=document.getElementById('recorder');varstartButton=document.getElementById('startButton');varpauseButton=document.getElementById('pauseButton');varresumeButton=document.getElementById('resumeButton');varstopButton=document.getElementById('stopButton');varplayer=document.getElementById('player');vardeleteButton=document.getElementById('deleteButton');varsaveButton=document.getElementById('saveButton');varloadRecorder=function(){varmediaRecorder=newMediaRecorder(stream);varblob;mediaRecorder.addEventListener('dataavailable',function(e){blob=e.data;player.src=window.URL.createObjectURL(blob);});startButton.addEventListener('click',function(){mediaRecorder.start();recorder.className='started';});pauseButton.addEventListener('click',function(){mediaRecorder.pause();recorder.className='paused';});resumeButton.addEventListener('click',function(){mediaRecorder.resume();recorder.className='started';});stopButton.addEventListener('click',function(){mediaRecorder.stop();recorder.className='stopped';});varsaveButtonListener=function(){varformData=newFormData();varxhr=newXMLHttpRequest();formData.append('\_\_REQUEST\_TOKEN\_\_',kintone.getRequestToken());formData.append('file',blob,moment().format('YYYY-MM-DD-HH-mm-ss')+'.'+([{extension:'aac',mimetype:'audio/aac'},{extension:'mid',mimetype:'audio/midi'},{extension:'mid',mimetype:'audio/x-midi'},{extension:'mp3',mimetype:'audio/mpeg'},{extension:'oga',mimetype:'audio/ogg'},{extension:'wav',mimetype:'audio/wav'},{extension:'weba',mimetype:'audio/webm'},{extension:'3gp',mimetype:'audio/3gpp'},{extension:'3g2',mimetype:'audio/3gpp2'}].find(function(format){returnblob.type.indexOf(format.mimetype)!==-1;})||{extension:blob.type.split(/\/|;/g)[1]}).extension);xhr.open('POST',encodeURI('/k/v1/file.json'));xhr.setRequestHeader('X-Requested-With','XMLHttpRequest');xhr.addEventListener('load',function(){kintone.api('/k/v1/record','POST',{app:(event.type==='app.record.index.show')?kintone.app.getId():kintone.mobile.app.getId(),record:{音声:{value:[{fileKey:JSON.parse(xhr.responseText).fileKey}]}}}).then(function(){alert('保存しました。');location.reload();});});xhr.send(formData);};saveButton.addEventListener('click',saveButtonListener);deleteButton.addEventListener('click',function(){recorder.className='default';saveButton.removeEventListener('click',saveButtonListener);loadRecorder();});};loadRecorder();document.getElementById('new').className='able';}).catch(function(e){document.getElementById('new').className='unable';});});})();

CSS

下記sample.cssを読み込みます。 ※モバイル版に対応する場合は、前述の通りカスタマイズビューのHTMLからCSSを読み込みます。

・sample.css

#new\>div{display:none;}#new.able#recorder,#new.unable#unableRecord{display:block;}#recorder\>\*{display:none;}#recorder.default#startButton,#recorder.started#pauseButton,#recorder.started#stopButton,#recorder.paused#resumeButton,#recorder.paused#stopButton,#recorder.stopped#deleteButton,#recorder.stopped#saveButton,#recorder.stopped#player{display:inline;}#new,#saved{padding:5px20px;}audio{max-width:100%;}#savedth,#savedtd{border:1pxsolid#000;padding:5px;}

動作環境

現状、MediaRecorder APIを利用できるブラウザは限られています。

MDN

Can I use

・筆者確認

iOSでは利用できないようですね。