arduino-audio-tools
Loading...
Searching...
No Matches
RTSPAudioStreamer.h
1/*
2 * Author: Phil Schatzmann
3 *
4 * Based on Micro-RTSP library:
5 * https://github.com/Tomp0801/Micro-RTSP-Audio
6 * https://github.com/geeksville/Micro-RTSP
7 *
8 */
9
10#pragma once
11
12#include <stdio.h>
13
14#ifdef __linux__
15#include "AudioTools/Concurrency/Desktop.h"
16#else
17#include "AudioTools/Concurrency/RTOS.h"
18#endif
19#include "AudioTools/CoreAudio/AudioBasic/Collections/Vector.h"
20#include "AudioTools/CoreAudio/AudioTimer.h"
21#include "IAudioSource.h"
22#include "RTSPPlatform.h"
23
24namespace audio_tools {
25
49template <typename Platform>
51 public:
64 LOGD("Creating RTSP Audio streamer base");
65 m_RtpServerPort = 0;
66 m_RtcpServerPort = 0;
67
68 m_SequenceNumber = 0;
69 m_Timestamp = 0;
70 m_SendIdx = 0;
71
72 m_RtpSocket = Platform::NULL_UDP_SOCKET;
73 m_RtcpSocket = Platform::NULL_UDP_SOCKET;
74
75 m_prevMsec = 0;
76
77 m_udpRefCount = 0;
78
79 m_useTcpInterleaved = false;
80 m_RtspTcpSocket = Platform::NULL_TCP_SOCKET;
81 m_TcpRtpChannel = 0;
82 m_TcpRtcpChannel = 1;
83
84 m_lastSamplesSent = 0;
85 }
86
104
114 // mRtpBuf is automatically managed by Vector
115 }
116
130 virtual void setAudioSource(IAudioSource *source) {
131 m_audioSource = source;
133 LOGI("RTSP Audio streamer created. Fragment size: %i bytes",
134 m_fragmentSize);
135 }
136
151 LOGI("initAudioSource");
152 if (getAudioSource() == nullptr) {
153 LOGE("audio_source is null");
154 return false;
155 }
157 m_payloadType = fmt.rtpPayloadType();
158 m_fragmentSize = fmt.fragmentSize();
159 m_timer_period_us = fmt.timerPeriodUs();
160 LOGI("m_fragmentSize (bytes): %d", m_fragmentSize);
161 return true;
162 }
163
182 bool initUdpTransport(IPAddress aClientIP, uint16_t aClientPort) {
183 m_ClientIP = aClientIP;
184 m_ClientPort = aClientPort;
185
186 m_SequenceNumber = random(65536);
187
188 if (m_udpRefCount != 0) {
189 ++m_udpRefCount;
190 return true;
191 }
192
193 for (u_short P = 6970; P < 0xFFFE; P += 2) {
194 m_RtpSocket = Platform::createUdpSocket(P);
195 if (m_RtpSocket) { // Rtp socket was bound successfully. Lets try to bind
196 // the consecutive Rtsp socket
197 m_RtcpSocket = Platform::createUdpSocket(P + 1);
198 if (m_RtcpSocket) {
199 m_RtpServerPort = P;
200 m_RtcpServerPort = P + 1;
201 break;
202 } else {
203 Platform::closeUdpSocket(m_RtpSocket);
204 Platform::closeUdpSocket(m_RtcpSocket);
205 };
206 }
207 };
208 ++m_udpRefCount;
209
210 LOGI("RTP Streamer set up with client IP %s and client Port %i",
211 m_ClientIP.toString().c_str(), m_ClientPort);
212
213 // If client IP is unknown (0.0.0.0), try to learn it from an inbound UDP packet
214 tryLearnClientFromUdp(true);
215
216 return true;
217 }
218
230 void initTcpInterleavedTransport(typename Platform::TcpClientType *tcpSock,
231 int rtpChannel, int rtcpChannel) {
232 m_RtspTcpSocket = tcpSock;
233 m_TcpRtpChannel = rtpChannel;
234 m_TcpRtcpChannel = rtcpChannel;
235 m_useTcpInterleaved = true;
236 m_SequenceNumber = random(65536);
237 LOGI("Using RTP over RTSP TCP interleaved: ch=%d/%d", rtpChannel,
238 rtcpChannel);
239 }
240
253 --m_udpRefCount;
254 if (m_udpRefCount == 0) {
255 m_RtpServerPort = 0;
256 m_RtcpServerPort = 0;
257 Platform::closeUdpSocket(m_RtpSocket);
258 Platform::closeUdpSocket(m_RtcpSocket);
259
260 m_RtpSocket = Platform::NULL_UDP_SOCKET;
261 m_RtcpSocket = Platform::NULL_UDP_SOCKET;
262 }
263 }
264
286 // check buffer
287 if (mRtpBuf.size() == 0) {
288 LOGE("mRtpBuf is empty");
289 return -1;
290 }
291
292 // append data to header
293 if (m_audioSource == nullptr) {
294 LOGE("No audio source provided");
295 return -1;
296 }
297
298 // unsigned char * dataBuf = &mRtpBuf[m_fragmentSize];
299 if (m_fragmentSize + HEADER_SIZE >= STREAMING_BUFFER_SIZE) {
300 LOGE(
301 "STREAMIN_BUFFER_SIZE too small for the sampling rate: increase to "
302 "%d",
303 m_fragmentSize + HEADER_SIZE);
304 return -1;
305 }
306
307 // Generic path (PCM, G711, etc.)
308 memset(mRtpBuf.data(), 0, STREAMING_BUFFER_SIZE);
309 buildRtpHeader();
310
311 unsigned char *dataBuf = &mRtpBuf[HEADER_SIZE];
312 int header_len = m_audioSource->getFormat().readHeader(dataBuf);
313 int maxPayload = STREAMING_BUFFER_SIZE - HEADER_SIZE - header_len;
314 dataBuf += header_len;
315
316 int toRead = m_fragmentSize;
317 if (toRead > maxPayload) {
318 LOGW("Fragment exceeds payload capacity (%d > %d); clamping", toRead, maxPayload);
319 toRead = maxPayload;
320 }
321 int bytesRead = m_audioSource->readBytes((void *)dataBuf, toRead);
322 LOGI("Read %d bytes from audio source", bytesRead);
323 int bytesNet = m_audioSource->getFormat().convert(dataBuf, bytesRead);
324
325 // Compute samples sent for timestamp increment
326 m_lastSamplesSent = m_audioSource->getFormat().timestampIncrement();
327 m_SequenceNumber++;
328 sendOut(HEADER_SIZE + bytesNet + header_len);
329 return bytesNet;
330 }
331
344 virtual void start() {
345 LOGI("Starting audio source (base)");
346
347 if (mRtpBuf.size() == 0) {
348 mRtpBuf.resize(STREAMING_BUFFER_SIZE + 1);
349 }
350
351 if (m_audioSource != nullptr) {
353 m_audioSource->start();
354 LOGI("Audio source started - ready for manual streaming");
355 } else {
356 LOGE("No streaming source");
357 }
358 }
359
372 virtual void stop() {
373 LOGI("Stopping audio source (base)");
374
375 if (m_audioSource != nullptr) {
376 m_audioSource->stop();
377 }
378
379 LOGI("Audio source stopped");
380 }
381
387 u_short getRtpServerPort() { return m_RtpServerPort; }
388
394 u_short getRtcpServerPort() { return m_RtcpServerPort; }
395
401 IAudioSource *getAudioSource() { return m_audioSource; }
402
408 uint32_t getTimerPeriodUs() const { return m_timer_period_us; }
409
415 uint32_t getTimerPeriodMs() const { return m_timer_period_us / 1000; }
416
421 uint16_t currentSeq() const { return m_SequenceNumber; }
422
427 uint32_t currentRtpTimestamp() const { return m_Timestamp; }
428
432 uint32_t currentSsrc() const { return m_Ssrc; }
433
446 if (m_audioSource == nullptr) {
447 return false;
448 }
449
450 uint32_t newPeriod = m_audioSource->getFormat().timerPeriodUs();
451 if (newPeriod != m_timer_period_us && newPeriod > 0) {
452 LOGI("Timer period changed from %u us to %u us",
453 (unsigned)m_timer_period_us, (unsigned)newPeriod);
454 m_timer_period_us = newPeriod;
455 return true;
456 }
457 return false;
458 }
459
477 static void timerCallback(void *audioStreamerObj) {
478 LOGD("timerCallback");
479 if (audioStreamerObj == nullptr) {
480 LOGE("audioStreamerObj is null");
481 return;
482 };
484 (RTSPAudioStreamerBase<Platform> *)audioStreamerObj;
485 unsigned long start, stop;
486
487 start = micros();
488
489 int bytes = streamer->sendRtpPacketDirect();
490
491 if (bytes < 0) {
492 LOGW("Direct sending of RTP stream failed");
493 } else if (bytes > 0) {
494 uint32_t inc = streamer->computeTimestampIncrement(bytes);
495 streamer->m_Timestamp += inc;
496 LOGD("%i samples (ts inc) sent; timestamp: %u", inc,
497 (unsigned)streamer->m_Timestamp);
498 }
499
500 stop = micros();
501 if (stop - start > streamer->m_timer_period_us) {
502 LOGW("RTP Stream can't keep up (took %lu us, %d is max)!", stop - start,
503 streamer->m_timer_period_us);
504 }
505 }
506
507 protected:
508 const int STREAMING_BUFFER_SIZE = 1024 * 3;
510
511 IAudioSource *m_audioSource = nullptr;
512 int m_fragmentSize = 0; // changed from samples to bytes !
513 int m_timer_period_us = 20000;
514 const int HEADER_SIZE = 12; // size of the RTP header
515 volatile bool m_timer_restart_needed =
516 false; // Flag for dynamic timer restart
517
518 typename Platform::UdpSocketType
519 *m_RtpSocket; // RTP socket for streaming RTP packets to client
520 typename Platform::UdpSocketType
521 *m_RtcpSocket; // RTCP socket for sending/receiving RTCP packages
522
523 uint16_t m_RtpServerPort; // RTP sender port on server
524 uint16_t m_RtcpServerPort; // RTCP sender port on server
525
526 u_short m_SequenceNumber;
527 uint32_t m_Timestamp;
528 int m_SendIdx;
529
530 IPAddress m_ClientIP;
531 uint16_t m_ClientPort;
532 uint32_t m_prevMsec;
533
534 int m_udpRefCount;
535
536 // TCP interleaved transport
537 bool m_useTcpInterleaved;
538 typename Platform::TcpClientType *m_RtspTcpSocket;
539 int m_TcpRtpChannel;
540 int m_TcpRtcpChannel;
541
542 int m_payloadType = 96;
543 int m_lastSamplesSent = 0;
544 uint32_t m_Ssrc = 0x13F97E67; // default fixed SSRC
545 // MP3 packetization carry buffer to ensure whole-frame packets
547 int mMp3CarryLen = 0;
548
561 inline uint32_t computeTimestampIncrement(int bytesSent) {
562 // Prefer exact samples sent (set by sender) if available
563 int samples = 0;
564 if (m_lastSamplesSent > 0) {
565 samples = m_lastSamplesSent;
566 } else if (m_audioSource) {
567 samples = m_audioSource->getFormat().timestampIncrement();
568 } else {
569 samples = bytesSent / 2; // crude fallback
570 }
571 return (uint32_t)samples;
572 }
573
574 inline void buildRtpHeader() {
575 mRtpBuf[0] = 0x80; // V=2
576 mRtpBuf[1] = (uint8_t)(m_payloadType & 0x7F);
577 if (m_payloadType == 14) {
578 // Set Marker bit on each complete MP3 frame packet
579 mRtpBuf[1] |= 0x80;
580 }
581 mRtpBuf[2] = (uint8_t)((m_SequenceNumber >> 8) & 0xFF);
582 mRtpBuf[3] = (uint8_t)(m_SequenceNumber & 0xFF);
583 mRtpBuf[4] = (uint8_t)((m_Timestamp >> 24) & 0xFF);
584 mRtpBuf[5] = (uint8_t)((m_Timestamp >> 16) & 0xFF);
585 mRtpBuf[6] = (uint8_t)((m_Timestamp >> 8) & 0xFF);
586 mRtpBuf[7] = (uint8_t)(m_Timestamp & 0xFF);
587 // SSRC
588 mRtpBuf[8] = (uint8_t)((m_Ssrc >> 24) & 0xFF);
589 mRtpBuf[9] = (uint8_t)((m_Ssrc >> 16) & 0xFF);
590 mRtpBuf[10] = (uint8_t)((m_Ssrc >> 8) & 0xFF);
591 mRtpBuf[11] = (uint8_t)(m_Ssrc & 0xFF);
592 }
593
594 inline void sendOut(uint16_t totalLen) {
595 if (m_useTcpInterleaved && m_RtspTcpSocket != Platform::NULL_TCP_SOCKET) {
596 LOGD("Sending TCP: %d", totalLen);
597 uint8_t hdr[4];
598 hdr[0] = 0x24; // '$'
599 hdr[1] = (uint8_t)m_TcpRtpChannel;
600 hdr[2] = (uint8_t)((totalLen >> 8) & 0xFF);
601 hdr[3] = (uint8_t)(totalLen & 0xFF);
602 Platform::sendSocket(m_RtspTcpSocket, hdr, sizeof(hdr));
603 Platform::sendSocket(m_RtspTcpSocket, mRtpBuf.data(), totalLen);
604 } else {
605 // If client IP is still unknown, attempt to learn it just-in-time
606 tryLearnClientFromUdp(false);
607 LOGI("Sending UDP: %d bytes (to %s:%d)", totalLen,
608 m_ClientIP.toString().c_str(), m_ClientPort);
609 Platform::sendUdpSocket(m_RtpSocket, mRtpBuf.data(), totalLen, m_ClientIP,
610 m_ClientPort);
611 }
612 }
613
614 inline void tryLearnClientFromUdp(bool warnIfNone) {
615 if (m_ClientIP == IPAddress(0, 0, 0, 0) && m_RtpSocket) {
616 int avail = m_RtpSocket->parsePacket();
617 if (avail > 0) {
618 IPAddress learnedIp = m_RtpSocket->remoteIP();
619 uint16_t learnedPort = m_RtpSocket->remotePort();
620 if (learnedIp != IPAddress(0, 0, 0, 0)) {
621 m_ClientIP = learnedIp;
622 if (m_ClientPort == 0) m_ClientPort = learnedPort;
623 LOGI("RTP learned client via UDP: %s:%u",
624 m_ClientIP.toString().c_str(), (unsigned)m_ClientPort);
625 }
626 } else if (warnIfNone) {
627 LOGW("Client IP unknown (0.0.0.0) and no inbound UDP yet");
628 }
629 }
630 }
631};
632
649template <typename Platform>
650class RTSPAudioStreamer : public RTSPAudioStreamerBase<Platform> {
651 public:
662 LOGD("Creating RTSP Audio streamer with timer");
663
664 // Setup timer callback for RTP streaming
665 rtpTimer.setCallbackParameter(this);
666
667 // CRITICAL FIX: Force timer to run in task context, not ISR context
668 // ISR context (ESP_TIMER_ISR) has severe limitations that cause
669 // LoadProhibited crashes Task context (ESP_TIMER_TASK) allows full object
670 // access and FreeRTOS calls
671 rtpTimer.setIsSave(
672 true); // true = use TimerCallbackInThread (ESP_TIMER_TASK)
673 LOGI("RTSPAudioStreamer: Timer set to safe task mode (ESP_TIMER_TASK)");
674 }
675
687 this->setAudioSource(&source);
688 }
689
703 void start() override {
704 LOGI("Starting RTP Stream with timer");
705
706 // Call base class start to initialize audio source and buffer
708
709 if (this->m_audioSource != nullptr) {
710 // Start timer with period in microseconds using specialized callback
712 this->m_timer_period_us, audio_tools::US)) {
713 LOGE("Could not start timer");
714 }
715 LOGI("timer: %u us", (unsigned)this->m_timer_period_us);
716#ifdef ESP32
717 LOGI("Free heap size: %i KB", esp_get_free_heap_size() / 1000);
718#endif
719 }
720 }
721
730 void updateTimer() {
731 if (this->checkTimerPeriodChange()) {
732 LOGI("Updating timer period to %u us", (unsigned)this->m_timer_period_us);
733 rtpTimer.begin(this->m_timer_period_us, audio_tools::US);
734 }
735 }
736
749 void stop() override {
750 LOGI("Stopping RTP Stream with timer");
751
752 // Stop timer first to prevent callbacks during cleanup
753 rtpTimer.end();
754
755 // Add small delay to ensure any running callbacks complete
756 delay(50);
757
758 // Call base class stop to stop audio source
760
761 LOGI("RTP Stream stopped - ready for restart");
762 }
763
764 protected:
766};
767
802template <typename Platform>
804 public:
822 RTSPAudioStreamerUsingTask(bool throttled = true)
823 : RTSPAudioStreamerBase<Platform>() {
824 LOGD("Creating RTSP Audio streamer with task");
825 m_taskRunning = false;
826 m_throttled = throttled;
827 }
828
848 RTSPAudioStreamerUsingTask(IAudioSource &source, bool throttled = true)
849 : RTSPAudioStreamerUsingTask(throttled) {
850 this->setAudioSource(&source);
851 }
852
859
878 void setTaskParameters(uint32_t stackSize, uint8_t priority, int core = -1) {
879 if (!m_taskRunning) {
880 m_taskStackSize = stackSize;
881 m_taskPriority = priority;
882 m_taskCore = core;
883 LOGI("Task parameters set: stack=%d bytes, priority=%d, core=%d",
884 stackSize, priority, core);
885 } else {
886 LOGW("Cannot change task parameters while streaming is active");
887 }
888 }
889
903 void start() override {
904 LOGI("Starting RTP Stream with task");
905
906 // Call base class start to initialize audio source and buffer
908
909 if (this->m_audioSource != nullptr && !m_taskRunning) {
910 m_taskRunning = true;
911
912 // Create AudioTools Task for streaming
913 if (!m_streamingTask.create("RTSPStreaming", m_taskStackSize,
915 LOGE("Failed to create streaming task");
916 m_taskRunning = false;
917 return;
918 }
919
920 // Set reference to this instance for the task
921 m_streamingTask.setReference(this);
922
923 // Start the task with our streaming loop
924 // Reset throttle window timing
925 m_send_counter = 0;
926 m_last_throttle_us = micros();
927
928 if (m_streamingTask.begin([this]() { this->streamingTaskLoop(); })) {
929 LOGI("Streaming task started successfully");
930 LOGI("Task: stack=%d bytes, priority=%d, core=%d, period=%d us",
932 this->m_timer_period_us);
933#ifdef ESP32
934 LOGI("Free heap size: %i KB", esp_get_free_heap_size() / 1000);
935#endif
936 } else {
937 LOGE("Failed to start streaming task");
938 m_taskRunning = false;
939 }
940 }
941 }
942
956 void stop() override {
957 LOGI("Stopping RTP Stream with task");
958
959 if (m_taskRunning) {
960 // Signal task to stop
961 m_taskRunning = false;
962
963 // Stop the AudioTools Task
965
966 // Small delay to ensure clean shutdown
967 delay(50);
968 }
969
970 // Call base class stop to stop audio source
972
973 LOGI("RTP Stream with task stopped - ready for restart");
974 }
975
980 bool isTaskRunning() const { return m_taskRunning; }
981
1008 void setThrottled(bool isThrottled) { m_throttled = isThrottled; }
1009
1022 void setFixedDelayMs(uint32_t delayUs) {
1023 this->m_fixed_delay_ms = delayUs;
1024 m_throttled = false;
1025 }
1026
1038 void setThrottleInterval(uint32_t interval) {
1039 m_throttle_interval = interval;
1040 }
1041
1042 protected:
1044 volatile bool m_taskRunning;
1045 uint32_t m_taskStackSize = 8192;
1046 uint8_t m_taskPriority = 5;
1047 int m_taskCore = -1;
1048 bool m_throttled = true;
1049 uint16_t m_fixed_delay_ms = 1;
1051 1000;
1053 0;
1054 unsigned long m_last_throttle_us =
1055 0;
1056
1076 LOGD("Streaming task loop iteration");
1077
1078 auto iterationStartUs = micros();
1079
1080 // Always call the timer callback to send RTP packet
1082
1083 // Apply throttling (fixed delay per send + periodic correction)
1084 applyThrottling(iterationStartUs);
1085 }
1086
1099 inline void applyThrottling(unsigned long iterationStartUs) {
1100 // Increment send counter and apply fixed delay after each send
1102 delay(m_fixed_delay_ms);
1103
1104 // If throttling by interval is enabled (m_throttled true), apply precise
1105 // correction periodically
1106 if (m_throttled && m_throttle_interval > 0) {
1107 // On timer period change, reset the throttle window to avoid drift
1108 if (this->checkTimerPeriodChange()) {
1109 LOGI("Timer period updated; resetting throttle window to %u us",
1110 (unsigned)this->m_timer_period_us);
1111 m_send_counter = 0;
1112 m_last_throttle_us = iterationStartUs;
1113 return;
1114 }
1115
1117 // Expected elapsed time for N sends at configured period
1118 uint64_t expectedUs =
1119 (uint64_t)m_throttle_interval * (uint64_t)this->getTimerPeriodUs();
1120 unsigned long nowUs = micros();
1121 uint64_t actualUs = (uint64_t)(nowUs - m_last_throttle_us);
1122
1123 if (actualUs < expectedUs) {
1124 uint32_t remainingUs = (uint32_t)(expectedUs - actualUs);
1125 // Sleep in ms then the remainder in us
1126 if (remainingUs >= 1000) {
1127 delay(remainingUs / 1000);
1128 }
1129 uint32_t remUs = remainingUs % 1000;
1130 if (remUs > 0) {
1131 delayMicroseconds(remUs);
1132 }
1133 } else if (actualUs > expectedUs + 1000) {
1134 LOGW("Throttling behind by %llu us over %u sends",
1135 (unsigned long long)(actualUs - expectedUs),
1136 (unsigned)m_throttle_interval);
1137 }
1138
1139 // Reset window
1140 m_send_counter = 0;
1141 m_last_throttle_us = micros();
1142 }
1143 }
1144 }
1145};
1146
1147} // namespace audio_tools
Audio Source Interface - Contract for Audio Data Providers.
Definition IAudioSource.h:22
virtual RTSPFormat & getFormat()=0
Get the audio format configuration.
virtual void start()
Initialize audio source for streaming.
Definition IAudioSource.h:68
virtual int readBytes(void *dest, int maxSamples)=0
Read audio data into provided buffer.
virtual void stop()
Cleanup audio source after streaming.
Definition IAudioSource.h:81
RTSPAudioStreamerBase - Core RTP Audio Streaming Engine.
Definition RTSPAudioStreamer.h:50
bool initUdpTransport(IPAddress aClientIP, uint16_t aClientPort)
Initialize UDP transport for RTP streaming.
Definition RTSPAudioStreamer.h:182
IAudioSource * getAudioSource()
Get the configured audio source.
Definition RTSPAudioStreamer.h:401
virtual void start()
Start audio source (base implementation)
Definition RTSPAudioStreamer.h:344
RTSPAudioStreamerBase()
Default constructor for RTSPAudioStreamerBase.
Definition RTSPAudioStreamer.h:63
bool initAudioSource()
Initialize audio source configuration.
Definition RTSPAudioStreamer.h:150
uint32_t currentRtpTimestamp() const
Get current RTP timestamp value that will be used in the next packet.
Definition RTSPAudioStreamer.h:427
virtual ~RTSPAudioStreamerBase()
Destructor.
Definition RTSPAudioStreamer.h:113
uint32_t computeTimestampIncrement(int bytesSent)
Compute RTP timestamp increment based on samples sent.
Definition RTSPAudioStreamer.h:561
virtual void setAudioSource(IAudioSource *source)
Configure the audio source for streaming.
Definition RTSPAudioStreamer.h:130
static void timerCallback(void *audioStreamerObj)
Static timer callback function for periodic RTP streaming.
Definition RTSPAudioStreamer.h:477
uint32_t currentSsrc() const
Get current SSRC used in RTP header.
Definition RTSPAudioStreamer.h:432
uint32_t getTimerPeriodMs() const
Get the timer period in milliseconds.
Definition RTSPAudioStreamer.h:415
uint16_t currentSeq() const
Get current RTP sequence number that will be used in the next packet.
Definition RTSPAudioStreamer.h:421
u_short getRtcpServerPort()
Get the RTCP server port number.
Definition RTSPAudioStreamer.h:394
u_short getRtpServerPort()
Get the RTP server port number.
Definition RTSPAudioStreamer.h:387
int sendRtpPacketDirect()
Send a single RTP packet with audio data.
Definition RTSPAudioStreamer.h:285
RTSPAudioStreamerBase(IAudioSource &source)
Constructor with audio source.
Definition RTSPAudioStreamer.h:101
void initTcpInterleavedTransport(typename Platform::TcpClientType *tcpSock, int rtpChannel, int rtcpChannel)
Initialize TCP interleaved transport for RTP over RTSP.
Definition RTSPAudioStreamer.h:230
uint32_t getTimerPeriodUs() const
Get the timer period in microseconds.
Definition RTSPAudioStreamer.h:408
virtual void stop()
Stop audio source (base implementation)
Definition RTSPAudioStreamer.h:372
void releaseUdpTransport(void)
Release UDP transport resources.
Definition RTSPAudioStreamer.h:252
bool checkTimerPeriodChange()
Check if timer period has changed and update if necessary.
Definition RTSPAudioStreamer.h:445
RTSPAudioStreamer - Timer-driven RTP Audio Streaming Engine.
Definition RTSPAudioStreamer.h:650
void updateTimer()
Update timer period if audio format has changed.
Definition RTSPAudioStreamer.h:730
void start() override
Start timer-driven RTP streaming.
Definition RTSPAudioStreamer.h:703
RTSPAudioStreamer(IAudioSource &source)
Constructor with audio source.
Definition RTSPAudioStreamer.h:686
RTSPAudioStreamer()
Default constructor for RTSPAudioStreamer.
Definition RTSPAudioStreamer.h:661
void stop() override
Stop timer-driven RTP streaming.
Definition RTSPAudioStreamer.h:749
RTSPAudioStreamerUsingTask - Task-driven RTP Audio Streaming Engine.
Definition RTSPAudioStreamer.h:803
RTSPAudioStreamerUsingTask(IAudioSource &source, bool throttled=true)
Constructor with audio source and throttling control.
Definition RTSPAudioStreamer.h:848
void applyThrottling(unsigned long iterationStartUs)
Apply streaming throttling policy.
Definition RTSPAudioStreamer.h:1099
audio_tools::Task m_streamingTask
AudioTools task for streaming loop.
Definition RTSPAudioStreamer.h:1043
volatile bool m_taskRunning
Flag indicating if task is active.
Definition RTSPAudioStreamer.h:1044
virtual ~RTSPAudioStreamerUsingTask()
Destructor.
Definition RTSPAudioStreamer.h:858
void setFixedDelayMs(uint32_t delayUs)
Set a fixed inter-packet delay in non-throttled mode.
Definition RTSPAudioStreamer.h:1022
void setThrottled(bool isThrottled)
Enable or disable throttled timing mode.
Definition RTSPAudioStreamer.h:1008
uint32_t m_throttle_interval
Number of sends before precise correction.
Definition RTSPAudioStreamer.h:1050
RTSPAudioStreamerUsingTask(bool throttled=true)
Default constructor for RTSPAudioStreamerUsingTask.
Definition RTSPAudioStreamer.h:822
void start() override
Start task-driven RTP streaming.
Definition RTSPAudioStreamer.h:903
unsigned long m_last_throttle_us
Start timestamp of current throttle window (micros)
Definition RTSPAudioStreamer.h:1054
uint8_t m_taskPriority
Task priority (5 = medium priority)
Definition RTSPAudioStreamer.h:1046
uint16_t m_fixed_delay_ms
Fixed delay in milliseconds (if used)
Definition RTSPAudioStreamer.h:1049
void setThrottleInterval(uint32_t interval)
Set the throttle interval (number of sends before precise correction)
Definition RTSPAudioStreamer.h:1038
bool isTaskRunning() const
Check if streaming task is currently running.
Definition RTSPAudioStreamer.h:980
void stop() override
Stop task-driven RTP streaming.
Definition RTSPAudioStreamer.h:956
void setTaskParameters(uint32_t stackSize, uint8_t priority, int core=-1)
Set task parameters for streaming task.
Definition RTSPAudioStreamer.h:878
void streamingTaskLoop()
Main streaming task loop iteration.
Definition RTSPAudioStreamer.h:1075
int m_taskCore
CPU core affinity (-1 = any core)
Definition RTSPAudioStreamer.h:1047
uint32_t m_send_counter
Counts sends within the current throttle window.
Definition RTSPAudioStreamer.h:1052
bool m_throttled
Enable precise microsecond timing.
Definition RTSPAudioStreamer.h:1048
uint32_t m_taskStackSize
Task stack size in bytes (8KB default)
Definition RTSPAudioStreamer.h:1045
Audio Format Definition - Base class for RTSP audio formats.
Definition RTSPFormat.h:40
virtual int timerPeriodUs()
Timer period in microseconds.
Definition RTSPFormat.h:78
virtual int readHeader(uint8_t *data)
Optional header: e.g. rfc2250.
Definition RTSPFormat.h:84
virtual int timestampIncrement()
Fragment size in samples.
Definition RTSPFormat.h:67
virtual int fragmentSize()
Fragment (=write) size in bytes.
Definition RTSPFormat.h:64
virtual int rtpPayloadType()
default dynamic
Definition RTSPFormat.h:81
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
Common Interface definition for TimerAlarmRepeating.
Definition AudioTimer.h:29
Vector implementation which provides the most important methods as defined by std::vector....
Definition Vector.h:21
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition AudioCodecsBase.h:10