RPi 2B/3B与DragonBoard 410c的不同之处在于它有一个耳机接口,你只需要一条耳机线,就可以利用它来播放音乐或者是播放一些提示信息。原以为使RPi 3B在Brillo系统下正常工作是一件很难的事情:由于之前一直在做高通Android的项目,关于Audio的配置非常的复杂,所以对Audio模块有点畏惧。这几天硬着头皮去看了一下Intel Edison/Qualcomm DragonBoard/Rockchip Kylin与Audio HAL层相关的代码,发现基本上大同小异,基本上都是是建立在ALSA架构的基础上。这里,RPi 3B @ brillo-m10-dev也是在复用Rockchhip Kylin上的代码。
- kernel及audio驱动
从kernel log中,我们可以看到kernel已经识别出来RPi 3B的音频设备,并使用ALSA架构:
01-01 00:00:03.140 0 0 W : Indeed it is in host mode hprt0 = 00001101
01-01 00:00:03.154 0 0 I netconsole: network logging started
01-01 00:00:03.163 0 0 E : Starting self testing
01-01 00:00:03.166 0 0 E : Finished self testing
01-01 00:00:03.170 0 0 I : ALSA device list:
01-01 00:00:03.173 0 0 I : #0: Dummy 1
01-01 00:00:03.175 0 0 I : #1: bcm2835 ALSA
01-01 00:00:03.180 0 0 I : Freeing unused kernel memory: 1024K (80d00000 - 80e00000)
01-01 00:00:03.189 0 0 I init : init first stage started!
01-01 00:00:03.202 0 0 D SELinux : 2048 avtab hash slots, 6576 rules.
01-01 00:00:03.210 0 0 D SELinux : 2048 avtab hash slots, 6576 rules.
01-01 00:00:03.210 0 0 D SELinux : 1 users, 2 roles, 661 types, 0 bools, 1 sens, 1024 cats
01-01 00:00:03.210 0 0 D SELinux : 56 classes, 6576 rules
我们可以通过/sys/class/sound目录查看当前系统有几个音频设备:
$ adb shell ls -l /sys/class/sound/
total 0
lrwxrwxrwx 1 root root 0 2016-04-02 10:39 card0 -> ../../devices/platform/snd_dummy.0/sound/card0
lrwxrwxrwx 1 root root 0 2016-04-02 10:39 card1 -> ../../devices/virtual/sound/card1
lrwxrwxrwx 1 root root 0 2016-04-02 10:39 controlC0 -> ../../devices/platform/snd_dummy.0/sound/card0/controlC0
lrwxrwxrwx 1 root root 0 2016-04-02 10:39 controlC1 -> ../../devices/virtual/sound/card1/controlC1
lrwxrwxrwx 1 root root 0 2016-04-02 10:39 pcmC0D0c -> ../../devices/platform/snd_dummy.0/sound/card0/pcmC0D0c
lrwxrwxrwx 1 root root 0 2016-04-02 10:39 pcmC0D0p -> ../../devices/platform/snd_dummy.0/sound/card0/pcmC0D0p
lrwxrwxrwx 1 root root 0 2016-04-02 10:39 pcmC1D0p -> ../../devices/virtual/sound/card1/pcmC1D0p
lrwxrwxrwx 1 root root 0 2016-04-02 10:39 pcmC1D1p -> ../../devices/virtual/sound/card1/pcmC1D1p
lrwxrwxrwx 1 root root 0 2016-04-02 10:39 timer -> ../../devices/virtual/sound/timer
这里,我们可以看到当前有两个音频设备: card0, card1。我们可以通过查看/sys/class/sound/card?/id来确实当音频设备的名称:
$ adb shell cat /sys/class/sound/card0/id Dummy $ adb shell cat /sys/class/sound/card1/id ALSA
- 相关工具
在Brillo-m10-dev系统中,我们已经将tinycap/tinymix/tinypcminfo/tinyplay这些工具编译进系统了,下面我们看一下这些工具的用法:
1. tinypcminfo – 查看音频设备信息(bcm2835是card1):
# tinypcminfo -D 1 Info for card 1, device 0: PCM out: Access: 0x000009 Format[0]: 0x000006 Format[1]: 00000000 Format Name: U8, S16_LE Subformat: 0x000001 Rate: min=8000Hz max=48000Hz Channels: min=1 max=2 Sample bits: min=8 max=16 Period size: min=256 max=65536 Period count: min=1 max=128 PCM in: cannot open device '/dev/snd/pcmC1D0c' Device does not exist.
可以看到这个单频设备只支持PCM输入,不支持PCM输入。
2. tinymix – 查看当前音频设备包含哪些widget:
# tinymix -D 1
Mixer name: 'bcm2835 ALSA'
Number of controls: 6
ctl type num name value
0 INT 1 PCM Playback Volume 0
1 BOOL 1 PCM Playback Switch On
2 INT 1 PCM Playback Route 0
3 IEC958 1 IEC958 Playback Default unknown
4 IEC958 1 IEC958 Playback Con Mask unknown
5 IEC958 1 IEC958 Playback PCM Stream unknown
NOTE: 看来还是得用tinymix来查看音频设备的名称比较好:能够正确显示当前card1对应的名称为bcm2835 ALSA。
3. tinyplay – 播放wav格式的音频文件:
# tinyplay /data/Over_the_Horizon.wav -D 1 Playing sample: 2 ch, 44100 hz, 16 bit
NOTE: 播放的时候需要指定音频设备。
4. tinycap – 录音
- Audio HAL实现
代码直接复用hardware/bsp/rockchip/peripheral/audio/generic的代码并用少量修改:
1. audio_hw.c
diff -r /local/brillo-m10-dev-rpi3b/device/hzak/rpi3b/bsp/audio/audio_hal.c generic/audio_hal.c 50c50 < #define AUDIO_STR "bcm2835" --- > #define AUDIO_STR "rt5616" 708d707 < out->profile->default_config.period_count = 4; 1129c1128 < #if 0 //TARGET_AUDIO_PRIMARY --- > #if TARGET_AUDIO_PRIMARY 1191c1190 < #if 0 //TARGET_AUDIO_PRIMARY --- > #if TARGET_AUDIO_PRIMARY 1226c1225 < #if 0 //TARGET_AUDIO_PRIMARY --- > #if TARGET_AUDIO_PRIMARY
2. audio_policy.conf
global_configuration { attached_output_devices AUDIO_DEVICE_OUT_WIRED_HEADPHONE default_output_device AUDIO_DEVICE_OUT_WIRED_HEADPHONE } audio_hw_modules { primary { outputs { primary { sampling_rates 8000|11025|12000|16000|22050|24000|32000|44100|48000 channel_masks AUDIO_CHANNEL_OUT_STEREO formats AUDIO_FORMAT_PCM_16_BIT devices AUDIO_DEVICE_OUT_WIRED_HEADPHONE flags AUDIO_OUTPUT_FLAG_PRIMARY } } } }
3. 加入Audio Effect模块,以便可以对不支持持音频文件进行resample
# Effect libraries PRODUCT_PACKAGES += \ libbundlewrapper \ libreverbwrapper \ libvisualizer \ libdownmix \ libldnhncr PRODUCT_COPY_FILES += \ frameworks/av/media/libeffects/data/audio_effects.conf:system/etc/audio_effects.conf
- 验证
我们可以通过stagefright命令验证Audio HAL模块是否能够正常播放。stagefright没有编译进system image中,可以通过如下命令单独编译stagefright模块:
hzak@B85RPI:/local/brillo-m10-dev-rpi3b$ mmm frameworks/av/cmds/stagefright/:stagefright $ adb remount $ adb sync system
使用stagefright播放音频文件:
# stagefright -a -o /data/Over\ the\ Horizon.mp3
- 调试相关
显示系统服务:
$ adb shell service list
Found 17 services:
0 media.radio: [android.hardware.IRadioService]
1 media.sound_trigger_hw: [android.hardware.ISoundTriggerHwService]
2 media.audio_policy: [android.media.IAudioPolicyService]
3 media.camera: [android.hardware.ICameraService]
4 media.resource_manager: [android.media.IResourceManagerService]
5 media.player: [android.media.IMediaPlayerService]
6 media.audio_flinger: [android.media.IAudioFlinger]
7 bluetooth-service: [bluetooth-service]
8 android.brillo.UpdateEngineService: [android.brillo.IUpdateEngine]
9 sensorservice: [android.gui.SensorServer]
10 weave_service: [android.weave.IWeaveServiceManager]
11 android.brillo.metrics.IMetricsCollectorService: [android.brillo.metrics.IMetricsCollectorService]
12 android.brillo.metrics.IMetricsd: [android.brillo.metrics.IMetricsd]
13 android.security.keystore: [android.security.IKeystoreService]
14 example_led_service: [brillo.examples.ledflasher.ILEDService]
15 android.os.IPeripheralManager: [android.os.IPeripheralManager]
16 power: [android.os.IPowerManager]
dumpsys media.audio_policy:
$ adb shell dumpsys media.audio_policy
AudioPolicyManager: 0x75bc5000
Command Thread: 0x75baaa80
Tones Thread: 0x75baaa20
AudioCommandThread 0x75baaa80 Dump
- Commands:
Command Time Wait pParam
Last Command
07 000956.109 0 0x7502e400
AudioCommandThread 0x75baaa20 Dump
- Commands:
Command Time Wait pParam
Last Command
none
AudioPolicyManager Dump: 0x75bc5000
Primary Output: 2
Phone state: 0
Force use for communications 0
Force use for media 0
Force use for record 0
Force use for dock 0
Force use for system 0
Force use for hdmi system audio 0
TTS output not available
Available output devices:
Device 1:
- id: 1
- type: AUDIO_DEVICE_OUT_WIRED_HEADPHONE
Available input devices:
HW Modules dump:
- HW Module 1:
- name: primary
- handle: 1
- version: 2.0
- outputs:
output 0:
- name: primary
- sampling rates: 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
- channel masks: 0x0003
- formats: AUDIO_FORMAT_PCM_16_BIT
- flags: 0x0002
- devices:
Device 1:
- type: AUDIO_DEVICE_OUT_WIRED_HEADPHONE
...