arduino-audio-tools
Loading...
Searching...
No Matches
WiFiUDPZephyr.h
Go to the documentation of this file.
1#pragma once
2
3#include <zephyr/net/net_ip.h>
4#include <zephyr/net/socket.h>
5#include <zephyr/sys/util.h>
6
7#include <cstring>
8#include "IPAddress.h"
9
10namespace audio_tools {
11
22 public:
23 WiFiUDPZephyr() = default;
25
26 // -------------------------
27 // Arduino API
28 // -------------------------
30 local_port = port;
31
33 if (sock < 0) return 0;
34
36 addr.sin_family = AF_INET;
37 addr.sin_port = htons(port);
38 addr.sin_addr.s_addr = htonl(INADDR_ANY);
39
40 if (zsock_bind(sock, (sockaddr*)&addr, sizeof(addr)) < 0) {
41 zsock_close(sock);
42 sock = -1;
43 return 0;
44 }
45
46 return 1;
47 }
48
56 local_port = port;
57
59 if (sock < 0) return 0;
60
61 // Allow multiple sockets to share the same port
62 int reuse = 1;
64
65 // Bind to INADDR_ANY on the multicast port
67 addr.sin_family = AF_INET;
68 addr.sin_port = htons(port);
69 addr.sin_addr.s_addr = htonl(INADDR_ANY);
70
71 if (zsock_bind(sock, (sockaddr*)&addr, sizeof(addr)) < 0) {
72 zsock_close(sock);
73 sock = -1;
74 return 0;
75 }
76
77 // Join the multicast group on the default interface
78 struct ip_mreq mreq{};
79 mreq.imr_multiaddr.s_addr = htonl((uint32_t)multicast);
80 mreq.imr_interface.s_addr = htonl(INADDR_ANY);
81
83 sizeof(mreq)) < 0) {
84 zsock_close(sock);
85 sock = -1;
86 return 0;
87 }
88
89 multicast_addr = multicast;
90 is_multicast = true;
91 return 1;
92 }
93
94 void stop() {
95 if (sock >= 0) {
96 // Leave multicast group before closing
97 if (is_multicast) {
98 struct ip_mreq mreq{};
99 mreq.imr_multiaddr.s_addr = htonl((uint32_t)multicast_addr);
100 mreq.imr_interface.s_addr = htonl(INADDR_ANY);
102 &mreq, sizeof(mreq));
103 is_multicast = false;
104 }
105
106 zsock_close(sock);
107 sock = -1;
108 }
109 }
110
111 // -------------------------
112 // TX (Arduino style)
113 // -------------------------
114 int beginPacket(const char* host, uint16_t port) {
115 memset(&tx_addr, 0, sizeof(tx_addr));
116
117 tx_addr.sin_family = AF_INET;
118 tx_addr.sin_port = htons(port);
119
120 if (zsock_inet_pton(AF_INET, host, &tx_addr.sin_addr) != 1) {
121 return 0;
122 }
123
124 tx_len = 0;
125 return 1;
126 }
127
130 memset(&tx_addr, 0, sizeof(tx_addr));
131 tx_addr.sin_family = AF_INET;
132 tx_addr.sin_port = htons(port);
133 tx_addr.sin_addr.s_addr = htonl((uint32_t)ip);
134 tx_len = 0;
135 return 1;
136 }
137
138 int endPacket() {
139 if (sock < 0) return 0;
140
141 // Zero-copy TX attempt: send accumulated buffer once
142 struct iovec iov;
143 iov.iov_base = tx_buffer;
144 iov.iov_len = tx_len;
145
146 struct msghdr msg{};
147 msg.msg_name = &tx_addr;
148 msg.msg_namelen = sizeof(tx_addr);
149 msg.msg_iov = &iov;
150 msg.msg_iovlen = 1;
151
152 int ret = zsock_sendmsg(sock, &msg, 0);
153
154 tx_len = 0;
155 return (ret >= 0);
156 }
157
158 // buffered write (Arduino compatibility)
159 size_t write(uint8_t b) {
160 if (tx_len < sizeof(tx_buffer)) {
161 tx_buffer[tx_len++] = b;
162 return 1;
163 }
164 return 0;
165 }
166
167 size_t write(const uint8_t* data, size_t len) {
168 size_t space = sizeof(tx_buffer) - tx_len;
169 if (len > space) len = space;
170
171 memcpy(tx_buffer + tx_len, data, len);
172 tx_len += len;
173 return len;
174 }
175
176 // -------------------------
177 // RX (ZERO-COPY CORE)
178 // -------------------------
179
181 rx_len = 0;
182
183 sockaddr_in from{};
184 socklen_t from_len = sizeof(from);
185
186 // IMPORTANT: MSG_DONTWAIT = non-blocking like Arduino
187 int len = zsock_recvfrom(sock, rx_buffer, sizeof(rx_buffer), MSG_DONTWAIT,
188 (sockaddr*)&from, &from_len);
189
190 if (len <= 0) return 0;
191
192 rx_len = len;
193 rx_offset = 0;
194 last_from = from;
195
196 return len;
197 }
198
199 // -------------------------
200 // ZERO-COPY RX ACCESS
201 // -------------------------
202
204 const uint8_t* getBuffer() const { return rx_buffer; }
205
206 int available() { return rx_len - rx_offset; }
207
208 int read() {
209 if (rx_offset >= rx_len) return -1;
210 return rx_buffer[rx_offset++];
211 }
212
213 int read(uint8_t* dst, size_t len) {
214 int avail = available();
215 if (avail <= 0) return 0;
216
217 if (len > (size_t)avail) len = avail;
218
219 memcpy(dst, rx_buffer + rx_offset, len);
220 rx_offset += len;
221 return len;
222 }
223
224 inline size_t readBytes(uint8_t* dest, size_t len){
225 return read(dest, len);
226 }
227
228 int peek() {
229 if (rx_offset >= rx_len) return -1;
230 return rx_buffer[rx_offset];
231 }
232
233 // -------------------------
234 // Remote info
235 // -------------------------
236
239 return IPAddress(ntohl(last_from.sin_addr.s_addr));
240 }
241
243 char* remoteIP(char* buf = nullptr) {
244 if (buf ==nullptr){
245 static char buffer[40];
246 buf = buffer;
247 }
248 zsock_inet_ntop(AF_INET, &last_from.sin_addr, buf, INET_ADDRSTRLEN);
249 return buf;
250 }
251
252 uint16_t remotePort() { return ntohs(last_from.sin_port); }
253
254 void flush() {
255 // UDP no-op
256 }
257
258 int availableForWrite() { return sizeof(tx_buffer) - tx_len; }
259
260 private:
261 int sock = -1;
262 uint16_t local_port = 0;
263
264 // TX
265 uint8_t tx_buffer[1472]; // MTU-aligned (good for WiFi + ESP32)
266 size_t tx_len = 0;
267 sockaddr_in tx_addr{};
268
269 // RX (ZERO-COPY BUFFER)
270 uint8_t rx_buffer[1472];
271 size_t rx_len = 0;
272 size_t rx_offset = 0;
273
274 sockaddr_in last_from{};
275 bool is_multicast = false;
276 IPAddress multicast_addr;
277
278};
279
281using EthernetUDP = WiFiUDPZephyr; // EthernetUDP API is identical to WiFiUDP
283
284} // namespace audio_tools
#define htons(x)
Definition Net.h:15
#define ntohl(x)
Definition Net.h:16
#define ntohs(x)
Definition Net.h:17
#define htonl(x)
Definition Net.h:14
Arduino-compatible IPAddress class implemented in pure C++.
Definition IPAddress.h:28
WiFiUDP (Zephyr zsock version) This class provides a UDP interface using Zephyr's socket API (zsock)....
Definition WiFiUDPZephyr.h:21
const uint8_t * getBuffer() const
Direct pointer to internal RX buffer (NO COPY)
Definition WiFiUDPZephyr.h:204
int read(uint8_t *dst, size_t len)
Definition WiFiUDPZephyr.h:213
~WiFiUDPZephyr()
Definition WiFiUDPZephyr.h:24
int beginPacket(const char *host, uint16_t port)
Definition WiFiUDPZephyr.h:114
uint16_t remotePort()
Definition WiFiUDPZephyr.h:252
uint8_t beginMulticast(IPAddress multicast, uint16_t port)
Join a multicast group and listen on the given port.
Definition WiFiUDPZephyr.h:55
int endPacket()
Definition WiFiUDPZephyr.h:138
int available()
Definition WiFiUDPZephyr.h:206
char * remoteIP(char *buf=nullptr)
Fills buf with the dotted-decimal remote IP string; returns buf.
Definition WiFiUDPZephyr.h:243
size_t readBytes(uint8_t *dest, size_t len)
Definition WiFiUDPZephyr.h:224
int availableForWrite()
Definition WiFiUDPZephyr.h:258
IPAddress remoteIP() const
Returns the remote IP as an IPAddress (Arduino-compatible)
Definition WiFiUDPZephyr.h:238
void stop()
Definition WiFiUDPZephyr.h:94
int peek()
Definition WiFiUDPZephyr.h:228
int read()
Definition WiFiUDPZephyr.h:208
size_t write(uint8_t b)
Definition WiFiUDPZephyr.h:159
uint8_t begin(uint16_t port)
Definition WiFiUDPZephyr.h:29
int beginPacket(IPAddress ip, uint16_t port)
Begin a packet to an IPAddress (avoids implicit conversion issues)
Definition WiFiUDPZephyr.h:129
void flush()
Definition WiFiUDPZephyr.h:254
int parsePacket()
Definition WiFiUDPZephyr.h:180
size_t write(const uint8_t *data, size_t len)
Definition WiFiUDPZephyr.h:167
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition AudioCodecsBase.h:10
size_t writeData(Print *p_out, T *data, int samples, int maxSamples=512)
Definition AudioTypes.h:508