arduino-audio-tools
RTSP.h
1 #pragma once
2 
3 #include "AudioStreamer.h"
4 #include "AudioTools/CoreAudio/AudioPlayer.h"
5 #include "AudioTools/CoreAudio/AudioStreams.h"
6 #include "IAudioSource.h"
7 #include "RTSPServer.h"
8 
17 namespace audio_tools {
18 
27 class RTSPOutputPCMInfo : public PCMInfo {
28 public:
29  RTSPOutputPCMInfo() = default;
30  virtual void begin(AudioStream &stream) { p_stream = &stream; }
31  int getSampleRate() override { return p_stream->audioInfo().sample_rate; }
32  int getChannels() override { return p_stream->audioInfo().channels; }
33  int getSampleSizeBytes() override {
34  return p_stream->audioInfo().bits_per_sample / 8;
35  };
36  virtual void setAudioInfo(AudioInfo ai) { p_stream->setAudioInfo(ai); }
37 
38 protected:
39  AudioStream *p_stream = nullptr;
40 };
41 
50 class RTSPPCMAudioInfo : public PCMInfo {
51 public:
52  RTSPPCMAudioInfo() = default;
53  virtual void begin(AudioInfo info) { this->info = info; }
54  int getSampleRate() override { return info.sample_rate; }
55  int getChannels() override { return info.channels; }
56  int getSampleSizeBytes() override { return info.bits_per_sample / 8; };
57  virtual void setAudioInfo(AudioInfo ai) { info = ai; }
58 
59 protected:
60  AudioInfo info;
61 };
62 
72 class RTSPSourceFromAudioStream : public IAudioSource {
73 public:
74  RTSPSourceFromAudioStream() = default;
81  setInput(stream);
82  setFormat(new RTSPFormatPCM(pcmInfo));
83  }
84 
85  RTSPSourceFromAudioStream(AudioStream &stream, RTSPFormat &format) {
86  setInput(stream);
87  setFormat(&format);
88  }
89 
90  void setInput(AudioStream &stream) {
91  p_audiostream = &stream;
92  pcmInfo.begin(stream);
93  }
94 
102  virtual void setAudioInfo(AudioInfo info) {
103  TRACEI();
104  p_audiostream->setAudioInfo(info);
105  }
106 
113  virtual int readBytes(void *dest, int byteCount) override {
114  time_of_last_read = millis();
115  int result = 0;
116  LOGD("readDataTo: %d", byteCount);
117  if (started) {
118  result = p_audiostream->readBytes((uint8_t *)dest, byteCount);
119  }
120  return result;
121  }
122  // Provides the Audio Information
123  virtual RTSPFormat *getFormat() override { return &format; }
124 
128  virtual void start() override {
129  TRACEI();
130  IAudioSource::start();
131  p_audiostream->begin();
132  started = true;
133  };
137  virtual void stop() override {
138  TRACEI();
140  started = false;
141  p_audiostream->end();
142  };
143 
144  void setFragmentSize(int fragmentSize) {
145  format.setFragmentSize(fragmentSize);
146  }
147 
148  void setTimerPeriod(int period) { format.setTimerPeriod(period); }
149 
152  bool isActive() { return millis() - time_of_last_read < 100; }
153 
155  bool isStarted() { return started; }
156 
157 protected:
158  AudioStream *p_audiostream = nullptr;
159  uint32_t time_of_last_read = 0;
160  bool started = true;
161  RTSPOutputPCMInfo pcmInfo;
162  RTSPFormatPCM format{pcmInfo};
163 };
164 
174 class RTSPSourceStream : public IAudioSource {
175 public:
183  p_stream = &stream;
184  rtp_info.begin(info);
185  setFormat(new RTSPFormatPCM(rtp_info));
186  }
187 
194  RTSPSourceStream(Stream &stream, RTSPFormat &format) {
195  p_stream = &stream;
196  setFormat(&format);
197  }
198 
206  virtual void setAudioInfo(AudioInfo info) {
207  TRACEI();
208  rtp_info.setAudioInfo(info);
209  }
210 
211  // Provides the Audio Information
212  virtual RTSPFormat *getFormat() override { return &format; }
213 
218  virtual int readBytes(void *dest, int byteCount) override {
219  int result = 0;
220  LOGD("readDataTo: %d", byteCount);
221  if (active) {
222  result = p_stream->readBytes((uint8_t *)dest, byteCount);
223  }
224  return result;
225  }
229  virtual void start() override {
230  TRACEI();
231  active = true;
232  };
236  virtual void stop() override {
237  TRACEI();
238  active = false;
239  };
240 
241  void setFragmentSize(int fragmentSize) {
242  format.setFragmentSize(fragmentSize);
243  }
244 
245  void setTimerPeriod(int period) { format.setTimerPeriod(period); }
246 
247 protected:
248  Stream *p_stream = nullptr;
249  bool active = true;
250  RTSPPCMAudioInfo rtp_info;
251  RTSPFormatPCM format{rtp_info};
252 };
253 
259 class RTSPFormatAudioTools : public RTSPFormat {
260 public:
261  virtual void begin(AudioInfo info) { cfg = info; }
263  virtual const char *format(char *buffer, int len) = 0;
265  virtual AudioInfo defaultConfig() = 0;
267  const char* name() {
268  return name_str;
269  }
271  void setName(const char* name){
272  name_str = name;
273  }
274 
275  void setFragmentSize(int fragmentSize) { RTSPFormat::setFragmentSize(fragmentSize);}
276  int fragmentSize() { return RTSPFormat::fragmentSize(); }
277 
278  void setTimerPeriod(int period) { RTSPFormat::setTimerPeriod(period); }
279  int timerPeriod() { return RTSPFormat::timerPeriod(); }
280 
281 protected:
282  AudioInfo cfg;
283  const char* name_str="RTSP-Demo";;
284 };
285 
293 public:
294  // Provides the Opus format information:
295  // m=audio 54312 RTP/AVP 101
296  // a=rtpmap:101 opus/48000/2
297  // a=fmtp:101 stereo=1; sprop-stereo=1
298  const char *format(char *buffer, int len) override {
299  TRACEI();
300  snprintf(buffer, len,
301  "s=%s\r\n" // Stream Name
302  "c=IN IP4 0.0.0.0\r\n" // Connection Information
303  "t=0 0\r\n" // start / stop - 0 -> unbounded and permanent session
304  "m=audio 0 RTP/AVP 101\r\n" // UDP sessions with format 101=opus
305  "a=rtpmap:101 opus/%d/2\r\n"
306  "a=fmtp:101 stereo=1; sprop-stereo=%d\r\n",
307  name(), cfg.sample_rate, cfg.channels == 2);
308  return (const char *)buffer;
309  }
311  AudioInfo cfg(44100, 2, 16);
312  return cfg;
313  }
314 };
315 
323 public:
324  // Provides the SBC format information:
325  // m=audio 5004 RTP/AVP 98
326  // a=rtpmap:98 aptx/44100/2
327  // a=fmtp:98 variant=standard; bitresolution=16;
328  const char *format(char *buffer, int len) override {
329  TRACEI();
330  snprintf(buffer, len,
331  "s=%s\r\n" // Stream Name
332  "c=IN IP4 0.0.0.0\r\n" // Connection Information
333  "t=0 0\r\n" // start / stop - 0 -> unbounded and permanent session
334  "m=audio 0 RTP/AVP 98\r\n" // UDP sessions with format 98=aptx
335  "a=rtpmap:98 aptx/%d/%d\r\n"
336  "a=fmtp:98 variant=standard; bitresolution=%d\r\n",
337  name(), cfg.sample_rate, cfg.channels, cfg.bits_per_sample);
338  return (const char *)buffer;
339  }
341  AudioInfo cfg(44100, 2, 16);
342  return cfg;
343  }
344 };
345 
353 public:
355  const char *format(char *buffer, int len) override {
356  TRACEI();
357  assert(cfg.sample_rate == 8000);
358  assert(cfg.channels == 1);
359 
360  snprintf(buffer, len,
361  "s=%s\r\n" // Stream Name
362  "c=IN IP4 0.0.0.0\r\n" // Connection Information
363  "t=0 0\r\n" // start / stop - 0 -> unbounded and permanent session
364  "m=audio 0 RTP/AVP 3\r\n" // UDP sessions with format 3=GSM
365  , name());
366  return (const char *)buffer;
367  }
368 
370  AudioInfo cfg(8000, 1, 16);
371  return cfg;
372  }
373 };
374 
383 public:
385  const char *format(char *buffer, int len) override {
386  TRACEI();
387  assert(cfg.sample_rate == 8000);
388  assert(cfg.channels == 1);
389 
390  snprintf(buffer, len,
391  "s=%s\r\n" // Stream Name
392  "c=IN IP4 0.0.0.0\r\n" // Connection Information
393  "t=0 0\r\n" // start / stop - 0 -> unbounded and permanent session
394  "m=audio 0 RTP/AVP %d\r\n" // UDP sessions with format 0=G711 μ-Law
395  , name(), getFormat());
396  return (const char *)buffer;
397  }
398 
400  void setIsULaw(bool flag) { is_ulaw = flag; }
401 
403  AudioInfo cfg(8000, 1, 16);
404  return cfg;
405  }
406 
407 protected:
408  bool is_ulaw = true;
409  uint8_t getFormat() { return is_ulaw ? 0 : 8; }
410 };
411 
419 public:
421  const char *format(char *buffer, int len) override {
422  TRACEI();
423  snprintf(buffer, len,
424  "s=%s\r\n" // Stream Name
425  "c=IN IP4 0.0.0.0\r\n" // Connection Information
426  "t=0 0\r\n" // start / stop - 0 -> unbounded and permanent session
427  "m=audio 0 RTP/AVP %d\r\n" // UDP sessions with format 10 or 11
428  "a=rtpmap:%s\r\n"
429  "a=rate:%i\r\n", // provide sample rate
430  name(), format(cfg.channels), payloadFormat(cfg.sample_rate, cfg.channels),
431  cfg.sample_rate);
432  return (const char *)buffer;
433  }
434 
436  AudioInfo cfg(16000, 2, 16);
437  return cfg;
438  }
439 
440 protected:
441  char payload_fromat[30];
442 
443  // format for mono is 11 and stereo 11
444  int format(int channels) {
445  int result = 0;
446  switch (channels) {
447  case 1:
448  result = 11;
449  break;
450  case 2:
451  result = 10;
452  break;
453  default:
454  LOGE("unsupported audio type");
455  break;
456  }
457  return result;
458  }
459 
460  const char *payloadFormat(int sampleRate, int channels) {
461  // see https://en.wikipedia.org/wiki/RTP_payload_formats
462  // 11 L16/%i/%i
463 
464  switch (channels) {
465  case 1:
466  snprintf(payload_fromat, 30, "%d L16/%i/%i", format(channels), sampleRate,
467  channels);
468  break;
469  case 2:
470  snprintf(payload_fromat, 30, "%d L16/%i/%i", format(channels), sampleRate,
471  channels);
472  break;
473  default:
474  LOGE("unsupported audio type");
475  break;
476  }
477  return payload_fromat;
478  }
479 };
480 
488 public:
489  const char *format(char *buffer, int len) override {
490  TRACEI();
491  snprintf(buffer, len,
492  "s=%s\r\n" // Stream Name
493  "c=IN IP4 0.0.0.0\r\n" // Connection Information
494  "t=0 0\r\n" // start / stop - 0 -> unbounded and permanent session
495  "m=audio 0 RTP/AVP 96\r\n" // UDP sessions with format 96=dynamic
496  "a=rtpmap:96 l8/%d/%d\r\n",
497  name(), cfg.sample_rate, cfg.channels);
498  return (const char *)buffer;
499  }
501  AudioInfo cfg(16000, 2, 8);
502  return cfg;
503  }
504 };
505 
516 class RTSPOutput : public AudioOutput {
517 public:
520  int buffer_size = 1024 * 2) {
521  buffer.resize(buffer_size);
522  p_format = &format;
523  p_encoder = &encoder;
524  p_encoder->setOutput(buffer);
525  }
526 
528  RTSPOutput(int buffer_size = 1024) {
529  buffer.resize(buffer_size);
530  p_encoder->setOutput(buffer);
531  }
532 
533  AudioStreamer *streamer() { return &rtsp_streamer; }
534 
535  bool begin(AudioInfo info) {
536  cfg = info;
537  return begin();
538  }
539 
540  bool begin() {
541  TRACEI();
542  if (p_input == nullptr) {
543  LOGE("input is null");
544  return false;
545  }
546  if (p_encoder == nullptr) {
547  LOGE("encoder is null");
548  return false;
549  }
550  if (p_format == nullptr) {
551  LOGE("format is null");
552  return false;
553  }
554  p_encoder->setAudioInfo(cfg);
555  p_encoder->begin();
556  p_format->begin(cfg);
557  // setup the AudioStreamer
558  rtsp_streamer.setAudioSource(&rtps_source);
559  // setup the RTSPSourceFromAudioStream
560  rtps_source.setInput(*p_input);
561  rtps_source.setFormat(p_format);
562  rtps_source.setAudioInfo(cfg);
563  rtps_source.start();
564  return true;
565  }
566 
567  void end() { rtps_source.stop(); }
568 
574  return rtps_source.isStarted() ? buffer.available() : 0;
575  }
576 
581  size_t write(const uint8_t *data, size_t len) override {
582  TRACED();
583  size_t result = p_encoder->write(data, len);
584  return result;
585  }
586 
588  operator bool() { return rtps_source.isActive(); }
589 
590 protected:
591  RTSPFormatPCM pcm;
592  CopyEncoder copy_encoder;
593  RTSPSourceFromAudioStream rtps_source;
594  RingBufferStream buffer{0};
595  AudioStream *p_input = &buffer;
596  AudioEncoder *p_encoder = &copy_encoder;
597  RTSPFormatAudioTools *p_format = &pcm;
598  AudioStreamer rtsp_streamer;
599 };
600 
601 // legacy name
602 #if USE_OBSOLETE
603 using RTSPStream = RTSPOutput;
604 #endif
605 
606 } // namespace audio_tools
Encoding of PCM data.
Definition: AudioCodecsBase.h:84
void setAudioInfo(AudioInfo from) override
Defines the sample rate, number of channels and bits per sample.
Definition: AudioCodecsBase.h:93
Abstract Audio Ouptut class.
Definition: AudioOutput.h:22
Base class for all Audio Streams. It support the boolean operator to test if the object is ready with...
Definition: BaseStream.h:109
virtual void setAudioInfo(AudioInfo newInfo) override
Defines the input AudioInfo.
Definition: BaseStream.h:117
virtual AudioInfo audioInfo() override
provides the actual input AudioInfo
Definition: BaseStream.h:140
Dummy Encoder which just copies the provided data to the output.
Definition: CodecCopy.h:62
abtX format for RTSP https://en.wikipedia.org/wiki/RTP_payload_formats
Definition: RTSP.h:322
const char * format(char *buffer, int len) override
Provides the format string.
Definition: RTSP.h:328
AudioInfo defaultConfig()
Provide a default format that will just work.
Definition: RTSP.h:340
RTSPFormat which supports the AudioInfo class.
Definition: RTSP.h:259
const char * name()
Proides the name.
Definition: RTSP.h:267
void setName(const char *name)
Defines the name.
Definition: RTSP.h:271
virtual const char * format(char *buffer, int len)=0
Provides the format string.
virtual AudioInfo defaultConfig()=0
Provide a default format that will just work.
G711 μ-Law format for RTSP https://en.wikipedia.org/wiki/RTP_payload_formats Packet intervall: 20,...
Definition: RTSP.h:382
void setIsULaw(bool flag)
Defines if we use ulow ar alow; by default we use ulaw!
Definition: RTSP.h:400
const char * format(char *buffer, int len) override
Provides the G711 format information.
Definition: RTSP.h:385
AudioInfo defaultConfig()
Provide a default format that will just work.
Definition: RTSP.h:402
GSM format for RTSP https://en.wikipedia.org/wiki/RTP_payload_formats.
Definition: RTSP.h:352
const char * format(char *buffer, int len) override
Provides the GSM format information.
Definition: RTSP.h:355
AudioInfo defaultConfig()
Provide a default format that will just work.
Definition: RTSP.h:369
Opus format for RTSP https://en.wikipedia.org/wiki/RTP_payload_formats.
Definition: RTSP.h:292
const char * format(char *buffer, int len) override
Provides the format string.
Definition: RTSP.h:298
AudioInfo defaultConfig()
Provide a default format that will just work.
Definition: RTSP.h:310
L8 format for RTSP https://en.wikipedia.org/wiki/RTP_payload_formats.
Definition: RTSP.h:487
const char * format(char *buffer, int len) override
Provides the format string.
Definition: RTSP.h:489
AudioInfo defaultConfig()
Provide a default format that will just work.
Definition: RTSP.h:500
PCM format for RTSP https://en.wikipedia.org/wiki/RTP_payload_formats.
Definition: RTSP.h:418
const char * format(char *buffer, int len) override
Provides the GSM format information.
Definition: RTSP.h:421
AudioInfo defaultConfig()
Provide a default format that will just work.
Definition: RTSP.h:435
We can write PCM data to the RTSPOutput. This is encoded by the indicated encoder (e....
Definition: RTSP.h:516
RTSPOutput(int buffer_size=1024)
Construcor using RTSPFormatPCM and no encoder.
Definition: RTSP.h:528
size_t write(const uint8_t *data, size_t len) override
Definition: RTSP.h:581
int availableForWrite()
Definition: RTSP.h:573
RTSPOutput(RTSPFormatAudioTools &format, AudioEncoder &encoder, int buffer_size=1024 *2)
Default constructor.
Definition: RTSP.h:519
PCMInfo subclass which provides the audio information from the related AudioStream Depends on the htt...
Definition: RTSP.h:27
PCMInfo subclass which provides the audio information from the AudioInfo parameter.
Definition: RTSP.h:50
Simple Facade which can turn AudioStream into a IAudioSource. This way we can e.g....
Definition: RTSP.h:72
virtual void stop() override
Definition: RTSP.h:137
virtual void start() override
Definition: RTSP.h:128
bool isStarted()
Returns true after start() has been called.
Definition: RTSP.h:155
RTSPSourceFromAudioStream(AudioStream &stream)
Construct a new RTSPOutputSource object from an AudioStream.
Definition: RTSP.h:80
virtual void setAudioInfo(AudioInfo info)
Set the Audio Info. This needs to be called if we just pass a Stream. The AudioStream is usually able...
Definition: RTSP.h:102
bool isActive()
Definition: RTSP.h:152
virtual int readBytes(void *dest, int byteCount) override
Definition: RTSP.h:113
Simple Facade which can turn any Stream into a IAudioSource. This way we can e.g. use an I2SStream as...
Definition: RTSP.h:174
virtual void stop() override
Definition: RTSP.h:236
virtual void start() override
Definition: RTSP.h:229
virtual void setAudioInfo(AudioInfo info)
Set the Audio Info. This needs to be called if we just pass a Stream. The AudioStream is usually able...
Definition: RTSP.h:206
RTSPSourceStream(Stream &stream, AudioInfo info)
Construct a new RTSPOutputSource object from an Arduino Stream You need to provide the audio informat...
Definition: RTSP.h:182
RTSPSourceStream(Stream &stream, RTSPFormat &format)
Construct a new RTSPOutputSource object from an Arduino Stream You need to provide the audio informat...
Definition: RTSP.h:194
virtual int readBytes(void *dest, int byteCount) override
Definition: RTSP.h:218
An AudioStream backed by a Ringbuffer. We can write to the end and read from the beginning of the str...
Definition: AudioStreams.h:342
Definition: NoArduino.h:125
void stop()
Public generic methods.
Definition: AudioRuntime.h:27
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition: AudioConfig.h:868
uint32_t millis()
Returns the milliseconds since the start.
Definition: Time.h:12
Basic Audio information which drives e.g. I2S.
Definition: AudioTypes.h:52
sample_rate_t sample_rate
Sample Rate: e.g 44100.
Definition: AudioTypes.h:55
uint16_t channels
Number of channels: 2=stereo, 1=mono.
Definition: AudioTypes.h:57
uint8_t bits_per_sample
Number of bits per sample (int16_t = 16 bits)
Definition: AudioTypes.h:59