a2play.c
来自「蓝牙blue tooth sco协议栈」· C语言 代码 · 共 872 行 · 第 1/2 页
C
872 行
// clear rfa bits header->rfa0 = 0; transaction = (transaction + 1) & 0xf;}static int process_seid(int s, struct acp_seid_info * get_seid_resp, unsigned short *psm){ int seid = get_seid_resp->acp_seid; struct getcap_req put_req; struct getcap_resp cap_resp; struct set_config s_config; struct set_config_resp s_resp; struct open_stream_cmd open_stream; struct open_stream_rsp open_resp; printf("seid = %d\n", seid); memset(&put_req, 0, sizeof(put_req)); init_request(&put_req.header, AVDTP_GET_CAPABILITIES); put_req.acp_seid = seid; if (write(s, &put_req, sizeof(put_req)) != sizeof(put_req)) { fprintf(stderr, "couldn't request caps for seid = %d\n", seid); return (-1); } if (read(s, &cap_resp, sizeof(cap_resp)) < sizeof(cap_resp) || cap_resp.header.message_type == MESSAGE_TYPE_REJECT || cap_resp.media_type != AUDIO_MEDIA_TYPE || cap_resp.media_codec_type != SBC_MEDIA_CODEC_TYPE) { fprintf(stderr, "didn't receive sbc codec params (first) for seid = %d\n", seid); return (-1); } printf("got capabilities response\n"); memset(&s_config, 0, sizeof(s_config)); init_request(&s_config.header, AVDTP_SET_CONFIGURATION); s_config.serv_cap = MEDIA_TRANSPORT_CATEGORY; s_config.acp_seid = seid; s_config.int_seid = 1; // how should I choose the int_seid?? s_config.cap_type = MEDIA_CODEC; s_config.length = 6; s_config.media_type = AUDIO_MEDIA_TYPE; s_config.media_codec_type = SBC_MEDIA_CODEC_TYPE; s_config.sbc_elements.channel_mode = 8 >> sbc_info.channel_mode; s_config.sbc_elements.frequency = 8 >> sbc_info.sampling_frequency; s_config.sbc_elements.allocation_method = 1 << sbc_info.allocation_method; s_config.sbc_elements.subbands = 2 >> sbc_info.subbands; s_config.sbc_elements.block_length = 8 >> sbc_info.blocks; s_config.sbc_elements.min_bitpool = cap_resp.sbc_elements.min_bitpool; s_config.sbc_elements.max_bitpool = cap_resp.sbc_elements.max_bitpool; //dump_packet(&s_config.sbc_elements, sizeof(s_config.sbc_elements)); exit(0); if (!(cap_resp.sbc_elements.channel_mode & s_config.sbc_elements.channel_mode)) printf("headset does not support this channel mode\n"); if (!(cap_resp.sbc_elements.frequency & s_config.sbc_elements.frequency)) printf("headset does not support this frequency\n"); if (!(cap_resp.sbc_elements.allocation_method & s_config.sbc_elements.allocation_method)) printf("headset does not support this allocation_method\n"); if (!(cap_resp.sbc_elements.subbands & s_config.sbc_elements.subbands)) printf("headset does not support this subbands setting\n"); if (write(s, &s_config, sizeof(s_config)) != sizeof(s_config)) { fprintf(stderr, "couldn't set config seid = %d\n", seid); return (-1); } printf("sent set_config\n"); int size = read(s, &s_resp, sizeof(s_resp)); if (size == sizeof(s_resp) - 2) { printf("set config accepted %d\n", s_resp.header.message_type); } else { printf("set config rejected\n"); return (-1); } memset(&open_stream, 0, sizeof(open_stream)); init_request(&open_stream.header, AVDTP_OPEN); open_stream.acp_seid = seid; if (write(s, &open_stream, sizeof(open_stream)) != sizeof(open_stream)) { fprintf(stderr, "couldn't open stream seid = %d\n", seid); return (-1); } printf("sent open_stream\n"); if (read(s, &open_resp, sizeof(open_resp)) < sizeof(open_resp) - 1 || open_resp.header.message_type == MESSAGE_TYPE_REJECT) { fprintf(stderr, "didn't receive open_resp confirm for seid = %d\n", seid); return (-1); } printf("got open stream confirm\n"); *psm = 25; return 0;}static int calc_frame_len(struct sbc_frame_header *hdr){ int tmp, nrof_subbands, nrof_blocks; nrof_subbands = (hdr->subbands + 1) * 4; nrof_blocks = (hdr->blocks + 1) * 4; switch (hdr->channel_mode) { case 0x00: nrof_subbands /= 2; tmp = nrof_blocks * hdr->bitpool; break; case 0x01: tmp = nrof_blocks * hdr->bitpool * 2; break; case 0x02: tmp = nrof_blocks * hdr->bitpool; break; case 0x03: tmp = nrof_blocks * hdr->bitpool + nrof_subbands; break; default: return 0; } return (nrof_subbands + ((tmp + 7) / 8));}static int read_header(int fd, struct sbc_frame_header *sbc_info) { if (read(fd, sbc_info, sizeof(*sbc_info)) < sizeof(*sbc_info)) { fprintf(stderr, "reached end of file?\n"); return -1; } if (sbc_info->syncword != 0x9c) { printf("out of sync (0x%02x)\n", sbc_info->syncword); return -1; } return calc_frame_len(sbc_info);}int main(int argc, char *argv[]){ struct sigaction sa; int streamfd; struct sepd_req put_req; struct sepd_resp get_resp; struct start_stream_cmd start_stream; struct start_stream_rsp start_resp; struct media_packet_header packet_header; struct media_payload_header payload_header; struct close_stream_cmd close_stream; struct close_stream_rsp close_resp; bdaddr_t src, dst; unsigned short psm_cmd, psm_stream; unsigned long flags; int frame_len; time_t timestamp; uint16_t mtu, seq_num; int fd; char *addrstr; char *filename; bacpy(&src, BDADDR_ANY); switch (argc) { case 3: addrstr = argv[1]; filename = argv[2]; break; case 2: addrstr = argv[1]; filename = "-"; break; default: usage(); exit(-1); } if(!strcmp(filename,"-")) { fd = 0; } else { fd = open(filename, 0); if (fd < 0) { fprintf(stderr, "couldn't open %s\n", filename); exit(-1); } } frame_len = read_header(fd, &sbc_info); if (frame_len < 0) { fprintf(stderr, "couldn't read header on %s\n", filename); exit(-1); } printf("subbands = %d\n" "allocation method = %d\n" "channel_mode = %d\n" "blocks = %d\n" "sampling frequency = %d\n" "bitpool = %d\n", sbc_info.subbands, sbc_info.allocation_method, sbc_info.channel_mode, sbc_info.blocks, sbc_info.sampling_frequency, sbc_info.bitpool); printf("frame len = %d\n", frame_len); printf("Using address: %s\n", addrstr); str2ba(addrstr, &dst); if (detect_a2dp(&src, &dst, &psm_cmd, &flags) < 0) { fprintf(stderr, "could not find A2DP services on device %s\n", addrstr); exit(-1); } /* setup sigterm handler. we must make sure to do a clean disconnect */ memset(&sa, 0, sizeof(sa)); sa.sa_flags = SA_NOCLDSTOP; sa.sa_handler = sig_term; sigaction(SIGTERM, &sa, NULL); sigaction(SIGINT, &sa, NULL); sa.sa_handler = SIG_IGN; sigaction(SIGCHLD, &sa, NULL); sigaction(SIGPIPE, &sa, NULL); cmdfd = do_connect(&src, &dst, psm_cmd, NULL); if (cmdfd < 0) { fprintf(stderr, "cannot open psm_cmd = %d\n", psm_cmd); exit(-1); } // avdt_discover_req memset(&put_req, 0, sizeof(put_req)); init_request(&put_req.header, AVDTP_DISCOVER); if (write(cmdfd, &put_req, sizeof(put_req)) != sizeof(put_req)) { fprintf(stderr, "couldn't send avdtp_discover\n"); close(cmdfd); exit(-1); } int size; size = read(cmdfd, &get_resp, sizeof(get_resp)); if (size < sizeof(get_resp) - MAX_ADDITIONAL_CODEC_OCTETS) { fprintf(stderr, "couldn't get avdtp_discover\n"); close(cmdfd); exit(-1); } int i; int seid = -1; int last_seid_index = MAX_ADDITIONAL_CODEC - ((sizeof(get_resp)-size)/sizeof(struct acp_seid_info)); for(i=0; i <= last_seid_index; i++) { if (process_seid(cmdfd, &get_resp.infos[i], &psm_stream) == 0) { seid = get_resp.infos[i].acp_seid; break; } } if(seid == -1) { fprintf(stderr, "couldn't locate the correct seid\n"); exit(-1); } // open the stream l2cap mtu = 48; streamfd = do_connect(&src, &dst, psm_stream, &mtu); if (streamfd < 0) { fprintf(stderr, "cannot open psm_stream = %d\n", psm_stream); exit(-1); } // start the stream memset(&start_stream, 0, sizeof(start_stream)); init_request(&start_stream.header, AVDTP_START); start_stream.acp_seid = seid; if (write(cmdfd, &start_stream, sizeof(start_stream)) != sizeof(start_stream)) { fprintf(stderr, "couldn't send start_stream\n"); close(streamfd); close(cmdfd); exit(-1); } printf("sent stream-start\n"); if (read(cmdfd, &start_resp, sizeof(start_resp)) < sizeof(start_resp) - 2 || start_resp.header.message_type == MESSAGE_TYPE_REJECT) { fprintf(stderr, "didn't receive start_resp confirm for seid = %d\n", seid); close(streamfd); close(cmdfd); return (-1); } printf("got start stream confirm\n"); char buf[BUFS]; int psize; if (mtu > BUFS) mtu = BUFS; terminate = 0; seq_num = 1; memset(&payload_header, 0, sizeof(payload_header)); timestamp = 0; while (!terminate) { // a2dp headers: avdtp p.45 memset(&packet_header, 0, sizeof(packet_header)); packet_header.v = 2; packet_header.pt = 1; packet_header.sequence_number = htons(seq_num); packet_header.timestamp = htonl(timestamp); packet_header.ssrc = htonl(1); timestamp += (sbc_info.blocks + 1)*4 * (sbc_info.subbands + 1)*4; memcpy(buf, &packet_header, sizeof(packet_header)); psize = sizeof(packet_header); // framing a2dp p.23 payload_header.frame_count = 0; /* BEGIN: NONSPECAUDIO == TRUE */ if (flags & NONSPECAUDIO) { buf[12] = 0xff; buf[13] = 0xff; memcpy(buf + MEDIA_PACKET_HEADER_LENGTH, &sbc_info, sizeof(sbc_info)); size = read(fd, buf + sizeof(sbc_info) + MEDIA_PACKET_HEADER_LENGTH, frame_len); if (size != frame_len) { terminate = 1; } else { // framing, fragmenting, a2dp headers: avdtp p.45 and a2dp spec p.23 write(streamfd, buf, size + sizeof(sbc_info) + MEDIA_PACKET_HEADER_LENGTH); } frame_len = read_header(fd, &sbc_info); if (frame_len < 0) { fprintf(stderr, "couldn't read header on %s\n", filename); break; } /* END: NONSPECAUDIO == TRUE */ } else { /* BEGIN: NONSPECAUDIO == FALSE */ // make room for the payload header but don't copy it yet (count up frames first) psize += sizeof(payload_header); do { payload_header.frame_count++; memcpy(buf + psize, &sbc_info, sizeof(sbc_info)); psize += sizeof(sbc_info); size = read(fd, buf + psize, frame_len); psize += size; if (size != frame_len) { fprintf(stderr, "couldn't read frame of %d bytes (frame %d) on %s\n", frame_len, payload_header.frame_count, filename); terminate = 1; break; } frame_len = read_header(fd, &sbc_info); if (frame_len < 0) { fprintf(stderr, "couldn't read header on %s\n", filename); terminate = 1; break; } } while(psize + frame_len + sizeof(sbc_info) < mtu); memcpy(buf + sizeof(packet_header), &payload_header, sizeof(payload_header)); write(streamfd, buf, psize); } /* END: NONSPECAUDIO == FALSE */ seq_num++; } close(fd); printf("sent %d packets\n", seq_num); // signal the stream close memset(&close_stream, 0, sizeof(close_stream)); init_request(&close_stream.header, AVDTP_CLOSE); close_stream.acp_seid = seid; if (write(cmdfd, &close_stream, sizeof(close_stream)) != sizeof(close_stream)) { fprintf(stderr, "couldn't send close_stream\n"); close(streamfd); close(cmdfd); exit(-1); } printf("sent stream-close\n"); if (read(cmdfd, &close_resp, sizeof(close_resp)) < sizeof(close_resp) - 1 || close_resp.header.message_type == MESSAGE_TYPE_REJECT) { fprintf(stderr, "didn't receive close_resp confirm for seid = %d\n", seid); close(streamfd); close(cmdfd); return (-1); } printf("got close stream confirm\n"); close(streamfd); close(cmdfd); return 0;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?