📄 control.c
字号:
/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2007 Nokia Corporation * Copyright (C) 2004-2008 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 <bluetooth/bluetooth.h>#include <bluetooth/sdp.h>#include <bluetooth/sdp_lib.h>#include <bluetooth/l2cap.h>#include <glib.h>#include <dbus/dbus.h>#include <gdbus.h>#include "dbus-service.h"#include "logging.h"#include "uinput.h"#include "device.h"#include "manager.h"#include "avdtp.h"#include "control.h"#include "sdpd.h"#include "glib-helper.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 audio_device *dev; avctp_state_t state; bdaddr_t src; bdaddr_t dst; int uinput; int sock; guint io; uint16_t mtu;};struct control { struct avctp *session;};static sdp_record_t *avrcp_ct_record(){ 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; record = sdp_record_alloc(); if (!record) return NULL; 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); 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); return record;}static sdp_record_t *avrcp_tg_record(){ 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; record = sdp_record_alloc(); if (!record) return NULL; 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); 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); return record;}static struct avctp *find_session(const bdaddr_t *src, const 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 struct avctp *avctp_get(const bdaddr_t *src, const bdaddr_t *dst){ struct avctp *session; assert(src != NULL); assert(dst != NULL); session = find_session(src, dst); if (session) 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 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; } switch (operands[0] & 0x7F) { case PLAY_OP: debug("AVRCP: PLAY %s", status); send_key(session->uinput, KEY_PLAYPAUSE, pressed); break; case STOP_OP: debug("AVRCP: STOP %s", status); send_key(session->uinput, KEY_STOP, pressed); break; case PAUSE_OP: debug("AVRCP: PAUSE %s", status); send_key(session->uinput, KEY_PLAYPAUSE, pressed); break; case NEXT_OP: debug("AVRCP: NEXT %s", status); send_key(session->uinput, KEY_NEXTSONG, pressed); break; case PREV_OP: debug("AVRCP: PREV %s", status); send_key(session->uinput, KEY_PREVIOUSSONG, pressed); break; case REWIND_OP: debug("AVRCP: REWIND %s", status); send_key(session->uinput, KEY_REWIND, pressed); break; case FAST_FORWARD_OP: debug("AVRCP: FAST FORWARD %s", status); send_key(session->uinput, KEY_FORWARD, pressed); break; default: debug("AVRCP: unknown button 0x%02X %s", operands[0] & 0x7F, status); break; }}static void avctp_unref(struct avctp *session){ sessions = g_slist_remove(sessions, session); if (session->state == AVCTP_STATE_CONNECTED) g_dbus_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); if (session->dev) session->dev->control->session = NULL; if (session->uinput >= 0) { ioctl(session->uinput, UI_DEV_DESTROY); close(session->uinput); } g_free(session);}static gboolean session_cb(GIOChannel *chan, GIOCondition cond, gpointer data){ struct avctp *session = data; unsigned char buf[1024], *operands; struct avctp_header *avctp; struct avrcp_header *avrcp; int ret, packet_size, operand_count; if (!(cond | G_IO_IN)) goto failed; ret = read(session->sock, buf, sizeof(buf)); if (ret <= 0) goto failed; debug("Got %d bytes of data for AVCTP session %p", ret, session); if (ret < sizeof(struct avctp_header)) { error("Too small AVCTP packet"); goto failed; } packet_size = ret; avctp = (struct avctp_header *) buf; debug("AVCTP transaction %u, packet type %u, C/R %u, IPID %u, " "PID 0x%04X", avctp->transaction, avctp->packet_type, avctp->cr, avctp->ipid, ntohs(avctp->pid)); ret -= sizeof(struct avctp_header); if (ret < sizeof(struct avrcp_header)) { error("Too small AVRCP packet"); goto failed; } avrcp = (struct avrcp_header *) (buf + sizeof(struct avctp_header)); ret -= sizeof(struct avrcp_header); operands = buf + sizeof(struct avctp_header) + sizeof(struct avrcp_header); operand_count = ret; debug("AVRCP %s 0x%01X, subunit_type 0x%02X, subunit_id 0x%01X, " "opcode 0x%02X, %d operands",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -