Skip to content

Commit 975a715

Browse files
committed
RP3040 example
1 parent 88bbab6 commit 975a715

File tree

4 files changed

+204
-2
lines changed

4 files changed

+204
-2
lines changed
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/**
2+
* @brief SnapClient with Opus decoder: Wifi processing is on core 0, decoding and
3+
* i2s output is on core 1.
4+
* @author Phil Schatzmann
5+
* @copyright GPLv3
6+
*/
7+
8+
#include "AudioTools.h"
9+
#include "AudioTools/AudioCodecs/CodecOpus.h"
10+
#include "SnapClient.h"
11+
#include "api/SnapProcessorRP2040.h"
12+
13+
//#define ARDUINO_LOOP_STACK_SIZE (10 * 1024)
14+
15+
I2SStream out;
16+
OpusAudioDecoder opus;
17+
WiFiClient wifi;
18+
//SnapTimeSyncDynamic synch(172, 10); // optional configuratioin
19+
SnapClient client(wifi, out, opus);
20+
SnapProcessorRP2040 processor_rp2040(1024*8); // define OPUS queue with 8 kbytes
21+
22+
void setup() {
23+
Serial.begin(115200);
24+
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
25+
while(!Serial);
26+
Serial.println("starting...");
27+
28+
// login to wifi -> Define values in SnapConfig.h or replace them here
29+
WiFi.begin("ssid", "password");
30+
Serial.print("Connecting to WiFi ..");
31+
while (WiFi.status() != WL_CONNECTED) {
32+
Serial.print('.');
33+
delay(1000);
34+
}
35+
36+
// print ip address
37+
Serial.println();
38+
Serial.println(WiFi.localIP());
39+
40+
// Define CONFIG_SNAPCAST_SERVER_HOST in SnapConfig.h or here
41+
client.setServerIP(IPAddress(192,168,1,44));
42+
client.setSnapProcessor(processor_rp2040);
43+
44+
// start snap client
45+
client.begin();
46+
Serial.println("started");
47+
}
48+
49+
void loop() {
50+
// fill queue
51+
client.doLoop();
52+
}
53+
54+
void setup1(){
55+
// setup I2S to define custom pins
56+
auto cfg = out.defaultConfig();
57+
//cfg.pin_bck = 14;
58+
//cfg.pin_ws = 15;
59+
//cfg.pin_data = 22;
60+
cfg.sample_rate = 48000;
61+
cfg.buffer_size = 1024;
62+
cfg.buffer_count = 4;
63+
out.begin(cfg);
64+
}
65+
66+
void loop1(){
67+
// trigger output from queue
68+
processor_rp2040.doLoop1();
69+
}

src/api/SnapLogger.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
#ifdef ESP32
88
# include "esp_log.h"
99
#else
10-
static char msg[100] = {0};
11-
# define DEFAULT_LOG(...) { Serial.println(__PRETTY_FUNCTION__); snprintf((char*)msg, 100, __VA_ARGS__); Serial.println(msg); }
10+
static char msg[100] = ": ";
11+
# define DEFAULT_LOG(...) { Serial.print(__PRETTY_FUNCTION__); snprintf((char*)msg+2, 100, __VA_ARGS__); Serial.println(msg); }
1212
# define ESP_LOGE(tag, ...) DEFAULT_LOG(__VA_ARGS__)
1313
# define ESP_LOGW(tag, ...) DEFAULT_LOG(__VA_ARGS__)
1414
# define ESP_LOGI(tag, ...) //DEFAULT_LOG(__VA_ARGS__)

src/api/SnapProcessor.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,11 @@ class SnapProcessor {
8585
return processLoopStep();
8686
}
8787

88+
/// Usually not used!
89+
virtual bool doLoop1() {
90+
return false;
91+
}
92+
8893
/// Defines the output class
8994
void setOutput(AudioOutput &output) { p_snap_output->setOutput(output); }
9095

