Skip to content

Commit 23908e5

Browse files
committed
SnapProcessorBuffered
1 parent efc181c commit 23908e5

File tree

2 files changed

+91
-1
lines changed

2 files changed

+91
-1
lines changed

src/api/SnapProcessor.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ class SnapProcessor {
6666
tv_t getLatency() { return time_message.latency; }
6767

6868
void setStartOutput(bool start) { output_start = start; }
69+
6970
void setStartTask(bool flag) { http_task_start = flag; }
7071

7172
/// Call via SnapClient in Arduino Loop!
@@ -155,7 +156,7 @@ class SnapProcessor {
155156
}
156157

157158
/// additional processing
158-
void processExt() {
159+
virtual void processExt() {
159160
delay(5);
160161
}
161162

src/api/SnapProcessorBuffered.h

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
#pragma once
2+
#include "SnapOutput.h"
3+
#include "freertos-all.h" // https://github.com/pschatzmann/arduino-freertos-addons
4+
5+
namespace snap_arduino {
6+
7+
/**
8+
* @brief Processor for which the encoded output is buffered in a ringbuffer in
9+
* order to prevent any buffer underruns.
10+
* @author Phil Schatzmann
11+
* @version 0.1
12+
* @date 2024-03-04
13+
* @copyright Copyright (c) 2024
14+
*/
15+
class SnapProcessorBuffered : public SnapProcessor {
16+
public:
17+
/// Default constructor
18+
SnapProcessorBuffered(int buffer_size, int activationAtPercent = 75)
19+
: SnapProcessor() {
20+
buffer.resize(buffer_size);
21+
active_percent = activationAtPercent;
22+
}
23+
24+
bool begin() override {
25+
// regular begin logic
26+
bool result = SnapProcessor::begin();
27+
// empty buffer
28+
buffer.reset();
29+
sizes.reset();
30+
is_active = false;
31+
return result;
32+
}
33+
34+
/// fill buffer
35+
size_t writeAudio(const uint8_t *data, size_t size) override {
36+
if (size > buffer.size()) {
37+
ESP_LOGE(TAG, "The buffer is too small. Use a multiple of %d", size);
38+
stop();
39+
}
40+
sizes.write(size);
41+
size_t result = buffer.writeArray(data, size);
42+
ESP_LOGI(TAG, "size: %zu / buffer %d", size, buffer.available());
43+
44+
if (result != size)
45+
ESP_LOGE(TAG, "Could not buffer all data %d->%d", size, result);
46+
47+
return result;
48+
}
49+
50+
/// Decode from buffer
51+
virtual void processExt() {
52+
if (isBufferActive()) {
53+
int16_t step_size = sizes.read();
54+
if (step_size > 0) {
55+
uint8_t tmp[step_size];
56+
int size_eff = buffer.readArray(tmp, step_size);
57+
int size_written = SnapProcessor::writeAudio(tmp, size_eff);
58+
if (size_written != size_eff) {
59+
ESP_LOGE(TAG, "Could not write all data %d->%d", size_eff,
60+
size_written);
61+
}
62+
}
63+
}
64+
delay(1);
65+
}
66+
67+
protected:
68+
const char *TAG = "SnapProcessorBuffered";
69+
RingBuffer<uint8_t> buffer{0};
70+
RingBuffer<int16_t> sizes{RTOS_MAX_QUEUE_ENTRY_COUNT};
71+
bool is_active = false;
72+
int active_percent;
73+
74+
bool isBufferActive() {
75+
if (!is_active) {
76+
if (buffer.available() >= bufferTaskActivationLimit()) {
77+
is_active = true;
78+
}
79+
}
80+
return is_active;
81+
}
82+
83+
/// Determines the buffer fill limit at which we start to process the data
84+
int bufferTaskActivationLimit() {
85+
return static_cast<float>(active_percent) / 100.0 * buffer.size();
86+
}
87+
};
88+
89+
} // namespace snap_arduino

0 commit comments

Comments
 (0)