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

📄 a2play.c

📁 蓝牙blue tooth sco协议栈
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * a2play.c * experimenting with sending a2dp audio to a headset * Brad Midgley *  *   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA * */ #ifdef HAVE_CONFIG_H#include <config.h>#endif#include <stdio.h>#include <errno.h>#include <fcntl.h>#include <unistd.h>#include <stdlib.h>#include <getopt.h>#include <signal.h>#include <string.h>#include <sys/socket.h>#include <bluetooth/bluetooth.h>#include <bluetooth/hci.h>#include <bluetooth/hci_lib.h>#include <bluetooth/l2cap.h>#include <bluetooth/sdp.h>#include <bluetooth/sdp_lib.h>#include <netinet/in.h>/* AVDTP structures *//* packet components */struct avdtp_header {	uint8_t packet_type:2;	uint8_t message_type:2;	uint8_t transaction_label:4;	uint8_t signal_id:6;	uint8_t rfa0:2;} __attribute__ ((packed));struct acp_seid_info {	uint8_t rfa0:1;	uint8_t inuse0:1;	uint8_t acp_seid:6;	uint8_t rfa2:3;	uint8_t tsep:1;	uint8_t media_type:4;} __attribute__ ((packed));struct sbc_codec_specific_elements {	// a2dp p. 20	uint8_t channel_mode:4;	uint8_t frequency:4;	uint8_t allocation_method:2;	uint8_t subbands:2;	uint8_t block_length:4;	uint8_t min_bitpool;	uint8_t max_bitpool;} __attribute__ ((packed));#define MAX_ADDITIONAL_CODEC 4#define MAX_ADDITIONAL_CODEC_OCTETS (MAX_ADDITIONAL_CODEC*sizeof(struct acp_seid_info))/* packets */struct sepd_req {	struct avdtp_header header;} __attribute__ ((packed));struct sepd_resp {	struct avdtp_header header;	struct acp_seid_info infos[1 + MAX_ADDITIONAL_CODEC];} __attribute__ ((packed));struct getcap_req {	struct avdtp_header header;	uint8_t rfa1:2;	uint8_t acp_seid:6;} __attribute__ ((packed));struct getcap_resp {	struct avdtp_header header;	uint8_t serv_cap;	uint8_t serv_cap_len;	uint8_t cap_type;	uint8_t length;	uint8_t media_type;	uint8_t media_codec_type;	struct sbc_codec_specific_elements sbc_elements;} __attribute__ ((packed));struct set_config {	struct avdtp_header header;	uint8_t rfa0:2;	uint8_t acp_seid:6;	uint8_t rfa1:2;	uint8_t int_seid:6;	uint8_t serv_cap;	uint8_t serv_cap_len;	uint8_t cap_type;	uint8_t length;	uint8_t media_type;	uint8_t media_codec_type;	struct sbc_codec_specific_elements sbc_elements;} __attribute__ ((packed));struct set_config_resp {	struct avdtp_header header;	// only present for an error	uint8_t serv_cat;	uint8_t error_code;} __attribute__ ((packed));struct open_stream_cmd {	struct avdtp_header header;	uint8_t rfa0:2;	uint8_t acp_seid:6;} __attribute__ ((packed));struct open_stream_rsp {	struct avdtp_header header;	// only present for an error	uint8_t error;} __attribute__ ((packed));struct start_stream_cmd {	struct avdtp_header header;	uint8_t rfa0:2;	uint8_t acp_seid:6;} __attribute__ ((packed));struct start_stream_rsp {	struct avdtp_header header;	// only present for an error	uint8_t rfa0:2;	uint8_t acp_seid:6;	uint8_t error;} __attribute__ ((packed));struct close_stream_cmd {	struct avdtp_header header;	uint8_t rfa0:2;	uint8_t acp_seid:6;} __attribute__ ((packed));struct close_stream_rsp {	struct avdtp_header header;	// only present for an error	uint8_t error;} __attribute__ ((packed));// this is an rtp, not bluetooth header, so values are big endianstruct media_packet_header {	uint8_t cc:4;	uint8_t x:1;	uint8_t p:1;	uint8_t v:2;	uint8_t pt:7;	uint8_t m:1;	uint16_t sequence_number;	uint32_t timestamp;	uint32_t ssrc;	uint32_t csrc[0];} __attribute__ ((packed));struct media_payload_header {	uint8_t frame_count:4;	uint8_t rfa0:1;	uint8_t is_last_fragment:1;	uint8_t is_first_fragment:1;	uint8_t is_fragmented:1;} __attribute__ ((packed));// SBC file format headerstruct sbc_frame_header {	uint8_t syncword:8;	/* Sync word */	uint8_t subbands:1;	/* Subbands */	uint8_t allocation_method:1;	/* Allocation method */	uint8_t channel_mode:2;	/* Channel mode */	uint8_t blocks:2;	/* Blocks */	uint8_t sampling_frequency:2;	/* Sampling frequency */	uint8_t bitpool:8;	/* Bitpool */	uint8_t crc_check:8;	/* CRC check */} __attribute__ ((packed));#define AVDTP_DISCOVER 1#define AVDTP_GET_CAPABILITIES 2#define AVDTP_SET_CONFIGURATION 3#define AVDTP_OPEN 6#define AVDTP_START 7#define AVDTP_CLOSE 8#define MEDIA_TRANSPORT_CATEGORY 1#define MEDIA_CODEC 7#define SBC_MEDIA_CODEC_TYPE 0#define AUDIO_MEDIA_TYPE 0#define PACKET_TYPE_SINGLE 0#define PACKET_TYPE_START 1#define PACKET_TYPE_CONTINUE 2#define PACKET_TYPE_END 3#define MESSAGE_TYPE_COMMAND 0#define MESSAGE_TYPE_ACCEPT 2#define MESSAGE_TYPE_REJECT 3#define BUFS 1024#define MEDIA_PACKET_HEADER_LENGTH 14#define NONSPECAUDIO 1static volatile int terminate = 0;static int cmdfd;static struct sbc_frame_header sbc_info;static void sig_term(int sig){	terminate = 1;}static void usage(){	fprintf(stderr, "use: a2play <bdaddr> <filename>\n");}static int detect_a2dp(bdaddr_t *src, bdaddr_t *dst, unsigned short *psm, unsigned long *flags){	sdp_session_t *sess;	sdp_list_t *attrid, *search, *seq, *next;	sdp_data_t *pdlist;	uuid_t group;	uint32_t range = 0x0000ffff;	int err;	sess = sdp_connect(src, dst, SDP_RETRY_IF_BUSY);	if (!sess) {		printf("Failed to connect to SDP server: %s\n", strerror(errno));		return -1;	}	/* 0x1108->all? 0x1101->rf sink 0x111e->handsfree 0x1108->headset */	sdp_uuid16_create(&group, 0x110d);	search = sdp_list_append(0, &group);	attrid = sdp_list_append(0, &range);	err = sdp_service_search_attr_req(sess, search,					SDP_ATTR_REQ_RANGE, attrid, &seq);	sdp_list_free(search, 0);	sdp_list_free(attrid, 0);	if (err) {		printf("Service Search failed: %s\n", strerror(errno));		sdp_close(sess);		return -1;	}	for (; seq; seq = next) {		sdp_record_t *rec = (sdp_record_t *) seq->data;		printf("Found A2DP Sink\n");		if (psm)			*psm = 25;		next = seq->next;		free(seq);		sdp_record_free(rec);	}	sdp_uuid16_create(&group, PNP_INFO_SVCLASS_ID);	search = sdp_list_append(0, &group);	attrid = sdp_list_append(0, &range);	err = sdp_service_search_attr_req(sess, search,					SDP_ATTR_REQ_RANGE, attrid, &seq);	sdp_list_free(search, 0);	sdp_list_free(attrid, 0);	if (err)		goto done;	if (flags)		*flags = 0;	for (; seq; seq = next) {		sdp_record_t *rec = (sdp_record_t *) seq->data;		uint16_t vendor, product, version;		pdlist = sdp_data_get(rec, 0x0201);		vendor = pdlist ? pdlist->val.uint16 : 0x0000;		pdlist = sdp_data_get(rec, 0x0202);		product = pdlist ? pdlist->val.uint16 : 0x0000;		pdlist = sdp_data_get(rec, 0x0203);		version = pdlist ? pdlist->val.uint16 : 0x0000;		printf("Product ID %04x:%04x:%04x\n", vendor, product, version);		if (vendor == 0x1310 && product == 0x0100 && version == 0x0104) {			printf("Enabling GCT media payload workaround\n");			if (flags)				*flags |= NONSPECAUDIO;		}		next = seq->next;		free(seq);		sdp_record_free(rec);	}done:	sdp_close(sess);	return 0;}static int do_connect(bdaddr_t *src, bdaddr_t *dst, unsigned short psm, uint16_t *mtu){	struct sockaddr_l2 addr;	struct l2cap_options opts;	int sk, opt;	sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);	if (sk < 0) {		fprintf(stderr, "Can't create socket. %s(%d)\n",			strerror(errno), errno);		return -1;	}	memset(&addr, 0, sizeof(addr));	addr.l2_family = AF_BLUETOOTH;	bacpy(&addr.l2_bdaddr, src);	if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {		fprintf(stderr, "Can't bind socket. %s(%d)\n",						strerror(errno), errno);		return -1;	}	/* Get default options */	opt = sizeof(opts);	if (getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, &opt) < 0) {		fprintf(stderr, "Can't get default L2CAP options. %s(%d)\n",						strerror(errno), errno);		return -1;	}	/* Set new options */	//opts.omtu = 48;	//opts.imtu = imtu;	if (setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, opt) < 0) {		fprintf(stderr, "Can't set L2CAP options. %s(%d)\n",						strerror(errno), errno);		return -1;	}	memset(&addr, 0, sizeof(addr));	addr.l2_family = AF_BLUETOOTH;	bacpy(&addr.l2_bdaddr, dst);	addr.l2_psm = htobs(psm);	if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {		fprintf(stderr, "Can't connect to %s. %s(%d)\n",			batostr(&addr.l2_bdaddr), strerror(errno), errno);		close(sk);		return -1;	}	opt = sizeof(opts);	if (getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, &opt) < 0) {		fprintf(stderr, "Can't get L2CAP options. %s(%d)\n",						strerror(errno), errno);		close(sk);		return -1;	}	fprintf(stderr, "Connected [imtu %d, omtu %d, flush_to %d]\n",					opts.imtu, opts.omtu, opts.flush_to);	if (mtu)		*mtu = opts.omtu;	return sk;}#if 0static void dump_packet(void *p, int size){	uint8_t *c = (uint8_t *) p;	while (size-- > 0)		printf(" %02x\n", *c++);	printf("\n");}#endifstatic void init_request(struct avdtp_header * header, int request_id){	static int transaction = 0;	header->packet_type = PACKET_TYPE_SINGLE;	header->message_type = MESSAGE_TYPE_COMMAND;	header->transaction_label = transaction;	header->signal_id = request_id;

⌨️ 快捷键说明

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