src/api/SnapProcessorRP2040.h

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
#pragma once
2+
#include "AudioTools/Concurrency/RP2040.h"
3+
#include "SnapOutput.h"
4+
5+
namespace snap_arduino {
6+
7+
/**
8+
* @brief Processor for which the encoded output is buffered in a queue. The decoding and
9+
* audio output can be done on the second core by calling loop1();
10+
*
11+
* @author Phil Schatzmann
12+
* @version 0.1
13+
* @date 2024-02-26
14+
* @copyright Copyright (c) 2023
15+
*/
16+
class SnapProcessorRP2040 : public SnapProcessor {
17+
public:
18+
/// Default constructor
19+
SnapProcessorRP2040(SnapOutput &output, int bufferSizeBytes, int activationAtPercent = 75)
20+
: SnapProcessor(output) {
21+
active_percent = activationAtPercent;
22+
initQueues(bufferSizeBytes);
23+
}
24+
/// Default constructor
25+
SnapProcessorRP2040(int bufferSizeBytes, int activationAtPercent = 75)
26+
: SnapProcessor() {
27+
active_percent = activationAtPercent;
28+
initQueues(bufferSizeBytes);
29+
}
30+
31+
bool begin() override {
32+
ESP_LOGW(TAG, "begin: %d", buffer_count * 1024);
33+
// regular begin logic
34+
bool result = SnapProcessor::begin();
35+
// allocate buffer, so that we could use psram
36+
size_queue.resize(RTOS_MAX_QUEUE_ENTRY_COUNT);
37+
buffer.resize(buffer_count * 1024);
38+
is_active = false;
39+
return result;
40+
}
41+
42+
void end(void) override {
43+
size_queue.clear();
44+
buffer.reset();
45+
SnapProcessor::end();
46+
}
47+
48+
bool doLoop1() override {
49+
ESP_LOGD(TAG, "doLoop1 %d / %d", size_queue.available(), buffer.available());
50+
if (!isBufferActive()) return true;
51+
52+
size_t size = 0;
53+
if (size_queue.readArray(&size, 1)) {
54+
uint8_t data[size];
55+
int read = buffer.readArray(data, size);
56+
if (read != size){
57+
ESP_LOGE(TAG, "readArray failed %d -> %d", size, read);
58+
}
59+
int written = p_snap_output->audioWrite(data, size);
60+
if (written != size) {
61+
ESP_LOGE(TAG, "write error: %d of %d", written, size);
62+
}
63+
}
64+
return true;
65+
}
66+
67+
protected:
68+
const char *TAG = "SnapProcessorRP2040";
69+
audio_tools::BufferRP2040T<size_t> size_queue{1, 0};
70+
audio_tools::BufferRP2040T<uint8_t> buffer{1024, 0}; // size defined in begin
71+
int buffer_count = 0;
72+
bool is_active = false;
73+
int active_percent = 0;
74+
75+
bool isBufferActive() {
76+
if (!is_active && buffer.available()>0) {
77+
78+
int limit = buffer.size() * active_percent / 100;
79+
if (buffer.available() >= limit) {
80+
LOGI("Setting buffer active");
81+
is_active = true;
82+
}
83+
delay(10);
84+
}
85+
return is_active;
86+
}
87+
88+
/// store parameters provided by constructor
89+
void initQueues(int bufferSizeBytes) {
90+
buffer_count = bufferSizeBytes / 1024;
91+
if (buffer_count <= 2){
92+
buffer_count = 2;
93+
}
94+
}
95+
96+
/// Writes the encoded audio data to a queue
97+
size_t writeAudio(const uint8_t *data, size_t size) override {
98+
99+
if (size > buffer.size()) {
100+
ESP_LOGE(TAG, "The buffer is too small with %d. Use a multiple of %d", buffer.size(), size);
101+
stop();
102+
}
103+
104+
ESP_LOGI(TAG, "size: %zu / buffer %d", size, buffer.available());
105+
if (!p_snap_output->isStarted() || size == 0) {
106+
ESP_LOGW(TAG, "not started");
107+
return 0;
108+
}
109+
110+
// if (!p_snap_output->synchronizePlayback()) {
111+
// return size;
112+
// }
113+
114+
if (!size_queue.writeArray(&size, 1)) {
115+
ESP_LOGW(TAG, "size_queue full");
116+
return 0;
117+
}
118+
119+
size_t size_written = buffer.writeArray(data, size);
120+
if (size_written != size) {
121+
ESP_LOGE(TAG, "buffer-overflow");
122+
}
123+
124+
return size;
125+
}
126+
};
127+
128+
} // namespace snap_arduino

0 commit comments

Comments
 (0)