Bluetooth: BAP: Add ISO state callbacks
Add callbacks to the stream objects that reflects the state of the isochronous channel. The connected callback is called when the isochronous channel is connected, and similarly the disconnected callback is called when it is disconnected. There is a special case for unicast, where if the ACL disconnects first, then we won't get a ISO disconnect callback. It should be assumed that the isochronous channel is no longer valid when the BAP stream enters the idle state, i.e. when the "released" callback is called. The purpose of the new callbacks is to provide additional information to the application. Especially the unicast client can use this to determine when the stream_start function can be called again, as there can only ever be 1 outstanding CIS connection request at a time, but there can be multiple GATT requests. Signed-off-by: Emil Gydesen <emil.gydesen@nordicsemi.no>
This commit is contained in:
parent
8ad0e5763f
commit
b857ef7f83
13 changed files with 264 additions and 29 deletions
|
@ -581,10 +581,38 @@ struct bt_bap_stream_ops {
|
|||
*
|
||||
* This callback is only used if the ISO data path is HCI.
|
||||
*
|
||||
* @param chan The channel which has sent data.
|
||||
* @param stream Stream object.
|
||||
*/
|
||||
void (*sent)(struct bt_bap_stream *stream);
|
||||
#endif /* CONFIG_BT_AUDIO_TX */
|
||||
|
||||
/**
|
||||
* @brief Isochronous channel connected callback
|
||||
*
|
||||
* If this callback is provided it will be called whenever the isochronous channel for the
|
||||
* stream has been connected. This does not mean that the stream is ready to be used, which
|
||||
* is indicated by the @ref bt_bap_stream_ops.started callback.
|
||||
*
|
||||
* If the stream shares an isochronous channel with another stream, then this callback may
|
||||
* still be called, without the stream going into the started state.
|
||||
*
|
||||
* @param stream Stream object.
|
||||
*/
|
||||
void (*connected)(struct bt_bap_stream *stream);
|
||||
|
||||
/**
|
||||
* @brief Isochronous channel disconnected callback
|
||||
*
|
||||
* If this callback is provided it will be called whenever the isochronous channel is
|
||||
* disconnected, including when a connection gets rejected.
|
||||
*
|
||||
* If the stream shares an isochronous channel with another stream, then this callback may
|
||||
* not be called, even if the stream is leaving the streaming state.
|
||||
*
|
||||
* @param stream Stream object.
|
||||
* @param reason BT_HCI_ERR_* reason for the disconnection.
|
||||
*/
|
||||
void (*disconnected)(struct bt_bap_stream *stream, uint8_t reason);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -386,7 +386,6 @@ static void ase_exit_state_streaming(struct bt_ascs_ase *ase)
|
|||
struct bt_bap_stream *stream = ase->ep.stream;
|
||||
struct bt_bap_stream_ops *ops;
|
||||
const enum bt_bap_ep_state next_state = ascs_ep_get_state(&ase->ep);
|
||||
|
||||
uint8_t reason = ase->ep.reason;
|
||||
|
||||
__ASSERT_NO_MSG(stream != NULL);
|
||||
|
@ -397,11 +396,6 @@ static void ase_exit_state_streaming(struct bt_ascs_ase *ase)
|
|||
}
|
||||
|
||||
ops = stream->ops;
|
||||
if (ops != NULL && ops->stopped != NULL) {
|
||||
ops->stopped(stream, reason);
|
||||
} else {
|
||||
LOG_WRN("No callback for stopped set");
|
||||
}
|
||||
|
||||
/*
|
||||
* On link-loss we go from streaming state to QOS configured state,
|
||||
|
@ -415,6 +409,12 @@ static void ase_exit_state_streaming(struct bt_ascs_ase *ase)
|
|||
LOG_WRN("No callback for disabled set");
|
||||
}
|
||||
}
|
||||
|
||||
if (ops != NULL && ops->stopped != NULL) {
|
||||
ops->stopped(stream, reason);
|
||||
} else {
|
||||
LOG_WRN("No callback for stopped set");
|
||||
}
|
||||
}
|
||||
|
||||
static void ase_exit_state_enabling(struct bt_ascs_ase *ase)
|
||||
|
@ -940,6 +940,7 @@ static void ascs_update_sdu_size(struct bt_bap_ep *ep)
|
|||
static void ascs_ep_iso_connected(struct bt_bap_ep *ep)
|
||||
{
|
||||
struct bt_ascs_ase *ase = CONTAINER_OF(ep, struct bt_ascs_ase, ep);
|
||||
const struct bt_bap_stream_ops *stream_ops;
|
||||
struct bt_bap_stream *stream;
|
||||
|
||||
if (ep->status.state != BT_BAP_EP_STATE_ENABLING) {
|
||||
|
@ -964,6 +965,13 @@ static void ascs_ep_iso_connected(struct bt_bap_ep *ep)
|
|||
*/
|
||||
ascs_update_sdu_size(ep);
|
||||
|
||||
LOG_DBG("stream %p ep %p dir %s", stream, ep, bt_audio_dir_str(ep->dir));
|
||||
|
||||
stream_ops = stream->ops;
|
||||
if (stream_ops != NULL && stream_ops->connected != NULL) {
|
||||
stream_ops->connected(stream);
|
||||
}
|
||||
|
||||
if (ep->dir == BT_AUDIO_DIR_SINK && ep->receiver_ready) {
|
||||
/* Source ASEs shall be ISO connected first, and then receive
|
||||
* the receiver start ready command to enter the streaming
|
||||
|
@ -971,8 +979,6 @@ static void ascs_ep_iso_connected(struct bt_bap_ep *ep)
|
|||
*/
|
||||
ascs_ep_set_state(ep, BT_BAP_EP_STATE_STREAMING);
|
||||
}
|
||||
|
||||
LOG_DBG("stream %p ep %p dir %s", stream, ep, bt_audio_dir_str(ep->dir));
|
||||
}
|
||||
|
||||
static void ascs_iso_connected(struct bt_iso_chan *chan)
|
||||
|
@ -996,6 +1002,7 @@ static void ascs_iso_connected(struct bt_iso_chan *chan)
|
|||
static void ascs_ep_iso_disconnected(struct bt_bap_ep *ep, uint8_t reason)
|
||||
{
|
||||
struct bt_ascs_ase *ase = CONTAINER_OF(ep, struct bt_ascs_ase, ep);
|
||||
const struct bt_bap_stream_ops *stream_ops;
|
||||
struct bt_bap_stream *stream;
|
||||
|
||||
stream = ep->stream;
|
||||
|
@ -1007,6 +1014,11 @@ static void ascs_ep_iso_disconnected(struct bt_bap_ep *ep, uint8_t reason)
|
|||
LOG_DBG("stream %p ep %p state %s reason 0x%02x", stream, stream->ep,
|
||||
bt_bap_ep_state_str(ep->status.state), reason);
|
||||
|
||||
stream_ops = stream->ops;
|
||||
if (stream_ops != NULL && stream_ops->disconnected != NULL) {
|
||||
stream_ops->disconnected(stream, reason);
|
||||
}
|
||||
|
||||
/* Cancel ASE disconnect work if pending */
|
||||
(void)k_work_cancel_delayable(&ase->disconnect_work);
|
||||
ep->reason = reason;
|
||||
|
|
|
@ -296,10 +296,13 @@ static void broadcast_sink_iso_connected(struct bt_iso_chan *chan)
|
|||
return;
|
||||
}
|
||||
|
||||
ops = stream->ops;
|
||||
|
||||
LOG_DBG("stream %p", stream);
|
||||
|
||||
ops = stream->ops;
|
||||
if (ops != NULL && ops->connected != NULL) {
|
||||
ops->connected(stream);
|
||||
}
|
||||
|
||||
sink = broadcast_sink_lookup_iso_chan(chan);
|
||||
if (sink == NULL) {
|
||||
LOG_ERR("Could not lookup sink by iso %p", chan);
|
||||
|
@ -311,7 +314,7 @@ static void broadcast_sink_iso_connected(struct bt_iso_chan *chan)
|
|||
if (ops != NULL && ops->started != NULL) {
|
||||
ops->started(stream);
|
||||
} else {
|
||||
LOG_WRN("No callback for connected set");
|
||||
LOG_WRN("No callback for started set");
|
||||
}
|
||||
|
||||
all_connected = true;
|
||||
|
@ -349,10 +352,13 @@ static void broadcast_sink_iso_disconnected(struct bt_iso_chan *chan,
|
|||
return;
|
||||
}
|
||||
|
||||
ops = stream->ops;
|
||||
|
||||
LOG_DBG("stream %p ep %p reason 0x%02x", stream, ep, reason);
|
||||
|
||||
ops = stream->ops;
|
||||
if (ops != NULL && ops->disconnected != NULL) {
|
||||
ops->disconnected(stream, reason);
|
||||
}
|
||||
|
||||
broadcast_sink_set_ep_state(ep, BT_BAP_EP_STATE_IDLE);
|
||||
|
||||
sink = broadcast_sink_lookup_iso_chan(chan);
|
||||
|
|
|
@ -166,10 +166,13 @@ static void broadcast_source_iso_connected(struct bt_iso_chan *chan)
|
|||
return;
|
||||
}
|
||||
|
||||
ops = stream->ops;
|
||||
|
||||
LOG_DBG("stream %p ep %p", stream, ep);
|
||||
|
||||
ops = stream->ops;
|
||||
if (ops != NULL && ops->connected != NULL) {
|
||||
ops->connected(stream);
|
||||
}
|
||||
|
||||
broadcast_source_set_ep_state(ep, BT_BAP_EP_STATE_STREAMING);
|
||||
|
||||
if (ops != NULL && ops->started != NULL) {
|
||||
|
@ -197,10 +200,13 @@ static void broadcast_source_iso_disconnected(struct bt_iso_chan *chan, uint8_t
|
|||
return;
|
||||
}
|
||||
|
||||
ops = stream->ops;
|
||||
|
||||
LOG_DBG("stream %p ep %p reason 0x%02x", stream, stream->ep, reason);
|
||||
|
||||
ops = stream->ops;
|
||||
if (ops != NULL && ops->disconnected != NULL) {
|
||||
ops->disconnected(stream, reason);
|
||||
}
|
||||
|
||||
broadcast_source_set_ep_state(ep, BT_BAP_EP_STATE_QOS_CONFIGURED);
|
||||
|
||||
if (ops != NULL && ops->stopped != NULL) {
|
||||
|
|
|
@ -296,6 +296,7 @@ static void unicast_client_ep_iso_sent(struct bt_iso_chan *chan)
|
|||
|
||||
static void unicast_client_ep_iso_connected(struct bt_bap_ep *ep)
|
||||
{
|
||||
const struct bt_bap_stream_ops *stream_ops;
|
||||
struct bt_bap_stream *stream;
|
||||
|
||||
if (ep->status.state != BT_BAP_EP_STATE_ENABLING) {
|
||||
|
@ -313,6 +314,11 @@ static void unicast_client_ep_iso_connected(struct bt_bap_ep *ep)
|
|||
LOG_DBG("stream %p ep %p dir %s receiver_ready %u",
|
||||
stream, ep, bt_audio_dir_str(ep->dir), ep->receiver_ready);
|
||||
|
||||
stream_ops = stream->ops;
|
||||
if (stream_ops != NULL && stream_ops->connected != NULL) {
|
||||
stream_ops->connected(stream);
|
||||
}
|
||||
|
||||
if (ep->receiver_ready && ep->dir == BT_AUDIO_DIR_SOURCE) {
|
||||
const int err = unicast_client_send_start(ep);
|
||||
|
||||
|
@ -345,6 +351,7 @@ static void unicast_client_iso_connected(struct bt_iso_chan *chan)
|
|||
|
||||
static void unicast_client_ep_iso_disconnected(struct bt_bap_ep *ep, uint8_t reason)
|
||||
{
|
||||
const struct bt_bap_stream_ops *stream_ops;
|
||||
struct bt_bap_stream *stream;
|
||||
|
||||
stream = ep->stream;
|
||||
|
@ -356,6 +363,11 @@ static void unicast_client_ep_iso_disconnected(struct bt_bap_ep *ep, uint8_t rea
|
|||
LOG_DBG("stream %p ep %p reason 0x%02x", stream, ep, reason);
|
||||
ep->reason = reason;
|
||||
|
||||
stream_ops = stream->ops;
|
||||
if (stream_ops != NULL && stream_ops->disconnected != NULL) {
|
||||
stream_ops->disconnected(stream, reason);
|
||||
}
|
||||
|
||||
/* If we were in the idle state when we started the ISO disconnection
|
||||
* then we need to call unicast_client_ep_idle_state again when
|
||||
* the ISO has finalized the disconnection
|
||||
|
@ -714,6 +726,7 @@ static void unicast_client_ep_config_state(struct bt_bap_ep *ep, struct net_buf_
|
|||
static void unicast_client_ep_qos_state(struct bt_bap_ep *ep, struct net_buf_simple *buf,
|
||||
uint8_t old_state)
|
||||
{
|
||||
const struct bt_bap_stream_ops *ops;
|
||||
struct bt_ascs_ase_status_qos *qos;
|
||||
struct bt_bap_stream *stream;
|
||||
|
||||
|
@ -727,17 +740,36 @@ static void unicast_client_ep_qos_state(struct bt_bap_ep *ep, struct net_buf_sim
|
|||
LOG_ERR("No stream active for endpoint");
|
||||
return;
|
||||
}
|
||||
ops = stream->ops;
|
||||
|
||||
if (ep->dir == BT_AUDIO_DIR_SINK && stream->ops != NULL && stream->ops->disabled != NULL) {
|
||||
/* If the old state was enabling or streaming, then the sink
|
||||
* ASE has been disabled. Since the sink ASE does not have a
|
||||
* disabling state, we can check if by comparing the old_state
|
||||
*/
|
||||
const bool disabled = old_state == BT_BAP_EP_STATE_ENABLING ||
|
||||
old_state == BT_BAP_EP_STATE_STREAMING;
|
||||
if (ops != NULL) {
|
||||
if (ep->dir == BT_AUDIO_DIR_SINK && ops->disabled != NULL) {
|
||||
/* If the old state was enabling or streaming, then the sink
|
||||
* ASE has been disabled. Since the sink ASE does not have a
|
||||
* disabling state, we can check if by comparing the old_state
|
||||
*/
|
||||
const bool disabled = old_state == BT_BAP_EP_STATE_ENABLING ||
|
||||
old_state == BT_BAP_EP_STATE_STREAMING;
|
||||
|
||||
if (disabled) {
|
||||
stream->ops->disabled(stream);
|
||||
if (disabled) {
|
||||
ops->disabled(stream);
|
||||
}
|
||||
} else if (ep->dir == BT_AUDIO_DIR_SOURCE &&
|
||||
old_state == BT_BAP_EP_STATE_DISABLING && ops->stopped != NULL) {
|
||||
/* We left the disabling state, let the upper layers know that the stream is
|
||||
* stopped
|
||||
*/
|
||||
uint8_t reason = ep->reason;
|
||||
|
||||
if (reason == BT_HCI_ERR_SUCCESS) {
|
||||
/* Default to BT_HCI_ERR_UNSPECIFIED if no other reason is set */
|
||||
reason = BT_HCI_ERR_UNSPECIFIED;
|
||||
} else {
|
||||
/* Reset reason */
|
||||
ep->reason = BT_HCI_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
ops->stopped(stream, reason);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -182,6 +182,28 @@ static void cap_stream_sent_cb(struct bt_bap_stream *bap_stream)
|
|||
}
|
||||
#endif /* CONFIG_BT_AUDIO_TX */
|
||||
|
||||
static void cap_stream_connected_cb(struct bt_bap_stream *bap_stream)
|
||||
{
|
||||
struct bt_cap_stream *cap_stream =
|
||||
CONTAINER_OF(bap_stream, struct bt_cap_stream, bap_stream);
|
||||
struct bt_bap_stream_ops *ops = cap_stream->ops;
|
||||
|
||||
if (ops != NULL && ops->connected != NULL) {
|
||||
ops->connected(bap_stream);
|
||||
}
|
||||
}
|
||||
|
||||
static void cap_stream_disconnected_cb(struct bt_bap_stream *bap_stream, uint8_t reason)
|
||||
{
|
||||
struct bt_cap_stream *cap_stream =
|
||||
CONTAINER_OF(bap_stream, struct bt_cap_stream, bap_stream);
|
||||
struct bt_bap_stream_ops *ops = cap_stream->ops;
|
||||
|
||||
if (ops != NULL && ops->disconnected != NULL) {
|
||||
ops->disconnected(bap_stream, reason);
|
||||
}
|
||||
}
|
||||
|
||||
static struct bt_bap_stream_ops bap_stream_ops = {
|
||||
#if defined(CONFIG_BT_BAP_UNICAST)
|
||||
.configured = cap_stream_configured_cb,
|
||||
|
@ -199,6 +221,8 @@ static struct bt_bap_stream_ops bap_stream_ops = {
|
|||
#if defined(CONFIG_BT_AUDIO_TX)
|
||||
.sent = cap_stream_sent_cb,
|
||||
#endif /* CONFIG_BT_AUDIO_TX */
|
||||
.connected = cap_stream_connected_cb,
|
||||
.disconnected = cap_stream_disconnected_cb,
|
||||
};
|
||||
|
||||
void bt_cap_stream_ops_register_bap(struct bt_cap_stream *cap_stream)
|
||||
|
|
|
@ -404,6 +404,7 @@ ZTEST_F(ascs_test_suite, test_cis_link_loss_in_streaming_state)
|
|||
expect_bt_bap_stream_ops_qos_set_called_once(stream);
|
||||
expect_bt_bap_stream_ops_disabled_called_once(stream);
|
||||
expect_bt_bap_stream_ops_released_not_called();
|
||||
expect_bt_bap_stream_ops_disconnected_called_once(stream);
|
||||
|
||||
bt_bap_unicast_server_unregister_cb(&mock_bap_unicast_server_cb);
|
||||
}
|
||||
|
@ -448,6 +449,7 @@ static void test_cis_link_loss_in_disabling_state(struct ascs_test_suite_fixture
|
|||
expect_bt_bap_stream_ops_qos_set_called_once(stream);
|
||||
expect_bt_bap_stream_ops_disabled_not_called();
|
||||
expect_bt_bap_stream_ops_released_not_called();
|
||||
expect_bt_bap_stream_ops_disconnected_called_once(stream);
|
||||
|
||||
bt_bap_unicast_server_unregister_cb(&mock_bap_unicast_server_cb);
|
||||
}
|
||||
|
@ -495,6 +497,7 @@ ZTEST_F(ascs_test_suite, test_cis_link_loss_in_enabling_state)
|
|||
/* Expected no change in ASE state */
|
||||
expect_bt_bap_stream_ops_qos_set_not_called();
|
||||
expect_bt_bap_stream_ops_released_not_called();
|
||||
expect_bt_bap_stream_ops_disconnected_called_once(stream);
|
||||
|
||||
err = bt_bap_stream_disable(stream);
|
||||
zassert_equal(0, err, "Failed to disable stream: err %d", err);
|
||||
|
@ -534,6 +537,7 @@ ZTEST_F(ascs_test_suite, test_cis_link_loss_in_enabling_state_client_retries)
|
|||
test_preamble_state_enabling(conn, ase_id, stream);
|
||||
err = mock_bt_iso_accept(conn, 0x01, 0x01, &chan);
|
||||
zassert_equal(0, err, "Failed to connect iso: err %d", err);
|
||||
expect_bt_bap_stream_ops_connected_called_once(stream);
|
||||
|
||||
/* Mock CIS disconnection */
|
||||
mock_bt_iso_disconnected(chan, BT_HCI_ERR_CONN_FAIL_TO_ESTAB);
|
||||
|
@ -541,6 +545,7 @@ ZTEST_F(ascs_test_suite, test_cis_link_loss_in_enabling_state_client_retries)
|
|||
/* Expected to not notify the upper layers */
|
||||
expect_bt_bap_stream_ops_qos_set_not_called();
|
||||
expect_bt_bap_stream_ops_released_not_called();
|
||||
expect_bt_bap_stream_ops_disconnected_called_once(stream);
|
||||
|
||||
/* Client retries to establish CIS */
|
||||
err = mock_bt_iso_accept(conn, 0x01, 0x01, &chan);
|
||||
|
@ -552,6 +557,7 @@ ZTEST_F(ascs_test_suite, test_cis_link_loss_in_enabling_state_client_retries)
|
|||
zassert_equal(0, err, "bt_bap_stream_start err %d", err);
|
||||
}
|
||||
|
||||
expect_bt_bap_stream_ops_connected_called_twice(stream);
|
||||
expect_bt_bap_stream_ops_started_called_once(stream);
|
||||
|
||||
bt_bap_unicast_server_unregister_cb(&mock_bap_unicast_server_cb);
|
||||
|
|
|
@ -288,6 +288,7 @@ ZTEST_F(test_sink_ase_state_transition, test_client_streaming_to_releasing)
|
|||
expect_bt_bap_stream_ops_stopped_called_once(stream, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
|
||||
expect_bt_bap_stream_ops_released_called_once(stream);
|
||||
expect_bt_bap_stream_ops_disabled_not_called();
|
||||
expect_bt_bap_stream_ops_disconnected_called_once(stream);
|
||||
}
|
||||
|
||||
ZTEST_F(test_sink_ase_state_transition, test_client_streaming_to_streaming)
|
||||
|
@ -510,6 +511,7 @@ ZTEST_F(test_sink_ase_state_transition, test_server_enabling_to_streaming)
|
|||
zassert_false(err < 0, "bt_bap_stream_start returned err %d", err);
|
||||
|
||||
/* Verification */
|
||||
expect_bt_bap_stream_ops_connected_called_once(stream);
|
||||
expect_bt_bap_stream_ops_started_called_once(stream);
|
||||
expect_bt_bap_stream_ops_disabled_not_called();
|
||||
/* XXX: unicast_server_cb->start is not called for Sink ASE */
|
||||
|
@ -585,6 +587,7 @@ ZTEST_F(test_sink_ase_state_transition, test_server_streaming_to_releasing)
|
|||
expect_bt_bap_stream_ops_stopped_called_once(stream, BT_HCI_ERR_LOCALHOST_TERM_CONN);
|
||||
expect_bt_bap_stream_ops_released_called_once(stream);
|
||||
expect_bt_bap_stream_ops_disabled_not_called();
|
||||
expect_bt_bap_stream_ops_disconnected_called_once(stream);
|
||||
}
|
||||
|
||||
static void *test_source_ase_state_transition_setup(void)
|
||||
|
@ -711,6 +714,7 @@ ZTEST_F(test_source_ase_state_transition, test_client_enabling_to_streaming)
|
|||
|
||||
/* Verification */
|
||||
expect_bt_bap_unicast_server_cb_start_called_once(stream);
|
||||
expect_bt_bap_stream_ops_connected_called_once(stream);
|
||||
expect_bt_bap_stream_ops_started_called_once(stream);
|
||||
expect_bt_bap_stream_ops_disabled_not_called();
|
||||
}
|
||||
|
@ -841,6 +845,7 @@ ZTEST_F(test_source_ase_state_transition, test_client_streaming_to_releasing)
|
|||
expect_bt_bap_stream_ops_stopped_called_once(stream, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
|
||||
expect_bt_bap_stream_ops_released_called_once(stream);
|
||||
expect_bt_bap_stream_ops_disabled_not_called();
|
||||
expect_bt_bap_stream_ops_disconnected_called_once(stream);
|
||||
}
|
||||
|
||||
ZTEST_F(test_source_ase_state_transition, test_client_streaming_to_streaming)
|
||||
|
@ -1160,4 +1165,5 @@ ZTEST_F(test_source_ase_state_transition, test_server_streaming_to_releasing)
|
|||
expect_bt_bap_stream_ops_stopped_called_once(stream, BT_HCI_ERR_LOCALHOST_TERM_CONN);
|
||||
expect_bt_bap_stream_ops_released_called_once(stream);
|
||||
expect_bt_bap_stream_ops_disabled_not_called();
|
||||
expect_bt_bap_stream_ops_disconnected_called_once(stream);
|
||||
}
|
||||
|
|
|
@ -218,6 +218,8 @@ ZTEST_F(bap_broadcast_source_test_suite, test_broadcast_source_create_start_send
|
|||
err = bt_bap_broadcast_source_start(fixture->source, &ext_adv);
|
||||
zassert_equal(0, err, "Unable to start broadcast source: err %d", err);
|
||||
|
||||
zexpect_call_count("bt_bap_stream_ops.connected", fixture->stream_cnt,
|
||||
mock_bap_stream_connected_cb_fake.call_count);
|
||||
zexpect_call_count("bt_bap_stream_ops.started", fixture->stream_cnt,
|
||||
mock_bap_stream_started_cb_fake.call_count);
|
||||
|
||||
|
@ -239,6 +241,8 @@ ZTEST_F(bap_broadcast_source_test_suite, test_broadcast_source_create_start_send
|
|||
err = bt_bap_broadcast_source_stop(fixture->source);
|
||||
zassert_equal(0, err, "Unable to stop broadcast source: err %d", err);
|
||||
|
||||
zexpect_call_count("bt_bap_stream_ops.disconnected", fixture->stream_cnt,
|
||||
mock_bap_stream_disconnected_cb_fake.call_count);
|
||||
zexpect_call_count("bt_bap_stream_ops.stopped", fixture->stream_cnt,
|
||||
mock_bap_stream_stopped_cb_fake.call_count);
|
||||
|
||||
|
|
|
@ -27,5 +27,7 @@ DECLARE_FAKE_VOID_FUNC(mock_bap_stream_stopped_cb, struct bt_bap_stream *, uint8
|
|||
DECLARE_FAKE_VOID_FUNC(mock_bap_stream_recv_cb, struct bt_bap_stream *,
|
||||
const struct bt_iso_recv_info *, struct net_buf *);
|
||||
DECLARE_FAKE_VOID_FUNC(mock_bap_stream_sent_cb, struct bt_bap_stream *);
|
||||
DECLARE_FAKE_VOID_FUNC(mock_bap_stream_connected_cb, struct bt_bap_stream *);
|
||||
DECLARE_FAKE_VOID_FUNC(mock_bap_stream_disconnected_cb, struct bt_bap_stream *, uint8_t);
|
||||
|
||||
#endif /* MOCKS_BAP_STREAM_H_ */
|
||||
|
|
|
@ -135,7 +135,7 @@ static inline void expect_bt_bap_stream_ops_released_called(const struct bt_bap_
|
|||
}
|
||||
}
|
||||
|
||||
static inline void expect_bt_bap_stream_ops_released_called_once(struct bt_bap_stream *stream)
|
||||
static inline void expect_bt_bap_stream_ops_released_called_once(const struct bt_bap_stream *stream)
|
||||
{
|
||||
expect_bt_bap_stream_ops_released_called(&stream, 1);
|
||||
}
|
||||
|
@ -193,6 +193,45 @@ static inline void expect_bt_bap_stream_ops_stopped_not_called(void)
|
|||
zexpect_call_count(func_name, 0, mock_bap_stream_stopped_cb_fake.call_count);
|
||||
}
|
||||
|
||||
static inline void
|
||||
expect_bt_bap_stream_ops_connected_called_once(const struct bt_bap_stream *stream)
|
||||
{
|
||||
const char *func_name = "bt_bap_stream_ops.connected";
|
||||
|
||||
zexpect_call_count(func_name, 1, mock_bap_stream_connected_cb_fake.call_count);
|
||||
|
||||
if (mock_bap_stream_connected_cb_fake.call_count > 0) {
|
||||
zexpect_equal_ptr(stream, mock_bap_stream_connected_cb_fake.arg0_val,
|
||||
"'%s()' was called with incorrect '%s'", func_name, "stream");
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
expect_bt_bap_stream_ops_connected_called_twice(const struct bt_bap_stream *stream)
|
||||
{
|
||||
const char *func_name = "bt_bap_stream_ops.connected";
|
||||
|
||||
zexpect_call_count(func_name, 2, mock_bap_stream_connected_cb_fake.call_count);
|
||||
|
||||
if (mock_bap_stream_connected_cb_fake.call_count > 0) {
|
||||
zexpect_equal_ptr(stream, mock_bap_stream_connected_cb_fake.arg0_val,
|
||||
"'%s()' was called with incorrect '%s'", func_name, "stream");
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
expect_bt_bap_stream_ops_disconnected_called_once(const struct bt_bap_stream *stream)
|
||||
{
|
||||
const char *func_name = "bt_bap_stream_ops.disconnected";
|
||||
|
||||
zexpect_call_count(func_name, 1, mock_bap_stream_disconnected_cb_fake.call_count);
|
||||
|
||||
if (mock_bap_stream_disconnected_cb_fake.call_count > 0) {
|
||||
zexpect_equal_ptr(stream, mock_bap_stream_disconnected_cb_fake.arg0_val,
|
||||
"'%s()' was called with incorrect '%s'", func_name, "stream");
|
||||
}
|
||||
}
|
||||
|
||||
static inline void expect_bt_bap_stream_ops_recv_called_once(struct bt_bap_stream *stream,
|
||||
const struct bt_iso_recv_info *info,
|
||||
struct net_buf *buf)
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
FAKE(mock_bap_stream_stopped_cb) \
|
||||
FAKE(mock_bap_stream_recv_cb) \
|
||||
FAKE(mock_bap_stream_sent_cb) \
|
||||
FAKE(mock_bap_stream_connected_cb) \
|
||||
FAKE(mock_bap_stream_disconnected_cb)
|
||||
|
||||
struct bt_bap_stream_ops mock_bap_stream_ops;
|
||||
|
||||
|
@ -35,6 +37,8 @@ DEFINE_FAKE_VOID_FUNC(mock_bap_stream_stopped_cb, struct bt_bap_stream *, uint8_
|
|||
DEFINE_FAKE_VOID_FUNC(mock_bap_stream_recv_cb, struct bt_bap_stream *,
|
||||
const struct bt_iso_recv_info *, struct net_buf *);
|
||||
DEFINE_FAKE_VOID_FUNC(mock_bap_stream_sent_cb, struct bt_bap_stream *);
|
||||
DEFINE_FAKE_VOID_FUNC(mock_bap_stream_connected_cb, struct bt_bap_stream *);
|
||||
DEFINE_FAKE_VOID_FUNC(mock_bap_stream_disconnected_cb, struct bt_bap_stream *, uint8_t);
|
||||
|
||||
void mock_bap_stream_init(void)
|
||||
{
|
||||
|
@ -56,6 +60,8 @@ void mock_bap_stream_init(void)
|
|||
#if defined(CONFIG_BT_AUDIO_TX)
|
||||
mock_bap_stream_ops.sent = mock_bap_stream_sent_cb;
|
||||
#endif /* CONFIG_BT_AUDIO_TX */
|
||||
mock_bap_stream_ops.connected = mock_bap_stream_connected_cb;
|
||||
mock_bap_stream_ops.disconnected = mock_bap_stream_disconnected_cb;
|
||||
}
|
||||
|
||||
void mock_bap_stream_cleanup(void)
|
||||
|
|
|
@ -45,7 +45,10 @@ static atomic_t flag_stream_qos_configured;
|
|||
CREATE_FLAG(flag_stream_enabled);
|
||||
CREATE_FLAG(flag_stream_metadata);
|
||||
CREATE_FLAG(flag_stream_started);
|
||||
CREATE_FLAG(flag_stream_connected);
|
||||
CREATE_FLAG(flag_stream_disconnected);
|
||||
CREATE_FLAG(flag_stream_disabled);
|
||||
CREATE_FLAG(flag_stream_stopped);
|
||||
CREATE_FLAG(flag_stream_released);
|
||||
CREATE_FLAG(flag_operation_success);
|
||||
|
||||
|
@ -86,6 +89,20 @@ static void stream_started(struct bt_bap_stream *stream)
|
|||
SET_FLAG(flag_stream_started);
|
||||
}
|
||||
|
||||
static void stream_connected(struct bt_bap_stream *stream)
|
||||
{
|
||||
printk("Connected stream %p\n", stream);
|
||||
|
||||
SET_FLAG(flag_stream_connected);
|
||||
}
|
||||
|
||||
static void stream_disconnected(struct bt_bap_stream *stream, uint8_t reason)
|
||||
{
|
||||
printk("Disconnected stream %p with reason %u\n", stream, reason);
|
||||
|
||||
SET_FLAG(flag_stream_disconnected);
|
||||
}
|
||||
|
||||
static void stream_metadata_updated(struct bt_bap_stream *stream)
|
||||
{
|
||||
printk("Metadata updated stream %p\n", stream);
|
||||
|
@ -107,6 +124,8 @@ static void stream_disabled(struct bt_bap_stream *stream)
|
|||
static void stream_stopped(struct bt_bap_stream *stream, uint8_t reason)
|
||||
{
|
||||
printk("Stopped stream %p with reason 0x%02X\n", stream, reason);
|
||||
|
||||
SET_FLAG(flag_stream_stopped);
|
||||
}
|
||||
|
||||
static void stream_released(struct bt_bap_stream *stream)
|
||||
|
@ -198,6 +217,8 @@ static struct bt_bap_stream_ops stream_ops = {
|
|||
.released = stream_released,
|
||||
.recv = stream_recv_cb,
|
||||
.sent = stream_sent_cb,
|
||||
.connected = stream_connected,
|
||||
.disconnected = stream_disconnected,
|
||||
};
|
||||
|
||||
static void unicast_client_location_cb(struct bt_conn *conn,
|
||||
|
@ -764,6 +785,8 @@ static void start_streams(void)
|
|||
source_stream = pair_params[0].rx_param == NULL ? NULL : pair_params[0].rx_param->stream;
|
||||
sink_stream = pair_params[0].tx_param == NULL ? NULL : pair_params[0].tx_param->stream;
|
||||
|
||||
UNSET_FLAG(flag_stream_connected);
|
||||
|
||||
if (sink_stream != NULL) {
|
||||
const int err = start_stream(sink_stream);
|
||||
|
||||
|
@ -783,6 +806,8 @@ static void start_streams(void)
|
|||
return;
|
||||
}
|
||||
}
|
||||
|
||||
WAIT_FOR_FLAG(flag_stream_connected);
|
||||
}
|
||||
|
||||
static void transceive_streams(void)
|
||||
|
@ -843,6 +868,42 @@ static void disable_streams(size_t stream_cnt)
|
|||
}
|
||||
}
|
||||
|
||||
static void stop_streams(size_t stream_cnt)
|
||||
{
|
||||
UNSET_FLAG(flag_stream_disconnected);
|
||||
|
||||
for (size_t i = 0; i < stream_cnt; i++) {
|
||||
struct bt_bap_stream *source_stream;
|
||||
int err;
|
||||
|
||||
/* We can only stop source streams */
|
||||
source_stream =
|
||||
pair_params[i].rx_param == NULL ? NULL : pair_params[i].rx_param->stream;
|
||||
|
||||
if (source_stream == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
UNSET_FLAG(flag_operation_success);
|
||||
UNSET_FLAG(flag_stream_stopped);
|
||||
|
||||
do {
|
||||
err = bt_bap_stream_stop(source_stream);
|
||||
if (err == -EBUSY) {
|
||||
k_sleep(BAP_STREAM_RETRY_WAIT);
|
||||
} else if (err != 0) {
|
||||
FAIL("Could not stop stream: %d\n", err);
|
||||
return;
|
||||
}
|
||||
} while (err == -EBUSY);
|
||||
|
||||
WAIT_FOR_FLAG(flag_operation_success);
|
||||
WAIT_FOR_FLAG(flag_stream_stopped);
|
||||
}
|
||||
|
||||
WAIT_FOR_FLAG(flag_stream_disconnected);
|
||||
}
|
||||
|
||||
static void release_streams(size_t stream_cnt)
|
||||
{
|
||||
for (size_t i = 0; i < stream_cnt; i++) {
|
||||
|
@ -994,9 +1055,12 @@ static void test_main(void)
|
|||
printk("Starting transceiving\n");
|
||||
transceive_streams();
|
||||
|
||||
printk("Stopping streams\n");
|
||||
printk("Disabling streams\n");
|
||||
disable_streams(stream_cnt);
|
||||
|
||||
printk("Stopping streams\n");
|
||||
stop_streams(stream_cnt);
|
||||
|
||||
printk("Releasing streams\n");
|
||||
release_streams(stream_cnt);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue