arduino-audio-tools
Loading...
Searching...
No Matches
RTSPServer.h
1/*
2 * Author: Phil Schatzmann
3 *
4 * Based on Micro-RTSP library:
5 * https://github.com/geeksville/Micro-RTSP
6 * https://github.com/Tomp0801/Micro-RTSP-Audio
7 *
8 */
9
10#pragma once
11#include "RTSPSession.h"
12#ifdef ESP32
13#include <WiFi.h>
14#include <esp_wifi.h>
15#include "AudioTools/Concurrency/RTOS.h"
16#endif
17
18namespace audio_tools {
19
46template <typename Platform>
48 public:
50
70 RTSPServer(streamer_t& streamer, int port = 8554, int core = 1) {
71 this->streamer = &streamer;
72 this->port = port;
73 this->core = core;
74 // Create tasks with specified core
75 serverTask.create("RTSPServerThread", 10000, 5, core);
76 sessionTask.create("RTSPSessionTask", 8000, 8, core);
77 }
78
83
99 bool begin(const char* ssid, const char* password) {
100#ifdef ESP32
101 // Start Wifi
102 WiFi.begin(ssid, password);
103 while (WiFi.status() != WL_CONNECTED) {
104 delay(500);
105 Serial.print(".");
106 }
107
108 esp_wifi_set_ps(WIFI_PS_NONE);
109#endif
110
111 Serial.println();
112 Serial.print("connect to rtsp://");
113 Serial.print(WiFi.localIP());
114 Serial.print(":");
115 Serial.println(port);
116 Serial.println();
117 return begin();
118 }
119
121 bool begin() {
122 bool ok = runAsync();
123 if (!ok) {
124 LOGE("Couldn't start RTSP server");
125 }
126 return ok;
127 }
128
129 audio_tools::Task& getTaskHandle() { return serverTask; };
130
131 int clientCount() { return client_count;}
132
133 operator bool() { return client_count > 0;}
134
135 protected:
136 int port; // port that the RTSP Server listens on
137 int core; // the core number the RTSP runs on (platform-specific)
138 audio_tools::Task serverTask{"RTSPServerThread", 15000, 5, core};
139 audio_tools::Task sessionTask{"RTSPSessionTask", 15000, 8, core};
140 typename Platform::TcpServerType* server = nullptr; // platform server
141 typename Platform::TcpClientType client; // RTSP client connection (value)
142 int client_count = 0; // number of connected clients
143 streamer_t* streamer = nullptr; // RTSPAudioStreamer object that acts as a
144 // source for data streams
145
160 bool runAsync() {
161 LOGI("Running RTSP server on port %d", port);
162 streamer->initAudioSource();
163 if (server == nullptr) {
164 server = Platform::createServer(port);
165 LOGI("RTSP server started on port %d", port);
166 }
167 if (!serverTask.begin([this]() { serverThreadLoop(); })) {
168 LOGE("Couldn't start server thread");
169 return false;
170 }
171 return true;
172 }
173
186 unsigned long lastCheck = millis();
187
188 LOGD("Server thread listening... (numClients: %d)", client_count);
189
190 // only allow one client at a time
191 if (client_count == 0) {
192 auto newClient = Platform::getAvailableClient(server);
193 if (newClient.connected()) {
194 client = newClient; // copy/move assign
195 LOGI("Client connected");
196 if (!sessionTask.begin([this]() { sessionThreadLoop(); })) {
197 LOGE("Couldn't start sessionThread");
198 Platform::closeSocket(&client);
199 } else {
200 client_count++;
201 LOGI("Number of clients: %d", client_count);
202 }
203 }
204 } else {
205 LOGD("Waiting for current session to end (numClients: %d)", client_count);
206 }
207 int time = 200 - (millis() - lastCheck);
208 if (time < 0) time = 0;
209 delay(time);
210 }
211
215 void stop() {
216 LOGI("Stopping RTSP server");
217
218 // Stop tasks
219 sessionTask.end();
220 serverTask.end();
221
222 // Close sockets
223 if (server) {
224 // server->stop(); // not supported by EthernetServer
225 delete server;
226 server = nullptr;
227 }
228
229 client_count = 0;
230 LOGI("RTSP server stopped");
231 }
232
247 typename Platform::TcpClientType* s = &client;
248 unsigned long lastCheck = millis();
249
250 // TODO check if everything is ok to go
251 LOGD("RTSP Task running");
252
253 // our threads RTSP session and state
254 RtspSession<Platform>* rtsp = new RtspSession<Platform>(*s, *streamer);
255 assert(rtsp != nullptr);
256
257 LOGI("Session ready");
258
259 while (rtsp->isSessionOpen()) {
260 uint32_t timeout = 30;
261 if (!rtsp->handleRequests(timeout)) {
262 LOGI("Request handling timed out or no data yet");
263 } else {
264 LOGD("Request handling successful");
265 }
266
267 int time = timeout - (millis() - lastCheck);
268 if (time < 0) time = 0;
269 delay(time);
270 }
271
272 LOGI("Session loop exited - session no longer open");
273
274 // cleanup when session ends
275 LOGI("sessionThread stopped, cleaning up");
276 delete rtsp;
277
278 // Clean up client socket
279 if (client.connected()) {
280 Platform::closeSocket(&client);
281 }
282
283 // Add delay to ensure complete cleanup before accepting new connections
284 delay(500);
285
286 client_count--;
287 LOGI("Session cleaned up: (numClients: %d)", client_count);
288
289 // end the task - this should be the last thing we do
290 sessionTask.end();
291 }
292};
293
294} // namespace audio_tools
RTSPAudioStreamerBase - Core RTP Audio Streaming Engine.
Definition RTSPAudioStreamer.h:50
RTSP Server - Multi-client Audio Streaming Server.
Definition RTSPServer.h:47
bool begin(const char *ssid, const char *password)
Initialize WiFi and start RTSP server.
Definition RTSPServer.h:99
bool runAsync()
Start RTSP server asynchronously.
Definition RTSPServer.h:160
~RTSPServer()
Destructor - ensures proper cleanup of server resources.
Definition RTSPServer.h:82
bool begin()
Definition RTSPServer.h:121
void serverThreadLoop()
Main server thread loop - listens for RTSP client connections.
Definition RTSPServer.h:185
void stop()
Stop the RTSP server and cleanup resources.
Definition RTSPServer.h:215
void sessionThreadLoop()
Client session thread loop - handles RTSP protocol for individual clients.
Definition RTSPServer.h:246
RTSPServer(streamer_t &streamer, int port=8554, int core=1)
Construct RTSP server.
Definition RTSPServer.h:70
RTSP Session Handler - Individual Client Protocol Management.
Definition RTSPSession.h:78
bool handleRequests(uint32_t readTimeoutMs)
Process incoming RTSP requests from the client.
Definition RTSPSession.h:149
FreeRTOS task.
Definition Task.h:21
bool create(const char *name, int stackSize, int priority=1, int core=-1)
If you used the empty constructor, you need to call create!
Definition Task.h:32
void end()
suspends the task
Definition Task.h:65
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition AudioCodecsBase.h:10
uint32_t millis()
Returns the milliseconds since the start.
Definition Time.h:12