xref: /btstack/src/classic/avrcp_browsing_controller.c (revision 12c4a6eeaf1081a351a6574937759b171cdbc0f2)
1 /*
2  * Copyright (C) 2016 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  * 4. Any redistribution, use, or modification is done solely for
17  *    personal benefit and not for any commercial purpose or for
18  *    monetary gain.
19  *
20  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
24  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * Please inquire about commercial licensing options at
34  * [email protected]
35  *
36  */
37 
38 #define BTSTACK_FILE__ "avrcp_browsing_controller.c"
39 
40 #include <stdint.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <inttypes.h>
45 #include "btstack.h"
46 #include "classic/avrcp.h"
47 #include "classic/avrcp_browsing_controller.h"
48 
49 #define PSM_AVCTP_BROWSING              0x001b
50 
51 static void avrcp_browsing_controller_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
52 
53 static int avrcp_browsing_controller_send_get_folder_items_cmd(uint16_t cid, avrcp_browsing_connection_t * connection){
54     uint8_t command[100];
55     int pos = 0;
56     // transport header
57     // Transaction label | Packet_type | C/R | IPID (1 == invalid profile identifier)
58     command[pos++] = (connection->transaction_label << 4) | (AVRCP_SINGLE_PACKET << 2) | (AVRCP_COMMAND_FRAME << 1) | 0;
59     // Profile IDentifier (PID)
60     command[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL >> 8;
61     command[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL & 0x00FF;
62     command[pos++] = AVRCP_PDU_ID_GET_FOLDER_ITEMS;
63 
64     uint32_t attribute_count = 0;
65     uint32_t attributes_to_copy = 0;
66 
67     switch (connection->attr_bitmap){
68         case AVRCP_MEDIA_ATTR_NONE:
69             attribute_count = AVRCP_MEDIA_ATTR_NONE; // 0xFFFFFFFF
70             break;
71         case AVRCP_MEDIA_ATTR_ALL:
72             attribute_count = AVRCP_MEDIA_ATTR_ALL;  // 0
73             break;
74         default:
75             attribute_count    = count_set_bits_uint32(connection->attr_bitmap & 0xff);
76             attributes_to_copy = attribute_count;
77             break;
78     }
79     big_endian_store_16(command, pos, 9 + 1 + (attribute_count*4));
80     pos += 2;
81 
82     command[pos++] = connection->scope;
83     big_endian_store_32(command, pos, connection->start_item);
84     pos += 4;
85     big_endian_store_32(command, pos, connection->end_item);
86     pos += 4;
87     command[pos++] = attribute_count;
88 
89     int bit_position = 1;
90     while (attributes_to_copy){
91         if (connection->attr_bitmap & (1 << bit_position)){
92             big_endian_store_32(command, pos, bit_position);
93             pos += 4;
94             attributes_to_copy--;
95         }
96         bit_position++;
97     }
98     return l2cap_send(cid, command, pos);
99 }
100 
101 
102 static int avrcp_browsing_controller_send_get_item_attributes_cmd(uint16_t cid, avrcp_browsing_connection_t * connection){
103     uint8_t command[100];
104     int pos = 0;
105     // transport header
106     // Transaction label | Packet_type | C/R | IPID (1 == invalid profile identifier)
107     command[pos++] = (connection->transaction_label << 4) | (AVRCP_SINGLE_PACKET << 2) | (AVRCP_COMMAND_FRAME << 1) | 0;
108     // Profile IDentifier (PID)
109     command[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL >> 8;
110     command[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL & 0x00FF;
111     command[pos++] = AVRCP_PDU_ID_GET_ITEM_ATTRIBUTES;
112 
113     uint32_t attribute_count;
114     uint32_t attributes_to_copy = 0;
115 
116     switch (connection->attr_bitmap){
117         case AVRCP_MEDIA_ATTR_NONE:
118         case AVRCP_MEDIA_ATTR_ALL:
119             attribute_count = 0;
120             break;
121         default:
122             attribute_count = count_set_bits_uint32(connection->attr_bitmap & 0xff);
123             attributes_to_copy = attribute_count;
124             break;
125     }
126 
127     big_endian_store_16(command, pos, 12 + (attribute_count*4));
128     pos += 2;
129 
130     command[pos++] = connection->scope;
131     (void)memcpy(command + pos, connection->folder_uid, 8);
132     pos += 8;
133     big_endian_store_16(command, pos, connection->uid_counter);
134     pos += 2;
135     command[pos++] = attribute_count;
136 
137     int bit_position = 1;
138     while (attributes_to_copy){
139         if (connection->attr_bitmap & (1 << bit_position)){
140             big_endian_store_32(command, pos, bit_position);
141             pos += 4;
142             attributes_to_copy--;
143         }
144         bit_position++;
145     }
146 
147     return l2cap_send(cid, command, pos);
148 }
149 
150 
151 static int avrcp_browsing_controller_send_change_path_cmd(uint16_t cid, avrcp_browsing_connection_t * connection){
152     uint8_t command[100];
153     int pos = 0;
154     // transport header
155     // Transaction label | Packet_type | C/R | IPID (1 == invalid profile identifier)
156     command[pos++] = (connection->transaction_label << 4) | (AVRCP_SINGLE_PACKET << 2) | (AVRCP_COMMAND_FRAME << 1) | 0;
157     // Profile IDentifier (PID)
158     command[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL >> 8;
159     command[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL & 0x00FF;
160     command[pos++] = AVRCP_PDU_ID_CHANGE_PATH;
161 
162     big_endian_store_16(command, pos, 11);
163     pos += 2;
164     pos += 2;
165     command[pos++] = connection->direction;
166     (void)memcpy(command + pos, connection->folder_uid, 8);
167     pos += 8;
168     return l2cap_send(cid, command, pos);
169 }
170 
171 static int avrcp_browsing_controller_send_search_cmd(uint16_t cid, avrcp_browsing_connection_t * connection){
172     uint8_t command[100];
173     int pos = 0;
174     // transport header
175     // Transaction label | Packet_type | C/R | IPID (1 == invalid profile identifier)
176     command[pos++] = (connection->transaction_label << 4) | (AVRCP_SINGLE_PACKET << 2) | (AVRCP_COMMAND_FRAME << 1) | 0;
177     // Profile IDentifier (PID)
178     command[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL >> 8;
179     command[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL & 0x00FF;
180     command[pos++] = AVRCP_PDU_ID_SEARCH;
181 
182     big_endian_store_16(command, pos, 4 + connection->search_str_len);
183     pos += 2;
184 
185     big_endian_store_16(command, pos, 0x006A);
186     pos += 2;
187     big_endian_store_16(command, pos, connection->search_str_len);
188     pos += 2;
189 
190     (void)memcpy(command + pos, connection->search_str,
191                  connection->search_str_len);
192     pos += connection->search_str_len;
193     return l2cap_send(cid, command, pos);
194 }
195 
196 static int avrcp_browsing_controller_send_set_browsed_player_cmd(uint16_t cid, avrcp_browsing_connection_t * connection){
197     uint8_t command[100];
198     int pos = 0;
199     // transport header
200     // Transaction label | Packet_type | C/R | IPID (1 == invalid profile identifier)
201     command[pos++] = (connection->transaction_label << 4) | (AVRCP_SINGLE_PACKET << 2) | (AVRCP_COMMAND_FRAME << 1) | 0;
202     // Profile IDentifier (PID)
203     command[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL >> 8;
204     command[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL & 0x00FF;
205     command[pos++] = AVRCP_PDU_ID_SET_BROWSED_PLAYER;
206 
207     big_endian_store_16(command, pos, 2);
208     pos += 2;
209     big_endian_store_16(command, pos, connection->browsed_player_id);
210     pos += 2;
211     return l2cap_send(cid, command, pos);
212 }
213 
214 static int avrcp_browsing_controller_send_get_total_nr_items_cmd(uint16_t cid, avrcp_browsing_connection_t * connection){
215     uint8_t command[7];
216     int pos = 0;
217     // transport header
218     // Transaction label | Packet_type | C/R | IPID (1 == invalid profile identifier)
219     command[pos++] = (connection->transaction_label << 4) | (AVRCP_SINGLE_PACKET << 2) | (AVRCP_COMMAND_FRAME << 1) | 0;
220     // Profile IDentifier (PID)
221     command[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL >> 8;
222     command[pos++] = BLUETOOTH_SERVICE_CLASS_AV_REMOTE_CONTROL & 0x00FF;
223     command[pos++] = AVRCP_PDU_ID_GET_TOTAL_NUMBER_OF_ITEMS;
224 
225     big_endian_store_16(command, pos, 1);
226     pos += 2;
227     command[pos++] = connection->get_total_nr_items_scope;
228     return l2cap_send(cid, command, pos);
229 }
230 
231 static void avrcp_browsing_controller_handle_can_send_now(avrcp_browsing_connection_t * connection){
232     switch (connection->state){
233         case AVCTP_CONNECTION_OPENED:
234             if (connection->set_browsed_player_id){
235                 connection->state = AVCTP_W2_RECEIVE_RESPONSE;
236                 connection->set_browsed_player_id = 0;
237                 avrcp_browsing_controller_send_set_browsed_player_cmd(connection->l2cap_browsing_cid, connection);
238                 break;
239             }
240 
241             if (connection->get_total_nr_items){
242                 connection->state = AVCTP_W2_RECEIVE_RESPONSE;
243                 connection->get_total_nr_items = 0;
244                 avrcp_browsing_controller_send_get_total_nr_items_cmd(connection->l2cap_browsing_cid, connection);
245                 break;
246             }
247 
248             if (connection->get_folder_items){
249                 connection->state = AVCTP_W2_RECEIVE_RESPONSE;
250                 connection->get_folder_items = 0;
251                 avrcp_browsing_controller_send_get_folder_items_cmd(connection->l2cap_browsing_cid, connection);
252                 break;
253             }
254 
255             if (connection->get_item_attributes){
256                 connection->state = AVCTP_W2_RECEIVE_RESPONSE;
257                 connection->get_item_attributes = 0;
258                 avrcp_browsing_controller_send_get_item_attributes_cmd(connection->l2cap_browsing_cid, connection);
259                 break;
260             }
261 
262             if (connection->change_path){
263                 connection->state = AVCTP_W2_RECEIVE_RESPONSE;
264                 connection->change_path = 0;
265                 avrcp_browsing_controller_send_change_path_cmd(connection->l2cap_browsing_cid, connection);
266                 break;
267             }
268 
269             if (connection->search){
270                 connection->state = AVCTP_W2_RECEIVE_RESPONSE;
271                 connection->search = 0;
272                 avrcp_browsing_controller_send_search_cmd(connection->l2cap_browsing_cid, connection);
273                 break;
274             }
275             break;
276         default:
277             return;
278     }
279 }
280 
281 
282 static void avrcp_browsing_controller_emit_done_with_uid_counter(btstack_packet_handler_t callback, uint16_t browsing_cid, uint16_t uid_counter, uint8_t browsing_status, uint8_t bluetooth_status){
283     btstack_assert(callback != NULL);
284 
285     uint8_t event[9];
286     int pos = 0;
287     event[pos++] = HCI_EVENT_AVRCP_META;
288     event[pos++] = sizeof(event) - 2;
289     event[pos++] = AVRCP_SUBEVENT_BROWSING_DONE;
290     little_endian_store_16(event, pos, browsing_cid);
291     pos += 2;
292     little_endian_store_16(event, pos, uid_counter);
293     pos += 2;
294     event[pos++] = browsing_status;
295     event[pos++] = bluetooth_status;
296     (*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
297 }
298 
299 static void avrcp_parser_reset(avrcp_browsing_connection_t * connection){
300     connection->parser_attribute_header_pos = 0;
301     connection->parsed_attribute_value_offset = 0;
302     connection->parsed_num_attributes = 0;
303     connection->parser_state = AVRCP_PARSER_GET_ATTRIBUTE_HEADER;
304 }
305 
306 
307 static void avrcp_browsing_parser_process_byte(uint8_t byte, avrcp_browsing_connection_t * connection){
308     uint8_t prepended_header_size = 1;
309     uint16_t attribute_total_value_len;
310 
311     switch(connection->parser_state){
312         case AVRCP_PARSER_GET_ATTRIBUTE_HEADER:
313             connection->parser_attribute_header[connection->parser_attribute_header_pos++] = byte;
314             if (connection->parser_attribute_header_pos < AVRCP_BROWSING_ITEM_HEADER_LEN) break;
315 
316             attribute_total_value_len = big_endian_read_16(connection->parser_attribute_header, 1);
317             connection->parsed_attribute_value[connection->parsed_attribute_value_offset++] = connection->parser_attribute_header[0];   // prepend with item type
318             connection->parsed_attribute_value_len = btstack_min(attribute_total_value_len, AVRCP_MAX_ATTRIBUTTE_SIZE - prepended_header_size);                 // reduce AVRCP_MAX_ATTRIBUTTE_SIZE for the size ot item type
319             connection->parser_state = AVRCP_PARSER_GET_ATTRIBUTE_VALUE;
320             break;
321 
322         case AVRCP_PARSER_GET_ATTRIBUTE_VALUE:
323             connection->parsed_attribute_value[connection->parsed_attribute_value_offset++] = byte;
324             if (connection->parsed_attribute_value_offset < (connection->parsed_attribute_value_len + prepended_header_size)){
325                 break;
326             }
327             if (connection->parsed_attribute_value_offset < big_endian_read_16(connection->parser_attribute_header, 1)){
328                 connection->parser_state = AVRCP_PARSER_IGNORE_REST_OF_ATTRIBUTE_VALUE;
329                 break;
330             }
331             connection->parser_state = AVRCP_PARSER_GET_ATTRIBUTE_HEADER;
332             (*avrcp_controller_context.browsing_avrcp_callback)(AVRCP_BROWSING_DATA_PACKET, connection->l2cap_browsing_cid, &connection->parsed_attribute_value[0], connection->parsed_attribute_value_offset);
333             connection->parsed_num_attributes++;
334             connection->parsed_attribute_value_offset = 0;
335             connection->parser_attribute_header_pos = 0;
336 
337             if (connection->parsed_num_attributes == connection->num_items){
338                 avrcp_parser_reset(connection);
339                 break;
340             }
341             break;
342 
343         case AVRCP_PARSER_IGNORE_REST_OF_ATTRIBUTE_VALUE:
344             connection->parsed_attribute_value_offset++;
345             if (connection->parsed_attribute_value_offset < (big_endian_read_16(connection->parser_attribute_header, 1) + prepended_header_size)){
346                 break;
347             }
348             connection->parser_state = AVRCP_PARSER_GET_ATTRIBUTE_HEADER;
349             (*avrcp_controller_context.browsing_avrcp_callback)(AVRCP_BROWSING_DATA_PACKET, connection->l2cap_browsing_cid, &connection->parsed_attribute_value[0], connection->parsed_attribute_value_offset);
350             connection->parsed_num_attributes++;
351             connection->parsed_attribute_value_offset = 0;
352             connection->parser_attribute_header_pos = 0;
353 
354             if (connection->parsed_num_attributes == connection->num_items){
355                 avrcp_parser_reset(connection);
356                 break;
357             }
358             break;
359         default:
360             break;
361     }
362 }
363 
364 static void avrcp_browsing_parse_and_emit_element_attrs(uint8_t * packet, uint16_t num_bytes_to_read, avrcp_browsing_connection_t * connection){
365     int i;
366     for (i=0;i<num_bytes_to_read;i++){
367         avrcp_browsing_parser_process_byte(packet[i], connection);
368     }
369 }
370 
371 static void avrcp_browsing_controller_emit_failed(btstack_packet_handler_t callback, uint16_t browsing_cid, uint8_t browsing_status, uint8_t bluetooth_status){
372     avrcp_browsing_controller_emit_done_with_uid_counter(callback, browsing_cid, 0, browsing_status, bluetooth_status);
373 }
374 
375 
376 static void avrcp_browsing_controller_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
377     avrcp_browsing_connection_t * browsing_connection;
378     uint8_t transport_header;
379     int pos;
380 
381     switch (packet_type) {
382         case L2CAP_DATA_PACKET:
383             browsing_connection = get_avrcp_browsing_connection_for_l2cap_cid_for_role(AVRCP_CONTROLLER, channel);
384             if (!browsing_connection) break;
385             pos = 0;
386             transport_header = packet[pos++];
387             // Transaction label | Packet_type | C/R | IPID (1 == invalid profile identifier)
388             browsing_connection->transaction_label = transport_header >> 4;
389             avrcp_packet_type_t avctp_packet_type = (transport_header & 0x0F) >> 2;
390             switch (avctp_packet_type){
391                 case AVRCP_SINGLE_PACKET:
392                 case AVRCP_START_PACKET:
393                     pos += 2;
394                     browsing_connection->num_packets = 1;
395                     if (avctp_packet_type == AVRCP_START_PACKET){
396                         browsing_connection->num_packets = packet[pos++];
397                     }
398                     if ((pos + 4) > size){
399                         browsing_connection->state = AVCTP_CONNECTION_OPENED;
400                         avrcp_browsing_controller_emit_failed(avrcp_controller_context.browsing_avrcp_callback, channel, AVRCP_BROWSING_ERROR_CODE_INVALID_COMMAND, ERROR_CODE_SUCCESS);
401                         return;
402                     }
403                     browsing_connection->pdu_id = packet[pos++];
404                     pos += 2;
405                     browsing_connection->browsing_status = packet[pos++];
406                     if (browsing_connection->browsing_status != AVRCP_BROWSING_ERROR_CODE_SUCCESS){
407                         browsing_connection->state = AVCTP_CONNECTION_OPENED;
408                         avrcp_browsing_controller_emit_failed(avrcp_controller_context.browsing_avrcp_callback, channel, browsing_connection->browsing_status, ERROR_CODE_SUCCESS);
409                         return;
410                     }
411                     break;
412                 default:
413                     break;
414             }
415 
416             uint32_t i;
417             uint8_t folder_depth;
418 
419             switch(browsing_connection->pdu_id){
420                 case AVRCP_PDU_ID_CHANGE_PATH:
421                     break;
422                 case AVRCP_PDU_ID_SET_ADDRESSED_PLAYER:
423                     break;
424                 case AVRCP_PDU_ID_GET_TOTAL_NUMBER_OF_ITEMS:
425                     break;
426                 case AVRCP_PDU_ID_SET_BROWSED_PLAYER:
427                     browsing_connection->uid_counter =  big_endian_read_16(packet, pos);
428                     pos += 2;
429                     // num_items
430                     pos += 4;
431                     // charset
432                     pos += 2;
433                     folder_depth = packet[pos++];
434 
435                     for (i = 0; i < folder_depth; i++){
436                         uint16_t folder_name_length = big_endian_read_16(packet, pos);
437                         pos += 2;
438                         // reuse packet and add data type as a header
439                         packet[pos-1] = AVRCP_BROWSING_MEDIA_ROOT_FOLDER;
440                         (*avrcp_controller_context.browsing_avrcp_callback)(AVRCP_BROWSING_DATA_PACKET, channel, packet+pos-1, folder_name_length+1);
441                         pos += folder_name_length;
442                     }
443                     break;
444 
445                 case AVRCP_PDU_ID_GET_FOLDER_ITEMS:{
446                     switch (avctp_packet_type){
447                         case AVRCP_SINGLE_PACKET:
448                         case AVRCP_START_PACKET:
449                             avrcp_parser_reset(browsing_connection);
450                             browsing_connection->uid_counter =  big_endian_read_16(packet, pos);
451                             pos += 2;
452                             browsing_connection->num_items = big_endian_read_16(packet, pos); //num_items
453                             pos += 2;
454                             avrcp_browsing_parse_and_emit_element_attrs(packet+pos, size-pos, browsing_connection);
455                             break;
456 
457                         case AVRCP_CONTINUE_PACKET:
458                             avrcp_browsing_parse_and_emit_element_attrs(packet+pos, size-pos, browsing_connection);
459                             break;
460 
461                         case AVRCP_END_PACKET:
462                             avrcp_browsing_parse_and_emit_element_attrs(packet+pos, size-pos, browsing_connection);
463                             avrcp_parser_reset(browsing_connection);
464                             break;
465                         default:
466                             break;
467                     }
468                     break;
469                 }
470                 case AVRCP_PDU_ID_SEARCH:
471                     browsing_connection->uid_counter =  big_endian_read_16(packet, pos);
472                     pos += 2;
473                     break;
474                 case AVRCP_PDU_ID_GET_ITEM_ATTRIBUTES:
475                     packet[pos-1] = AVRCP_BROWSING_MEDIA_ELEMENT_ITEM_ATTRIBUTE;
476                     (*avrcp_controller_context.browsing_avrcp_callback)(AVRCP_BROWSING_DATA_PACKET, channel, packet+pos-1, size - pos + 1);
477                     break;
478                 default:
479                     log_info(" not parsed pdu ID 0x%02x", browsing_connection->pdu_id);
480                     break;
481             }
482 
483             switch (avctp_packet_type){
484                 case AVRCP_SINGLE_PACKET:
485                 case AVRCP_END_PACKET:
486                     browsing_connection->state = AVCTP_CONNECTION_OPENED;
487                     avrcp_browsing_controller_emit_done_with_uid_counter(avrcp_controller_context.browsing_avrcp_callback, channel, browsing_connection->uid_counter, browsing_connection->browsing_status, ERROR_CODE_SUCCESS);
488                     break;
489                 default:
490                     break;
491             }
492             break;
493 
494         case HCI_EVENT_PACKET:
495             switch (hci_event_packet_get_type(packet)){
496                 case L2CAP_EVENT_CAN_SEND_NOW:
497                     browsing_connection = get_avrcp_browsing_connection_for_l2cap_cid_for_role(AVRCP_CONTROLLER,channel);
498                     if (!browsing_connection) break;
499                     avrcp_browsing_controller_handle_can_send_now(browsing_connection);
500                     break;
501                 default:
502                     avrcp_browser_packet_handler(packet_type, channel, packet, size, &avrcp_controller_context);
503                     break;
504             }
505             break;
506 
507         default:
508             break;
509     }
510 }
511 
512 void avrcp_browsing_controller_init(void){
513     avrcp_controller_context.browsing_packet_handler = avrcp_browsing_controller_packet_handler;
514     l2cap_register_service(&avrcp_browsing_controller_packet_handler, PSM_AVCTP_BROWSING, 0xffff, gap_get_security_level());
515 }
516 
517 void avrcp_browsing_controller_register_packet_handler(btstack_packet_handler_t callback){
518     btstack_assert(callback != NULL);
519     avrcp_controller_context.browsing_avrcp_callback = callback;
520 }
521 
522 uint8_t avrcp_browsing_controller_connect(bd_addr_t bd_addr, uint8_t * ertm_buffer, uint32_t size, l2cap_ertm_config_t * ertm_config, uint16_t * avrcp_browsing_cid){
523     return avrcp_browsing_connect(bd_addr, AVRCP_CONTROLLER, avrcp_browsing_controller_packet_handler, ertm_buffer, size, ertm_config, avrcp_browsing_cid);
524 }
525 
526 uint8_t avrcp_browsing_controller_disconnect(uint16_t avrcp_browsing_cid){
527     return avrcp_browsing_disconnect(avrcp_browsing_cid, AVRCP_CONTROLLER);
528 }
529 
530 uint8_t avrcp_browsing_controller_configure_incoming_connection(uint16_t avrcp_browsing_cid, uint8_t * ertm_buffer, uint32_t size, l2cap_ertm_config_t * ertm_config){
531     avrcp_connection_t * avrcp_connection = get_avrcp_connection_for_browsing_cid_for_role(AVRCP_CONTROLLER, avrcp_browsing_cid);
532     if (!avrcp_connection){
533         log_error("avrcp_browsing_controller_decline_incoming_connection: could not find a connection.");
534         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
535     }
536     if (!avrcp_connection->browsing_connection){
537         log_error("avrcp_browsing_controller_decline_incoming_connection: no browsing connection.");
538         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
539     }
540 
541     if (avrcp_connection->browsing_connection->state != AVCTP_CONNECTION_W4_ERTM_CONFIGURATION){
542         log_error("avrcp_browsing_controller_decline_incoming_connection: browsing connection in a wrong state.");
543         return ERROR_CODE_COMMAND_DISALLOWED;
544     }
545 
546     avrcp_connection->browsing_connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED;
547     avrcp_connection->browsing_connection->ertm_buffer = ertm_buffer;
548     avrcp_connection->browsing_connection->ertm_buffer_size = size;
549     (void)memcpy(&avrcp_connection->browsing_connection->ertm_config,
550                  ertm_config, sizeof(l2cap_ertm_config_t));
551     l2cap_accept_ertm_connection(avrcp_connection->browsing_connection->l2cap_browsing_cid, &avrcp_connection->browsing_connection->ertm_config, avrcp_connection->browsing_connection->ertm_buffer, avrcp_connection->browsing_connection->ertm_buffer_size);
552     return ERROR_CODE_SUCCESS;
553 }
554 
555 uint8_t avrcp_browsing_controller_decline_incoming_connection(uint16_t avrcp_browsing_cid){
556     avrcp_connection_t * avrcp_connection = get_avrcp_connection_for_browsing_cid_for_role(AVRCP_CONTROLLER, avrcp_browsing_cid);
557     if (!avrcp_connection){
558         log_error("avrcp_browsing_controller_decline_incoming_connection: could not find a connection.");
559         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
560     }
561     if (!avrcp_connection->browsing_connection) return ERROR_CODE_SUCCESS;
562     if (avrcp_connection->browsing_connection->state > AVCTP_CONNECTION_W4_ERTM_CONFIGURATION) return ERROR_CODE_COMMAND_DISALLOWED;
563 
564     l2cap_decline_connection(avrcp_connection->browsing_connection->l2cap_browsing_cid);
565     // free connection
566     btstack_memory_avrcp_browsing_connection_free(avrcp_connection->browsing_connection);
567     avrcp_connection->browsing_connection = NULL;
568     return ERROR_CODE_SUCCESS;
569 }
570 
571 uint8_t avrcp_browsing_controller_get_item_attributes_for_scope(uint16_t avrcp_browsing_cid, uint8_t * uid, uint16_t uid_counter, uint32_t attr_bitmap, avrcp_browsing_scope_t scope){
572     avrcp_connection_t * avrcp_connection = get_avrcp_connection_for_browsing_cid_for_role(AVRCP_CONTROLLER, avrcp_browsing_cid);
573     if (!avrcp_connection){
574         log_error("avrcp_browsing_controller_get_item_attributes: could not find a connection.");
575         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
576     }
577     avrcp_browsing_connection_t * connection = avrcp_connection->browsing_connection;
578     if (connection->state != AVCTP_CONNECTION_OPENED){
579         log_error("avrcp_browsing_controller_get_item_attributes: connection in wrong state %d, expected %d.", connection->state, AVCTP_CONNECTION_OPENED);
580         return ERROR_CODE_COMMAND_DISALLOWED;
581     }
582 
583     connection->get_item_attributes = 1;
584     connection->scope = scope;
585     (void)memcpy(connection->folder_uid, uid, 8);
586     connection->uid_counter = uid_counter;
587     connection->attr_bitmap = attr_bitmap;
588 
589     avrcp_request_can_send_now(avrcp_connection, connection->l2cap_browsing_cid);
590     return ERROR_CODE_SUCCESS;
591 }
592 
593 /**
594  * @brief Retrieve a listing of the contents of a folder.
595  * @param scope    0-player list, 1-virtual file system, 2-search, 3-now playing
596  * @param start_item
597  * @param end_item
598  * @param attribute_count
599  * @param attribute_list
600  **/
601 static uint8_t avrcp_browsing_controller_get_folder_items(uint16_t avrcp_browsing_cid, avrcp_browsing_scope_t scope, uint32_t start_item, uint32_t end_item, uint32_t attr_bitmap){
602     avrcp_connection_t * avrcp_connection = get_avrcp_connection_for_browsing_cid_for_role(AVRCP_CONTROLLER, avrcp_browsing_cid);
603     if (!avrcp_connection){
604         log_error("avrcp_browsing_controller_disconnect: could not find a connection.");
605         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
606     }
607     avrcp_browsing_connection_t * connection = avrcp_connection->browsing_connection;
608     if (connection->state != AVCTP_CONNECTION_OPENED) {
609         log_error("avrcp_browsing_controller_get_folder_items: connection in wrong state %d, expected %d.", connection->state, AVCTP_CONNECTION_OPENED);
610         return ERROR_CODE_COMMAND_DISALLOWED;
611     }
612 
613     connection->get_folder_items = 1;
614     connection->scope = scope;
615     connection->start_item = start_item;
616     connection->end_item = end_item;
617     connection->attr_bitmap = attr_bitmap;
618 
619     avrcp_request_can_send_now(avrcp_connection, connection->l2cap_browsing_cid);
620     return ERROR_CODE_SUCCESS;
621 }
622 
623 uint8_t avrcp_browsing_controller_get_media_players(uint16_t avrcp_browsing_cid, uint32_t start_item, uint32_t end_item, uint32_t attr_bitmap){
624     return avrcp_browsing_controller_get_folder_items(avrcp_browsing_cid, AVRCP_BROWSING_MEDIA_PLAYER_LIST, start_item, end_item, attr_bitmap);
625 }
626 
627 uint8_t avrcp_browsing_controller_browse_file_system(uint16_t avrcp_browsing_cid, uint32_t start_item, uint32_t end_item, uint32_t attr_bitmap){
628     // return avrcp_browsing_controller_get_folder_items(avrcp_browsing_cid, 1, 0, 0xFFFFFFFF, attr_bitmap);
629     return avrcp_browsing_controller_get_folder_items(avrcp_browsing_cid, AVRCP_BROWSING_MEDIA_PLAYER_VIRTUAL_FILESYSTEM, start_item, end_item, attr_bitmap);
630 }
631 
632 uint8_t avrcp_browsing_controller_browse_media(uint16_t avrcp_browsing_cid, uint32_t start_item, uint32_t end_item, uint32_t attr_bitmap){
633     // return avrcp_browsing_controller_get_folder_items(avrcp_browsing_cid, 2, 0, 0xFFFFFFFF, 0, NULL);
634     return avrcp_browsing_controller_get_folder_items(avrcp_browsing_cid, AVRCP_BROWSING_SEARCH, start_item, end_item, attr_bitmap);
635 }
636 
637 uint8_t avrcp_browsing_controller_browse_now_playing_list(uint16_t avrcp_browsing_cid, uint32_t start_item, uint32_t end_item, uint32_t attr_bitmap){
638     return avrcp_browsing_controller_get_folder_items(avrcp_browsing_cid, AVRCP_BROWSING_NOW_PLAYING, start_item, end_item, attr_bitmap);
639 }
640 
641 
642 uint8_t avrcp_browsing_controller_set_browsed_player(uint16_t avrcp_browsing_cid, uint16_t browsed_player_id){
643     avrcp_connection_t * avrcp_connection = get_avrcp_connection_for_browsing_cid_for_role(AVRCP_CONTROLLER, avrcp_browsing_cid);
644     if (!avrcp_connection){
645         log_error("avrcp_browsing_controller_change_path: could not find a connection.");
646         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
647     }
648 
649     avrcp_browsing_connection_t * connection = avrcp_connection->browsing_connection;
650     if (connection->state != AVCTP_CONNECTION_OPENED){
651         log_error("avrcp_browsing_controller_change_path: connection in wrong state.");
652         return ERROR_CODE_COMMAND_DISALLOWED;
653     }
654 
655     connection->set_browsed_player_id = 1;
656     connection->browsed_player_id = browsed_player_id;
657     avrcp_request_can_send_now(avrcp_connection, connection->l2cap_browsing_cid);
658     return ERROR_CODE_SUCCESS;
659 }
660 
661 /**
662  * @brief Retrieve a listing of the contents of a folder.
663  * @param direction     0-folder up, 1-folder down
664  * @param folder_uid    8 bytes long
665  **/
666 uint8_t avrcp_browsing_controller_change_path(uint16_t avrcp_browsing_cid, uint8_t direction, uint8_t * folder_uid){
667     avrcp_connection_t * avrcp_connection = get_avrcp_connection_for_browsing_cid_for_role(AVRCP_CONTROLLER, avrcp_browsing_cid);
668     if (!avrcp_connection){
669         log_error("avrcp_browsing_controller_change_path: could not find a connection.");
670         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
671     }
672 
673     avrcp_browsing_connection_t * connection = avrcp_connection->browsing_connection;
674 
675     if ((connection == NULL) || (connection->state != AVCTP_CONNECTION_OPENED)){
676         log_error("avrcp_browsing_controller_change_path: connection in wrong state.");
677         return ERROR_CODE_COMMAND_DISALLOWED;
678     }
679 
680     if (!connection->browsed_player_id){
681         log_error("avrcp_browsing_controller_change_path: no browsed player set.");
682         return ERROR_CODE_COMMAND_DISALLOWED;
683     }
684     connection->change_path = 1;
685     connection->direction = direction;
686     memset(connection->folder_uid, 0, 8);
687     if (folder_uid){
688         (void)memcpy(connection->folder_uid, folder_uid, 8);
689     }
690 
691     avrcp_request_can_send_now(avrcp_connection, connection->l2cap_browsing_cid);
692     return ERROR_CODE_SUCCESS;
693 }
694 
695 uint8_t avrcp_browsing_controller_go_up_one_level(uint16_t avrcp_browsing_cid){
696     return avrcp_browsing_controller_change_path(avrcp_browsing_cid, 0, NULL);
697 }
698 
699 uint8_t avrcp_browsing_controller_go_down_one_level(uint16_t avrcp_browsing_cid, uint8_t * folder_uid){
700     return avrcp_browsing_controller_change_path(avrcp_browsing_cid, 1, folder_uid);
701 }
702 
703 uint8_t avrcp_browsing_controller_search(uint16_t avrcp_browsing_cid, uint16_t search_str_len, char * search_str){
704     avrcp_connection_t * avrcp_connection = get_avrcp_connection_for_browsing_cid_for_role(AVRCP_CONTROLLER, avrcp_browsing_cid);
705     if (!avrcp_connection){
706         log_error("avrcp_browsing_controller_change_path: could not find a connection.");
707         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
708     }
709 
710     avrcp_browsing_connection_t * connection = avrcp_connection->browsing_connection;
711 
712     if ((connection == NULL) || (connection->state != AVCTP_CONNECTION_OPENED)){
713         log_error("avrcp_browsing_controller_change_path: connection in wrong state.");
714         return ERROR_CODE_COMMAND_DISALLOWED;
715     }
716 
717     if (!connection->browsed_player_id){
718         log_error("avrcp_browsing_controller_change_path: no browsed player set.");
719         return ERROR_CODE_COMMAND_DISALLOWED;
720     }
721     if (!search_str || (search_str_len == 0)){
722         return AVRCP_BROWSING_ERROR_CODE_INVALID_COMMAND;
723     }
724 
725     connection->search = 1;
726 
727     connection->search_str_len = btstack_min(search_str_len, sizeof(connection->search_str)-1);
728     memset(connection->search_str, 0, sizeof(connection->search_str));
729     (void)memcpy(connection->search_str, search_str,
730                  connection->search_str_len);
731     avrcp_request_can_send_now(avrcp_connection, connection->l2cap_browsing_cid);
732     return ERROR_CODE_SUCCESS;
733 }
734 
735 uint8_t avrcp_browsing_controller_get_total_nr_items_for_scope(uint16_t avrcp_browsing_cid, avrcp_browsing_scope_t scope){
736     avrcp_connection_t * avrcp_connection = get_avrcp_connection_for_browsing_cid_for_role(AVRCP_CONTROLLER, avrcp_browsing_cid);
737     if (!avrcp_connection){
738         log_error("avrcp_browsing_controller_change_path: could not find a connection.");
739         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
740     }
741 
742     avrcp_browsing_connection_t * connection = avrcp_connection->browsing_connection;
743 
744     if ((connection == NULL) || (connection->state != AVCTP_CONNECTION_OPENED)){
745         log_error("avrcp_browsing_controller_change_path: connection in wrong state.");
746         return ERROR_CODE_COMMAND_DISALLOWED;
747     }
748 
749     if (!connection->browsed_player_id){
750         log_error("avrcp_browsing_controller_change_path: no browsed player set.");
751         return ERROR_CODE_COMMAND_DISALLOWED;
752     }
753     connection->get_total_nr_items = 1;
754     connection->get_total_nr_items_scope = scope;
755     avrcp_request_can_send_now(avrcp_connection, connection->l2cap_browsing_cid);
756     return ERROR_CODE_SUCCESS;
757 }
758