質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

WebRTC

WebRTC(Web Real-Time Communication)とは、プラグイン無しでウェブブラウザ間の音声通話・ビデオチャットなどリアルタイムコミュニケーションができるオープンフレームワークです。W3CがAPIレベルで、IETFがプロトコルレベルでそれぞれ標準化が進められています。

Q&A

0回答

1246閲覧

iOS for SafariのブラウザアプリでRecordRTCのgetUserMediaが認識しない

poipoi

総合スコア0

Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

WebRTC

WebRTC(Web Real-Time Communication)とは、プラグイン無しでウェブブラウザ間の音声通話・ビデオチャットなどリアルタイムコミュニケーションができるオープンフレームワークです。W3CがAPIレベルで、IETFがプロトコルレベルでそれぞれ標準化が進められています。

0グッド

0クリップ

投稿2022/01/24 08:41

前提・実現したいこと

iOS15.2 for Safariで開発中のブラウザアプリにおいてwebRTCを活用したマイク入力&録音を行い、その後webSocket経由でサーバへ送ったのち、自然言語処理の外部APIにデータを渡そうとしています。
(サーバ&クライアントはNodeJSにて開発 / 初心者ベースとお考えください)

下記RecordRTCのaudio-recording.htmlを参考にすべく、まずiPhone8側SafariにてTestLiveにおけるdemoを開き、ボタン押下できちんと録音&プレビューまで正常稼働できているのを確認しています。
https://github.com/muaz-khan/RecordRTC/blob/master/simple-demos/README.md

※現在、手元にiPhone8 しかないため、Android等の他端末では挙動確認できていません

audio-recording.htmlのエラー

まずサーバからwebsocketにてコマンドを受け取ったタイミングで、上記リンクのsourceをスマホ側のJSコード上にhtml表示させて音声入力ボタン(Start Recording)を押下すると、mediaDevices.getUserMediaが認識エラーとなるようです。
demoではボタン押下後にマイク許可の表示と、Safariの場合、さらに念押しの確認画面が出るはずなのですが、こちらのブラウザソースではマイク認識の時点でエラーとなってしまいます。
('This browser does not supports WebRTC getUserMedia API.')

なぜ同じソースコードでもdemoでできていて、JSで側のhtml表示ではエラーとなるか、初歩的な部分かもしれませんがよろしくご教示ください。

そもそもの音声入力はweb Speech APIにて行っていましたが、iOS14→15アップデート後に1秒尺くらいしか認識しなくなってしまい、急遽webRTCのボタン押下によって長尺の音声データを取得する方法へと変更しようといます。

html

