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

📄 manager.c

📁 Linux的蓝牙操作工具。配合bluez-lib使用
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * *  BlueZ - Bluetooth protocol stack for Linux * *  Copyright (C) 2006-2007  Nokia Corporation *  Copyright (C) 2004-2007  Marcel Holtmann <marcel@holtmann.org> * * *  This program is free software; you can redistribute it and/or modify *  it under the terms of the GNU General Public License as published by *  the Free Software Foundation; either version 2 of the License, or *  (at your option) any later version. * *  This program is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *  GNU General Public License for more details. * *  You should have received a copy of the GNU General Public License *  along with this program; if not, write to the Free Software *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA * */#ifdef HAVE_CONFIG_H#include <config.h>#endif#include <stdio.h>#include <stdlib.h>#include <stdarg.h>#include <errno.h>#include <unistd.h>#include <stdint.h>#include <sys/stat.h>#include <dirent.h>#include <ctype.h>#include <signal.h>#include <bluetooth/bluetooth.h>#include <bluetooth/hci.h>#include <bluetooth/hci_lib.h>#include <bluetooth/rfcomm.h>#include <bluetooth/sdp.h>#include <bluetooth/sdp_lib.h>#include <glib.h>#include <dbus/dbus.h>#include "dbus-helper.h"#include "dbus.h"#include "logging.h"#include "textfile.h"#include "ipc.h"#include "device.h"#include "error.h"#include "avdtp.h"#include "a2dp.h"#include "headset.h"#include "gateway.h"#include "sink.h"#include "control.h"#include "manager.h"typedef enum {	HEADSET	= 1 << 0,	GATEWAY	= 1 << 1,	SINK	= 1 << 2,	SOURCE	= 1 << 3,	CONTROL	= 1 << 4,	TARGET	= 1 << 5,	INVALID	= 1 << 6} audio_service_type;typedef enum {		GENERIC_AUDIO = 0,		ADVANCED_AUDIO,		AV_REMOTE,		GET_RECORDS} audio_sdp_state_t;struct audio_sdp_data {	struct device *device;	DBusMessage *msg;	/* Method call or NULL */	GSList *handles;	/* uint32_t * */	GSList *records;	/* sdp_record_t * */	audio_sdp_state_t state;	create_dev_cb_t cb;	void *cb_data;};static DBusConnection *connection = NULL;static struct device *default_hs = NULL;static struct device *default_dev = NULL;static GSList *devices = NULL;static uint32_t hs_record_id = 0;static uint32_t hf_record_id = 0;static GIOChannel *hs_server = NULL;static GIOChannel *hf_server = NULL;static const struct enabled_interfaces *enabled;static gboolean enable_hfp = FALSE;static void get_next_record(struct audio_sdp_data *data);static DBusHandlerResult get_handles(const char *uuid,					struct audio_sdp_data *data);static struct device *create_device(bdaddr_t *bda){	static int device_id = 0;	char path[128];	snprintf(path, sizeof(path) - 1,			"%s/device%d", AUDIO_MANAGER_PATH, device_id++);	return device_register(connection, path, bda);}static void destroy_device(struct device *device){	dbus_connection_destroy_object_path(connection, device->path);}static void remove_device(struct device *device){	if (device == default_dev) {		debug("Removing default device");		default_dev = NULL;	}	if (device == default_hs) {		debug("Removing default headset");		default_hs = NULL;	}	devices = g_slist_remove(devices, device);	destroy_device(device);}static gboolean add_device(struct device *device, gboolean send_signals){	if (!send_signals)		goto add;	dbus_connection_emit_signal(connection, AUDIO_MANAGER_PATH,					AUDIO_MANAGER_INTERFACE,					"DeviceCreated",					DBUS_TYPE_STRING, &device->path,					DBUS_TYPE_INVALID);	if (device->headset)		dbus_connection_emit_signal(connection,				AUDIO_MANAGER_PATH,				AUDIO_MANAGER_INTERFACE,				"HeadsetCreated",				DBUS_TYPE_STRING, &device->path,				DBUS_TYPE_INVALID);add:	if (default_dev == NULL && g_slist_length(devices) == 0) {		debug("Selecting default device");		default_dev = device;	}	if (!default_hs && device->headset && !devices)		default_hs = device;	devices = g_slist_append(devices, device);	return TRUE;}static uint16_t get_service_uuid(const sdp_record_t *record){	sdp_list_t *classes;	uuid_t uuid;	uint16_t uuid16 = 0;	if (sdp_get_service_classes(record, &classes) < 0) {		error("Unable to get service classes from record");		return 0;	}	memcpy(&uuid, classes->data, sizeof(uuid));	if (!sdp_uuid128_to_uuid(&uuid)) {		error("Not a 16 bit UUID");		sdp_list_free(classes, free);		return 0;	}	if (uuid.type == SDP_UUID32) {		if (uuid.value.uuid32 > 0xFFFF) {			error("Not a 16 bit UUID");			goto done;		}		uuid16 = (uint16_t) uuid.value.uuid32;	} else		uuid16 = uuid.value.uuid16;done:	sdp_list_free(classes, free);	return uuid16;}static gboolean server_is_enabled(uint16_t svc){	gboolean ret;	switch (svc) {	case HEADSET_SVCLASS_ID:		ret = (hs_server != NULL);		break;	case HANDSFREE_SVCLASS_ID:		ret = (hf_server != NULL);		break;	case AUDIO_SINK_SVCLASS_ID:		return enabled->sink;	case AV_REMOTE_TARGET_SVCLASS_ID:	case AV_REMOTE_SVCLASS_ID:		return enabled->control;	default:		ret = FALSE;		break;	}	return ret;}static void handle_record(sdp_record_t *record, struct device *device){	gboolean is_default;	uint16_t uuid16;	uuid16 = get_service_uuid(record);	if (!server_is_enabled(uuid16))		return;	switch (uuid16) {	case HEADSET_SVCLASS_ID:		debug("Found Headset record");		if (device->headset)			headset_update(device, record, uuid16);		else			device->headset = headset_init(device,							enable_hfp,							record, uuid16);		break;	case HEADSET_AGW_SVCLASS_ID:		debug("Found Headset AG record");		break;	case HANDSFREE_SVCLASS_ID:		debug("Found Hansfree record");		if (device->headset)			headset_update(device, record, uuid16);		else			device->headset = headset_init(device,							enable_hfp,							record, uuid16);		break;	case HANDSFREE_AGW_SVCLASS_ID:		debug("Found Handsfree AG record");		break;	case AUDIO_SINK_SVCLASS_ID:		debug("Found Audio Sink");		if (device->sink == NULL)			device->sink = sink_init(device);		break;	case AUDIO_SOURCE_SVCLASS_ID:		debug("Found Audio Source");		break;	case AV_REMOTE_SVCLASS_ID:		debug("Found AV Remote");		if (device->control == NULL)			device->control = control_init(device);		if (device->sink && sink_is_active(device))			avrcp_connect(device);		break;	case AV_REMOTE_TARGET_SVCLASS_ID:		debug("Found AV Target");		if (device->control == NULL)			device->control = control_init(device);		if (device->sink && sink_is_active(device))			avrcp_connect(device);		break;	default:		debug("Unrecognized UUID: 0x%04X", uuid16);		break;	}	is_default = (default_dev == device) ? TRUE : FALSE;	device_store(device, is_default);}static void finish_sdp(struct audio_sdp_data *data, gboolean success){	const char *addr;	DBusMessage *reply = NULL;	DBusError derr;	debug("Audio service discovery completed with %s",			success ? "success" : "failure");	device_finish_sdp_transaction(data->device);	if (!success)		goto done;	if (!data->msg)		goto update;	dbus_error_init(&derr);	dbus_message_get_args(data->msg, &derr,				DBUS_TYPE_STRING, &addr,				DBUS_TYPE_INVALID);	if (dbus_error_is_set(&derr)) {		error("Unable to get message args");		success = FALSE;		error_failed(connection, data->msg, derr.message);		dbus_error_free(&derr);		goto done;	}	/* Return error if no audio related service records were found */	if (!data->records) {		debug("No audio audio related service records were found");		success = FALSE;		error_not_supported(connection, data->msg);		goto done;	}	reply = dbus_message_new_method_return(data->msg);	if (!reply) {		success = FALSE;		error_failed(connection, data->msg, "Out of memory");		goto done;	}update:	g_slist_foreach(data->records, (GFunc) handle_record, data->device);	if (!g_slist_find(devices, data->device))		add_device(data->device, TRUE);	if (reply) {		dbus_message_append_args(reply, DBUS_TYPE_STRING,					&data->device->path,					DBUS_TYPE_INVALID);		send_message_and_unref(connection, reply);	}done:	if (success) {		if (data->cb)			data->cb(data->device, data->cb_data);	} else {		if (data->cb)			data->cb(NULL, data->cb_data);		if (!g_slist_find(devices, data->device))			destroy_device(data->device);	}	if (data->msg)		dbus_message_unref(data->msg);	g_slist_foreach(data->handles, (GFunc) g_free, NULL);	g_slist_free(data->handles);	g_slist_foreach(data->records, (GFunc) sdp_record_free, NULL);	g_slist_free(data->records);	g_free(data);}static void get_record_reply(DBusPendingCall *call,				struct audio_sdp_data *data){	DBusMessage *reply;	DBusError derr;	uint8_t *array;	int array_len, record_len;	sdp_record_t *record;	reply = dbus_pending_call_steal_reply(call);	dbus_error_init(&derr);	if (dbus_set_error_from_message(&derr, reply)) {		/* FIXME : forward error message as is */		error("GetRemoteServiceRecord failed: %s", derr.message);		if (dbus_error_has_name(&derr,					"org.bluez.Error.ConnectionAttemptFailed"))			error_connection_attempt_failed(connection, data->msg,				EHOSTDOWN);		else			error_failed(connection, data->msg, derr.message);		dbus_error_free(&derr);		goto failed;	}	if (!dbus_message_get_args(reply, NULL,				DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &array, &array_len,				DBUS_TYPE_INVALID)) {		error_failed(connection, data->msg,				"Unable to get args from GetRecordReply");		goto failed;	}	record = sdp_extract_pdu(array, &record_len);	if (!record) {		error("Unable to extract service record from reply");		goto done;	}	if (record_len != array_len)		debug("warning: array len (%d) != record len (%d)",				array_len, record_len);	data->records = g_slist_append(data->records, record);done:	dbus_message_unref(reply);	if (data->handles)		get_next_record(data);	else		finish_sdp(data, TRUE);	return;failed:	if (reply)		dbus_message_unref(reply);	finish_sdp(data, FALSE);}static void get_next_record(struct audio_sdp_data *data){	DBusMessage *msg;	DBusPendingCall *pending;	char address[18], *ptr = address;	dbus_uint32_t *handle;	msg = dbus_message_new_method_call("org.bluez",						data->device->adapter_path,						"org.bluez.Adapter",						"GetRemoteServiceRecord");	if (!msg) {		error("Unable to allocate new method call");		error_out_of_memory(connection, data->msg);		finish_sdp(data, FALSE);		return;	}	handle = data->handles->data;	data->handles = g_slist_remove(data->handles, data->handles->data);	ba2str(&data->device->dst, address);	dbus_message_append_args(msg, DBUS_TYPE_STRING, &ptr,					DBUS_TYPE_UINT32, handle,					DBUS_TYPE_INVALID);	g_free(handle);	if (!dbus_connection_send_with_reply(connection, msg, &pending, -1)) {		error("Sending GetRemoteServiceRecord failed");		error_connection_attempt_failed(connection, data->msg, EIO);		finish_sdp(data, FALSE);		return;	}	dbus_pending_call_set_notify(pending,			(DBusPendingCallNotifyFunction) get_record_reply,			data, NULL);	dbus_pending_call_unref(pending);	dbus_message_unref(msg);}static GSList *find_handle(GSList *handles, dbus_uint32_t handle){	while (handles) {		if (*(dbus_uint32_t *) handles->data == handle)			return handles;		handles = handles->next;	}	return NULL;}static void get_handles_reply(DBusPendingCall *call,				struct audio_sdp_data *data){	DBusMessage *reply;	DBusError derr;	dbus_uint32_t *array = NULL;	int array_len, i;	reply = dbus_pending_call_steal_reply(call);	dbus_error_init(&derr);	if (dbus_set_error_from_message(&derr, reply)) {		/* FIXME : forward error message as is */		error("GetRemoteServiceHandles failed: %s", derr.message);		if (dbus_error_has_name(&derr,					"org.bluez.Error.ConnectionAttemptFailed"))			error_connection_attempt_failed(connection, data->msg, 						EHOSTDOWN);		else			error_failed(connection, data->msg, derr.message);		dbus_error_free(&derr);		goto failed;	}	if (!dbus_message_get_args(reply, NULL,				DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32,				&array, &array_len,				DBUS_TYPE_INVALID)) {		error_failed(connection, data->msg,				"Unable to get args from reply");		goto failed;	}	for (i = 0; i < array_len; i++) {		if (!find_handle(data->handles, array[i])) {			dbus_uint32_t *handle = g_new(dbus_uint32_t, 1);			*handle = array[i];			data->handles = g_slist_append(data->handles, handle);		}	}	data->state++;	switch (data->state) {	case ADVANCED_AUDIO:		get_handles(ADVANCED_AUDIO_UUID, data);		break;	case AV_REMOTE:		get_handles(AVRCP_REMOTE_UUID, data);		break;	default:		if (data->handles)			get_next_record(data);		else			finish_sdp(data, TRUE);	}	dbus_message_unref(reply);	return;failed:	dbus_message_unref(reply);	finish_sdp(data, FALSE);}static DBusHandlerResult get_handles(const char *uuid,					struct audio_sdp_data *data){	DBusPendingCall *pending;	char address[18];	const char *ptr = address;	DBusMessage *msg;	msg = dbus_message_new_method_call("org.bluez",						data->device->adapter_path,						"org.bluez.Adapter",						"GetRemoteServiceHandles");	if (!msg) {		error_failed(connection, data->msg,				"Could not create a new dbus message");		goto failed;	}	ba2str(&data->device->dst, address);	dbus_message_append_args(msg, DBUS_TYPE_STRING, &ptr,					DBUS_TYPE_STRING, &uuid,					DBUS_TYPE_INVALID);	if (!dbus_connection_send_with_reply(connection, msg, &pending, -1)) {		error_failed(connection, data->msg,				"Sending GetRemoteServiceHandles failed");		goto failed;	}	dbus_pending_call_set_notify(pending,			(DBusPendingCallNotifyFunction) get_handles_reply,			data, NULL);	dbus_pending_call_unref(pending);	dbus_message_unref(msg);	return DBUS_HANDLER_RESULT_HANDLED;

⌨️ 快捷键说明

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