arduino-audio-tools
Loading...
Searching...
No Matches
AudioServerT.h
1#pragma once
2
3#include "AudioTools/AudioCodecs/CodecWAV.h"
4#include "AudioTools/CoreAudio/AudioStreams.h"
5#include "AudioTools/CoreAudio/StreamCopy.h"
6#include "AudioToolsConfig.h"
7
8namespace audio_tools {
9
11typedef void (*AudioServerDataCallback)(Print *out);
12
25typedef void (*AudioServerDataCallback)(Print *out);
26
36template <class Client, class Server>
38 public:
43 AudioServerT(int port = 80) {
44 // the client returns 0 for avialableForWrite()
45 copier.setCheckAvailableForWrite(false);
46 setupServer(port);
47 }
48
55 AudioServerT(const char *network, const char *password, int port = 80) {
56 this->network = (char *)network;
57 this->password = (char *)password;
58 // the client returns 0 for avialableForWrite()
59 copier.setCheckAvailableForWrite(false);
60 setupServer(port);
61 }
62
70 bool begin(Stream &in, const char *contentType) {
71 TRACED();
72 this->in = &in;
73 this->content_type = contentType;
74
75#ifdef USE_WIFI
76 connectWiFi();
77#endif
78 // start server
79 server.begin();
80 return true;
81 }
82
89 bool begin(AudioServerDataCallback cb, const char *contentType) {
90 TRACED();
91 this->in = nullptr;
92 this->callback = cb;
93 this->content_type = contentType;
94
95#ifdef USE_WIFI
96 connectWiFi();
97#endif
98
99 // start server
100 server.begin();
101 return true;
102 }
103
112 bool copy() { return doLoop(); }
113
118 bool doLoop() {
119 // LOGD("doLoop");
120 bool active = true;
121 if (!client_obj.connected()) {
122#if USE_SERVER_ACCEPT
123 client_obj = server.accept(); // listen for incoming clients
124#else
125 client_obj = server.available(); // listen for incoming clients
126#endif
127 processClient();
128 } else {
129 // We are connected: copy input from source to wav output
130 if (client_obj) {
131 if (callback == nullptr) {
132 LOGD("copy data...");
133 if (converter_ptr == nullptr) {
134 sent += copier.copy();
135 } else {
136 sent += copier.copy(*converter_ptr);
137 }
138
139 if (max_bytes > 0 && sent >= max_bytes) {
140 LOGI("range exhausted...");
141 client_obj.stop();
142 active = false;
143 }
144
145 // if we limit the size of the WAV the encoder gets automatically
146 // closed when all has been sent
147 if (!client_obj) {
148 LOGI("stop client...");
149 client_obj.stop();
150 active = false;
151 }
152 }
153 } else {
154 LOGI("client was not connected");
155 }
156 }
157 return active;
158 }
159
161 void setConverter(BaseConverter *c) { converter_ptr = c; }
162
164 Stream &out() { return client_obj; }
165
167 Client *out_ptr() { return &client_obj; }
168
170 bool isClientConnected() { return client_obj.connected(); }
171
173 void setCopyBufferSize(int size) { copier.resize(size); }
174
175 protected:
176 // WIFI
177#ifdef ESP32
178 Server server;
179#else
180 Server server{80};
181#endif
182 Client client_obj;
183 char *password = nullptr;
184 char *network = nullptr;
185 size_t max_bytes = 0;
186 size_t sent = 0;
187
188 // Content
189 const char *content_type = nullptr;
190 AudioServerDataCallback callback = nullptr;
191 Stream *in = nullptr;
192 StreamCopy copier;
193 BaseConverter *converter_ptr = nullptr;
194
195 void setupServer(int port) {
196 Server tmp(port);
197 server = tmp;
198 }
199
200#ifdef USE_WIFI
201 void connectWiFi() {
202 TRACED();
203 if (WiFi.status() != WL_CONNECTED && network != nullptr &&
204 password != nullptr) {
205 WiFi.begin(network, password);
206 while (WiFi.status() != WL_CONNECTED) {
207 Serial.print(".");
208 delay(500);
209 }
210#ifdef ESP32
211 WiFi.setSleep(false);
212#endif
213 Serial.println();
214 }
215 Serial.print("IP address: ");
216 Serial.println(WiFi.localIP());
217 }
218#endif
219
220 virtual void sendReplyHeader() {
221 TRACED();
222
223 // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
224 // and a content-type so the client knows what's coming, then a blank line:
225 const char *response;
226 if (max_bytes > 0) {
227 response = "HTTP/1.1 206 OK";
228 } else {
229 response = "HTTP/1.1 200 OK";
230 }
231 client_obj.println(response);
232 LOGI("%s", response);
233 if (content_type != nullptr) {
234 client_obj.print("Content-type:");
235 client_obj.println(content_type);
236 LOGI("Content-type: %s", content_type);
237 }
238 client_obj.println();
239 if (!client_obj.connected()) {
240 LOGE("connection was closed");
241 }
242 }
243
244 virtual void sendReplyContent() {
245 TRACED();
246 if (callback != nullptr) {
247 // provide data via Callback
248 LOGI("sendReply - calling callback");
249 callback(&client_obj);
250 client_obj.stop();
251 } else if (in != nullptr) {
252 // provide data for stream
253 LOGI("sendReply - Returning audio stream...");
254 copier.begin(client_obj, *in);
255 if (!client_obj.connected()) {
256 LOGE("connection was closed");
257 }
258 }
259 }
260
261 // Handle an new client connection and return the data
262 void processClient() {
263 // LOGD("processClient");
264 if (client_obj) { // if you get a client,
265 LOGI("New Client:"); // print a message out the serial port
266 String currentLine =
267 ""; // make a String to hold incoming data from the client
268 long firstbyte = 0;
269 long lastbyte = 0;
270 while (client_obj.connected()) { // loop while the client's connected
271 if (client_obj
272 .available()) { // if there's bytes to read from the client,
273 char c = client_obj.read(); // read a byte, then
274 if (c == '\n') { // if the byte is a newline character
275 LOGI("Request: %s", currentLine.c_str());
276 if (currentLine.startsWith(String("Range: bytes="))) {
277 int minuspos = currentLine.indexOf('-', 13);
278
279 // toInt returns 0 if it's an invalid conversion, so it's "safe"
280 firstbyte = currentLine.substring(13, minuspos).toInt();
281 lastbyte = currentLine.substring(minuspos + 1).toInt();
282 }
283 // if the current line is blank, you got two newline characters in a
284 // row. that's the end of the client HTTP request, so send a
285 // response:
286 if (currentLine.length() == 0) {
287 sendReplyHeader();
288 sendReplyContent();
289 max_bytes = lastbyte - firstbyte;
290 sent = 0;
291 // break out of the while loop:
292 break;
293 } else { // if you got a newline, then clear currentLine:
294 currentLine = "";
295 }
296 } else if (c != '\r') { // if you got anything else but a carriage
297 // return character,
298 currentLine += c; // add it to the end of the currentLine
299 }
300 }
301 }
302 }
303 }
304};
305
306} // namespace audio_tools
A simple Arduino Webserver which streams the result This class is based on the WiFiServer class....
Definition AudioServerT.h:37
void setConverter(BaseConverter *c)
defines a converter that will be used when the audio is rendered
Definition AudioServerT.h:161
bool isClientConnected()
Checks if any clinent has connnected.
Definition AudioServerT.h:170
bool begin(AudioServerDataCallback cb, const char *contentType)
Start the server. The data must be provided by a callback method.
Definition AudioServerT.h:89
bool copy()
Add this method to your loop Returns true while the client is connected. (The same functionality like...
Definition AudioServerT.h:112
Client * out_ptr()
Provides a pointer to the WiFiClient.
Definition AudioServerT.h:167
AudioServerT(const char *network, const char *password, int port=80)
Construct a new Audio WAV Server object.
Definition AudioServerT.h:55
AudioServerT(int port=80)
Construct a new Audio Server object We assume that the WiFi is already connected.
Definition AudioServerT.h:43
void setCopyBufferSize(int size)
Changes the copy buffer size.
Definition AudioServerT.h:173
bool doLoop()
Add this method to your loop Returns true while the client is connected.
Definition AudioServerT.h:118
bool begin(Stream &in, const char *contentType)
Start the server. You need to be connected to WiFI before calling this method.
Definition AudioServerT.h:70
Stream & out()
Provides the output stream.
Definition AudioServerT.h:164
Abstract Base class for Converters A converter is processing the data in the indicated array.
Definition BaseConverter.h:24
Definition NoArduino.h:169
Definition NoArduino.h:62
void resize(int len)
resizes the copy buffer
Definition StreamCopy.h:309
size_t copy()
Definition StreamCopy.h:100
void setCheckAvailableForWrite(bool flag)
Definition StreamCopy.h:295
Definition NoArduino.h:142
void(* AudioServerDataCallback)(Print *out)
Calback which writes the sound data to the stream.
Definition AudioServerT.h:11
StreamCopyT< uint8_t > StreamCopy
We provide the typeless StreamCopy.
Definition StreamCopy.h:425
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition AudioCodecsBase.h:10