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

📄 device.c

📁 Linux的蓝牙操作工具。配合bluez-lib使用
💻 C
字号:
/* * *  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 <errno.h>#include <unistd.h>#include <sys/stat.h>#include <netinet/in.h>#include <glib.h>#include <dbus/dbus.h>#include <bluetooth/bluetooth.h>#include <bluetooth/hci.h>#include <bluetooth/hci_lib.h>#include <bluetooth/sdp.h>#include <bluetooth/sdp_lib.h>#include "dbus.h"#include "dbus-helper.h"#include "logging.h"#include "textfile.h"#include "error.h"#include "ipc.h"#include "device.h"#include "avdtp.h"#include "control.h"#include "headset.h"#include "sink.h"static DBusHandlerResult device_get_address(DBusConnection *conn,						DBusMessage *msg, void *data){	struct device *device = data;	DBusMessage *reply;	char address[18], *ptr = address;	reply = dbus_message_new_method_return(msg);	if (!reply)		return DBUS_HANDLER_RESULT_NEED_MEMORY;	ba2str(&device->dst, address);	dbus_message_append_args(reply, DBUS_TYPE_STRING, &ptr,							DBUS_TYPE_INVALID);	return send_message_and_unref(conn, reply);}static char *get_dev_name(DBusConnection *conn, const char *adapter_path,				bdaddr_t *bda){	DBusMessage *msg, *reply;	DBusError derr;	const char *name;	char address[18], *addr_ptr = address, *ret;	msg = dbus_message_new_method_call("org.bluez", adapter_path,					"org.bluez.Adapter", "GetRemoteName");	if (!msg)		return NULL;	ba2str(bda, address);	dbus_message_append_args(msg, DBUS_TYPE_STRING, &addr_ptr,					DBUS_TYPE_INVALID);	dbus_error_init(&derr);	reply = dbus_connection_send_with_reply_and_block(conn, msg, -1,								&derr);	dbus_message_unref(msg);	if (dbus_error_is_set(&derr)) {		error("%s GetRemoteName(): %s", adapter_path, derr.message);		dbus_error_free(&derr);		return NULL;	}	if (!dbus_message_get_args(reply, NULL,					DBUS_TYPE_STRING, &name,					DBUS_TYPE_INVALID))		return NULL;	ret = g_strdup(name);	dbus_message_unref(reply);	return ret;}static DBusHandlerResult device_get_name(DBusConnection *conn,						DBusMessage *msg, void *data){	struct device *dev = data;	DBusMessage *reply;	const char *name = dev->name ? dev->name : "";	reply = dbus_message_new_method_return(msg);	if (!reply)		return DBUS_HANDLER_RESULT_NEED_MEMORY;	dbus_message_append_args(reply, DBUS_TYPE_STRING, &name,					DBUS_TYPE_INVALID);	return send_message_and_unref(conn, reply);}static DBusHandlerResult device_get_adapter(DBusConnection *conn,						DBusMessage *msg, void *data){	struct device *device = data;	DBusMessage *reply;	char address[18], *ptr = address;	reply = dbus_message_new_method_return(msg);	if (!reply)		return DBUS_HANDLER_RESULT_NEED_MEMORY;	ba2str(&device->src, address);	dbus_message_append_args(reply, DBUS_TYPE_STRING, &ptr,							DBUS_TYPE_INVALID);	return send_message_and_unref(conn, reply);}static DBusHandlerResult device_get_connected(DBusConnection *conn,						DBusMessage *msg, void *data){	DBusMessageIter iter, array_iter;	struct device *device = data;	DBusMessage *reply;	const char *iface;	reply = dbus_message_new_method_return(msg);	if (!reply)		return DBUS_HANDLER_RESULT_NEED_MEMORY;	dbus_message_iter_init_append(reply, &iter);	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,						DBUS_TYPE_STRING_AS_STRING,						&array_iter);	if (device->headset &&			headset_get_state(device) >= HEADSET_STATE_CONNECTED) {		iface = AUDIO_HEADSET_INTERFACE;		dbus_message_iter_append_basic(&array_iter,						DBUS_TYPE_STRING, &iface);	}	dbus_message_iter_close_container(&iter, &array_iter);	return send_message_and_unref(conn, reply);}static DBusMethodVTable device_methods[] = {	{ "GetAddress",			device_get_address,	"",	"s" },	{ "GetName",			device_get_name,	"",	"s" },	{ "GetAdapter",			device_get_adapter,	"",	"s" },	{ "GetConnectedInterfaces",	device_get_connected,	"",	"as" },	{ NULL, NULL, NULL, NULL }};static void device_free(struct device *dev){	if (dev->headset)		headset_free(dev);	if (dev->sink)		sink_free(dev);	if (dev->control)		control_free(dev);	if (dev->conn)		dbus_connection_unref(dev->conn);	g_free(dev->adapter_path);	g_free(dev->path);	g_free(dev->name);	g_free(dev);}static void device_unregister(DBusConnection *conn, void *data){	struct device *device = data;	info("Unregistered device path:%s", device->path);	device_free(device);}char *find_adapter(DBusConnection *conn, bdaddr_t *src){	DBusMessage *msg, *reply;	DBusError derr;	char address[18], *addr_ptr = address;	char *path, *ret;	msg = dbus_message_new_method_call("org.bluez", "/org/bluez",						"org.bluez.Manager",						"FindAdapter");	if (!msg) {		error("Unable to allocate new method call");		return NULL;	}	ba2str(src, address);	dbus_message_append_args(msg, DBUS_TYPE_STRING, &addr_ptr,				 DBUS_TYPE_INVALID);	dbus_error_init(&derr);	reply = dbus_connection_send_with_reply_and_block(conn, msg, -1,								&derr);	dbus_message_unref(msg);	if (dbus_error_is_set(&derr) ||				dbus_set_error_from_message(&derr, reply)) {		error("FindAdapter(%s) failed: %s", address, derr.message);		dbus_error_free(&derr);		return NULL;	}	dbus_error_init(&derr);	dbus_message_get_args(reply, &derr,				DBUS_TYPE_STRING, &path,				DBUS_TYPE_INVALID);	if (dbus_error_is_set(&derr)) {		error("Unable to get message args");		dbus_message_unref(reply);		dbus_error_free(&derr);		return FALSE;	}	ret = g_strdup(path);	dbus_message_unref(reply);	debug("Got path %s for adapter with address %s", ret, address);	return ret;}struct device *device_register(DBusConnection *conn,					const char *path, bdaddr_t *bda){	struct device *dev;	bdaddr_t src;	int dev_id;	if (!conn || !path)		return NULL;	bacpy(&src, BDADDR_ANY);	dev_id = hci_get_route(&src);	if ((dev_id < 0) || (hci_devba(dev_id, &src) < 0))		return NULL;	dev = g_new0(struct device, 1);	dev->adapter_path = find_adapter(conn, &src);	if (!dev->adapter_path) {		device_free(dev);		return NULL;	}	if (!dbus_connection_create_object_path(conn, path, dev,							device_unregister)) {		error("D-Bus failed to register %s path", path);		device_free(dev);		return NULL;	}	if (!dbus_connection_register_interface(conn, path,			AUDIO_DEVICE_INTERFACE, device_methods, NULL, NULL)) {		error("Failed to register %s interface to %s",					AUDIO_DEVICE_INTERFACE, path);		dbus_connection_destroy_object_path(conn, path);		return NULL;	}	dev->name = get_dev_name(conn, dev->adapter_path, bda);	dev->path = g_strdup(path);	bacpy(&dev->dst, bda);	bacpy(&dev->src, &src);	bacpy(&dev->store, &src);	dev->conn = dbus_connection_ref(conn);	return dev;}int device_store(struct device *dev, gboolean is_default){	char value[64];	char filename[PATH_MAX + 1];	char src_addr[18], dst_addr[18];	int offset = 0;	if (!dev->path)		return -EINVAL;	ba2str(&dev->dst, dst_addr);	ba2str(&dev->store, src_addr);	create_name(filename, PATH_MAX, STORAGEDIR, src_addr, "audio");	create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);	if (is_default)		textfile_put(filename, "default", dst_addr);	if (dev->headset) {		snprintf(value, 64, "headset ");		offset += strlen("headset ");	}	if (dev->gateway) {		snprintf(value + offset, 64 - offset, "gateway ");		offset += strlen("gateway ");	}	if (dev->sink) {		snprintf(value + offset, 64 - offset, "sink ");		offset += strlen("sink ");	}	if (dev->source) {		snprintf(value + offset, 64 - offset, "source ");		offset += strlen("source ");	}	if (dev->control) {		snprintf(value + offset, 64 - offset, "control ");		offset += strlen("control ");	}	if (dev->target)		snprintf(value + offset, 64 - offset, "target");	return textfile_put(filename, dst_addr, value);}int device_remove_stored(struct device *dev){	char filename[PATH_MAX + 1];	char src_addr[18], dst_addr[18];	ba2str(&dev->dst, dst_addr);	ba2str(&dev->store, src_addr);	create_name(filename, PATH_MAX, STORAGEDIR, src_addr, "audio");	return textfile_del(filename, dst_addr);}void device_finish_sdp_transaction(struct device *dev){	char address[18], *addr_ptr = address;	DBusMessage *msg, *reply;	DBusError derr;	ba2str(&dev->dst, address);	msg = dbus_message_new_method_call("org.bluez", dev->adapter_path,						"org.bluez.Adapter",						"FinishRemoteServiceTransaction");	if (!msg) {		error("Unable to allocate new method call");		return;	}	dbus_message_append_args(msg, DBUS_TYPE_STRING, &addr_ptr,				 DBUS_TYPE_INVALID);	dbus_error_init(&derr);	reply = dbus_connection_send_with_reply_and_block(dev->conn,							msg, -1, &derr);	dbus_message_unref(msg);	if (dbus_error_is_set(&derr) ||				dbus_set_error_from_message(&derr, reply)) {		error("FinishRemoteServiceTransaction(%s) failed: %s",						address, derr.message);		dbus_error_free(&derr);		return;	}	dbus_message_unref(reply);}#if 0static avdtp_state_t ipc_to_avdtp_state(uint8_t ipc_state){	switch (ipc_state) {	case STATE_DISCONNECTED:		return AVDTP_STATE_IDLE;	case STATE_CONNECTING:		return AVDTP_STATE_CONFIGURED;	case STATE_CONNECTED:		return AVDTP_STATE_OPEN;	case STATE_STREAM_STARTING:	case STATE_STREAMING:		return AVDTP_STATE_STREAMING;	default:		error("Unknown ipc state");		return AVDTP_STATE_IDLE;	}}static headset_state_t ipc_to_hs_state(uint8_t ipc_state){	switch (ipc_state) {	case STATE_DISCONNECTED:		return HEADSET_STATE_DISCONNECTED;	case STATE_CONNECTING:		return HEADSET_STATE_CONNECT_IN_PROGRESS;	case STATE_CONNECTED:		return HEADSET_STATE_CONNECTED;	case STATE_STREAM_STARTING:		return HEADSET_STATE_PLAY_IN_PROGRESS;	case STATE_STREAMING:		return HEADSET_STATE_PLAYING;	default:		error("Unknown ipc state");		return HEADSET_STATE_DISCONNECTED;	}}static uint8_t avdtp_to_ipc_state(avdtp_state_t state){	switch (state) {	case AVDTP_STATE_IDLE:		return STATE_DISCONNECTED;	case AVDTP_STATE_CONFIGURED:		return STATE_CONNECTING;	case AVDTP_STATE_OPEN:		return STATE_CONNECTED;	case AVDTP_STATE_STREAMING:		return STATE_STREAMING;	default:		error("Unknown avdt state");		return AVDTP_STATE_IDLE;	}}static uint8_t hs_to_ipc_state(headset_state_t state){	switch (state) {	case HEADSET_STATE_DISCONNECTED:		return STATE_DISCONNECTED;	case HEADSET_STATE_CONNECT_IN_PROGRESS:		return STATE_CONNECTING;	case HEADSET_STATE_CONNECTED:		return STATE_CONNECTED;	case HEADSET_STATE_PLAY_IN_PROGRESS:		return STATE_STREAMING;	default:		error("Unknown headset state");		return AVDTP_STATE_IDLE;	}}uint8_t device_get_state(struct device *dev){	avdtp_state_t sink_state;	headset_state_t hs_state;	if (dev->sink && sink_is_active(dev)) {		sink_state = sink_get_state(dev);		return avdtp_to_ipc_state(sink_state);	}	else if (dev->headset && headset_is_active(dev)) {		hs_state = headset_get_state(dev);		return hs_to_ipc_state(hs_state);	}	else if (dev->control && control_is_active(dev))		return STATE_CONNECTED;	return STATE_DISCONNECTED;}#endifgboolean device_is_connected(struct device *dev, const char *interface){	if (!interface) {		if ((dev->sink || dev->source) &&			avdtp_is_connected(&dev->src, &dev->dst))			return TRUE;		if (dev->headset && headset_is_active(dev))			return TRUE;	}	else if (!strcmp(interface, AUDIO_SINK_INTERFACE) && dev->sink &&			avdtp_is_connected(&dev->src, &dev->dst))		return TRUE;	else if (!strcmp(interface, AUDIO_SOURCE_INTERFACE) && dev->source &&			avdtp_is_connected(&dev->src, &dev->dst))		return TRUE;	else if (!strcmp(interface, AUDIO_HEADSET_INTERFACE) && dev->headset &&			headset_is_active(dev))		return TRUE;	else if (!strcmp(interface, AUDIO_CONTROL_INTERFACE) && dev->headset &&			control_is_active(dev))		return TRUE;	return FALSE;}

⌨️ 快捷键说明

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