Commit 240ad5ce authored by Make Shi's avatar Make Shi Committed by Chris Friedt
Browse files

bluetooth: avrcp: Add support for AVRCP browsing



- AVRCP SDP record updates for browsing channel
- L2CAP setup for AVCTP browsing channel, and add connect/disconnect
- Add SetBrowsedPlayer browsing command handling

Signed-off-by: default avatarMake Shi <make.shi@nxp.com>
parent b923bde6
Loading
Loading
Loading
Loading
+248 −2
Original line number Diff line number Diff line
@@ -141,6 +141,124 @@ typedef enum __packed {
	BT_AVRCP_BUTTON_RELEASED = 1,
} bt_avrcp_button_state_t;

/**
 * @brief AVRCP status and error codes.
 *
 * These status codes are used in AVRCP responses to indicate the result of a command.
 */
typedef enum __packed {
	/** Invalid command.
	 * Valid for Commands: All
	 */
	BT_AVRCP_STATUS_INVALID_COMMAND = 0x00,

	/** Invalid parameter.
	 * Valid for Commands: All
	 */
	BT_AVRCP_STATUS_INVALID_PARAMETER = 0x01,

	/** Parameter content error.
	 * Valid for Commands: All
	 */
	BT_AVRCP_STATUS_PARAMETER_CONTENT_ERROR = 0x02,

	/** Internal error.
	 * Valid for Commands: All
	 */
	BT_AVRCP_STATUS_INTERNAL_ERROR = 0x03,

	/** Operation completed without error.
	 * Valid for Commands: All except where the response CType is AV/C REJECTED
	 */
	BT_AVRCP_STATUS_OPERATION_COMPLETED = 0x04,

	/** The UIDs on the device have changed.
	 * Valid for Commands: All
	 */
	BT_AVRCP_STATUS_UID_CHANGED = 0x05,

	/** The Direction parameter is invalid.
	 * Valid for Commands: ChangePath
	 */
	BT_AVRCP_STATUS_INVALID_DIRECTION = 0x07,

	/** The UID provided does not refer to a folder item.
	 * Valid for Commands: ChangePath
	 */
	BT_AVRCP_STATUS_NOT_A_DIRECTORY = 0x08,

	/** The UID provided does not refer to any currently valid item.
	 * Valid for Commands: ChangePath, PlayItem, AddToNowPlaying, GetItemAttributes
	 */
	BT_AVRCP_STATUS_DOES_NOT_EXIST = 0x09,

	/** Invalid scope.
	 * Valid for Commands: GetFolderItems, PlayItem, AddToNowPlayer, GetItemAttributes,
	 * GetTotalNumberOfItems
	 */
	BT_AVRCP_STATUS_INVALID_SCOPE = 0x0a,

	/** Range out of bounds.
	 * Valid for Commands: GetFolderItems
	 */
	BT_AVRCP_STATUS_RANGE_OUT_OF_BOUNDS = 0x0b,

	/** Folder item is not playable.
	 * Valid for Commands: Play Item, AddToNowPlaying
	 */
	BT_AVRCP_STATUS_FOLDER_ITEM_IS_NOT_PLAYABLE = 0x0c,

	/** Media in use.
	 * Valid for Commands: PlayItem, AddToNowPlaying
	 */
	BT_AVRCP_STATUS_MEDIA_IN_USE = 0x0d,

	/** Now Playing List full.
	 * Valid for Commands: AddToNowPlaying
	 */
	BT_AVRCP_STATUS_NOW_PLAYING_LIST_FULL = 0x0e,

	/** Search not supported.
	 * Valid for Commands: Search
	 */
	BT_AVRCP_STATUS_SEARCH_NOT_SUPPORTED = 0x0f,

	/** Search in progress.
	 * Valid for Commands: Search
	 */
	BT_AVRCP_STATUS_SEARCH_IN_PROGRESS = 0x10,

	/** The specified Player Id does not refer to a valid player.
	 * Valid for Commands: SetAddressedPlayer, SetBrowsedPlayer
	 */
	BT_AVRCP_STATUS_INVALID_PLAYER_ID = 0x11,

	/** Player not browsable.
	 * Valid for Commands: SetBrowsedPlayer
	 */
	BT_AVRCP_STATUS_PLAYER_NOT_BROWSABLE = 0x12,

	/** Player not addressed.
	 * Valid for Commands: Search, SetBrowsedPlayer
	 */
	BT_AVRCP_STATUS_PLAYER_NOT_ADDRESSED = 0x13,

	/** No valid search results.
	 * Valid for Commands: GetFolderItems
	 */
	BT_AVRCP_STATUS_NO_VALID_SEARCH_RESULTS = 0x14,

	/** No available players.
	 * Valid for Commands: ALL
	 */
	BT_AVRCP_STATUS_NO_AVAILABLE_PLAYERS = 0x15,

	/** Addressed player changed.
	 * Valid for Commands: All Register Notification commands
	 */
	BT_AVRCP_STATUS_ADDRESSED_PLAYER_CHANGED = 0x16,
} bt_avrcp_status_t;

