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 LOGD("RTP Streamer set up with client IP %s and client Port %i",
211 m_ClientIP.toString().c_str(), m_ClientPort);
212
213 return true;
214 }
215
227 void initTcpInterleavedTransport(typename Platform::TcpClientType *tcpSock,
228 int rtpChannel, int rtcpChannel) {
229 m_RtspTcpSocket = tcpSock;
230 m_TcpRtpChannel = rtpChannel;
231 m_TcpRtcpChannel = rtcpChannel;
232 m_useTcpInterleaved = true;
233 m_SequenceNumber = random(65536);
234 LOGI("Using RTP over RTSP TCP interleaved: ch=%d/%d", rtpChannel,
235 rtcpChannel);
236 }
237
250 --m_udpRefCount;
251 if (m_udpRefCount == 0) {
252 m_RtpServerPort = 0;
253 m_RtcpServerPort = 0;
254 Platform::closeUdpSocket(m_RtpSocket);
255 Platform::closeUdpSocket(m_RtcpSocket);
256
257 m_RtpSocket = Platform::NULL_UDP_SOCKET;
258 m_RtcpSocket = Platform::NULL_UDP_SOCKET;
259 }
260 }
261
283 // check buffer
284 if (mRtpBuf.size() == 0) {
285 LOGE("mRtpBuf is empty");
286 return -1;
287 }
288
289 // append data to header
290 if (m_audioSource == nullptr) {
291 LOGE("No audio source provided");
292 return -1;
293 }
294
295 // unsigned char * dataBuf = &mRtpBuf[m_fragmentSize];
296 if (m_fragmentSize + HEADER_SIZE >= STREAMING_BUFFER_SIZE) {
297 LOGE(
298 "STREAMIN_BUFFER_SIZE too small for the sampling rate: increase to "
299 "%d",
300 m_fragmentSize + HEADER_SIZE);
301 return -1;
302 }
303
304 // Generic path (PCM, G711, etc.)
305 memset(mRtpBuf.data(), 0, STREAMING_BUFFER_SIZE);
306 buildRtpHeader();
307
308 unsigned char *dataBuf = &mRtpBuf[HEADER_SIZE];
309 int header_len = m_audioSource->getFormat().readHeader(dataBuf);
310 int maxPayload = STREAMING_BUFFER_SIZE - HEADER_SIZE - header_len;
311 dataBuf += header_len;
312
313 int toRead = m_fragmentSize;
314 if (toRead > maxPayload) {
315 LOGW("Fragment exceeds payload capacity (%d > %d); clamping", toRead, maxPayload);
316 toRead = maxPayload;
317 }
318 int bytesRead = m_audioSource->readBytes((void *)dataBuf, toRead);
319 LOGI("Read %d bytes from audio source", bytesRead);
320 int bytesNet = m_audioSource->getFormat().convert(dataBuf, bytesRead);
321
322 // Compute samples sent for timestamp increment
323 m_lastSamplesSent = m_audioSource->getFormat().timestampIncrement();
324 m_SequenceNumber++;
325 sendOut(HEADER_SIZE + bytesNet + header_len);
326 return bytesNet;
327 }
328
341 virtual void start() {
342 LOGI("Starting audio source (base)");
343
344 if (mRtpBuf.size() == 0) {
345 mRtpBuf.resize(STREAMING_BUFFER_SIZE + 1);
346 }
347
348 if (m_audioSource != nullptr) {
350 m_audioSource->start();
351 LOGI("Audio source started - ready for manual streaming");
352 } else {
353 LOGE("No streaming source");
354 }
355 }
356
369 virtual void stop() {
370 LOGI("Stopping audio source (base)");
371
372 if (m_audioSource != nullptr) {
373 m_audioSource->stop();
374 }
375
376 LOGI("Audio source stopped");
377 }
378
384 u_short getRtpServerPort() { return m_RtpServerPort; }
385
391 u_short getRtcpServerPort() { return m_RtcpServerPort; }
392
398 IAudioSource *getAudioSource() { return m_audioSource; }
399
405 uint32_t getTimerPeriodUs() const { return m_timer_period_us; }
406
412 uint32_t getTimerPeriodMs() const { return m_timer_period_us / 1000; }
413
418 uint16_t currentSeq() const { return m_SequenceNumber; }
419
424 uint32_t currentRtpTimestamp() const { return m_Timestamp; }
425
429 uint32_t currentSsrc() const { return m_Ssrc; }
430
443 if (m_audioSource == nullptr) {
444 return false;
445 }
446
447 uint32_t newPeriod = m_audioSource->getFormat().timerPeriodUs();
448 if (newPeriod != m_timer_period_us && newPeriod > 0) {
449 LOGI("Timer period changed from %u us to %u us",
450 (unsigned)m_timer_period_us, (unsigned)newPeriod);
451 m_timer_period_us = newPeriod;
452 return true;
453 }
454 return false;
455 }
456
474 static void timerCallback(void *audioStreamerObj) {
475 LOGD("timerCallback");
476 if (audioStreamerObj == nullptr) {
477 LOGE("audioStreamerObj is null");
478 return;
479 };
481 (RTSPAudioStreamerBase<Platform> *)audioStreamerObj;
482 unsigned long start, stop;
483
484 start = micros();
485
486 int bytes = streamer->sendRtpPacketDirect();
487
488 if (bytes < 0) {
489 LOGW("Direct sending of RTP stream failed");
490 } else if (bytes > 0) {
491 uint32_t inc = streamer->computeTimestampIncrement(bytes);
492 streamer->m_Timestamp += inc;
493 LOGD("%i samples (ts inc) sent; timestamp: %u", inc,
494 (unsigned)streamer->m_Timestamp);
495 }
496
497 stop = micros();
498 if (stop - start > streamer->m_timer_period_us) {
499 LOGW("RTP Stream can't keep up (took %lu us, %d is max)!", stop - start,
500 streamer->m_timer_period_us);
501 }
502 }
503
504 protected:
505 const int STREAMING_BUFFER_SIZE = 1024 * 3;
507
508 IAudioSource *m_audioSource = nullptr;
509 int m_fragmentSize = 0; // changed from samples to bytes !
510 int m_timer_period_us = 20000;
511 const int HEADER_SIZE = 12; // size of the RTP header
512 volatile bool m_timer_restart_needed =
513 false; // Flag for dynamic timer restart
514
515 typename Platform::UdpSocketType
516 *m_RtpSocket; // RTP socket for streaming RTP packets to client
517 typename Platform::UdpSocketType
518 *m_RtcpSocket; // RTCP socket for sending/receiving RTCP packages
519
520 uint16_t m_RtpServerPort; // RTP sender port on server
521 uint16_t m_RtcpServerPort; // RTCP sender port on server
522
523 u_short m_SequenceNumber;
524 uint32_t m_Timestamp;
525 int m_SendIdx;
526
527 IPAddress m_ClientIP;
528 uint16_t m_ClientPort;
529 uint32_t m_prevMsec;
530
531 int m_udpRefCount;
532
533 // TCP interleaved transport
534 bool m_useTcpInterleaved;
535 typename Platform::TcpClientType *m_RtspTcpSocket;
536 int m_TcpRtpChannel;
537 int m_TcpRtcpChannel;
538
539 int m_payloadType = 96;
540 int m_lastSamplesSent = 0;
541 uint32_t m_Ssrc = 0x13F97E67; // default fixed SSRC
542 // MP3 packetization carry buffer to ensure whole-frame packets
544 int mMp3CarryLen = 0;
545
558 inline uint32_t computeTimestampIncrement(int bytesSent) {
559 // Prefer exact samples sent (set by sender) if available
560 int samples = 0;
561 if (m_lastSamplesSent > 0) {
562 samples = m_lastSamplesSent;
563 } else if (m_audioSource) {
564 samples = m_audioSource->getFormat().timestampIncrement();
565 } else {
566 samples = bytesSent / 2; // crude fallback
567 }
568 return (uint32_t)samples;
569 }
570
571 inline void buildRtpHeader() {
572 mRtpBuf[0] = 0x80; // V=2
573 mRtpBuf[1] = (uint8_t)(m_payloadType & 0x7F);
574 if (m_payloadType == 14) {
575 // Set Marker bit on each complete MP3 frame packet
576 mRtpBuf[1] |= 0x80;
577 }
578 mRtpBuf[2] = (uint8_t)((m_SequenceNumber >> 8) & 0xFF);
579 mRtpBuf[3] = (uint8_t)(m_SequenceNumber & 0xFF);
580 mRtpBuf[4] = (uint8_t)((m_Timestamp >> 24) & 0xFF);
581 mRtpBuf[5] = (uint8_t)((m_Timestamp >> 16) & 0xFF);
582 mRtpBuf[6] = (uint8_t)((m_Timestamp >> 8) & 0xFF);
583 mRtpBuf[7] = (uint8_t)(m_Timestamp & 0xFF);
584 // SSRC
585 mRtpBuf[8] = (uint8_t)((m_Ssrc >> 24) & 0xFF);
586 mRtpBuf[9] = (uint8_t)((m_Ssrc >> 16) & 0xFF);
587 mRtpBuf[10] = (uint8_t)((m_Ssrc >> 8) & 0xFF);
588 mRtpBuf[11] = (uint8_t)(m_Ssrc & 0xFF);
589 }
590
591 inline void sendOut(uint16_t totalLen) {
592 if (m_useTcpInterleaved && m_RtspTcpSocket != Platform::NULL_TCP_SOCKET) {
593 uint8_t hdr[4];
594 hdr[0] = 0x24; // '$'
595 hdr[1] = (uint8_t)m_TcpRtpChannel;
596 hdr[2] = (uint8_t)((totalLen >> 8) & 0xFF);
597 hdr[3] = (uint8_t)(totalLen & 0xFF);
598 Platform::sendSocket(m_RtspTcpSocket, hdr, sizeof(hdr));
599 Platform::sendSocket(m_RtspTcpSocket, mRtpBuf.data(), totalLen);
600 } else {
601 Platform::sendUdpSocket(m_RtpSocket, mRtpBuf.data(), totalLen, m_ClientIP,
602 m_ClientPort);
603 }
604 }
605};
606
623template <typename Platform>
624class RTSPAudioStreamer : public RTSPAudioStreamerBase<Platform> {
625 public:
636 LOGD("Creating RTSP Audio streamer with timer");
637
638 // Setup timer callback for RTP streaming
639 rtpTimer.setCallbackParameter(this);
640
641 // CRITICAL FIX: Force timer to run in task context, not ISR context
642 // ISR context (ESP_TIMER_ISR) has severe limitations that cause
643 // LoadProhibited crashes Task context (ESP_TIMER_TASK) allows full object
644 // access and FreeRTOS calls
645 rtpTimer.setIsSave(
646 true); // true = use TimerCallbackInThread (ESP_TIMER_TASK)
647 LOGI("RTSPAudioStreamer: Timer set to safe task mode (ESP_TIMER_TASK)");
648 }
649
661 this->setAudioSource(&source);
662 }
663
677 void start() override {
678 LOGI("Starting RTP Stream with timer");
679
680 // Call base class start to initialize audio source and buffer
682
683 if (this->m_audioSource != nullptr) {
684 // Start timer with period in microseconds using specialized callback
686 this->m_timer_period_us, audio_tools::US)) {
687 LOGE("Could not start timer");
688 }
689 LOGI("timer: %u us", (unsigned)this->m_timer_period_us);
690#ifdef ESP32
691 LOGI("Free heap size: %i KB", esp_get_free_heap_size() / 1000);
692#endif
693 }
694 }
695
704 void updateTimer() {
705 if (this->checkTimerPeriodChange()) {
706 LOGI("Updating timer period to %u us", (unsigned)this->m_timer_period_us);
707 rtpTimer.begin(this->m_timer_period_us, audio_tools::US);
708 }
709 }
710
723 void stop() override {
724 LOGI("Stopping RTP Stream with timer");
725
726 // Stop timer first to prevent callbacks during cleanup
727 rtpTimer.end();
728
729 // Add small delay to ensure any running callbacks complete
730 delay(50);
731
732 // Call base class stop to stop audio source
734
735 LOGI("RTP Stream stopped - ready for restart");
736 }
737
738 protected:
740};
741
776template <typename Platform>
778 public:
796 RTSPAudioStreamerUsingTask(bool throttled = true)
797 : RTSPAudioStreamerBase<Platform>() {
798 LOGD("Creating RTSP Audio streamer with task");
799 m_taskRunning = false;
800 m_throttled = throttled;
801 }
802
822 RTSPAudioStreamerUsingTask(IAudioSource &source, bool throttled = true)
823 : RTSPAudioStreamerUsingTask(throttled) {
824 this->setAudioSource(&source);
825 }
826
833
852 void setTaskParameters(uint32_t stackSize, uint8_t priority, int core = -1) {
853 if (!m_taskRunning) {
854 m_taskStackSize = stackSize;
855 m_taskPriority = priority;
856 m_taskCore = core;
857 LOGI("Task parameters set: stack=%d bytes, priority=%d, core=%d",
858 stackSize, priority, core);
859 } else {
860 LOGW("Cannot change task parameters while streaming is active");
861 }
862 }
863
877 void start() override {
878 LOGI("Starting RTP Stream with task");
879
880 // Call base class start to initialize audio source and buffer
882
883 if (this->m_audioSource != nullptr && !m_taskRunning) {
884 m_taskRunning = true;
885
886 // Create AudioTools Task for streaming
887 if (!m_streamingTask.create("RTSPStreaming", m_taskStackSize,
889 LOGE("Failed to create streaming task");
890 m_taskRunning = false;
891 return;
892 }
893
894 // Set reference to this instance for the task
895 m_streamingTask.setReference(this);
896
897 // Start the task with our streaming loop
898 // Reset throttle window timing
899 m_send_counter = 0;
900 m_last_throttle_us = micros();
901
902 if (m_streamingTask.begin([this]() { this->streamingTaskLoop(); })) {
903 LOGI("Streaming task started successfully");
904 LOGI("Task: stack=%d bytes, priority=%d, core=%d, period=%d us",
906 this->m_timer_period_us);
907#ifdef ESP32
908 LOGI("Free heap size: %i KB", esp_get_free_heap_size() / 1000);
909#endif
910 } else {
911 LOGE("Failed to start streaming task");
912 m_taskRunning = false;
913 }
914 }
915 }
916
930 void stop() override {
931 LOGI("Stopping RTP Stream with task");
932
933 if (m_taskRunning) {
934 // Signal task to stop
935 m_taskRunning = false;
936
937 // Stop the AudioTools Task
939
940 // Small delay to ensure clean shutdown
941 delay(50);
942 }
943
944 // Call base class stop to stop audio source
946
947 LOGI("RTP Stream with task stopped - ready for restart");
948 }
949
954 bool isTaskRunning() const { return m_taskRunning; }
955
982 void setThrottled(bool isThrottled) { m_throttled = isThrottled; }
983
996 void setFixedDelayMs(uint32_t delayUs) {
997 this->m_fixed_delay_ms = delayUs;
998 m_throttled = false;
999 }
1000
1012 void setThrottleInterval(uint32_t interval) {
1013 m_throttle_interval = interval;
1014 }
1015
1016 protected:
1018 volatile bool m_taskRunning;
1019 uint32_t m_taskStackSize = 8192;
1020 uint8_t m_taskPriority = 5;
1021 int m_taskCore = -1;
1022 bool m_throttled = true;
1023 uint16_t m_fixed_delay_ms = 1;
1025 1000;
1027 0;
1028 unsigned long m_last_throttle_us =
1029 0;
1030
1050 LOGD("Streaming task loop iteration");
1051
1052 auto iterationStartUs = micros();
1053
1054 // Always call the timer callback to send RTP packet
1056
1057 // Apply throttling (fixed delay per send + periodic correction)
1058 applyThrottling(iterationStartUs);
1059 }
1060
1073 inline void applyThrottling(unsigned long iterationStartUs) {
1074 // Increment send counter and apply fixed delay after each send
1076 delay(m_fixed_delay_ms);
1077
1078 // If throttling by interval is enabled (m_throttled true), apply precise
1079 // correction periodically
1080 if (m_throttled && m_throttle_interval > 0) {
1081 // On timer period change, reset the throttle window to avoid drift
1082 if (this->checkTimerPeriodChange()) {
1083 LOGI("Timer period updated; resetting throttle window to %u us",
1084 (unsigned)this->m_timer_period_us);
1085 m_send_counter = 0;
1086 m_last_throttle_us = iterationStartUs;
1087 return;
1088 }
1089
1091 // Expected elapsed time for N sends at configured period
1092 uint64_t expectedUs =
1093 (uint64_t)m_throttle_interval * (uint64_t)this->getTimerPeriodUs();
1094 unsigned long nowUs = micros();
1095 uint64_t actualUs = (uint64_t)(nowUs - m_last_throttle_us);
1096
1097 if (actualUs < expectedUs) {
1098 uint32_t remainingUs = (uint32_t)(expectedUs - actualUs);
1099 // Sleep in ms then the remainder in us
1100 if (remainingUs >= 1000) {
1101 delay(remainingUs / 1000);
1102 }
1103 uint32_t remUs = remainingUs % 1000;
1104 if (remUs > 0) {
1105 delayMicroseconds(remUs);
1106 }
1107 } else if (actualUs > expectedUs + 1000) {
1108 LOGW("Throttling behind by %llu us over %u sends",
1109 (unsigned long long)(actualUs - expectedUs),
1110 (unsigned)m_throttle_interval);
1111 }
1112
1113 // Reset window
1114 m_send_counter = 0;
1115 m_last_throttle_us = micros();
1116 }
1117 }
1118 }
1119};
1120
1121} // namespace audio_tools
Audio Source Interface - Contract for Audio Data Providers.
Definition IAudioSource.h:23
virtual RTSPFormat & getFormat()=0
Get the audio format configuration.
virtual void start()
Initialize audio source for streaming.
Definition IAudioSource.h:69
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:82
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:398
virtual void start()
Start audio source (base implementation)
Definition RTSPAudioStreamer.h:341
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:424
virtual ~RTSPAudioStreamerBase()
Destructor.
Definition RTSPAudioStreamer.h:113
uint32_t computeTimestampIncrement(int bytesSent)
Compute RTP timestamp increment based on samples sent.
Definition RTSPAudioStreamer.h:558
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:474
uint32_t currentSsrc() const
Get current SSRC used in RTP header.
Definition RTSPAudioStreamer.h:429
uint32_t getTimerPeriodMs() const
Get the timer period in milliseconds.
Definition RTSPAudioStreamer.h:412
uint16_t currentSeq() const
Get current RTP sequence number that will be used in the next packet.
Definition RTSPAudioStreamer.h:418
u_short getRtcpServerPort()
Get the RTCP server port number.
Definition RTSPAudioStreamer.h:391
u_short getRtpServerPort()
Get the RTP server port number.
Definition RTSPAudioStreamer.h:384
int sendRtpPacketDirect()
Send a single RTP packet with audio data.
Definition RTSPAudioStreamer.h:282
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:227
uint32_t getTimerPeriodUs() const
Get the timer period in microseconds.
Definition RTSPAudioStreamer.h:405
virtual void stop()
Stop audio source (base implementation)
Definition RTSPAudioStreamer.h:369
void releaseUdpTransport(void)
Release UDP transport resources.
Definition RTSPAudioStreamer.h:249
bool checkTimerPeriodChange()
Check if timer period has changed and update if necessary.
Definition RTSPAudioStreamer.h:442
RTSPAudioStreamer - Timer-driven RTP Audio Streaming Engine.
Definition RTSPAudioStreamer.h:624
void updateTimer()
Update timer period if audio format has changed.
Definition RTSPAudioStreamer.h:704
void start() override
Start timer-driven RTP streaming.
Definition RTSPAudioStreamer.h:677
RTSPAudioStreamer(IAudioSource &source)
Constructor with audio source.
Definition RTSPAudioStreamer.h:660
RTSPAudioStreamer()
Default constructor for RTSPAudioStreamer.
Definition RTSPAudioStreamer.h:635
void stop() override
Stop timer-driven RTP streaming.
Definition RTSPAudioStreamer.h:723
RTSPAudioStreamerUsingTask - Task-driven RTP Audio Streaming Engine.
Definition RTSPAudioStreamer.h:777
RTSPAudioStreamerUsingTask(IAudioSource &source, bool throttled=true)
Constructor with audio source and throttling control.
Definition RTSPAudioStreamer.h:822
void applyThrottling(unsigned long iterationStartUs)
Apply streaming throttling policy.
Definition RTSPAudioStreamer.h:1073
audio_tools::Task m_streamingTask
AudioTools task for streaming loop.
Definition RTSPAudioStreamer.h:1017
volatile bool m_taskRunning
Flag indicating if task is active.
Definition RTSPAudioStreamer.h:1018
virtual ~RTSPAudioStreamerUsingTask()
Destructor.
Definition RTSPAudioStreamer.h:832
void setFixedDelayMs(uint32_t delayUs)
Set a fixed inter-packet delay in non-throttled mode.
Definition RTSPAudioStreamer.h:996
void setThrottled(bool isThrottled)
Enable or disable throttled timing mode.
Definition RTSPAudioStreamer.h:982
uint32_t m_throttle_interval
Number of sends before precise correction.
Definition RTSPAudioStreamer.h:1024
RTSPAudioStreamerUsingTask(bool throttled=true)
Default constructor for RTSPAudioStreamerUsingTask.
Definition RTSPAudioStreamer.h:796
void start() override
Start task-driven RTP streaming.
Definition RTSPAudioStreamer.h:877
unsigned long m_last_throttle_us
Start timestamp of current throttle window (micros)
Definition RTSPAudioStreamer.h:1028
uint8_t m_taskPriority
Task priority (5 = medium priority)
Definition RTSPAudioStreamer.h:1020
uint16_t m_fixed_delay_ms
Fixed delay in milliseconds (if used)
Definition RTSPAudioStreamer.h:1023
void setThrottleInterval(uint32_t interval)
Set the throttle interval (number of sends before precise correction)
Definition RTSPAudioStreamer.h:1012
bool isTaskRunning() const
Check if streaming task is currently running.
Definition RTSPAudioStreamer.h:954
void stop() override
Stop task-driven RTP streaming.
Definition RTSPAudioStreamer.h:930
void setTaskParameters(uint32_t stackSize, uint8_t priority, int core=-1)
Set task parameters for streaming task.
Definition RTSPAudioStreamer.h:852
void streamingTaskLoop()
Main streaming task loop iteration.
Definition RTSPAudioStreamer.h:1049
int m_taskCore
CPU core affinity (-1 = any core)
Definition RTSPAudioStreamer.h:1021
uint32_t m_send_counter
Counts sends within the current throttle window.
Definition RTSPAudioStreamer.h:1026
bool m_throttled
Enable precise microsecond timing.
Definition RTSPAudioStreamer.h:1022
uint32_t m_taskStackSize
Task stack size in bytes (8KB default)
Definition RTSPAudioStreamer.h:1019
Audio Format Definition - Base class for RTSP audio formats.
Definition RTSPFormat.h:41
virtual int timerPeriodUs()
Timer period in microseconds.
Definition RTSPFormat.h:79
virtual int readHeader(uint8_t *data)
Optional header: e.g. rfc2250.
Definition RTSPFormat.h:85
virtual int timestampIncrement()
Fragment size in samples.
Definition RTSPFormat.h:68
virtual int fragmentSize()
Fragment (=write) size in bytes.
Definition RTSPFormat.h:65
virtual int rtpPayloadType()
default dynamic
Definition RTSPFormat.h:82
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