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

📄 headset.c

📁 这是Linux环境下的蓝牙源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	err = handle_event(device, &hs->buf[hs->data_start]);	if (err == -EINVAL) {		error("Badly formated or unrecognized command: %s",				&hs->buf[hs->data_start]);		err = headset_send(hs, "\r\nERROR\r\n");	} else if (err < 0)		error("Error handling command %s: %s (%d)",			&hs->buf[hs->data_start], strerror(-err), -err);	hs->data_start += cmd_len;	hs->data_length -= cmd_len;	if (!hs->data_length)		hs->data_start = 0;	return TRUE;failed:	headset_set_state(device, HEADSET_STATE_DISCONNECTED);	return FALSE;}static gboolean sco_cb(GIOChannel *chan, GIOCondition cond,			struct audio_device *device){	struct headset *hs;	if (cond & G_IO_NVAL)		return FALSE;	hs = device->headset;	error("Audio connection got disconnected");	headset_set_state(device, HEADSET_STATE_CONNECTED);	return FALSE;}static void rfcomm_connect_cb(GIOChannel *chan, int err, const bdaddr_t *src,			const bdaddr_t *dst, gpointer user_data){	struct audio_device *dev = user_data;	struct headset *hs = dev->headset;	struct pending_connect *p = hs->pending;	char hs_address[18];	if (err < 0) {		error("connect(): %s (%d)", strerror(-err), -err);		goto failed;	}	ba2str(&dev->dst, hs_address);	hs->rfcomm = chan;	p->io = NULL;	if (server_is_enabled(HANDSFREE_SVCLASS_ID) && hs->hfp_handle != 0)		hs->hfp_active = TRUE;	else		hs->hfp_active = FALSE;	g_io_add_watch(chan, G_IO_IN | G_IO_ERR | G_IO_HUP| G_IO_NVAL,			(GIOFunc) rfcomm_io_cb, dev);	debug("%s: Connected to %s", dev->path, hs_address);	/* In HFP mode wait for Service Level Connection */	if (hs->hfp_active)		return;	headset_set_state(dev, HEADSET_STATE_CONNECTED);	if (p->target_state == HEADSET_STATE_PLAYING) {		p->err = sco_connect(dev, NULL, NULL, NULL);		if (p->err < 0)			goto failed;		return;	}	if (p->msg) {		DBusMessage *reply = dbus_message_new_method_return(p->msg);		dbus_connection_send(dev->conn, reply, NULL);		dbus_message_unref(reply);	}	pending_connect_finalize(dev);	return;failed:	if (p->msg)		error_connection_attempt_failed(dev->conn, p->msg, p->err);	pending_connect_finalize(dev);	if (hs->rfcomm)		headset_set_state(dev, HEADSET_STATE_CONNECTED);	else		headset_set_state(dev, HEADSET_STATE_DISCONNECTED);}static void get_record_cb(sdp_list_t *recs, int err, gpointer user_data){	struct audio_device *dev = user_data;	struct headset *hs = dev->headset;	struct pending_connect *p = hs->pending;	int ch = -1;	sdp_record_t *record = NULL;	sdp_list_t *protos, *classes = NULL;	uuid_t uuid;	if (err < 0) {		error("Unable to get service record: %s (%d)", strerror(-err),			-err);		goto failed_not_supported;	}	if (!recs || !recs->data) {		error("No records found");		goto failed_not_supported;	}	record = recs->data;	if (sdp_get_service_classes(record, &classes) < 0) {		error("Unable to get service classes from record");		goto failed_not_supported;	}	memcpy(&uuid, classes->data, sizeof(uuid));	if (!sdp_uuid128_to_uuid(&uuid) || uuid.type != SDP_UUID16) {		error("Not a 16 bit UUID");		goto failed_not_supported;	}	if (hs->search_hfp) {		if (uuid.value.uuid16 != HANDSFREE_SVCLASS_ID) {			error("Service record didn't contain the HFP UUID");			goto failed_not_supported;		}		hs->hfp_handle = record->handle;	} else {		if (uuid.value.uuid16 != HEADSET_SVCLASS_ID) {			error("Service record didn't contain the HSP UUID");			goto failed_not_supported;		}		hs->hsp_handle = record->handle;	}	if (!sdp_get_access_protos(record, &protos)) {		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);		protos = NULL;	}	if (ch == -1) {		error("Unable to extract RFCOMM channel from service record");		goto failed_not_supported;	}	hs->rfcomm_ch = ch;	err = rfcomm_connect(dev, NULL, NULL, NULL);	if (err < 0) {		error("Unable to connect: %s (%s)", strerror(-err), -err);		p->err = -err;		error_connection_attempt_failed(dev->conn, p->msg, p->err);		goto failed;	}	sdp_list_free(classes, free);	sdp_record_free(record);	return;failed_not_supported:	if (p->msg) {		error_not_supported(dev->conn, p->msg);		dbus_message_unref(p->msg);		p->msg = NULL;	}failed:	if (classes)		sdp_list_free(classes, free);	if (record)		sdp_record_free(record);	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");	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 gboolean ring_timer_cb(gpointer data){	struct audio_device *device = data;	struct headset *hs = device->headset;	int err;	err = headset_send(hs, "\r\nRING\r\n");	if (err < 0)		error("Error while sending RING: %s (%d)",				strerror(-err), -err);	if (hs->cli_active && hs->ph_number) {		err = headset_send(hs, "\r\n+CLIP:\"%s\",%d\r\n",					hs->ph_number, hs->type);		if (err < 0)			error("Error while sending CLIP: %s (%d)",					strerror(-err), -err);	}	return TRUE;}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 (hs->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));	}	if (hs->cli_active && hs->ph_number) {		err = headset_send(hs, "\r\n+CLIP:\"%s\",%d\r\n",					hs->ph_number, hs->type);		if (err < 0) {			dbus_message_unref(reply);			return g_dbus_create_error(msg, ERROR_INTERFACE						".Failed", "%s",						strerror(-err));		}	}	hs->ring_timer = g_timeout_add(RING_INTERVAL, ring_timer_cb, device);done:	return reply;}static DBusMessage *hs_cancel_ringing(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 (!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:	if (hs->hfp_active) {		int err;		/*+CIEV: (callsetup = 0)*/		err = headset_send(hs, "\r\n+CIEV:3,0\r\n");		if (err < 0) {			dbus_message_unref(reply);			return g_dbus_create_error(msg, ERROR_INTERFACE						".Failed", "%s",						strerror(-err));		}	}	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:		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, char type){	struct audio_device *device = data;	struct headset *hs = device->headset;	DBusMessage *reply;	dbus_uint16_t gain;	int err;	if (hs->state < HEADSET_STATE_CONNECTED)		return g_dbus_create_error(msg, ERROR_INTERFACE						".NotConnected",						"Device not Connected");	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT16, &gain,				DBUS_TYPE_INVALID))		return NULL;	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){	return hs_set_gain(conn, msg, data, HEADSET_GAIN_SPEAKER);}static DBusMessage *hs_set_mic_gain(DBusConnection *conn,					DBusMessage *msg,					void *data){	return hs_set_gain(conn, msg, data, HEADSET_GAIN_MICROPHONE);}static DBusMessage *hf_setup_call(DBusConnection *conn,					DBusMessage *msg,					void *data){	struct audio_device *device = data;	struct headset *hs = device->headset;	DBusMessage *reply;	const char *value;	int err;

⌨️ 快捷键说明

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