Bluetooth: AVRCP: Implemation of AVRCP.

This patch implementing avrcp.c
New Kconfig BT_AVRCP is provided to enable this layer.
BT_AVRCP_TARGET and BT_AVRCP_CONTROLLER are then
provided to enable one of the two roles independently.
avrcp.h shows the APIs for the upper layer.

Only connection and disconnection interfaces are provided in this patch.

Signed-off-by: Zihao Gao <gaozihao@xiaomi.com>
This commit is contained in:
Zihao Gao 2024-10-30 10:45:02 +08:00 committed by Anas Nashif
parent 27f71b044a
commit 70b415dab6
7 changed files with 279 additions and 0 deletions

View file

@ -0,0 +1,78 @@
/** @file
* @brief Audio Video Remote Control Profile header.
*/
/*
* Copyright (c) 2015-2016 Intel Corporation
* Copyright (C) 2024 Xiaomi Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_INCLUDE_BLUETOOTH_AVRCP_H_
#define ZEPHYR_INCLUDE_BLUETOOTH_AVRCP_H_
#ifdef __cplusplus
extern "C" {
#endif
/** @brief AVRCP structure */
struct bt_avrcp;
struct bt_avrcp_cb {
/** @brief An AVRCP connection has been established.
*
* This callback notifies the application of an avrcp connection,
* i.e., an AVCTP L2CAP connection.
*
* @param avrcp AVRCP connection object.
*/
void (*connected)(struct bt_avrcp *avrcp);
/** @brief An AVRCP connection has been disconnected.
*
* This callback notifies the application that an avrcp connection
* has been disconnected.
*
* @param avrcp AVRCP connection object.
*/
void (*disconnected)(struct bt_avrcp *avrcp);
};
/** @brief Connect AVRCP.
*
* This function is to be called after the conn parameter is obtained by
* performing a GAP procedure. The API is to be used to establish AVRCP
* connection between devices.
*
* @param conn Pointer to bt_conn structure.
*
* @return pointer to struct bt_avrcp in case of success or NULL in case
* of error.
*/
struct bt_avrcp *bt_avrcp_connect(struct bt_conn *conn);
/** @brief Disconnect AVRCP.
*
* This function close AVCTP L2CAP connection.
*
* @param avrcp The AVRCP instance.
*
* @return 0 in case of success or error code in case of error.
*/
int bt_avrcp_disconnect(struct bt_avrcp *avrcp);
/** @brief Register callback.
*
* Register AVRCP callbacks to monitor the state and interact with the remote device.
*
* @param cb The callback function.
*
* @return 0 in case of success or error code in case of error.
*/
int bt_avrcp_register_cb(const struct bt_avrcp_cb *cb);
#ifdef __cplusplus
}
#endif
#endif /* ZEPHYR_INCLUDE_BLUETOOTH_AVRCP_H_ */

View file

@ -391,6 +391,10 @@ module = BT_AVCTP
module-str = "Bluetooth AVCTP"
source "subsys/logging/Kconfig.template.log_config_inherit"
module = BT_AVRCP
module-str = "Bluetooth AVRCP"
source "subsys/logging/Kconfig.template.log_config_inherit"
module = BT_SDP
module-str = "Bluetooth Service Discovery Protocol (SDP)"
source "subsys/logging/Kconfig.template.log_config_inherit"

View file

@ -7,6 +7,7 @@ zephyr_library_link_libraries(subsys__bluetooth)
zephyr_library_sources_ifdef(CONFIG_BT_A2DP a2dp.c a2dp_codec_sbc.c)
zephyr_library_sources_ifdef(CONFIG_BT_AVDTP avdtp.c)
zephyr_library_sources_ifdef(CONFIG_BT_AVRCP avrcp.c)
zephyr_library_sources_ifdef(CONFIG_BT_AVCTP avctp.c)
zephyr_library_sources_ifdef(CONFIG_BT_RFCOMM rfcomm.c)

View file

@ -184,6 +184,27 @@ config BT_AVCTP
help
This option enables Bluetooth AVCTP support
config BT_AVRCP
bool "Bluetooth AVRCP Profile [EXPERIMENTAL]"
select BT_AVCTP
select EXPERIMENTAL
help
This option enables the AVRCP profile
if BT_AVRCP
config BT_AVRCP_TARGET
bool "Bluetooth AVRCP Profile Target Function"
help
This option enables the AVRCP profile target function
config BT_AVRCP_CONTROLLER
bool "Bluetooth AVRCP Profile Controller Function"
help
This option enables the AVRCP profile controller function
endif # BT_AVRCP
config BT_PAGE_TIMEOUT
hex "Bluetooth Page Timeout"
default 0x2000

View file

