diff --git a/examples/examples-desktop/hls/hls.ino b/examples/examples-desktop/hls/hls.ino deleted file mode 100644 index e7c384627d..0000000000 --- a/examples/examples-desktop/hls/hls.ino +++ /dev/null @@ -1,35 +0,0 @@ -#include "AudioTools.h" -#include "AudioCodecs/CodecMTS.h" -#include "AudioCodecs/CodecAACHelix.h" - - -// HLSStream hls(out,"SSID", "PWD"); -const int buffer_size = 1024; -CsvOutput out(Serial, 2); // Or use StdOuput -MTSDecoder decoder; -AACDecoderHelix aac; -EncodedAudioStream dec_str(&out, &aac); // Decoding stream -EncodedAudioStream mts_str(&dec_str, &decoder); - -FILE *file; -uint8_t buffer[buffer_size]; - -// Arduino Setup -void setup(void) { - // Serial.begin(115200); - AudioLogger::instance().begin(Serial, AudioLogger::Debug); - - file = fopen("/home/pschatzmann/Downloads/test.ts", "rb"); - dec_str.begin(); - mts_str.begin(); -} - -// Arduino loop -void loop() { - size_t fileSize = fread(buffer, 1, buffer_size, file); - if (fileSize > 0) { - int written = mts_str.write(buffer, fileSize); - LOGI("written %d, ", written); - fileSize = fread(buffer, 1, buffer_size, file); - } -} \ No newline at end of file diff --git a/examples/tests/test-vector/test-vector.ino b/examples/tests/test-vector/test-vector.ino new file mode 100644 index 0000000000..6e348d7eab --- /dev/null +++ b/examples/tests/test-vector/test-vector.ino @@ -0,0 +1,89 @@ + +#include "AudioTools.h" + +void print(const char *title, Vector &vector) { + Serial.println(title); + for (int j = 0; j < vector.size(); j++) { + Serial.print(vector[j]); + Serial.print(" "); + } + Serial.println(); + Serial.println(); +} + +void testPushBack() { + Vector vector; + for (int j = 0; j < 10; j++) { + vector.push_back(j); + } + print("testPushBack", vector); + for (int j = 0; j < 10; j++) { + assert(vector[j] == j); + } +} + +void testPushFront() { + Vector vector; + for (int j = 0; j < 10; j++) { + vector.push_front(j); + } + print("testPushFront", vector); + + for (int j = 0; j < 10; j++) { + assert(vector[9 - j] == j); + } +} + +void testPopFront() { + Vector vector; + for (int j = 0; j < 10; j++) { + vector.push_back(j); + } + vector.pop_front(); + print("testPopFront", vector); + + assert(vector.size() == 9); + for (int j = 0; j < 9; j++) { + assert(vector[j] == j + 1); + } +} + +void testPopBack() { + Vector vector; + for (int j = 0; j < 10; j++) { + vector.push_back(j); + } + vector.pop_back(); + print("testPopBack", vector); + + assert(vector.size() == 9); + for (int j = 0; j < 9; j++) { + assert(vector[j] == j); + } +} + +void testErase() { + Vector vector; + for (int j = 0; j < 10; j++) { + vector.push_back(j); + } + vector.erase(0); + print("testErase", vector); + + assert(vector.size() == 9); + for (int j = 0; j < 9; j++) { + assert(vector[j] == j + 1); + } +} + +void setup() { + Serial.begin(115200); + testPushBack(); + testPushFront(); + testPopFront(); + testPopBack(); + testErase(); + Serial.print("All tests passed"); +} + +void loop() {} \ No newline at end of file diff --git a/src/AudioBasic/Collections/Vector.h b/src/AudioBasic/Collections/Vector.h index 7feeb86578..b8b9b14c3a 100644 --- a/src/AudioBasic/Collections/Vector.h +++ b/src/AudioBasic/Collections/Vector.h @@ -188,8 +188,7 @@ class Vector { } inline void pop_front(){ - erase(0); - + erase(0); } diff --git a/src/AudioBasic/Str.h b/src/AudioBasic/Str.h index f2854a05b8..15bb927c85 100644 --- a/src/AudioBasic/Str.h +++ b/src/AudioBasic/Str.h @@ -555,7 +555,8 @@ class Str { /// remove leading spaces virtual void ltrim(){ int n = count(' ',0); - *this << n; + if (n > 0) + *this << n; } /// remove trailing spaces diff --git a/src/AudioBasic/StrExt.h b/src/AudioBasic/StrExt.h index bd05a8cb4f..5565628785 100644 --- a/src/AudioBasic/StrExt.h +++ b/src/AudioBasic/StrExt.h @@ -27,6 +27,7 @@ class StrExt : public Str { StrExt(int initialAllocatedLength) : Str() { maxlen = initialAllocatedLength; + is_const = false; } StrExt(Str &source) : Str() { @@ -52,7 +53,10 @@ class StrExt : public Str { StrExt (StrExt &&obj) = default; // move assignment - StrExt& operator = (StrExt &&obj) = default; + StrExt& operator = (StrExt &&obj) { + set(obj.c_str()); + return *this; + } // copy assingment StrExt& operator = (StrExt &obj) { @@ -61,19 +65,14 @@ class StrExt : public Str { }; - ~StrExt() { - if (chars!=nullptr){ - LOGD("delete %d",maxlen); - delete [] chars; - chars = nullptr; - } + ~StrExt() { } - bool isOnHeap() { + bool isOnHeap() override { return true; } - bool isConst() { + bool isConst() override { return false; } @@ -134,9 +133,11 @@ class StrExt : public Str { } protected: + Vector vector; bool grow(int newMaxLen){ bool grown = false; + assert(newMaxLen<1024*10); if (chars==nullptr || newMaxLen > maxlen ){ LOGD("grow(%d)",newMaxLen); @@ -144,18 +145,8 @@ class StrExt : public Str { grown = true; // we use at minimum the defined maxlen int newSize = newMaxLen > maxlen ? newMaxLen : maxlen; - if (chars!=nullptr){ - char* tmp = chars; - chars = new char[newSize+1]; - if (chars!=nullptr){ - strcpy(chars,tmp); - } - delete [] tmp; - } else { - chars = new char[newSize+1]; - if (chars!=nullptr) - chars[0] = 0; - } + vector.resize(newSize+1); + chars = &vector[0]; maxlen = newSize; } diff --git a/src/AudioCodecs/AudioEncoded.h b/src/AudioCodecs/AudioEncoded.h index 730f8fe503..12df777848 100644 --- a/src/AudioCodecs/AudioEncoded.h +++ b/src/AudioCodecs/AudioEncoded.h @@ -380,7 +380,7 @@ class EncodedAudioOutput : public AudioStream { return result; } - int availableForWrite() override { return ptr_out->availableForWrite(); } + int availableForWrite() override { return min(ptr_out->availableForWrite(), DEFAULT_BUFFER_SIZE); } /// Returns true if status is active and we still have data to be processed operator bool() { return active; } diff --git a/src/AudioCodecs/CodecAACHelix.h b/src/AudioCodecs/CodecAACHelix.h index d8369eb74e..c8d03d0203 100644 --- a/src/AudioCodecs/CodecAACHelix.h +++ b/src/AudioCodecs/CodecAACHelix.h @@ -104,8 +104,7 @@ class AACDecoderHelix : public AudioDecoder { } void setAudioInfo(AudioInfo info) override { - AudioDecoder::setAudioInfo(info); - //aac->setAudioInfo(info.channels, info.sample_rate); + this->info = info; if(p_notify!=nullptr && info_notifications_active){ p_notify->setAudioInfo(info); } @@ -114,7 +113,16 @@ class AACDecoderHelix : public AudioDecoder { /// Write AAC data to decoder size_t write(const void* aac_data, size_t len) override { LOGD("AACDecoderHelix::write: %d", (int)len); - return aac==nullptr ? 0 : aac->write(aac_data, len); + if (aac==nullptr) return 0; + int open = len; + int processed = 0; + uint8_t *data = (uint8_t*)aac_data; + while(open>0){ + int act_write = aac->write(data+processed, min(open, DEFAULT_BUFFER_SIZE)); + open -= act_write; + processed += act_write; + } + return processed; } /// checks if the class is active diff --git a/src/AudioCodecs/CodecADTS.h b/src/AudioCodecs/CodecADTS.h index 9d736e9ea4..32dbe40892 100644 --- a/src/AudioCodecs/CodecADTS.h +++ b/src/AudioCodecs/CodecADTS.h @@ -133,7 +133,7 @@ class ADTSDecoder : public AudioDecoder { /// Write AAC data to decoder size_t write(const void *dataIn, size_t len) override { - LOGD("ADTSDecoder::write: %d", len); + LOGD("AACDecoderADTS::write: %d", (int)len); // make sure that we can hold at least the len if (buffer.size() < len) { @@ -225,7 +225,7 @@ class ADTSDecoder : public AudioDecoder { void resizeBuffer() { if (parser.size() > buffer.size()) { - LOGI("resize buffer %d to %d", buffer.size(), parser.size()); + LOGI("resize buffer %d to %d", (int)buffer.size(), (int)parser.size()); buffer.resize(parser.size()); buffer_write_size = parser.size(); } diff --git a/src/AudioCodecs/CodecMTS.h b/src/AudioCodecs/CodecMTS.h index 526efc820f..93c518ffce 100644 --- a/src/AudioCodecs/CodecMTS.h +++ b/src/AudioCodecs/CodecMTS.h @@ -252,7 +252,7 @@ class MTSDecoder : public AudioDecoder { TSDPESPacket *pes = (TSDPESPacket *)data; // This is where we write the PES data into our buffer. LOGD("===================="); - LOGD("PID %d PES Packet, Size: %ld, stream_id=%u, pts=%lu, dts=%lu", pid, + LOGD("PID %x PES Packet, Size: %ld, stream_id=%u, pts=%lu, dts=%lu", pid, pes->data_bytes_length, pes->stream_id, pes->pts, pes->dts); // print out the PES Packet data if it's in our print list int i; @@ -261,7 +261,7 @@ class MTSDecoder : public AudioDecoder { if (print_pids[i] == pid) { // log data if (logger.isLogging(AudioLogger::Debug)) { - logger.print(" PES data "); + logger.print(" PES data"); logger.print(is_write_active? "active:":"inactive:"); int j = 0; while (j < pes->data_bytes_length) { @@ -862,24 +862,24 @@ class MTSDecoder : public AudioDecoder { static void* log_malloc (size_t size) { void *result = malloc(size); - LOGI("malloc(%d) -> %p %s\n", (int)size,result, result!=NULL?"OK":"ERROR"); + LOGI("malloc(%d) -> %p %s", (int)size,result, result!=NULL?"OK":"ERROR"); return result; } static void* log_calloc(size_t num, size_t size){ void *result = calloc(num, size); - LOGI("calloc(%d) -> %p %s\n", (int)(num*size),result, result!=NULL?"OK":"ERROR"); + LOGI("calloc(%d) -> %p %s", (int)(num*size),result, result!=NULL?"OK":"ERROR"); return result; } static void* log_realloc(void *ptr, size_t size){ void *result = realloc(ptr, size); - LOGI("realloc(%d) -> %p %s\n", (int)size, result, result!=NULL?"OK":"ERROR"); + LOGI("realloc(%d) -> %p %s", (int)size, result, result!=NULL?"OK":"ERROR"); return result; } static void log_free (void *mem){ - LOGD("free(%p)\n", mem); + LOGD("free(%p)", mem); free(mem); } diff --git a/src/AudioConfig.h b/src/AudioConfig.h index e246a36c7b..63e90a0fb3 100644 --- a/src/AudioConfig.h +++ b/src/AudioConfig.h @@ -51,7 +51,7 @@ #define LOG_STREAM Serial #endif -#define LOG_PRINTF_BUFFER_SIZE 256 +#define LOG_PRINTF_BUFFER_SIZE 303 #define LOG_METHOD __PRETTY_FUNCTION__ // cheange USE_CHECK_MEMORY to 1 to activate memory checks @@ -648,6 +648,7 @@ using WiFiServerSecure = BearSSL::WiFiServerSecure; #ifdef IS_DESKTOP # include # include +# define USE_WIFI # define USE_URL_ARDUINO # define USE_STREAM_WRITE_OVERRIDE # define USE_STREAM_READ_OVERRIDE diff --git a/src/AudioHttp/HLSStream.h b/src/AudioHttp/HLSStream.h index b905b90ae9..ce27ec1634 100644 --- a/src/AudioHttp/HLSStream.h +++ b/src/AudioHttp/HLSStream.h @@ -6,7 +6,7 @@ #include "AudioBasic/StrExt.h" #include "AudioHttp/URLStream.h" -#define MAX_HLS_LINE 400 +#define MAX_HLS_LINE 512 namespace audio_tools { @@ -27,6 +27,7 @@ class URLLoader { bool begin() { TRACED(); + buffer.resize(buffer_size, buffer_count); active = true; return true; } @@ -74,15 +75,22 @@ class URLLoader { return stream.httpRequest().reply().get(CONTENT_TYPE); } - const char *contentLength() { - if (!stream) return nullptr; - return stream.httpRequest().reply().get(CONTENT_LENGTH); + int contentLength() { + if (!stream) return 0; + return stream.contentLength(); + } + + void setBuffer(int size, int count){ + buffer_size = size; + buffer_count = count; } protected: Vector urls{10}; - NBuffer buffer{DEFAULT_BUFFER_SIZE, 50}; + NBuffer buffer{DEFAULT_BUFFER_SIZE, 10}; bool active = false; + int buffer_size = DEFAULT_BUFFER_SIZE; + int buffer_count = 10; URLStream stream; @@ -90,12 +98,18 @@ class URLLoader { void bufferRefill() { TRACED(); // we have nothing to do - if (urls.empty()) return; - if (buffer.availableForWrite()==0) return; + if (urls.empty()) { + LOGD("urls empty"); + return; + } + if (buffer.availableForWrite()==0) { + LOGD("buffer full"); + return; + } // switch current stream if we have no more data if ((!stream || stream.totalRead()==stream.contentLength()) && !urls.empty()) { - assert(stream.available()==0); + LOGD("Refilling"); const char* url = urls[0]; urls.pop_front(); assert(urls[0]!=url); @@ -106,26 +120,26 @@ class URLLoader { LOGI("Playing %s of %d", url, urls.size()); stream.clear(); - stream.setWaitForData(false); + stream.setWaitForData(true); if (!stream.begin(url)){ TRACEE(); } // free memory delete(url); - return; } // copy data to buffer - stream.waitForData(); + //LOGD("waitForData"); + //stream.waitForData(); 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; uint8_t tmp[to_write]={0}; int read = stream.readBytes(tmp, to_write); total += read; if (read>0){ - if (stream.totalRead()==stream.contentLength()) break; buffer.writeArray(tmp, read); to_write = min(buffer.availableForWrite(),DEFAULT_BUFFER_SIZE); } else { @@ -242,14 +256,13 @@ class HLSParser { return url_loader.contentType(); } - const char *contentLength() { + int contentLength() { return url_loader.contentLength(); } /// Closes the processing void end() { TRACEI(); - //timer.end(); codec.clear(); segments_url_str.clear(); url_stream.end(); @@ -267,6 +280,10 @@ class HLSParser { custom_log_level.set(level); } + void setBuffer(int size, int count){ + url_loader.setBuffer(size, count); + } + protected: CustomLogLevel custom_log_level; int bandwidth = 0; @@ -509,7 +526,7 @@ class HLSStream : public AudioStream { return parser.contentType(); } - const char *contentLength() { + int contentLength() { return parser.contentLength(); } @@ -528,6 +545,11 @@ class HLSStream : public AudioStream { parser.setLogLevel(level); } + /// Defines the buffer size + void setBuffer(int size, int count){ + parser.setBuffer(size, count); + } + protected: HLSParser parser; const char* ssid = nullptr; @@ -547,8 +569,6 @@ class HLSStream : public AudioStream { LOGW("login not supported"); #endif } - - }; } // namespace audio_tools diff --git a/src/AudioHttp/HttpHeader.h b/src/AudioHttp/HttpHeader.h index b9cc07253c..d67a5e99a4 100644 --- a/src/AudioHttp/HttpHeader.h +++ b/src/AudioHttp/HttpHeader.h @@ -80,7 +80,8 @@ class HttpHeader { if (activeFlag){ (*it)->active = false; } else { - delete *it; + (*it)->active = false; + //delete *it; // this leads to exceptions } } if (!activeFlag){ @@ -195,8 +196,8 @@ class HttpHeader { msg[len-2] = 0; LOGI(" -> %s ", msg); - // marke as processed - header->active = false; + // mark as processed + // header->active = false; } const char* urlPath() { @@ -243,6 +244,7 @@ class HttpHeader { } LOGI("Data availble"); } + readLine(in, line, MAX_HTTP_HEADER_LINE_LENGTH); parse1stLine(line); while (in.available()){ @@ -254,11 +256,9 @@ class HttpHeader { break; } put(line); - } + } } - } else { - LOGW("connection lost"); - } + } } /// writes the full header to the indicated HttpStreamedMultiOutput stream @@ -274,6 +274,12 @@ class HttpHeader { is_written = true; } + void setProcessed() { + for (auto it = lines.begin() ; it != lines.end(); ++it){ + (*it)->active = false; + } + } + /// automatically create new lines void setAutoCreateLines(bool is_auto_line){ create_new_lines = is_auto_line; diff --git a/src/AudioHttp/HttpRequest.h b/src/AudioHttp/HttpRequest.h index c72b9b192e..82da70d593 100644 --- a/src/AudioHttp/HttpRequest.h +++ b/src/AudioHttp/HttpRequest.h @@ -237,7 +237,7 @@ class HttpRequest { if (!this->connected()){ LOGI("process connecting to host %s port %d", url.host(), url.port()); int is_connected = connect(url.host(), url.port(), clientTimeout); - if (is_connected!=1){ + if (!is_connected){ LOGE("Connect failed"); return false; } @@ -249,6 +249,9 @@ class HttpRequest { LOGI("Free heap: %u", ESP.getFreeHeap()); #endif + reply_header.setProcessed(); + + host_name = url.host(); request_header.setValues(action, url.path()); if (lenData>0){ @@ -330,7 +333,7 @@ class HttpRequest { LOGI("connected %d timeout %d", is_connected, (int) timeout); return is_connected; } - + }; } diff --git a/src/AudioHttp/URLStream.h b/src/AudioHttp/URLStream.h index 601a7f6b2d..558fafb223 100644 --- a/src/AudioHttp/URLStream.h +++ b/src/AudioHttp/URLStream.h @@ -52,6 +52,9 @@ class URLStream : public AbstractURLStream { setPassword(password); } + URLStream(const URLStream&) = delete; + + ~URLStream(){ TRACED(); end(); @@ -93,7 +96,7 @@ class URLStream : public AbstractURLStream { url.setUrl(url_str.c_str()); int result = -1; - // close it - if we have an active connection +// close it - if we have an active connection if (active) end(); // optional: login if necessary @@ -232,8 +235,8 @@ class URLStream : public AbstractURLStream { wait_for_data = flag; } - size_t contentLength() { - return request.contentLength(); + int contentLength() { + return size; } size_t totalRead() { @@ -387,7 +390,6 @@ class URLStream : public AbstractURLStream { delay(500); } #else - LOGE("login not supported"); #endif } diff --git a/src/AudioLibs/Desktop/NoArduino.h b/src/AudioLibs/Desktop/NoArduino.h index 730a25743d..4b01e8af41 100644 --- a/src/AudioLibs/Desktop/NoArduino.h +++ b/src/AudioLibs/Desktop/NoArduino.h @@ -82,13 +82,13 @@ class Print { } virtual int print(char c, PrintCharFmt spec){ - char result[3]; + char result[5]; switch(spec){ case DEC: snprintf(result, 3,"%c", c); return print(result); case HEX: - snprintf(result, 3,"%x", c & 0xff); + snprintf(result, 3,"%x", c); return print(result); } return -1; diff --git a/src/AudioLibs/PortAudioStream.h b/src/AudioLibs/PortAudioStream.h index 5efe05cf9f..e383f0d4cb 100644 --- a/src/AudioLibs/PortAudioStream.h +++ b/src/AudioLibs/PortAudioStream.h @@ -189,10 +189,6 @@ class PortAudioStream : public AudioStream { return len; } - int available() override { - return DEFAULT_BUFFER_SIZE; - } - protected: PaStream *stream = nullptr; @@ -219,7 +215,7 @@ class PortAudioStream : public AudioStream { /// automatically start the stream when we start to get data void startStream() { - if (!stream_started) { + if (!stream_started && stream != nullptr) { TRACED(); err = Pa_StartStream( stream ); if( err == paNoError ) { diff --git a/src/AudioTools/AudioStreams.h b/src/AudioTools/AudioStreams.h index 1ccf40c2df..48c2f16125 100644 --- a/src/AudioTools/AudioStreams.h +++ b/src/AudioTools/AudioStreams.h @@ -1582,6 +1582,87 @@ class CallbackStream : public AudioStream { size_t (*cb_read)(uint8_t* data, size_t len) = nullptr; }; +/** + * @brief Provides data from a concatenation of Streams. Please note that the provided + * Streams can be played only once! You will need to reset them (e.g. moving the file pointer to the beginning) + * and readd them back if you want to process them a second time. The default timeout on the available() method + * is set to 0. This might be not good if you use e.g. a URLStream. + * @ingroup io + * @author Phil Schatzmann + * @copyright GPLv3 + */ +class CatStream : public AudioStream { + CatStream(){ + _timeout = 0; + } + void add(Stream *stream){ + input_streams.push_back(stream); + } + void add(Stream &stream){ + input_streams.push_back(&stream); + } + + bool begin() override { + is_active = true; + return AudioStream::begin(); + } + + void end() override { + is_active = false; + return AudioStream::end(); + } + + int available() override { + if (!is_active) return 0; + if (!moveToNextStreamOnEnd()){ + return 0; + } + return availableWithTimout(); + } + + size_t readBytes(uint8_t* data, size_t len) override { + if (!is_active) return 0; + if (!moveToNextStreamOnEnd()){ + return 0; + } + return p_current_stream->readBytes(data, len); + } + + /// Returns true if active and we still have data + operator bool(){ + return is_active && available()>0; + } + + +protected: + Vector input_streams; + Stream *p_current_stream = nullptr; + bool is_active = false; + + /// moves to the next stream if necessary: returns true if we still have a valid stream + bool moveToNextStreamOnEnd(){ + if ((p_current_stream==nullptr || availableWithTimout()) && !input_streams.empty()){ + p_current_stream = input_streams[0]; + input_streams.pop_front(); + } + // returns true if we have a valid stream + return p_current_stream!=nullptr; + } + + int availableWithTimout(){ + int result = p_current_stream->available(); + if (result==0){ + for (int j=0; j <_timeout/10;j++){ + delay(10); + result = p_current_stream->available(); + if (result!=0) break; + } + } + return result; + } + +}; + /** * @brief Stream to which we can apply Filters for each channel. The filter * might change the result size! diff --git a/src/AudioTools/Buffers.h b/src/AudioTools/Buffers.h index df9b4084af..b3cd107c81 100644 --- a/src/AudioTools/Buffers.h +++ b/src/AudioTools/Buffers.h @@ -549,35 +549,11 @@ template class NBuffer : public BaseBuffer { public: NBuffer(int size, int count) { - filled_buffers.resize(count); - avaliable_buffers.resize(count); - - write_buffer_count = 0; - buffer_count = count; - buffer_size = size; - for (int j = 0; j < count; j++) { - avaliable_buffers[j] = new SingleBuffer(size); - if (avaliable_buffers[j] == nullptr) { - LOGE("Not Enough Memory for buffer %d", j); - } - } + resize(size, count); } virtual ~NBuffer() { - delete actual_write_buffer; - delete actual_read_buffer; - - BaseBuffer *ptr = getNextAvailableBuffer(); - while (ptr != nullptr) { - delete ptr; - ptr = getNextAvailableBuffer(); - } - - ptr = getNextFilledBuffer(); - while (ptr != nullptr) { - delete ptr; - ptr = getNextFilledBuffer(); - } + freeMemory(); } // reads an entry from the buffer @@ -724,7 +700,23 @@ class NBuffer : public BaseBuffer { return result; } - void setBufferSize(int size) { buffer_size = size; } + void resize(int size, int count) { + if (buffer_size==size && buffer_count == count) + return; + freeMemory(); + filled_buffers.resize(count); + avaliable_buffers.resize(count); + + write_buffer_count = 0; + buffer_count = count; + buffer_size = size; + for (int j = 0; j < count; j++) { + avaliable_buffers[j] = new SingleBuffer(size); + if (avaliable_buffers[j] == nullptr) { + LOGE("Not Enough Memory for buffer %d", j); + } + } + } protected: int buffer_size = 0; @@ -740,6 +732,25 @@ class NBuffer : public BaseBuffer { // empty constructor only allowed by subclass NBuffer() = default; + void freeMemory() { + delete actual_write_buffer; + actual_write_buffer = nullptr; + delete actual_read_buffer; + actual_read_buffer = nullptr; + + BaseBuffer *ptr = getNextAvailableBuffer(); + while (ptr != nullptr) { + delete ptr; + ptr = getNextAvailableBuffer(); + } + + ptr = getNextFilledBuffer(); + while (ptr != nullptr) { + delete ptr; + ptr = getNextFilledBuffer(); + } + } + void resetCurrent() { if (actual_read_buffer != nullptr) { actual_read_buffer->reset(); diff --git a/examples/examples-desktop/hls/CMakeLists.txt b/tests-cmake/hls/CMakeLists.txt similarity index 72% rename from examples/examples-desktop/hls/CMakeLists.txt rename to tests-cmake/hls/CMakeLists.txt index 8bca17ca17..574ca94855 100644 --- a/examples/examples-desktop/hls/CMakeLists.txt +++ b/tests-cmake/hls/CMakeLists.txt @@ -9,12 +9,12 @@ set (DCMAKE_CXX_FLAGS "-Werror") include(FetchContent) # Deactivate Emulator and Portaudio -set(ADD_ARDUINO_EMULATOR OFF CACHE BOOL "Add Arduino Emulator Library") +set(ADD_ARDUINO_EMULATOR ON CACHE BOOL "Add Arduino Emulator Library") set(ADD_PORTAUDIO OFF CACHE BOOL "Add Portaudio Library") # Build with arduino-audio-tools if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) - add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../.. ${CMAKE_CURRENT_BINARY_DIR}/arduino-audio-tools ) +add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../.. ${CMAKE_CURRENT_BINARY_DIR}/arduino-audio-tools ) endif() # Build with tms @@ -36,13 +36,13 @@ endif() # build sketch as executable set_source_files_properties(hls.ino PROPERTIES LANGUAGE CXX) -add_executable (hls hls.ino) +add_executable (hls hls.cpp ../main.cpp ) # set preprocessor defines -target_compile_definitions(hls PUBLIC -DIS_MIN_DESKTOP -DEXIT_ON_STOP -DHELIX_PRINT) +target_compile_definitions(hls PUBLIC -DARDUINO -DIS_DESKTOP -DEXIT_ON_STOP -DHELIX_PRINT) # specify libraries -target_link_libraries(hls arduino-audio-tools tsdemux arduino_helix) +target_link_libraries(hls arduino-audio-tools arduino_emulator tsdemux arduino_helix portaudio) diff --git a/tests-cmake/hls/hls.cpp b/tests-cmake/hls/hls.cpp new file mode 100644 index 0000000000..cc80ee36d3 --- /dev/null +++ b/tests-cmake/hls/hls.cpp @@ -0,0 +1,46 @@ +#include "AudioTools.h" +#include "AudioCodecs/CodecMTS.h" +#include "AudioCodecs/CodecADTS.h" +#include "AudioCodecs/CodecAACHelix.h" +#include "AudioLibs/PortAudioStream.h" + +AudioInfo info(48000,2,16); +HLSStream hls_stream("NA", "NA"); +// HexDumpOutput hex(Serial); +// NullStream null; +//CsvOutput out(Serial, 2); // Or use StdOuput +PortAudioStream out; +MTSDecoder mts; +AACDecoderADTS adts; +AACDecoderHelix aac; +EncodedAudioStream aac_stream(&out, &aac); +EncodedAudioStream adts_stream(&aac_stream, &adts); +EncodedAudioStream mts_stream(&adts_stream, &mts); +StreamCopy copier(mts_stream, hls_stream); + +// Arduino Setup +void setup(void) { + //Serial.begin(115200); + AudioLogger::instance().begin(Serial, AudioLogger::Info); + //hls_stream.setLogLevel(AudioLogger::Debug); // hls_stream is quite chatty at Info + //adts_stream.setLogLevel(AudioLogger::Debug); + mts_stream.setLogLevel(AudioLogger::Debug); + + aac.setAudioInfoNotifications(false); + + auto cfg = out.defaultConfig(TX_MODE); + cfg.copyFrom(info); + out.begin(); + + mts_stream.begin(); + aac_stream.begin(); + adts_stream.begin(); + + hls_stream.begin("http://a.files.bbci.co.uk/media/live/manifesto/audio/simulcast/hls/nonuk/sbr_vlow/ak/bbc_world_service.m3u8"); + Serial.println("playing..."); +} + +// Arduino loop +void loop() { + copier.copy(); +} diff --git a/tests-cmake/url-test/url-test.cpp b/tests-cmake/url-test/url-test.cpp index efa54d15b8..0577518089 100644 --- a/tests-cmake/url-test/url-test.cpp +++ b/tests-cmake/url-test/url-test.cpp @@ -9,7 +9,7 @@ StreamCopy copier(null_out, url); // copy url to decoder void setup(){ Serial.begin(115200); - AudioLogger::instance().begin(Serial, AudioLogger::Debug); + AudioLogger::instance().begin(Serial, AudioLogger::Info); // mp3 radio url.begin("http://stream.srg-ssr.ch/m/rsj/mp3_128","audio/mp3"); }