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 } else {
196 LOGI("client was not connected");
197 }
198 }
199 return active;
200 }
201
204
206 Stream &out() { return client_obj; }
207
209 Client *out_ptr() { return &client_obj; }
210
213
215 operator bool() { return client_obj.connected(); }
216
218 void setCopyBufferSize(int size) { copier.resize(size); }
219
223 void setChunked(bool flag) { is_chunked = flag; }
224
226 bool isChunked() { return is_chunked; }
227
232 void setMaxOutputSize(size_t size) {
233 max_output_size = size;
234 is_chunked = (size == 0);
235 }
236
238 size_t maxOutputSize() { return max_output_size; }
239
241 void end() {
242 if (client_obj) {
243 endChunked();
245 }
246 // reset the state
247 callback = nullptr;
248 in = nullptr;
249 converter_ptr = nullptr;
250 sent = 0;
251 }
252
253
254 protected:
255 // WIFI
256#ifdef ESP32
257 Server server;
258#else
259 Server server{80};
260#endif
261
263
264 std::string password;
265 std::string network;
266
267 size_t sent = 0;
268 size_t max_output_size = 0;
269
270 // Content
271 const char *content_type = nullptr;
272
274 Stream *in = nullptr;
275
278
279 // no size defined (default) => fall back to chunked transfer encoding
280 bool is_chunked = true;
282
283 void setupServer(int port) {
284 Server tmp(port);
285 server = tmp;
286 }
287
290 bool startServer() {
291#ifdef USE_WIFI
292 connectWiFi();
293#endif
294 server.begin();
295 return true;
296 }
297
298#ifdef USE_WIFI
299 void connectWiFi() {
300 TRACED();
301
302 if (WiFi.status() != WL_CONNECTED &&
303 !network.empty() &&
304 !password.empty()) {
305
306 WiFi.begin(network.c_str(), password.c_str());
307
308 while (WiFi.status() != WL_CONNECTED) {
309 Serial.print(".");
310 delay(500);
311 }
312
313#ifdef ESP32
314 WiFi.setSleep(false);
315#endif
316
317 Serial.println();
318 }
319
320 Serial.print("IP address: ");
321 Serial.println(WiFi.localIP());
322 }
323#endif
324
325 virtual void sendReplyHeader() {
326 TRACED();
327
328 // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
329 // and a content-type so the client knows what's coming, then a blank line:
330 const char *response = "HTTP/1.1 200 OK";
331 client_obj.println(response);
332 LOGI("%s", response);
333
334 if (content_type != nullptr) {
335 client_obj.print("Content-type:");
336 client_obj.println(content_type);
337 LOGI("Content-type: %s", content_type);
338 }
339
340 // for firefox to play
341 client_obj.println("Content-Disposition: inline");
342
343 if (max_output_size > 0) {
344 client_obj.print("Content-Length:");
345 client_obj.println((unsigned long)max_output_size);
346 LOGI("Content-Length: %lu", (unsigned long)max_output_size);
347 } else if (is_chunked) {
348 client_obj.println("Transfer-Encoding: chunked");
349 LOGI("Transfer-Encoding: chunked");
350 }
351
352 client_obj.println();
353
354 if (!client_obj.connected()) {
355 LOGE("connection was closed");
356 }
357 }
358
359 virtual void sendReplyContent() {
360 TRACED();
361
362 Print *p_out = &client_obj;
363 if (is_chunked) {
365 p_out = &chunked_print;
366 }
367
368 if (callback != nullptr) {
369 // provide data via Callback
370 LOGI("sendReply - calling callback");
371 callback(p_out);
372 endChunked();
374 } else if (in != nullptr) {
375 // provide data for stream
376 LOGI("sendReply - Returning audio stream...");
377 copier.begin(*p_out, *in);
378
379 if (!client_obj.connected()) {
380 LOGE("connection was closed");
381 }
382 }
383 }
384
386 void endChunked() {
387 if (is_chunked) {
388 LOGI("endChunked");
390 }
391 }
392
397 // LOGD("processClient");
398 if (client_obj) {
399 LOGI("New Client:");
400
401 std::string currentLine;
402 currentLine.reserve(128);
403
404 while (client_obj.connected()) {
405 if (client_obj.available()) {
406 char c = client_obj.read();
407
408 if (c == '\n') {
409 LOGI("Request: %s", currentLine.c_str());
410
411 // if the current line is blank, you got two newline characters in a
412 // row. that's the end of the client HTTP request, so send a response:
413 if (currentLine.length() == 0) {
416
417 sent = 0;
418
419 break;
420 } else {
421 currentLine = "";
422 }
423 } else if (c != '\r') {
424 currentLine += c;
425 }
426 }
427 }
428 }
429 }
430};
431
432} // 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:265
bool isChunked()
Determines if chunked transfer encoding is active.
Definition AudioServerT.h:226
void connectWiFi()
Definition AudioServerT.h:299
Stream * in
Definition AudioServerT.h:274
void setMaxOutputSize(size_t size)
Definition AudioServerT.h:232
size_t maxOutputSize()
Provides the defined total number of bytes that will be sent.
Definition AudioServerT.h:238
void endChunked()
Sends the terminating 0-length chunk when chunked transfer is active.
Definition AudioServerT.h:386
virtual void sendReplyContent()
Definition AudioServerT.h:359
void setConverter(BaseConverter *c)
defines a converter that will be used when the audio is rendered
Definition AudioServerT.h:203
std::string password
Definition AudioServerT.h:264
bool isClientConnected()
Checks if any client has connected.
Definition AudioServerT.h:212
void setChunked(bool flag)
Definition AudioServerT.h:223
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:209
virtual void sendReplyHeader()
Definition AudioServerT.h:325
bool startServer()
Definition AudioServerT.h:290
StreamCopy copier
Definition AudioServerT.h:276
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:277
size_t sent
Definition AudioServerT.h:267
void end()
Ends the connection and resets the state.
Definition AudioServerT.h:241
Client client_obj
Definition AudioServerT.h:262
void setCopyBufferSize(int size)
Changes the copy buffer size.
Definition AudioServerT.h:218
void processClient()
Handle an new client connection and return the data.
Definition AudioServerT.h:396
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:268
bool is_chunked
Definition AudioServerT.h:280
AudioServerDataCallback callback
Definition AudioServerT.h:273
const char * content_type
Definition AudioServerT.h:271
void setupServer(int port)
Definition AudioServerT.h:283
ChunkedPrint chunked_print
Definition AudioServerT.h:281
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:206
Server server
Definition AudioServerT.h:257
Abstract Base class for Converters A converter is processing the data in the indicated array.
Definition BaseConverter.h:26
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:259
@ 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