mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-03-14 01:27:41 +00:00
avrcp: introduced shuffle and repeat
This commit is contained in:
parent
96b12aa570
commit
2a029560d7
@ -1327,12 +1327,12 @@ typedef uint8_t sm_key_t[16];
|
||||
/** AVRCP Subevent */
|
||||
|
||||
/**
|
||||
* @format 1H2B1
|
||||
* @format 1H12B1
|
||||
* @param subevent_code
|
||||
* @param con_handle
|
||||
* @param status 0 == OK
|
||||
* @param local_cid
|
||||
* @param bd_addr
|
||||
* @param status 0 == OK
|
||||
*/
|
||||
#define AVRCP_SUBEVENT_CONNECTION_ESTABLISHED 0x01
|
||||
|
||||
@ -1341,13 +1341,13 @@ typedef uint8_t sm_key_t[16];
|
||||
* @param subevent_code
|
||||
* @param con_handle
|
||||
*/
|
||||
#define AVRCP_SUBEVENT_CONNECTION_CLOSED 0x02
|
||||
#define AVRCP_SUBEVENT_CONNECTION_CLOSED 0x02
|
||||
|
||||
#define AVRCP_NOW_PLAYING_INFO 0x03
|
||||
/**
|
||||
* @format 1HJVJVJVJV114
|
||||
* @format 1H1JVJVJVJV114
|
||||
* @param subevent_code
|
||||
* @param con_handle
|
||||
* @param status
|
||||
* @param title_len
|
||||
* @param title
|
||||
* @param artist_len
|
||||
@ -1360,6 +1360,16 @@ typedef uint8_t sm_key_t[16];
|
||||
* @param total_tracks
|
||||
* @param song_length in ms
|
||||
*/
|
||||
#define AVRCP_SUBEVENT_NOW_PLAYING_INFO 0x03
|
||||
|
||||
/**
|
||||
* @format 1H111
|
||||
* @param subevent_code
|
||||
* @param con_handle
|
||||
* @param status
|
||||
* @param repeat_mode
|
||||
* @param shuffle_mode
|
||||
*/
|
||||
#define AVRCP_SUBEVENT_SHUFFLE_AND_REPEAT_MODE 0x04
|
||||
|
||||
#endif
|
||||
|
@ -4262,6 +4262,15 @@ static inline const uint8_t * avdtp_subevent_signaling_media_codec_other_configu
|
||||
static inline hci_con_handle_t avrcp_subevent_connection_established_get_con_handle(const uint8_t * event){
|
||||
return little_endian_read_16(event, 3);
|
||||
}
|
||||
/**
|
||||
* @brief Get field status from event AVRCP_SUBEVENT_CONNECTION_ESTABLISHED
|
||||
* @param event packet
|
||||
* @return status
|
||||
* @note: btstack_type 1
|
||||
*/
|
||||
static inline uint8_t avrcp_subevent_connection_established_get_status(const uint8_t * event){
|
||||
return event[5];
|
||||
}
|
||||
/**
|
||||
* @brief Get field local_cid from event AVRCP_SUBEVENT_CONNECTION_ESTABLISHED
|
||||
* @param event packet
|
||||
@ -4269,7 +4278,7 @@ static inline hci_con_handle_t avrcp_subevent_connection_established_get_con_han
|
||||
* @note: btstack_type 2
|
||||
*/
|
||||
static inline uint16_t avrcp_subevent_connection_established_get_local_cid(const uint8_t * event){
|
||||
return little_endian_read_16(event, 5);
|
||||
return little_endian_read_16(event, 6);
|
||||
}
|
||||
/**
|
||||
* @brief Get field bd_addr from event AVRCP_SUBEVENT_CONNECTION_ESTABLISHED
|
||||
@ -4278,16 +4287,7 @@ static inline uint16_t avrcp_subevent_connection_established_get_local_cid(const
|
||||
* @note: btstack_type B
|
||||
*/
|
||||
static inline void avrcp_subevent_connection_established_get_bd_addr(const uint8_t * event, bd_addr_t bd_addr){
|
||||
reverse_bd_addr(&event[7], bd_addr);
|
||||
}
|
||||
/**
|
||||
* @brief Get field status from event AVRCP_SUBEVENT_CONNECTION_ESTABLISHED
|
||||
* @param event packet
|
||||
* @return status
|
||||
* @note: btstack_type 1
|
||||
*/
|
||||
static inline uint8_t avrcp_subevent_connection_established_get_status(const uint8_t * event){
|
||||
return event[13];
|
||||
reverse_bd_addr(&event[8], bd_addr);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -4300,6 +4300,161 @@ static inline hci_con_handle_t avrcp_subevent_connection_closed_get_con_handle(c
|
||||
return little_endian_read_16(event, 3);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get field con_handle from event AVRCP_SUBEVENT_NOW_PLAYING_INFO
|
||||
* @param event packet
|
||||
* @return con_handle
|
||||
* @note: btstack_type H
|
||||
*/
|
||||
static inline hci_con_handle_t avrcp_subevent_now_playing_info_get_con_handle(const uint8_t * event){
|
||||
return little_endian_read_16(event, 3);
|
||||
}
|
||||
/**
|
||||
* @brief Get field status from event AVRCP_SUBEVENT_NOW_PLAYING_INFO
|
||||
* @param event packet
|
||||
* @return status
|
||||
* @note: btstack_type 1
|
||||
*/
|
||||
static inline uint8_t avrcp_subevent_now_playing_info_get_status(const uint8_t * event){
|
||||
return event[5];
|
||||
}
|
||||
/**
|
||||
* @brief Get field title_len from event AVRCP_SUBEVENT_NOW_PLAYING_INFO
|
||||
* @param event packet
|
||||
* @return title_len
|
||||
* @note: btstack_type J
|
||||
*/
|
||||
static inline int avrcp_subevent_now_playing_info_get_title_len(const uint8_t * event){
|
||||
return event[6];
|
||||
}
|
||||
/**
|
||||
* @brief Get field title from event AVRCP_SUBEVENT_NOW_PLAYING_INFO
|
||||
* @param event packet
|
||||
* @return title
|
||||
* @note: btstack_type V
|
||||
*/
|
||||
static inline const uint8_t * avrcp_subevent_now_playing_info_get_title(const uint8_t * event){
|
||||
return &event[7];
|
||||
}
|
||||
/**
|
||||
* @brief Get field artist_len from event AVRCP_SUBEVENT_NOW_PLAYING_INFO
|
||||
* @param event packet
|
||||
* @return artist_len
|
||||
* @note: btstack_type J
|
||||
*/
|
||||
static inline int avrcp_subevent_now_playing_info_get_artist_len(const uint8_t * event){
|
||||
return event[6];
|
||||
}
|
||||
/**
|
||||
* @brief Get field artist from event AVRCP_SUBEVENT_NOW_PLAYING_INFO
|
||||
* @param event packet
|
||||
* @return artist
|
||||
* @note: btstack_type V
|
||||
*/
|
||||
static inline const uint8_t * avrcp_subevent_now_playing_info_get_artist(const uint8_t * event){
|
||||
return &event[7];
|
||||
}
|
||||
/**
|
||||
* @brief Get field album_len from event AVRCP_SUBEVENT_NOW_PLAYING_INFO
|
||||
* @param event packet
|
||||
* @return album_len
|
||||
* @note: btstack_type J
|
||||
*/
|
||||
static inline int avrcp_subevent_now_playing_info_get_album_len(const uint8_t * event){
|
||||
return event[6];
|
||||
}
|
||||
/**
|
||||
* @brief Get field album from event AVRCP_SUBEVENT_NOW_PLAYING_INFO
|
||||
* @param event packet
|
||||
* @return album
|
||||
* @note: btstack_type V
|
||||
*/
|
||||
static inline const uint8_t * avrcp_subevent_now_playing_info_get_album(const uint8_t * event){
|
||||
return &event[7];
|
||||
}
|
||||
/**
|
||||
* @brief Get field genre_len from event AVRCP_SUBEVENT_NOW_PLAYING_INFO
|
||||
* @param event packet
|
||||
* @return genre_len
|
||||
* @note: btstack_type J
|
||||
*/
|
||||
static inline int avrcp_subevent_now_playing_info_get_genre_len(const uint8_t * event){
|
||||
return event[6];
|
||||
}
|
||||
/**
|
||||
* @brief Get field genre from event AVRCP_SUBEVENT_NOW_PLAYING_INFO
|
||||
* @param event packet
|
||||
* @return genre
|
||||
* @note: btstack_type V
|
||||
*/
|
||||
static inline const uint8_t * avrcp_subevent_now_playing_info_get_genre(const uint8_t * event){
|
||||
return &event[7];
|
||||
}
|
||||
/**
|
||||
* @brief Get field track from event AVRCP_SUBEVENT_NOW_PLAYING_INFO
|
||||
* @param event packet
|
||||
* @return track
|
||||
* @note: btstack_type 1
|
||||
*/
|
||||
static inline uint8_t avrcp_subevent_now_playing_info_get_track(const uint8_t * event){
|
||||
return event[6];
|
||||
}
|
||||
/**
|
||||
* @brief Get field total_tracks from event AVRCP_SUBEVENT_NOW_PLAYING_INFO
|
||||
* @param event packet
|
||||
* @return total_tracks
|
||||
* @note: btstack_type 1
|
||||
*/
|
||||
static inline uint8_t avrcp_subevent_now_playing_info_get_total_tracks(const uint8_t * event){
|
||||
return event[7];
|
||||
}
|
||||
/**
|
||||
* @brief Get field song_length from event AVRCP_SUBEVENT_NOW_PLAYING_INFO
|
||||
* @param event packet
|
||||
* @return song_length
|
||||
* @note: btstack_type 4
|
||||
*/
|
||||
static inline uint32_t avrcp_subevent_now_playing_info_get_song_length(const uint8_t * event){
|
||||
return little_endian_read_32(event, 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get field con_handle from event AVRCP_SUBEVENT_SHUFFLE_AND_REPEAT_MODE
|
||||
* @param event packet
|
||||
* @return con_handle
|
||||
* @note: btstack_type H
|
||||
*/
|
||||
static inline hci_con_handle_t avrcp_subevent_shuffle_and_repeat_mode_get_con_handle(const uint8_t * event){
|
||||
return little_endian_read_16(event, 3);
|
||||
}
|
||||
/**
|
||||
* @brief Get field status from event AVRCP_SUBEVENT_SHUFFLE_AND_REPEAT_MODE
|
||||
* @param event packet
|
||||
* @return status
|
||||
* @note: btstack_type 1
|
||||
*/
|
||||
static inline uint8_t avrcp_subevent_shuffle_and_repeat_mode_get_status(const uint8_t * event){
|
||||
return event[5];
|
||||
}
|
||||
/**
|
||||
* @brief Get field repeat_mode from event AVRCP_SUBEVENT_SHUFFLE_AND_REPEAT_MODE
|
||||
* @param event packet
|
||||
* @return repeat_mode
|
||||
* @note: btstack_type 1
|
||||
*/
|
||||
static inline uint8_t avrcp_subevent_shuffle_and_repeat_mode_get_repeat_mode(const uint8_t * event){
|
||||
return event[6];
|
||||
}
|
||||
/**
|
||||
* @brief Get field shuffle_mode from event AVRCP_SUBEVENT_SHUFFLE_AND_REPEAT_MODE
|
||||
* @param event packet
|
||||
* @return shuffle_mode
|
||||
* @note: btstack_type 1
|
||||
*/
|
||||
static inline uint8_t avrcp_subevent_shuffle_and_repeat_mode_get_shuffle_mode(const uint8_t * event){
|
||||
return event[7];
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* API_END */
|
||||
|
@ -1119,4 +1119,71 @@ void avrcp_set_absolute_volume(uint16_t con_handle, uint8_t volume){
|
||||
avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid);
|
||||
}
|
||||
|
||||
void avrcp_query_shuffle_and_repeat_modes(uint16_t con_handle){
|
||||
avrcp_connection_t * connection = get_avrcp_connection_for_con_handle(con_handle);
|
||||
if (!connection){
|
||||
log_error("avrcp_get_capabilities: coud not find a connection.");
|
||||
return;
|
||||
}
|
||||
if (connection->state != AVCTP_CONNECTION_OPENED) return;
|
||||
connection->state = AVCTP_W2_SEND_COMMAND;
|
||||
|
||||
connection->transaction_label++;
|
||||
connection->cmd_to_send = AVRCP_CMD_OPCODE_VENDOR_DEPENDENT;
|
||||
connection->command_type = AVRCP_CTYPE_STATUS;
|
||||
connection->subunit_type = AVRCP_SUBUNIT_TYPE_PANEL;
|
||||
connection->subunit_id = 0;
|
||||
big_endian_store_24(connection->cmd_operands, 0, BT_SIG_COMPANY_ID);
|
||||
connection->cmd_operands[3] = AVRCP_PDU_ID_GetCurrentPlayerApplicationSettingValue; // PDU ID
|
||||
connection->cmd_operands[4] = 0;
|
||||
big_endian_store_16(connection->cmd_operands, 5, 5); // parameter length
|
||||
connection->cmd_operands[7] = 4; // NumPlayerApplicationSettingAttributeID
|
||||
// PlayerApplicationSettingAttributeID1 AVRCP Spec, Appendix F, 133
|
||||
connection->cmd_operands[8] = 0x01; // equalizer (1-OFF, 2-ON)
|
||||
connection->cmd_operands[9] = 0x02; // repeat (1-off, 2-single track, 3-all tracks, 4-group repeat)
|
||||
connection->cmd_operands[10] = 0x03; // shuffle (1-off, 2-all tracks, 3-group shuffle)
|
||||
connection->cmd_operands[11] = 0x04; // scan (1-off, 2-all tracks, 3-group scan)
|
||||
connection->cmd_operands_lenght = 12;
|
||||
avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid);
|
||||
}
|
||||
|
||||
|
||||
static void avrcp_set_current_player_application_setting_value(uint16_t con_handle, uint8_t attribute_id, uint8_t attribute_value){
|
||||
avrcp_connection_t * connection = get_avrcp_connection_for_con_handle(con_handle);
|
||||
if (!connection){
|
||||
log_error("avrcp_get_capabilities: coud not find a connection.");
|
||||
return;
|
||||
}
|
||||
if (connection->state != AVCTP_CONNECTION_OPENED) return;
|
||||
connection->state = AVCTP_W2_SEND_COMMAND;
|
||||
|
||||
connection->transaction_label++;
|
||||
connection->cmd_to_send = AVRCP_CMD_OPCODE_VENDOR_DEPENDENT;
|
||||
connection->command_type = AVRCP_CTYPE_CONTROL;
|
||||
connection->subunit_type = AVRCP_SUBUNIT_TYPE_PANEL;
|
||||
connection->subunit_id = 0;
|
||||
int pos = 0;
|
||||
big_endian_store_24(connection->cmd_operands, pos, BT_SIG_COMPANY_ID);
|
||||
pos += 3;
|
||||
connection->cmd_operands[pos++] = AVRCP_PDU_ID_SetPlayerApplicationSettingValue; // PDU ID
|
||||
connection->cmd_operands[pos++] = 0;
|
||||
// Parameter Length
|
||||
big_endian_store_16(connection->cmd_operands, pos, 3);
|
||||
pos += 2;
|
||||
connection->cmd_operands[pos++] = 2;
|
||||
connection->cmd_operands_lenght = pos;
|
||||
connection->cmd_operands[pos++] = attribute_id;
|
||||
connection->cmd_operands[pos++] = attribute_value;
|
||||
connection->cmd_operands_lenght = pos;
|
||||
avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid);
|
||||
}
|
||||
|
||||
void avrcp_set_shuffle_mode(uint16_t con_handle, avrcp_shuffle_mode_t mode){
|
||||
if (mode < AVRCP_SHUFFLE_MODE_OFF || mode > AVRCP_SHUFFLE_MODE_GROUP) return;
|
||||
avrcp_set_current_player_application_setting_value(con_handle, 0x03, mode);
|
||||
}
|
||||
|
||||
void avrcp_set_repeat_mode(uint16_t con_handle, avrcp_repeat_mode_t mode){
|
||||
if (mode < AVRCP_REPEAT_MODE_OFF || mode > AVRCP_REPEAT_MODE_GROUP) return;
|
||||
avrcp_set_current_player_application_setting_value(con_handle, 0x02, mode);
|
||||
}
|
@ -70,6 +70,8 @@ typedef enum {
|
||||
|
||||
typedef enum {
|
||||
AVRCP_PDU_ID_GET_CAPABILITIES = 0x10,
|
||||
AVRCP_PDU_ID_GetCurrentPlayerApplicationSettingValue = 0x13,
|
||||
AVRCP_PDU_ID_SetPlayerApplicationSettingValue = 0x14,
|
||||
AVRCP_PDU_ID_GET_ELEMENT_ATTRIBUTES = 0x20,
|
||||
AVRCP_PDU_ID_GET_PLAY_STATUS = 0x30,
|
||||
AVRCP_PDU_ID_REGISTER_NOTIFICATION = 0x31,
|
||||
@ -201,15 +203,28 @@ typedef struct {
|
||||
uint16_t notifications_to_deregister;
|
||||
} avrcp_connection_t;
|
||||
|
||||
typedef enum {
|
||||
typedef enum {
|
||||
AVRCP_PLAY_STATUS_STOPPED = 0x00,
|
||||
AVRCP_PLAY_STATUS_PLAYING,
|
||||
AVRCP_PLAY_STATUS_PAUSED,
|
||||
AVRCP_PLAY_STATUS_FWD_SEEK,
|
||||
AVRCP_PLAY_STATUS_REV_SEEK,
|
||||
AVRCP_PLAY_STATUS_ERROR = 0xFF
|
||||
} avrcp_play_status_t;
|
||||
|
||||
} avrcp_play_status_t;
|
||||
|
||||
typedef enum {
|
||||
AVRCP_SHUFFLE_MODE_OFF = 0x01,
|
||||
AVRCP_SHUFFLE_MODE_ALL_TRACKS,
|
||||
AVRCP_SHUFFLE_MODE_GROUP
|
||||
} avrcp_shuffle_mode_t;
|
||||
|
||||
typedef enum {
|
||||
AVRCP_REPEAT_MODE_OFF = 0x01,
|
||||
AVRCP_REPEAT_MODE_SINGLE_TRACK,
|
||||
AVRCP_REPEAT_MODE_ALL_TRACKS,
|
||||
AVRCP_REPEAT_MODE_GROUP
|
||||
} avrcp_repeat_mode_t;
|
||||
|
||||
/**
|
||||
* @brief AVDTP Sink service record.
|
||||
* @param service
|
||||
@ -360,6 +375,24 @@ void avrcp_start_mute(uint16_t con_handle);
|
||||
*/
|
||||
void avrcp_start_skip(uint16_t con_handle);
|
||||
|
||||
/**
|
||||
* @brief Query repeat and shuffle mode.
|
||||
* @param con_handle
|
||||
*/
|
||||
void avrcp_query_shuffle_and_repeat_modes(uint16_t con_handle);
|
||||
|
||||
/**
|
||||
* @brief Set shuffle mode.
|
||||
* @param con_handle
|
||||
*/
|
||||
void avrcp_set_shuffle_mode(uint16_t con_handle, avrcp_shuffle_mode_t mode);
|
||||
|
||||
/**
|
||||
* @brief Set repeat mode.
|
||||
* @param con_handle
|
||||
*/
|
||||
void avrcp_set_repeat_mode(uint16_t con_handle, avrcp_repeat_mode_t mode);
|
||||
|
||||
/* API_END */
|
||||
#if defined __cplusplus
|
||||
}
|
||||
|
@ -142,6 +142,13 @@ static void show_usage(void){
|
||||
printf("a - absolute volume of %d percent\n", 5000/127);
|
||||
printf("m - mute\n");
|
||||
printf("k - skip\n");
|
||||
|
||||
printf("q - query repeat and shuffle mode\n");
|
||||
printf("x - set repeat mode: SINGLE_TRACK\n");
|
||||
printf("X - disable repeat mode\n");
|
||||
printf("y - set shuffle mode ALL_TRACKS\n");
|
||||
printf("Y - disable shuffle mode\n");
|
||||
|
||||
printf("Ctrl-c - exit\n");
|
||||
printf("---\n");
|
||||
}
|
||||
@ -218,7 +225,22 @@ static void stdin_process(btstack_data_source_t *ds, btstack_data_source_callbac
|
||||
case 'k':
|
||||
avrcp_start_skip(con_handle);
|
||||
break;
|
||||
|
||||
case 'q':
|
||||
avrcp_query_shuffle_and_repeat_modes(con_handle);
|
||||
break;
|
||||
case 'x':
|
||||
avrcp_set_repeat_mode(con_handle, AVRCP_REPEAT_MODE_SINGLE_TRACK);
|
||||
break;
|
||||
case 'X':
|
||||
avrcp_set_repeat_mode(con_handle, AVRCP_REPEAT_MODE_OFF);
|
||||
break;
|
||||
case 'y':
|
||||
avrcp_set_shuffle_mode(con_handle, AVRCP_SHUFFLE_MODE_ALL_TRACKS);
|
||||
break;
|
||||
case 'Y':
|
||||
avrcp_set_shuffle_mode(con_handle, AVRCP_SHUFFLE_MODE_OFF);
|
||||
break;
|
||||
|
||||
default:
|
||||
show_usage();
|
||||
break;
|
||||
|
Loading…
x
Reference in New Issue
Block a user