MediaRecorder APIは、動画や音声のようなメディアストリームを記録するためのAPIです。 音声データ処理などの知識がなくても簡単に利用することができます。
サンプル
ブラウザで録音し、kintoneに保存します。
フォーム設定
コード
HTML(カスタマイズビュー : 録音)
<link rel="stylesheet" href="//your-domain/path/sample.css"> <div id="new"> <p>新規</p> <div id="recorder" class="default"> <a id="startButton">開始</a> <a id="pauseButton">一時停止</a> <a id="resumeButton">再開</a> <a id="stopButton">停止</a> <audio id="player" controls></audio> <a id="deleteButton">削除</a> <a id="saveButton">保存</a> </div> <div id="unableRecord"> <p>録音できません。マイクが無効になっているか、ブラウザが録音機能に対応していません。</p> </div> </div> <div id="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><audio src="<%= 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){ return new kintone.Promise(function(resolve){ var xhr = new XMLHttpRequest(); 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){ return html + _.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){ var recorder = document.getElementById('recorder'); var startButton = document.getElementById('startButton'); var pauseButton = document.getElementById('pauseButton'); var resumeButton = document.getElementById('resumeButton'); var stopButton = document.getElementById('stopButton'); var player = document.getElementById('player'); var deleteButton = document.getElementById('deleteButton'); var saveButton = document.getElementById('saveButton'); var loadRecorder = function(){ var mediaRecorder = new MediaRecorder(stream); var blob; 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'; }); var saveButtonListener = function(){ var formData = new FormData(); var xhr = new XMLHttpRequest(); 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){ return blob.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: 5px 20px; } audio{ max-width: 100%; } #saved th, #saved td{ border: 1px solid #000; padding: 5px; }
動作環境
現状、MediaRecorder APIを利用できるブラウザは限られています。
・MDN
・筆者確認
iOSでは利用できないようですね。
0件のコメント