1//htmlソースを変数HTML_webRTC02に設定したものを、サーバからのトリガー受信後に表示させようとしている 2 3const HTML_webRTC02 = 4'<html> 5 6<style> 7 html, 8 body { 9 margin: 0 !important; 10 padding: 0 !important; 11 } 12</style> 13 14<title>Audio Recording | RecordRTC</title> 15<h1>Simple Audio Recording using RecordRTC</h1> 16<meta charset="utf-8" /> 17<meta http-equiv="content-type" content="text/html; charset=utf-8" /> 18<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0"> 19 20<br> 21 22<button id="btn-start-recording">Start Recording</button> 23<button id="btn-stop-recording" disabled>Stop Recording</button> 24<button id="btn-release-microphone" disabled>Release Microphone</button> 25<button id="btn-download-recording" disabled>Download</button> 26 27<hr> 28<div><audio controls autoplay playsinline="true"></audio></div> 29 30<script src="https://www.WebRTC-Experiment.com/RecordRTC.js"></script> 31 32 33 34<script> 35 var audio = document.querySelector('audio'); 36 37 function captureMicrophone(callback) { 38 btnReleaseMicrophone.disabled = false; 39 40 if (microphone) { 41 callback(microphone); 42 return; 43 } 44 45 //!!最初の時点でデバイス認識エラーがでています 46 // 'This browser does not supports WebRTC getUserMedia API. 47 if (typeof navigator.mediaDevices === 'undefined' || !navigator.mediaDevices.getUserMedia) { 48 alert('This browser does not supports WebRTC getUserMedia API.'); 49 50 if (!!navigator.getUserMedia) { 51 alert('This browser seems supporting deprecated getUserMedia API.'); 52 } 53 } 54 55 navigator.mediaDevices.getUserMedia({ 56 audio: isEdge ? true : { 57 echoCancellation: false 58 } 59 }).then(function (mic) { 60 callback(mic); 61 }).catch(function (error) { 62 alert('Unable to capture your microphone. Please check console logs.'); 63 console.error(error); 64 }); 65 } 66 67 function replaceAudio(src) { 68 var newAudio = document.createElement('audio'); 69 newAudio.controls = true; 70 newAudio.autoplay = true; 71 72 if (src) { 73 newAudio.src = src; 74 } 75 76 var parentNode = audio.parentNode; 77 parentNode.innerHTML = ''; 78 parentNode.appendChild(newAudio); 79 80 audio = newAudio; 81 } 82 83 function stopRecordingCallback() { 84 //replaceAudio(URL.createObjectURL(recorder.getBlob())); 85 if (!recorder || !recorder.getBlob()) return; 86 recorder.getDataURL(function (audioDataURL) { 87 88 //8) 89 var files = { 90 audio: { 91 type: recorder.getBlob().type || 'audio/wav', 92 dataURL: audioDataURL 93 } 94 }; 95 // submit the audio file to the server 96 //socketio.emit('message', files); 97 98 //(2022.01.11)socketioは使わず、websocketをそのまま利用 99 sock.send(JSON.stringify({ 100 msg: scene14, 101 audio: { 102 type: recorder.getBlob().type || 'audio/wav', 103 dataURL: audioDataURL 104 } 105 })); 106 }); 107 108 btnStartRecording.disabled = false; 109 /* 110 setTimeout(function () { 111 if (!audio.paused) return; 112 113 setTimeout(function () { 114 if (!audio.paused) return; 115 audio.play(); 116 }, 1000); 117 118 audio.play(); 119 }, 300); 120 121 audio.play(); 122 */ 123 btnDownloadRecording.disabled = false; 124 125 if (isSafari) { 126 click(btnReleaseMicrophone); 127 } 128 } 129 130 var isEdge = navigator.userAgent.indexOf('Edge') !== -1 && (!!navigator.msSaveOrOpenBlob || !!navigator.msSaveBlob); 131 var isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent); 132 133 var recorder; // globally accessible 134 var microphone; 135 136 var btnStartRecording = document.getElementById('btn-start-recording'); 137 var btnStopRecording = document.getElementById('btn-stop-recording'); 138 var btnReleaseMicrophone = document.querySelector('#btn-release-microphone'); 139 var btnDownloadRecording = document.getElementById('btn-download-recording'); 140 141 btnStartRecording.onclick = function () { 142 this.disabled = true; 143 this.style.border = ''; 144 this.style.fontSize = ''; 145 146 if (!microphone) { 147 captureMicrophone(function (mic) { 148 microphone = mic; 149 150 if (isSafari) { 151 replaceAudio(); 152 153 audio.muted = true; 154 audio.srcObject = microphone; 155 156 btnStartRecording.disabled = false; 157 btnStartRecording.style.border = '1px solid red'; 158 btnStartRecording.style.fontSize = '150%'; 159 160 alert('Please click startRecording button again. First time we tried to access your microphone. Now we will record it.'); 161 return; 162 } 163 164 click(btnStartRecording); 165 }); 166 return; 167 } 168 169 replaceAudio(); 170 171 audio.muted = true; 172 audio.srcObject = microphone; 173 174 var options = { 175 type: 'audio', 176 numberOfAudioChannels: isEdge ? 1 : 2, 177 checkForInactiveTracks: true, 178 bufferSize: 16384 179 }; 180 181 if (isSafari || isEdge) { 182 options.recorderType = StereoAudioRecorder; 183 } 184 185 if (navigator.platform && navigator.platform.toString().toLowerCase().indexOf('win') === -1) { 186 options.sampleRate = 48000; // or 44100 or remove this line for default 187 } 188 189 if (isSafari) { 190 options.sampleRate = 44100; 191 options.bufferSize = 4096; 192 options.numberOfAudioChannels = 2; 193 } 194 195 if (recorder) { 196 recorder.destroy(); 197 recorder = null; 198 } 199 200 recorder = RecordRTC(microphone, options); 201 202 recorder.startRecording(); 203 204 btnStopRecording.disabled = false; 205 btnDownloadRecording.disabled = true; 206 }; 207 208 btnStopRecording.onclick = function () { 209 this.disabled = true; 210 recorder.stopRecording(stopRecordingCallback); 211 }; 212 213 btnReleaseMicrophone.onclick = function () { 214 this.disabled = true; 215 btnStartRecording.disabled = false; 216 217 if (microphone) { 218 microphone.stop(); 219 microphone = null; 220 } 221 222 if (recorder) { 223 // click(btnStopRecording); 224 } 225 }; 226 227 btnDownloadRecording.onclick = function () { 228 this.disabled = true; 229 if (!recorder || !recorder.getBlob()) return; 230 231 if (isSafari) { 232 recorder.getDataURL(function (dataURL) { 233 SaveToDisk(dataURL, getFileName('mp3')); 234 }); 235 return; 236 } 237 238 var blob = recorder.getBlob(); 239 var file = new File([blob], getFileName('mp3'), { 240 type: 'audio/mp3' 241 }); 242 invokeSaveAsDialog(file); 243 }; 244 245 246 247</script> 248 249<footer style="margin-top: 20px;"><small id="send-message"></small></footer> 250<script src="https://www.webrtc-experiment.com/common.js"></script> 251 252</html>'

以下はブラウザ側で表示させるエリア

html

1$('#phoneMain').html(HTML_webRTC02)

スマホブラウザ側のpug

html

1doctype html 2html(lang="jp") 3 head 4 meta(charset="utf-8") 5 meta(name="viewport" content="width=300") 6 link(rel='stylesheet', href='/css/style.css') 7 link(rel='stylesheet', href='/css/phone.css') 8 script(src="https://code.jquery.com/jquery-3.4.1.min.js", integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=", crossorigin="anonymous") 9 script(src="https://rawgit.com/kimmobrunfeldt/progressbar.js/master/dist/progressbar.min.js") 10 script(src="/js/howler.min.js") 11 script(src="/js/config.js") 12 script(src="/js/phone.js") 13 14 //webRTCのhtmlとJSをphoneJSのhtmlに追加 15 script(src="https://www.WebRTC-Experiment.com/RecordRTC.js") 16 17 body 18 // div.phoneSpacer &nbsp; 19 div#phoneMain 20 div.phoneSpacer &nbsp; 21 h2.phoneTitle #{msg} 22 // div.phoneSpacer &nbsp; 23 .phoneBtns 24 button.joinBtn#joinBtn 参加 25 div.phoneSpacer &nbsp; 26 div.phoneSpacer &nbsp; 27 div.ringTone 28 audio#ringTone(src="/mp4/office_phone.mp3", preload="auto") 29 div#status 30 31

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問