xref: /btstack/src/le-audio/le_audio_base_parser.c (revision 2e624289f9e34d7048397ae659279a09d2636aca)
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
le_audio_base_parser_fetch_subgroup_info(le_audio_base_parser_t * parser)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 
le_audio_base_parser_init(le_audio_base_parser_t * parser,const uint8_t * buffer,uint16_t size)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 
le_audio_base_parser_get_presentation_delay(le_audio_base_parser_t * parser)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 
le_audio_base_parser_subgroup_get_num_bis(le_audio_base_parser_t * parser)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 
le_audio_base_parser_get_num_subgroups(le_audio_base_parser_t * parser)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 
le_audio_base_parser_subgroup_get_codec_id(le_audio_base_parser_t * parser)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 
le_audio_base_parser_subgroup_get_codec_specific_configuration_length(le_audio_base_parser_t * parser)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 
le_audio_base_parser_subgroup_get_codec_specific_configuration(le_audio_base_parser_t * parser)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 
le_audio_base_parser_subgroup_get_metadata_length(le_audio_base_parser_t * parser)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 
le_audio_base_subgroup_parser_get_metadata(le_audio_base_parser_t * parser)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 
le_audio_base_parser_bis_get_index(le_audio_base_parser_t * parser)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 
le_audio_base_parser_bis_get_codec_specific_configuration_length(le_audio_base_parser_t * parser)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 
le_audio_base_bis_parser_get_codec_specific_configuration(le_audio_base_parser_t * parser)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 
le_audio_base_parser_bis_next(le_audio_base_parser_t * parser)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 
le_audio_base_parser_subgroup_next(le_audio_base_parser_t * parser)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