avrcp: add media item iterator

This commit is contained in:
Milanka Ringwald 2017-11-17 14:54:38 +01:00
parent 6afb9aca51
commit 954cc391b7
10 changed files with 480 additions and 103 deletions

View File

@ -108,6 +108,7 @@ HXCMOD_PLAYER = \
${BTSTACK_ROOT}/3rd-party/hxcmod-player/mods/nao-deceased_by_disease.c \
EXAMPLES = \
avrcp_browsing_client \
a2dp_sink_demo \
a2dp_source_demo \
ancs_client_demo \
@ -276,7 +277,7 @@ a2dp_source_demo: ${CORE_OBJ} ${COMMON_OBJ} ${CLASSIC_OBJ} ${SDP_CLIENT} ${SBC_E
a2dp_sink_demo: ${CORE_OBJ} ${COMMON_OBJ} ${CLASSIC_OBJ} ${SDP_CLIENT} ${SBC_ENCODER_OBJ} ${SBC_DECODER_OBJ} ${AVDTP_OBJ} avrcp.o avrcp_controller.o a2dp_sink_demo.c
${CC} $^ ${CFLAGS} ${LDFLAGS} -o $@
avrcp_browsing_client: ${CORE_OBJ} ${COMMON_OBJ} ${CLASSIC_OBJ} ${SDP_CLIENT} avrcp.o avrcp_controller.o avrcp_browsing_controller.o avrcp_browsing_client.c
avrcp_browsing_client: ${CORE_OBJ} ${COMMON_OBJ} ${CLASSIC_OBJ} ${SDP_CLIENT} avrcp.o avrcp_controller.o avrcp_browsing_controller.o avrcp_media_item_iterator.o avrcp_browsing_client.c
${CC} $^ ${CFLAGS} ${LDFLAGS} -o $@
dut_mode_classic: ${CORE_OBJ} ${COMMON_OBJ} ${CLASSIC_OBJ} dut_mode_classic.c

View File

@ -55,12 +55,12 @@
// *****************************************************************************
#include <stdint.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "btstack.h"
#include "avrcp_browsing_controller.h"
#ifdef HAVE_BTSTACK_STDIN
#include "btstack_stdin.h"
@ -84,6 +84,9 @@ static uint16_t browsing_cid = 0;
static uint8_t avrcp_browsing_connected = 0;
static uint8_t sdp_avrcp_browsing_controller_service_buffer[200];
static uint8_t browsing_query_active = 0;
static avrcp_media_item_context_t media_item_context;
static btstack_packet_callback_registration_t hci_event_callback_registration;
static uint8_t ertm_buffer[10000];
@ -165,16 +168,95 @@ int btstack_main(int argc, const char * argv[]){
}
/* LISTING_END */
static void avrcp_browsing_controller_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
UNUSED(channel);
UNUSED(size);
if (packet_type != HCI_EVENT_PACKET) return;
if (hci_event_packet_get_type(packet) != HCI_EVENT_AVRCP_META) return;
int pos;
switch(packet_type){
case AVRCP_BROWSING_DATA_PACKET:
pos = 0;
browsing_query_active = 1;
avrcp_browsing_item_type_t data_type = (avrcp_browsing_item_type_t)packet[pos++];
pos += 2; // length
switch (data_type){
case AVRCP_BROWSING_MEDIA_PLAYER_ITEM:{
printf("AVRCP Browsing Client: Received media player item \n");
uint16_t player_id = big_endian_read_16(packet, pos);
pos += 2;
avrcp_browsing_media_player_major_type_t major_type = packet[pos++];
avrcp_browsing_media_player_subtype_t subtype = big_endian_read_32(packet, pos);
pos += 4;
uint8_t status = packet[pos++];
uint8_t feature_bitmask[16];
memcpy(feature_bitmask, packet, 16);
pos += 16;
printf("player ID 0x%04x\n, major_type %d, subtype %d, status %d\n", player_id, major_type, subtype, status);
printf_hexdump(feature_bitmask, 16);
break;
}
case AVRCP_BROWSING_FOLDER_ITEM:{
printf("AVRCP Browsing Client: Received folder item \n");
uint32_t folder_uid_high = big_endian_read_32(packet, pos);
pos += 4;
uint32_t folder_uid_low = big_endian_read_32(packet, pos+4);
pos += 4;
avrcp_browsing_folder_type_t folder_type = packet[pos++];
uint8_t is_playable = packet[pos++];
uint16_t charset = big_endian_read_16(packet, pos);
pos += 2;
uint16_t displayable_name_length = big_endian_read_16(packet, pos);
pos += 2;
char value[20];
uint16_t value_len = sizeof(value) > displayable_name_length ? displayable_name_length:sizeof(value)-1;
memcpy(value, packet+pos, value_len);
value[value_len] = 0;
printf("Folder UID: 0x%08" PRIx32 "%08" PRIx32 ", folder_type 0x%02x, is_playable %d, charset 0x%02x, displayable_name_length %d, value %s\n",
folder_uid_high, folder_uid_low, folder_type, is_playable, charset, displayable_name_length, value);
break;
}
case AVRCP_BROWSING_MEDIA_ELEMENT_ITEM:{
printf("AVRCP Browsing Client: Received media item \n");
uint32_t media_uid_high = big_endian_read_32(packet, pos);
pos += 4;
uint32_t media_uid_low = big_endian_read_32(packet, pos+4);
pos += 4;
avrcp_browsing_media_type_t media_type = packet[pos++];
uint16_t charset = big_endian_read_16(packet, pos);
pos += 2;
uint16_t displayable_name_length = big_endian_read_16(packet, pos);
pos += 2;
pos += displayable_name_length;
printf("Media UID: 0x%08" PRIx32 "%08" PRIx32 ", media_type 0x%02x, charset 0x%02x, displayable_name_length %d\n", media_uid_high, media_uid_low, media_type, charset, displayable_name_length);
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("Attr ID 0x%08" PRIx32 ", charset %d, attr_value_length %d, value %s", attr_id, attr_charset, attr_value_length, attr_value);
}
break;
}
default:
log_error("AVRCP browsing: unknown browsable item type 0%02x", data_type);
break;
}
break;
case HCI_EVENT_PACKET:
if (hci_event_packet_get_type(packet) != HCI_EVENT_AVRCP_META) return;
uint16_t local_cid;
uint8_t status = 0xFF;
bd_addr_t adress;
bd_addr_t address;
switch (packet[2]){
case AVRCP_SUBEVENT_CONNECTION_ESTABLISHED: {
@ -193,8 +275,8 @@ static void avrcp_browsing_controller_packet_handler(uint8_t packet_type, uint16
avrcp_cid = local_cid;
avrcp_connected = 1;
avrcp_subevent_connection_established_get_bd_addr(packet, adress);
printf("AVRCP Browsing Client: AVRCP Controller Channel successfully opened: %s, avrcp_cid 0x%02x\n", bd_addr_to_str(adress), avrcp_cid);
avrcp_subevent_connection_established_get_bd_addr(packet, address);
printf("AVRCP Browsing Client: AVRCP Controller Channel successfully opened: %s, avrcp_cid 0x%02x\n", bd_addr_to_str(address), avrcp_cid);
return;
}
case AVRCP_SUBEVENT_CONNECTION_RELEASED:
@ -219,8 +301,8 @@ static void avrcp_browsing_controller_packet_handler(uint8_t packet_type, uint16
browsing_cid = local_cid;
avrcp_browsing_connected = 1;
avrcp_subevent_browsing_connection_established_get_bd_addr(packet, adress);
printf("AVRCP Browsing Client: AVRCP Browsing Controller Channel successfully opened: %s, browsing_cid 0x%02x\n", bd_addr_to_str(adress), browsing_cid);
avrcp_subevent_browsing_connection_established_get_bd_addr(packet, address);
printf("AVRCP Browsing Client: AVRCP Browsing Controller Channel successfully opened: %s, browsing_cid 0x%02x\n", bd_addr_to_str(address), browsing_cid);
return;
}
case AVRCP_SUBEVENT_BROWSING_CONNECTION_RELEASED:
@ -228,10 +310,24 @@ static void avrcp_browsing_controller_packet_handler(uint8_t packet_type, uint16
browsing_cid = 0;
avrcp_browsing_connected = 0;
return;
case AVRCP_SUBEVENT_BROWSING_MEDIA_ITEM_DONE:
printf("AVRCP Browsing Client: query done with browsing status 0x%02x, bluetooth status 0x%02x.\n",
avrcp_subevent_browsing_media_item_done_get_browsing_status(packet),
avrcp_subevent_browsing_media_item_done_get_bluetooth_status(packet));
browsing_query_active = 0;
break;
default:
printf("AVRCP Browsing Client: event is not parsed\n");
break;
}
break;
default:
break;
}
}
#ifdef HAVE_BTSTACK_STDIN
@ -253,6 +349,13 @@ static void show_usage(void){
static void stdin_process(char cmd){
uint8_t status = ERROR_CODE_SUCCESS;
if (cmd != 'a' && cmd != 'A' && cmd != 'c' && cmd != 'C'){
if (browsing_query_active){
printf("Query active, try later!\n");
return;
}
}
switch (cmd){
case 'a':
printf(" - Create AVRCP connection for control to addr %s.\n", bd_addr_to_str(device_addr));

View File

@ -245,6 +245,33 @@ typedef enum {
#define ERROR_CODE_COARSE_CLOCK_ADJUSTMENT_REJECTED_BUT_WILL_TRY_TO_ADJUST_USING_CLOCK_DRAGGING 0x40
/* ENUM_END */
/* ENUM_START: AVRCP_BROWSING_ERROR_CODE */
#define AVRCP_BROWSING_ERROR_CODE_INVALID_COMMAND 0x00 // Sent if TG received a PDU that it did not understand. Valid for All.
#define AVRCP_BROWSING_ERROR_CODE_INVALID_PARAMETER 0x01 // Sent if the TG received a PDU with a parameter ID that it did not understand. Sent if there is only one parameter ID in the PDU. Valid for All.
#define AVRCP_BROWSING_ERROR_CODE_SPECIFIED_PARAMETER_NOT_FOUND 0x02 // Sent if the parameter ID is understood, but content is wrong or corrupted. Valid for All.
#define AVRCP_BROWSING_ERROR_CODE_INTERNAL_ERROR 0x03 // Sent if there are error conditions not covered by a more specific error code. Valid for All.
#define AVRCP_BROWSING_ERROR_CODE_SUCCESS 0x04 // This is the status that should be returned if the operation was successful. Valid for All except where the response CType is AV/C REJECTED.
#define AVRCP_BROWSING_ERROR_CODE_UID_CHANGED 0x05 // The UIDs on the device have changed. Valid for All.
#define AVRCP_BROWSING_ERROR_CODE_RESERVED_06 0x06 // Valid for All.
#define AVRCP_BROWSING_ERROR_CODE_INVALID_DIRECTION 0x07 // The Direction parameter is invalid. Valid for Change Path.
#define AVRCP_BROWSING_ERROR_CODE_NOT_A_DIRECTORY 0x08 // The UID provided does not refer to a folder item. Valid for Change Path.
#define AVRCP_BROWSING_ERROR_CODE_DOES_NOT_EXIST 0x09 // The UID provided does not refer to any currently valid. Valid for Change Path, PlayItem, AddToNowPlaying, GetItemAttributes.
#define AVRCP_BROWSING_ERROR_CODE_INVALID_SCOPE 0x0a // The scope parameter is invalid. Valid for GetFolderItems, PlayItem, AddToNowPlayer, GetItemAttributes,.
#define AVRCP_BROWSING_ERROR_CODE_RANGE_OUT_OF_BOUNDS 0x0b // The start of range provided is not valid. Valid for GetFolderItems.
#define AVRCP_BROWSING_ERROR_CODE_UID_IS_A_DIRECTORY 0x0c // The UID provided refers to a directory, which cannot be handled by this media player. Valid for PlayItem, AddToNowPlaying.
#define AVRCP_BROWSING_ERROR_CODE_MEDIA_IN_USES 0x0d // The media is not able to be used for this operation at this time. Valid for PlayItem, AddToNowPlaying.
#define AVRCP_BROWSING_ERROR_CODE_NOW_PLAYING_LIST_FULL 0x0e // No more items can be added to the Now Playing List. Valid for AddToNowPlaying.
#define AVRCP_BROWSING_ERROR_CODE_SEARCH_NOT_SUPPORTED 0x0f // The Browsed Media Player does not support search. Valid for Search.
#define AVRCP_BROWSING_ERROR_CODE_SEARCH_IN_PROGRESS 0x10 // A search operation is already in progress. Valid for Search.
#define AVRCP_BROWSING_ERROR_CODE_INVALID_PLAYER_ID 0x11 // The specified Player Id does not refer to a valid player. Valid for SetAddressedPlayer, SetBrowsedPlayer.
#define AVRCP_BROWSING_ERROR_CODE_PLAYER_NOT_BROWSABLE 0x12 // The Player Id supplied refers to a Media Player which does not support browsing. Valid for SetBrowsedPlayer.
#define AVRCP_BROWSING_ERROR_CODE_PLAYER_NOT_ADDRESSED 0x13 // The Player Id supplied refers to a player which is not currently addressed, and the command is not able to be performed if the player is not set as addressed. Valid for Search SetBrowsedPlayer.
#define AVRCP_BROWSING_ERROR_CODE_NO_VALID_SEARCH_RESULTS 0x14 // The Search result list does not contain valid entries, e.g. after being invalidated due to change of browsed player. Valid for GetFolderItems.
#define AVRCP_BROWSING_ERROR_CODE_NO_AVAILABLE_PLAYERS 0x15 // Valid for All.
#define AVRCP_BROWSING_ERROR_CODE_ADDRESSED_PLAYER_CHANGED 0x16 // Valid for Register Notification.
// 0x17-0xff Reserved
/* ENUM_END */
// HCI roles
#define HCI_ROLE_MASTER 0
#define HCI_ROLE_SLAVE 1

View File

@ -92,7 +92,9 @@
#include "classic/avdtp_source.h"
#include "classic/avdtp_util.h"
#include "classic/avrcp.h"
#include "classic/avrcp_browsing_controller.h"
#include "classic/avrcp_controller.h"
#include "classic/avrcp_media_item_iterator.h"
#include "classic/avrcp_target.h"
#include "classic/bnep.h"
#include "classic/btstack_link_key_db.h"

View File

@ -189,7 +189,6 @@ typedef uint8_t sm_key_t[16];
#define AVDTP_CONNECTION_IN_WRONG_STATE 0xC2
#define AVDTP_STREAM_ENDPOINT_IN_WRONG_STATE 0xC3
#define AVDTP_MEDIA_CONNECTION_DOES_NOT_EXIST 0xC4
/* ENUM_END */
// DAEMON COMMANDS
@ -1809,9 +1808,11 @@ typedef uint8_t sm_key_t[16];
/**
* @format 12
* @format 1211
* @param subevent_code
* @param browsing_cid
* @param browsing_status
* @param bluetooth_status
*/
#define AVRCP_SUBEVENT_BROWSING_MEDIA_ITEM_DONE 0x1D

View File

@ -5759,6 +5759,24 @@ static inline uint16_t avrcp_subevent_browsing_connection_released_get_browsing_
static inline uint16_t avrcp_subevent_browsing_media_item_done_get_browsing_cid(const uint8_t * event){
return little_endian_read_16(event, 3);
}
/**
* @brief Get field browsing_status from event AVRCP_SUBEVENT_BROWSING_MEDIA_ITEM_DONE
* @param event packet
* @return browsing_status
* @note: btstack_type 1
*/
static inline uint8_t avrcp_subevent_browsing_media_item_done_get_browsing_status(const uint8_t * event){
return event[5];
}
/**
* @brief Get field bluetooth_status from event AVRCP_SUBEVENT_BROWSING_MEDIA_ITEM_DONE
* @param event packet
* @return bluetooth_status
* @note: btstack_type 1
*/
static inline uint8_t avrcp_subevent_browsing_media_item_done_get_bluetooth_status(const uint8_t * event){
return event[6];
}
/**
* @brief Get field goep_cid from event GOEP_SUBEVENT_CONNECTION_OPENED

View File

@ -283,59 +283,74 @@ static void avrcp_browsing_controller_handle_can_send_now(avrcp_browsing_connect
}
}
static void avrcp_browsing_controller_emit_done(btstack_packet_handler_t callback, uint16_t browsing_cid){
static void avrcp_browsing_controller_emit_done(btstack_packet_handler_t callback, uint16_t browsing_cid, uint8_t browsing_status, uint8_t bluetooth_status){
if (!callback) return;
uint8_t event[5];
uint8_t event[6];
int pos = 0;
event[pos++] = HCI_EVENT_AVRCP_META;
event[pos++] = sizeof(event) - 2;
event[pos++] = AVRCP_SUBEVENT_BROWSING_MEDIA_ITEM_DONE;
little_endian_store_16(event, pos, browsing_cid);
pos += 2;
event[pos++] = browsing_status;
event[pos++] = bluetooth_status;
(*callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
}
static void avrcp_browsing_controller_handle_l2cap_data_packet(avrcp_connection_t * connection, uint8_t *packet, uint16_t size){
UNUSED(size);
printf("avrcp_browsing_controller_handle_l2cap_data_packet \n");
printf_hexdump(packet, size);
static void avrcp_browsing_controller_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
avrcp_browsing_connection_t * browsing_connection;
switch (packet_type) {
case L2CAP_DATA_PACKET:{
browsing_connection = get_avrcp_browsing_connection_for_l2cap_cid(channel, &avrcp_controller_context);
if (!browsing_connection) break;
browsing_connection->state = AVCTP_CONNECTION_OPENED;
int pos = 3;
avrcp_pdu_id_t pdu_id = packet[pos++];
if (size < pos + 4){
avrcp_browsing_controller_emit_done(avrcp_controller_context.avrcp_callback, channel, AVRCP_BROWSING_ERROR_CODE_INVALID_COMMAND, ERROR_CODE_SUCCESS);
break;
}
avrcp_pdu_id_t pdu_id = packet[pos++];
uint16_t length = big_endian_read_16(packet, pos);
pos += 2;
uint8_t browsing_status = packet[pos++];
if (browsing_status != AVRCP_BROWSING_ERROR_CODE_SUCCESS){
avrcp_browsing_controller_emit_done(avrcp_controller_context.avrcp_callback, channel, browsing_status, ERROR_CODE_SUCCESS);
break;
}
if (size + pos < length){
avrcp_browsing_controller_emit_done(avrcp_controller_context.avrcp_callback, channel, AVRCP_BROWSING_ERROR_CODE_INVALID_COMMAND, ERROR_CODE_SUCCESS);
break;
}
// uint16_t uid_counter = big_endian_read_16(packet, pos);
pos += 2;
uint16_t num_items = big_endian_read_16(packet, pos);
pos += 2;
int i;
switch(pdu_id){
case AVRCP_PDU_ID_GET_FOLDER_ITEMS:
printf("AVRCP_PDU_ID_GET_FOLDER_ITEMS response \n");
avrcp_browsing_controller_emit_done(avrcp_controller_context.avrcp_callback, connection->avrcp_browsing_cid);
for (i = 0; i < num_items; i++){
uint16_t browsable_item_length = big_endian_read_16(packet, pos+1);
(*avrcp_controller_context.avrcp_callback)(AVRCP_BROWSING_DATA_PACKET, channel, packet+pos, browsable_item_length);
pos += 3 + browsable_item_length;
}
avrcp_browsing_controller_emit_done(avrcp_controller_context.avrcp_callback, channel, browsing_status, ERROR_CODE_SUCCESS);
break;
default:
break;
}
connection->state = AVCTP_CONNECTION_OPENED;
}
static void avrcp_browsing_controller_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
avrcp_browsing_connection_t * connection;
avrcp_connection_t * avrcp_connection;
printf("avrcp_browsing_controller_packet_handler, packet type 0%02x\n", packet_type);
switch (packet_type) {
case L2CAP_DATA_PACKET:
avrcp_connection = get_avrcp_connection_for_browsing_l2cap_cid(channel, &avrcp_controller_context);
if (!avrcp_connection){
printf("connection not found 0%2x\n", channel);
break;
}
avrcp_browsing_controller_handle_l2cap_data_packet(avrcp_connection, packet, size);
break;
case HCI_EVENT_PACKET:
switch (hci_event_packet_get_type(packet)){
case L2CAP_EVENT_CAN_SEND_NOW:
connection = get_avrcp_browsing_connection_for_l2cap_cid(channel, &avrcp_controller_context);
if (!connection) break;
avrcp_browsing_controller_handle_can_send_now(connection);
browsing_connection = get_avrcp_browsing_connection_for_l2cap_cid(channel, &avrcp_controller_context);
if (!browsing_connection) break;
avrcp_browsing_controller_handle_can_send_now(browsing_connection);
break;
default:
avrcp_browser_packet_handler(packet_type, channel, packet, size, &avrcp_controller_context);
@ -396,5 +411,5 @@ uint8_t avrcp_browsing_controller_get_folder_items(uint16_t avrcp_browsing_cid,
}
uint8_t avrcp_browsing_controller_get_player_list(uint16_t avrcp_browsing_cid){
return avrcp_browsing_controller_get_folder_items(avrcp_browsing_cid, 0, 0, 0xFFFFFFFF, 0, NULL);
return avrcp_browsing_controller_get_folder_items(avrcp_browsing_cid, 0x01, 0, 0xFFFFFFFF, 0, NULL);
}

View File

@ -36,7 +36,7 @@
*/
/*
* avrcp_browsing.h
* avrcp_browsing_controller.h
*
* Audio/Video Remote Control Profile Browsing
*
@ -55,6 +55,48 @@ extern "C" {
/* API_START */
typedef enum {
AVRCP_BROWSING_MEDIA_PLAYER_ITEM = 0x01,
AVRCP_BROWSING_FOLDER_ITEM,
AVRCP_BROWSING_MEDIA_ELEMENT_ITEM
} avrcp_browsing_item_type_t;
typedef enum {
AVRCP_BROWSING_MEDIA_PLAYER_MAJOR_TYPE_AUDIO = 1,
AVRCP_BROWSING_MEDIA_PLAYER_MAJOR_TYPE_VIDEO = 2,
AVRCP_BROWSING_MEDIA_PLAYER_MAJOR_TYPE_BROADCASTING_AUDIO = 4,
AVRCP_BROWSING_MEDIA_PLAYER_MAJOR_TYPE_BROADCASTING_VIDEO = 8
} avrcp_browsing_media_player_major_type_t;
typedef enum {
AVRCP_BROWSING_MEDIA_PLAYER_SUBTYPE_AUDIO_BOOK = 1,
AVRCP_BROWSING_MEDIA_PLAYER_SUBTYPE_POADCAST = 2
} avrcp_browsing_media_player_subtype_t;
typedef enum {
AVRCP_BROWSING_MEDIA_PLAYER_STATUS_STOPPED = 0,
AVRCP_BROWSING_MEDIA_PLAYER_STATUS_PLAYING,
AVRCP_BROWSING_MEDIA_PLAYER_STATUS_PAUSED,
AVRCP_BROWSING_MEDIA_PLAYER_STATUS_FWD_SEEK,
AVRCP_BROWSING_MEDIA_PLAYER_STATUS_REV_SEEK,
AVRCP_BROWSING_MEDIA_PLAYER_STATUS_ERROR = 0xFF
} avrcp_browsing_media_player_status_t;
typedef enum {
AVRCP_BROWSING_FOLDER_TYPE_MIXED = 0x00,
AVRCP_BROWSING_FOLDER_TYPE_TITLES,
AVRCP_BROWSING_FOLDER_TYPE_ALBUMS,
AVRCP_BROWSING_FOLDER_TYPE_ARTISTS,
AVRCP_BROWSING_FOLDER_TYPE_GENRES,
AVRCP_BROWSING_FOLDER_TYPE_PLAYLISTS,
AVRCP_BROWSING_FOLDER_TYPE_YEARS
} avrcp_browsing_folder_type_t;
typedef enum {
AVRCP_BROWSING_MEDIA_TYPE_AUDIO = 0x00,
AVRCP_BROWSING_MEDIA_TYPE_VIDEO
} avrcp_browsing_media_type_t;
/**
* @brief Set up AVRCP Browsing Controller device.
*/

View File

@ -0,0 +1,90 @@
/*
* Copyright (C) 2014 BlueKitchen GmbH
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* 4. Any redistribution, use, or modification is done solely for
* personal benefit and not for any commercial purpose or for
* monetary gain.
*
* THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
* RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* Please inquire about commercial licensing options at
* contact@bluekitchen-gmbh.com
*
*/
#define __BTSTACK_FILE__ "avrcp_media_item_iterator.c"
// *****************************************************************************
//
// AVRCP Media Item Iterator
//
// *****************************************************************************
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "classic/avrcp_media_item_iterator.h"
#include "btstack_util.h"
void avrcp_media_item_iterator_init(avrcp_media_item_context_t *context, uint16_t avrcp_media_item_len, const uint8_t * avrcp_media_item_data){
context->data = avrcp_media_item_data;
context->length = avrcp_media_item_len;
context->offset = 0;
}
int avrcp_media_item_iterator_has_more(const avrcp_media_item_context_t * context){
return context->offset < context->length;
}
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;
// avoid uint8_t overrun
if (new_offset > 0xffff){
new_offset = 0xffff;
}
context->offset = new_offset;
}
uint32_t avrcp_media_item_iterator_get_attr_id(const avrcp_media_item_context_t * context){
return big_endian_read_32(context->data, context->offset);
}
uint16_t avrcp_media_item_iterator_get_attr_charset(const avrcp_media_item_context_t * context){
return big_endian_read_16(context->data, context->offset + 4);
}
uint16_t avrcp_media_item_iterator_get_attr_value_len(const avrcp_media_item_context_t * context){
return big_endian_read_16(context->data, context->offset + 6);
}
const uint8_t * avrcp_media_item_iterator_get_attr_value(const avrcp_media_item_context_t * context){
return &context->data[context->offset + 8];
}

View File

@ -0,0 +1,78 @@
/*
* Copyright (C) 2017 BlueKitchen GmbH
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* 4. Any redistribution, use, or modification is done solely for
* personal benefit and not for any commercial purpose or for
* monetary gain.
*
* THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
* RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* Please inquire about commercial licensing options at
* contact@bluekitchen-gmbh.com
*
*/
// *****************************************************************************
//
// AVRCP Media Item Iterator
//
// *****************************************************************************
#ifndef __AVRCP_MEDIA_ITEM_ITERATOR_H
#define __AVRCP_MEDIA_ITEM_ITERATOR_H
#include "btstack_config.h"
#include <stdint.h>
#if defined __cplusplus
extern "C" {
#endif
/* API_START */
typedef struct avrcp_media_item_context {
const uint8_t * data;
uint16_t offset;
uint16_t length;
} avrcp_media_item_context_t;
// Media item data iterator
void avrcp_media_item_iterator_init(avrcp_media_item_context_t *context, uint16_t avrcp_media_item_len, const uint8_t * avrcp_media_item_data);
int avrcp_media_item_iterator_has_more(const avrcp_media_item_context_t * context);
void avrcp_media_item_iterator_next(avrcp_media_item_context_t * context);
// Access functions
uint32_t avrcp_media_item_iterator_get_attr_id(const avrcp_media_item_context_t * context);
uint16_t avrcp_media_item_iterator_get_attr_charset(const avrcp_media_item_context_t * context);
uint16_t avrcp_media_item_iterator_get_attr_value_len(const avrcp_media_item_context_t * context);
const uint8_t * avrcp_media_item_iterator_get_attr_value(const avrcp_media_item_context_t * context);
/* API_END */
#if defined __cplusplus
}
#endif
#endif // __AVRCP_MEDIA_ITEM_ITERATOR_H