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