1
完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
接入某些USB摄像头后, 扬声器没有声音
2017-01-01 21:19:24.770 228-287/? E/AudioHardwareTiny: pcm_open(PCM_CARD_HDMI) failed: 222 cannot open device '/dev/snd/pcmC0D1p': No such file or directory 原因 USB摄像头包含有MIC输入, 在启动初始化后, 会直接抢占card0, 而默认的声卡的初始化比这个慢, 导致card0中, 只有一个有效的输入, 而没有输出; 主要的原因还是, 在HAL中, 并没有对无效的输出作处理, 有的, 只有上面一个错误的LOG. 解决方案
diff --git a/hardware/rockchip/audio/tinyalsa_hal/audio_hw.c b/hardware/rockchip/audio/tinyalsa_hal/audio_hw.c index 53069ab..266fcac 100755 --- a/hardware/rockchip/audio/tinyalsa_hal/audio_hw.c +++ b/hardware/rockchip/audio/tinyalsa_hal/audio_hw.c @@ -660,33 +660,54 @@ static int start_output_stream(struct stream_out *out) } } + ALOGD("start_output_stream :666 out->device=%x", out->device); if (out->device & (AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_OUT_WIRED_HEADSET | AUDIO_DEVICE_OUT_WIRED_HEADPHONE | AUDIO_DEVICE_OUT_ALL_SCO)) { + int card = PCM_CARD_HDMI; + bool success = true; /* open & close hdmi card to mute hdmi audio */ - out->pcm_device = 1; - out->pcm[PCM_CARD_HDMI] = pcm_open(PCM_CARD_HDMI, out->pcm_device, + out->pcm_device = 1; + ALOGD("start_output_stream pcm_open(%d, %d)", card, out->pcm_device); + out->pcm[0] = pcm_open(card, out->pcm_device, PCM_OUT | PCM_MONOTONIC, &out->config); - if (out->pcm[PCM_CARD_HDMI] && - !pcm_is_ready(out->pcm[PCM_CARD_HDMI])) { - ALOGE("pcm_open(PCM_CARD_HDMI) failed: 222%s", - pcm_get_error(out->pcm[PCM_CARD_HDMI])); - pcm_close(out->pcm[PCM_CARD_HDMI]); - return -ENOMEM; + if (out->pcm[0] && + !pcm_is_ready(out->pcm[0])) { + ALOGE("pcm_open(PCM_CARD_HDMI) failed: 222 %s", + pcm_get_error(out->pcm[0])); + pcm_close(out->pcm[0]); + success = false; + //return -ENOMEM; } - if (out->pcm[PCM_CARD_HDMI]) - pcm_close(out->pcm[PCM_CARD_HDMI]); - out->pcm_device = 0; - out->pcm[PCM_CARD] = pcm_open(PCM_CARD, out->pcm_device, + + if(!success){ + //CARD 1 + card = PCM_CARD_BOARD; + out->pcm[0] = pcm_open(card, out->pcm_device, + PCM_OUT | PCM_MONOTONIC, &out->config); + if (out->pcm[0] && + !pcm_is_ready(out->pcm[0])) { + ALOGE("pcm_open(%d) failed: 222 %s", + card, pcm_get_error(out->pcm[0])); + pcm_close(out->pcm[0]); + return -ENOMEM; + } + } + + if (out->pcm[0]) + pcm_close(out->pcm[0]); + + out->pcm_device = 0; + ALOGD("start_output_stream pcm_open(%d, %d) b", card, out->pcm_device); + out->pcm[0] = pcm_open(card, out->pcm_device, PCM_OUT | PCM_MONOTONIC, &out->config); - if (out->pcm[PCM_CARD] && !pcm_is_ready(out->pcm[PCM_CARD])) { - ALOGE("pcm_open(PCM_CARD) failed: %s", - pcm_get_error(out->pcm[PCM_CARD])); - pcm_close(out->pcm[PCM_CARD]); - return -ENOMEM; + if (out->pcm[0] && !pcm_is_ready(out->pcm[0])) { + ALOGE("pcm_open(PCM_CARD) failed: %s", + pcm_get_error(out->pcm[0])); + pcm_close(out->pcm[0]); + return -ENOMEM; } - } if (out->device & AUDIO_DEVICE_OUT_SPDIF) { @@ -707,8 +728,10 @@ static int start_output_stream(struct stream_out *out) adev->out_device |= out->device; if (out->device & AUDIO_DEVICE_OUT_ALL_SCO) { + ALOGD("start_output_stream ALL_SCO"); start_bt_sco(adev); #ifdef BT_AP_SCO // HARD CODE FIXME + ALOGD("start_output_stream BT_AP_SCO"); out->pcm[PCM_BT] = pcm_open(PCM_BT, 0, PCM_OUT | PCM_MONOTONIC, &pcm_config_ap_sco); ret = create_resampler(48000, @@ -1545,6 +1568,7 @@ static void set_data_slice(void *in_data,struct stream_out *out,size_t length) static ssize_t out_write(struct audio_stream_out *stream, const void* buffer, size_t bytes) { + ALOGD("out_write"); int ret = 0; struct stream_out *out = (struct stream_out *)stream; struct audio_device *adev = out->dev; diff --git a/hardware/rockchip/audio/tinyalsa_hal/audio_hw.h b/hardware/rockchip/audio/tinyalsa_hal/audio_hw.h index aebcd0a..f579c10 100755 --- a/hardware/rockchip/audio/tinyalsa_hal/audio_hw.h +++ b/hardware/rockchip/audio/tinyalsa_hal/audio_hw.h @@ -83,6 +83,7 @@ int PCM_CARD_SPDIF = 1; #else int PCM_CARD = 0; int PCM_CARD_HDMI = 0; +int PCM_CARD_BOARD = 1; int PCM_CARD_SPDIF = 2; #endif int PCM_BT = 3; 状态信息 //声卡 rk3288:/ # ll proc/asound/ total 0 lrwxrwxrwx 1 root root 5 2017-01-02 00:52 AMCAP -> card0 dr-xr-xr-x 3 root root 0 2017-01-02 00:52 card0 dr-xr-xr-x 5 root root 0 2017-01-02 00:52 card1 -r--r--r-- 1 root root 0 2017-01-02 00:52 cards -r--r--r-- 1 root root 0 2017-01-02 00:52 devices -r--r--r-- 1 root root 0 2017-01-02 00:52 hwdep -r--r--r-- 1 root root 0 2017-01-02 00:52 pcm lrwxrwxrwx 1 root root 5 2017-01-02 00:52 rockchipes8316c -> card1 -r--r--r-- 1 root root 0 2017-01-02 00:52 timers -r--r--r-- 1 root root 0 2017-01-02 00:52 version //声卡信息, 0为USB摄像头 rk3288:/ # cat /proc/asound/cards 0 [AMCAP ]: USB-Audio - USB 2.0 AMCAP Sonix Technology Co., Ltd. USB 2.0 AMCAP at u***-ff540000.u***-1.2, high speed 1 [rockchipes8316c]: rockchip_es8316 - rockchip,es8316-codec rockchip,es8316-codec //声卡设备 rk3288:/ # cat /proc/asound/devices 2: [ 0] : control 3: [ 0- 0]: digital audio capture 4: [ 1] : control 5: [ 1- 0]: digital audio playback 6: [ 1- 0]: digital audio capture 7: [ 1- 1]: digital audio playback 33: : timer //设备节点 rk3288:/dev/snd # ll total 0 crw-rw---- 1 system audio 116, 2 2017-01-02 00:26 controlC0 crw-rw---- 1 system audio 116, 4 2017-01-02 00:26 controlC1 crw-rw---- 1 system audio 116, 3 2017-01-02 00:26 pcmC0D0c crw-rw---- 1 system audio 116, 6 2017-01-02 00:26 pcmC1D0c crw-rw---- 1 system audio 116, 5 2017-01-02 00:26 pcmC1D0p crw-rw---- 1 system audio 116, 7 2017-01-02 00:26 pcmC1D1p crw-rw---- 1 system audio 116, 33 2017-01-02 00:26 timer //输出PCM信息 rk3288:/ # tinypcminfo -D 0 Info for card 0, device 0: PCM out: cannot open device '/dev/snd/pcmC0D0p' Device does not exist. PCM in: Access: 0x000009 Format[0]: 0x000004 Format[1]: 00000000 Format Name: S16_LE Subformat: 0x000001 Rate: min=8000Hz max=48000Hz Channels: min=2 max=2 Sample bits: min=16 max=16 Period size: min=16 max=131072 Period count: min=2 max=1024 rk3288:/ # tinypcminfo -D 1 Info for card 1, device 0: PCM out: Access: 0x000009 Format[0]: 0x000044 Format[1]: 00000000 Format Name: S16_LE, S24_LE Subformat: 0x000001 Rate: min=8000Hz max=96000Hz Channels: min=2 max=2 Sample bits: min=16 max=32 Period size: min=32 max=65536 Period count: min=2 max=4096 PCM in: Access: 0x000009 Format[0]: 0x000044 Format[1]: 00000000 Format Name: S16_LE, S24_LE Subformat: 0x000001 Rate: min=8000Hz max=96000Hz Channels: min=2 max=2 Sample bits: min=16 max=32 Period size: min=32 max=65536 Period count: min=2 max=4096 相关源码 rk3288_n712$ ll hardware/rockchip/audio/tinyalsa_hal/ alsa_audio.h alsa_mixer.c alsa_route.c amix.c Android.mk asound.h audio_bitstream.c audio_bitstream.h audio_hw.c audio_hw.h audio_hw_hdmi.c audio_hw_hdmi.h audio_setting.c audio_setting.h codec_config/ voice_preprocess.c voice_preprocess.h |-- hardware/rockchip/audio/tinyalsa_hal/audio_hw.c static int start_output_stream(struct stream_out *out) { ALOGD("start_output_stream"); char value[PROPERTY_VALUE_MAX] = ""; struct audio_device *adev = out->dev; int type; bool connect_hdmi = true; int ret = 0; ALOGD("%s",__FUNCTION__); if (out == adev->outputs[OUTPUT_HDMI_MULTI]) { force_non_hdmi_out_standby(adev); } else if (adev->outputs[OUTPUT_HDMI_MULTI] && !adev->outputs[OUTPUT_HDMI_MULTI]->standby) { out->disabled = true; return 0; } out->disabled = false; read_hdmi_audioinfo(); int device = getOutputDevice(); ALOGD("start_output_stream device=%x", device); ALOGD("start_output_stream out->device=%x", out->device); if (device == SPDIF_PASSTHROUGH_MODE) { out->device &= ~AUDIO_DEVICE_OUT_AUX_DIGITAL; out->device |= AUDIO_DEVICE_OUT_SPDIF; } else if (device == HDMI_BITSTREAM_MODE) { out->device &= ~AUDIO_DEVICE_OUT_SPDIF; out->device |= AUDIO_DEVICE_OUT_AUX_DIGITAL; } #ifdef BOX_HAL if (out->device & AUDIO_DEVICE_OUT_AUX_DIGITAL) { /*BOX hdmi & codec use the same i2s,so only config the codec card*/ out->device &= ~AUDIO_DEVICE_OUT_SPEAKER; } read_snd_card_info(); if (out->config.flag == HW_PARAMS_FLAG_LPCM){ if(hasSpdif() && ((out->device & AUDIO_DEVICE_OUT_SPDIF)==0)){ out->device |= AUDIO_DEVICE_OUT_SPDIF; } } #ifdef RK3228 if (out->config.flag == HW_PARAMS_FLAG_LPCM) { if (out->device & AUDIO_DEVICE_OUT_AUX_DIGITAL) { out->device |= AUDIO_DEVICE_OUT_SPEAKER; } } #endif out_dump(out, 0); #endif connect_hdmi = true; route_pcm_open(getRouteFromDevice(out->device)); if (out->device & AUDIO_DEVICE_OUT_AUX_DIGITAL) { if (connect_hdmi) { #ifdef BOX_HAL #ifdef USE_DRM int ret = 0; ret = mixer_mode_set(out); if (ret!=0) { ALOGE("mixer mode set error,ret=%d!",ret); } #endif #endif out->pcm_device = 1; out->pcm[PCM_CARD_HDMI] = pcm_open(PCM_CARD_HDMI, out->pcm_device, PCM_OUT | PCM_MONOTONIC, &out->config); if (out->pcm[PCM_CARD_HDMI] && !pcm_is_ready(out->pcm[PCM_CARD_HDMI])) { ALOGE("pcm_open(PCM_CARD_HDMI) failed:111 %s", pcm_get_error(out->pcm[PCM_CARD_HDMI])); pcm_close(out->pcm[PCM_CARD_HDMI]); return -ENOMEM; } } else { ALOGD("The current HDMI is DVI mode"); out->device |= AUDIO_DEVICE_OUT_SPEAKER; } } if (out->device & (AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_OUT_WIRED_HEADSET | AUDIO_DEVICE_OUT_WIRED_HEADPHONE | AUDIO_DEVICE_OUT_ALL_SCO)) { /* open & close hdmi card to mute hdmi audio */ out->pcm_device = 1; out->pcm[PCM_CARD_HDMI] = pcm_open(PCM_CARD_HDMI, out->pcm_device, PCM_OUT | PCM_MONOTONIC, &out->config); if (out->pcm[PCM_CARD_HDMI] && !pcm_is_ready(out->pcm[PCM_CARD_HDMI])) { ALOGE("pcm_open(PCM_CARD_HDMI) failed: 222 %s", pcm_get_error(out->pcm[PCM_CARD_HDMI])); pcm_close(out->pcm[PCM_CARD_HDMI]); return -ENOMEM; } if (out->pcm[PCM_CARD_HDMI]) pcm_close(out->pcm[PCM_CARD_HDMI]); out->pcm_device = 0; out->pcm[PCM_CARD] = pcm_open(PCM_CARD, out->pcm_device, PCM_OUT | PCM_MONOTONIC, &out->config); if (out->pcm[PCM_CARD] && !pcm_is_ready(out->pcm[PCM_CARD])) { ALOGE("pcm_open(PCM_CARD) failed: %s", pcm_get_error(out->pcm[PCM_CARD])); pcm_close(out->pcm[PCM_CARD]); return -ENOMEM; } } if (out->device & AUDIO_DEVICE_OUT_SPDIF) { out->pcm_device = 0; out->pcm[PCM_CARD_SPDIF] = pcm_open(PCM_CARD_SPDIF, out->pcm_device, PCM_OUT | PCM_MONOTONIC, &out->config); if (out->pcm[PCM_CARD_SPDIF] && !pcm_is_ready(out->pcm[PCM_CARD_SPDIF])) { ALOGE("pcm_open(PCM_CARD_SPDIF) failed: %s", pcm_get_error(out->pcm[PCM_CARD_SPDIF])); pcm_close(out->pcm[PCM_CARD_SPDIF]); return -ENOMEM; } } adev->out_device |= out->device; if (out->device & AUDIO_DEVICE_OUT_ALL_SCO) { start_bt_sco(adev); #ifdef BT_AP_SCO // HARD CODE FIXME out->pcm[PCM_BT] = pcm_open(PCM_BT, 0, PCM_OUT | PCM_MONOTONIC, &pcm_config_ap_sco); ret = create_resampler(48000, 8000, 2, RESAMPLER_QUALITY_DEFAULT, NULL, &out->resampler); if (ret != 0) { ret = -EINVAL; } #endif } if(adev->hdmiin_state){ ALOGD("%s HDMIin state open hdmiin route",__FUNCTION__); route_pcm_open(HDMI_IN_NORMAL_ROUTE); } return 0; } |-- external/tinyalsa/pcm.c(PCM结构体) struct pcm { int fd; unsigned int flags; int running:1; int prepared:1; int underruns; unsigned int buffer_size; unsigned int boundary; char error[PCM_ERROR_MAX]; struct pcm_config config; struct snd_pcm_mmap_status *mmap_status; struct snd_pcm_mmap_control *mmap_control; struct snd_pcm_sync_ptr *sync_ptr; void *mmap_buffer; unsigned int noirq_frames_per_msec; int wait_for_avail_min; }; struct pcm *pcm_open(unsigned int card, unsigned int device, unsigned int flags, struct pcm_config *config) { struct pcm *pcm; struct snd_pcm_info info; struct snd_pcm_hw_params params; struct snd_pcm_sw_params sparams; char fn[256]; int rc; pcm = calloc(1, sizeof(struct pcm)); if (!pcm || !config) return &bad_pcm; /* TODO: could support default config here */ pcm->config = *config; snprintf(fn, sizeof(fn), "/dev/snd/pcmC%uD%u%c", card, device, flags & PCM_IN ? 'c' : 'p'); pcm->flags = flags; pcm->fd = open(fn, O_RDWR|O_NONBLOCK); if (pcm->fd < 0) { oops(pcm, errno, "cannot open device '%s'", fn); return pcm; } if (fcntl(pcm->fd, F_SETFL, fcntl(pcm->fd, F_GETFL) & ~O_NONBLOCK) < 0) { oops(pcm, errno, "failed to reset blocking mode '%s'", fn); goto fail_close; } if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_INFO, &info)) { oops(pcm, errno, "cannot get info"); goto fail_close; } param_init(¶ms); param_set_mask(¶ms, SNDRV_PCM_HW_PARAM_FORMAT, pcm_format_to_alsa(config->format)); param_set_mask(¶ms, SNDRV_PCM_HW_PARAM_SUBFORMAT, SNDRV_PCM_SUBFORMAT_STD); param_set_min(¶ms, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, config->period_size); param_set_int(¶ms, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, pcm_format_to_bits(config->format)); param_set_int(¶ms, SNDRV_PCM_HW_PARAM_FRAME_BITS, pcm_format_to_bits(config->format) * config->channels); param_set_int(¶ms, SNDRV_PCM_HW_PARAM_CHANNELS, config->channels); param_set_int(¶ms, SNDRV_PCM_HW_PARAM_PERIODS, config->period_count); param_set_int(¶ms, SNDRV_PCM_HW_PARAM_RATE, config->rate); param_set_flag(¶ms, config->flag); if (flags & PCM_NOIRQ) { if (!(flags & PCM_MMAP)) { oops(pcm, -EINVAL, "noirq only currently supported with mmap()."); goto fail_close; } params.flags |= SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP; pcm->noirq_frames_per_msec = config->rate / 1000; } if (flags & PCM_MMAP) param_set_mask(¶ms, SNDRV_PCM_HW_PARAM_ACCESS, SNDRV_PCM_ACCESS_MMAP_INTERLEAVED); else param_set_mask(¶ms, SNDRV_PCM_HW_PARAM_ACCESS, SNDRV_PCM_ACCESS_RW_INTERLEAVED); if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_HW_PARAMS, ¶ms)) { oops(pcm, errno, "cannot set hw params"); goto fail_close; } /* get our refined hw_params */ config->period_size = param_get_int(¶ms, SNDRV_PCM_HW_PARAM_PERIOD_SIZE); config->period_count = param_get_int(¶ms, SNDRV_PCM_HW_PARAM_PERIODS); pcm->buffer_size = config->period_count * config->period_size; if (flags & PCM_MMAP) { pcm->mmap_buffer = mmap(NULL, pcm_frames_to_bytes(pcm, pcm->buffer_size), PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, pcm->fd, 0); if (pcm->mmap_buffer == MAP_FAILED) { oops(pcm, -errno, "failed to mmap buffer %d bytesn", pcm_frames_to_bytes(pcm, pcm->buffer_size)); goto fail_close; } } memset(&sparams, 0, sizeof(sparams)); sparams.tstamp_mode = SNDRV_PCM_TSTAMP_ENABLE; sparams.period_step = 1; if (!config->start_threshold) { if (pcm->flags & PCM_IN) pcm->config.start_threshold = sparams.start_threshold = 1; else pcm->config.start_threshold = sparams.start_threshold = config->period_count * config->period_size / 2; } else sparams.start_threshold = config->start_threshold; /* pick a high stop threshold - todo: does this need further tuning */ if (!config->stop_threshold) { if (pcm->flags & PCM_IN) pcm->config.stop_threshold = sparams.stop_threshold = config->period_count * config->period_size * 10; else pcm->config.stop_threshold = sparams.stop_threshold = config->period_count * config->period_size; } else sparams.stop_threshold = config->stop_threshold; if (!pcm->config.avail_min) { if (pcm->flags & PCM_MMAP) pcm->config.avail_min = sparams.avail_min = pcm->config.period_size; else pcm->config.avail_min = sparams.avail_min = 1; } else sparams.avail_min = config->avail_min; sparams.xfer_align = config->period_size / 2; /* needed for old kernels */ sparams.silence_threshold = config->silence_threshold; sparams.silence_size = config->silence_size; pcm->boundary = sparams.boundary = pcm->buffer_size; while (pcm->boundary * 2 <= INT_MAX - pcm->buffer_size) pcm->boundary *= 2; if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_SW_PARAMS, &sparams)) { oops(pcm, errno, "cannot set sw params"); goto fail; } rc = pcm_hw_mmap_status(pcm); if (rc < 0) { oops(pcm, rc, "mmap status failed"); goto fail; } #ifdef SNDRV_PCM_IOCTL_TTSTAMP if (pcm->flags & PCM_MONOTONIC) { int arg = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC; rc = ioctl(pcm->fd, SNDRV_PCM_IOCTL_TTSTAMP, &arg); if (rc < 0) { oops(pcm, rc, "cannot set timestamp type"); goto fail; } } #endif pcm->underruns = 0; return pcm; fail: if (flags & PCM_MMAP) munmap(pcm->mmap_buffer, pcm_frames_to_bytes(pcm, pcm->buffer_size)); fail_close: close(pcm->fd); pcm->fd = -1; return pcm; } int pcm_is_ready(struct pcm *pcm) { return pcm->fd >= 0; } |
|
|
|
你正在撰写答案
如果你是对答案或其他答案精选点评或询问,请使用“评论”功能。
基于米尔瑞芯微RK3576核心板/开发板的人脸疲劳检测应用方案
498 浏览 0 评论
768 浏览 1 评论
667 浏览 1 评论
1893 浏览 1 评论
3138 浏览 1 评论
小黑屋| 手机版| Archiver| 德赢Vwin官网 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-22 00:52 , Processed in 0.422641 second(s), Total 40, Slave 34 queries .
Powered by 德赢Vwin官网 网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
德赢Vwin官网 观察
版权所有 © 湖南华秋数字科技有限公司
德赢Vwin官网 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号