1 /*
2 * Copyright (c) 2025 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #include <errno.h>
7 #include <stdint.h>
8 #include <string.h>
9
10 #include <zephyr/autoconf.h>
11 #include <zephyr/bluetooth/audio/audio.h>
12 #include <zephyr/bluetooth/audio/bap.h>
13 #include <zephyr/bluetooth/hci_types.h>
14 #include <zephyr/bluetooth/iso.h>
15 #include <zephyr/kernel.h>
16 #include <zephyr/logging/log.h>
17 #include <zephyr/logging/log_core.h>
18 #include <zephyr/net_buf.h>
19 #include <zephyr/sys/util.h>
20 #include <zephyr/sys/util_macro.h>
21
22 #if defined(CONFIG_LIBLC3)
23 #include <lc3.h>
24 #endif /* defined(CONFIG_LIBLC3) */
25
26 #include "stream_rx.h"
27 #include "lc3.h"
28
29 struct stream_rx rx_streams[CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT];
30 uint64_t total_rx_iso_packet_count; /* This value is exposed to test code */
31
32 LOG_MODULE_REGISTER(stream_rx, CONFIG_LOG_DEFAULT_LEVEL);
33
34 #if CONFIG_INFO_REPORTING_INTERVAL > 0
log_stream_rx(const struct stream_rx * stream,const struct bt_iso_recv_info * info,const struct net_buf * buf)35 static void log_stream_rx(const struct stream_rx *stream, const struct bt_iso_recv_info *info,
36 const struct net_buf *buf)
37 {
38 LOG_INF("[%zu]: Incoming audio on stream %p len %u, flags 0x%02X, seq_num %u and ts %u: "
39 "Valid %zu | Error %zu | Loss %zu | Dup TS %zu | Dup PSN %zu",
40 stream->reporting_info.recv_cnt, &stream->stream, buf->len, info->flags,
41 info->seq_num, info->ts, stream->reporting_info.valid_cnt,
42 stream->reporting_info.error_cnt, stream->reporting_info.loss_cnt,
43 stream->reporting_info.dup_ts_cnt, stream->reporting_info.dup_psn_cnt);
44 }
45 #endif /* CONFIG_INFO_REPORTING_INTERVAL > 0 */
46
stream_rx_recv(struct bt_bap_stream * bap_stream,const struct bt_iso_recv_info * info,struct net_buf * buf)47 void stream_rx_recv(struct bt_bap_stream *bap_stream, const struct bt_iso_recv_info *info,
48 struct net_buf *buf)
49 {
50 struct stream_rx *stream = CONTAINER_OF(bap_stream, struct stream_rx, stream);
51
52 #if CONFIG_INFO_REPORTING_INTERVAL > 0
53 bool do_log = false;
54
55 stream->reporting_info.recv_cnt++;
56 if (stream->reporting_info.recv_cnt == 1U) {
57 /* Log first reception */
58 do_log = true;
59
60 } else if ((stream->reporting_info.recv_cnt % CONFIG_INFO_REPORTING_INTERVAL) == 0U) {
61 /* Log once for every CONFIG_INFO_REPORTING_INTERVAL reception */
62 do_log = true;
63 }
64
65 if (stream->reporting_info.recv_cnt > 1U && info->ts == stream->reporting_info.last_ts) {
66 stream->reporting_info.dup_ts_cnt++;
67 do_log = true;
68 LOG_WRN("Duplicated timestamp received: %u", stream->reporting_info.last_ts);
69 }
70
71 if (stream->reporting_info.recv_cnt > 1U &&
72 info->seq_num == stream->reporting_info.last_seq_num) {
73 stream->reporting_info.dup_psn_cnt++;
74 do_log = true;
75 LOG_WRN("Duplicated PSN received: %u", stream->reporting_info.last_seq_num);
76 }
77
78 if (info->flags & BT_ISO_FLAGS_ERROR) {
79 stream->reporting_info.error_cnt++;
80 do_log = true;
81 LOG_DBG("ISO receive error");
82 }
83
84 if (info->flags & BT_ISO_FLAGS_LOST) {
85 stream->reporting_info.loss_cnt++;
86 do_log = true;
87 LOG_DBG("ISO receive lost");
88 }
89
90 if (info->flags & BT_ISO_FLAGS_VALID) {
91 if (buf->len == 0U) {
92 stream->reporting_info.empty_sdu_cnt++;
93 } else {
94 stream->reporting_info.valid_cnt++;
95 }
96 }
97
98 if (do_log) {
99 log_stream_rx(stream, info, buf);
100 }
101
102 stream->reporting_info.last_seq_num = info->seq_num;
103 stream->reporting_info.last_ts = info->ts;
104 #endif /* CONFIG_INFO_REPORTING_INTERVAL > 0 */
105
106 total_rx_iso_packet_count++;
107
108 if (IS_ENABLED(CONFIG_LIBLC3)) {
109 /* Invalid SDUs will trigger PLC */
110 lc3_enqueue_for_decoding(stream, info, buf);
111 }
112 }
113
stream_rx_started(struct bt_bap_stream * bap_stream)114 int stream_rx_started(struct bt_bap_stream *bap_stream)
115 {
116 struct stream_rx *stream = CONTAINER_OF(bap_stream, struct stream_rx, stream);
117
118 if (stream == NULL) {
119 return -EINVAL;
120 }
121
122 #if CONFIG_INFO_REPORTING_INTERVAL > 0
123 memset(&stream->reporting_info, 0, sizeof((stream->reporting_info)));
124 #endif /* CONFIG_INFO_REPORTING_INTERVAL > 0 */
125
126 if (IS_ENABLED(CONFIG_LIBLC3) && bap_stream->codec_cfg != NULL &&
127 bap_stream->codec_cfg->id == BT_HCI_CODING_FORMAT_LC3) {
128 int err;
129
130 err = lc3_enable(stream);
131 if (err < 0) {
132 LOG_ERR("Error: cannot enable LC3 codec: %d", err);
133 return err;
134 }
135 }
136
137 return 0;
138 }
139
stream_rx_stopped(struct bt_bap_stream * bap_stream)140 int stream_rx_stopped(struct bt_bap_stream *bap_stream)
141 {
142 struct stream_rx *stream = CONTAINER_OF(bap_stream, struct stream_rx, stream);
143
144 if (bap_stream == NULL) {
145 return -EINVAL;
146 }
147
148 if (IS_ENABLED(CONFIG_LIBLC3) && bap_stream->codec_cfg != NULL &&
149 bap_stream->codec_cfg->id == BT_HCI_CODING_FORMAT_LC3) {
150 int err;
151
152 err = lc3_disable(stream);
153 if (err < 0) {
154 LOG_ERR("Error: cannot disable LC3 codec: %d", err);
155 return err;
156 }
157 }
158
159 return 0;
160 }
161
stream_rx_get_streams(struct bt_bap_stream * bap_streams[CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT])162 void stream_rx_get_streams(
163 struct bt_bap_stream *bap_streams[CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT])
164 {
165 for (size_t i = 0U; i < ARRAY_SIZE(rx_streams); i++) {
166 bap_streams[i] = &rx_streams[i].stream;
167 }
168 }
169