涉及平台:rk3399、ok4418
系统音频设备信息
rk3399_all:/ $ ls /dev/snd/
controlC0 controlC2 pcmC0D0p pcmC1D0p timer
controlC1 pcmC0D0c pcmC1D0c pcmC2D0p
rk3399_all:/ $ ls /sys/class/sound/
card0 card2 controlC1 pcmC0D0c pcmC1D0c pcmC2D0p
card1 controlC0 controlC2 pcmC0D0p pcmC1D0p timer
rk3399_all:/ $ cat /sys/class/sound/card0/id
RKPCMCARD
rk3399_all:/ $ cat /sys/class/sound/card0/number
0
rk3399_all:/ $ cat /sys/class/sound/card0/controlC0/dev
116:2
rk3399_all:/ $ cat /sys/class/sound/card1/id
RKWM8960
rk3399_all:/ $ cat /sys/class/sound/card1/number
1
rk3399_all:/ $ cat /sys/class/sound/card1/controlC1/dev
116:5
rk3399_all:/ $ cat /sys/class/sound/card2/id
rockchiphdmi
rk3399_all:/ $ cat /sys/class/sound/card2/number
2
rk3399_all:/ $ cat /sys/class/sound/card2/controlC2/dev
116:8
内核音频设备加载信息
RK3399:
[ 5.280018] ALSA device list:
[ 5.280228] #0: RK-PCM-CARD
[ 5.280428] #1: RKWM8960
[ 5.280671] #2: rockchip,hdmi
ok4418:
[ 2.477000] ALSA device list:
[ 2.480000] #0: I2S-WM8960
[ 2.483000] #1: SPDIF-Transciever
虚拟声卡
RK3399 设备树定义的虚拟声卡
rockchip_pcm_codec: rockchip-pcm-codec {
compatible = "rockchip-pcm-codec";
};
rockchip-pcm-card {
compatible = "rockchip-pcm-card";
status = "okay";
dais {
dai0 {
audio-codec = <&rockchip_pcm_codec>;
audio-controller = <&i2s1>;
format = "i2s";
};
};
};
驱动文件
kernel/sound/soc/codecs/rk_pcm_codec.c
struct snd_soc_dai_driver pcm_card_dai = {
.name = "rockchip-pcm-card-hifi",
.playback = {
.stream_name = "HiFi Playback",
.channels_min = 2,
.channels_max = 2,
.rates = (SNDRV_PCM_RATE_8000|
SNDRV_PCM_RATE_16000 |
SNDRV_PCM_RATE_32000 |
SNDRV_PCM_RATE_44100 |
SNDRV_PCM_RATE_48000 |
SNDRV_PCM_RATE_96000 |
SNDRV_PCM_RATE_192000),
.formats = FORMATS,
},
.capture = {
.stream_name = "HiFi Capture",
.channels_min = 2,
.channels_max = 2,
.rates = (
SNDRV_PCM_RATE_8000|
SNDRV_PCM_RATE_16000|
SNDRV_PCM_RATE_32000 |
SNDRV_PCM_RATE_44100 |
SNDRV_PCM_RATE_48000 |
SNDRV_PCM_RATE_96000 |
SNDRV_PCM_RATE_192000),
.formats = FORMATS,
},
};
xx18 板级文件定义的虚拟网卡
#if defined(CONFIG_SND_CODEC_NULL)
static struct platform_device snd_null = {
.name = "snd-null",
.id = -1,
};
struct nxp_snd_dai_plat_data snd_null_dai_data = {
.i2s_ch = 0,
.sample_rate = 48000,
.pcm_format = SNDRV_PCM_FMTBIT_S16_LE,
};
static struct platform_device snd_null_dai = {
.name = "snd-null-card",
.id = -1,
.dev = {
.platform_data = &snd_null_dai_data,
}
};
//-------------------------------------
static struct platform_device snd_null_1 = {
.name = "snd-null",
.id = 1,
};
struct nxp_snd_dai_plat_data snd_null_dai_data_1 = {
.i2s_ch = 1,
.sample_rate = 48000,
.pcm_format = SNDRV_PCM_FMTBIT_S16_LE,
};
static struct platform_device snd_null_dai_1 = {
.name = "snd-null-card",
.id = 1,
.dev = {
.platform_data = &snd_null_dai_data_1 ,
}
};
//-------------------------------------
static struct platform_device snd_null_2 = {
.name = "snd-null",
.id = 2,
};
struct nxp_snd_dai_plat_data snd_null_dai_data_2 = {
.i2s_ch = 2,
.sample_rate = 48000,
.pcm_format = SNDRV_PCM_FMTBIT_S16_LE,
};
static struct platform_device snd_null_dai_2 = {
.name = "snd-null-card",
.id = 2,
.dev = {
.platform_data = &snd_null_dai_data_2 ,
}
};
#endif
驱动程序
linux/kernel/kernel-3.4.39/sound/soc/nexell/nxp-null.c
static struct platform_driver snd_null_driver = {
.probe = snd_null_probe,
.remove = snd_null_remove,
.driver = {
.name = "snd-null",
.owner = THIS_MODULE,
},
};
module_platform_driver(snd_null_driver);
static struct platform_driver snd_card_driver = {
.driver = {
.name = "snd-null-card",
.owner = THIS_MODULE,
.pm = &snd_soc_pm_ops, /* for suspend */
},
.probe = snd_card_probe,
.remove = snd_card_remove,
};
module_platform_driver(snd_card_driver);
Android下虚拟声卡的应用
当外接的音频codec缺失的情况下,Android系统有部分功能会因声卡的缺失而异常:
1、摄像头不能录像
I/MediaCodec( 132): MediaCodec will operate in async mode
E/audio_hw_primary( 132): get_input_buffer_size not opened input device, set default pcm config !!!
E/audio_hw_primary( 132): pcm_config_setup pcmC0D0c device does not exist.
E/AudioSystem( 132): AudioSystem::getInputBufferSize failed sampleRate 44100 format 0x1 channelMask 10
E/AudioRecord( 132): AudioSystem could not query the input buffer size for sampleRate 44100, format 0x1, channelMask 0x10; status -22
E/StagefrightRecorder( 132): audio source is not initialized
D/MPEG4Writer( 132): Video track stopping
E/MPEG4Writer( 132): Stop() called but track is not started
D/NX_OMXENC( 132): Sequrnce buffer Size = 21
E/MediaRecorder( 1337): start failed: -2147483648
E/CAM_VideoModule( 1337): Could not start media recorder.
E/CAM_VideoModule( 1337): java.lang.RuntimeException: start failed.
E/CAM_VideoModule( 1337): at android.media.MediaRecorder.start(Native Method)
E/CAM_VideoModule( 1337): at com.android.camera.VideoModule$11.onStorageUpdateDone(VideoModule.java:1376)
E/CAM_VideoModule( 1337): at com.android.camera.CameraActivity$19.onPostExecute(CameraActivity.java:2089)
E/CAM_VideoModule( 1337): at com.android.camera.CameraActivity$19.onPostExecute(CameraActivity.java:2074)
E/CAM_VideoModule( 1337): at android.os.AsyncTask.finish(AsyncTask.java:636)
E/CAM_VideoModule( 1337): at android.os.AsyncTask.access$500(AsyncTask.java:177)
E/CAM_VideoModule( 1337): at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:653)
E/CAM_VideoModule( 1337): at android.os.Handler.dispatchMessage(Handler.java:102)
E/CAM_VideoModule( 1337): at android.os.Looper.loop(Looper.java:135)
E/CAM_VideoModule( 1337): at android.app.ActivityThread.main(ActivityThread.java:5254)
E/CAM_VideoModule( 1337): at java.lang.reflect.Method.invoke(Native Method)
E/CAM_VideoModule( 1337): at java.lang.reflect.Method.invoke(Method.java:372)
E/CAM_VideoModule( 1337): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
E/CAM_VideoModule( 1337): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
I/CAM_VideoModule( 1337): Releasing media recorder.
2、播放视频卡顿
这个时候注册虚拟声卡就可以解决这种问题。
TBC