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
avrcp_browsing_controller_send_get_folder_items_cmd(uint16_t cid,avrcp_browsing_connection_t * connection)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_NUM)-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
avrcp_browsing_controller_send_get_item_attributes_cmd(uint16_t cid,avrcp_browsing_connection_t * connection)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_NUM)-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->item_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
avrcp_browsing_controller_send_change_path_cmd(uint16_t cid,avrcp_browsing_connection_t * connection)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->item_uid, 8);
168 pos += 8;
169 return l2cap_send(cid, command, pos);
170 }
171
avrcp_browsing_controller_send_search_cmd(uint16_t cid,avrcp_browsing_connection_t * connection)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
avrcp_browsing_controller_send_set_browsed_player_cmd(uint16_t cid,avrcp_browsing_connection_t * connection)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
avrcp_browsing_controller_send_get_total_nr_items_cmd(uint16_t cid,avrcp_browsing_connection_t * connection)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
avrcp_browsing_controller_handle_can_send_now(avrcp_browsing_connection_t * connection)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
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 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
avrcp_parser_reset(avrcp_browsing_connection_t * connection)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
avrcp_browsing_parser_process_byte(uint8_t byte,avrcp_browsing_connection_t * connection)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
avrcp_browsing_parse_and_emit_element_attrs(uint8_t * packet,uint16_t num_bytes_to_read,avrcp_browsing_connection_t * connection)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
avrcp_browsing_controller_emit_failed(btstack_packet_handler_t callback,uint16_t browsing_cid,uint8_t browsing_status,uint8_t bluetooth_status)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
avrcp_browsing_controller_packet_handler(uint8_t packet_type,uint16_t channel,uint8_t * packet,uint16_t size)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
avrcp_browsing_controller_init(void)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
avrcp_browsing_controller_deinit(void)522 void avrcp_browsing_controller_deinit(void){
523 avrcp_controller_context.browsing_packet_handler = NULL;
524 }
525
avrcp_browsing_controller_register_packet_handler(btstack_packet_handler_t callback)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
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)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->item_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 **/
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)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
avrcp_browsing_controller_get_media_players(uint16_t avrcp_browsing_cid,uint32_t start_item,uint32_t end_item,uint32_t attr_bitmap)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
avrcp_browsing_controller_browse_file_system(uint16_t avrcp_browsing_cid,uint32_t start_item,uint32_t end_item,uint32_t attr_bitmap)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
avrcp_browsing_controller_browse_media(uint16_t avrcp_browsing_cid,uint32_t start_item,uint32_t end_item,uint32_t attr_bitmap)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
avrcp_browsing_controller_browse_now_playing_list(uint16_t avrcp_browsing_cid,uint32_t start_item,uint32_t end_item,uint32_t attr_bitmap)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
avrcp_browsing_controller_set_browsed_player(uint16_t avrcp_browsing_cid,uint16_t browsed_player_id)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 **/
avrcp_browsing_controller_change_path(uint16_t avrcp_browsing_cid,uint8_t direction,uint8_t * folder_uid)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->item_uid, 0, 8);
647 if (folder_uid){
648 (void)memcpy(connection->item_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
avrcp_browsing_controller_go_up_one_level(uint16_t avrcp_browsing_cid)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
avrcp_browsing_controller_go_down_one_level(uint16_t avrcp_browsing_cid,uint8_t * folder_uid)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
avrcp_browsing_controller_search(uint16_t avrcp_browsing_cid,uint16_t search_str_len,char * search_str)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
avrcp_browsing_controller_get_total_nr_items_for_scope(uint16_t avrcp_browsing_cid,avrcp_browsing_scope_t scope)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