avrcp browsing controller: adding now playing functionality

This commit is contained in:
Milanka Ringwald 2018-04-11 15:21:05 +02:00
parent 5c4bbc4e0f
commit 4614c04963
7 changed files with 136 additions and 71 deletions

View File

@ -106,7 +106,7 @@ typedef enum {
#define AVRCP_BROWSING_MAX_NUM_ATTR_IDS 8
typedef enum {
AVRCP_MEDIA_ATTR_ALL = 0,
AVRCP_MEDIA_ATTR_ALL = 0x00000000,
AVRCP_MEDIA_ATTR_TITLE,
AVRCP_MEDIA_ATTR_ARTIST,
AVRCP_MEDIA_ATTR_ALBUM,

View File

@ -41,7 +41,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include "btstack.h"
#include "classic/avrcp.h"
#include "classic/avrcp_browsing_controller.h"
@ -608,8 +608,6 @@ static void avrcp_browsing_controller_packet_handler(uint8_t packet_type, uint16
avrcp_browsing_controller_emit_failed(avrcp_controller_context.browsing_avrcp_callback, channel, browsing_connection->browsing_status, ERROR_CODE_SUCCESS);
return;
}
browsing_connection->uid_counter = big_endian_read_16(packet, pos);
pos += 2;
break;
default:
break;
@ -630,6 +628,8 @@ static void avrcp_browsing_controller_packet_handler(uint8_t packet_type, uint16
break;
}
case AVRCP_PDU_ID_SET_BROWSED_PLAYER:{
browsing_connection->uid_counter = big_endian_read_16(packet, pos);
pos += 2;
// uint32_t num_items = big_endian_read_32(packet, pos);
pos += 4;
// uint16_t charset = big_endian_read_16(packet, pos);
@ -652,6 +652,8 @@ static void avrcp_browsing_controller_packet_handler(uint8_t packet_type, uint16
case AVRCP_SINGLE_PACKET:
case AVRCP_START_PACKET:
avrcp_parser_reset(browsing_connection);
browsing_connection->uid_counter = big_endian_read_16(packet, pos);
pos += 2;
browsing_connection->num_items = big_endian_read_16(packet, pos); //num_items
pos += 2;
avrcp_browsing_parse_and_emit_element_attrs(packet+pos, size-pos, browsing_connection);
@ -670,12 +672,19 @@ static void avrcp_browsing_controller_packet_handler(uint8_t packet_type, uint16
}
case AVRCP_PDU_ID_SEARCH:{
uint32_t num_items = big_endian_read_32(packet, pos);
printf("TODO: send as event, search found %d items\n", num_items);
break;
}
browsing_connection->uid_counter = big_endian_read_16(packet, pos);
pos += 2;
uint32_t num_items = big_endian_read_32(packet, pos);
printf("TODO: send as event, search found %d items\n", num_items);
break;
}
case AVRCP_PDU_ID_GET_ITEM_ATTRIBUTES:
packet[pos-1] = AVRCP_BROWSING_MEDIA_ELEMENT_ITEM_ATTRIBUTE;
(*avrcp_controller_context.browsing_avrcp_callback)(AVRCP_BROWSING_DATA_PACKET, channel, packet+pos-1, size - pos + 1);
break;
default:
printf(" not parsed\n");
printf(" not parsed pdu ID 0x%02x\n", browsing_connection->pdu_id);
break;
}
@ -779,18 +788,15 @@ uint8_t avrcp_avrcp_browsing_decline_incoming_connection(uint16_t avrcp_browsing
return ERROR_CODE_SUCCESS;
}
static uint8_t avrcp_browsing_controller_get_item_attributes(uint16_t avrcp_browsing_cid, avrcp_browsing_scope_t scope, uint8_t * uid, uint16_t uid_counter, uint32_t attr_bitmap){
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){
avrcp_connection_t * avrcp_connection = get_avrcp_connection_for_browsing_cid(avrcp_browsing_cid, &avrcp_controller_context);
printf("avrcp_browsing_controller_get_item_attributes \n");
if (!avrcp_connection){
log_error("avrcp_browsing_controller_get_item_attributes: could not find a connection.");
printf("avrcp_browsing_controller_get_item_attributes: : could not find a connection \n");
return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
}
avrcp_browsing_connection_t * connection = avrcp_connection->browsing_connection;
if (connection->state != AVCTP_CONNECTION_OPENED){
log_error("avrcp_browsing_controller_get_item_attributes: connection in wrong state %d, expected %d.", connection->state, AVCTP_CONNECTION_OPENED);
printf("avrcp_browsing_controller_get_item_attributes: : connection in wrong state %d, expected %d\n", connection->state, AVCTP_CONNECTION_OPENED);
return ERROR_CODE_COMMAND_DISALLOWED;
}
@ -804,11 +810,6 @@ static uint8_t avrcp_browsing_controller_get_item_attributes(uint16_t avrcp_brow
return ERROR_CODE_SUCCESS;
}
uint8_t avrcp_browsing_controller_get_item_attributes_with_virtual_file_system_scope(uint16_t avrcp_browsing_cid, uint8_t * uid, uint16_t uid_counter, uint32_t attr_bitmap){
return avrcp_browsing_controller_get_item_attributes(avrcp_browsing_cid, AVRCP_BROWSING_MEDIA_PLAYER_VIRTUAL_FILESYSTEM, uid, uid_counter, attr_bitmap);
}
/**
* @brief Retrieve a listing of the contents of a folder.
* @param scope 0-player list, 1-virtual file system, 2-search, 3-now playing
@ -952,7 +953,7 @@ uint8_t avrcp_browsing_controller_search(uint16_t avrcp_browsing_cid, uint16_t s
return ERROR_CODE_SUCCESS;
}
uint8_t avrcp_browsing_controller_get_total_nr_items(uint16_t avrcp_browsing_cid, avrcp_browsing_scope_t scope){
uint8_t avrcp_browsing_controller_get_total_nr_items_for_scope(uint16_t avrcp_browsing_cid, avrcp_browsing_scope_t scope){
avrcp_connection_t * avrcp_connection = get_avrcp_connection_for_browsing_cid(avrcp_browsing_cid, &avrcp_controller_context);
if (!avrcp_connection){
log_error("avrcp_browsing_controller_change_path: could not find a connection.");

View File

@ -58,7 +58,8 @@ typedef enum {
AVRCP_BROWSING_MEDIA_PLAYER_ITEM = 0x01,
AVRCP_BROWSING_FOLDER_ITEM,
AVRCP_BROWSING_MEDIA_ELEMENT_ITEM,
AVRCP_BROWSING_MEDIA_ROOT_FOLDER
AVRCP_BROWSING_MEDIA_ROOT_FOLDER,
AVRCP_BROWSING_MEDIA_ELEMENT_ITEM_ATTRIBUTE
} avrcp_browsing_item_type_t;
typedef enum {
@ -189,12 +190,14 @@ uint8_t avrcp_browsing_controller_set_browsed_player(uint16_t avrcp_browsing_cid
/**
* @brief Get total num attributes
* @param avrcp_browsing_cid
* @param scope
*/
uint8_t avrcp_browsing_controller_get_total_nr_items(uint16_t avrcp_browsing_cid, avrcp_browsing_scope_t scope);
uint8_t avrcp_browsing_controller_get_total_nr_items_for_scope(uint16_t avrcp_browsing_cid, avrcp_browsing_scope_t scope);
/**
* @brief Navigate one level up or down in thhe virtual filesystem. Requires that s browsed player is set.
* @param avrcp_browsing_cid
* @param direction 0-folder up, 1-folder down
* @param folder_uid 8 bytes long
**/
@ -203,7 +206,15 @@ uint8_t avrcp_browsing_controller_go_up_one_level(uint16_t avrcp_browsing_cid);
uint8_t avrcp_browsing_controller_go_down_one_level(uint16_t avrcp_browsing_cid, uint8_t * folder_uid);
uint8_t avrcp_browsing_controller_get_item_attributes_with_virtual_file_system_scope(uint16_t avrcp_browsing_cid, uint8_t * uid, uint16_t uid_counter, uint32_t attr_bitmap);
/**
* @brief Retrives metadata information (title, artist, album, ...) about a media element with given uid.
* @param avrcp_browsing_cid
* @param uid media element uid
* @param uid_counter Used to detect change to the media database on target device. A TG device that supports the UID Counter shall update the value of the counter on each change to the media database.
* @param attr_bitmap 0x00000000 - retrieve all, chek avrcp_media_attribute_id_t in avrcp.h for detailed bit position description.
* @param scope check avrcp_browsing_scope_t in avrcp.h
**/
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);
/**
* @brief Searches are performed from the current folder in the Browsed Players virtual filesystem. The search applies to the current folder and all folders below that.

View File

@ -673,6 +673,20 @@ static void avrcp_handle_l2cap_data_packet_for_signaling_connection(avrcp_connec
(*avrcp_controller_context.avrcp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
break;
}
case AVRCP_NOTIFICATION_EVENT_UIDS_CHANGED:{
uint8_t event[7];
int offset = 0;
event[offset++] = HCI_EVENT_AVRCP_META;
event[offset++] = sizeof(event) - 2;
event[offset++] = AVRCP_NOTIFICATION_EVENT_UIDS_CHANGED;
little_endian_store_16(event, offset, connection->avrcp_cid);
offset += 2;
event[offset++] = ctype;
event[offset++] = packet[pos++] & 0x7F;
(*avrcp_controller_context.avrcp_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
break;
}
// case AVRCP_NOTIFICATION_EVENT_PLAYER_APPLICATION_SETTING_CHANGED:{
// uint8_t num_PlayerApplicationSettingAttributes = packet[pos++];
// int i;
@ -1222,7 +1236,7 @@ uint8_t avrcp_controller_disconnect(uint16_t avrcp_cid){
return ERROR_CODE_SUCCESS;
}
uint8_t avrcp_controller_play_item(uint16_t avrcp_cid, avrcp_browsing_scope_t scope, uint8_t * uid, uint16_t uid_counter){
uint8_t avrcp_controller_play_item_for_scope(uint16_t avrcp_cid, uint8_t * uid, uint16_t uid_counter, avrcp_browsing_scope_t scope){
avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_controller_context);
if (!connection){
log_error("avrcp_controller_play_item: could not find a connection.");

View File

@ -297,12 +297,11 @@ uint8_t avrcp_controller_set_repeat_mode(uint16_t avrcp_cid, avrcp_repeat_mode_t
/**
* @brief The PlayItem command starts playing an item indicated by the UID. It is routed to the Addressed Player.
* @param avrcp_cid
* @param scope
* @param uid
* @param uid_counter
* @return status
* @param scope
**/
uint8_t avrcp_controller_play_item(uint16_t avrcp_cid, avrcp_browsing_scope_t scope, uint8_t * uid, uint16_t uid_counter);
uint8_t avrcp_controller_play_item_for_scope(uint16_t avrcp_cid, uint8_t * uid, uint16_t uid_counter, avrcp_browsing_scope_t scope);
/**
* @brief Set addressed player.

View File

@ -64,7 +64,7 @@ int avrcp_media_item_iterator_has_more(const avrcp_media_item_context_t * conte
void avrcp_media_item_iterator_next(avrcp_media_item_context_t * context){
int chunk_len = big_endian_read_16(context->data, context->offset + 6);
int new_offset = context->offset + 1 + chunk_len;
int new_offset = context->offset + 2 + 2 + 4 + chunk_len;
// avoid uint8_t overrun
if (new_offset > 0xffff){
new_offset = 0xffff;

View File

@ -244,9 +244,9 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe
}
case AVRCP_BROWSING_MEDIA_ELEMENT_ITEM:{
printf("Received media element item UID: ");
int index = next_media_element_item_index();
memcpy(media_element_items[index].uid, packet+pos, 8);
printf("Received media element item UID (index %d): ", index);
uint32_t media_uid_high = big_endian_read_32(packet, pos);
pos += 4;
@ -269,21 +269,35 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe
// printf("Media UID: 0x%08" PRIx32 "%08" PRIx32 ", media_type 0x%02x, charset 0x%02x, actual len %d, name %s\n", media_uid_high, media_uid_low, media_type, charset, value_len, value);
printf_hexdump(media_element_items[index].uid, 8);
printf("media_type 0x%02x, charset 0x%02x, actual len %d, name %s\n", media_type, charset, value_len, value);
uint8_t num_attributes = packet[pos++];
// printf("Num media attributes %d\n", num_attributes);
// for (avrcp_media_item_iterator_init(&media_item_context, size-pos, packet+pos); avrcp_media_item_iterator_has_more(&media_item_context); avrcp_media_item_iterator_next(&media_item_context)){
// uint32_t attr_id = avrcp_media_item_iterator_get_attr_id(&media_item_context);
// uint16_t attr_charset = avrcp_media_item_iterator_get_attr_charset(&media_item_context);
// uint16_t attr_value_length = avrcp_media_item_iterator_get_attr_value_len(&media_item_context);
// const uint8_t * attr_value = avrcp_media_item_iterator_get_attr_value(&media_item_context);
printf(" Media type 0x%02x, charset 0x%02x, actual len %d, name %s, num attributes %d:\n", media_type, charset, value_len, value, num_attributes);
// // printf("Attr ID 0x%08" PRIx32 ", charset %d, attr_value_length %d, value %s", attr_id, attr_charset, attr_value_length, attr_value);
// }
avrcp_media_item_context_t media_item_context;
for (avrcp_media_item_iterator_init(&media_item_context, size-pos, packet+pos); avrcp_media_item_iterator_has_more(&media_item_context); avrcp_media_item_iterator_next(&media_item_context)){
uint32_t attr_id = avrcp_media_item_iterator_get_attr_id(&media_item_context);
uint16_t attr_charset = avrcp_media_item_iterator_get_attr_charset(&media_item_context);
uint16_t attr_value_length = avrcp_media_item_iterator_get_attr_value_len(&media_item_context);
const uint8_t * attr_value = avrcp_media_item_iterator_get_attr_value(&media_item_context);
printf(" - attr ID 0x%08" PRIx32 ", charset 0x%02x, actual len %d, name %s\n", attr_id, attr_charset, attr_value_length, attr_value);
}
break;
}
case AVRCP_BROWSING_MEDIA_ELEMENT_ITEM_ATTRIBUTE:{
uint8_t num_attributes = packet[pos++];
printf("Num media attributes %d:\n", num_attributes);
avrcp_media_item_context_t media_item_context;
for (avrcp_media_item_iterator_init(&media_item_context, size-pos, packet+pos); avrcp_media_item_iterator_has_more(&media_item_context); avrcp_media_item_iterator_next(&media_item_context)){
uint32_t attr_id = avrcp_media_item_iterator_get_attr_id(&media_item_context);
uint16_t attr_charset = avrcp_media_item_iterator_get_attr_charset(&media_item_context);
uint16_t attr_value_length = avrcp_media_item_iterator_get_attr_value_len(&media_item_context);
uint8_t * attr_value = avrcp_media_item_iterator_get_attr_value(&media_item_context);
attr_value[attr_value_length] = 0;
printf(" - attr ID 0x%08" PRIx32 ", charset 0x%02x, actual len %d, name %s\n", attr_id, attr_charset, attr_value_length, attr_value);
}
}
default:
printf("AVRCP browsing: unknown browsable item type 0%02x\n", data_type);
break;
@ -535,20 +549,29 @@ static void show_usage(void){
printf("pp - get media players. Browsing cid 0x%02X\n", browsing_cid);
printf("pI - Set addressed player\n");
printf("pO - Set browsed player\n");
printf("pQ - browse folders\n");
printf("pP - browse media items\n");
printf("pW - go up one level\n");
printf("pT - go down one level of %s\n", (char *)parent_folder_name);
printf("pi - Play item %s, MEDIA_PLAYER_VIRTUAL_FILESYSTEM\n", (char *)parent_folder_name);
printf("pQ - browse folders\n");
printf("pP - browse media items\n");
printf("pj - browse now playing items\n");
printf("pn - search 3\n");
printf("ps - browse search folder\n");
printf("pt - Play item %s, AVRCP_BROWSING_SEARCH\n", (char *)parent_folder_name);
printf("pl - Get total num items in MEDIA_PLAYER_LIST\n");
printf("pn - search 3\n");
printf("pm - Set max num fragments to 0x02\n");
printf("pM - Set max num fragments to 0xFF\n");
printf("pv - Get item attributes with virtual file system scope\n");
printf("p1 - Get item attributes of first media element for virtual file system scope\n");
printf("p2 - Get item attributes of first media element for now playing scope\n");
printf("pl - Get total num items for media player list scope\n");
printf("pL - Get total num items for now playing scope\n");
printf("pi - Play first media item %s for virtual filesystem scope \n", (char *)parent_folder_name);
printf("pt - Play first media item %s for search scope \n", (char *)parent_folder_name);
printf("pr - Play first media item %s for now playing scope\n", (char *)parent_folder_name);
printf("Ctrl-c - exit\n");
printf("---\n");
}
@ -860,15 +883,7 @@ static void stdin_process(char * cmd, int size){
status = avrcp_browsing_controller_go_down_one_level(browsing_cid, parent_folder_uid);
folder_index = -1;
break;
case 'i':
printf("Play item %s, MEDIA_PLAYER_VIRTUAL_FILESYSTEM\n", (char *)parent_folder_name);
if (media_element_item_index < 0){
printf("AVRCP Browsing: no media items found\n");
break;
}
// printf_hexdump(media_element_items[0].uid, 8);
status = avrcp_controller_play_item(avrcp_cid, AVRCP_BROWSING_MEDIA_PLAYER_VIRTUAL_FILESYSTEM, media_element_items[0].uid, media_element_item_index);
break;
case 'j':
printf("AVRCP Browsing: browse now playing items\n");
playable_folder_index = 0;
@ -884,19 +899,6 @@ static void stdin_process(char * cmd, int size){
media_element_item_index = -1;
status = avrcp_browsing_controller_browse_media(browsing_cid, 0, 0xFFFFFFFF, AVRCP_MEDIA_ATTR_ALL);
break;
case 't':
printf("Play item %s, AVRCP_BROWSING_SEARCH\n", (char *)parent_folder_name);
if (media_element_item_index < 0){
printf("AVRCP Browsing: no media items found\n");
break;
}
// printf_hexdump(media_element_items[0].uid, 8);
status = avrcp_controller_play_item(avrcp_cid, AVRCP_BROWSING_SEARCH, media_element_items[0].uid, media_element_item_index);
break;
case 'l':
printf("Get total num items in MEDIA_PLAYER_LIST\n");
status = avrcp_browsing_controller_get_total_nr_items(browsing_cid, AVRCP_BROWSING_MEDIA_PLAYER_LIST);
break;
case 'm':
printf("Set max num fragments to 0x02\n");
status = avrcp_controller_set_max_num_fragments(avrcp_cid, 0x02);
@ -920,13 +922,51 @@ static void stdin_process(char * cmd, int size){
folder_index = -1;
break;
case '1':
printf("Get item attributes with virtual file system scope, counter %d, scope %d\n", browsing_uid_counter, AVRCP_BROWSING_MEDIA_PLAYER_VIRTUAL_FILESYSTEM);
avrcp_browsing_controller_get_item_attributes_with_virtual_file_system_scope(browsing_cid, media_element_items[0].uid, browsing_uid_counter, 1 << AVRCP_MEDIA_ATTR_TITLE);
printf("Get item attributes of first media item for virtual file system scope\n");
avrcp_browsing_controller_get_item_attributes_for_scope(browsing_cid, media_element_items[0].uid, browsing_uid_counter, 1 << AVRCP_MEDIA_ATTR_TITLE, AVRCP_BROWSING_MEDIA_PLAYER_VIRTUAL_FILESYSTEM);
break;
case '2':
printf("Get item attributes with virtual file system scope, counter %d, scope %d\n", browsing_uid_counter, AVRCP_BROWSING_MEDIA_PLAYER_VIRTUAL_FILESYSTEM);
avrcp_browsing_controller_get_item_attributes_with_virtual_file_system_scope(browsing_cid, media_element_items[1].uid, browsing_uid_counter, 1 << AVRCP_MEDIA_ATTR_TITLE);
printf("Get item attributes of first media item for now playing scope\n");
avrcp_browsing_controller_get_item_attributes_for_scope(browsing_cid, media_element_items[0].uid, browsing_uid_counter, 1 << AVRCP_MEDIA_ATTR_TITLE, AVRCP_BROWSING_NOW_PLAYING);
break;
case 'l':
printf("Get total num items for media player list scope\n");
status = avrcp_browsing_controller_get_total_nr_items_for_scope(browsing_cid, AVRCP_BROWSING_MEDIA_PLAYER_LIST);
break;
case 'L':
printf("Get total num items for now playing scope.\n");
status = avrcp_browsing_controller_get_total_nr_items_for_scope(browsing_cid, AVRCP_BROWSING_NOW_PLAYING);
break;
case 'i':
printf("Play first media item %s for virtual filesystem scope\n", (char *)parent_folder_name);
if (media_element_item_index < 0){
printf("AVRCP Browsing: no media items found\n");
break;
}
// printf_hexdump(media_element_items[0].uid, 8);
status = avrcp_controller_play_item_for_scope(avrcp_cid, media_element_items[0].uid, media_element_item_index, AVRCP_BROWSING_MEDIA_PLAYER_VIRTUAL_FILESYSTEM);
break;
case 't':
printf("Play first media item %s for search scope\n", (char *)parent_folder_name);
if (media_element_item_index < 0){
printf("AVRCP Browsing: no media items found\n");
break;
}
// printf_hexdump(media_element_items[0].uid, 8);
status = avrcp_controller_play_item_for_scope(avrcp_cid, media_element_items[0].uid, media_element_item_index, AVRCP_BROWSING_SEARCH);
break;
case 'r':
printf("Play first media item %s for now playing scope\n", (char *)parent_folder_name);
if (media_element_item_index < 0){
printf("AVRCP Browsing: no media items found\n");
break;
}
// printf_hexdump(media_element_items[0].uid, 8);
status = avrcp_controller_play_item_for_scope(avrcp_cid, media_element_items[0].uid, media_element_item_index, AVRCP_BROWSING_NOW_PLAYING);
break;
default:
break;
}