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 	if ((stream->reporting_info.recv_cnt % CONFIG_INFO_REPORTING_INTERVAL) == 0U) {
54 		log_stream_rx(stream, info, buf);
55 	}
56 
57 	if (stream->reporting_info.recv_cnt > 0U && info->ts == stream->reporting_info.last_ts) {
58 		log_stream_rx(stream, info, buf);
59 		LOG_WRN("Duplicated timestamp received: %u\n", stream->reporting_info.last_ts);
60 		stream->reporting_info.dup_ts_cnt++;
61 	}
62 
63 	if (stream->reporting_info.recv_cnt > 0U &&
64 	    info->seq_num == stream->reporting_info.last_seq_num) {
65 		log_stream_rx(stream, info, buf);
66 		LOG_WRN("Duplicated PSN received: %u\n", stream->reporting_info.last_seq_num);
67 		stream->reporting_info.dup_psn_cnt++;
68 	}
69 
70 	if (info->flags & BT_ISO_FLAGS_ERROR) {
71 		log_stream_rx(stream, info, buf);
72 		LOG_DBG("ISO receive error\n");
73 		stream->reporting_info.error_cnt++;
74 	}
75 
76 	if (info->flags & BT_ISO_FLAGS_LOST) {
77 		log_stream_rx(stream, info, buf);
78 		LOG_DBG("ISO receive lost\n");
79 		stream->reporting_info.loss_cnt++;
80 	}
81 
82 	if (info->flags & BT_ISO_FLAGS_VALID) {
83 		if (buf->len == 0U) {
84 			stream->reporting_info.empty_sdu_cnt++;
85 		} else {
86 			stream->reporting_info.valid_cnt++;
87 		}
88 	}
89 
90 	stream->reporting_info.last_seq_num = info->seq_num;
91 	stream->reporting_info.last_ts = info->ts;
92 	stream->reporting_info.recv_cnt++;
93 #endif /* CONFIG_INFO_REPORTING_INTERVAL > 0 */
94 
95 	total_rx_iso_packet_count++;
96 
97 	if (IS_ENABLED(CONFIG_LIBLC3)) {
98 		/* Invalid SDUs will trigger PLC */
99 		lc3_enqueue_for_decoding(stream, info, buf);
100 	}
101 }
102 
stream_rx_started(struct bt_bap_stream * bap_stream)103 int stream_rx_started(struct bt_bap_stream *bap_stream)
104 {
105 	struct stream_rx *stream = CONTAINER_OF(bap_stream, struct stream_rx, stream);
106 
107 	if (stream == NULL) {
108 		return -EINVAL;
109 	}
110 
111 #if CONFIG_INFO_REPORTING_INTERVAL > 0
112 	memset(&stream->reporting_info, 0, sizeof((stream->reporting_info)));
113 #endif /* CONFIG_INFO_REPORTING_INTERVAL > 0 */
114 
115 	if (IS_ENABLED(CONFIG_LIBLC3) && bap_stream->codec_cfg != NULL &&
116 	    bap_stream->codec_cfg->id == BT_HCI_CODING_FORMAT_LC3) {
117 		int err;
118 
119 		err = lc3_enable(stream);
120 		if (err < 0) {
121 			LOG_ERR("Error: cannot enable LC3 codec: %d", err);
122 			return err;
123 		}
124 	}
125 
126 	return 0;
127 }
128 
stream_rx_stopped(struct bt_bap_stream * bap_stream)129 int stream_rx_stopped(struct bt_bap_stream *bap_stream)
130 {
131 	struct stream_rx *stream = CONTAINER_OF(bap_stream, struct stream_rx, stream);
132 
133 	if (bap_stream == NULL) {
134 		return -EINVAL;
135 	}
136 
137 	if (IS_ENABLED(CONFIG_LIBLC3) && bap_stream->codec_cfg != NULL &&
138 	    bap_stream->codec_cfg->id == BT_HCI_CODING_FORMAT_LC3) {
139 		int err;
140 
141 		err = lc3_disable(stream);
142 		if (err < 0) {
143 			LOG_ERR("Error: cannot disable LC3 codec: %d", err);
144 			return err;
145 		}
146 	}
147 
148 	return 0;
149 }
150 
stream_rx_get_streams(struct bt_bap_stream * bap_streams[CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT])151 void stream_rx_get_streams(
152 	struct bt_bap_stream *bap_streams[CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT])
153 {
154 	for (size_t i = 0U; i < ARRAY_SIZE(rx_streams); i++) {
155 		bap_streams[i] = &rx_streams[i].stream;
156 	}
157 }
158