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

📄 headset.c

📁 Linux的蓝牙操作工具。配合bluez-lib使用
💻 C
📖 第 1 页 / 共 3 页
字号:
		return error_failed(conn, msg, "Failed");	}	hs->ring_timer = g_timeout_add(RING_INTERVAL, ring_timer_cb, device);done:	send_message_and_unref(conn, reply);	return DBUS_HANDLER_RESULT_HANDLED;}static DBusHandlerResult hs_cancel_ringing(DBusConnection *conn,						DBusMessage *msg,						void *data){	struct device *device = data;	struct headset *hs = device->headset;	DBusMessage *reply = NULL;	if (hs->state < HEADSET_STATE_CONNECTED)		return error_not_connected(conn, msg);	reply = dbus_message_new_method_return(msg);	if (!reply)		return DBUS_HANDLER_RESULT_NEED_MEMORY;	if (!hs->ring_timer) {		debug("Got CancelRinging method call but ringing is not in progress");		goto done;	}	g_source_remove(hs->ring_timer);	hs->ring_timer = 0;done:	send_message_and_unref(conn, reply);	return DBUS_HANDLER_RESULT_HANDLED;}static DBusHandlerResult hs_play(DBusConnection *conn, DBusMessage *msg,					void *data){	struct device *device = data;	struct headset *hs = device->headset;	struct pending_connect *c;	int err;	if (hs->state < HEADSET_STATE_CONNECTED)		return error_not_connected(conn, msg);	if (hs->state >= HEADSET_STATE_PLAY_IN_PROGRESS)		return error_already_connected(conn, msg);	c = g_try_new0(struct pending_connect, 1);	if (!c)		return DBUS_HANDLER_RESULT_NEED_MEMORY;	c->msg = msg ? dbus_message_ref(msg) : NULL;	err = sco_connect(device, c);	if (err < 0) {		pending_connect_free(c);		return error_failed(conn, msg, strerror(-err));	}	return DBUS_HANDLER_RESULT_HANDLED;}static DBusHandlerResult hs_get_speaker_gain(DBusConnection *conn,						DBusMessage *msg,						void *data){	struct device *device = data;	struct headset *hs = device->headset;	DBusMessage *reply;	dbus_uint16_t gain;	if (hs->state < HEADSET_STATE_CONNECTED || hs->sp_gain < 0)		return error_not_available(conn, msg);	reply = dbus_message_new_method_return(msg);	if (!reply)		return DBUS_HANDLER_RESULT_NEED_MEMORY;	gain = (dbus_uint16_t) hs->sp_gain;	dbus_message_append_args(reply, DBUS_TYPE_UINT16, &gain,					DBUS_TYPE_INVALID);	send_message_and_unref(conn, reply);	return DBUS_HANDLER_RESULT_HANDLED;}static DBusHandlerResult hs_get_mic_gain(DBusConnection *conn,						DBusMessage *msg,						void *data){	struct device *device = data;	struct headset *hs = device->headset;	DBusMessage *reply;	dbus_uint16_t gain;	if (hs->state < HEADSET_STATE_CONNECTED || hs->mic_gain < 0)		return error_not_available(conn, msg);	reply = dbus_message_new_method_return(msg);	if (!reply)		return DBUS_HANDLER_RESULT_NEED_MEMORY;	gain = (dbus_uint16_t) hs->mic_gain;	dbus_message_append_args(reply, DBUS_TYPE_UINT16, &gain,					DBUS_TYPE_INVALID);	send_message_and_unref(conn, reply);	return DBUS_HANDLER_RESULT_HANDLED;}static DBusHandlerResult hs_set_gain(DBusConnection *conn,					DBusMessage *msg,					void *data, char type){	struct device *device = data;	struct headset *hs = device->headset;	DBusMessage *reply;	DBusError derr;	dbus_uint16_t gain;	int err;	if (hs->state < HEADSET_STATE_CONNECTED)		return error_not_connected(conn, msg);	dbus_error_init(&derr);	dbus_message_get_args(msg, &derr, DBUS_TYPE_UINT16, &gain,				DBUS_TYPE_INVALID);	if (dbus_error_is_set(&derr)) {		error_invalid_arguments(conn, msg, derr.message);		dbus_error_free(&derr);		return DBUS_HANDLER_RESULT_HANDLED;	}	if (gain > 15)		return error_invalid_arguments(conn, msg,					"Must be less than or equal to 15");	reply = dbus_message_new_method_return(msg);	if (!reply)		return DBUS_HANDLER_RESULT_NEED_MEMORY;	if (hs->state != HEADSET_STATE_PLAYING)		goto done;	err = headset_send(device->headset, "\r\n+VG%c=%u\r\n", type, gain);	if (err) {		dbus_message_unref(reply);		return error_failed(conn, msg, "Unable to send to headset");	}done:	if (type == HEADSET_GAIN_SPEAKER) {		hs->sp_gain = gain;		dbus_connection_emit_signal(conn, device->path,						AUDIO_HEADSET_INTERFACE,						"SpeakerGainChanged",						DBUS_TYPE_UINT16, &gain,						DBUS_TYPE_INVALID);	} else {		hs->mic_gain = gain;		dbus_connection_emit_signal(conn, device->path,						AUDIO_HEADSET_INTERFACE,						"MicrophoneGainChanged",						DBUS_TYPE_UINT16, &gain,						DBUS_TYPE_INVALID);	}	send_message_and_unref(conn, reply);	return DBUS_HANDLER_RESULT_HANDLED;}static DBusHandlerResult hs_set_speaker_gain(DBusConnection *conn,						DBusMessage *msg,						void *data){	return hs_set_gain(conn, msg, data, HEADSET_GAIN_SPEAKER);}static DBusHandlerResult hs_set_mic_gain(DBusConnection *conn,						DBusMessage *msg,						void *data){	return hs_set_gain(conn, msg, data, HEADSET_GAIN_MICROPHONE);}static DBusMethodVTable headset_methods[] = {	{ "Connect",		hs_connect,		"",	""	},	{ "Disconnect",		hs_disconnect,		"",	""	},	{ "IsConnected",	hs_is_connected,	"",	"b"	},	{ "IndicateCall",	hs_ring,		"",	""	},	{ "CancelCall",		hs_cancel_ringing,	"",	""	},	{ "Play",		hs_play,		"",	""	},	{ "Stop",		hs_stop,		"",	""	},	{ "IsPlaying",		hs_is_playing,		"",	"b"	},	{ "GetSpeakerGain",	hs_get_speaker_gain,	"",	"q"	},	{ "GetMicrophoneGain",	hs_get_mic_gain,	"",	"q"	},	{ "SetSpeakerGain",	hs_set_speaker_gain,	"q",	""	},	{ "SetMicrophoneGain",	hs_set_mic_gain,	"q",	""	},	{ NULL, NULL, NULL, NULL }};static DBusSignalVTable headset_signals[] = {	{ "Connected",			""	},	{ "Disconnected",		""	},	{ "AnswerRequested",		""	},	{ "Stopped",			""	},	{ "Playing",			""	},	{ "SpeakerGainChanged",		"q"	},	{ "MicrophoneGainChanged",	"q"	},	{ NULL, NULL }};static void headset_set_channel(struct headset *headset, sdp_record_t *record){	int ch;	sdp_list_t *protos;	if (sdp_get_access_protos(record, &protos) < 0) {		error("Unable to get access protos from headset record");		return;	}	ch = sdp_get_proto_port(protos, RFCOMM_UUID);	sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL);	sdp_list_free(protos, NULL);	if (ch > 0) {		headset->rfcomm_ch = ch;		debug("Discovered Headset service on RFCOMM channel %d", ch);	} else		error("Unable to get RFCOMM channel from Headset record");}void headset_update(struct device *dev, sdp_record_t *record, uint16_t svc){	struct headset *headset = dev->headset;	switch (svc) {	case HANDSFREE_SVCLASS_ID:		if (headset->hfp_handle &&				(headset->hfp_handle != record->handle)) {			error("More than one HFP record found on device");			return;		}		headset->hfp_handle = record->handle;		break;	case HEADSET_SVCLASS_ID:		if (headset->hsp_handle &&				(headset->hsp_handle != record->handle)) {			error("More than one HSP record found on device");			return;		}		headset->hsp_handle = record->handle;		/* Ignore this record if we already have access to HFP */		if (headset->hfp_handle)			return;		break;	default:		debug("Invalid record passed to headset_update");		return;	}	headset_set_channel(headset, record);}struct headset *headset_init(struct device *dev, int enable_hfp,				sdp_record_t *record, uint16_t svc){	struct headset *hs;	hs = g_new0(struct headset, 1);	hs->rfcomm_ch = -1;	hs->sp_gain = -1;	hs->mic_gain = -1;	hs->enable_hfp = enable_hfp;	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);register_iface:	if (!dbus_connection_register_interface(dev->conn, dev->path,						AUDIO_HEADSET_INTERFACE,						headset_methods,						headset_signals, NULL)) {		g_free(hs);		return NULL;	}	return hs;}void headset_free(struct device *dev){	struct headset *hs = dev->headset;	if (hs->sco) {		g_io_channel_close(hs->sco);		g_io_channel_unref(hs->sco);	}	if (hs->rfcomm) {		g_io_channel_close(hs->rfcomm);		g_io_channel_unref(hs->rfcomm);	}	g_free(hs);	dev->headset = NULL;}gboolean headset_cancel_stream(struct device *dev, unsigned int id){	struct headset *hs = dev->headset;	GSList *l;	struct pending_connect *pending = NULL;	for (l = hs->pending; l != NULL; l = l->next) {		struct pending_connect *tmp = l->data;		if (tmp->id == id) {			pending = tmp;			break;		}	}	if (!pending)		return FALSE;	hs->pending = g_slist_remove(hs->pending, pending);	pending_connect_free(pending);	if (!hs->pending)		headset_set_state(dev, HEADSET_STATE_DISCONNECTED);	return TRUE;}unsigned int headset_request_stream(struct device *dev, headset_stream_cb_t cb,					void *user_data){	struct headset *hs = dev->headset;	struct pending_connect *c;	static unsigned int cb_id = 0;	int err;	c = g_new0(struct pending_connect, 1);	c->cb = cb;	c->cb_data = user_data;	c->id = ++cb_id;	if (hs->rfcomm && hs->sco) {		hs->pending = g_slist_append(hs->pending, c);		g_idle_add((GSourceFunc) finalize_stream_setup, dev);		return c->id;	}	if (hs->rfcomm == NULL)		err = rfcomm_connect(dev, c);	else if (hs->sco == NULL)		err = sco_connect(dev, c);	if (err < 0)		goto error;	return c->id;error:	pending_connect_free(c);	return 0;}headset_type_t headset_get_type(struct device *dev){	struct headset *hs = dev->headset;	return hs->type;}void headset_set_type(struct device *dev, headset_type_t type){	struct headset *hs = dev->headset;	hs->type = type;}int headset_connect_rfcomm(struct device *dev, int sock){	struct headset *hs = dev->headset;	hs->rfcomm = g_io_channel_unix_new(sock);	return hs->rfcomm ? 0 : -EINVAL;}int headset_close_rfcomm(struct device *dev){	struct headset *hs = dev->headset;	if (hs->ring_timer) {		g_source_remove(hs->ring_timer);		hs->ring_timer = 0;	}	if (hs->rfcomm) {		g_io_channel_close(hs->rfcomm);		g_io_channel_unref(hs->rfcomm);		hs->rfcomm = NULL;	}	hs->data_start = 0;	hs->data_length = 0;	return 0;}void headset_set_state(struct device *dev, headset_state_t state){	struct headset *hs = dev->headset;	if (hs->state == state)		return;	switch(state) {	case HEADSET_STATE_DISCONNECTED:		close_sco(dev);		headset_close_rfcomm(dev);		dbus_connection_emit_signal(dev->conn, dev->path,						AUDIO_HEADSET_INTERFACE,						"Disconnected",						DBUS_TYPE_INVALID);		break;	case HEADSET_STATE_CONNECT_IN_PROGRESS:		break;	case HEADSET_STATE_CONNECTED:		close_sco(dev);		if (hs->state < state) {			g_io_add_watch(hs->rfcomm,				G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,				(GIOFunc) rfcomm_io_cb, dev);			dbus_connection_emit_signal(dev->conn, dev->path,						AUDIO_HEADSET_INTERFACE,						"Connected",						DBUS_TYPE_INVALID);		} else if (hs->state == HEADSET_STATE_PLAYING) {			dbus_connection_emit_signal(dev->conn, dev->path,						AUDIO_HEADSET_INTERFACE,						"Stopped",						DBUS_TYPE_INVALID);		}		break;	case HEADSET_STATE_PLAY_IN_PROGRESS:		break;	case HEADSET_STATE_PLAYING:		hs->sco_id = g_io_add_watch(hs->sco,					G_IO_ERR | G_IO_HUP | G_IO_NVAL,					(GIOFunc) sco_cb, dev);		dbus_connection_emit_signal(dev->conn, dev->path,						AUDIO_HEADSET_INTERFACE,						"Playing", DBUS_TYPE_INVALID);		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 device *dev){	struct headset *hs = dev->headset;	return hs->state;}int headset_get_channel(struct device *dev){	struct headset *hs = dev->headset;	return hs->rfcomm_ch;}gboolean headset_is_active(struct device *dev){	struct headset *hs = dev->headset;	if (hs->state != HEADSET_STATE_DISCONNECTED)		return TRUE;	return FALSE;}gboolean headset_lock(struct 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 device *dev, headset_lock_t lock){	struct headset *hs = dev->headset;	if (!(hs->lock & lock))		return FALSE;	hs->lock &= ~lock;	if (!hs->lock && hs->state > HEADSET_STATE_DISCONNECTED)		headset_set_state(dev, HEADSET_STATE_DISCONNECTED);	return TRUE;}gboolean headset_suspend(struct device *dev, void *data){	return TRUE;}gboolean headset_play(struct device *dev, void *data){	return TRUE;}int headset_get_sco_fd(struct device *dev){	struct headset *hs = dev->headset;	if (!hs->sco)		return -1;	return g_io_channel_unix_get_fd(hs->sco);}

⌨️ 快捷键说明

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