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