5 #include "AudioTools/AudioLibs/vban/vban.h"
6 #include "AudioTools/CoreAudio/AudioStreams.h"
7 #include "AudioTools/Concurrency/BufferRTOS.h"
26 const char*
ssid =
nullptr;
29 int rx_buffer_count = 30;
31 bool throttle_active =
false;
34 int throttle_correction_us = 0;
37 DEFAULT_BUFFER_SIZE * 2;
59 void setOutput(
Print &out){
66 auto thc = throttle.defaultConfig();
68 thc.correction_us = cfg.throttle_correction_us;
70 if (cfg.mode == TX_MODE) {
82 if (cfg.mode == TX_MODE) {
84 LOGE(
"Only 16 bits supported")
87 tx_buffer.resize(VBAN_PACKET_NUM_SAMPLES);
91 rx_buffer.
resize(DEFAULT_BUFFER_SIZE * cfg.rx_buffer_count);
92 rx_buffer.setReadMaxWait(10);
94 rx_buffer.
resize(DEFAULT_BUFFER_SIZE, cfg.rx_buffer_count);
100 size_t write(
const uint8_t* data,
size_t len)
override {
101 if (!udp_connected)
return 0;
103 int16_t* adc_data = (int16_t*)data;
107 if (cfg.throttle_active) {
108 throttle.delayFrames(samples / cfg.
channels);
111 for (
int j = 0; j < samples; j++) {
112 tx_buffer.
write(adc_data[j]);
114 memcpy(vban.data_frame, tx_buffer.
data(), vban.packet_data_bytes);
115 *vban.packet_counter = packet_counter;
117 if (cfg.
target_ip == broadcast_address) {
118 udp.broadcastTo((uint8_t*)&vban.packet, vban.packet_total_bytes,
121 udp.writeTo((uint8_t*)&vban.packet, vban.packet_total_bytes,
132 int availableForWrite() {
return cfg.max_write_size; }
134 size_t readBytes(uint8_t* data,
size_t len)
override {
137 if (cfg.throttle_active) {
138 throttle.delayFrames(samples / cfg.
channels);
143 int available() {
return available_active ? rx_buffer.
available() : 0; }
146 const IPAddress broadcast_address{0, 0, 0, 0};
150 SingleBuffer<int16_t> tx_buffer{0};
152 BufferRTOS<uint8_t> rx_buffer{ 0};
154 NBuffer<uint8_t> rx_buffer{DEFAULT_BUFFER_SIZE, 0};
156 bool udp_connected =
false;
157 uint32_t packet_counter = 0;
159 size_t bytes_received = 0;
160 bool available_active =
false;
161 Print *p_out =
nullptr;
164 if (!configure_tx()) {
168 if (WiFi.status() != WL_CONNECTED) {
169 LOGE(
"Wifi not connected");
172 WiFi.setSleep(
false);
173 IPAddress myIP = WiFi.localIP();
174 udp_connected = udp.connect(myIP, cfg.udp_port);
175 return udp_connected;
180 if (WiFi.status() != WL_CONNECTED) {
181 LOGE(
"Wifi not connected");
184 WiFi.setSleep(
false);
186 this->available_active =
false;
188 if (!udp.listen(cfg.udp_port)) {
189 LOGE(
"Could not connect to '%s:%d' target", toString(cfg.target_ip),
193 udp.onPacket([
this](AsyncUDPPacket packet) {
receive_udp(packet); });
198 bool configure_tx() {
199 int rate = vban_sample_rate();
201 LOGE(
"Invalid sample rate: %d", cfg.sample_rate);
204 configure_vban((VBanSampleRates)rate);
209 if (cfg.ssid ==
nullptr)
return;
210 if (cfg.password ==
nullptr)
return;
211 LOGI(
"ssid %s", cfg.ssid);
213 WiFi.begin(cfg.ssid, cfg.password);
214 while (WiFi.status() != WL_CONNECTED) {
220 LOGI(
"Wifi connected to IP (%d.%d.%d.%d)", WiFi.localIP()[0],
221 WiFi.localIP()[1], WiFi.localIP()[2], WiFi.localIP()[3]);
224 void configure_vban(VBanSampleRates rate) {
228 vban.packet_counter = (uint32_t*)&vban.packet[VBAN_PACKET_HEADER_BYTES];
231 .packet[VBAN_PACKET_HEADER_BYTES + VBAN_PACKET_COUNTER_BYTES];
234 strncpy(vban.hdr->preamble,
"VBAN", 4);
235 vban.hdr->sample_rate =
236 static_cast<int>(VBAN_PROTOCOL_AUDIO) |
238 vban.hdr->num_samples =
239 (VBAN_PACKET_NUM_SAMPLES / cfg.channels) - 1;
240 vban.hdr->num_channels = cfg.channels - 1;
241 vban.hdr->sample_format =
242 static_cast<int>(VBAN_BITFMT_16_INT) | VBAN_CODEC_PCM;
243 strncpy(vban.hdr->stream_name, cfg.stream_name,
244 min((
int)strlen(cfg.stream_name), VBAN_STREAM_NAME_SIZE));
246 vban.packet_data_bytes =
247 (vban.hdr->num_samples + 1) * (vban.hdr->num_channels + 1) *
248 ((vban.hdr->sample_format & VBAN_BIT_RESOLUTION_MASK) + 1);
249 vban.packet_total_bytes = vban.packet_data_bytes +
250 VBAN_PACKET_HEADER_BYTES +
251 VBAN_PACKET_COUNTER_BYTES;
254 int vban_sample_rate() {
256 switch (cfg.sample_rate) {
258 result = SAMPLE_RATE_6000_HZ;
261 result = SAMPLE_RATE_12000_HZ;
264 result = SAMPLE_RATE_24000_HZ;
267 result = SAMPLE_RATE_48000_HZ;
270 result = SAMPLE_RATE_96000_HZ;
273 result = SAMPLE_RATE_192000_HZ;
276 result = SAMPLE_RATE_384000_HZ;
279 result = SAMPLE_RATE_8000_HZ;
282 result = SAMPLE_RATE_16000_HZ;
285 result = SAMPLE_RATE_32000_HZ;
288 result = SAMPLE_RATE_64000_HZ;
291 result = SAMPLE_RATE_128000_HZ;
294 result = SAMPLE_RATE_256000_HZ;
297 result = SAMPLE_RATE_512000_HZ;
300 result = SAMPLE_RATE_11025_HZ;
303 result = SAMPLE_RATE_22050_HZ;
306 result = SAMPLE_RATE_44100_HZ;
309 result = SAMPLE_RATE_88200_HZ;
312 result = SAMPLE_RATE_176400_HZ;
315 result = SAMPLE_RATE_352800_HZ;
318 result = SAMPLE_RATE_705600_HZ;
324 const char* toString(IPAddress adr) {
325 static char str[11] = {0};
326 snprintf(str, 11,
"%d.%d.%d.%d", adr[0], adr[1], adr[2], adr[3]);
346 uint16_t vban_rx_data_bytes, vban_rx_sample_count;
347 int16_t* vban_rx_data;
348 uint32_t* vban_rx_pkt_nbr;
349 uint16_t outBuf[VBAN_PACKET_MAX_SAMPLES + 1];
352 int len = packet.length();
354 LOGD(
"receive_udp %d", len);
355 uint8_t* udpIncomingPacket = packet.data();
359 if (len <= (VBAN_PACKET_HEADER_BYTES + VBAN_PACKET_COUNTER_BYTES) ||
360 len > VBAN_PACKET_MAX_LEN_BYTES) {
361 LOGE(
"Packet length %u bytes", len);
367 if (strncmp(
"VBAN", (
const char*)udpIncomingPacket, 4) != 0) {
368 LOGE(
"Unrecognized preamble %.4s", udpIncomingPacket);
373 len - (VBAN_PACKET_HEADER_BYTES + VBAN_PACKET_COUNTER_BYTES);
374 vban_rx_pkt_nbr = (uint32_t*)&udpIncomingPacket[VBAN_PACKET_HEADER_BYTES];
375 vban_rx_data = (int16_t*)&udpIncomingPacket[VBAN_PACKET_HEADER_BYTES +
376 VBAN_PACKET_COUNTER_BYTES];
377 vban_rx_sample_count = vban_rx_data_bytes / (cfg.bits_per_sample / 8);
378 uint8_t vbanSampleRateIdx = udpIncomingPacket[4] & VBAN_SR_MASK;
379 uint8_t vbchannels = udpIncomingPacket[6] + 1;
380 uint8_t vbframes = udpIncomingPacket[5] + 1;
381 uint8_t vbformat = udpIncomingPacket[7] & VBAN_PROTOCOL_MASK;;
382 uint8_t vbformat_bits = udpIncomingPacket[7] & VBAN_BIT_RESOLUTION_MASK;;
383 uint32_t vbanSampleRate = VBanSRList[vbanSampleRateIdx];
389 if (vbformat != cfg.format){
390 LOGE(
"Format ignored: 0x%x", vbformat);
395 if (vbformat_bits != VBAN_BITFMT_16_INT){
396 LOGE(
"Format only 16 bits supported");
402 if (vban_rx_sample_count > VBAN_PACKET_MAX_SAMPLES) {
403 LOGE(
"unexpected packet size: %u", vban_rx_sample_count);
408 if (cfg.sample_rate != vbanSampleRate || cfg.channels != vbchannels) {
410 cfg.sample_rate = vbanSampleRate;
411 cfg.channels = vbchannels;
415 available_active =
false;
419 int size_written = p_out->write((uint8_t*)vban_rx_data, vban_rx_data_bytes);
420 if (size_written != vban_rx_data_bytes) {
421 LOGE(
"buffer overflow %d -> %d", vban_rx_data_bytes, size_written);
427 int size_written = rx_buffer.
writeArray((uint8_t*)vban_rx_data, vban_rx_data_bytes);
428 if (size_written != vban_rx_data_bytes) {
429 LOGE(
"buffer overflow %d -> %d", vban_rx_data_bytes, size_written);
433 if (!available_active) {
434 bytes_received += vban_rx_data_bytes;
435 if (bytes_received >= cfg.rx_buffer_count * DEFAULT_BUFFER_SIZE * 0.75){
436 available_active =
true;
437 LOGI(
"Activating vban");
RxTxMode
The Microcontroller is the Audio Source (TX_MODE) or Audio Sink (RX_MODE). RXTX_MODE is Source and Si...
Definition: AudioTypes.h:28