arduino-audio-tools
Loading...
Searching...
No Matches
AudioServerT.h
Go to the documentation of this file.
1#pragma once
2
3#include <string>
4
8#include "AudioToolsConfig.h"
9
10namespace audio_tools {
11
13typedef void (*AudioServerDataCallback)(Print *out);
14
25class ChunkedPrint : public Print {
26 public:
27 ChunkedPrint() = default;
28
30 void begin(Print &out) { p_out = &out; }
31
32 size_t write(uint8_t c) override { return write(&c, 1); }
33
34 size_t write(const uint8_t *data, size_t len) override {
35 if (p_out == nullptr || len == 0) return 0;
36 p_out->print(len, HEX);
37 p_out->print("\r\n");
38 size_t written = p_out->write(data, len);
39 p_out->print("\r\n");
40 return written;
41 }
42
44 void end() {
45 if (p_out == nullptr) return;
46 p_out->print("0\r\n\r\n");
47 p_out = nullptr;
48 }
49
50 protected:
51 Print *p_out = nullptr;
52};
53
79template <class Client, class Server>
81 public:
86 AudioServerT(int port = 80) {
87 // the client returns 0 for availableForWrite()
89 setupServer(port);
90 }
91
98 AudioServerT(const char *network, const char *password, int port = 80) {
99 this->network = network ? network : "";
100 this->password = password ? password : "";
101
102 // the client returns 0 for availableForWrite()
104 setupServer(port);
105 }
106
114 bool begin(Stream &in, const char *contentType) {
115 TRACED();
116
117 this->in = &in;
118 this->callback = nullptr;
119 setContentType(contentType);
120
121 return startServer();
122 }
123
130 bool begin(AudioServerDataCallback cb, const char *contentType) {
131 TRACED();
132
133 this->in = nullptr;
134 this->callback = cb;
135 setContentType(contentType);
136
137 return startServer();
138 }
139
141 bool begin() {
142 if (content_type == nullptr) {
143 LOGE("Content type is not defined");
144 return false;
145 }
146 return startServer();
147 }
148
150 void setContentType(const char *contentType) { this->content_type = contentType ? contentType : ""; }
151
160 bool copy() { return doLoop(); }
161
166 bool doLoop() {
167 // LOGD("doLoop");
168 bool active = true;
169
170 if (!client_obj.connected()) {
171#if USE_SERVER_ACCEPT
172 client_obj = server.accept(); // listen for incoming clients
173#else
174 client_obj = server.available(); // listen for incoming clients
175#endif
177 } else {
178 // We are connected: copy input from source to wav output
179 if (client_obj) {
180 if (callback == nullptr) {
181 LOGD("copy data...");
182 if (converter_ptr == nullptr) {
183 sent += copier.copy();
184 } else {
186 }
187
188 if (max_output_size > 0 && sent >= max_output_size) {
189 LOGI("max output size reached...");
190 endChunked();
192 active = false;
193 }
194
195 if (!client_obj) {
196 LOGI("stop client...");
197 endChunked();
199 active = false;
200 }
201 }
202 } else {
203 LOGI("client was not connected");
204 }
205 }
206 return active;
207 }
208
211
213 Stream &out() { return client_obj; }
214
216 Client *out_ptr() { return &client_obj; }
217
220
222 operator bool() { return client_obj.connected(); }
223
225 void setCopyBufferSize(int size) { copier.resize(size); }
226
230 void setChunked(bool flag) { is_chunked = flag; }
231
233 bool isChunked() { return is_chunked; }
234
239 void setMaxOutputSize(size_t size) {
240 max_output_size = size;
241 is_chunked = (size == 0);
242 }
243
245 size_t maxOutputSize() { return max_output_size; }
246
248 void end() {
249 if (client_obj) {
250 endChunked();
252 }
253 // reset the state
254 callback = nullptr;
255 in = nullptr;
256 converter_ptr = nullptr;
257 sent = 0;
258 }
259
260
261 protected:
262 // WIFI
263#ifdef ESP32
264 Server server;
265#else
266 Server server{80};
267#endif
268
270
271 std::string password;
272 std::string network;
273
274 size_t sent = 0;
275 size_t max_output_size = 0;
276
277 // Content
278 const char *content_type = nullptr;
279
281 Stream *in = nullptr;
282
285
286 // no size defined (default) => fall back to chunked transfer encoding
287 bool is_chunked = true;
289
290 void setupServer(int port) {
291 Server tmp(port);
292 server = tmp;
293 }
294
297 bool startServer() {
298#ifdef USE_WIFI
299 connectWiFi();
300#endif
301 server.begin();
302 return true;
303 }
304
305#ifdef USE_WIFI
306 void connectWiFi() {
307 TRACED();
308
309 if (WiFi.status() != WL_CONNECTED &&
310 !network.empty() &&
311 !password.empty()) {
312
313 WiFi.begin(network.c_str(), password.c_str());
314
315 while (WiFi.status() != WL_CONNECTED) {
316 Serial.print(".");
317 delay(500);
318 }
319
320#ifdef ESP32
321 WiFi.setSleep(false);
322#endif
323
324 Serial.println();
325 }
326
327 Serial.print("IP address: ");
328 Serial.println(WiFi.localIP());
329 }
330#endif
331
332 virtual void sendReplyHeader() {
333 TRACED();
334
335 // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
336 // and a content-type so the client knows what's coming, then a blank line:
337 const char *response = "HTTP/1.1 200 OK";
338 client_obj.println(response);
339 LOGI("%s", response);
340
341 if (content_type != nullptr) {
342 client_obj.print("Content-type:");
343 client_obj.println(content_type);
344 LOGI("Content-type: %s", content_type);
345 }
346
347 // for firefox to play
348 client_obj.println("Content-Disposition: inline");
349
350 if (max_output_size > 0) {
351 client_obj.print("Content-Length:");
352 client_obj.println((unsigned long)max_output_size);
353 LOGI("Content-Length: %lu", (unsigned long)max_output_size);
354 } else if (is_chunked) {
355 client_obj.println("Transfer-Encoding: chunked");
356 LOGI("Transfer-Encoding: chunked");
357 }
358
359 client_obj.println();
360
361 if (!client_obj.connected()) {
362 LOGE("connection was closed");
363 }
364 }
365
366 virtual void sendReplyContent() {
367 TRACED();
368
369 Print *p_out = &client_obj;
370 if (is_chunked) {
372 p_out = &chunked_print;
373 }
374
375 if (callback != nullptr) {
376 // provide data via Callback
377 LOGI("sendReply - calling callback");
378 callback(p_out);
379 endChunked();
381 } else if (in != nullptr) {
382 // provide data for stream
383 LOGI("sendReply - Returning audio stream...");
384 copier.begin(*p_out, *in);
385
386 if (!client_obj.connected()) {
387 LOGE("connection was closed");
388 }
389 }
390 }
391
393 void endChunked() {
395 }
396
401 // LOGD("processClient");
402 if (client_obj) {
403 LOGI("New Client:");
404
405 std::string currentLine;
406 currentLine.reserve(128);
407
408 while (client_obj.connected()) {
409 if (client_obj.available()) {
410 char c = client_obj.read();
411
412 if (c == '\n') {
413 LOGI("Request: %s", currentLine.c_str());
414
415 // if the current line is blank, you got two newline characters in a
416 // row. that's the end of the client HTTP request, so send a response:
417 if (currentLine.length() == 0) {
420
421 sent = 0;
422
423 break;
424 } else {
425 currentLine = "";
426 }
427 } else if (c != '\r') {
428 currentLine += c;
429 }
430 }
431 }
432 }
433 }
434};
435
436} // namespace audio_tools
static HardwareSerial Serial
Definition Arduino.h:179
@ HEX
Definition Arduino.h:54
#define TRACED()
Definition AudioLoggerIDF.h:31
#define LOGI(...)
Definition AudioLoggerIDF.h:28
#define LOGD(...)
Definition AudioLoggerIDF.h:27
#define LOGE(...)
Definition AudioLoggerIDF.h:30
Definition Arduino.h:162
bool connected()
Definition Arduino.h:167
virtual int read(uint8_t *buffer, size_t len)
Definition Arduino.h:165
void stop()
Definition Arduino.h:164
Definition Arduino.h:56
virtual size_t write(const uint8_t *data, size_t len)
Definition Arduino.h:120
Definition Arduino.h:136
virtual int available()
Definition Arduino.h:139
A minimal, single-client HTTP server that streams audio (or any other data) to a browser or media pla...
Definition AudioServerT.h:80
std::string network
Definition AudioServerT.h:272
bool isChunked()
Determines if chunked transfer encoding is active.
Definition AudioServerT.h:233
void connectWiFi()
Definition AudioServerT.h:306
Stream * in
Definition AudioServerT.h:281
void setMaxOutputSize(size_t size)
Definition AudioServerT.h:239
size_t maxOutputSize()
Provides the defined total number of bytes that will be sent.
Definition AudioServerT.h:245
void endChunked()
Sends the terminating 0-length chunk when chunked transfer is active.
Definition AudioServerT.h:393
virtual void sendReplyContent()
Definition AudioServerT.h:366
void setConverter(BaseConverter *c)
defines a converter that will be used when the audio is rendered
Definition AudioServerT.h:210
std::string password
Definition AudioServerT.h:271
bool isClientConnected()
Checks if any client has connected.
Definition AudioServerT.h:219
void setChunked(bool flag)
Definition AudioServerT.h:230
bool begin(AudioServerDataCallback cb, const char *contentType)
Start the server. The data must be provided by a callback method.
Definition AudioServerT.h:130
void setContentType(const char *contentType)
Defines the content type (MIME type) of the data that will be sent to the client. Needs to be set bef...
Definition AudioServerT.h:150
bool begin()
Just starts the server.
Definition AudioServerT.h:141
bool copy()
Add this method to your loop Returns true while the client is connected. (The same functionality like...
Definition AudioServerT.h:160
Client * out_ptr()
Provides a pointer to the WiFiClient.
Definition AudioServerT.h:216
virtual void sendReplyHeader()
Definition AudioServerT.h:332
bool startServer()
Definition AudioServerT.h:297
StreamCopy copier
Definition AudioServerT.h:283
AudioServerT(const char *network, const char *password, int port=80)
Construct a new Audio WAV Server object.
Definition AudioServerT.h:98
AudioServerT(int port=80)
Construct a new Audio Server object We assume that the WiFi is already connected.
Definition AudioServerT.h:86
BaseConverter * converter_ptr
Definition AudioServerT.h:284
size_t sent
Definition AudioServerT.h:274
void end()
Ends the connection and resets the state.
Definition AudioServerT.h:248
Client client_obj
Definition AudioServerT.h:269
void setCopyBufferSize(int size)
Changes the copy buffer size.
Definition AudioServerT.h:225
void processClient()
Handle an new client connection and return the data.
Definition AudioServerT.h:400
bool doLoop()
Add this method to your loop Returns true while the client is connected.
Definition AudioServerT.h:166
size_t max_output_size
Definition AudioServerT.h:275
bool is_chunked
Definition AudioServerT.h:287
AudioServerDataCallback callback
Definition AudioServerT.h:280
const char * content_type
Definition AudioServerT.h:278
void setupServer(int port)
Definition AudioServerT.h:290
ChunkedPrint chunked_print
Definition AudioServerT.h:288
bool begin(Stream &in, const char *contentType)
Start the server. You need to be connected to WiFI before calling this method.
Definition AudioServerT.h:114
Stream & out()
Provides the output stream.
Definition AudioServerT.h:213
Server server
Definition AudioServerT.h:264
Abstract Base class for Converters A converter is processing the data in the indicated array.
Definition BaseConverter.h:25
Wraps a Print target and applies HTTP chunked transfer encoding framing (chunk-size in hex + CRLF + d...
Definition AudioServerT.h:25
size_t write(uint8_t c) override
Definition AudioServerT.h:32
size_t write(const uint8_t *data, size_t len) override
Definition AudioServerT.h:34
Print * p_out
Definition AudioServerT.h:51
void end()
Sends the terminating (zero length) chunk.
Definition AudioServerT.h:44
void begin(Print &out)
(re-)starts the chunked encoding for the indicated target
Definition AudioServerT.h:30
void begin()
(Re)starts the processing
Definition StreamCopy.h:56
bool resize(size_t len)
resizes the copy buffer
Definition StreamCopy.h:309
size_t copy()
Definition StreamCopy.h:100
void setCheckAvailableForWrite(bool flag)
Definition StreamCopy.h:295
bool begin(const char *ssid, const char *password)
Definition WiFiZephyr.h:51
wifi_status_t status()
Definition WiFiZephyr.h:85
const char * localIP()
Definition WiFiZephyr.h:90
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition LMSEchoCancellationStream.h:6
void delay(uint32_t ms)
Definition Arduino.h:255
@ WL_CONNECTED
Definition WiFiZephyr.h:30
static WiFiZephyr WiFi
Definition WiFiZephyr.h:230
void(* AudioServerDataCallback)(Print *out)
Callback which writes the sound data to the stream.
Definition AudioServerT.h:13