Skip to content

Commit 5bb77b5

Browse files
committed
vban
1 parent 3a5177d commit 5bb77b5

File tree

5 files changed

+121
-18
lines changed

5 files changed

+121
-18
lines changed
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/**
2+
* @file streams-i2s-vban.ino
3+
* @author Phil Schatzmann
4+
* @brief sends signal from i2s (using an AudioKit) to VBAN Receptor App
5+
*/
6+
7+
#include "AudioTools.h"
8+
#include "AudioLibs/VBANStream.h"
9+
#include "AudioLibs/AudioBoardStream.h" // comment out when not using AudioKit
10+
11+
AudioBoardStream out(AudioKitEs8388V1); // Audio source e.g. replace with I2SStream
12+
VBANStream in;
13+
StreamCopy copier(out, in); // copies sound into i2s
14+
15+
// Arduino Setup
16+
void setup(void) {
17+
// Open Serial
18+
Serial.begin(115200);
19+
while(!Serial);
20+
AudioLogger::instance().begin(Serial, AudioLogger::Info);
21+
22+
// setup output
23+
auto cfg_out = out.defaultConfig(TX_MODE);
24+
if (!out.begin(cfg_out)) stop();
25+
26+
// setup input from vban
27+
auto cfg_in = in.defaultConfig(RX_MODE);
28+
cfg_in.ssid = "ssid";
29+
cfg_in.password = "password";
30+
cfg_in.stream_name = "Talkie";
31+
in.begin(cfg_in);
32+
}
33+
34+
// Arduino loop - copy sound to out
35+
void loop() {
36+
copier.copy();
37+
}

src/AudioLibs/VBANStream.h