/** @brief AVRCP CT structure */
struct bt_avrcp_ct;
/** @brief AVRCP TG structure */
@@ -167,13 +285,34 @@ struct bt_avrcp_passthrough_rsp {
	uint8_t byte0; /**< [7]: state_flag, [6:0]: opid */
	uint8_t data_len;
	uint8_t data[];
};
} __packed;

struct bt_avrcp_get_cap_rsp {
	uint8_t cap_id;  /**< bt_avrcp_cap_t */
	uint8_t cap_cnt; /**< number of items contained in *cap */
	uint8_t cap[];   /**< 1 or 3 octets each depends on cap_id */
};
} __packed;

/** @brief AVRCP Character Set IDs */
typedef enum __packed {
	BT_AVRCP_CHARSET_UTF8 = 0x006a,
} bt_avrcp_charset_t;

/** @brief get folder name (response) */
struct bt_avrcp_folder_name {
	uint16_t folder_name_len;
	uint8_t folder_name[];
} __packed;

/** @brief Set browsed player response structure */
struct bt_avrcp_set_browsed_player_rsp {
	uint8_t status;                              /**< Status see bt_avrcp_status_t.*/
	uint16_t uid_counter;                        /**< UID counter */
	uint32_t num_items;                          /**< Number of items in the folder */
	uint16_t charset_id;                         /**< Character set ID */
	uint8_t folder_depth;                        /**< Folder depth */
	struct bt_avrcp_folder_name folder_names[0]; /**< Folder names data */
} __packed;

struct bt_avrcp_ct_cb {
	/** @brief An AVRCP CT connection has been established.
@@ -195,6 +334,25 @@ struct bt_avrcp_ct_cb {
	 */
	void (*disconnected)(struct bt_avrcp_ct *ct);

	/** @brief An AVRCP CT browsing connection has been established.
	 *
	 *  This callback notifies the application of an avrcp browsing connection,
	 *  i.e., an AVCTP browsing L2CAP connection.
	 *
	 *  @param conn Connection object.
	 *  @param ct AVRCP CT connection object.
	 */
	void (*browsing_connected)(struct bt_conn *conn, struct bt_avrcp_ct *ct);

	/** @brief An AVRCP CT browsing connection has been disconnected.
	 *
	 *  This callback notifies the application that an avrcp browsing connection
	 *  has been disconnected.
	 *
	 *  @param ct AVRCP CT connection object.
	 */
	void (*browsing_disconnected)(struct bt_avrcp_ct *ct);

	/** @brief Callback function for bt_avrcp_get_cap().
	 *
	 *  Called when the get capabilities process is completed.
@@ -239,6 +397,19 @@ struct bt_avrcp_ct_cb {
	 */
	void (*passthrough_rsp)(struct bt_avrcp_ct *ct, uint8_t tid, bt_avrcp_rsp_t result,
				const struct bt_avrcp_passthrough_rsp *rsp);

