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

📄 headset.c

📁 BlueZ源码
💻 C
📖 第 1 页 / 共 4 页
字号:
		headset_set_state(dev, HEADSET_STATE_DISCONNECTED);	}	info("Unregistered interface %s on path %s",		AUDIO_HEADSET_INTERFACE, dev->path);	headset_free(dev);}void headset_unregister(struct audio_device *dev){	g_dbus_unregister_interface(dev->conn, dev->path,		AUDIO_HEADSET_INTERFACE);}struct headset *headset_init(struct audio_device *dev, uint16_t svc,				const char *uuidstr){	struct headset *hs;	const sdp_record_t *record;	hs = g_new0(struct headset, 1);	hs->rfcomm_ch = -1;	hs->sp_gain = -1;	hs->mic_gain = -1;	hs->search_hfp = server_is_enabled(&dev->src, HANDSFREE_SVCLASS_ID);	hs->hfp_active = FALSE;	hs->cli_active = FALSE;	record = btd_device_get_record(dev->btd_dev, uuidstr);	if (!record)		goto register_iface;	switch (svc) {	case HANDSFREE_SVCLASS_ID:		hs->hfp_handle = record->handle;		break;	case HEADSET_SVCLASS_ID:		hs->hsp_handle = record->handle;		break;	default:		debug("Invalid record passed to headset_init");		g_free(hs);		return NULL;	}	headset_set_channel(hs, record, svc);register_iface:	if (!g_dbus_register_interface(dev->conn, dev->path,					AUDIO_HEADSET_INTERFACE,					headset_methods, headset_signals, NULL,					dev, path_unregister)) {		g_free(hs);		return NULL;	}	info("Registered interface %s on path %s",		AUDIO_HEADSET_INTERFACE, dev->path);	return hs;}uint32_t headset_config_init(GKeyFile *config){	GError *err = NULL;	char *str;	/* Use the default values if there is no config file */	if (config == NULL)		return ag.features;	str = g_key_file_get_string(config, "General", "SCORouting",					&err);	if (err) {		debug("audio.conf: %s", err->message);		g_clear_error(&err);	} else {		if (strcmp(str, "PCM") == 0)			sco_hci = FALSE;		else if (strcmp(str, "HCI") == 0)			sco_hci = TRUE;		else			error("Invalid Headset Routing value: %s", str);		g_free(str);	}	return ag.features;}static gboolean hs_dc_timeout(struct audio_device *dev){	headset_set_state(dev, HEADSET_STATE_DISCONNECTED);	return FALSE;}gboolean headset_cancel_stream(struct audio_device *dev, unsigned int id){	struct headset *hs = dev->headset;	struct pending_connect *p = hs->pending;	GSList *l;	struct connect_cb *cb = NULL;	if (!p)		return FALSE;	for (l = p->callbacks; l != NULL; l = l->next) {		struct connect_cb *tmp = l->data;		if (tmp->id == id) {			cb = tmp;			break;		}	}	if (!cb)		return FALSE;	p->callbacks = g_slist_remove(p->callbacks, cb);	g_free(cb);	if (p->callbacks || p->msg)		return TRUE;	if (hs->auto_dc) {		if (hs->rfcomm)			hs->dc_timer = g_timeout_add_seconds(DC_TIMEOUT,						(GSourceFunc) hs_dc_timeout,						dev);		else			headset_set_state(dev, HEADSET_STATE_DISCONNECTED);	}	return TRUE;}static gboolean dummy_connect_complete(struct audio_device *dev){	pending_connect_finalize(dev);	return FALSE;}unsigned int headset_request_stream(struct audio_device *dev,					headset_stream_cb_t cb,					headset_lock_t lock,					void *user_data){	struct headset *hs = dev->headset;	unsigned int id;	if (hs->rfcomm && hs->sco) {		id = connect_cb_new(hs, HEADSET_STATE_PLAYING, cb, user_data);		g_idle_add((GSourceFunc) dummy_connect_complete, dev);		return id;	}	if (hs->dc_timer) {		g_source_remove(hs->dc_timer);		hs->dc_timer = 0;	}	if (hs->state == HEADSET_STATE_CONNECT_IN_PROGRESS ||			hs->state == HEADSET_STATE_PLAY_IN_PROGRESS)		return connect_cb_new(hs, HEADSET_STATE_PLAYING, cb, user_data);	if (hs->rfcomm == NULL) {		if (rfcomm_connect(dev, cb, user_data, &id) < 0)			return 0;		hs->auto_dc = TRUE;	} else {		if (sco_connect(dev, cb, user_data, &id) < 0)			return 0;	}	hs->pending->target_state = HEADSET_STATE_PLAYING;	return id;}unsigned int headset_config_stream(struct audio_device *dev,					headset_stream_cb_t cb,					headset_lock_t lock,					void *user_data){	struct headset *hs = dev->headset;	unsigned int id;	if (hs->lock & lock)		return 0;	if (hs->dc_timer) {		g_source_remove(hs->dc_timer);		hs->dc_timer = 0;	}	if (hs->state == HEADSET_STATE_CONNECT_IN_PROGRESS)		return connect_cb_new(hs, HEADSET_STATE_CONNECTED, cb,					user_data);	if (hs->rfcomm)		goto done;	if (rfcomm_connect(dev, cb, user_data, &id) < 0)		return 0;	hs->auto_dc = TRUE;	hs->pending->target_state = HEADSET_STATE_CONNECTED;	return id;done:	id = connect_cb_new(hs, HEADSET_STATE_CONNECTED, cb, user_data);	g_idle_add((GSourceFunc) dummy_connect_complete, dev);	return id;}unsigned int headset_suspend_stream(struct audio_device *dev,					headset_stream_cb_t cb,					headset_lock_t lock,					void *user_data){	struct headset *hs = dev->headset;	unsigned int id;	if (hs->lock & ~lock || !hs->rfcomm || !hs->sco)		return 0;	if (hs->dc_timer) {		g_source_remove(hs->dc_timer);		hs->dc_timer = 0;	}	close_sco(dev);	id = connect_cb_new(hs, HEADSET_STATE_CONNECTED, cb, user_data);	g_idle_add((GSourceFunc) dummy_connect_complete, dev);	return id;}gboolean get_hfp_active(struct audio_device *dev){	struct headset *hs = dev->headset;	return hs->hfp_active;}void set_hfp_active(struct audio_device *dev, gboolean active){	struct headset *hs = dev->headset;	hs->hfp_active = active;}int headset_connect_rfcomm(struct audio_device *dev, GIOChannel *io){	struct headset *hs = dev->headset;	hs->tmp_rfcomm = io;	return hs->tmp_rfcomm ? 0 : -EINVAL;}int headset_connect_sco(struct audio_device *dev, GIOChannel *io){	struct headset *hs = dev->headset;	if (hs->sco)		return -EISCONN;	hs->sco = io;	if (hs->pending_ring) {		ring_timer_cb(NULL);		ag.ring_timer = g_timeout_add_seconds(RING_INTERVAL,						ring_timer_cb,						NULL);		hs->pending_ring = FALSE;	}	return 0;}static int headset_close_rfcomm(struct audio_device *dev){	struct headset *hs = dev->headset;	GIOChannel *rfcomm = hs->tmp_rfcomm ? hs->tmp_rfcomm : hs->rfcomm;	if (rfcomm) {		g_io_channel_close(rfcomm);		g_io_channel_unref(rfcomm);		hs->tmp_rfcomm = NULL;		hs->rfcomm = NULL;	}	hs->data_start = 0;	hs->data_length = 0;	return 0;}void headset_set_authorized(struct audio_device *dev){	struct headset *hs = dev->headset;	/* For HFP telephony isn't ready just disconnect */	if (hs->hfp_active && !ag.telephony_ready) {		error("Unable to accept HFP connection since the telephony "				"subsystem isn't initialized");		headset_set_state(dev, HEADSET_STATE_DISCONNECTED);		return;	}	hs->rfcomm = hs->tmp_rfcomm;	hs->tmp_rfcomm = NULL;	g_io_add_watch(hs->rfcomm,			G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,			(GIOFunc) rfcomm_io_cb, dev);	hs->auto_dc = FALSE;	/* For HSP (no special SLC setup) move to CONNECTED state */	if (!hs->hfp_active)		headset_set_state(dev, HEADSET_STATE_CONNECTED);}void headset_set_state(struct audio_device *dev, headset_state_t state){	struct headset *hs = dev->headset;	gboolean value;	if (hs->state == state)		return;	switch (state) {	case HEADSET_STATE_DISCONNECTED:		value = FALSE;		close_sco(dev);		headset_close_rfcomm(dev);		g_dbus_emit_signal(dev->conn, dev->path,					AUDIO_HEADSET_INTERFACE,					"Disconnected",					DBUS_TYPE_INVALID);		emit_property_changed(dev->conn, dev->path,					AUDIO_HEADSET_INTERFACE, "Connected",					DBUS_TYPE_BOOLEAN, &value);		telephony_device_disconnected(dev);		active_devices = g_slist_remove(active_devices, dev);		break;	case HEADSET_STATE_CONNECT_IN_PROGRESS:		break;	case HEADSET_STATE_CONNECTED:		close_sco(dev);		if (hs->state < state) {			value = TRUE;			g_dbus_emit_signal(dev->conn, dev->path,						AUDIO_HEADSET_INTERFACE,						"Connected",						DBUS_TYPE_INVALID);			emit_property_changed(dev->conn, dev->path,						AUDIO_HEADSET_INTERFACE,						"Connected",						DBUS_TYPE_BOOLEAN, &value);			active_devices = g_slist_append(active_devices, dev);			telephony_device_connected(dev);		} else if (hs->state == HEADSET_STATE_PLAYING) {			value = FALSE;			g_dbus_emit_signal(dev->conn, dev->path,						AUDIO_HEADSET_INTERFACE,						"Stopped",						DBUS_TYPE_INVALID);			emit_property_changed(dev->conn, dev->path,						AUDIO_HEADSET_INTERFACE,						"Playing",						DBUS_TYPE_BOOLEAN, &value);		}		break;	case HEADSET_STATE_PLAY_IN_PROGRESS:		break;	case HEADSET_STATE_PLAYING:		value = TRUE;		hs->sco_id = g_io_add_watch(hs->sco,					G_IO_ERR | G_IO_HUP | G_IO_NVAL,					(GIOFunc) sco_cb, dev);		g_dbus_emit_signal(dev->conn, dev->path,					AUDIO_HEADSET_INTERFACE, "Playing",					DBUS_TYPE_INVALID);		emit_property_changed(dev->conn, dev->path,					AUDIO_HEADSET_INTERFACE, "Playing",					DBUS_TYPE_BOOLEAN, &value);		if (hs->sp_gain >= 0)			headset_send(hs, "\r\n+VGS=%u\r\n", hs->sp_gain);		if (hs->mic_gain >= 0)			headset_send(hs, "\r\n+VGM=%u\r\n", hs->mic_gain);		break;	}	debug("State changed %s: %s -> %s", dev->path, str_state[hs->state],		str_state[state]);	hs->state = state;}headset_state_t headset_get_state(struct audio_device *dev){	struct headset *hs = dev->headset;	return hs->state;}int headset_get_channel(struct audio_device *dev){	struct headset *hs = dev->headset;	return hs->rfcomm_ch;}gboolean headset_is_active(struct audio_device *dev){	struct headset *hs = dev->headset;	if (hs->state != HEADSET_STATE_DISCONNECTED)		return TRUE;	return FALSE;}gboolean headset_lock(struct audio_device *dev, headset_lock_t lock){	struct headset *hs = dev->headset;	if (hs->lock & lock)		return FALSE;	hs->lock |= lock;	return TRUE;}gboolean headset_unlock(struct audio_device *dev, headset_lock_t lock){	struct headset *hs = dev->headset;	if (!(hs->lock & lock))		return FALSE;	hs->lock &= ~lock;	if (hs->lock)		return TRUE;	if (hs->state == HEADSET_STATE_PLAYING)		headset_set_state(dev, HEADSET_STATE_CONNECTED);	if (hs->auto_dc) {		if (hs->state == HEADSET_STATE_CONNECTED)			hs->dc_timer = g_timeout_add_seconds(DC_TIMEOUT,						(GSourceFunc) hs_dc_timeout,						dev);		else			headset_set_state(dev, HEADSET_STATE_DISCONNECTED);	}	return TRUE;}gboolean headset_suspend(struct audio_device *dev, void *data){	return TRUE;}gboolean headset_play(struct audio_device *dev, void *data){	return TRUE;}int headset_get_sco_fd(struct audio_device *dev){	struct headset *hs = dev->headset;	if (!hs->sco)		return -1;	return g_io_channel_unix_get_fd(hs->sco);}int telephony_event_ind(int index){	if (!active_devices)		return -ENODEV;	if (!ag.er_ind) {		debug("telephony_report_event called but events are disabled");		return -EINVAL;	}	send_foreach_headset(active_devices, hfp_cmp,				"\r\n+CIEV: %d,%d\r\n", index + 1,				ag.indicators[index].val);	return 0;}int telephony_response_and_hold_ind(int rh){	if (!active_devices)		return -ENODEV;	ag.rh = rh;	/* If we aren't in any response and hold state don't send anything */	if (ag.rh < 0)		return 0;	send_foreach_headset(active_devices, hfp_cmp, "\r\n+BTRH: %d\r\n",				ag.rh);	return 0;}int telephony_incoming_call_ind(const char *number, int type){	struct audio_device *dev;	struct headset *hs;	if (!active_devices)		return -ENODEV;	/* Get the latest connected device */	dev = active_devices->data;	hs = dev->headset;	if (ag.ring_timer) {		debug("telephony_incoming_call_ind: already calling");		return -EBUSY;	}	g_free(ag.number);	ag.number = g_strdup(number);	ag.number_type = type;	if (ag.features & AG_FEATURE_INBAND_RINGTONE && hs->hfp_active &&			hs->state != HEADSET_STATE_PLAYING) {		if (hs->state == HEADSET_STATE_CONNECTED) {			int ret;			ret = sco_connect(dev, NULL, NULL, NULL);			if (ret < 0)				return ret;		}		hs->pending_ring = TRUE;		return 0;	}	ring_timer_cb(NULL);	ag.ring_timer = g_timeout_add_seconds(RING_INTERVAL, ring_timer_cb,						NULL);	return 0;}int telephony_calling_stopped_ind(void){	struct audio_device *dev;	if (!active_devices)		return -ENODEV;	/* In case SCO isn't fully up yet */	dev = active_devices->data;	if (!dev->headset->pending_ring && !ag.ring_timer)		return -EINVAL;	dev->headset->pending_ring = FALSE;	if (ag.ring_timer) {		g_source_remove(ag.ring_timer);		ag.ring_timer = 0;	}	return 0;}int telephony_ready_ind(uint32_t features,			const struct indicator *indicators, int rh,			const char *chld){	ag.telephony_ready = TRUE;	ag.features = features;	ag.indicators = indicators;	ag.rh = rh;	ag.chld = g_strdup(chld);	debug("Telephony plugin initialized");	print_ag_features(ag.features);	return 0;}int telephony_list_current_call_ind(int idx, int dir, int status, int mode,					int mprty, const char *number,					int type){	if (!active_devices)		return -ENODEV;	if (number)		send_foreach_headset(active_devices, hfp_cmp,					"\r\n+CLCC: %d,%d,%d,%d,%d,%s,%d\r\n",					idx, dir, status, mode, mprty,					number, type);	else		send_foreach_headset(active_devices, hfp_cmp,					"\r\n+CLCC: %d,%d,%d,%d,%d\r\n",					idx, dir, status, mode, mprty);	return 0;}int telephony_subscriber_number_ind(const char *number, int type, int service){	if (!active_devices)		return -ENODEV;	send_foreach_headset(active_devices, hfp_cmp,				"\r\n+CNUM: ,%s,%d,,%d\r\n",				number, type, service);	return 0;}static int cwa_cmp(struct headset *hs){	if (!hs->hfp_active)		return -1;	if (hs->cwa_enabled)		return 0;	else		return -1;}int telephony_call_waiting_ind(const char *number, int type){	if (!active_devices)		return -ENODEV;	send_foreach_headset(active_devices, cwa_cmp, "\r\n+CCWA: %s,%d\r\n",				number, type);	return 0;}

⌨️ 快捷键说明

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