查找出现“wait_event_timeout failed for session X”的原因
1 Audio相关代码文件
Sound/soc/msm/qdsp6/q6asm.c
Sound/soc/msm/qdsp6/q6adm.c
Sound/soc/msm/qdsp6/q6afe.c
Sound/soc/msm/msm8x60-dai.c
Sound/soc/msm/msm8x60.c
Sound/soc/msm/msm8x60-pcm.c
Sound/soc/msm/snd-soc-lpass-dma.c
Sound/soc/codec/wnc/wnc/wnc_wm8737.c
Arch/arm/mach-msm/qdsp6v2/pcm_out.c
Arch/arm/mach-msm/qdsp6v2/pcm_in.c
Hardware/qcom/media/audio/msm8660/
2在Arch/arm/mach-msm/qdsp6v2/pcm_out.c
中
static ssize_t pcm_out_write(struct file *file, const char __user *buf,
size_t count, loff_t *pos)
{
。。。。。。
rc = wait_event_timeout(pcm->write_wait,
(atomic_read(&pcm->out_count) ||
atomic_read(&pcm->out_stopped)), 1 * HZ );
if (!rc) {
pr_err("%s: wait_event_timeout failed for session %d\n",
__func__, pcm->ac->session);
goto fail;
}
。。。。。。
rc = q6asm_write(pcm->ac, xfer, 0, 0, NO_TIMESTAMP);
。。。。。。
atomic_dec(&pcm->out_count);
。。。。。。
}
pcm->out_count为目前闲着的buffer个数。向底层每写入1buffer数据,out_count加1.
3 pcm_out_cb()为回调函数,当底层写完数据后进入,out_count减1.
void pcm_out_cb(uint32_t opcode, uint32_t token,
uint32_t *payload, void *priv)
{
struct pcm *pcm = (struct pcm *) priv;
unsigned long flags;
spin_lock_irqsave(&pcm->dsp_lock, flags);
switch (opcode) {
case ASM_DATA_EVENT_WRITE_DONE:
atomic_inc(&pcm->out_count);
wake_up(&pcm->write_wait);
break;
default:
break;
}
spin_unlock_irqrestore(&pcm->dsp_lock, flags);
}
4 当atomic_read(&pcm->out_count)等于0时,证明没有闲着的buffer,等1秒钟,仍然没有可以用的buffer,则打印“wait_event_timeout failed for session X”,向上返回0.
若底层有问题,数据传不下去,则会不停的报“wait_event_timeout failed for session X”,若只报一次,证明下次就正常了,所以问题不大。
5 HAL层向下写入的过程:
ssize_t AudioHardware::AudioStreamOutMSM72xx::write(const void* buffer, size_t bytes)
{
if (mStandby) {
// open driver
status = ::open("/dev/msm_pcm_out", O_WRONLY/*O_RDWR*/);
// configuration
status = ioctl(mFd, AUDIO_GET_CONFIG, &config);
config.channel_count = AudioSystem::popCount(channels());
config.sample_rate = sampleRate();
config.buffer_size = bufferSize();
config.buffer_count = AUDIO_HW_NUM_OUT_BUF;
config.codec_type = CODEC_TYPE_PCM;
status = ioctl(mFd, AUDIO_SET_CONFIG, &config);
// fill 2 buffers before AUDIO_START
mStartCount = AUDIO_HW_NUM_OUT_BUF;
mStandby = false;
}
while (count) {
ssize_t written = ::write(mFd, p, count);
if (written > 0) {
count -= written;
p += written;
} else {
if (errno != EAGAIN) return written;
mRetryCount++;
LOGW("EAGAIN - retry");
}
}
// start audio after we fill 2 buffers
if (mStartCount) {
if (--mStartCount == 0) {
if(ioctl(mFd, AUDIO_GET_SESSION_ID, &dec_id)) {
LOGE("AUDIO_GET_SESSION_ID failed*********");
return 0;
}
ioctl(mFd, AUDIO_START, 0);
}
}
return bytes;
}
通过ioctl(mFd, AUDIO_SET_CONFIG, &config);将配置传下去。(Buffersize=4800,buffercount=2)。
先写入两个buffer,再ioctl(mFd, AUDIO_START, 0);然后再继续写。底层接到AUDIO_START命令后,会设置音量等。猜想这样做可能是为了消除pop音。
6 音频设备
输入(1)遥控器 usb声卡 pcm1804_mic_tx
(2)卡拉OK CODEC
输出 HDMI hdmi_stereo_rx