	/** @brief Callback function for bt_avrcp_ct_set_browsed_player().
	 *
	 *  Called when the set browsed player process is completed.
	 *
	 *  @param ct AVRCP CT connection object.
	 *  @param tid The transaction label of the response.
	 *  @param buf The response buffer containing the set browsed player response data.
	 *             The application can parse this payload according to the format defined in
	 *             @ref bt_avrcp_set_browsed_player_rsp. Note that the data is encoded in
	 *             big-endian format.
	 */
	void (*browsed_player_rsp)(struct bt_avrcp_ct *ct, uint8_t tid, struct net_buf *buf);
};

/** @brief Connect AVRCP.
@@ -277,6 +448,27 @@ int bt_avrcp_disconnect(struct bt_conn *conn);
 */
struct net_buf *bt_avrcp_create_pdu(struct net_buf_pool *pool);

/** @brief Connect AVRCP browsing channel.
 *
 *  This function is to be called after the AVRCP control channel is established.
 *  The API is to be used to establish AVRCP browsing connection between devices.
 *
 *  @param conn Pointer to bt_conn structure.
 *
 *  @return 0 in case of success or error code in case of error.
 */
int bt_avrcp_browsing_connect(struct bt_conn *conn);

/** @brief Disconnect AVRCP browsing channel.
 *
 *  This function close AVCTP browsing channel L2CAP connection.
 *
 *  @param conn Pointer to bt_conn structure.
 *
 *  @return 0 in case of success or error code in case of error.
 */
int bt_avrcp_browsing_disconnect(struct bt_conn *conn);

/** @brief Register callback.
 *
 *  Register AVRCP callbacks to monitor the state and interact with the remote device.
@@ -339,6 +531,18 @@ int bt_avrcp_ct_get_subunit_info(struct bt_avrcp_ct *ct, uint8_t tid);
int bt_avrcp_ct_passthrough(struct bt_avrcp_ct *ct, uint8_t tid, uint8_t opid, uint8_t state,
			    const uint8_t *payload, uint8_t len);

/** @brief Set browsed player.
 *
 *  This function sets the browsed player on the remote device.
 *
 *  @param ct The AVRCP CT instance.
 *  @param tid The transaction label of the response, valid from 0 to 15.
 *  @param player_id The player ID to be set as browsed player.
 *
 *  @return 0 in case of success or error code in case of error.
 */
int bt_avrcp_ct_set_browsed_player(struct bt_avrcp_ct *ct, uint8_t tid, uint16_t player_id);

struct bt_avrcp_tg_cb {
	/** @brief An AVRCP TG connection has been established.
	 *
@@ -367,6 +571,35 @@ struct bt_avrcp_tg_cb {
	 *  @param tg AVRCP TG connection object.
	 */
	void (*unit_info_req)(struct bt_avrcp_tg *tg, uint8_t tid);

	/** @brief An AVRCP TG browsing connection has been established.
	 *
	 *  This callback notifies the application of an avrcp browsing connection,
	 *  i.e., an AVCTP browsing L2CAP connection.
	 *
	 *  @param conn Connection object.
	 *  @param tg AVRCP TG connection object.
	 */
	void (*browsing_connected)(struct bt_conn *conn, struct bt_avrcp_tg *tg);

	/** @brief An AVRCP TG browsing connection has been disconnected.
	 *
	 *  This callback notifies the application that an avrcp browsing connection
	 *  has been disconnected.
	 *
	 *  @param tg AVRCP TG connection object.
	 */
	void (*browsing_disconnected)(struct bt_avrcp_tg *tg);

	/** @brief Set browsed player request callback.
	 *
	 *  This callback is called whenever an AVRCP set browsed player request is received.
	 *
	 *  @param tg AVRCP TG connection object.
	 *  @param tid The transaction label of the request.
	 *  @param player_id The player ID to be set as browsed player.
	 */
	void (*set_browsed_player_req)(struct bt_avrcp_tg *tg, uint8_t tid, uint16_t player_id);
};

