一、問題背景:
音樂播放器播放music,發現能夠播放但是沒有聲音,但是用tinyplay播放又有聲音。
二、問題分析:
無聲是必現的,抓取log分析,發現播放音訊時並沒有走primary module,而是走的r_submix module,這個無聲問題就能解釋通了,音訊流並沒有走到adsp。
07-24 11:59:21.285 1015 1859 I AudioFlinger: openOutput() this 0xb4000077f35ce9c0, module 26 Device AUDIO_DEVICE_OUT_REMOTE_SUBMIX, @:0, SamplingRate 48000, Format 0x000001, Channels 0x3, flags 0
07-24 11:59:21.286 907 930 D r_submix: adev_open_output_stream(address=0)
07-24 11:59:21.287 907 930 I r_submix: adev_open_output_stream(): about to create pipe at index 9, rate 48000, pipe size 4096
07-24 11:59:21.287 907 930 D r_submix: submix_audio_device_create_pipe_l(addr=0, idx=9)
07-24 11:59:21.287 907 930 D r_submix: now using address 0 for route 9
為什麼會走到AUDIO_DEVICE_OUT_REMOTE_SUBMIX這個裝置出去呢? 從官網上查詢到REMOTE_SUBMIX這個音訊型別,描述上看就是捕獲裝置音訊流投到遠端裝置上。
參考官網:MediaRecorder.AudioSource | Android Developers (google.cn)
從log上看,確實有錄音動作,AUDIO_SOURCE_REMOTE_SUBMIX這個就是REMOTE_SUBMIX這個音源型別
7-24 11:59:21.235 1015 1015 V APM_AudioPolicyManager: getInputForAttr() source 8, sampling rate 48000, format 0x1, channel mask 0xc, session 225, flags 0 attributes={ Content type: AUDIO_CONTENT_TYPE_UNKNOWN Usage: AUDIO_USAGE_UNKNOWN Source: AUDIO_SOURCE_REMOTE_SUBMIX Flags: 0x800 Tags: } requested device ID 0
07-24 11:59:21.236 1015 1015 V APM_AudioPolicyManager: getInputForAttr found device type is 0x80000100
07-24 11:59:21.238 907 930 D r_submix: adev_open_input_stream(addr=0)
07-24 11:59:21.239 907 930 I r_submix: adev_open_input_stream(): about to create pipe at index 9, rate 48000, pipe size 4096
07-24 11:59:21.239 907 930 D r_submix: submix_audio_device_create_pipe_l(addr=0, idx=9)
07-24 11:59:21.240 907 930 D r_submix: now using address 0 for route 9
同測試溝通,瞭解到使用了scrcpy投屏工具,這就對上了
三、scrcpy音訊錄製分析:
下載scrcpy原始碼:github.com/Genymobile/…
原始碼中確實有錄音動作,AudioCapture.java中會建立AudioRecord scrcpy/server/src/main/java/com/genymobile/scrcpy/AudioCapture.java
private static AudioRecord createAudioRecord(int audioSource) { AudioRecord.Builder builder = new AudioRecord.Builder(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { // On older APIs, Workarounds.fillAppInfo() must be called beforehand builder.setContext(FakeContext.get()); } builder.setAudioSource(audioSource); builder.setAudioFormat(createAudioFormat()); int minBufferSize = AudioRecord.getMinBufferSize(SAMPLE_RATE, CHANNEL_CONFIG, ENCODING); // This buffer size does not impact latency builder.setBufferSizeInBytes(8 * minBufferSize); return builder.build(); }
跟蹤audioSource來源,發現是MediaRecorder.AudioSource.REMOTE_SUBMIX這個音訊源,這個又對上了
Options.java
private AudioSource audioSource = AudioSource.OUTPUT;
AudioSource.java
OUTPUT("output", MediaRecorder.AudioSource.REMOTE_SUBMIX),
scrcpy錄製Android裝置音訊原理:原始碼中的java程式碼編譯打包到scrcpy-server,然後push到Android裝置,執行app_process執行scrcpy-server
四、總結:
scrcpy投屏工具將Android裝置音訊流錄製後投到PC端,PC端插上耳機後能聽到Android裝置播放的music