Skip to content

Commit 2d35f76

Browse files
authored
Changes for aoo (#2037)
* CodecNetworkFormat * AOO Draft * AAOSourceLine: FormatConverter as object * AAOSink improvements * AAOSink: use MultiDecoder * AOOSink: added CodecFactory * OutputMixer: availablePercent * DRAFT examples * Cleanup Ringbuffer * aao examples corrections * OutputMixer: support custom buffer types * Cleanup NBuffer * SingleBuffer: optional attributes * DRAFT AOOSinkSingle * aoo corrections * Priority Queue * Delete aoo
1 parent be1207e commit 2d35f76

File tree

8 files changed

+236
-79
lines changed

8 files changed

+236
-79
lines changed

src/AudioTools/AudioCodecs/AudioCodecs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,4 @@
2929
#include "AudioTools/AudioCodecs/CodecMTS.h"
3030
#include "AudioTools/AudioCodecs/CodecADTS.h"
3131
#include "AudioTools/AudioCodecs/CodecNetworkFormat.h"
32+
#include "AudioTools/AudioCodecs/CodecFactory.h"
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
#pragma once
2+
3+
#include "AudioTools/AudioCodecs/AudioCodecsBase.h"
4+
5+
namespace audio_tools {
6+
/**
7+
* @brief Factory for creating new decoders based on the mime type or id
8+
* @ingroup codecs
9+
* @ingroup decoder
10+
* @author Phil Schatzmann
11+
*/
12+
class CodecFactory {
13+
public:
14+
bool addDecoder(const char* id, AudioDecoder* (*cb)()) {
15+
if (id == nullptr || cb == nullptr) return false;
16+
DecoderFactoryLine line;
17+
line.id = id;
18+
line.cb = cb;
19+
decoders.push_back(line);
20+
return true;
21+
}
22+
23+
bool addEncoder(const char* id, AudioEncoder* (*cb)()) {
24+
if (id == nullptr || cb == nullptr) return false;
25+
EncoderFactoryLine line;
26+
line.id = id;
27+
line.cb = cb;
28+
encoders.push_back(line);
29+
return true;
30+
}
31+
32+
/// create a new decoder instance
33+
AudioDecoder* createDecoder(const char* str) {
34+
for (auto& line : decoders) {
35+
if (line.id.equals(str)) {
36+
return line.cb();
37+
}
38+
}
39+
return nullptr;
40+
}
41+
/// create a new encoder instance
42+
AudioEncoder* createEncoder(const char* str) {
43+
for (auto& line : encoders) {
44+
if (line.id.equals(str)) {
45+
return line.cb();
46+
}
47+
}
48+
return nullptr;
49+
}
50+
51+
protected:
52+
struct DecoderFactoryLine {
53+
Str id;
54+
AudioDecoder* (*cb)() = nullptr;
55+
};
56+
struct EncoderFactoryLine {
57+
Str id;
58+
AudioEncoder* (*cb)() = nullptr;
59+
};
60+
Vector<DecoderFactoryLine> decoders;
61+
Vector<EncoderFactoryLine> encoders;
62+
};
63+
64+
} // namespace audio_tools

src/AudioTools/Communication/UDPStream.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ class UDPStream : public BaseStream {
7272
connect();
7373
remote_address_ext = IPAddress((uint32_t)0);
7474
remote_port_ext = port_ext != 0 ? port_ext : port;
75+
printIP();
7576
return p_udp->begin(port);
7677
}
7778

@@ -126,11 +127,17 @@ class UDPStream : public BaseStream {
126127
protected:
127128
WiFiUDP default_udp;
128129
UDP *p_udp = &default_udp;
129-
uint16_t remote_port_ext;
130+
uint16_t remote_port_ext = 0;
130131
IPAddress remote_address_ext;
131132
const char *ssid = nullptr;
132133
const char *password = nullptr;
133134

135+
void printIP(){
136+
Serial.print(WiFi.localIP());
137+
Serial.print(":");
138+
Serial.println(remote_port_ext);
139+
}
140+
134141
/// connect to WIFI if necessary
135142
void connect() {
136143
if (WiFi.status() != WL_CONNECTED && ssid != nullptr &&
@@ -142,9 +149,9 @@ class UDPStream : public BaseStream {
142149
}
143150
#if defined(ESP32)
144151
if (WiFi.status() == WL_CONNECTED) {
152+
esp_wifi_set_ps(WIFI_PS_NONE);
145153
// Performance Hack
146154
// client.setNoDelay(true);
147-
esp_wifi_set_ps(WIFI_PS_NONE);
148155
}
149156
#endif
150157
}

src/AudioTools/CoreAudio/AudioBasic/Collections.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,5 @@
1111
#include "AudioTools/CoreAudio/AudioBasic/Collections/Queue.h"
1212
#include "AudioTools/CoreAudio/AudioBasic/Collections/QueueFromVector.h"
1313
#include "AudioTools/CoreAudio/AudioBasic/Collections/BitVector.h"
14-
#include "AudioTools/CoreAudio/AudioBasic/Collections/Slice.h"
14+
#include "AudioTools/CoreAudio/AudioBasic/Collections/Slice.h"
15+
#include "AudioTools/CoreAudio/AudioBasic/Collections/PriorityQueue.h"
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
#pragma once
2+
#include "AudioTools/CoreAudio/AudioBasic/Collections/List.h"
3+
4+
namespace audio_tools {
5+
6+
/**
7+
* @brief Priority Queue which is based on a List. The order of the elements is
8+
* defined by a compare function which is provided in the constructor. If the
9+
* function returns > 0 if v1 > v2, the data will be provided in increasing
10+
* order.
11+
* @ingroup collections
12+
* @author Phil Schatzmann
13+
* @copyright GPLv3
14+
* @tparam T
15+
*/
16+
template <class T>
17+
class PriorityQueue {
18+
public:
19+
PriorityQueue(int (*compare)(T &v1, T &v2)) { compare_cb = compare; };
20+
21+
bool enqueue(T &&data) {
22+
for (auto it = l.begin(); it != l.end(); ++it) {
23+
if (compare_cb(*it, data) > 0) {
24+
l.insert(it, data);
25+
return true;
26+
}
27+
}
28+
return l.push_back(data);
29+
}
30+
31+
bool peek(T &data) {
32+
if (l.end()->prior == nullptr) return false;
33+
data = *(l.end()->prior);
34+
return true;
35+
}
36+
37+
bool dequeue(T &data) { return l.pop_front(data); }
38+
39+
size_t size() { return l.size(); }
40+
41+
bool clear() { return l.clear(); }
42+
43+
bool empty() { return l.empty(); }
44+
45+
void setAllocator(Allocator &allocator) { l.setAllocator(allocator); }
46+
47+
protected:
48+
List<T> l;
49+
int (*compare_cb)(T &v1, T &v2);
50+
};
51+
52+
} // namespace audio_tools

src/AudioTools/CoreAudio/AudioBasic/Collections/QueueFromVector.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@ class QueueFromVector {
8282
vector.setAllocator(allocator);
8383
}
8484

85+
Vector<T>& toVector() {
86+
return vector;
87+
}
88+
8589
protected:
8690
Vector<T> vector;
8791
int32_t _end_pos = 0;

src/AudioTools/CoreAudio/AudioOutput.h

Lines changed: 28 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,8 @@ class HexDumpOutput : public AudioOutput {
296296

297297

298298
/**
299-
* @brief Mixing of multiple outputs to one final output
299+
* @brief Mixing of multiple outputs to one final output.
300+
* By default a RingBuffer is used as buffer type.
300301
* @ingroup transform
301302
* @author Phil Schatzmann
302303
* @copyright GPLv3
@@ -340,12 +341,10 @@ class OutputMixer : public Print {
340341
}
341342

342343
/// Starts the processing.
343-
bool begin(int copy_buffer_size_bytes = DEFAULT_BUFFER_SIZE,
344-
MemoryType memoryType = PS_RAM) {
344+
bool begin(int copy_buffer_size_bytes = DEFAULT_BUFFER_SIZE) {
345345
is_active = true;
346346
size_bytes = copy_buffer_size_bytes;
347347
stream_idx = 0;
348-
memory_type = memoryType;
349348
allocate_buffers(size_bytes);
350349
return true;
351350
}
@@ -381,7 +380,7 @@ class OutputMixer : public Print {
381380
size_t write(int idx, const uint8_t *buffer_c, size_t bytes) {
382381
LOGD("write idx %d: %d", idx, bytes);
383382
size_t result = 0;
384-
RingBuffer<T> *p_buffer = idx < output_count ? buffers[idx] : nullptr;
383+
BaseBuffer<T> *p_buffer = idx < output_count ? buffers[idx] : nullptr;
385384
assert(p_buffer != nullptr);
386385
size_t samples = bytes / sizeof(T);
387386
if (p_buffer->availableForWrite() >= samples) {
@@ -401,20 +400,25 @@ class OutputMixer : public Print {
401400

402401
/// Provides the bytes available to write for the indicated stream index
403402
int availableForWrite(int idx) {
404-
RingBuffer<T> *p_buffer = buffers[idx];
403+
BaseBuffer<T> *p_buffer = buffers[idx];
405404
if (p_buffer == nullptr)
406405
return 0;
407406
return p_buffer->availableForWrite() * sizeof(T);
408407
}
409408

410409
/// Provides the available bytes in the buffer
411410
int available(int idx){
412-
RingBuffer<T> *p_buffer = buffers[idx];
411+
BaseBuffer<T> *p_buffer = buffers[idx];
413412
if (p_buffer == nullptr)
414413
return 0;
415414
return p_buffer->available() * sizeof(T);
416415
}
417416

417+
/// Provides the % fill level of the buffer for the indicated index
418+
int availablePercent(int idx){
419+
return 100.0 * available(idx) / size_bytes;
420+
}
421+
418422
/// Force output to final destination
419423
void flushMixer() {
420424
LOGD("flush");
@@ -465,7 +469,6 @@ class OutputMixer : public Print {
465469
size_bytes = size;
466470
}
467471

468-
469472
size_t writeSilence(size_t bytes) {
470473
if (bytes == 0) return 0;
471474
uint8_t silence[bytes];
@@ -495,8 +498,18 @@ class OutputMixer : public Print {
495498
stream_idx++;
496499
}
497500

501+
/// Define callback to allocate custum buffer types
502+
void setCreateBufferCallback(BaseBuffer<T>* (*cb)(int size) ){
503+
create_buffer_cb = cb;
504+
}
505+
506+
/// Provides the write buffer for the indicated index
507+
BaseBuffer<T>* getBuffer(int idx){
508+
return idx < output_count ? buffers[idx] : nullptr;
509+
}
510+
498511
protected:
499-
Vector<RingBuffer<T> *> buffers{0};
512+
Vector<BaseBuffer<T> *> buffers{0};
500513
Vector<T> output{0};
501514
Vector<float> weights{0};
502515
Print *p_final_output = nullptr;
@@ -505,9 +518,13 @@ class OutputMixer : public Print {
505518
int stream_idx = 0;
506519
int size_bytes = 0;
507520
int output_count = 0;
508-
MemoryType memory_type;
509521
void *p_memory = nullptr;
510522
bool is_auto_index = true;
523+
BaseBuffer<T>* (*create_buffer_cb)(int size) = create_buffer;
524+
525+
static BaseBuffer<T>* create_buffer(int size) {
526+
return new RingBuffer<T>(size / sizeof(T));
527+
}
511528

512529
void update_total_weights() {
513530
total_weights = 0.0;
@@ -522,22 +539,7 @@ class OutputMixer : public Print {
522539
if (buffers[j] != nullptr) {
523540
delete buffers[j];
524541
}
525-
#if defined(ESP32) && defined(ARDUINO)
526-
if (memory_type == PS_RAM && ESP.getFreePsram() >= size) {
527-
p_memory = ps_malloc(size);
528-
LOGI("Buffer %d allocated %d bytes in PS_RAM", j, size);
529-
} else {
530-
p_memory = malloc(size);
531-
LOGI("Buffer %d allocated %d bytes in RAM", j, size);
532-
}
533-
if (p_memory != nullptr) {
534-
buffers[j] = new (p_memory) RingBuffer<T>(size / sizeof(T));
535-
} else {
536-
LOGE("Not enough memory to allocate %d bytes", size);
537-
}
538-
#else
539-
buffers[j] = new RingBuffer<T>(size / sizeof(T));
540-
#endif
542+
buffers[j] = create_buffer(size);
541543
}
542544
}
543545

@@ -546,11 +548,6 @@ class OutputMixer : public Print {
546548
for (int j = 0; j < output_count; j++) {
547549
if (buffers[j] != nullptr) {
548550
delete buffers[j];
549-
#ifdef ESP32
550-
if (p_memory != nullptr) {
551-
free(p_memory);
552-
}
553-
#endif
554551
buffers[j] = nullptr;
555552
}
556553
}

0 commit comments

Comments
 (0)