/** @brief Register callback.
@@ -391,6 +624,19 @@ int bt_avrcp_tg_register_cb(const struct bt_avrcp_tg_cb *cb);
 */
int bt_avrcp_tg_send_unit_info_rsp(struct bt_avrcp_tg *tg, uint8_t tid,
				   struct bt_avrcp_unit_info_rsp *rsp);

/** @brief Send the set browsed player response.
 *
 *  This function is called by the application to send the set browsed player response.
 *
 *  @param tg The AVRCP TG instance.
 *  @param tid The transaction label of the response, valid from 0 to 15.
 *  @param buf The response buffer containing the set browsed player response data.
 *
 *  @return 0 in case of success or error code in case of error.
 */
int bt_avrcp_tg_send_set_browsed_player_rsp(struct bt_avrcp_tg *tg, uint8_t tid,
					    struct net_buf *buf);
#ifdef __cplusplus
}
#endif
+8 −0
Original line number Diff line number Diff line
@@ -485,6 +485,14 @@ config BT_AVRCP_CONTROLLER
	help
	  This option enables the AVRCP profile controller function

config BT_AVRCP_BROWSING
	bool "Bluetooth AVRCP Browsing channel support [EXPERIMENTAL]"
	select EXPERIMENTAL
	select BT_L2CAP_ENH_RET
	help
	  This option enables support for the AVRCP Browsing channel
	  over Bluetooth BR/EDR.

endif # BT_AVRCP

config BT_PAGE_TIMEOUT
+508 −9

File changed.

Preview size limit exceeded, changes collapsed.

+24 −4
Original line number Diff line number Diff line
@@ -16,6 +16,11 @@
#define AVRCP_CAT_2                       BIT(1) /* Monitor/Amplifier */
#define AVRCP_CAT_3                       BIT(2) /* Tuner */
#define AVRCP_CAT_4                       BIT(3) /* Menu */
#define AVRCP_PLAYER_APPLICATION_SETTINGS BIT(4) /* Bit 0 must also be set */
#define AVRCP_GROUP_NAVIGATION            BIT(5) /* Bit 0 must also be set */
#define AVRCP_BROWSING_SUPPORT            BIT(6)
#define AVRCP_MULTIPLE_MEDIA_PLAYERS      BIT(7)
#define AVRCP_COVER_ART_SUPPORT           BIT(8)

#define AVRCP_SUBUNIT_PAGE              (0) /* Fixed value according to AVRCP */
#define AVRCP_SUBUNIT_EXTENSION_CODE    (7) /* Fixed value according to TA Document 2001012 */
@@ -23,6 +28,15 @@
#define BT_AVRCP_UNIT_INFO_RSP_SIZE     (5)
#define BT_AVRCP_SUBUNIT_INFO_RSP_SIZE  (5)

#define BT_L2CAP_PSM_AVRCP 0x0017
#define BT_L2CAP_PSM_AVRCP_BROWSING 0x001b

#if defined(CONFIG_BT_AVRCP_BROWSING)
#define AVRCP_BROWSING_ENABLE AVRCP_BROWSING_SUPPORT
#else
#define AVRCP_BROWSING_ENABLE 0
#endif /* CONFIG_BT_AVRCP_BROWSING */

typedef enum __packed {
	BT_AVRCP_SUBUNIT_ID_ZERO = 0x0,
	BT_AVRCP_SUBUNIT_ID_IGNORE = 0x7,
@@ -122,6 +136,12 @@ struct bt_avrcp_avc_pdu {
	uint8_t param[];
} __packed;

struct bt_avrcp_avc_brow_pdu {
	uint8_t pdu_id;
	uint16_t param_len;
	uint8_t param[];
} __packed;

/** The 4-bit command type or the 4-bit response code. */
#define BT_AVRCP_HDR_GET_CTYPE_OR_RSP(hdr) FIELD_GET(GENMASK(3, 0), ((hdr)->byte0))
/** Taken together, the subunit_type and subunit_ID fields define the command recipient’s  address