From 190fdc0502ea36add7d768966632dfb03c7f2547 Mon Sep 17 00:00:00 2001 From: Phil Schatzmann Date: Tue, 17 Oct 2023 09:27:14 +0200 Subject: [PATCH] example: rtsp client --- .../communication-rtsp-i2s.ino | 46 +++++++++++++++ src/AudioConfig.h | 4 +- src/AudioHttp/HLSStream.h | 56 ++++++++++--------- 3 files changed, 79 insertions(+), 27 deletions(-) create mode 100644 examples/examples-communication/rtsp/communication-rtsp-i2s/communication-rtsp-i2s.ino diff --git a/examples/examples-communication/rtsp/communication-rtsp-i2s/communication-rtsp-i2s.ino b/examples/examples-communication/rtsp/communication-rtsp-i2s/communication-rtsp-i2s.ino new file mode 100644 index 0000000000..67b318eb29 --- /dev/null +++ b/examples/examples-communication/rtsp/communication-rtsp-i2s/communication-rtsp-i2s.ino @@ -0,0 +1,46 @@ +/** + * @file communication-rtsp-i2s.ino + * @author Phil Schatzmann + * @brief Demo for RTSP Client that is playing mp3 + * @version 0.1 + * @date 2022-05-02 + * + * @copyright Copyright (c) 2022 + * + */ + +#include "AudioTools.h" // https://github.com/pschatzmann/arduino-audio-tools +#include "AudioCodecs/CodecMP3Helix.h" // https://github.com/pschatzmann/arduino-libhelix +#include "RTSPSimpleClient.hh" // https://github.com/pschatzmann/arduino-live555.git + +I2SStream i2s; +EncodedAudioStream out_mp3(&i2s, new MP3DecoderHelix()); // Decoding stream +RTSPSimpleClient rtsp; + +void setup() { + Serial.begin(115200); + AudioLogger::instance().begin(Serial, AudioLogger::Info); + + // setup output: make sure we can buffer 1 decoded frame + auto cfg_i2s = i2s.defaultConfig(TX_MODE); + cfg_i2s.buffer_size = 1024; + cfg_i2s.buffer_count = 10; + i2s.begin(cfg_i2s); + + out_mp3.begin(); + + // setup rtsp data source + auto cfg = rtsp.defaultConfig(); + cfg.ssid = "ssid"; + cfg.password = "password"; + cfg.url = "rtsp://192.168.1.38:8554/test.mp3"; + cfg.output = &out_mp3; + cfg.buffer_size = 1024*2; // space for 1 encoded frame + //cfg.is_tcp = false; // use udp when false (default false) + //cfg.is_blocking = false; // call singleStep in loop if false (default false) + rtsp.begin(cfg); +} + +void loop() { + rtsp.singleStep(); +} \ No newline at end of file diff --git a/src/AudioConfig.h b/src/AudioConfig.h index 6cf72e7a4d..3c3244c499 100644 --- a/src/AudioConfig.h +++ b/src/AudioConfig.h @@ -700,4 +700,6 @@ using int24_t = audio_tools::int24_4bytes_t; #pragma GCC diagnostic ignored "-Wsign-compare" #ifdef USE_INITIALIZER_LIST #pragma GCC diagnostic ignored "-Wnarrowing" -#endif \ No newline at end of file +#endif + +#undef rewind \ No newline at end of file diff --git a/src/AudioHttp/HLSStream.h b/src/AudioHttp/HLSStream.h index a34eff5e61..aa2b382aa1 100644 --- a/src/AudioHttp/HLSStream.h +++ b/src/AudioHttp/HLSStream.h @@ -34,7 +34,8 @@ class URLLoader { void end(){ TRACED(); - stream.end(); + p_stream->end(); + p_stream = nullptr; buffer.clear(); active = false; } @@ -42,10 +43,17 @@ class URLLoader { /// Adds the next url to be played in sequence void addUrl(const char* url){ LOGI("Adding %s", url); - Str url_str(url); - char *str = new char[url_str.length()+1]; - memcpy(str, url_str.c_str(), url_str.length()+1); - urls.push_back(str); + //Str url_str(url); + //char *str = new char[url_str.length()+1]; + //memcpy(str, url_str.c_str(), url_str.length()+1); + URLStream *p_stream = new URLStream(); + p_stream->setWaitForData(false); + p_stream->setAutoCreateLines(false); + if (!p_stream->begin(url)){ + TRACEE(); + } + + urls.push_back(p_stream); } /// Provides the number of open urls which can be played. Refills them, when min limit is reached. @@ -71,13 +79,13 @@ class URLLoader { } const char *contentType() { - if (!stream) return nullptr; - return stream.httpRequest().reply().get(CONTENT_TYPE); + if (p_stream==nullptr) return nullptr; + return p_stream->httpRequest().reply().get(CONTENT_TYPE); } int contentLength() { - if (!stream) return 0; - return stream.contentLength(); + if (p_stream==nullptr) return 0; + return p_stream->contentLength(); } void setBuffer(int size, int count){ @@ -86,12 +94,12 @@ class URLLoader { } protected: - Vector urls{10}; + Vector urls{10}; NBuffer buffer{DEFAULT_BUFFER_SIZE, 50}; bool active = false; int buffer_size = DEFAULT_BUFFER_SIZE; int buffer_count = 10; - URLStream stream; + URLStream *p_stream = nullptr; /// try to keep the buffer filled @@ -108,34 +116,30 @@ class URLLoader { } // switch current stream if we have no more data - if ((!stream || stream.totalRead()==stream.contentLength()) && !urls.empty()) { + if ((p_stream==nullptr || p_stream->totalRead()==p_stream->contentLength()) && !urls.empty()) { LOGD("Refilling"); - const char* url = urls[0]; + if (p_stream!=nullptr) { + p_stream->end(); + delete p_stream; + } + p_stream = urls[0]; + p_stream->waitForData(); urls.pop_front(); - assert(urls[0]!=url); + //assert(urls[0]!=url); #ifdef ESP32 LOGI("Free heap: %d", ESP.getFreeHeap()); #endif - LOGI("Playing %s of %d", url, urls.size()); - - stream.clear(); - stream.setWaitForData(true); - stream.setAutoCreateLines(false); - if (!stream.begin(url)){ - TRACEE(); - } - // free memory - delete[] url; + LOGI("Playing %s of %d", p_stream->urlStr(), urls.size()); } int to_write = min(buffer.availableForWrite(),DEFAULT_BUFFER_SIZE); if (to_write>0){ int total = 0; while(to_write>0){ - if (stream.totalRead()==stream.contentLength()) break; + if (p_stream->totalRead()==p_stream->contentLength()) break; uint8_t tmp[to_write]={0}; - int read = stream.readBytes(tmp, to_write); + int read = p_stream->readBytes(tmp, to_write); total += read; if (read>0){ buffer.writeArray(tmp, read);