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

📄 a2dpd.c

📁 linux蓝牙剖面实现
💻 C
📖 第 1 页 / 共 4 页
字号:
			}			// Wait must take place after sending a packet			// This way, you will allow the plugin to send it's data			// And you will collect the new data			// Time reference floating because of 44100/1000 error in integer calculation			if((delay = a2dp_timer_sleep(&TimerInfos, A2DPTIMERPREDELAY))>0) {				usleep(delay);			}			// Display daemon state if enabled			if(TimerInfos.display>0) {				if(g_brereadconfig) {					char addr[20];					char plug[20];					int bredirect = read_config_int(g_srcfilename, "a2dpd", "enableredirectalsa", REDIRECT_A2DP);										read_config_string(g_srcfilename, "a2dpd", "address", addr, sizeof(addr), "");					read_config_string(g_srcfilename, "a2dpd", "alsaoutput", plug, sizeof(plug), "");					if((strcmp(addr, lpDevice->addr) != 0) || (strcmp(plug, lpDevice->plug) != 0) || (bredirect != lpDevice->bredirect)) {						DBG("File change detected");						// Force destroy, device will be recreated upon audio incoming						strcpy(lpDevice->addr, addr);						strcpy(lpDevice->plug, plug);						lpDevice->bredirect = bredirect;						a2dp_set_dst_addr(a2dp, addr);						destroy_count=lpDevice->a2dp_timeout+1;					}				}				if(a2dp_get_user_flags(a2dp) & A2DPD_FLAGS_DISPLAYSTATE) {					struct timeval now;					gettimeofday(&now, NULL);					timersub(&now, &hdr.packet_date, &now);						DBG("[%d,%d|%d,%d] %s %s clients=%d freq=%d latency=%d", lpDevice->mixer.volume_speaker_left,					lpDevice->mixer.volume_speaker_right,					lpDevice->mixer.volume_micro_left,					lpDevice->mixer.volume_micro_right,					(state_current==DEVICE_STATE_SOUND)?"playing":"silent",					a2dp_is_connected(a2dp)?"connected":"disconnected", lpDevice->nb_clients, TimerInfos.display, (int)now.tv_usec);				}			}			// Force destroy			if(bError || (g_autoconnect && destroy_count>lpDevice->a2dp_timeout)){				if(a2dp_is_connecting(a2dp)) {					destroy_count = -1;					a2dp_state_disconnect(a2dp);				}				if(sco_is_connecting(sco)) {					destroy_count = -1;					sco_state_disconnect(sco);				}			}			// Remember state			state_previous = state_current;			if(a2dp_is_connected(a2dp) || sco_is_connected(sco)) {				a2dpd_dbus_state = CONNECTED;				a2dpd_signal_state(CONNECTED, lpDevice->addr);			} else if(a2dp_is_connecting(a2dp) || sco_is_connecting(sco)) {				a2dpd_dbus_state = CONNECTING;				a2dpd_signal_state(CONNECTING, lpDevice->addr);			} else {				a2dpd_dbus_state = DISCONNECTED;				a2dpd_signal_state(DISCONNECTED, "");			}		}		safefree(pcm_buffer);		// Sleep a little bit before retrying		if (!bSigINTReceived) {			DBG("Sleeping");			sleep(1);		}		// Free A2DP		alsa_destroy(&alsa);		a2dp_destroy(&a2dp);		close_socket(&avdtpfd);	}	DBG("Thread finished");	return 0;}// This function handle the bluetooth connectionvoid * avrcp_listener(void *param){	// As long as daemon is running	while (!bSigINTReceived) {		int sockfd = a2dp_make_listen_socket(23);		if (sockfd >= 0) {			DBG("avrcp: Accepting incoming connection");			while (!bSigINTReceived) {				// Wait for incoming connections				char szRemote[64];				uint16_t iMTU = 0;				if(poll_accept(sockfd, 1000)) {					int new_fd = a2dp_wait_connection(sockfd, szRemote,									sizeof(szRemote),									&iMTU);					if (new_fd > 0) {						DBG("socket %d: Connection from %s, mtu=%d", new_fd, szRemote, iMTU);						// Loop and manage what the client sends						int iReceived = 0;						do {							iReceived = 0;							errno = 0;							if(poll_accept(new_fd, 1000)) {								iReceived = a2dp_handle_avrcp_message(new_fd);							}						}						while (!bSigINTReceived && (iReceived > 0 || errno == EAGAIN));						DBG("socket %d: timed out", new_fd);						close_socket(&new_fd);					} else if (errno != EAGAIN) {						DBG("a2dp_wait_connection failed");						break;					}				} else {					if(errno==EINTR) {						DBG("Signal received in poll");					}				}			}			close_socket(&sockfd);		}		// Sleep a little bit if we must retry		sleep(bSigINTReceived ? 0 : 1);	}	DBG("Thread finished");	return 0;}// server processing loopvoid main_loop(char *addr){	DBG("");	while (!bSigINTReceived) {		// Master socket		int sockfd = make_server_socket();		if (sockfd > 0) {			LPBTA2DPPERDEVICEDATA lpDevice = bta2dpdevicenew(addr);			// Set pthread stack size to decrease unused memory usage			pthread_attr_t tattr;			pthread_t havrcp;			size_t size = PTHREAD_STACK_MIN;			int ret = pthread_attr_init(&tattr);			ret = pthread_attr_setstacksize(&tattr, size);			pthread_create(&lpDevice->thread, &tattr, a2dp_handler, lpDevice);			pthread_create(&havrcp, &tattr, avrcp_listener, lpDevice);			while (!bSigINTReceived) {				int new_fd = -1;				if(g_stdin) {					// Are there some data on stdin					if(poll_accept(fileno(stdin), 0)) {						DBG("Data on stdin");						char c [512];						fgets(c, sizeof(c), stdin);						if(c[0]) {							// write valid commands to ctl_socket							write(lpDevice->ctl_socket[WRITE_SIDE], &c, sizeof(c));							DBG("Sent %c %d", c[0], c[0]);						}					}				}				if(poll_accept(sockfd, 0)) {					new_fd = accept_socket(sockfd);					// Handle connection if it is not the final dummy client					if (!bSigINTReceived && new_fd > 0) {						// Add client to device table						pthread_mutex_lock(&lpDevice->mutex);						DBG("New client %d", new_fd);						int client_index = get_index_for_client(lpDevice);						DBG("Got index %d", client_index);							if(client_index<MAXCLIENTSPERDEVICE) {							lpDevice->clients[client_index].socket = new_fd;						} else {							DBG("Too many clients");							close_socket(&new_fd);						}						pthread_mutex_unlock(&lpDevice->mutex);					} else {						close_socket(&new_fd);					}				}				// Let this thread handle everything stream socket related				poll_incoming_clients_sockets(lpDevice, 10000);			}			close_server_socket(&sockfd);			// ask avdtp and avrcp thread to stop			DBG("Killing");			pthread_kill(havrcp, SIGUSR1);			pthread_kill(lpDevice->thread, SIGUSR1);			DBG("joining");			pthread_join(lpDevice->thread, NULL);			pthread_join(havrcp, NULL);			DBG("continuing");			// Free informations on the device			bta2dpdevicefree(lpDevice);			pthread_attr_destroy(&tattr);		} else {			DBG("Cannot get the socket");		}		sleep(bSigINTReceived?0:1);	}}static struct option main_lopts[] = {	{ "nofork",		0, 0, 'n' },	{ "daemon",		0, 0, 'd' },	{ "verbose",		0, 0, 'v' },	{ "silent",		0, 0, 's' },	{ "kill",		0, 0, 'k' },	{ "realtime",		0, 0, 'r' },	{ "file",		1, 0, 'f' },	{ "address",		1, 0, 'a' },	{ "logfile",		1, 0, 'l' },	{ "configread",		0, 0, 'c' },	{ "autoconnect",	0, 0, 'o' },	{ "debug",		0, 0, 'g' },	{ "sessionbus",		0, 0, 'b' },	{ "help",		0, 0, 'h' },	{ 0, 0, 0, 0 }};static char main_sopts[] = "ndvskrf:a:l:cogbh";char* opts_comment[] = {	"Do not fork",	"Fork and run as daemon",	"Use stdout instead of /dev/null",	"Do not redirect output",	"Kill currently running daemon",	"Set realtime priority, use with care",	"Read config from file <param>",	"Connect to bluetooth address <param>",	"Redirect output in file <param>",	"Read config file periodically",	"Automatically connect to headset",	"Display debug traces",	"Use session bus",	// keep last	"Display usage",	NULL};void usage(int argc, char** argv){	int i = 0;	printf("%s", argv[0]);	while(opts_comment[i]) {		printf("\t--%-15s -%c\t%s\t%s\r\n", main_lopts[i].name, main_lopts[i].val, main_lopts[i].has_arg?"<param>":"", opts_comment[i]); 		i++;	}}// main functionint main(int argc, char *argv[]){	int opt = 0;	struct timespec timer_resolution = { 0, 0 };	char address[256] = "";	char *addr = &address[0];	struct sched_param schedparam = { sched_get_priority_max(SCHED_FIFO) };	int res = 0, bFork = 0, bVerbose = 1, bKill = 0, bRealtime = 0, bSessionBus = -1;	get_config_filename(g_srcfilename, sizeof(g_srcfilename));	// parse arguments on cmdline	while ((opt=getopt_long(argc, argv, main_sopts, main_lopts, NULL)) != -1) {		switch(opt) {		case 'n':			bFork = 0;			break;		case 'd':			bFork = 1;			break;		case 'v':			bVerbose = 1;			break;		case 's':			bVerbose = 0;			break;		case 'k':			bKill = 1;			break;		case 'r':			bRealtime = 1;			break;		case 'f':			strncpy(g_srcfilename, optarg, sizeof(g_srcfilename)-1);			g_srcfilename[sizeof(g_srcfilename)-1] = 0;			DBG("Config file %s", g_srcfilename);			break;		case 'a':			strncpy(address, optarg, sizeof(address)-1);			address[sizeof(address)-1] = 0;			break;		case 'l':			strncpy(g_sOutputFilename, optarg, sizeof(g_sOutputFilename)-1);			g_sOutputFilename[sizeof(g_sOutputFilename)-1] = 0;			break;		case 'c':			g_brereadconfig = 1;			break;		case 'o':			g_autoconnect = 1;			break;		case 'g':			g_bdebug = 1;			break;		case 'b':			bSessionBus = 1;			break;		case 'h':		default:			usage(argc, argv);			exit(0);			break;		}	}	// Read config values from config file	if(address[0]=='\0') read_config_string(g_srcfilename, "a2dpd", "address", address, sizeof(address), "");	if(g_sCmdPlay[0]=='\0') read_config_string(g_srcfilename, "a2dpd", "cmdplay", g_sCmdPlay, sizeof(g_sCmdPlay), "");	if(g_sCmdPause[0]=='\0') read_config_string(g_srcfilename, "a2dpd", "cmdpause", g_sCmdPause, sizeof(g_sCmdPause), "");	if(g_sCmdStop[0]=='\0') read_config_string(g_srcfilename, "a2dpd", "cmdstop", g_sCmdStop, sizeof(g_sCmdStop), "");	if(g_sCmdPrev[0]=='\0') read_config_string(g_srcfilename, "a2dpd", "cmdprev", g_sCmdPrev, sizeof(g_sCmdPrev), "");	if(g_sCmdNext[0]=='\0') read_config_string(g_srcfilename, "a2dpd", "cmdnext", g_sCmdNext, sizeof(g_sCmdNext), "");	if(g_sCmdNew[0]=='\0') read_config_string(g_srcfilename, "a2dpd", "cmdnew", g_sCmdNew, sizeof(g_sCmdNew), "");	if(g_sOutputFilename[0]=='\0') read_config_string(g_srcfilename, "a2dpd", "logfile", g_sOutputFilename, sizeof(g_sOutputFilename), "/dev/null");	if(g_brereadconfig<0) g_brereadconfig = read_config_int(g_srcfilename, "a2dpd", "enablerereadconfig", 1);	if(g_breversestereo<0) g_breversestereo = read_config_int(g_srcfilename, "a2dpd", "enablereversestereo", 0);	if(g_autoconnect<0) g_autoconnect = read_config_int(g_srcfilename, "a2dpd", "enableautoconnect", 1);	if(g_bdebug<0) g_bdebug = read_config_int(g_srcfilename, "a2dpd", "enabledebug", 1);	if(g_stdin<0) g_stdin = read_config_int(g_srcfilename, "a2dpd", "enablestdin", 0);	if(bSessionBus<0) bSessionBus = read_config_int(g_srcfilename, "a2dpd", "sessionbus", 0);	clock_getres(CLOCK_REALTIME, &timer_resolution);	ignore_child_processes_return_values();	// Redirect outputs (if a file is specified, redirect to it and not stdout)	if(strcmp(g_sOutputFilename, "/dev/null") != 0) bVerbose = 0;	make_daemon_process(bFork, bVerbose, g_sOutputFilename);	// Lockfile must be acquired after daemonisation	if(lockfile(bKill)<0)		RETURNERROR("Lockfile acquisition failed");	init_uinput();	DBG("%s addr=%s timer=%d us [%s %s]", argv[0], addr, (int) (timer_resolution.tv_nsec / 1000), __DATE__, __TIME__);	// If we can be realtime it will be better	if(bRealtime)	{		DBG("Setting realtime priority to process, use with care");		// After some trouble while coding, a2dpd started spining 100%cpu		// In realtime, this led me with the only option of rebooting my PC		res = sched_setscheduler(0, SCHED_FIFO, &schedparam);		if(res != 0)			DBG("Setscheduler failed");	}	// set up the handler	signal(SIGINT, sigint_handler);	signal(SIGTERM, sigint_handler);	signal(SIGUSR1, SIG_IGN);	// global initialisations	a2dpd_signal_init(bSessionBus);	a2dp_init();	// Run main loop	main_loop(addr);	// global termination	a2dp_exit();	a2dpd_signal_kill();	kill_uinput();	DBG("Terminated succesfully");	return 0;}

⌨️ 快捷键说明

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