📄 control.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 <stdlib.h>#include <stdint.h>#include <errno.h>#include <unistd.h>#include <assert.h>#include <signal.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <netinet/in.h>#include <glib.h>#include <dbus/dbus.h>#include <bluetooth/bluetooth.h>#include <bluetooth/sdp.h>#include <bluetooth/sdp_lib.h>#include <bluetooth/l2cap.h>#include "dbus.h"#include "dbus-helper.h"#include "logging.h"#include "uinput.h"#include "device.h"#include "manager.h"#include "avdtp.h"#include "control.h"#define AVCTP_PSM 23/* Message types */#define AVCTP_COMMAND 0#define AVCTP_RESPONSE 1/* Packet types */#define AVCTP_PACKET_SINGLE 0#define AVCTP_PACKET_START 1#define AVCTP_PACKET_CONTINUE 2#define AVCTP_PACKET_END 3/* ctype entries */#define CTYPE_CONTROL 0x0#define CTYPE_STATUS 0x1#define CTYPE_ACCEPTED 0x9#define CTYPE_STABLE 0xC/* opcodes */#define OP_UNITINFO 0x30#define OP_SUBUNITINFO 0x31#define OP_PASSTHROUGH 0x7c/* subunits of interest */#define SUBUNIT_PANEL 0x09/* operands in passthrough commands */#define VOLUP_OP 0x41#define VOLDOWN_OP 0x42#define MUTE_OP 0x43#define PLAY_OP 0x44#define STOP_OP 0x45#define PAUSE_OP 0x46#define REWIND_OP 0x48#define FAST_FORWARD_OP 0x49#define NEXT_OP 0x4b#define PREV_OP 0x4cstatic DBusConnection *connection = NULL;static uint32_t tg_record_id = 0;static uint32_t ct_record_id = 0;static GIOChannel *avctp_server = NULL;static GSList *sessions = NULL;typedef enum { AVCTP_STATE_DISCONNECTED = 0, AVCTP_STATE_CONNECTING, AVCTP_STATE_CONNECTED} avctp_state_t;#if __BYTE_ORDER == __LITTLE_ENDIANstruct avctp_header { uint8_t ipid:1; uint8_t cr:1; uint8_t packet_type:2; uint8_t transaction:4; uint16_t pid;} __attribute__ ((packed));struct avrcp_header { uint8_t code:4; uint8_t _hdr0:4; uint8_t subunit_id:3; uint8_t subunit_type:5; uint8_t opcode;} __attribute__ ((packed));#elif __BYTE_ORDER == __BIG_ENDIANstruct avctp_header { uint8_t transaction:4; uint8_t packet_type:2; uint8_t cr:1; uint8_t ipid:1; uint16_t pid;} __attribute__ ((packed));struct avrcp_header { uint8_t _hdr0:4; uint8_t code:4; uint8_t subunit_type:5; uint8_t subunit_id:3; uint8_t opcode;} __attribute__ ((packed));#else#error "Unknown byte order"#endifstruct avctp { struct device *dev; avctp_state_t state; bdaddr_t src; bdaddr_t dst; int uinput; int sock; guint io; uint16_t mtu; DBusPendingCall *pending_auth;};struct control { struct avctp *session;};static int avrcp_ct_record(sdp_buf_t *buf){ sdp_list_t *svclass_id, *pfseq, *apseq, *root; uuid_t root_uuid, l2cap, avctp, avrct; sdp_profile_desc_t profile[1]; sdp_list_t *aproto, *proto[2]; sdp_record_t record; sdp_data_t *psm, *version, *features; uint16_t lp = AVCTP_PSM, ver = 0x0103, feat = 0x000f; int ret = 0; memset(&record, 0, sizeof(sdp_record_t)); sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP); root = sdp_list_append(0, &root_uuid); sdp_set_browse_groups(&record, root); /* Service Class ID List */ sdp_uuid16_create(&avrct, AV_REMOTE_SVCLASS_ID); svclass_id = sdp_list_append(0, &avrct); sdp_set_service_classes(&record, svclass_id); /* Protocol Descriptor List */ sdp_uuid16_create(&l2cap, L2CAP_UUID); proto[0] = sdp_list_append(0, &l2cap); psm = sdp_data_alloc(SDP_UINT16, &lp); proto[0] = sdp_list_append(proto[0], psm); apseq = sdp_list_append(0, proto[0]); sdp_uuid16_create(&avctp, AVCTP_UUID); proto[1] = sdp_list_append(0, &avctp); version = sdp_data_alloc(SDP_UINT16, &ver); proto[1] = sdp_list_append(proto[1], version); apseq = sdp_list_append(apseq, proto[1]); aproto = sdp_list_append(0, apseq); sdp_set_access_protos(&record, aproto); /* Bluetooth Profile Descriptor List */ sdp_uuid16_create(&profile[0].uuid, AV_REMOTE_PROFILE_ID); profile[0].version = ver; pfseq = sdp_list_append(0, &profile[0]); sdp_set_profile_descs(&record, pfseq); features = sdp_data_alloc(SDP_UINT16, &feat); sdp_attr_add(&record, SDP_ATTR_SUPPORTED_FEATURES, features); sdp_set_info_attr(&record, "AVRCP CT", 0, 0); if (sdp_gen_record_pdu(&record, buf) < 0) ret = -1; else ret = 0; free(psm); free(version); sdp_list_free(proto[0], 0); sdp_list_free(proto[1], 0); sdp_list_free(apseq, 0); sdp_list_free(pfseq, 0); sdp_list_free(aproto, 0); sdp_list_free(root, 0); sdp_list_free(svclass_id, 0); sdp_list_free(record.attrlist, (sdp_free_func_t) sdp_data_free); sdp_list_free(record.pattern, free); return ret;}static int avrcp_tg_record(sdp_buf_t *buf){ sdp_list_t *svclass_id, *pfseq, *apseq, *root; uuid_t root_uuid, l2cap, avctp, avrtg; sdp_profile_desc_t profile[1]; sdp_list_t *aproto, *proto[2]; sdp_record_t record; sdp_data_t *psm, *version, *features; uint16_t lp = AVCTP_PSM, ver = 0x0103, feat = 0x000f; int ret = 0; memset(&record, 0, sizeof(sdp_record_t)); sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP); root = sdp_list_append(0, &root_uuid); sdp_set_browse_groups(&record, root); /* Service Class ID List */ sdp_uuid16_create(&avrtg, AV_REMOTE_TARGET_SVCLASS_ID); svclass_id = sdp_list_append(0, &avrtg); sdp_set_service_classes(&record, svclass_id); /* Protocol Descriptor List */ sdp_uuid16_create(&l2cap, L2CAP_UUID); proto[0] = sdp_list_append(0, &l2cap); psm = sdp_data_alloc(SDP_UINT16, &lp); proto[0] = sdp_list_append(proto[0], psm); apseq = sdp_list_append(0, proto[0]); sdp_uuid16_create(&avctp, AVCTP_UUID); proto[1] = sdp_list_append(0, &avctp); version = sdp_data_alloc(SDP_UINT16, &ver); proto[1] = sdp_list_append(proto[1], version); apseq = sdp_list_append(apseq, proto[1]); aproto = sdp_list_append(0, apseq); sdp_set_access_protos(&record, aproto); /* Bluetooth Profile Descriptor List */ sdp_uuid16_create(&profile[0].uuid, AV_REMOTE_PROFILE_ID); profile[0].version = ver; pfseq = sdp_list_append(0, &profile[0]); sdp_set_profile_descs(&record, pfseq); features = sdp_data_alloc(SDP_UINT16, &feat); sdp_attr_add(&record, SDP_ATTR_SUPPORTED_FEATURES, features); sdp_set_info_attr(&record, "AVRCP TG", 0, 0); if (sdp_gen_record_pdu(&record, buf) < 0) ret = -1; else ret = 0; free(psm); free(version); sdp_list_free(proto[0], 0); sdp_list_free(proto[1], 0); sdp_list_free(apseq, 0); sdp_list_free(aproto, 0); sdp_list_free(pfseq, 0); sdp_list_free(root, 0); sdp_list_free(svclass_id, 0); sdp_list_free(record.attrlist, (sdp_free_func_t) sdp_data_free); sdp_list_free(record.pattern, free); return ret;}static GIOChannel *avctp_server_socket(void){ int sock, lm; struct sockaddr_l2 addr; GIOChannel *io; sock = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP); if (sock < 0) { error("AVCTP server socket: %s (%d)", strerror(errno), errno); return NULL; } lm = L2CAP_LM_SECURE; if (setsockopt(sock, SOL_L2CAP, L2CAP_LM, &lm, sizeof(lm)) < 0) { error("AVCTP server setsockopt: %s (%d)", strerror(errno), errno); close(sock); return NULL; } memset(&addr, 0, sizeof(addr)); addr.l2_family = AF_BLUETOOTH; bacpy(&addr.l2_bdaddr, BDADDR_ANY); addr.l2_psm = htobs(AVCTP_PSM); if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { error("AVCTP server bind: %s", strerror(errno), errno); close(sock); return NULL; } if (listen(sock, 4) < 0) { error("AVCTP server listen: %s", strerror(errno), errno); close(sock); return NULL; } io = g_io_channel_unix_new(sock); if (!io) { error("Unable to allocate new io channel"); close(sock); return NULL; } return io;}static struct avctp *find_session(bdaddr_t *src, bdaddr_t *dst){ GSList *l; for (l = sessions; l != NULL; l = g_slist_next(l)) { struct avctp *s = l->data; if (bacmp(src, &s->src) || bacmp(dst, &s->dst)) continue; return s; } return NULL;}static void avctp_unref(struct avctp *session){ sessions = g_slist_remove(sessions, session); if (session->pending_auth) { manager_cancel_authorize(&session->dst, AVRCP_TARGET_UUID, NULL); dbus_pending_call_cancel(session->pending_auth); dbus_pending_call_unref(session->pending_auth); } if (session->state == AVCTP_STATE_CONNECTED) dbus_connection_emit_signal(session->dev->conn, session->dev->path, AUDIO_CONTROL_INTERFACE, "Disconnected", DBUS_TYPE_INVALID); if (session->sock >= 0) close(session->sock); if (session->io) g_source_remove(session->io); session->dev->control->session = NULL; if (session->uinput >= 0) { ioctl(session->uinput, UI_DEV_DESTROY); close(session->uinput); } g_free(session);}static int uinput_create(char *name){ struct uinput_dev dev; int fd, err; fd = open("/dev/uinput", O_RDWR); if (fd < 0) { fd = open("/dev/input/uinput", O_RDWR); if (fd < 0) { fd = open("/dev/misc/uinput", O_RDWR); if (fd < 0) { err = errno; error("Can't open input device: %s (%d)", strerror(err), err); return -err; } } } memset(&dev, 0, sizeof(dev)); if (name) strncpy(dev.name, name, UINPUT_MAX_NAME_SIZE); dev.id.bustype = BUS_BLUETOOTH; dev.id.vendor = 0x0000; dev.id.product = 0x0000; dev.id.version = 0x0000; if (write(fd, &dev, sizeof(dev)) < 0) { err = errno; error("Can't write device information: %s (%d)", strerror(err), err); close(fd); errno = err; return -err; } ioctl(fd, UI_SET_EVBIT, EV_KEY); ioctl(fd, UI_SET_EVBIT, EV_REL); ioctl(fd, UI_SET_EVBIT, EV_REP); ioctl(fd, UI_SET_EVBIT, EV_SYN); ioctl(fd, UI_SET_KEYBIT, KEY_PLAYPAUSE); ioctl(fd, UI_SET_KEYBIT, KEY_STOP); ioctl(fd, UI_SET_KEYBIT, KEY_NEXTSONG); ioctl(fd, UI_SET_KEYBIT, KEY_PREVIOUSSONG); ioctl(fd, UI_SET_KEYBIT, KEY_REWIND); ioctl(fd, UI_SET_KEYBIT, KEY_FORWARD); if (ioctl(fd, UI_DEV_CREATE, NULL) < 0) { err = errno; error("Can't create uinput device: %s (%d)", strerror(err), err); close(fd); errno = err; return -err; } return fd;}static struct avctp *avctp_get(bdaddr_t *src, bdaddr_t *dst){ struct avctp *session; assert(src != NULL); assert(dst != NULL); session = find_session(src, dst); if (session) { if (session->pending_auth) return NULL; else return session; } session = g_new0(struct avctp, 1); session->uinput = -1; session->sock = -1; bacpy(&session->src, src); bacpy(&session->dst, dst); sessions = g_slist_append(sessions, session); return session;}static void init_uinput(struct avctp *session){ char address[18], *name; ba2str(&session->dst, address); name = session->dev->name ? session->dev->name : address; session->uinput = uinput_create(name); if (session->uinput < 0) error("AVRCP: failed to init uinput for %s", name); else debug("AVRCP: uinput initialized for %s", name);}static int send_event(int fd, uint16_t type, uint16_t code, int32_t value){ struct uinput_event event; memset(&event, 0, sizeof(event)); event.type = type; event.code = code; event.value = value; return write(fd, &event, sizeof(event));}static void send_key(int fd, uint16_t key, int pressed){ if (fd < 0) return; send_event(fd, EV_KEY, key, pressed); send_event(fd, EV_SYN, SYN_REPORT, 0);}static void handle_panel_passthrough(struct avctp *session, const unsigned char *operands, int operand_count){ const char *status; int pressed; if (operand_count == 0) return; if (operands[0] & 0x80) { status = "released"; pressed = 0; } else { status = "pressed"; pressed = 1; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -