-
Notifications
You must be signed in to change notification settings - Fork 226
/
Copy pathrtsp.cpp
156 lines (140 loc) · 5.62 KB
/
rtsp.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
// Library can be found here https://github.com/rjsachse/ESP32-RTSPServer.git or in Arduino library
// Initialize the RTSP server
/**
* @brief Initializes the RTSP server with the specified configuration.
*
* This method can be called with specific parameters, or the parameters
* can be set directly in the RTSPServer instance before calling begin().
* If any parameter is not explicitly set, the method uses default values.
*
* @param transport The transport type. Default is VIDEO_AND_SUBTITLES. Options are (VIDEO_ONLY, AUDIO_ONLY, VIDEO_AND_AUDIO, VIDEO_AND_SUBTITLES, AUDIO_AND_SUBTITLES, VIDEO_AUDIO_SUBTITLES).
* @param rtspPort The RTSP port to use. Default is 554.
* @param sampleRate The sample rate for audio streaming. Default is 0 must pass or set if using audio.
* @param port1 The first port (used for video, audio or subtitles depending on transport). Default is 5430.
* @param port2 The second port (used for audio or subtitles depending on transport). Default is 5432.
* @param port3 The third port (used for subtitles). Default is 5434.
* @param rtpIp The IP address for RTP multicast streaming. Default is IPAddress(239, 255, 0, 1).
* @param rtpTTL The TTL value for RTP multicast packets. Default is 64.
* @return true if initialization is successful, false otherwise.
*/
// RjSachse 2025
#include "appGlobals.h"
#if INCLUDE_RTSP
#include <ESP32-RTSPServer.h>
RTSPServer rtspServer;
bool rtspVideo;
bool rtspAudio;
bool rtspSubtitles;
int rtspPort;
uint16_t rtpVideoPort;
uint16_t rtpAudioPort;
uint16_t rtpSubtitlesPort;
char RTP_ip [MAX_IP_LEN];
uint8_t rtpTTL;
IPAddress rtpIp;
char transportStr[30]; // Adjust the size as needed
RTSPServer::TransportType determineTransportType() {
if (rtspVideo && rtspAudio && rtspSubtitles) {
strcpy(transportStr, "s: Video, Audio & Subtitles");
return RTSPServer::VIDEO_AUDIO_SUBTITLES;
} else if (rtspVideo && rtspAudio) {
strcpy(transportStr, "s: Video & Audio");
return RTSPServer::VIDEO_AND_AUDIO;
} else if (rtspVideo && rtspSubtitles) {
strcpy(transportStr, "s: Video & Subtitles");
return RTSPServer::VIDEO_AND_SUBTITLES;
} else if (rtspAudio && rtspSubtitles) {
strcpy(transportStr, "s: Audio & Subtitles");
return RTSPServer::AUDIO_AND_SUBTITLES;
} else if (rtspVideo) {
strcpy(transportStr, ": Video");
return RTSPServer::VIDEO_ONLY;
} else if (rtspAudio) {
strcpy(transportStr, ": Audio");
return RTSPServer::AUDIO_ONLY;
} else if (rtspSubtitles) {
strcpy(transportStr, ": Subtitles");
return RTSPServer::SUBTITLES_ONLY;
} else {
strcpy(transportStr, ": None!");
return RTSPServer::NONE;
}
}
static void sendRTSPVideo(void* p) {
// Send jpeg frames via RTSP at current frame rate
uint8_t taskNum = 1;
streamBufferSize[taskNum] = 0;
while (true) {
if (xSemaphoreTake(frameSemaphore[taskNum], pdMS_TO_TICKS(MAX_FRAME_WAIT)) == pdTRUE) {
if (streamBufferSize[taskNum] && rtspServer.readyToSendFrame()) {
// use frame stored by processFrame()
rtspServer.sendRTSPFrame(streamBuffer[taskNum], streamBufferSize[taskNum], quality, frameData[fsizePtr].frameWidth, frameData[fsizePtr].frameHeight);
}
}
streamBufferSize[taskNum] = 0;
}
vTaskDelete(NULL);
}
static void sendRTSPAudio(void* p) {
#if INCLUDE_AUDIO
// send audio chunks via RTSP
audioBytes = 0;
while (true) {
if (micGain && audioBytes && rtspServer.readyToSendAudio()) {
rtspServer.sendRTSPAudio((int16_t*)audioBuffer, audioBytes);
audioBytes = 0;
}
delay(20);
}
#endif
vTaskDelete(NULL);
}
void sendRTSPSubtitles(void* arg) {
char data[100];
time_t currEpoch = getEpoch();
size_t len = strftime(data, 12, "%H:%M:%S ", localtime(&currEpoch));
len += sprintf(data + len, "FPS: %lu", rtspServer.rtpFps);
#if INCLUDE_TELEM
// add telemetry data
if (teleUse) {
storeSensorData(true);
if (srtBytes) len += sprintf(data + len, "%s", (const char*)srtBuffer);
srtBytes = 0;
}
#endif
rtspServer.sendRTSPSubtitles(data, len);
}
static void startRTSPSubtitles(void* arg) {
rtspServer.startSubtitlesTimer(sendRTSPSubtitles); // 1-second period
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
vTaskDelete(NULL); // not reached
}
void prepRTSP() {
RTSPServer::TransportType transport = determineTransportType();
rtpIp.fromString(RTP_ip);
rtspServer.transport = transport;
#if INCLUDE_AUDIO
rtspServer.sampleRate = SAMPLE_RATE;
#endif
rtspServer.rtspPort = rtspPort;
rtspServer.rtpVideoPort = rtpVideoPort;
rtspServer.rtpAudioPort = rtpAudioPort;
rtspServer.rtpSubtitlesPort = rtpSubtitlesPort;
rtspServer.rtpIp = rtpIp;
rtspServer.rtpTTL = rtpTTL;
if (transport != RTSPServer::NONE) {
if (rtspServer.init()) {
LOG_INF("RTSP server started successfully with transport%s", transportStr);
LOG_INF("Connect to: rtsp://%s:%d", WiFi.localIP().toString().c_str(), rtspServer.rtspPort);
// start RTSP tasks, need bigger stack for video
if (rtspVideo) xTaskCreate(sendRTSPVideo, "sendRTSPVideo", 1024 * 5, NULL, SUSTAIN_PRI, &sustainHandle[1]);
if (rtspAudio) xTaskCreate(sendRTSPAudio, "sendRTSPAudio", 1024 * 4, NULL, SUSTAIN_PRI, &sustainHandle[2]);
if (rtspSubtitles) xTaskCreate(startRTSPSubtitles, "startRTSPSubtitles", 1024 * 1, NULL, SUSTAIN_PRI, &sustainHandle[3]);
} else {
LOG_ERR("Failed to start RTSP server");
}
} else {
LOG_WRN("RTSP server not started, no transport selected");
}
}
#endif