avdtp.c revision 1.4
1/* $NetBSD: avdtp.c,v 1.4 2020/05/14 08:34:19 msaitoh Exp $ */ 2 3/*- 4 * Copyright (c) 2015 - 2016 Nathanial Sloss <nathanialsloss@yahoo.com.au> 5 * All rights reserved. 6 * 7 * This software is dedicated to the memory of - 8 * Baron James Anlezark (Barry) - 1 Jan 1949 - 13 May 2012. 9 * 10 * Barry was a man who loved his music. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 * POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34#include <errno.h> 35#include <malloc.h> 36#include <string.h> 37#include <unistd.h> 38 39#include "avdtp_signal.h" 40#include "sbc_encode.h" 41 42static uint8_t transLabel = 1; 43int 44avdtpSendCommand(int fd, uint8_t command, uint8_t type, uint8_t *data, 45 size_t datasize) 46{ 47#define SINGLE_PACKET 0 48#define START_PACKET 1 49#define CONTINUE_PACKET 2 50#define END_PACKET 3 51#define signalID 3 52 53 uint8_t header[64]; 54 size_t extra_size = 0; 55 const uint8_t packetType = (SINGLE_PACKET & 3) << 2; 56 const uint8_t messageType = (type & 3); 57 58 transLabel &= 0xf; 59 60 header[0] = (uint8_t)((transLabel << 4) | packetType | messageType); 61 if (command != 0) 62 header[1] = command & 0x3f; 63 else 64 header[1] = signalID & 0x3f; /* Bits 7/6 Reserved */ 65 66 transLabel++; 67 if (data != NULL) { 68 extra_size = datasize; 69 memcpy(header + 2, data, extra_size); 70 } 71 write(fd, &header, extra_size + 2); 72 73 return transLabel - 1; 74} 75 76int 77avdtpCheckResponse(int recvfd, bool *isCommand, uint8_t *trans, uint8_t 78 *signalId, uint8_t *pkt_type, uint8_t *data, size_t *datasize, uint8_t *sep) 79{ 80 uint8_t buffer[1024]; 81 size_t len; 82 83 *isCommand = false; 84 len = (size_t)read(recvfd, buffer, sizeof(buffer)); 85 86 if (datasize) 87 *datasize = 0; 88 89 if (len < AVDTP_LEN_SUCCESS) 90 return ENOMEM; 91 92 *trans = (uint8_t)((buffer[0] & TRANSACTIONLABEL) >> TRANSACTIONLABEL_S); 93 *signalId = buffer[1] & SIGNALID_MASK; 94 if ((buffer[0] & MESSAGETYPE) == COMMAND) { 95 if (datasize) 96 *datasize = 0; 97 if (sep && len > 2) 98 *sep = buffer[2] >> 2; 99 *isCommand = true; 100 } 101 102 if (len == AVDTP_LEN_ERROR) 103 return buffer[2]; 104 else if ((len % AVDTP_LEN_SUCCESS) == 0 && 105 buffer[0] & RESPONSEACCEPT) { 106 if (len == AVDTP_LEN_SUCCESS) 107 return 0; 108 } 109 if (datasize && data && len > AVDTP_LEN_SUCCESS && 110 buffer[0] & RESPONSEACCEPT) { 111 memcpy(data, buffer + 2, len - 2); 112 *datasize = len - 2; 113 114 return 0; 115 } 116 117 if (isCommand) 118 return 0; 119 120 return EINVAL; 121} 122 123int 124avdtpSendCapabilitiesResponseSBC(int fd, int recvfd, int trans, uint8_t mySep, 125 uint8_t bitpool, uint8_t freq, uint8_t mode, uint8_t bands, uint8_t blocks, 126 uint8_t alloc_method) 127{ 128 uint8_t data[12], freqmode, blk_len_sb_alloc, freq_dat, mode_dat; 129 uint8_t bands_dat, blocks_dat, alloc_dat; 130 131 132 freq_dat = (uint8_t)(freq << 4); 133 mode_dat = mode; 134 freqmode = freq_dat | mode_dat; 135 136 blocks_dat = (uint8_t)(blocks << 4); 137 bands_dat = (uint8_t)(bands << 2); 138 alloc_dat = alloc_method; 139 blk_len_sb_alloc = blocks_dat| bands_dat | alloc_dat; 140 141 data[0] = (uint8_t)(trans << 4 | RESPONSEACCEPT); 142 data[1] = AVDTP_GET_CAPABILITIES; 143 data[2] = mediaTransport; 144 data[3] = 0; 145 data[4] = mediaCodec; 146 data[5] = 0x6; 147 data[6] = mediaTypeAudio; 148 data[7] = SBC_CODEC_ID; 149 data[8] = freqmode; 150 data[9] = blk_len_sb_alloc; 151 data[10] = MIN_BITPOOL; 152 if (bitpool > MIN_BITPOOL) 153 data[11] = bitpool; 154 else 155 data[11] = DEFAULT_MAXBPOOL; 156 157 write(fd, data, sizeof(data)); 158 159 return 0; 160} 161 162int 163avdtpSendAccept(int fd, int recvfd, uint8_t trans, uint8_t myCommand) 164{ 165 uint8_t data[2]; 166 167 data[0] = (uint8_t)(trans << 4 | RESPONSEACCEPT); 168 data[1] = myCommand; 169 170 write(fd, data, sizeof(data)); 171 172 return 0; 173} 174 175int 176avdtpSendReject(int fd, int recvfd, uint8_t trans, uint8_t myCommand) 177{ 178 uint8_t data[4]; 179 180 data[0] = (uint8_t)(trans << 4 | RESPONSEREJECT); 181 data[1] = myCommand; 182 data[2] = 0; 183 184 write(fd, data, sizeof(data)); 185 186 return 0; 187} 188 189int 190avdtpSendDiscResponseAudio(int fd, int recvfd, uint8_t trans, uint8_t mySep, 191 bool sink) 192{ 193 uint8_t data[4]; 194 195 data[0] = (uint8_t)(trans << 4 | RESPONSEACCEPT); 196 data[1] = AVDTP_DISCOVER; 197 data[2] = (uint8_t)(mySep << 2); 198 data[3] = (uint8_t)((sink ? 1 : 0) << 3); 199 200 write(fd, data, sizeof(data)); 201 202 return 0; 203} 204 205int 206avdtpDiscover(uint8_t *buffer, size_t recvsize, struct avdtp_sepInfo *sepInfo, 207 bool sink) 208{ 209 size_t offset; 210 bool isSink; 211 212 if (recvsize >= 2) { 213 for (offset = 0; offset < recvsize - 1; offset += 2) { 214 sepInfo->sep = buffer[offset] >> 2; 215 sepInfo->media_Type = buffer[offset+1] >> 4; 216 isSink = (buffer[offset+1] >> 3) & 1; 217 if (buffer[offset] & DISCOVER_SEP_IN_USE || 218 isSink != sink) 219 continue; 220 else 221 break; 222 } 223 if (offset > recvsize) 224 return EINVAL; 225 226 return 0; 227 } 228 229 return EINVAL; 230} 231 232void 233avdtpGetCapabilities(int fd, int recvfd, uint8_t sep) 234{ 235 uint8_t address = (uint8_t)(sep << 2); 236 237 avdtpSendCommand(fd, AVDTP_GET_CAPABILITIES, 0, &address, 1); 238} 239 240int 241avdtpSetConfiguration(int fd, int recvfd, uint8_t sep, uint8_t *data, 242 size_t datasize, int srcsep) 243{ 244 uint8_t configAddresses[2]; 245 uint8_t *configData; 246 247 if (data == NULL || datasize == 0) 248 return EINVAL; 249 250 configData = malloc(datasize + 2); 251 if (configData == NULL) 252 return ENOMEM; 253 configAddresses[0] = (uint8_t)(sep << 2); 254 configAddresses[1] = (uint8_t)(srcsep << 2); 255 256 memcpy(configData, configAddresses, 2); 257 memcpy(configData + 2, data, datasize); 258 259 avdtpSendCommand(fd, AVDTP_SET_CONFIGURATION, 0, 260 configData, datasize + 2); 261 free(configData); 262 263 return 0; 264 265} 266 267void 268avdtpOpen(int fd, int recvfd, uint8_t sep) 269{ 270 uint8_t address = (uint8_t)(sep << 2); 271 272 avdtpSendCommand(fd, AVDTP_OPEN, 0, &address, 1); 273} 274 275void 276avdtpStart(int fd, int recvfd, uint8_t sep) 277{ 278 uint8_t address = (uint8_t)(sep << 2); 279 280 avdtpSendCommand(fd, AVDTP_START, 0, &address, 1); 281} 282 283void 284avdtpClose(int fd, int recvfd, uint8_t sep) 285{ 286 uint8_t address = (uint8_t)(sep << 2); 287 288 avdtpSendCommand(fd, AVDTP_CLOSE, 0, &address, 1); 289} 290 291void 292avdtpSuspend(int fd, int recvfd, uint8_t sep) 293{ 294 uint8_t address = (uint8_t)(sep << 2); 295 296 avdtpSendCommand(fd, AVDTP_SUSPEND, 0, &address, 1); 297} 298 299void 300avdtpAbort(int fd, int recvfd, uint8_t sep) 301{ 302 uint8_t address = (uint8_t)(sep << 2); 303 304 avdtpSendCommand(fd, AVDTP_ABORT, 0, &address, 1); 305} 306 307int 308avdtpAutoConfigSBC(int fd, int recvfd, uint8_t *capabilities, size_t cap_len, 309 uint8_t sep, uint8_t *freq, uint8_t *mode, uint8_t *alloc_method, uint8_t 310 *bitpool, uint8_t* bands, uint8_t *blocks, uint8_t srcsep) 311{ 312 uint8_t freqmode, blk_len_sb_alloc, availFreqMode, availConfig; 313 uint8_t supBitpoolMin, supBitpoolMax, tmp_mask; 314 size_t i; 315 316 for (i = 0; i < cap_len - 5; i++) { 317 if (capabilities[i] == mediaTransport && 318 capabilities[i + 1] == 0 && 319 capabilities[i + 2] == mediaCodec && 320 capabilities[i + 4] == mediaTypeAudio && 321 capabilities[i + 5] == SBC_CODEC_ID) 322 break; 323 } 324 if (i >= cap_len - 9) 325 goto auto_config_failed; 326 327 availFreqMode = capabilities[i + 6]; 328 availConfig = capabilities[i + 7]; 329 supBitpoolMin = capabilities[i + 8]; 330 supBitpoolMax = capabilities[i + 9]; 331 332 freqmode = (uint8_t)(*freq << 4 | *mode); 333 tmp_mask = availFreqMode & freqmode; 334 *mode = (uint8_t)(1 << FLS(tmp_mask & 0xf)); 335 *freq = (uint8_t)(1 << FLS(tmp_mask >> 4)); 336 337 freqmode = (uint8_t)(*freq << 4 | *mode); 338 if ((availFreqMode & freqmode) != freqmode) 339 goto auto_config_failed; 340 341 blk_len_sb_alloc = (uint8_t)(*blocks << 4 | *bands << 2 | 342 *alloc_method); 343 344 tmp_mask = availConfig & blk_len_sb_alloc; 345 *blocks = (uint8_t)(1 << FLS(tmp_mask >> 4)); 346 *bands = (uint8_t)(1 << FLS((tmp_mask >> 2) & 3)); 347 *alloc_method = (uint8_t)(1 << FLS(tmp_mask & 3)); 348 349 blk_len_sb_alloc = (uint8_t)(*blocks << 4 | *bands << 2 | 350 *alloc_method); 351 352 if ((availConfig & blk_len_sb_alloc) != blk_len_sb_alloc) 353 goto auto_config_failed; 354 355 if (*alloc_method == ALLOC_SNR) 356 supBitpoolMax &= (uint8_t)~1; 357 358 if (*mode == MODE_DUAL || *mode == MODE_MONO) 359 supBitpoolMax /= 2; 360 361 if (*bands == BANDS_4) 362 supBitpoolMax /= 2; 363 364 if (supBitpoolMax > *bitpool) 365 supBitpoolMax = *bitpool; 366 else 367 *bitpool = supBitpoolMax; 368 369 uint8_t config[] = {mediaTransport, 0x0, mediaCodec, 0x6, 370 mediaTypeAudio, SBC_CODEC_ID, freqmode, blk_len_sb_alloc, 371 supBitpoolMin, supBitpoolMax}; 372 373 if (avdtpSetConfiguration(fd, fd, sep, config, sizeof(config), 374 srcsep) == 0) 375 return 0; 376 377auto_config_failed: 378 return EINVAL; 379} 380