mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-03-29 13:20:39 +00:00
example/a2dp_sink_demo: support cover art
This commit is contained in:
parent
4c7f527567
commit
60d7c35e67
@ -92,7 +92,7 @@
|
|||||||
#define MAX_SBC_FRAME_SIZE 120
|
#define MAX_SBC_FRAME_SIZE 120
|
||||||
|
|
||||||
#ifdef HAVE_BTSTACK_STDIN
|
#ifdef HAVE_BTSTACK_STDIN
|
||||||
static const char * device_addr_string = "5C:F3:70:60:7B:87"; // pts
|
static const char * device_addr_string = "00:1B:DC:08:E2:72"; // pts v5.0
|
||||||
static bd_addr_t device_addr;
|
static bd_addr_t device_addr;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -152,6 +152,30 @@ static int request_frames;
|
|||||||
static int volume_percentage = 0;
|
static int volume_percentage = 0;
|
||||||
static avrcp_battery_status_t battery_status = AVRCP_BATTERY_STATUS_WARNING;
|
static avrcp_battery_status_t battery_status = AVRCP_BATTERY_STATUS_WARNING;
|
||||||
|
|
||||||
|
#ifdef ENABLE_AVRCP_COVER_ART
|
||||||
|
static char a2dp_sink_demo_image_handle[8];
|
||||||
|
static avrcp_cover_art_client_t a2dp_sink_demo_cover_art_client;
|
||||||
|
static bool a2dp_sink_demo_cover_art_client_connected;
|
||||||
|
static uint16_t a2dp_sink_demo_cover_art_cid;
|
||||||
|
static uint8_t a2dp_sink_demo_ertm_buffer[2000];
|
||||||
|
static l2cap_ertm_config_t a2dp_sink_demo_ertm_config = {
|
||||||
|
1, // ertm mandatory
|
||||||
|
2, // max transmit, some tests require > 1
|
||||||
|
2000,
|
||||||
|
12000,
|
||||||
|
512, // l2cap ertm mtu
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
1, // 16-bit FCS
|
||||||
|
};
|
||||||
|
static bool a2dp_sink_cover_art_download_active;
|
||||||
|
static uint32_t a2dp_sink_cover_art_file_size;
|
||||||
|
#ifdef HAVE_POSIX_FILE_IO
|
||||||
|
static const char * a2dp_sink_demo_thumbnail_path = "cover.jpg";
|
||||||
|
static FILE * a2dp_sink_cover_art_file;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t reconfigure;
|
uint8_t reconfigure;
|
||||||
uint8_t num_channels;
|
uint8_t num_channels;
|
||||||
@ -236,7 +260,10 @@ static int setup_demo(void){
|
|||||||
// Initialize LE Security Manager. Needed for cross-transport key derivation
|
// Initialize LE Security Manager. Needed for cross-transport key derivation
|
||||||
sm_init();
|
sm_init();
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef ENABLE_AVRCP_COVER_ART
|
||||||
|
goep_client_init();
|
||||||
|
avrcp_cover_art_client_init();
|
||||||
|
#endif
|
||||||
|
|
||||||
// Init profiles
|
// Init profiles
|
||||||
a2dp_sink_init();
|
a2dp_sink_init();
|
||||||
@ -273,9 +300,12 @@ static int setup_demo(void){
|
|||||||
|
|
||||||
// - Create AVRCP Controller service record and register it with SDP. We send Category 1 commands to the media player, e.g. play/pause
|
// - Create AVRCP Controller service record and register it with SDP. We send Category 1 commands to the media player, e.g. play/pause
|
||||||
memset(sdp_avrcp_controller_service_buffer, 0, sizeof(sdp_avrcp_controller_service_buffer));
|
memset(sdp_avrcp_controller_service_buffer, 0, sizeof(sdp_avrcp_controller_service_buffer));
|
||||||
uint16_t controller_supported_features = AVRCP_FEATURE_MASK_CATEGORY_PLAYER_OR_RECORDER;
|
uint16_t controller_supported_features = 1 << AVRCP_CONTROLLER_SUPPORTED_FEATURE_CATEGORY_PLAYER_OR_RECORDER;
|
||||||
#ifdef AVRCP_BROWSING_ENABLED
|
#ifdef AVRCP_BROWSING_ENABLED
|
||||||
controller_supported_features |= AVRCP_FEATURE_MASK_BROWSING;
|
controller_supported_features |= 1 << AVRCP_CONTROLLER_SUPPORTED_FEATURE_BROWSING;
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_AVRCP_COVER_ART
|
||||||
|
controller_supported_features |= 1 << AVRCP_CONTROLLER_SUPPORTED_FEATURE_COVER_ART_GET_LINKED_THUMBNAIL;
|
||||||
#endif
|
#endif
|
||||||
avrcp_controller_create_sdp_record(sdp_avrcp_controller_service_buffer, sdp_create_service_record_handle(),
|
avrcp_controller_create_sdp_record(sdp_avrcp_controller_service_buffer, sdp_create_service_record_handle(),
|
||||||
controller_supported_features, NULL, NULL);
|
controller_supported_features, NULL, NULL);
|
||||||
@ -284,7 +314,7 @@ static int setup_demo(void){
|
|||||||
// - Create and register A2DP Sink service record
|
// - Create and register A2DP Sink service record
|
||||||
// - We receive Category 2 commands from the media player, e.g. volume up/down
|
// - We receive Category 2 commands from the media player, e.g. volume up/down
|
||||||
memset(sdp_avrcp_target_service_buffer, 0, sizeof(sdp_avrcp_target_service_buffer));
|
memset(sdp_avrcp_target_service_buffer, 0, sizeof(sdp_avrcp_target_service_buffer));
|
||||||
uint16_t target_supported_features = AVRCP_FEATURE_MASK_CATEGORY_MONITOR_OR_AMPLIFIER;
|
uint16_t target_supported_features = 1 << AVRCP_TARGET_SUPPORTED_FEATURE_CATEGORY_MONITOR_OR_AMPLIFIER;
|
||||||
avrcp_target_create_sdp_record(sdp_avrcp_target_service_buffer,
|
avrcp_target_create_sdp_record(sdp_avrcp_target_service_buffer,
|
||||||
sdp_create_service_record_handle(), target_supported_features, NULL, NULL);
|
sdp_create_service_record_handle(), target_supported_features, NULL, NULL);
|
||||||
sdp_register_service(sdp_avrcp_target_service_buffer);
|
sdp_register_service(sdp_avrcp_target_service_buffer);
|
||||||
@ -622,6 +652,96 @@ static void dump_sbc_configuration(media_codec_configuration_sbc_t * configurati
|
|||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void hci_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_PIN_CODE_REQUEST) {
|
||||||
|
bd_addr_t address;
|
||||||
|
printf("Pin code request - using '0000'\n");
|
||||||
|
hci_event_pin_code_request_get_bd_addr(packet, address);
|
||||||
|
gap_pin_code_response(address, "0000");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_AVRCP_COVER_ART
|
||||||
|
static void a2dp_sink_demo_cover_art_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) {
|
||||||
|
UNUSED(channel);
|
||||||
|
UNUSED(size);
|
||||||
|
uint8_t status;
|
||||||
|
uint16_t cid;
|
||||||
|
switch (packet_type){
|
||||||
|
case BIP_DATA_PACKET:
|
||||||
|
if (a2dp_sink_cover_art_download_active){
|
||||||
|
a2dp_sink_cover_art_file_size += size;
|
||||||
|
#ifdef HAVE_POSIX_FILE_IO
|
||||||
|
fwrite(packet, 1, size, a2dp_sink_cover_art_file);
|
||||||
|
#else
|
||||||
|
printf("Cover art : TODO - store %u bytes image data\n", size);
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
uint16_t i;
|
||||||
|
for (i=0;i<size;i++){
|
||||||
|
putchar(packet[i]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case HCI_EVENT_PACKET:
|
||||||
|
switch (hci_event_packet_get_type(packet)){
|
||||||
|
case HCI_EVENT_AVRCP_META:
|
||||||
|
switch (hci_event_avrcp_meta_get_subevent_code(packet)){
|
||||||
|
case AVRCP_SUBEVENT_COVER_ART_CONNECTION_ESTABLISHED:
|
||||||
|
status = avrcp_subevent_cover_art_connection_established_get_status(packet);
|
||||||
|
cid = avrcp_subevent_cover_art_connection_established_get_cover_art_cid(packet);
|
||||||
|
if (status == ERROR_CODE_SUCCESS){
|
||||||
|
printf("Cover Art : connection established, cover art cid 0x%02x\n", cid);
|
||||||
|
a2dp_sink_demo_cover_art_client_connected = true;
|
||||||
|
} else {
|
||||||
|
printf("Cover Art : connection failed, status 0x%02x\n", status);
|
||||||
|
a2dp_sink_demo_cover_art_cid = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case AVRCP_SUBEVENT_COVER_ART_OPERATION_COMPLETE:
|
||||||
|
if (a2dp_sink_cover_art_download_active){
|
||||||
|
a2dp_sink_cover_art_download_active = false;
|
||||||
|
#ifdef HAVE_POSIX_FILE_IO
|
||||||
|
printf("Cover Art : download of '%s complete, size %u bytes'\n",
|
||||||
|
a2dp_sink_demo_thumbnail_path, a2dp_sink_cover_art_file_size);
|
||||||
|
fclose(a2dp_sink_cover_art_file);
|
||||||
|
a2dp_sink_cover_art_file = NULL;
|
||||||
|
#else
|
||||||
|
printf("Cover Art: download completed\n");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case AVRCP_SUBEVENT_COVER_ART_CONNECTION_RELEASED:
|
||||||
|
a2dp_sink_demo_cover_art_client_connected = false;
|
||||||
|
a2dp_sink_demo_cover_art_cid = 0;
|
||||||
|
printf("Cover Art : connection released 0x%02x\n",
|
||||||
|
avrcp_subevent_cover_art_connection_released_get_cover_art_cid(packet));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t a2dp_sink_demo_cover_art_connect(void) {
|
||||||
|
uint8_t status;
|
||||||
|
status = avrcp_cover_art_client_connect(&a2dp_sink_demo_cover_art_client, a2dp_sink_demo_cover_art_packet_handler,
|
||||||
|
device_addr, a2dp_sink_demo_ertm_buffer,
|
||||||
|
sizeof(a2dp_sink_demo_ertm_buffer), &a2dp_sink_demo_ertm_config,
|
||||||
|
&a2dp_sink_demo_cover_art_cid);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void avrcp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
|
static void avrcp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
|
||||||
UNUSED(channel);
|
UNUSED(channel);
|
||||||
UNUSED(size);
|
UNUSED(size);
|
||||||
@ -647,6 +767,11 @@ static void avrcp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t
|
|||||||
avrcp_subevent_connection_established_get_bd_addr(packet, address);
|
avrcp_subevent_connection_established_get_bd_addr(packet, address);
|
||||||
printf("AVRCP: Connected to %s, cid 0x%02x\n", bd_addr_to_str(address), connection->avrcp_cid);
|
printf("AVRCP: Connected to %s, cid 0x%02x\n", bd_addr_to_str(address), connection->avrcp_cid);
|
||||||
|
|
||||||
|
#ifdef HAVE_BTSTACK_STDIN
|
||||||
|
// use address for outgoing connections
|
||||||
|
avrcp_subevent_connection_established_get_bd_addr(packet, device_addr);
|
||||||
|
#endif
|
||||||
|
|
||||||
avrcp_target_support_event(connection->avrcp_cid, AVRCP_NOTIFICATION_EVENT_VOLUME_CHANGED);
|
avrcp_target_support_event(connection->avrcp_cid, AVRCP_NOTIFICATION_EVENT_VOLUME_CHANGED);
|
||||||
avrcp_target_support_event(connection->avrcp_cid, AVRCP_NOTIFICATION_EVENT_BATT_STATUS_CHANGED);
|
avrcp_target_support_event(connection->avrcp_cid, AVRCP_NOTIFICATION_EVENT_BATT_STATUS_CHANGED);
|
||||||
avrcp_target_battery_status_changed(connection->avrcp_cid, battery_status);
|
avrcp_target_battery_status_changed(connection->avrcp_cid, battery_status);
|
||||||
@ -688,7 +813,7 @@ static void avrcp_controller_packet_handler(uint8_t packet_type, uint16_t channe
|
|||||||
break;
|
break;
|
||||||
case AVRCP_SUBEVENT_GET_CAPABILITY_EVENT_ID_DONE:
|
case AVRCP_SUBEVENT_GET_CAPABILITY_EVENT_ID_DONE:
|
||||||
|
|
||||||
printf("\nSupported remote AVRCP Target notifications:\n");
|
printf("AVRCP Controller: supported notifications by target:\n");
|
||||||
for (event_id = (uint8_t) AVRCP_NOTIFICATION_EVENT_FIRST_INDEX; event_id < (uint8_t) AVRCP_NOTIFICATION_EVENT_LAST_INDEX; event_id++){
|
for (event_id = (uint8_t) AVRCP_NOTIFICATION_EVENT_FIRST_INDEX; event_id < (uint8_t) AVRCP_NOTIFICATION_EVENT_LAST_INDEX; event_id++){
|
||||||
printf(" - [%s] %s\n",
|
printf(" - [%s] %s\n",
|
||||||
(avrcp_connection->notifications_supported_by_target & (1 << event_id)) != 0 ? "X" : " ",
|
(avrcp_connection->notifications_supported_by_target & (1 << event_id)) != 0 ? "X" : " ",
|
||||||
@ -700,6 +825,13 @@ static void avrcp_controller_packet_handler(uint8_t packet_type, uint16_t channe
|
|||||||
avrcp_controller_enable_notification(avrcp_connection->avrcp_cid, AVRCP_NOTIFICATION_EVENT_PLAYBACK_STATUS_CHANGED);
|
avrcp_controller_enable_notification(avrcp_connection->avrcp_cid, AVRCP_NOTIFICATION_EVENT_PLAYBACK_STATUS_CHANGED);
|
||||||
avrcp_controller_enable_notification(avrcp_connection->avrcp_cid, AVRCP_NOTIFICATION_EVENT_NOW_PLAYING_CONTENT_CHANGED);
|
avrcp_controller_enable_notification(avrcp_connection->avrcp_cid, AVRCP_NOTIFICATION_EVENT_NOW_PLAYING_CONTENT_CHANGED);
|
||||||
avrcp_controller_enable_notification(avrcp_connection->avrcp_cid, AVRCP_NOTIFICATION_EVENT_TRACK_CHANGED);
|
avrcp_controller_enable_notification(avrcp_connection->avrcp_cid, AVRCP_NOTIFICATION_EVENT_TRACK_CHANGED);
|
||||||
|
|
||||||
|
#ifdef ENABLE_AVRCP_COVER_ART
|
||||||
|
// image handles become invalid on player change, registe for notifications
|
||||||
|
avrcp_controller_enable_notification(a2dp_sink_demo_avrcp_connection.avrcp_cid, AVRCP_NOTIFICATION_EVENT_UIDS_CHANGED);
|
||||||
|
// trigger cover art client connection
|
||||||
|
a2dp_sink_demo_cover_art_connect();
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AVRCP_SUBEVENT_NOTIFICATION_STATE:
|
case AVRCP_SUBEVENT_NOTIFICATION_STATE:
|
||||||
@ -776,7 +908,7 @@ static void avrcp_controller_packet_handler(uint8_t packet_type, uint16_t channe
|
|||||||
printf("AVRCP Controller: Genre %s\n", avrcp_subevent_value);
|
printf("AVRCP Controller: Genre %s\n", avrcp_subevent_value);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AVRCP_SUBEVENT_PLAY_STATUS:
|
case AVRCP_SUBEVENT_PLAY_STATUS:
|
||||||
printf("AVRCP Controller: Song length %"PRIu32" ms, Song position %"PRIu32" ms, Play status %s\n",
|
printf("AVRCP Controller: Song length %"PRIu32" ms, Song position %"PRIu32" ms, Play status %s\n",
|
||||||
avrcp_subevent_play_status_get_song_length(packet),
|
avrcp_subevent_play_status_get_song_length(packet),
|
||||||
@ -799,7 +931,23 @@ static void avrcp_controller_packet_handler(uint8_t packet_type, uint16_t channe
|
|||||||
case AVRCP_SUBEVENT_PLAYER_APPLICATION_VALUE_RESPONSE:
|
case AVRCP_SUBEVENT_PLAYER_APPLICATION_VALUE_RESPONSE:
|
||||||
printf("AVRCP Controller: Set Player App Value %s\n", avrcp_ctype2str(avrcp_subevent_player_application_value_response_get_command_type(packet)));
|
printf("AVRCP Controller: Set Player App Value %s\n", avrcp_ctype2str(avrcp_subevent_player_application_value_response_get_command_type(packet)));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
#ifdef ENABLE_AVRCP_COVER_ART
|
||||||
|
case AVRCP_SUBEVENT_NOTIFICATION_EVENT_UIDS_CHANGED:
|
||||||
|
if (a2dp_sink_demo_cover_art_client_connected){
|
||||||
|
printf("AVRCP Controller: UIDs changed -> disconnect cover art client\n");
|
||||||
|
avrcp_cover_art_client_disconnect(a2dp_sink_demo_cover_art_cid);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AVRCP_SUBEVENT_NOW_PLAYING_COVER_ART_INFO:
|
||||||
|
if (avrcp_subevent_now_playing_cover_art_info_get_value_len(packet) == 7){
|
||||||
|
memcpy(a2dp_sink_demo_image_handle, avrcp_subevent_now_playing_cover_art_info_get_value(packet), 7);
|
||||||
|
printf("AVRCP Controller: Cover Art %s\n", a2dp_sink_demo_image_handle);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -851,18 +999,6 @@ static void avrcp_target_packet_handler(uint8_t packet_type, uint16_t channel, u
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hci_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_PIN_CODE_REQUEST) {
|
|
||||||
bd_addr_t address;
|
|
||||||
printf("Pin code request - using '0000'\n");
|
|
||||||
hci_event_pin_code_request_get_bd_addr(packet, address);
|
|
||||||
gap_pin_code_response(address, "0000");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void a2dp_sink_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
|
static void a2dp_sink_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
|
||||||
UNUSED(channel);
|
UNUSED(channel);
|
||||||
UNUSED(size);
|
UNUSED(size);
|
||||||
@ -978,15 +1114,13 @@ static void a2dp_sink_packet_handler(uint8_t packet_type, uint16_t channel, uint
|
|||||||
static void show_usage(void){
|
static void show_usage(void){
|
||||||
bd_addr_t iut_address;
|
bd_addr_t iut_address;
|
||||||
gap_local_bd_addr(iut_address);
|
gap_local_bd_addr(iut_address);
|
||||||
printf("\n--- Bluetooth AVDTP Sink/AVRCP Connection Test Console %s ---\n", bd_addr_to_str(iut_address));
|
printf("\n--- A2DP Sink Demo Console %s ---\n", bd_addr_to_str(iut_address));
|
||||||
printf("b - AVDTP Sink create connection to addr %s\n", bd_addr_to_str(device_addr));
|
printf("b - A2DP Sink create connection to addr %s\n", bd_addr_to_str(device_addr));
|
||||||
printf("B - AVDTP Sink disconnect\n");
|
printf("B - A2DP Sink disconnect\n");
|
||||||
printf("c - AVRCP create connection to addr %s\n", bd_addr_to_str(device_addr));
|
|
||||||
printf("C - AVRCP disconnect\n");
|
|
||||||
|
|
||||||
printf("w - delay report\n");
|
printf("\n--- AVRCP Controller ---\n");
|
||||||
|
printf("c - AVRCP create connection to addr %s\n", bd_addr_to_str(device_addr));
|
||||||
printf("\n--- Bluetooth AVRCP Commands %s ---\n", bd_addr_to_str(iut_address));
|
printf("C - AVRCP disconnect\n");
|
||||||
printf("O - get play status\n");
|
printf("O - get play status\n");
|
||||||
printf("j - get now playing info\n");
|
printf("j - get now playing info\n");
|
||||||
printf("k - play\n");
|
printf("k - play\n");
|
||||||
@ -1002,6 +1136,7 @@ static void show_usage(void){
|
|||||||
printf("r - skip\n");
|
printf("r - skip\n");
|
||||||
printf("q - query repeat and shuffle mode\n");
|
printf("q - query repeat and shuffle mode\n");
|
||||||
printf("v - repeat single track\n");
|
printf("v - repeat single track\n");
|
||||||
|
printf("w - delay report\n");
|
||||||
printf("x - repeat all tracks\n");
|
printf("x - repeat all tracks\n");
|
||||||
printf("X - disable repeat mode\n");
|
printf("X - disable repeat mode\n");
|
||||||
printf("z - shuffle all tracks\n");
|
printf("z - shuffle all tracks\n");
|
||||||
@ -1016,11 +1151,28 @@ static void show_usage(void){
|
|||||||
printf("t - volume up for 10 percent\n");
|
printf("t - volume up for 10 percent\n");
|
||||||
printf("T - volume down for 10 percent\n");
|
printf("T - volume down for 10 percent\n");
|
||||||
printf("V - toggle Battery status from AVRCP_BATTERY_STATUS_NORMAL to AVRCP_BATTERY_STATUS_FULL_CHARGE\n");
|
printf("V - toggle Battery status from AVRCP_BATTERY_STATUS_NORMAL to AVRCP_BATTERY_STATUS_FULL_CHARGE\n");
|
||||||
|
|
||||||
|
#ifdef ENABLE_AVRCP_COVER_ART
|
||||||
|
printf("\n--- Cover Art Client ---\n");
|
||||||
|
printf("d - connect to addr %s\n", bd_addr_to_str(device_addr));
|
||||||
|
printf("D - disconnect\n");
|
||||||
|
if (a2dp_sink_demo_cover_art_client_connected == false){
|
||||||
|
if (a2dp_sink_demo_avrcp_connection.avrcp_cid == 0){
|
||||||
|
printf("Not connected, press 'b' or 'c' to first connect AVRCP, then press 'd' to connect cover art client\n");
|
||||||
|
} else {
|
||||||
|
printf("Not connected, press 'd' to connect cover art client\n");
|
||||||
|
}
|
||||||
|
} else if (a2dp_sink_demo_image_handle[0] == 0){
|
||||||
|
printf("No image handle, use 'j' to get current track info\n");
|
||||||
|
}
|
||||||
printf("---\n");
|
printf("---\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_BTSTACK_STDIN
|
#ifdef HAVE_BTSTACK_STDIN
|
||||||
|
|
||||||
static void stdin_process(char cmd){
|
static void stdin_process(char cmd){
|
||||||
uint8_t status = ERROR_CODE_SUCCESS;
|
uint8_t status = ERROR_CODE_SUCCESS;
|
||||||
uint8_t volume;
|
uint8_t volume;
|
||||||
@ -1048,7 +1200,7 @@ static void stdin_process(char cmd){
|
|||||||
printf(" - AVRCP disconnect from addr %s.\n", bd_addr_to_str(device_addr));
|
printf(" - AVRCP disconnect from addr %s.\n", bd_addr_to_str(device_addr));
|
||||||
status = avrcp_disconnect(avrcp_connection->avrcp_cid);
|
status = avrcp_disconnect(avrcp_connection->avrcp_cid);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '\n':
|
case '\n':
|
||||||
case '\r':
|
case '\r':
|
||||||
break;
|
break;
|
||||||
@ -1182,6 +1334,25 @@ static void stdin_process(char cmd){
|
|||||||
printf("AVRCP: release long button press REWIND\n");
|
printf("AVRCP: release long button press REWIND\n");
|
||||||
status = avrcp_controller_release_press_and_hold_cmd(avrcp_connection->avrcp_cid);
|
status = avrcp_controller_release_press_and_hold_cmd(avrcp_connection->avrcp_cid);
|
||||||
break;
|
break;
|
||||||
|
#ifdef ENABLE_AVRCP_COVER_ART
|
||||||
|
case 'd':
|
||||||
|
printf(" - Create AVRCP Cover Art connection to addr %s.\n", bd_addr_to_str(device_addr));
|
||||||
|
status = a2dp_sink_demo_cover_art_connect();
|
||||||
|
break;
|
||||||
|
case 'D':
|
||||||
|
printf(" - AVRCP Cover Art disconnect from addr %s.\n", bd_addr_to_str(device_addr));
|
||||||
|
status = avrcp_cover_art_client_disconnect(a2dp_sink_demo_cover_art_cid);
|
||||||
|
break;
|
||||||
|
case '@':
|
||||||
|
printf("Get linked thumbnail for '%s'\n", a2dp_sink_demo_image_handle);
|
||||||
|
#ifdef HAVE_POSIX_FILE_IO
|
||||||
|
a2dp_sink_cover_art_file = fopen(a2dp_sink_demo_thumbnail_path, "w");
|
||||||
|
#endif
|
||||||
|
a2dp_sink_cover_art_download_active = true;
|
||||||
|
a2dp_sink_cover_art_file_size = 0;
|
||||||
|
status = avrcp_cover_art_client_get_linked_thumbnail(a2dp_sink_demo_cover_art_cid, a2dp_sink_demo_image_handle);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
show_usage();
|
show_usage();
|
||||||
return;
|
return;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user