背景:实现全志R16-linux开发板上的mplayer的调试
一、mplayer软件架构:
这里详细介绍了alsa的相关知识
二、问题解决1:播放卡顿
0.问题描述:播放过程中会突然发生卡顿,就是感觉声音突然快进了似的。
1.mplayer.c中的调用了fill_audio_out_buffers 这个函数:
这个代码主要是两个while循环:
循环1:while(1)这一部分主要是通过get_space()函数获取需要写的字节数,一直填充,直到其数值大于outburst才停止。这里还根据数据的大小算出sleep的时间,防止占用cpu过多。
循环2:while(bytes_to_write)这个地方根据上面的值进行数据的填充。
2.其中调用了get_space()这个函数
这里面调用了很多alsa驱动的函数。
snd_pcm_status_get_avail 来获取当前驱动缓冲区中可用的帧数。
就是这个函数主要是来从buffer中拿出一个帧的长度,如果buffer不够一针,就拿出那么多,如果超过了一针,那么久取出一针的长度。
1 ret = snd_pcm_status_get_avail(status) * bytes_per_sample; 2 // printf("aaa:buf=%d\n", ao_data.buffersize); // always 88200 3 // printf("aaa:bpS=%d\n", bytes_per_sample); // always 4 4 if (ret > ao_data.buffersize/8){ // Buffer underrun? 5 // printf("aaa:ret\n"); 6 ret = ao_data.buffersize; // never 7 } 8 // printf("aaa:getSpace=%d\n", ret); // 88200 when cracking 9 return ret;
音乐播放buffer层次:
三层buffer:应用程序buffer(mplayer使用的buffer)、alsa驱动buffer(ring uffer)、硬件buffer。
数据在这三层buffer中传输,
playsize = mpctx->audio_out->play(sh_audio->a_out_buffer, playsize, playflags);
这里需要打印一下看看到底每次传的一样吗?
问题分析:
猜测:有hw:0,0 只能write 8的倍数的数据,default数据则是随便的,需要实验验证一下。
暂时结论就是,由于每次都是好像跳过了一针,推测是因为写的时候把之前的buffer覆盖了,导致丢帧了。因为没有用HW:0,0导致写的时候不是8的倍数,
解决:扩大buffer,让后面的不能追上前面的。
https://blog.csdn.net/kickxxx/article/details/8291598
三、问题解决2:播放器有哒哒哒的声音:
下面是开发板开机的一个启动脚本,经过定位发现是加载一个gpio_key的时候会发生哒哒哒的声音。
因为加载的事案件驱动,尝试按了一下案件,发现只要按一下案件,就不会有噪声了。
首先看问题驱动的源码
(需要继续看一下源码更新一下)
二、问题解决3:音乐采样率和DAC采样率不匹配
void dsp_init(int sample_rate) { int fd; int ret; //DSP start long data = 0; fd = open("/dev/gpio_ctl_dsp",O_RDWR); if(fd < 0){ printf("cant't open the dsp device\n"); return -1; } switch(sample_rate) { case 44100:ret = ioctl(fd,SA441K,data);break; case 88200:ret = ioctl(fd,SA882K,data);break; case 176400:ret = ioctl(fd,SA1764K,data);break; case 48000:ret = ioctl(fd,SA48K,data);break; case 96000:ret = ioctl(fd,SA96K,data);break; case 192000:ret = ioctl(fd,SA192K,data);break; default:break; } if(ret == 0) close(fd); //DSP end //DAC start char buf[50]; int regaddr, slaveaddr; slaveaddr = 0x10; regaddr = 0x00; fd = open("/dev/i2c-2",O_RDWR); if(fd < 0){ printf("#########open i2c failed########\n"); return -1; } ioctl(fd,I2C_TENBIT,0); ioctl(fd,I2C_SLAVE,slaveaddr); buf[0] = 0x07; buf[1] = 0x12; buf[2] = 0x00; buf[3] = 0xF9; buf[4] = 0xF9; buf[5] = 0x00; buf[6] = 0x00; buf[7] = 0x03; buf[8] = 0x01; buf[9] = 0x00; buf[10] = 0x0D; buf[11] = 0x0C; buf[12] = 0x00; buf[13] = 0x00; buf[14] = 0x50; buf[15] = 0xFF; buf[16] = 0xFF; ret = iic_write(fd, buf, regaddr, 17); if(ret > 0){ ; } close(fd); //DAC end return 0; }