From 4931e24a4e38c450fc9f7aa14b9fea1c3ab0b574 Mon Sep 17 00:00:00 2001 From: Milanka Ringwald Date: Wed, 11 Apr 2018 15:50:46 +0200 Subject: [PATCH] avrcp browsing: implemented adding media item to now playing --- src/classic/avrcp.h | 1 + src/classic/avrcp_controller.c | 47 ++++++++++++++++++++++++++++++-- src/classic/avrcp_controller.h | 9 ++++++ test/pts/avrcp_controller_test.c | 35 ++++++++++++++++++++---- 4 files changed, 84 insertions(+), 8 deletions(-) diff --git a/src/classic/avrcp.h b/src/classic/avrcp.h index 8da8c2a1a..bc6664133 100644 --- a/src/classic/avrcp.h +++ b/src/classic/avrcp.h @@ -136,6 +136,7 @@ typedef enum { AVRCP_PDU_ID_PLAY_ITEM = 0x74, AVRCP_PDU_ID_GET_TOTAL_NUMBER_OF_ITEMS = 0x75, AVRCP_PDU_ID_SEARCH = 0x80, + AVRCP_PDU_ADD_TO_NOW_PLAYING = 0x90, AVRCP_PDU_ID_UNDEFINED = 0xFF } avrcp_pdu_id_t; diff --git a/src/classic/avrcp_controller.c b/src/classic/avrcp_controller.c index c3435a9c9..94a8dc76a 100644 --- a/src/classic/avrcp_controller.c +++ b/src/classic/avrcp_controller.c @@ -1239,10 +1239,13 @@ uint8_t avrcp_controller_disconnect(uint16_t avrcp_cid){ 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."); + log_error("Could not find a connection with cid 0%02x.", avrcp_cid); return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; } - if (connection->state != AVCTP_CONNECTION_OPENED) return ERROR_CODE_COMMAND_DISALLOWED; + if (connection->state != AVCTP_CONNECTION_OPENED){ + log_error("Connection in wrong state, expected %d, received %d", AVCTP_CONNECTION_OPENED, connection->state); + return ERROR_CODE_COMMAND_DISALLOWED; + } connection->state = AVCTP_W2_SEND_COMMAND; connection->transaction_label++; @@ -1273,6 +1276,46 @@ uint8_t avrcp_controller_play_item_for_scope(uint16_t avrcp_cid, uint8_t * uid, return ERROR_CODE_SUCCESS; } +uint8_t avrcp_controller_add_item_from_scope_to_now_playing_list(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("Could not find a connection with cid 0%02x.", avrcp_cid); + return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER; + } + if (connection->state != AVCTP_CONNECTION_OPENED){ + log_error("Connection in wrong state, expected %d, received %d", AVCTP_CONNECTION_OPENED, connection->state); + return ERROR_CODE_COMMAND_DISALLOWED; + } + connection->state = AVCTP_W2_SEND_COMMAND; + + connection->transaction_label++; + connection->command_type = AVRCP_CTYPE_CONTROL; + connection->subunit_type = AVRCP_SUBUNIT_TYPE_PANEL; + connection->subunit_id = AVRCP_SUBUNIT_ID; + connection->command_opcode = AVRCP_CMD_OPCODE_VENDOR_DEPENDENT; + int pos = 0; + big_endian_store_24(connection->cmd_operands, pos, BT_SIG_COMPANY_ID); + pos += 3; + connection->cmd_operands[pos++] = AVRCP_PDU_ADD_TO_NOW_PLAYING; // PDU ID + // reserved + connection->cmd_operands[pos++] = 0; + // Parameter Length + big_endian_store_16(connection->cmd_operands, pos, 11); + pos += 2; + connection->cmd_operands[pos++] = scope; + memset(&connection->cmd_operands[pos], 0, 8); + if (uid){ + memcpy(&connection->cmd_operands[pos], uid, 8); + } + pos += 8; + big_endian_store_16(connection->cmd_operands, pos, uid_counter); + pos += 2; + connection->cmd_operands_length = pos; + + avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid); + return ERROR_CODE_SUCCESS; +} + uint8_t avrcp_controller_set_max_num_fragments(uint16_t avrcp_cid, uint8_t max_num_fragments){ avrcp_connection_t * connection = get_avrcp_connection_for_avrcp_cid(avrcp_cid, &avrcp_controller_context); if (!connection){ diff --git a/src/classic/avrcp_controller.h b/src/classic/avrcp_controller.h index 6f1b5e992..2ea78a2b6 100644 --- a/src/classic/avrcp_controller.h +++ b/src/classic/avrcp_controller.h @@ -303,6 +303,15 @@ uint8_t avrcp_controller_set_repeat_mode(uint16_t avrcp_cid, avrcp_repeat_mode_t **/ 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 Adds an item indicated by the UID to the Now Playing queue. + * @param avrcp_cid + * @param uid + * @param uid_counter + * @param scope + **/ +uint8_t avrcp_controller_add_item_from_scope_to_now_playing_list(uint16_t avrcp_cid, uint8_t * uid, uint16_t uid_counter, avrcp_browsing_scope_t scope); + /** * @brief Set addressed player. * @param avrcp_cid diff --git a/test/pts/avrcp_controller_test.c b/test/pts/avrcp_controller_test.c index 0681c29e3..40549cc57 100644 --- a/test/pts/avrcp_controller_test.c +++ b/test/pts/avrcp_controller_test.c @@ -568,10 +568,13 @@ static void show_usage(void){ 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("pi - Play first media item for virtual filesystem scope \n"); + printf("pt - Play first media item for search scope \n"); + printf("pr - Play first media item for now playing scope\n"); + printf("p3 - Add to now playing: first media item from virtual file system\n"); + printf("p4 - Add to now playing: first media item from search folder\n"); + printf("Ctrl-c - exit\n"); printf("---\n"); } @@ -940,7 +943,7 @@ static void stdin_process(char * cmd, int size){ break; case 'i': - printf("Play first media item %s for virtual filesystem scope\n", (char *)parent_folder_name); + printf("Play first media item for virtual filesystem scope\n"); if (media_element_item_index < 0){ printf("AVRCP Browsing: no media items found\n"); break; @@ -949,7 +952,7 @@ static void stdin_process(char * cmd, int size){ 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); + printf("Play first media item for search scope\n"); if (media_element_item_index < 0){ printf("AVRCP Browsing: no media items found\n"); break; @@ -958,7 +961,7 @@ static void stdin_process(char * cmd, int size){ 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); + printf("Play first media item for now playing scope\n"); if (media_element_item_index < 0){ printf("AVRCP Browsing: no media items found\n"); break; @@ -967,6 +970,26 @@ static void stdin_process(char * cmd, int size){ status = avrcp_controller_play_item_for_scope(avrcp_cid, media_element_items[0].uid, media_element_item_index, AVRCP_BROWSING_NOW_PLAYING); break; + case '3': + printf("Add to now playing: first media item from virtual file system\n"); + 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_add_item_from_scope_to_now_playing_list(avrcp_cid, media_element_items[0].uid, media_element_item_index, AVRCP_BROWSING_MEDIA_PLAYER_VIRTUAL_FILESYSTEM); + break; + + case '4': + printf("Add to now playing: first media item from search folder\n"); + 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_add_item_from_scope_to_now_playing_list(avrcp_cid, media_element_items[0].uid, media_element_item_index, AVRCP_BROWSING_SEARCH); + break; + default: break; }