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