1 /* 2 * Copyright (C) 2022 BlueKitchen GmbH 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the copyright holders nor the names of 14 * contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 20 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN 21 * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 24 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 25 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 27 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 * 30 */ 31 32 #define BTSTACK_FILE__ "le_audio_base_parser.c" 33 34 /** 35 * @title Broadcast Audio Source Endpoint AD Parser 36 */ 37 38 #include <string.h> 39 40 #include "bluetooth.h" 41 #include "bluetooth_data_types.h" 42 #include "bluetooth_gatt.h" 43 #include "btstack_util.h" 44 #include "btstack_debug.h" 45 #include "le-audio/le_audio_base_parser.h" 46 47 // precondition: subgroup_offset set 48 static void le_audio_base_parser_fetch_subgroup_info(le_audio_base_parser_t * parser){ 49 const uint8_t * buffer = parser->buffer; 50 uint16_t offset = parser->subgroup_offset; 51 parser->bis_count = buffer[offset++]; 52 // Codec ID 53 offset += 5; 54 parser->subgroup_codec_specific_configuration_len = buffer[offset++]; 55 // Codec Specific Configuration 56 offset += parser->subgroup_codec_specific_configuration_len; 57 parser->subgroup_metadata_len = buffer[offset++]; 58 // Metadata 59 offset += parser->subgroup_metadata_len; 60 parser->bis_index = 0; 61 parser->bis_offset =offset; 62 } 63 64 bool le_audio_base_parser_init(le_audio_base_parser_t * parser, const uint8_t * buffer, uint16_t size){ 65 memset(parser, 0, sizeof(le_audio_base_parser_t)); 66 // check buffer 67 if (size < 8) { 68 return false; 69 } 70 uint16_t offset = 1; 71 if (buffer[offset++] != BLUETOOTH_DATA_TYPE_SERVICE_DATA_16_BIT_UUID) { 72 return false; 73 } 74 if (little_endian_read_16(buffer, offset) != ORG_BLUETOOTH_SERVICE_BASIC_AUDIO_ANNOUNCEMENT_SERVICE){ 75 return false; 76 } 77 offset += 5; 78 79 parser->buffer = buffer; 80 parser->size = size; 81 82 parser->subgroup_count = buffer[offset++]; 83 parser->subgroup_index = 0; 84 85 // fully validate structure 86 uint8_t i; 87 uint8_t k; 88 for (i=0;i<parser->subgroup_count;i++){ 89 if ((offset+8) > size) { 90 return false; 91 } 92 uint8_t num_bis = buffer[offset++]; 93 offset += 5; 94 uint8_t config_len = buffer[offset++]; 95 offset += config_len; 96 if ((offset+1) > size) { 97 return false; 98 } 99 int8_t meta_len = buffer[offset++]; 100 offset += meta_len; 101 if (offset > size) { 102 return false; 103 } 104 for (k=0;k<num_bis;k++){ 105 if ((offset+2) > size) { 106 return false; 107 } 108 offset++; 109 config_len = buffer[offset++]; 110 offset += config_len; 111 if (offset > size) { 112 return false; 113 } 114 } 115 } 116 117 if (parser->subgroup_count > 0){ 118 parser->subgroup_offset = 8; 119 le_audio_base_parser_fetch_subgroup_info(parser); 120 } 121 122 return true; 123 } 124 125 uint32_t le_audio_base_parser_get_presentation_delay(le_audio_base_parser_t * parser){ 126 btstack_assert(parser->buffer != NULL); 127 return little_endian_read_24(parser->buffer, 4); 128 } 129 130 uint8_t le_audio_base_parser_subgroup_get_num_bis(le_audio_base_parser_t * parser){ 131 btstack_assert(parser->subgroup_offset > 0); 132 return parser->bis_count; 133 } 134 135 uint8_t le_audio_base_parser_get_num_subgroups(le_audio_base_parser_t * parser){ 136 btstack_assert(parser->buffer != NULL); 137 return parser->subgroup_count; 138 } 139 140 const uint8_t * le_audio_base_parser_subgroup_get_codec_id(le_audio_base_parser_t * parser){ 141 btstack_assert(parser->subgroup_offset > 0); 142 return &parser->buffer[parser->subgroup_offset]; 143 } 144 145 uint8_t le_audio_base_parser_subgroup_get_codec_specific_configuration_length(le_audio_base_parser_t * parser){ 146 btstack_assert(parser->subgroup_offset > 0); 147 return parser->subgroup_codec_specific_configuration_len; 148 } 149 150 const uint8_t * le_audio_base_parser_subgroup_get_codec_specific_configuration(le_audio_base_parser_t * parser){ 151 btstack_assert(parser->subgroup_offset > 0); 152 return &parser->buffer[parser->subgroup_offset + 7]; 153 } 154 155 uint8_t le_audio_base_parser_subgroup_get_metadata_length(le_audio_base_parser_t * parser){ 156 btstack_assert(parser->subgroup_offset > 0); 157 return parser->buffer[parser->subgroup_offset + 7 + parser->subgroup_codec_specific_configuration_len]; 158 } 159 160 const uint8_t * le_audio_base_subgroup_parser_get_metadata(le_audio_base_parser_t * parser){ 161 btstack_assert(parser->subgroup_offset > 0); 162 return &parser->buffer[parser->subgroup_offset + 7 + parser->subgroup_codec_specific_configuration_len + 1]; 163 } 164 165 uint8_t le_audio_base_parser_bis_get_index(le_audio_base_parser_t * parser){ 166 btstack_assert(parser->bis_offset > 0); 167 return parser->buffer[parser->bis_offset]; 168 } 169 170 uint8_t le_audio_base_parser_bis_get_codec_specific_configuration_length(le_audio_base_parser_t * parser){ 171 btstack_assert(parser->bis_offset > 0); 172 return parser->buffer[parser->bis_offset + 1]; 173 } 174 175 const uint8_t * le_audio_base_bis_parser_get_codec_specific_configuration(le_audio_base_parser_t * parser){ 176 btstack_assert(parser->bis_offset > 0); 177 return &parser->buffer[parser->bis_offset + 2]; 178 } 179 180 void le_audio_base_parser_bis_next(le_audio_base_parser_t * parser){ 181 btstack_assert(parser->bis_offset > 0); 182 parser->bis_index++; 183 if (parser->bis_index < parser->bis_count){ 184 parser->bis_offset += 1 + 1 + parser->buffer[parser->bis_offset+1]; 185 } else { 186 parser->bis_offset = 0; 187 } 188 } 189 190 void le_audio_base_parser_subgroup_next(le_audio_base_parser_t * parser){ 191 btstack_assert(parser->subgroup_offset > 0); 192 while (parser->bis_index < parser->bis_count){ 193 le_audio_base_parser_bis_next(parser); 194 } 195 parser->subgroup_index++; 196 if (parser->subgroup_index < parser->subgroup_count){ 197 parser->subgroup_offset = parser->bis_offset; 198 le_audio_base_parser_fetch_subgroup_info(parser); 199 } else { 200 parser->bis_offset = 0; 201 } 202 } 203