Bluetooth: HFP_AG: Enable 3-way feature

Add a configuration `BT_HFP_AG_3WAY_CALL` to control the feature.

Add a configuration `BT_HFP_AG_MAX_CALLS` to define supported maximum
calls.

Add a structure `struct bt_hfp_ag_call` to manage the call.

Add the call object to callback `outgoing`, and`incoming`.

Use call object to replace AG object for callbacks `incoming_held`,
`ringing`, `accept`, `reject`, and `terminate`.

Add callback `held` to notify the call held status.

Use call object to replace AG object for function
`bt_hfp_ag_hold_incoming`, `bt_hfp_ag_reject`, `bt_hfp_ag_accept`,
`bt_hfp_ag_terminate`, `bt_hfp_ag_remote_ringing`,
`bt_hfp_ag_remote_reject`, `bt_hfp_ag_remote_accept`, and
`bt_hfp_ag_remote_terminate`.

Signed-off-by: Lyle Zhu <lyle.zhu@nxp.com>
This commit is contained in:
Lyle Zhu 2024-11-13 16:23:12 +08:00 committed by Benjamin Cabé
parent bbc0f1fa57
commit 94de015498
5 changed files with 2052 additions and 553 deletions

View File

@ -42,6 +42,7 @@ enum bt_hfp_ag_indicator {
#define BT_HFP_AG_CODEC_LC3_SWB 0x03
struct bt_hfp_ag;
struct bt_hfp_ag_call;
/** @brief HFP profile AG application callback */
struct bt_hfp_ag_cb {
@ -117,9 +118,10 @@ struct bt_hfp_ag_cb {
* new call is outgoing.
*
* @param ag HFP AG object.
* @param call HFP AG call object.
* @param number Dailing number
*/
void (*outgoing)(struct bt_hfp_ag *ag, const char *number);
void (*outgoing)(struct bt_hfp_ag *ag, struct bt_hfp_ag_call *call, const char *number);
/** HF incoming Callback
*
@ -127,55 +129,74 @@ struct bt_hfp_ag_cb {
* new call is incoming.
*
* @param ag HFP AG object.
* @param call HFP AG call object.
* @param number Incoming number
*/
void (*incoming)(struct bt_hfp_ag *ag, const char *number);
void (*incoming)(struct bt_hfp_ag *ag, struct bt_hfp_ag_call *call, const char *number);
/** HF incoming call is held Callback
*
* If this callback is provided it will be called whenever the
* incoming call is held but not accepted.
*
* @param ag HFP AG object.
* @param call HFP AG call object.
*/
void (*incoming_held)(struct bt_hfp_ag *ag);
void (*incoming_held)(struct bt_hfp_ag_call *call);
/** HF ringing Callback
*
* If this callback is provided it will be called whenever the
* call is in the ringing
*
* @param ag HFP AG object.
* @param call HFP AG call object.
* @param in_bond true - in-bond ringing, false - No in-bond ringing
*/
void (*ringing)(struct bt_hfp_ag *ag, bool in_band);
void (*ringing)(struct bt_hfp_ag_call *call, bool in_band);
/** HF call accept Callback
*
* If this callback is provided it will be called whenever the
* call is accepted.
*
* @param ag HFP AG object.
* @param call HFP AG call object.
*/
void (*accept)(struct bt_hfp_ag *ag);
void (*accept)(struct bt_hfp_ag_call *call);
/** HF call held Callback
*
* If this callback is provided it will be called whenever the
* call is held.
*
* @param call HFP AG call object.
*/
void (*held)(struct bt_hfp_ag_call *call);
/** HF call retrieve Callback
*
* If this callback is provided it will be called whenever the
* call is retrieved.
*
* @param call HFP AG call object.
*/
void (*retrieve)(struct bt_hfp_ag_call *call);
/** HF call reject Callback
*
* If this callback is provided it will be called whenever the
* call is rejected.
*
* @param ag HFP AG object.
* @param call HFP AG call object.
*/
void (*reject)(struct bt_hfp_ag *ag);
void (*reject)(struct bt_hfp_ag_call *call);
/** HF call terminate Callback
*
* If this callback is provided it will be called whenever the
* call is terminated.
*
* @param ag HFP AG object.
* @param call HFP AG call object.
*/
void (*terminate)(struct bt_hfp_ag *ag);
void (*terminate)(struct bt_hfp_ag_call *call);
/** Supported codec Ids callback
*
@ -244,6 +265,23 @@ struct bt_hfp_ag_cb {
* @param ag HFP AG object.
*/
void (*ecnr_turn_off)(struct bt_hfp_ag *ag);
/** HF explicit call transfer callback
*
* If this callback is provided it will be called whenever the
* AT+CHLD=4 is sent from HF.
* When the callback is notified, the application should connect
* the two calls and disconnects the subscriber from both calls
* (Explicit Call Transfer).
* After the callback returned, the call objects will be invalid.
* If the callback is NULL, the response result code of AT command
* will be an AT ERROR.
* If @kconfig{CONFIG_BT_HFP_AG_3WAY_CALL} is not enabled, the
* callback will not be notified.
*
* @param ag HFP AG object.
*/
void (*explicit_call_transfer)(struct bt_hfp_ag *ag);
};
/** @brief Register HFP AG profile
@ -294,41 +332,61 @@ int bt_hfp_ag_remote_incoming(struct bt_hfp_ag *ag, const char *number);
*
* Put the incoming call on hold.
*
* @param ag HFP AG object.
* @param call HFP AG call object.
*
* @return 0 in case of success or negative value in case of error.
*/
int bt_hfp_ag_hold_incoming(struct bt_hfp_ag *ag);
int bt_hfp_ag_hold_incoming(struct bt_hfp_ag_call *call);
/** @brief Reject the incoming call
*
* Reject the incoming call.
*
* @param ag HFP AG object.
* @param call HFP AG call object.
*
* @return 0 in case of success or negative value in case of error.
*/
int bt_hfp_ag_reject(struct bt_hfp_ag *ag);
int bt_hfp_ag_reject(struct bt_hfp_ag_call *call);
/** @brief Accept the incoming call
*
* Accept the incoming call.
*
* @param ag HFP AG object.
* @param call HFP AG call object.
*
* @return 0 in case of success or negative value in case of error.
*/
int bt_hfp_ag_accept(struct bt_hfp_ag *ag);
int bt_hfp_ag_accept(struct bt_hfp_ag_call *call);
/** @brief Terminate the active/hold call
*
* Terminate the active/hold call.
*
* @param ag HFP AG object.
* @param call HFP AG call object.
*
* @return 0 in case of success or negative value in case of error.
*/
int bt_hfp_ag_terminate(struct bt_hfp_ag *ag);
int bt_hfp_ag_terminate(struct bt_hfp_ag_call *call);
/** @brief Retrieve the held call
*
* Retrieve the held call.
*
* @param call HFP AG call object.
*
* @return 0 in case of success or negative value in case of error.
*/
int bt_hfp_ag_retrieve(struct bt_hfp_ag_call *call);
/** @brief Hold the active call
*
* Hold the active call.
*
* @param call HFP AG call object.
*
* @return 0 in case of success or negative value in case of error.
*/
int bt_hfp_ag_hold(struct bt_hfp_ag_call *call);
/** @brief Dial a call
*
@ -345,41 +403,54 @@ int bt_hfp_ag_outgoing(struct bt_hfp_ag *ag, const char *number);
*
* Notify HFP Unit that the remote starts ringing.
*
* @param ag HFP AG object.
* @param call HFP AG call object.
*
* @return 0 in case of success or negative value in case of error.
*/
int bt_hfp_ag_remote_ringing(struct bt_hfp_ag *ag);
int bt_hfp_ag_remote_ringing(struct bt_hfp_ag_call *call);
/** @brief Notify HFP Unit that the remote rejects the call
*
* Notify HFP Unit that the remote rejects the call.
*
* @param ag HFP AG object.
* @param call HFP AG call object.
*
* @return 0 in case of success or negative value in case of error.
*/
int bt_hfp_ag_remote_reject(struct bt_hfp_ag *ag);
int bt_hfp_ag_remote_reject(struct bt_hfp_ag_call *call);
/** @brief Notify HFP Unit that the remote accepts the call
*
* Notify HFP Unit that the remote accepts the call.
*
* @param ag HFP AG object.
* @param call HFP AG call object.
*
* @return 0 in case of success or negative value in case of error.
*/
int bt_hfp_ag_remote_accept(struct bt_hfp_ag *ag);
int bt_hfp_ag_remote_accept(struct bt_hfp_ag_call *call);
/** @brief Notify HFP Unit that the remote terminates the active/hold call
*
* Notify HFP Unit that the remote terminates the active/hold call.
*
* @param call HFP AG call object.
*
* @return 0 in case of success or negative value in case of error.
*/
int bt_hfp_ag_remote_terminate(struct bt_hfp_ag_call *call);
/** @brief explicit call transfer
*
* Connects the two calls and disconnects the subscriber from
* both calls (Explicit Call Transfer).
* If @kconfig{CONFIG_BT_HFP_AG_3WAY_CALL} is not enabled, the error
* `-ENOTSUP` will be returned if the function called.
*
* @param ag HFP AG object.
*
* @return 0 in case of success or negative value in case of error.
*/
int bt_hfp_ag_remote_terminate(struct bt_hfp_ag *ag);
int bt_hfp_ag_explicit_call_transfer(struct bt_hfp_ag *ag);
/** @brief Set the HF microphone gain
*

View File

@ -228,11 +228,31 @@ config BT_HFP_AG_ECNR
help
This option enables EC and/or NR function for HFP AG
config BT_HFP_AG_3WAY_CALL
bool "Three-way calling for HFP AG [EXPERIMENTAL]"
help
This option enables Three-way calling for HFP AG
config BT_HFP_AG_MAX_CALLS
int "Maximum supported calls for HFP AG [EXPERIMENTAL]"
default 2 if BT_HFP_AG_3WAY_CALL
default 1
range 1 2
help
This option sets maximum supported calls for HFP AG
config BT_HFP_AG_ECS
bool "Enhanced call status for HFP AG [EXPERIMENTAL]"
default y if BT_HFP_AG_3WAY_CALL
help
This option enables Enhanced call status for HFP AG
config BT_HFP_AG_ECC
bool "Enhanced call control for HFP AG [EXPERIMENTAL]"
default y if BT_HFP_AG_3WAY_CALL
help
This option enables Enhanced call control for HFP AG
config BT_HFP_AG_TX_BUF_COUNT
int "Maximum number of TX buffers for HFP AG [EXPERIMENTAL]"
default BT_RFCOMM_TX_MAX

File diff suppressed because it is too large Load Diff

View File

@ -46,18 +46,33 @@
#define BT_HFP_AG_FEATURE_ECS_ENABLE 0
#endif /* CONFIG_BT_HFP_AG_ECS*/
#if defined(CONFIG_BT_HFP_AG_3WAY_CALL)
#define BT_HFP_AG_FEATURE_3WAY_CALL_ENABLE BT_HFP_AG_FEATURE_3WAY_CALL
#define BT_HFP_AG_SDP_FEATURE_3WAY_CALL_ENABLE BT_HFP_AG_SDP_FEATURE_3WAY_CALL
#else
#define BT_HFP_AG_FEATURE_3WAY_CALL_ENABLE 0
#define BT_HFP_AG_SDP_FEATURE_3WAY_CALL_ENABLE 0
#endif /* CONFIG_BT_HFP_AG_3WAY_CALL */
#if defined(CONFIG_BT_HFP_AG_ECC)
#define BT_HFP_AG_FEATURE_ECC_ENABLE BT_HFP_AG_FEATURE_ECC
#else
#define BT_HFP_AG_FEATURE_ECC_ENABLE 0
#endif /* CONFIG_BT_HFP_AG_ECC */
/* HFP AG Supported features */
#define BT_HFP_AG_SUPPORTED_FEATURES (\
BT_HFP_AG_FEATURE_3WAY_CALL | \
BT_HFP_AG_FEATURE_3WAY_CALL_ENABLE | \
BT_HFP_AG_FEATURE_INBAND_RINGTONE | \
BT_HFP_AG_FEATURE_EXT_ERR_ENABLE | \
BT_HFP_AG_FEATURE_CODEC_NEG_ENABLE | \
BT_HFP_AG_FEATURE_ECNR_ENABLE | \
BT_HFP_AG_FEATURE_ECS_ENABLE)
BT_HFP_AG_FEATURE_ECS_ENABLE | \
BT_HFP_AG_FEATURE_ECC_ENABLE)
/* HFP AG Supported features in SDP */
#define BT_HFP_AG_SDP_SUPPORTED_FEATURES (\
BT_HFP_AG_SDP_FEATURE_3WAY_CALL | \
BT_HFP_AG_SDP_FEATURE_3WAY_CALL_ENABLE | \
BT_HFP_AG_SDP_FEATURE_INBAND_RINGTONE | \
BT_HFP_AG_SDP_FEATURE_ECNR_ENABLE)
@ -69,8 +84,6 @@ enum {
BT_HFP_AG_CCWA_ENABLE, /* Call Waiting notification */
BT_HFP_AG_INBAND_RING, /* In-band ring */
BT_HFP_AG_COPS_SET, /* Query Operator selection */
BT_HFP_AG_INCOMING_CALL, /* Incoming call */
BT_HFP_AG_INCOMING_HELD, /* Incoming call held */
BT_HFP_AG_AUDIO_CONN, /* Audio connection */
BT_HFP_AG_CODEC_CONN, /* Codec connection is ongoing */
BT_HFP_AG_CODEC_CHANGED, /* Codec Id Changed */
@ -81,6 +94,19 @@ enum {
BT_HFP_AG_NUM_FLAGS,
};
/* bt_hfp_ag_call flags: the flags defined here represent HFP AG parameters */
enum {
BT_HFP_AG_CALL_IN_USING, /* Object is in using */
BT_HFP_AG_CALL_INCOMING, /* Incoming call */
BT_HFP_AG_CALL_INCOMING_HELD, /* Incoming call held */
BT_HFP_AG_CALL_OPEN_SCO, /* Open SCO */
BT_HFP_AG_CALL_OUTGOING_3WAY, /* Outgoing 3 way call */
BT_HFP_AG_CALL_INCOMING_3WAY, /* Incoming 3 way call */
/* Total number of flags - must be at the end of the enum */
BT_HFP_AG_CALL_NUM_FLAGS,
};
/* HFP HF Indicators */
enum {
HFP_HF_ENHANCED_SAFETY_IND = 1, /* Enhanced Safety */
@ -103,21 +129,38 @@ typedef enum __packed {
typedef enum __packed {
/** Call terminate */
BT_HFP_CALL_TERMINATE,
BT_HFP_CALL_TERMINATE = 1,
/** Call outgoing */
BT_HFP_CALL_OUTGOING,
BT_HFP_CALL_OUTGOING = 2,
/** Call incoming */
BT_HFP_CALL_INCOMING,
BT_HFP_CALL_INCOMING = 4,
/** Call alerting */
BT_HFP_CALL_ALERTING,
BT_HFP_CALL_ALERTING = 8,
/** Call active */
BT_HFP_CALL_ACTIVE,
BT_HFP_CALL_ACTIVE = 16,
/** Call hold */
BT_HFP_CALL_HOLD,
BT_HFP_CALL_HOLD = 32,
} bt_hfp_call_state_t;
#define AT_COPS_OPERATOR_MAX_LEN 16
struct bt_hfp_ag_call {
struct bt_hfp_ag *ag;
char number[CONFIG_BT_HFP_AG_PHONE_NUMBER_MAX_LEN + 1];
uint8_t type;
ATOMIC_DEFINE(flags, BT_HFP_AG_CALL_NUM_FLAGS);
/* HFP Call state */
bt_hfp_call_state_t call_state;
/* Calling Line Identification notification */
struct k_work_delayable ringing_work;
struct k_work_delayable deferred_work;
};
struct bt_hfp_ag {
struct bt_rfcomm_dlc rfcomm_dlc;
char buffer[HF_MAX_BUF_LEN];
@ -136,14 +179,6 @@ struct bt_hfp_ag {
/* HFP Connection state */
bt_hfp_state_t state;
/* HFP Call state */
bt_hfp_call_state_t call_state;
/* Delayed work deferred tasks:
* - call status cleanup.
*/
struct k_work_delayable deferred_work;
/* AG Indicators */
uint8_t indicator_value[BT_HFP_AG_IND_MAX];
uint32_t indicator;
@ -157,17 +192,18 @@ struct bt_hfp_ag {
uint8_t mode;
char operator[AT_COPS_OPERATOR_MAX_LEN + 1];
/* calls */
struct bt_hfp_ag_call calls[CONFIG_BT_HFP_AG_MAX_CALLS];
/* last dialing number and type */
char last_number[CONFIG_BT_HFP_AG_PHONE_NUMBER_MAX_LEN + 1];
uint8_t type;
/* SCO Connection Object */
struct bt_sco_chan sco_chan;
/* HFP TX pending */
sys_slist_t tx_pending;
/* Dial number or incoming number */
char number[CONFIG_BT_HFP_AG_PHONE_NUMBER_MAX_LEN + 1];
/* Calling Line Identification notification */
struct k_work_delayable ringing_work;
/* Critical locker */
struct k_sem lock;

View File

@ -182,3 +182,35 @@ enum hfp_hf_ag_indicators {
#define BT_HFP_BTRH_ON_HOLD 0
#define BT_HFP_BTRH_ACCEPTED 1
#define BT_HFP_BTRH_REJECTED 2
/* HFP Call held status */
/* No calls held */
#define BT_HFP_CALL_HELD_NONE 0
/* Call is placed on hold or active/held calls swapped
* The AG has both an active AND a held call
*/
#define BT_HFP_CALL_HELD_ACTIVE_HELD 1
/* Call on hold, no active call */
#define BT_HFP_CALL_HELD_HELD 2
/* HFP AT+CHLD command value */
/* Releases all held calls or sets User Determined User Busy
* (UDUB) for a waiting call
*/
#define BT_HFP_CHLD_RELEASE_ALL 0
/* Releases all active calls (if any exist) and accepts the
* other (held or waiting) call.
*/
#define BT_HFP_CHLD_RELEASE_ACTIVE_ACCEPT_OTHER 1
/* Places all active calls (if any exist) on hold and accepts
* the other (held or waiting) call
*/
#define BT_HFP_CALL_HOLD_ACTIVE_ACCEPT_OTHER 2
/* Adds a held call to the conversation */
#define BT_HFP_CALL_ACTIVE_HELD 3
/* Connects the two calls and disconnects the subscriber from
* both calls (Explicit Call Transfer).
* Support for this value and its associated functionality is
* optional for the HF.
*/
#define BT_HFP_CALL_QUITE 4