QEMU 中音频模拟如何工作

2017-09-30  本文已影响87人  hanpfei

事情有点棘手,但这里有一个粗略的描述:

QEMUSoundCard:建模一个给定的模拟的声卡
SWVoiceOut:建模一个来自 QEMUSoundCard 的音频输出
SWVoiceIn:建模一个来自 QEMUSoundCard 的音频输入

HWVoiceOut:建模一个主机端的音频输出(后端)
HWVoiceIn:建模一个主机端的音频输入(后端)

每个声音在采样大小,字节序,速率等方面都可以有自己的设置。

对于一个给定声卡的模拟典型的做法如下:

1/ 创建一个 QEMUSoundCard 对象,然后用 AUD_register_card() 注册它
2/ 对于每个模拟的输出,调用 AUD_open_out() 创建一个 SWVoiceOut 对象
3/ 对于每个模拟的输入,调用 AUD_open_in() 创建一个 SWVoiceIn 对象

注意你必须给 AUD_open_out()AUD_open_in() 传递一个回调函数;后面有更多相关内容。

每个 SWVoiceOut 与一个 HWVoiceOut 关联,每个 SWVoiceIn 与一个 HWVoiceIn 关联。

然而你可以让多个 SWVoiceOut 与相同的 HWVoiceOut 关联(相同的事情也发生在 SWVoiceIn/HWVoiceIn 中)。

声音播放细节

每个 HWVoiceOut 也有以下这些:

            |<----------------- samples ----------------------->|

            |                                                   |

            |       rpos                                        |
                    |
            |_______v___________________________________________|
            |       |                                           |
            |       |                                           |
            |_______|___________________________________________|

每个 SWVoiceOut 有以下这些:

                                         ______________
                                        |              |
                                        |  SWVoiceOut2 |
                                        |______________|
                  ______________           |
                 |              |          |
                 |  SWVoiceOut1 |          |     thsm<N> := total_hw_samples_mixed
                 |______________|          |                for SWVoiceOut<N>
                           |               |
                           |               |
                    |<-----|------------thsm2-->|
                    |      |                    |
                    |<---thsm1-------->|        |
             _______|__________________v________|_______________ 
            |       |111111111111111111|        v               |
            |       |222222222222222222222222222|               |
            |_______|___________________________________________|
                    ^
                    |         HWVoiceOut stereo buffer
                    rpos

这是一个小的图形,更好地解释了它:

   SWVoiceOut:  模拟的硬件声音缓冲区:
          |
          |   (通过 AUD_write() 混合,该函数在用户提供的回到中调用,
          |    回调本身在每次音频始终滴答时调用 ).
          |
          v
   HWVoiceOut: 立体声采样循环缓冲区
          |
          |   (通过 HWVoiceOut 的 `clip` 函数发送,它在 `run_out` 方法中调用,
          |    也在每次音频时钟滴答时调用)
          |
          v
   后端特有的声音缓冲区

audio/audio.c 中的 audio_timer() 函数被周期性地调用,且被用作一个执行声音缓冲区的传输和混合的脉冲。对于音频输出语音更具体的如下:

重要的是要注意SWVoiceOut回调:

因此,最后我们有伪代码:

    every sound timer ticks:
      for hw in list_HWVoiceOut:
         live = MIN([sw.total_hw_samples_mixed for sw in hw.list_SWVoiceOut ])
         if live > 0:
            played = hw.run_out(live)
            for sw in hw.list_SWVoiceOut:
                sw.total_hw_samples_mixed -= played

        for sw in hw.list_SWVoiceOut:
            free = hw.samples - sw.total_hw_samples_mixed
            if free > 0:
                sw.callback(sw, free)

录音详情

情况类似但顺序相反,比如,HWVoiceIn 在它的立体声缓冲区中获取声音采样数据,且 SWVoiceIn 对象必须尽快消费它们。

原文 $QEMU/android/docs/AUDIO.TXT

上一篇 下一篇

猜你喜欢

热点阅读