⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pcm_a2dpd.c

📁 linux蓝牙剖面实现
💻 C
📖 第 1 页 / 共 2 页
字号:
	DBG("");	a2dp_disconnect(a2dp);	a2dp_free(a2dp);	DBG("OK");	return 0;}static int a2dp_params(snd_pcm_ioplug_t * io, snd_pcm_hw_params_t * params){	snd_pcm_a2dp_t *a2dp = io->private_data;	unsigned int period_bytes;	a2dp->frame_bytes = (snd_pcm_format_physical_width(io->format) * io->channels) / 8;	period_bytes = io->period_size * a2dp->frame_bytes;	DBG("format %s rate %d channels %d", snd_pcm_format_name(io->format), io->rate, io->channels);	return 0;}static int a2dp_prepare(snd_pcm_ioplug_t * io){	snd_pcm_a2dp_t *a2dp = io->private_data;	float block = ((float)A2DPD_BLOCK_SIZE);	a2dp->num = 0;	a2dp->rate = io->rate;	a2dp->channels = io->channels;	if(a2dp->opened_for == A2DPD_PLUGIN_PCM_READ) {		block = 48;		// ALSA library is really picky on the fact num is not null. If it is, capture won't start 		a2dp->num = io->period_size;	}	a2dp->TimerInfos.fps = (float) ((((float)a2dp->rate) * ((float) a2dp->frame_bytes) / block) / 1.0);	DBG("block %f, %f fps", block, a2dp->TimerInfos.fps);		return 0;}// static int a2dp_drain(snd_pcm_ioplug_t * io)// {// 	snd_pcm_a2dp_t *a2dp = io->private_data;// 	DBG("a2dp %p", a2dp);// 	return 0;// }// static int a2dp_descriptors_count(snd_pcm_ioplug_t * io)// {// 	return 1;// }// static int a2dp_descriptors(snd_pcm_ioplug_t * io, struct pollfd *pfds, unsigned int space)// {// 	if (space < 1) {//		DBG("Can't fill in descriptors");// 		SNDERR("Can't fill in descriptors");// 		return 0;// 	}// 	// Alsa does make sure writing now will not block// 	// So give him an always writable socket!// 	pfds[0].fd = fileno(stdout);// 	pfds[0].events = POLLOUT;// 	return 1;// }// static int a2dp_poll(snd_pcm_ioplug_t * io, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)// {// 	snd_pcm_a2dp_t *a2dp = io->private_data;// 	*revents = pfds[0].revents;// // 	if (a2dp->sk <= 0)// 		return 0;// // 	if (pfds[0].revents & POLLHUP) {// 		a2dp_disconnect(a2dp);// 		snd_pcm_ioplug_reinit_status(&a2dp->io);// 	}// // 	return 0;// }static snd_pcm_ioplug_callback_t a2dp_write_callback = {	.close = a2dp_close,	.start = a2dp_start,	.stop = a2dp_stop,	.prepare = a2dp_prepare,	.pointer = a2dp_pointer,	.transfer = a2dp_transfer,	.hw_params = a2dp_params,//	.drain = a2dp_drain,//	.poll_descriptors_count = a2dp_descriptors_count,//	.poll_descriptors = a2dp_descriptors,//	.poll_revents = a2dp_poll,};static snd_pcm_ioplug_callback_t a2dp_read_callback = {	.close = a2dp_close,	.start = a2dp_start,	.stop = a2dp_stop,	.prepare = a2dp_prepare,	.pointer = a2dp_pointer,	.transfer = a2dp_read,	.hw_params = a2dp_params,};// Alsa can convert about any format/channels/rate to any other rate// However, since we added some code in the daemon to convert, why not do it ourselves!!!// Moreover some player like aplay won't play a wav file if the device that do not natively support the requested format// If you want alsa to do the conversion, just remove the value you want to see convertedstatic int a2dp_constraint(snd_pcm_a2dp_t * a2dp){	snd_pcm_ioplug_t *io = &a2dp->io;	snd_pcm_access_t access_list[] = { SND_PCM_ACCESS_RW_INTERLEAVED, SND_PCM_ACCESS_MMAP_INTERLEAVED };	unsigned int formats[] = { SND_PCM_FORMAT_U8, SND_PCM_FORMAT_S8, SND_PCM_FORMAT_S16_LE };	unsigned int channels[] = { 1, 2 };	unsigned int rates[] = { 8000, 11025, 22050, 32000, 44100, 48000 };	int formats_nb = ARRAY_SIZE(formats);	int channels_nb = ARRAY_SIZE(channels);	int rates_nb = ARRAY_SIZE(rates);	int rate_daemon = 0;	int rate_prefered = 0;	int period_bytes = 8192;	char srcfilename[512];	int err;	if(a2dp->opened_for == A2DPD_PLUGIN_PCM_WRITE) {		get_config_filename(srcfilename, sizeof(srcfilename));		// Default is same as the daemon		rate_daemon = read_config_int(srcfilename, "a2dpd", "rate", A2DPD_FRAME_RATE);		// If a value is specified, use it		rate_prefered = read_config_int(srcfilename, "a2dpd", "plugin-rate", rate_daemon);		// If a constraint is defined for the plugin use it		if(a2dp->rateconstraint != 0) {			rate_prefered = a2dp->rateconstraint;		}		// If this value is not 0, alsa will convert to plugin-rate		if(rate_prefered != 0) {			// use defaults settings the rate specified + 16 bits stereo			rates[0] = rate_prefered;			rates_nb = 1;			formats[0] = SND_PCM_FORMAT_S16_LE;			formats_nb = 1;			channels[0] = 2;			channels_nb = 1;			period_bytes = 8192;			DBG("%d", rate_prefered);		} else {			// If this value is 0, the daemon will do most conversions		}		DBG("A2DPD_PLUGIN_PCM_WRITE %d", rate_prefered);	} else if(a2dp->opened_for == A2DPD_PLUGIN_PCM_READ) {		// Capture is only available using SCO		// 8000 hz, 16bits, Mono		rates[0] = 8000;		rates_nb = 1;		formats[0] = SND_PCM_FORMAT_S16_LE;		formats_nb = 1;		channels[0] = 1;		channels_nb = 1;		period_bytes = 48;		DBG("A2DPD_PLUGIN_PCM_READ %d", 8000);	}	err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_ACCESS, ARRAY_SIZE(access_list), access_list);	if (err < 0)		return err;	err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_FORMAT, formats_nb, formats);	if (err < 0)		return err;	err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_CHANNELS, channels_nb, channels);	if (err < 0)		return err;	err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_RATE, rates_nb, rates);	if (err < 0)		return err;	err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_PERIOD_BYTES, 8192, 8192);	if (err < 0)		return err;	err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_PERIODS, 2, 2);	if (err < 0)		return err;	return 0;}SND_PCM_PLUGIN_DEFINE_FUNC(a2dpd){	snd_pcm_a2dp_t *a2dp = NULL;	snd_config_iterator_t i, next;	int err = 0;	long rateconstraint = 0;	long streamid = 0;	long debug = 0;	long starta2dpd = 0;	DBG("Open mode is for %s", stream == SND_PCM_STREAM_PLAYBACK ? "Playback" : stream == SND_PCM_STREAM_CAPTURE ? "Capture" : "Undefined (capture and playback)");	snd_config_for_each(i, next, conf) {		snd_config_t *n = snd_config_iterator_entry(i);		const char *id;		if (snd_config_get_id(n, &id) < 0)			continue;		// Alsa specific options		if (!strcmp(id, "comment") || !strcmp(id, "type"))			continue;		// Ignore old options		if (strstr("ipaddr bdaddr port src dst use_rfcomm", id))			continue;		// rate of the plugin (overwrite plugin-rate in .a2dprc)		if (!strcmp(id, "rateconstraint")) {			if (snd_config_get_integer(n, &rateconstraint) < 0) {				SNDERR("Invalid type for %s", id);				return -EINVAL;			}			continue;		}		// Start a2dpd		if (!strcmp(id, "starta2dpd")) {			if (snd_config_get_integer(n, &starta2dpd) < 0) {				SNDERR("Invalid type for %s", id);				return -EINVAL;			}			continue;		}		// streamid (to be used later)		if (!strcmp(id, "streamid")) {			if (snd_config_get_integer(n, &streamid) < 0) {				SNDERR("Invalid type for %s", id);				return -EINVAL;			}			continue;		}		// debug		if (!strcmp(id, "debug")) {			if (snd_config_get_integer(n, &debug) < 0) {				SNDERR("Invalid type for %s", id);				return -EINVAL;			}			continue;		}		SNDERR("Unknown field %s", id);		return -EINVAL;	}	g_bdebug = debug;	a2dp = a2dp_alloc();	if (!a2dp) {		SNDERR("Can't allocate plugin data");		return -ENOMEM;	}	// Notify plugin	a2dp->rateconstraint = rateconstraint;	a2dp->streamid = streamid;	a2dp->io.version = SND_PCM_IOPLUG_VERSION;	a2dp->io.name = "Bluetooth Advanced Audio Distribution";	a2dp->io.mmap_rw = 0;	a2dp->io.poll_fd     =  1; /* Do not use poll !! */	a2dp->io.poll_events =  POLLOUT; /* Do not use poll !! */	a2dp->io.callback = (stream == SND_PCM_STREAM_PLAYBACK)?(&a2dp_write_callback):(&a2dp_read_callback);	a2dp->io.private_data = a2dp;	a2dp->opened_for = (stream == SND_PCM_STREAM_PLAYBACK)?(A2DPD_PLUGIN_PCM_WRITE):(A2DPD_PLUGIN_PCM_READ);	// Startup A2DPD	if(starta2dpd) {		startup_a2dpd_upon_request();	}	err = snd_pcm_ioplug_create(&a2dp->io, name, stream, mode);	if (err < 0)		goto error;	err = a2dp_constraint(a2dp);	if (err < 0) {		snd_pcm_ioplug_delete(&a2dp->io);		goto error;	}	*pcmp = a2dp->io.pcm;	return 0;      error:	a2dp_disconnect(a2dp);	a2dp_free(a2dp);	return err;}SND_PCM_PLUGIN_SYMBOL(a2dpd);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -