😇
Mobile Safari(iPad,iPhone)でRecordRTCで無音の音声しか録音できない現象に遭遇した件
- RecordRTCを使い、ブラウザ上で音声の録音をしようと思ったところ、iPad, iPhoneのSafariでのみ無音の音声が録音されるという現象が発生したので、解決策のメモ
現象が発生するときの実装
音声を録音モジュールの実装は以下
export default clas AudioRecordingModule{
public asyn setAudioStream(){
private stream?: MediaStream
private recorder?: RecordRTC
private mediaDevice?: MediaDevices
try {
this.stream = await navigator.mediaDevices.getUserMedia({
audio: true,
})
this.recorder = new RecordRTC(stream.clone(), {
type: 'audio',
mimeType: 'audio/wav',
disableLogs: true,
recorderType: StereoAudioRecorder,
numberOfAudioChannels: 2,
})
} catch (e) {
console.log(e)
return false
}
}
public async recStart() {
if (state == 'recording') {
this.recorder?.stopRecording()
}
this.recorder.reset()
this.recorder = new RecordRTC(stream.clone(), {
type: 'audio',
mimeType: 'audio/wav',
disableLogs: true,
recorderType: StereoAudioRecorder,
numberOfAudioChannels: 2,
})
this.recorder.startRecording()
}
}
- 録音する直前ではなく、ページを表示した際にデバイスアクセスの許可をとり、取得したMediaStreamを使ってrecorderを起動。
- RecordRTCのインスタンスは一度作ったら流用。
- AndroidのChrome,WindowsのChrome,Macのsafariなどでは問題なく動作をしましたが、iOS(iPadOS)のsafariだと無音の音声が録音されるという現象が発生。
- 無音ですが、録音時にはエラーメッセージもなく、録音した時間分は確保されている状態。
原因の調査
- 現象として、調査をしている中分かったことは
- 録音開始時等にエラーは表示されない
- 無音だけれども、録音時間分のデータは作成されている
-
- の現象として、さらに細かく分けると以下の3つの可能性を考えました。
- 録音後に、実際にはwav->mp3変換を行っているが、そこでデータが落ちている(変換の問題)
- 時間分のデータが作成されていることから、録音は実際にできているものの、ブラウザ上(またはデバイス上)で何かしらの問題で再生がされていない(ブラウザとデータの問題)
- 録音時にMediaStreamとの接続がうまくいっていない(録音時のデバイス接続の問題)
- 結果的には3が正しかったのですが、前述のコードでもRecordRTCが読み取っているMediaStreamはちゃんととっているし問題は無い…はず…
- RecordRTCは再利用不可だったとして、録音時にsetAudioStreamを叩くようにしたときに動作をしないのが解せない…
問題を解決した実装
export default clas AudioRecordingModule{
private stream?: MediaStream
private recorder?: RecordRTC
private mediaDevice?: MediaDevices
public asyn setAudioStream(){
try {
this.getStream()
} catch (e) {
console.log(e)
return false
}
}
private async getStream(){
if(!this.stream){
this.stream = await navigator.mediaDevices.getUserMedia({
audio: true,
})
}
return this.stream
}
public async recStart() {
if (state == 'recording') {
this.recorder?.stopRecording()
}
if(this.recorder){
this.recorder.destroy()
}
const stream = this.getStream()
this.recorder = new RecordRTC(stream.clone(), {
type: 'audio',
mimeType: 'audio/wav',
disableLogs: true,
recorderType: StereoAudioRecorder,
numberOfAudioChannels: 2,
})
this.recorder.startRecording()
}
}
- 変更としては
- Streamは再利用
- RecordRTCは録音時に毎回インスタンスを破棄し作成をする
解決した実装を見て
- 解せぬ…が、streamは読み込む度にIDが変更される。iOSでは、複数のタブでMediaStreamを読み込むと、最期にアクティブになったメディアストリームが生き、他は一時停止される。
- ページ内でMediaStreamを読み込むと、実際に録音に使っているMediaStreamが停止され、マイクにアクセスできないという現象はあり得るかもしれない。
- であれば、最初の実装でなぜ動かないのか…はよくわからない…
- RecordRTCは録音の直前にインスタンスを起動し、Streamは必ず使いまわしたほうが良い。
- ちゃんと接続ができていないなら、ちゃんとエラーを表示してほしい…(切実
Discussion