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

📄 headset.c

📁 BlueZ源码
💻 C
📖 第 1 页 / 共 4 页
字号:
	}	sdp_list_free(classes, free);	return;failed_not_supported:	if (p->msg)		error_not_supported(dev->conn, p->msg);failed:	if (classes)		sdp_list_free(classes, free);	pending_connect_finalize(dev);	headset_set_state(dev, HEADSET_STATE_DISCONNECTED);}static int get_records(struct audio_device *device, headset_stream_cb_t cb,			void *user_data, unsigned int *cb_id){	struct headset *hs = device->headset;	uuid_t uuid;	sdp_uuid16_create(&uuid, hs->search_hfp ? HANDSFREE_SVCLASS_ID :				HEADSET_SVCLASS_ID);	headset_set_state(device, HEADSET_STATE_CONNECT_IN_PROGRESS);	pending_connect_init(hs, HEADSET_STATE_CONNECTED);	if (cb) {		unsigned int id;		id = connect_cb_new(hs, HEADSET_STATE_CONNECTED,					cb, user_data);		if (cb_id)			*cb_id = id;	}	return bt_search_service(&device->src, &device->dst, &uuid,			get_record_cb, device, NULL);}static int rfcomm_connect(struct audio_device *dev, headset_stream_cb_t cb,				void *user_data, unsigned int *cb_id){	struct headset *hs = dev->headset;	char address[18];	int err;	if (hs->rfcomm_ch < 0)		return get_records(dev, cb, user_data, cb_id);	ba2str(&dev->dst, address);	debug("%s: Connecting to %s channel %d", dev->path, address,		hs->rfcomm_ch);	err = bt_rfcomm_connect(&dev->src, &dev->dst, hs->rfcomm_ch,			rfcomm_connect_cb, dev);	if (err < 0) {		error("connect() failed: %s (%d)", strerror(-err), -err);		return err;	}	headset_set_state(dev, HEADSET_STATE_CONNECT_IN_PROGRESS);	pending_connect_init(hs, HEADSET_STATE_CONNECTED);	if (cb) {		unsigned int id = connect_cb_new(hs, HEADSET_STATE_CONNECTED,							cb, user_data);		if (cb_id)			*cb_id = id;	}	return 0;}static DBusMessage *hs_stop(DBusConnection *conn, DBusMessage *msg,					void *data){	struct audio_device *device = data;	struct headset *hs = device->headset;	DBusMessage *reply = NULL;	if (hs->state < HEADSET_STATE_PLAY_IN_PROGRESS)		return g_dbus_create_error(msg, ERROR_INTERFACE						".NotConnected",						"Device not Connected");	reply = dbus_message_new_method_return(msg);	if (!reply)		return NULL;	headset_set_state(device, HEADSET_STATE_CONNECTED);	return reply;}static DBusMessage *hs_is_playing(DBusConnection *conn, DBusMessage *msg,					void *data){	struct audio_device *device = data;	struct headset *hs = device->headset;	DBusMessage *reply;	dbus_bool_t playing;	reply = dbus_message_new_method_return(msg);	if (!reply)		return NULL;	playing = (hs->state == HEADSET_STATE_PLAYING);	dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &playing,					DBUS_TYPE_INVALID);	return reply;}static DBusMessage *hs_disconnect(DBusConnection *conn, DBusMessage *msg,					void *data){	struct audio_device *device = data;	struct headset *hs = device->headset;	DBusMessage *reply = NULL;	char hs_address[18];	reply = dbus_message_new_method_return(msg);	if (!reply)		return NULL;	if (hs->state == HEADSET_STATE_DISCONNECTED)		return g_dbus_create_error(msg, ERROR_INTERFACE						".NotConnected",						"Device not Connected");	headset_set_state(device, HEADSET_STATE_DISCONNECTED);	ba2str(&device->dst, hs_address);	info("Disconnected from %s, %s", hs_address, device->path);	return reply;}static DBusMessage *hs_is_connected(DBusConnection *conn,						DBusMessage *msg,						void *data){	struct audio_device *device = data;	DBusMessage *reply;	dbus_bool_t connected;	reply = dbus_message_new_method_return(msg);	if (!reply)		return NULL;	connected = (device->headset->state >= HEADSET_STATE_CONNECTED);	dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &connected,					DBUS_TYPE_INVALID);	return reply;}static DBusMessage *hs_connect(DBusConnection *conn, DBusMessage *msg,					void *data){	struct audio_device *device = data;	struct headset *hs = device->headset;	int err;	if (hs->state == HEADSET_STATE_CONNECT_IN_PROGRESS)		return g_dbus_create_error(msg, ERROR_INTERFACE ".InProgress",						"Connect in Progress");	else if (hs->state > HEADSET_STATE_CONNECT_IN_PROGRESS)		return g_dbus_create_error(msg, ERROR_INTERFACE						".AlreadyConnected",						"Already Connected");	if (hs->hfp_handle && !ag.telephony_ready)		return g_dbus_create_error(msg, ERROR_INTERFACE ".NotReady",					"Telephony subsystem not ready");	if (!manager_allow_headset_connection(&device->src))		return g_dbus_create_error(msg, ERROR_INTERFACE ".NotAllowed",						"Too many connected devices");	err = rfcomm_connect(device, NULL, NULL, NULL);	if (err < 0)		return g_dbus_create_error(msg, ERROR_INTERFACE						".ConnectAttemptFailed",						"Connect Attempt Failed");	hs->auto_dc = FALSE;	hs->pending->msg = dbus_message_ref(msg);	return NULL;}static DBusMessage *hs_ring(DBusConnection *conn, DBusMessage *msg,					void *data){	struct audio_device *device = data;	struct headset *hs = device->headset;	DBusMessage *reply = NULL;	int err;	if (hs->state < HEADSET_STATE_CONNECTED)		return g_dbus_create_error(msg, ERROR_INTERFACE						".NotConnected",						"Device not Connected");	reply = dbus_message_new_method_return(msg);	if (!reply)		return NULL;	if (ag.ring_timer) {		debug("IndicateCall received when already indicating");		goto done;	}	err = headset_send(hs, "\r\nRING\r\n");	if (err < 0) {		dbus_message_unref(reply);		return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",						"%s", strerror(-err));	}	ring_timer_cb(NULL);	ag.ring_timer = g_timeout_add_seconds(RING_INTERVAL, ring_timer_cb,						NULL);done:	return reply;}static DBusMessage *hs_cancel_call(DBusConnection *conn,					DBusMessage *msg,					void *data){	struct audio_device *device = data;	struct headset *hs = device->headset;	DBusMessage *reply = NULL;	if (hs->state < HEADSET_STATE_CONNECTED)		return g_dbus_create_error(msg, ERROR_INTERFACE						".NotConnected",						"Device not Connected");	reply = dbus_message_new_method_return(msg);	if (!reply)		return NULL;	if (ag.ring_timer) {		g_source_remove(ag.ring_timer);		ag.ring_timer = 0;	} else		debug("Got CancelCall method call but no call is active");	return reply;}static DBusMessage *hs_play(DBusConnection *conn, DBusMessage *msg,				void *data){	struct audio_device *device = data;	struct headset *hs = device->headset;	int err;	if (sco_hci) {		error("Refusing Headset.Play() because SCO HCI routing "				"is enabled");		return g_dbus_create_error(msg, ERROR_INTERFACE ".NotAvailable",						"Operation not Available");	}	switch (hs->state) {	case HEADSET_STATE_DISCONNECTED:	case HEADSET_STATE_CONNECT_IN_PROGRESS:		return g_dbus_create_error(msg, ERROR_INTERFACE						".NotConnected",						"Device not Connected");	case HEADSET_STATE_PLAY_IN_PROGRESS:		if (hs->pending && hs->pending->msg == NULL) {			hs->pending->msg = dbus_message_ref(msg);			return NULL;		}		return g_dbus_create_error(msg, ERROR_INTERFACE						".InProgress",						"Play in Progress");	case HEADSET_STATE_PLAYING:		return g_dbus_create_error(msg, ERROR_INTERFACE						".AlreadyConnected",						"Device Already Connected");	case HEADSET_STATE_CONNECTED:	default:		break;	}	err = sco_connect(device, NULL, NULL, NULL);	if (err < 0)		return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",						"%s", strerror(-err));	hs->pending->msg = dbus_message_ref(msg);	return NULL;}static DBusMessage *hs_get_speaker_gain(DBusConnection *conn,					DBusMessage *msg,					void *data){	struct audio_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 g_dbus_create_error(msg, ERROR_INTERFACE ".NotAvailable",						"Operation not Available");	reply = dbus_message_new_method_return(msg);	if (!reply)		return NULL;	gain = (dbus_uint16_t) hs->sp_gain;	dbus_message_append_args(reply, DBUS_TYPE_UINT16, &gain,					DBUS_TYPE_INVALID);	return reply;}static DBusMessage *hs_get_mic_gain(DBusConnection *conn,					DBusMessage *msg,					void *data){	struct audio_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 g_dbus_create_error(msg, ERROR_INTERFACE ".NotAvailable",						"Operation not Available");	reply = dbus_message_new_method_return(msg);	if (!reply)		return NULL;	gain = (dbus_uint16_t) hs->mic_gain;	dbus_message_append_args(reply, DBUS_TYPE_UINT16, &gain,					DBUS_TYPE_INVALID);	return reply;}static DBusMessage *hs_set_gain(DBusConnection *conn,				DBusMessage *msg,				void *data, uint16_t gain,				char type){	struct audio_device *device = data;	struct headset *hs = device->headset;	DBusMessage *reply;	int err;	if (hs->state < HEADSET_STATE_CONNECTED)		return g_dbus_create_error(msg, ERROR_INTERFACE						".NotConnected",						"Device not Connected");	if (gain > 15)		return g_dbus_create_error(msg, ERROR_INTERFACE						".InvalidArgument",						"Must be less than or equal to 15");	reply = dbus_message_new_method_return(msg);	if (!reply)		return NULL;	if (hs->state != HEADSET_STATE_PLAYING)		goto done;	err = headset_send(hs, "\r\n+VG%c=%u\r\n", type, gain);	if (err < 0) {		dbus_message_unref(reply);		return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",						"%s", strerror(-err));	}done:	if (type == HEADSET_GAIN_SPEAKER) {		hs->sp_gain = gain;		g_dbus_emit_signal(conn, device->path,					AUDIO_HEADSET_INTERFACE,					"SpeakerGainChanged",					DBUS_TYPE_UINT16, &gain,					DBUS_TYPE_INVALID);	} else {		hs->mic_gain = gain;		g_dbus_emit_signal(conn, device->path,					AUDIO_HEADSET_INTERFACE,					"MicrophoneGainChanged",					DBUS_TYPE_UINT16, &gain,					DBUS_TYPE_INVALID);	}	return reply;}static DBusMessage *hs_set_speaker_gain(DBusConnection *conn,					DBusMessage *msg,					void *data){	uint16_t gain;	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT16, &gain,				DBUS_TYPE_INVALID))		return NULL;	return hs_set_gain(conn, msg, data, gain, HEADSET_GAIN_SPEAKER);}static DBusMessage *hs_set_mic_gain(DBusConnection *conn,					DBusMessage *msg,					void *data){	uint16_t gain;	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT16, &gain,				DBUS_TYPE_INVALID))		return NULL;	return hs_set_gain(conn, msg, data, gain, HEADSET_GAIN_MICROPHONE);}static DBusMessage *hs_get_properties(DBusConnection *conn,					DBusMessage *msg, void *data){	struct audio_device *device = data;	DBusMessage *reply;	DBusMessageIter iter;	DBusMessageIter dict;	gboolean value;	reply = dbus_message_new_method_return(msg);	if (!reply)		return NULL;	dbus_message_iter_init_append(reply, &iter);	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,			DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING			DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING			DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);	/* Playing */	value = (device->headset->state == HEADSET_STATE_PLAYING);	dict_append_entry(&dict, "Playing", DBUS_TYPE_BOOLEAN, &value);	/* Connected */	value = (device->headset->state >= HEADSET_STATE_CONNECTED);	dict_append_entry(&dict, "Connected", DBUS_TYPE_BOOLEAN, &value);	if (!value)		goto done;	/* SpeakerGain */	dict_append_entry(&dict, "SpeakerGain",				DBUS_TYPE_UINT16, &device->headset->sp_gain);	/* MicrophoneGain */	dict_append_entry(&dict, "MicrophoneGain",				DBUS_TYPE_UINT16, &device->headset->mic_gain);done:	dbus_message_iter_close_container(&iter, &dict);	return reply;}static DBusMessage *hs_set_property(DBusConnection *conn,					DBusMessage *msg, void *data){	const char *property;	DBusMessageIter iter;	DBusMessageIter sub;	uint16_t gain;	if (!dbus_message_iter_init(msg, &iter))		return invalid_args(msg);	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)		return invalid_args(msg);	dbus_message_iter_get_basic(&iter, &property);	dbus_message_iter_next(&iter);	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)		return invalid_args(msg);	dbus_message_iter_recurse(&iter, &sub);	if (g_str_equal("SpeakerGain", property)) {		if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_UINT16)			return invalid_args(msg);		dbus_message_iter_get_basic(&sub, &gain);		return hs_set_gain(conn, msg, data, gain,					HEADSET_GAIN_SPEAKER);	} else if (g_str_equal("MicrophoneGain", property)) {		if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_UINT16)			return invalid_args(msg);		dbus_message_iter_get_basic(&sub, &gain);		return hs_set_gain(conn, msg, data, gain,					HEADSET_GAIN_MICROPHONE);	}	return invalid_args(msg);}static GDBusMethodTable headset_methods[] = {	{ "Connect",		"",	"",	hs_connect,						G_DBUS_METHOD_FLAG_ASYNC },	{ "Disconnect",		"",	"",	hs_disconnect },	{ "IsConnected",	"",	"b",	hs_is_connected },	{ "IndicateCall",	"",	"",	hs_ring },	{ "CancelCall",		"",	"",	hs_cancel_call },	{ "Play",		"",	"",	hs_play,						G_DBUS_METHOD_FLAG_ASYNC },	{ "Stop",		"",	"",	hs_stop },	{ "IsPlaying",		"",	"b",	hs_is_playing,						G_DBUS_METHOD_FLAG_DEPRECATED },	{ "GetSpeakerGain",	"",	"q",	hs_get_speaker_gain,						G_DBUS_METHOD_FLAG_DEPRECATED },	{ "GetMicrophoneGain",	"",	"q",	hs_get_mic_gain,						G_DBUS_METHOD_FLAG_DEPRECATED },	{ "SetSpeakerGain",	"q",	"",	hs_set_speaker_gain,						G_DBUS_METHOD_FLAG_DEPRECATED },	{ "SetMicrophoneGain",	"q",	"",	hs_set_mic_gain,						G_DBUS_METHOD_FLAG_DEPRECATED },	{ "GetProperties",	"",	"a{sv}",hs_get_properties },	{ "SetProperty",	"sv",	"",	hs_set_property },	{ NULL, NULL, NULL, NULL }};static GDBusSignalTable headset_signals[] = {	{ "Connected",			"",	G_DBUS_SIGNAL_FLAG_DEPRECATED },	{ "Disconnected",		"",	G_DBUS_SIGNAL_FLAG_DEPRECATED },	{ "AnswerRequested",		""	},	{ "Stopped",			"",	G_DBUS_SIGNAL_FLAG_DEPRECATED },	{ "Playing",			"",	G_DBUS_SIGNAL_FLAG_DEPRECATED },	{ "SpeakerGainChanged",		"q",	G_DBUS_SIGNAL_FLAG_DEPRECATED },	{ "MicrophoneGainChanged",	"q",	G_DBUS_SIGNAL_FLAG_DEPRECATED },	{ "CallTerminated",		""	},	{ "PropertyChanged",		"sv"	},	{ NULL, NULL }};static void headset_set_channel(struct headset *headset,				const sdp_record_t *record, uint16_t svc){	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 %s service on RFCOMM channel %d",			svc == HEADSET_SVCLASS_ID ? "Headset" : "Handsfree",			ch);	} else		error("Unable to get RFCOMM channel from Headset record");}void headset_update(struct audio_device *dev, uint16_t svc,			const char *uuidstr){	struct headset *headset = dev->headset;	const sdp_record_t *record;	record = btd_device_get_record(dev->btd_dev, uuidstr);	if (!record)		return;	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, svc);}static void headset_free(struct audio_device *dev){	struct headset *hs = dev->headset;	if (hs->dc_timer) {		g_source_remove(hs->dc_timer);		hs->dc_timer = 0;	}	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;}static void path_unregister(void *data){	struct audio_device *dev = data;	struct headset *hs = dev->headset;	if (hs->state > HEADSET_STATE_DISCONNECTED) {		debug("Headset unregistered while device was connected!");

⌨️ 快捷键说明

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