bluez-alsa流程说明

//整个的写流程如下,请在对应的调整点/数据记录监控点进行记录调试,确认问题。
//eq_drc层:(调整点1,是否可以增大buffsize)
#define READ_FRAME_DEFAULT      1920
#define PERIOD_SIZE_DEFAULT     (READ_FRAME_DEFAULT)
#define PERIOD_COUNTS_DEFAULT   (8*2)
#define BUFFER_SIZE_DEFAULT     (PERIOD_SIZE_DEFAULT * PERIOD_COUNTS_DEFAULT) /* Keeping a large buffer_size ASAP */
#define MUTE_TIME_DEFAULT       (3) /* seconds */

//从虚拟声卡读 (数据记录监控点1:主要是确认aplay送下来的数据是否完整)
err = snd_pcm_readi(capture_handle, buffer, g_read_frame);

//寻找播放设备
alsa_fake_device_write_open()
	if (device_flag == DEVICE_FLAG_BLUETOOTH) {
		sprintf(bluealsa_device, "%s%s", "bluealsa:HCI=hci0,PROFILE=a2dp,DEV=",
	        g_bt_mac_addr);
		eq_debug("[EQ_WRITE_OPEN] Open PCM: %s\n", bluealsa_device);
		//打开bluez的蓝牙设备
		write_err = snd_pcm_open(write_handle, bluealsa_device,
	                         SND_PCM_STREAM_PLAYBACK, 0);
	}
	//设置各类参数, 对应上面的define的各种参数
	snd_pcm_hw_params_set_access()
	snd_pcm_hw_params_set_format()
	snd_pcm_hw_params_set_channels()
	snd_pcm_hw_params_set_buffer_size_near()
	snd_pcm_hw_params_set_period_size_near()
	//对应的输出如下:
	//eq_drc_process: [EQ_WRITE_OPEN] interleaved mode 
	//eq_drc_process: [EQ_WRITE_OPEN] snd_pcm_hw_params_alloca 
	//eq_drc_process: [EQ_WRITE_OPEN] interleaved mode 
	//eq_drc_process: [EQ_WRITE_OPEN] format successed 
	//eq_drc_process: [EQ_WRITE_OPEN] channels = 2 
	//eq_drc_process: [EQ_WRITE_OPEN] setting sampling rate (48000)
	//eq_drc_process: [EQ_WRITE_OPEN] write_bufferSize = 15360 
	//eq_drc_process: [EQ_WRITE_OPEN] write_periodSize = 1920 

//写音频数据到write_handle(数据记录监控点2,对比是否跟监控1一致,及写是否会出错)
err = snd_pcm_writei(write_handle, buffer, g_read_frame);

//bluez-alsa层:
//bluez-alsa\src\asound\bluealsa-pcm.c //这是一个模拟蓝牙音频插件
//eq-drc的相关蓝牙操作都会调用到这里:
static const snd_pcm_ioplug_callback_t bluealsa_callback = {
	.start = bluealsa_start,
	.stop = bluealsa_stop,
	.pointer = bluealsa_pointer,
	.close = bluealsa_close,
	.hw_params = bluealsa_hw_params,
	.hw_free = bluealsa_hw_free,
	.sw_params = bluealsa_sw_params,
	.prepare = bluealsa_prepare,
	.drain = bluealsa_drain,
	.pause = bluealsa_pause,
	.dump = bluealsa_dump,
	.delay = bluealsa_delay,
	.poll_descriptors_count = bluealsa_poll_descriptors_count,
	.poll_descriptors = bluealsa_poll_descriptors,
	.poll_revents = bluealsa_poll_revents,
};
//eqdrc设置的各类参数都会调到这里:
bluealsa_hw_params()
	 //从框架获取一个pcm_fd,先记住整个pcm_fd
	 pcm->pcm_fd = bluealsa_open_transport(pcm->fd, &pcm->transport)
	 
	if (pcm->io.stream == SND_PCM_STREAM_PLAYBACK) {
		/* By default, the size of the pipe buffer is set to a too large value for
		 * our purpose. On modern Linux system it is 65536 bytes. Large buffer in
		 * the playback mode might contribute to an unnecessary audio delay. Since
		 * it is possible to modify the size of this buffer we will set is to some
		 * low value, but big enough to prevent audio tearing. Note, that the size
		 * will be rounded up to the page size (typically 4096 bytes). */
		//配置pcm_fd的buffer大小,(调整点2, 参考上面的描述)
		pcm->pcm_buffer_size = fcntl(pcm->pcm_fd, F_SETPIPE_SZ, 2048);
		debug("FIFO buffer 2048 size: %zd", pcm->pcm_buffer_size);
	}
	//根据eqdrc设置,最终得到的实际的参数
	debug("Selected HW buffer: %zd periods x %zd bytes %c= %zd bytes",
			io->buffer_size / io->period_size, pcm->frame_size * io->period_size,
			io->period_size * (io->buffer_size / io->period_size) == io->buffer_size ? '=' : '<',
			io->buffer_size * pcm->frame_size);

//启动接收数据线程,eqdrc的数据都会被写到这里
static int bluealsa_start(snd_pcm_ioplug_t *io) 
	pthread_create(&pcm->io_thread, NULL, io_thread, io)
	io_thread()
		debug("Starting IO loop xy");
		for (;;) {
		    //eqdrc的snd_pcm_writei写数据都会体现在pcm->io_ptr这里
			snd_pcm_uframes_t io_ptr = pcm->io_ptr;
			snd_pcm_uframes_t io_buffer_size = io->buffer_size;
			snd_pcm_uframes_t io_hw_ptr = pcm->io_hw_ptr;
			snd_pcm_uframes_t io_hw_boundary = pcm->io_hw_boundary;
			snd_pcm_uframes_t frames = io->period_size;
			... ...
			/* Perform atomic write - see the explanation above. */
			do {
			    //把上面从eqdrc获取的数据 都写入到bluealsa_hw_params获取的pcm_fd
			    //(数据记录监控点3,对比是否跟监控2一致)
				if ((ret = write(pcm->pcm_fd, head, len)) == -1) {
					debug("pcm write ret: %d, len: %d", ret, len);
					if (errno == EINTR)
						continue;
					SNDERR("PCM FIFO write error: %s", strerror(errno));
					goto final;
				}
				debug("pcm write ret: %d, len: %d", ret, len);
				head += ret;
				len -= ret;
			} while (len != 0);
		}

//bluealsa在eqdrc打开蓝牙虚拟设备时会创建一个线程,整个线程专门把接收到的音频数据送给bluez
//bluez-alsa\src\io.c
void *io_thread_a2dp_source_sbc(void *arg) {
	for (;;) {
		//这里会从上面的bluealsa_start(io_thread)的pcm_fd读eqdrc的数据
		//(数据记录监控点4,对比是否跟监控3一致)
		io_thread_read_pcm(&t->a2dp.pcm, pcm.tail, ffb_len_in(&pcm))
		//SBC编码
		sbc_encode()
		//最后送给bluez
		io_thread_write_bt()
	}
}

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值