Lines changed: 57 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class VBANConfig : public AudioInfo {
2525
const char* ssid = nullptr;
2626
/// password for wifi connection
2727
const char* password = nullptr;
28-
int rx_buffer_count = 10;
28+
int rx_buffer_count = 30;
2929
// set to true if samples are generated faster then sample rate
3030
bool throttle_active = false;
3131
// when negative the number of ms that are subtracted from the calculated wait
@@ -34,6 +34,7 @@ class VBANConfig : public AudioInfo {
3434
// defines the max write size
3535
int max_write_size =
3636
DEFAULT_BUFFER_SIZE * 2; // just good enough for 44100 stereo
37+
uint8_t format = 0;
3738
};
3839

3940
/**
@@ -54,13 +55,16 @@ class VBANStream : public AudioStream {
5455
return def;
5556
}
5657

58+
void setOutput(Print &out){
59+
p_out = &out;
60+
}
61+
5762
void setAudioInfo(AudioInfo info) override {
5863
cfg.copyFrom(info);
5964
AudioStream::setAudioInfo(info);
6065
auto thc = throttle.defaultConfig();
6166
thc.copyFrom(info);
62-
thc.correction_us = cfg.throttle_correction_us;
63-
;
67+
thc.correction_us = cfg.throttle_correction_us;
6468
throttle.begin(thc);
6569
if (cfg.mode == TX_MODE) {
6670
configure_tx();
@@ -82,7 +86,12 @@ class VBANStream : public AudioStream {
8286
tx_buffer.resize(VBAN_PACKET_NUM_SAMPLES);
8387
return begin_tx();
8488
} else {
85-
rx_buffer.resize(VBAN_PACKET_MAX_LEN_BYTES, cfg.rx_buffer_count);
89+
#ifdef ESP32
90+
rx_buffer.resize(DEFAULT_BUFFER_SIZE * cfg.rx_buffer_count);
91+
rx_buffer.setReadMaxWait(10);
92+
#else
93+
rx_buffer.resize(DEFAULT_BUFFER_SIZE, cfg.rx_buffer_count);
94+
#endif
8695
return begin_rx();
8796
}
8897
}
@@ -91,8 +100,7 @@ class VBANStream : public AudioStream {
91100
if (!udp_connected) return 0;
92101

93102
int16_t* adc_data = (int16_t*)data;
94-
;
95-
size_t samples = byteCount / 2;
103+
size_t samples = byteCount / (cfg.bits_per_sample/8);
96104

97105
// limit output speed
98106
if (cfg.throttle_active) {
@@ -123,6 +131,11 @@ class VBANStream : public AudioStream {
123131
int availableForWrite() { return cfg.max_write_size; }
124132

125133
size_t readBytes(uint8_t* data, size_t byteCount) override {
134+
TRACED();
135+
size_t samples = byteCount / (cfg.bits_per_sample/8);
136+
if (cfg.throttle_active) {
137+
throttle.delayFrames(samples / cfg.channels);
138+
}
126139
return rx_buffer.readArray(data, byteCount);
127140
}
128141

@@ -134,12 +147,17 @@ class VBANStream : public AudioStream {
134147
VBan vban;
135148
VBANConfig cfg;
136149
SingleBuffer<int16_t> tx_buffer{0};
150+
#ifdef ESP32
151+
SynchronizedBufferRTOS<uint8_t> rx_buffer{ 0};
152+
#else
137153
NBuffer<uint8_t> rx_buffer{DEFAULT_BUFFER_SIZE, 0};
154+
#endif
138155
bool udp_connected = false;
139156
uint32_t packet_counter = 0;
140157
Throttle throttle;
141158
size_t bytes_received = 0;
142159
bool available_active = false;
160+
Print *p_out = nullptr;
143161

144162
bool begin_tx() {
145163
if (!configure_tx()) {
@@ -332,19 +350,21 @@ class VBANStream : public AudioStream {
332350

333351
int len = packet.length();
334352
if (len > 0) {
353+
LOGD("receive_udp %d", len);
335354
uint8_t* udpIncomingPacket = packet.data();
336355

337356
// receive incoming UDP packet
338357
// Check if packet length meets VBAN specification:
339358
if (len <= (VBAN_PACKET_HEADER_BYTES + VBAN_PACKET_COUNTER_BYTES) ||
340359
len > VBAN_PACKET_MAX_LEN_BYTES) {
341-
LOGE("Error: packet length %u bytes\n", len);
360+
LOGE("Packet length %u bytes", len);
361+
rx_buffer.reset();
342362
return;
343363
}
344364

345365
// Check if preamble matches VBAN format:
346366
if (strncmp("VBAN", (const char*)udpIncomingPacket, 4) != 0) {
347-
LOGE("Unrecognized preamble %.4s\n", udpIncomingPacket);
367+
LOGE("Unrecognized preamble %.4s", udpIncomingPacket);
348368
return;
349369
}
350370

@@ -353,15 +373,26 @@ class VBANStream : public AudioStream {
353373
vban_rx_pkt_nbr = (uint32_t*)&udpIncomingPacket[VBAN_PACKET_HEADER_BYTES];
354374
vban_rx_data = (int16_t*)&udpIncomingPacket[VBAN_PACKET_HEADER_BYTES +
355375
VBAN_PACKET_COUNTER_BYTES];
356-
vban_rx_sample_count = vban_rx_data_bytes / 2;
376+
vban_rx_sample_count = vban_rx_data_bytes / (cfg.bits_per_sample / 8);
357377
uint8_t vbanSampleRateIdx = udpIncomingPacket[4] & VBAN_SR_MASK;
358378
uint8_t vbchannels = udpIncomingPacket[6] + 1;
379+
uint8_t vbframes = udpIncomingPacket[5] + 1;
380+
uint8_t vbformat = udpIncomingPacket[4] & VBAN_PROTOCOL_MASK;;
359381
uint32_t vbanSampleRate = VBanSRList[vbanSampleRateIdx];
382+
383+
LOGD("sample_count: %d - frames: %d", vban_rx_sample_count, vbframes);
384+
assert (vban_rx_sample_count == vbframes*vbchannels);
385+
386+
387+
if (vbformat != cfg.format){
388+
LOGE("Format ignored: 0x%x", vbformat);
389+
return;
390+
}
360391

361392
// Just to be safe, re-check sample count against max sample count to
362393
// avoid overrunning outBuf later
363394
if (vban_rx_sample_count > VBAN_PACKET_MAX_SAMPLES) {
364-
LOGE("error: unexpected packet size: %u\n", vban_rx_sample_count);
395+
LOGE("unexpected packet size: %u", vban_rx_sample_count);
365396
return;
366397
}
367398

@@ -372,17 +403,28 @@ class VBANStream : public AudioStream {
372403
setAudioInfo(cfg);
373404
}
374405

406+
if (p_out!=nullptr){
407+
int size_written = p_out->write((uint8_t*)vban_rx_data, vban_rx_data_bytes);
408+
if (size_written != vban_rx_data_bytes) {
409+
LOGE("buffer overflow %d -> %d", vban_rx_data_bytes, size_written);
410+
}
411+
return;
412+
}
413+
375414
// write data to buffer
376-
int size = vban_rx_sample_count * sizeof(uint16_t);
377-
if (rx_buffer.writeArray((uint8_t*)&vban_rx_data, size) != size) {
378-
LOGE("buffer overflow");
415+
TRACED();
416+
int size_written = rx_buffer.writeArray((uint8_t*)vban_rx_data, vban_rx_data_bytes);
417+
if (size_written != vban_rx_data_bytes) {
418+
LOGE("buffer overflow %d -> %d", vban_rx_data_bytes, size_written);
379419
}
380420

381421
// report available bytes only when buffer is 50% full
382422
if (!available_active) {
383-
bytes_received += size;
384-
if (bytes_received >= cfg.rx_buffer_count * DEFAULT_BUFFER_SIZE * 0.5)
423+
bytes_received += vban_rx_data_bytes;
424+
if (bytes_received >= cfg.rx_buffer_count * DEFAULT_BUFFER_SIZE * 0.75){
385425
available_active = true;
426+
LOGI("Activating vban");
427+
}
386428
}
387429
}
388430
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"folders": [
3+
{
4+
"path": "../.."
5+
}
6+
],
7+
"settings": {
8+
"files.associations": {
9+
"array": "cpp",
10+
"deque": "cpp",
11+
"forward_list": "cpp",
12+
"list": "cpp",
13+
"string": "cpp",
14+
"unordered_map": "cpp",
15+
"unordered_set": "cpp",
16+
"vector": "cpp",
17+
"string_view": "cpp",
18+
"initializer_list": "cpp",
19+
"regex": "cpp"
20+
}
21+
}
22+
}

src/AudioTools/AudioStreams.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1412,7 +1412,7 @@ class Throttle : public AudioStream {
14121412
uint64_t durationUsEff = micros() - start_time;
14131413
uint64_t durationUsToBe = getDelayUs(sum_frames);
14141414
int64_t waitUs = durationUsToBe - durationUsEff + cfg.correction_us;
1415-
LOGI("wait us: %ld", static_cast<long>(waitUs));
1415+
LOGD("wait us: %ld", static_cast<long>(waitUs));
14161416
if (waitUs > 0) {
14171417
int64_t waitMs = waitUs / 1000;
14181418
if (waitMs > 0) delay(waitMs);

src/AudioTools/SynchronizedBuffers.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,7 @@ class SynchronizedBufferRTOS : public BaseBuffer<T> {
345345
public:
346346
SynchronizedBufferRTOS(size_t xStreamBufferSizeBytes, size_t xTriggerLevel=256, TickType_t writeMaxWait=portMAX_DELAY, TickType_t readMaxWait=portMAX_DELAY)
347347
: BaseBuffer<T>() {
348+
if (xStreamBufferSizeBytes>0)
348349
xStreamBuffer = xStreamBufferCreate(xStreamBufferSizeBytes, xTriggerLevel);
349350
readWait = readMaxWait;
350351
writeWait = writeMaxWait;
@@ -355,7 +356,8 @@ class SynchronizedBufferRTOS : public BaseBuffer<T> {
355356

356357
void resize(size_t size){
357358
if (current_size != size){
358-
vStreamBufferDelete(xStreamBuffer);
359+
if (xStreamBuffer!=nullptr)
360+
vStreamBufferDelete(xStreamBuffer);
359361
xStreamBuffer = xStreamBufferCreate(size, trigger_level);
360362
current_size = size;
361363
}
@@ -459,7 +461,7 @@ class SynchronizedBufferRTOS : public BaseBuffer<T> {
459461
}
460462

461463
protected:
462-
StreamBufferHandle_t xStreamBuffer;
464+
StreamBufferHandle_t xStreamBuffer = nullptr;
463465
BaseType_t xHigherPriorityTaskWoken = pdFALSE; // Initialised to pdFALSE.
464466
int readWait = portMAX_DELAY;
465467
int writeWait = portMAX_DELAY;

0 commit comments

Comments
 (0)