@ -0,0 +1,158 @@
/** @file
* @brief Audio Video Remote Control Profile
*/
/*
* Copyright (c) 2015-2016 Intel Corporation
* Copyright (C) 2024 Xiaomi Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <errno.h>
#include <zephyr/sys/atomic.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/sys/util.h>
#include <zephyr/sys/printk.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/classic/avrcp.h>
#include <zephyr/bluetooth/l2cap.h>
#include "host/hci_core.h"
#include "host/conn_internal.h"
#include "host/l2cap_internal.h"
#include "avctp_internal.h"
#include "avrcp_internal.h"
#define LOG_LEVEL CONFIG_BT_AVRCP_LOG_LEVEL
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(bt_avrcp);
struct bt_avrcp {
struct bt_avctp session;
};
#define AVRCP_AVCTP(_avctp) CONTAINER_OF(_avctp, struct bt_avrcp, session)
static const struct bt_avrcp_cb *avrcp_cb;
static struct bt_avrcp avrcp_connection[CONFIG_BT_MAX_CONN];
static struct bt_avrcp *get_new_connection(struct bt_conn *conn)
{
struct bt_avrcp *avrcp;
if (!conn) {
LOG_ERR("Invalid Input (err: %d)", -EINVAL);
return NULL;
}
avrcp = &avrcp_connection[bt_conn_index(conn)];
memset(avrcp, 0, sizeof(struct bt_avrcp));
return avrcp;
}
/* The AVCTP L2CAP channel established */
static void avrcp_connected(struct bt_avctp *session)
{
struct bt_avrcp *avrcp = AVRCP_AVCTP(session);
if ((avrcp_cb != NULL) && (avrcp_cb->connected != NULL)) {
avrcp_cb->connected(avrcp);
}
}
/* The AVCTP L2CAP channel released */
static void avrcp_disconnected(struct bt_avctp *session)
{
struct bt_avrcp *avrcp = AVRCP_AVCTP(session);
if ((avrcp_cb != NULL) && (avrcp_cb->disconnected != NULL)) {
avrcp_cb->disconnected(avrcp);
}
}
static const struct bt_avctp_ops_cb avctp_ops = {
.connected = avrcp_connected,
.disconnected = avrcp_disconnected,
};
static int avrcp_accept(struct bt_conn *conn, struct bt_avctp **session)
{
struct bt_avrcp *avrcp;
avrcp = get_new_connection(conn);
if (!avrcp) {
return -ENOMEM;
}
*session = &(avrcp->session);
avrcp->session.ops = &avctp_ops;
LOG_DBG("session: %p", &(avrcp->session));
return 0;
}
static struct bt_avctp_event_cb avctp_cb = {
.accept = avrcp_accept,
};
int bt_avrcp_init(void)
{
int err;
/* Register event handlers with AVCTP */
err = bt_avctp_register(&avctp_cb);
if (err < 0) {
LOG_ERR("AVRCP registration failed");
return err;
}
LOG_DBG("AVRCP Initialized successfully.");
return 0;
}
struct bt_avrcp *bt_avrcp_connect(struct bt_conn *conn)
{
struct bt_avrcp *avrcp;
int err;
avrcp = get_new_connection(conn);
if (!avrcp) {
LOG_ERR("Cannot allocate memory");
return NULL;
}
avrcp->session.ops = &avctp_ops;
err = bt_avctp_connect(conn, &(avrcp->session));
if (err < 0) {
/* If error occurs, undo the saving and return the error */
memset(avrcp, 0, sizeof(struct bt_avrcp));
LOG_DBG("AVCTP Connect failed");
return NULL;
}
LOG_DBG("Connection request sent");
return avrcp;
}
int bt_avrcp_disconnect(struct bt_avrcp *avrcp)
{
int err;
err = bt_avctp_disconnect(&(avrcp->session));
if (err < 0) {
LOG_DBG("AVCTP Disconnect failed");
return err;
}
return err;
}
int bt_avrcp_register_cb(const struct bt_avrcp_cb *cb)
{
avrcp_cb = cb;
return 0;
}

View file

@ -0,0 +1,12 @@
/** @file
* @brief Audio Video Remote Control Profile internal header.
*/
/*
* Copyright (c) 2015-2016 Intel Corporation
* Copyright (C) 2024 Xiaomi Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
int bt_avrcp_init(void);

View file

@ -26,6 +26,7 @@
#include "avdtp_internal.h"
#include "a2dp_internal.h"
#include "avctp_internal.h"
#include "avrcp_internal.h"
#include "rfcomm_internal.h"
#include "sdp_internal.h"
@ -2084,4 +2085,8 @@ void bt_l2cap_br_init(void)
if (IS_ENABLED(CONFIG_BT_A2DP)) {
bt_a2dp_init();
}
if (IS_ENABLED(CONFIG_BT_AVRCP)) {
bt_avrcp_init();
}
}