acid-drop

- Hacking the planet from a LilyGo T-Deck using custom firmware
git clone git://git.acid.vegas/acid-drop.git
Log | Files | Refs | Archive | README | LICENSE

Audio.h (26309B)

      1 /*
      2  * Audio.h
      3  *
      4  *  Created on: Oct 28,2018
      5  *  Updated on: Nov 22,2022
      6  *      Author: Wolle (schreibfaul1)
      7  */
      8 
      9 //#define SDFATFS_USED  // activate for SdFat
     10 
     11 
     12 #pragma once
     13 #pragma GCC optimize ("Ofast")
     14 #include <vector>
     15 #include <Arduino.h>
     16 #include <libb64/cencode.h>
     17 #include <esp32-hal-log.h>
     18 
     19 #include <WiFi.h>
     20 #include <WiFiClientSecure.h>
     21 #include <vector>
     22 #include <driver/i2s.h>
     23 
     24 #ifndef AUDIO_NO_SD_FS
     25 #include <SPI.h>
     26 #ifdef SDFATFS_USED
     27 #include <SdFat.h>  // https://github.com/greiman/SdFat
     28 #else
     29 #include <SD.h>
     30 #include <SD_MMC.h>
     31 #include <SPIFFS.h>
     32 #include <FS.h>
     33 #include <FFat.h>
     34 #endif // SDFATFS_USED
     35 
     36 
     37 #ifdef SDFATFS_USED
     38 //typedef File32 File;
     39 typedef FsFile File;
     40 
     41 namespace fs {
     42     class FS : public SdFat {
     43     public:
     44         bool begin(SdCsPin_t csPin = SS, uint32_t maxSck = SD_SCK_MHZ(25)) { return SdFat::begin(csPin, maxSck); }
     45     };
     46 
     47     class SDFATFS : public fs::FS {
     48     public:
     49         // sdcard_type_t cardType();
     50         uint64_t cardSize() {
     51             return totalBytes();
     52         }
     53         uint64_t usedBytes() {
     54             // set SdFatConfig MAINTAIN_FREE_CLUSTER_COUNT non-zero. Then only the first call will take time.
     55             return (uint64_t)(clusterCount() - freeClusterCount()) * (uint64_t)bytesPerCluster();
     56         }
     57         uint64_t totalBytes() {
     58             return (uint64_t)clusterCount() * (uint64_t)bytesPerCluster();
     59         }
     60     };
     61 }
     62 
     63 extern fs::SDFATFS SD_SDFAT;
     64 
     65 using namespace fs;
     66 #define SD SD_SDFAT
     67 #endif //SDFATFS_USED
     68 #endif // AUDIO_NO_SD_FS
     69 
     70 using namespace std;
     71 
     72 extern __attribute__((weak)) void audio_info(const char *);
     73 extern __attribute__((weak)) void audio_id3data(const char *); // ID3 metadata
     74 #ifndef AUDIO_NO_SD_FS
     75 extern __attribute__((weak)) void audio_id3image(File& file, const size_t pos, const size_t size); // ID3 metadata image
     76 #endif
     77 extern __attribute__((weak)) void audio_eof_mp3(const char*); //end of mp3 file
     78 extern __attribute__((weak)) void audio_showstreamtitle(const char*);
     79 extern __attribute__((weak)) void audio_showstation(const char *);
     80 extern __attribute__((weak)) void audio_bitrate(const char*);
     81 extern __attribute__((weak)) void audio_commercial(const char*);
     82 extern __attribute__((weak)) void audio_icyurl(const char*);
     83 extern __attribute__((weak)) void audio_icydescription(const char*);
     84 extern __attribute__((weak)) void audio_lasthost(const char*);
     85 extern __attribute__((weak)) void audio_eof_speech(const char*);
     86 extern __attribute__((weak)) void audio_eof_stream(const char*); // The webstream comes to an end
     87 extern __attribute__((weak)) void audio_process_extern(int16_t* buff, uint16_t len, bool *continueI2S); // record audiodata or send via BT
     88 extern __attribute__((weak)) void audio_process_i2s(uint32_t* sample, bool *continueI2S); // record audiodata or send via BT
     89 
     90 #define AUDIO_INFO(...) {char buff[512 + 64]; sprintf(buff,__VA_ARGS__); if(audio_info) audio_info(buff);}
     91 
     92 //----------------------------------------------------------------------------------------------------------------------
     93 
     94 class AudioBuffer {
     95 // AudioBuffer will be allocated in PSRAM, If PSRAM not available or has not enough space AudioBuffer will be
     96 // allocated in FlashRAM with reduced size
     97 //
     98 //  m_buffer            m_readPtr                 m_writePtr                 m_endPtr
     99 //   |                       |<------dataLength------->|<------ writeSpace ----->|
    100 //   ▼                       ▼                         ▼                         ▼
    101 //   ---------------------------------------------------------------------------------------------------------------
    102 //   |                     <--m_buffSize-->                                      |      <--m_resBuffSize -->     |
    103 //   ---------------------------------------------------------------------------------------------------------------
    104 //   |<-----freeSpace------->|                         |<------freeSpace-------->|
    105 //
    106 //
    107 //
    108 //   if the space between m_readPtr and buffend < m_resBuffSize copy data from the beginning to resBuff
    109 //   so that the mp3/aac/flac frame is always completed
    110 //
    111 //  m_buffer                      m_writePtr                 m_readPtr        m_endPtr
    112 //   |                                 |<-------writeSpace------>|<--dataLength-->|
    113 //   ▼                                 ▼                         ▼                ▼
    114 //   ---------------------------------------------------------------------------------------------------------------
    115 //   |                        <--m_buffSize-->                                    |      <--m_resBuffSize -->     |
    116 //   ---------------------------------------------------------------------------------------------------------------
    117 //   |<---  ------dataLength--  ------>|<-------freeSpace------->|
    118 //
    119 //
    120 
    121 public:
    122     AudioBuffer(size_t maxBlockSize = 0);       // constructor
    123     ~AudioBuffer();                             // frees the buffer
    124     size_t   init();                            // set default values
    125     bool     isInitialized() { return m_f_init; };
    126     void     setBufsize(int ram, int psram);
    127     void     changeMaxBlockSize(uint16_t mbs);  // is default 1600 for mp3 and aac, set 16384 for FLAC
    128     uint16_t getMaxBlockSize();                 // returns maxBlockSize
    129     size_t   freeSpace();                       // number of free bytes to overwrite
    130     size_t   writeSpace();                      // space fom writepointer to bufferend
    131     size_t   bufferFilled();                    // returns the number of filled bytes
    132     void     bytesWritten(size_t bw);           // update writepointer
    133     void     bytesWasRead(size_t br);           // update readpointer
    134     uint8_t* getWritePtr();                     // returns the current writepointer
    135     uint8_t* getReadPtr();                      // returns the current readpointer
    136     uint32_t getWritePos();                     // write position relative to the beginning
    137     uint32_t getReadPos();                      // read position relative to the beginning
    138     void     resetBuffer();                     // restore defaults
    139     bool     havePSRAM() { return m_f_psram; };
    140 
    141 protected:
    142     size_t   m_buffSizePSRAM    = 300000;   // most webstreams limit the advance to 100...300Kbytes
    143     size_t   m_buffSizeRAM      = 1600 * 5;
    144     size_t   m_buffSize         = 0;
    145     size_t   m_freeSpace        = 0;
    146     size_t   m_writeSpace       = 0;
    147     size_t   m_dataLength       = 0;
    148     size_t   m_resBuffSizeRAM   = 1600;     // reserved buffspace, >= one mp3  frame
    149     size_t   m_resBuffSizePSRAM = 4096 * 4; // reserved buffspace, >= one flac frame
    150     size_t   m_maxBlockSize     = 1600;
    151     uint8_t* m_buffer           = NULL;
    152     uint8_t* m_writePtr         = NULL;
    153     uint8_t* m_readPtr          = NULL;
    154     uint8_t* m_endPtr           = NULL;
    155     bool     m_f_start          = true;
    156     bool     m_f_init           = false;
    157     bool     m_f_psram          = false;    // PSRAM is available (and used...)
    158 };
    159 //----------------------------------------------------------------------------------------------------------------------
    160 
    161 class Audio : private AudioBuffer{
    162 
    163     AudioBuffer InBuff; // instance of input buffer
    164 
    165 public:
    166     Audio(bool internalDAC = false, uint8_t channelEnabled = 3, uint8_t i2sPort = I2S_NUM_0); // #99
    167     ~Audio();
    168     void setBufsize(int rambuf_sz, int psrambuf_sz);
    169     bool connecttohost(const char* host, const char* user = "", const char* pwd = "");
    170 
    171     bool connecttospeech(const char* speech, const char* lang);
    172     bool connecttomarytts(const char* speech, const char* lang, const char* voice);
    173 #ifndef AUDIO_NO_SD_FS
    174     bool connecttoFS(fs::FS &fs, const char* path, uint32_t resumeFilePos = 0);
    175     bool connecttoSD(const char* path, uint32_t resumeFilePos = 0);
    176 #endif                           // AUDIO_NO_SD_FS
    177     bool setFileLoop(bool input);//TEST loop
    178     void setConnectionTimeout(uint16_t timeout_ms, uint16_t timeout_ms_ssl);
    179     bool setAudioPlayPosition(uint16_t sec);
    180     bool setFilePos(uint32_t pos);
    181     bool audioFileSeek(const float speed);
    182     bool setTimeOffset(int sec);
    183     bool setPinout(uint8_t BCLK, uint8_t LRC, uint8_t DOUT, int8_t DIN = I2S_PIN_NO_CHANGE, int8_t MCK = I2S_PIN_NO_CHANGE);
    184     bool pauseResume();
    185     bool isRunning() {return m_f_running;}
    186     void loop();
    187     uint32_t stopSong();
    188     void forceMono(bool m);
    189     void setBalance(int8_t bal = 0);
    190     void setVolume(uint8_t vol);
    191     uint8_t getVolume();
    192     uint8_t getI2sPort();
    193 
    194     uint32_t getAudioDataStartPos();
    195     uint32_t getFileSize();
    196     uint32_t getFilePos();
    197     uint32_t getSampleRate();
    198     uint8_t  getBitsPerSample();
    199     uint8_t  getChannels();
    200     uint32_t getBitRate(bool avg = false);
    201     uint32_t getAudioFileDuration();
    202     uint32_t getAudioCurrentTime();
    203     uint32_t getTotalPlayingTime();
    204 
    205     esp_err_t i2s_mclk_pin_select(const uint8_t pin);
    206     uint32_t inBufferFilled(); // returns the number of stored bytes in the inputbuffer
    207     uint32_t inBufferFree();   // returns the number of free bytes in the inputbuffer
    208     void setTone(int8_t gainLowPass, int8_t gainBandPass, int8_t gainHighPass);
    209     void setI2SCommFMT_LSB(bool commFMT);
    210     int getCodec() {return m_codec;}
    211     const char *getCodecname() {return codecname[m_codec];}
    212 
    213 private:
    214 
    215     #ifndef ESP_ARDUINO_VERSION_VAL
    216         #define ESP_ARDUINO_VERSION_MAJOR 0
    217         #define ESP_ARDUINO_VERSION_MINOR 0
    218         #define ESP_ARDUINO_VERSION_PATCH 0
    219     #endif
    220 
    221     void UTF8toASCII(char* str);
    222     bool latinToUTF8(char* buff, size_t bufflen);
    223     void setDefaults(); // free buffers and set defaults
    224     void initInBuff();
    225     bool httpPrint(const char* host);
    226 #ifndef AUDIO_NO_SD_FS
    227     void processLocalFile();
    228 #endif // AUDIO_NO_SD_FS
    229     void processWebStream();
    230     void processWebFile();
    231     void processWebStreamTS();
    232     void processWebStreamHLS();
    233     void playAudioData();
    234     bool readPlayListData();
    235     const char* parsePlaylist_M3U();
    236     const char* parsePlaylist_PLS();
    237     const char* parsePlaylist_ASX();
    238     const char* parsePlaylist_M3U8();
    239     bool STfromEXTINF(char* str);
    240     void showCodecParams();
    241     int  findNextSync(uint8_t* data, size_t len);
    242     int  sendBytes(uint8_t* data, size_t len);
    243     void compute_audioCurrentTime(int bd);
    244     void printDecodeError(int r);
    245     void showID3Tag(const char* tag, const char* val);
    246     void unicode2utf8(char* buff, uint32_t len);
    247     size_t readAudioHeader(uint32_t bytes);
    248     int  read_WAV_Header(uint8_t* data, size_t len);
    249     int  read_FLAC_Header(uint8_t *data, size_t len);
    250     int  read_ID3_Header(uint8_t* data, size_t len);
    251     int  read_M4A_Header(uint8_t* data, size_t len);
    252     int  read_OGG_Header(uint8_t *data, size_t len);
    253     size_t process_m3u8_ID3_Header(uint8_t* packet);
    254     bool setSampleRate(uint32_t hz);
    255     bool setBitsPerSample(int bits);
    256     bool setChannels(int channels);
    257     bool setBitrate(int br);
    258     bool playChunk();
    259     bool playSample(int16_t sample[2]) ;
    260     void playI2Sremains();
    261     int32_t Gain(int16_t s[2]);
    262     bool fill_InputBuf();
    263     void showstreamtitle(const char* ml);
    264     bool parseContentType(char* ct);
    265     bool parseHttpResponseHeader();
    266     bool initializeDecoder();
    267     esp_err_t I2Sstart(uint8_t i2s_num);
    268     esp_err_t I2Sstop(uint8_t i2s_num);
    269     void urlencode(char* buff, uint16_t buffLen, bool spacesOnly = false);
    270     int16_t* IIR_filterChain0(int16_t iir_in[2], bool clear = false);
    271     int16_t* IIR_filterChain1(int16_t* iir_in, bool clear = false);
    272     int16_t* IIR_filterChain2(int16_t* iir_in, bool clear = false);
    273     inline void setDatamode(uint8_t dm){m_datamode=dm;}
    274     inline uint8_t getDatamode(){return m_datamode;}
    275     inline uint32_t streamavail(){ return _client ? _client->available() : 0;}
    276     void IIR_calculateCoefficients(int8_t G1, int8_t G2, int8_t G3);
    277     bool ts_parsePacket(uint8_t* packet, uint8_t* packetStart, uint8_t* packetLength);
    278 
    279 //+++ W E B S T R E A M  -  H E L P   F U N C T I O N S +++
    280     uint16_t readMetadata(uint16_t b, bool first = false);
    281     size_t   chunkedDataTransfer(uint8_t* bytes);
    282     bool     readID3V1Tag();
    283     void     slowStreamDetection(uint32_t inBuffFilled, uint32_t maxFrameSize);
    284     void     lostStreamDetection(uint32_t bytesAvail);
    285 #ifndef AUDIO_NO_SD_FS
    286     void     seek_m4a_stsz();
    287     uint32_t m4a_correctResumeFilePos(uint32_t resumeFilePos);
    288     uint32_t flac_correctResumeFilePos(uint32_t resumeFilePos);
    289     uint32_t mp3_correctResumeFilePos(uint32_t resumeFilePos);
    290 #endif // AUDIO_NO_SD_FS
    291 
    292     //++++ implement several function with respect to the index of string ++++
    293     void trim(char *s) {
    294     //fb   trim in place
    295         char *pe;
    296         char *p = s;
    297         while ( isspace(*p) ) p++; //left
    298         pe = p; //right
    299         while ( *pe != '\0' ) pe++;
    300         do {
    301             pe--;
    302         } while ( (pe > p) && isspace(*pe) );
    303         if (p == s) {
    304             *++pe = '\0';
    305         } else {  //move
    306             while ( p <= pe ) *s++ = *p++;
    307             *s = '\0';
    308         }
    309     }
    310 
    311     bool startsWith (const char* base, const char* str) {
    312     //fb
    313         char c;
    314         while ( (c = *str++) != '\0' )
    315           if (c != *base++) return false;
    316         return true;
    317     }
    318 
    319     bool endsWith (const char* base, const char* str) {
    320     //fb
    321         int slen = strlen(str) - 1;
    322         const char *p = base + strlen(base) - 1;
    323         while(p > base && isspace(*p)) p--;  // rtrim
    324         p -= slen;
    325         if (p < base) return false;
    326         return (strncmp(p, str, slen) == 0);
    327     }
    328 
    329     int indexOf (const char* base, const char* str, int startIndex = 0) {
    330     //fb
    331         const char *p = base;
    332         for (; startIndex > 0; startIndex--)
    333             if (*p++ == '\0') return -1;
    334         char* pos = strstr(p, str);
    335         if (pos == nullptr) return -1;
    336         return pos - base;
    337     }
    338 
    339     int indexOf (const char* base, char ch, int startIndex = 0) {
    340     //fb
    341         const char *p = base;
    342         for (; startIndex > 0; startIndex--)
    343             if (*p++ == '\0') return -1;
    344         char *pos = strchr(p, ch);
    345         if (pos == nullptr) return -1;
    346         return pos - base;
    347     }
    348 
    349     int lastIndexOf(const char* haystack, const char* needle) {
    350     //fb
    351         int nlen = strlen(needle);
    352         if (nlen == 0) return -1;
    353         const char *p = haystack - nlen + strlen(haystack);
    354         while (p >= haystack) {
    355           int i = 0;
    356           while (needle[i] == p[i])
    357             if (++i == nlen) return p - haystack;
    358           p--;
    359         }
    360         return -1;
    361     }
    362 
    363     int lastIndexOf(const char* haystack, const char needle) {
    364     //fb
    365         const char *p = strrchr(haystack, needle);
    366         return (p ? p - haystack : -1);
    367     }
    368 
    369     int specialIndexOf (uint8_t* base, const char* str, int baselen, bool exact = false){
    370         int result;  // seek for str in buffer or in header up to baselen, not nullterninated
    371         if (strlen(str) > baselen) return -1; // if exact == true seekstr in buffer must have "\0" at the end
    372         for (int i = 0; i < baselen - strlen(str); i++){
    373             result = i;
    374             for (int j = 0; j < strlen(str) + exact; j++){
    375                 if (*(base + i + j) != *(str + j)){
    376                     result = -1;
    377                     break;
    378                 }
    379             }
    380             if (result >= 0) break;
    381         }
    382         return result;
    383     }
    384 
    385     // some other functions
    386     size_t bigEndian(uint8_t* base, uint8_t numBytes, uint8_t shiftLeft = 8){
    387         uint64_t result = 0;
    388         if(numBytes < 1 || numBytes > 8) return 0;
    389         for (int i = 0; i < numBytes; i++) {
    390                 result += *(base + i) << (numBytes -i - 1) * shiftLeft;
    391         }
    392         if(result > SIZE_MAX) {log_e("range overflow"); result = 0;} // overflow
    393         return (size_t)result;
    394     }
    395 
    396     bool b64encode(const char* source, uint16_t sourceLength, char* dest){
    397         size_t size = base64_encode_expected_len(sourceLength) + 1;
    398         char * buffer = (char *) malloc(size);
    399         if(buffer) {
    400             base64_encodestate _state;
    401             base64_init_encodestate(&_state);
    402             int len = base64_encode_block(&source[0], sourceLength, &buffer[0], &_state);
    403             len = base64_encode_blockend((buffer + len), &_state);
    404             memcpy(dest, buffer, strlen(buffer));
    405             dest[strlen(buffer)] = '\0';
    406             free(buffer);
    407             return true;
    408         }
    409         return false;
    410     }
    411     size_t urlencode_expected_len(const char* source){
    412         size_t expectedLen = strlen(source);
    413         for(int i = 0; i < strlen(source); i++) {
    414             if(isalnum(source[i])){;}
    415             else expectedLen += 2;
    416         }
    417         return expectedLen;
    418     }
    419     void vector_clear_and_shrink(vector<char*>&vec){
    420         uint size = vec.size();
    421         for (int i = 0; i < size; i++) {
    422             if(vec[i]){
    423                 free(vec[i]);
    424                 vec[i] = NULL;
    425             }
    426         }
    427         vec.clear();
    428         vec.shrink_to_fit();
    429     }
    430     uint32_t simpleHash(const char* str){
    431         if(str == NULL) return 0;
    432         uint32_t hash = 0;
    433         for(int i=0; i<strlen(str); i++){
    434 		    if(str[i] < 32) continue; // ignore control sign
    435 		    hash += (str[i] - 31) * i * 32;
    436         }
    437         return hash;
    438 	}
    439 
    440 private:
    441     const char *codecname[9] = {"unknown", "WAV", "MP3", "AAC", "M4A", "FLAC", "OGG", "OGG FLAC", "OPUS"};
    442     enum : int { APLL_AUTO = -1, APLL_ENABLE = 1, APLL_DISABLE = 0 };
    443     enum : int { EXTERNAL_I2S = 0, INTERNAL_DAC = 1, INTERNAL_PDM = 2 };
    444     enum : int { FORMAT_NONE = 0, FORMAT_M3U = 1, FORMAT_PLS = 2, FORMAT_ASX = 3, FORMAT_M3U8 = 4};
    445     enum : int { AUDIO_NONE, HTTP_RESPONSE_HEADER, AUDIO_DATA, AUDIO_LOCALFILE,
    446                  AUDIO_PLAYLISTINIT, AUDIO_PLAYLISTHEADER,  AUDIO_PLAYLISTDATA};
    447     enum : int { FLAC_BEGIN = 0, FLAC_MAGIC = 1, FLAC_MBH =2, FLAC_SINFO = 3, FLAC_PADDING = 4, FLAC_APP = 5,
    448                  FLAC_SEEK = 6, FLAC_VORBIS = 7, FLAC_CUESHEET = 8, FLAC_PICTURE = 9, FLAC_OKAY = 100};
    449     enum : int { M4A_BEGIN = 0, M4A_FTYP = 1, M4A_CHK = 2, M4A_MOOV = 3, M4A_FREE = 4, M4A_TRAK = 5, M4A_MDAT = 6,
    450                  M4A_ILST = 7, M4A_MP4A = 8, M4A_AMRDY = 99, M4A_OKAY = 100};
    451     enum : int { OGG_BEGIN = 0, OGG_MAGIC = 1, OGG_HEADER = 2, OGG_FIRST = 3, OGG_AMRDY = 99, OGG_OKAY = 100};
    452     enum : int { CODEC_NONE = 0, CODEC_WAV = 1, CODEC_MP3 = 2, CODEC_AAC = 3, CODEC_M4A = 4, CODEC_FLAC = 5,
    453                  CODEC_OGG = 6, CODEC_OGG_FLAC = 7, CODEC_OGG_OPUS = 8, CODEC_AACP = 9};
    454     enum : int { ST_NONE = 0, ST_WEBFILE = 1, ST_WEBSTREAM = 2};
    455     typedef enum { LEFTCHANNEL=0, RIGHTCHANNEL=1 } SampleIndex;
    456     typedef enum { LOWSHELF = 0, PEAKEQ = 1, HIFGSHELF =2 } FilterType;
    457 
    458     const uint8_t volumetable[22]={   0,  1,  2,  3,  4 , 6 , 8, 10, 12, 14, 17,
    459                                      20, 23, 27, 30 ,34, 38, 43 ,48, 52, 58, 64}; //22 elements
    460 
    461     typedef struct _filter{
    462         float a0;
    463         float a1;
    464         float a2;
    465         float b1;
    466         float b2;
    467     } filter_t;
    468 
    469     typedef struct _pis_array{
    470         int number;
    471         int pids[4];
    472     } pid_array;
    473 
    474 #ifndef AUDIO_NO_SD_FS
    475     File                  audiofile;    // @suppress("Abstract class cannot be instantiated")
    476 #endif  // AUDIO_NO_SD_FS
    477     WiFiClient            client;       // @suppress("Abstract class cannot be instantiated")
    478     WiFiClientSecure      clientsecure; // @suppress("Abstract class cannot be instantiated")
    479     WiFiClient*           _client = nullptr;
    480     i2s_config_t          m_i2s_config = {}; // stores values for I2S driver
    481     i2s_pin_config_t      m_pin_config = {};
    482     std::vector<char*>    m_playlistContent; // m3u8 playlist buffer
    483     std::vector<char*>    m_playlistURL;     // m3u8 streamURLs buffer
    484     std::vector<uint32_t> m_hashQueue;
    485 
    486     const size_t    m_frameSizeWav  = 1024;
    487     const size_t    m_frameSizeMP3  = 1600;
    488     const size_t    m_frameSizeAAC  = 1600;
    489     const size_t    m_frameSizeFLAC = 4096 * 4;
    490 
    491     static const uint8_t m_tsPacketSize  = 188;
    492     static const uint8_t m_tsHeaderSize  = 4;
    493 
    494     char*           m_chbuf = NULL;
    495     uint16_t        m_chbufSize = 0;                // will set in constructor (depending on PSRAM)
    496     char            m_lastHost[512];                // Store the last URL to a webstream
    497     char*           m_playlistBuff = NULL;          // stores playlistdata
    498     const uint16_t  m_plsBuffEntryLen = 256;        // length of each entry in playlistBuff
    499     filter_t        m_filter[3];                    // digital filters
    500     int             m_LFcount = 0;                  // Detection of end of header
    501     uint32_t        m_sampleRate=16000;
    502     uint32_t        m_bitRate=0;                    // current bitrate given fom decoder
    503     uint32_t        m_avr_bitrate = 0;              // average bitrate, median computed by VBR
    504     int             m_readbytes = 0;                // bytes read
    505     uint32_t        m_metacount = 0;                // counts down bytes between metadata
    506     int             m_controlCounter = 0;           // Status within readID3data() and readWaveHeader()
    507     int8_t          m_balance = 0;                  // -16 (mute left) ... +16 (mute right)
    508     uint8_t         m_vol=64;                       // volume
    509     uint8_t         m_bitsPerSample = 16;           // bitsPerSample
    510     uint8_t         m_channels = 2;
    511     uint8_t         m_i2s_num = I2S_NUM_0;          // I2S_NUM_0 or I2S_NUM_1
    512     uint8_t         m_playlistFormat = 0;           // M3U, PLS, ASX
    513     uint8_t         m_codec = CODEC_NONE;           //
    514     uint8_t         m_expectedCodec = CODEC_NONE;   // set in connecttohost (e.g. http://url.mp3 -> CODEC_MP3)
    515     uint8_t         m_expectedPlsFmt = FORMAT_NONE; // set in connecttohost (e.g. streaming01.m3u) -> FORMAT_M3U)
    516     uint8_t         m_filterType[2];                // lowpass, highpass
    517     uint8_t         m_streamType = ST_NONE;
    518     uint8_t         m_ID3Size = 0;                  // lengt of ID3frame - ID3header
    519     int16_t         m_outBuff[2048*2];              // Interleaved L/R
    520     int16_t         m_validSamples = 0;
    521     int16_t         m_curSample = 0;
    522     uint16_t        m_datamode = 0;                 // Statemaschine
    523     uint16_t        m_streamTitleHash = 0;          // remember streamtitle, ignore multiple occurence in metadata
    524     uint16_t        m_timeout_ms = 250;
    525     uint16_t        m_timeout_ms_ssl = 2700;
    526     uint8_t         m_flacBitsPerSample = 0;        // bps should be 16
    527     uint8_t         m_flacNumChannels = 0;          // can be read out in the FLAC file header
    528     uint32_t        m_flacSampleRate = 0;           // can be read out in the FLAC file header
    529     uint16_t        m_flacMaxFrameSize = 0;         // can be read out in the FLAC file header
    530     uint16_t        m_flacMaxBlockSize = 0;         // can be read out in the FLAC file header
    531     uint32_t        m_flacTotalSamplesInStream = 0; // can be read out in the FLAC file header
    532     uint32_t        m_metaint = 0;                  // Number of databytes between metadata
    533     uint32_t        m_chunkcount = 0 ;              // Counter for chunked transfer
    534     uint32_t        m_t0 = 0;                       // store millis(), is needed for a small delay
    535     uint32_t        m_contentlength = 0;            // Stores the length if the stream comes from fileserver
    536     uint32_t        m_bytesNotDecoded = 0;          // pictures or something else that comes with the stream
    537     uint32_t        m_PlayingStartTime = 0;         // Stores the milliseconds after the start of the audio
    538     uint32_t        m_resumeFilePos = 0;            // the return value from stopSong() can be entered here
    539     uint16_t        m_m3u8_targetDuration = 10;     //
    540     uint32_t        m_stsz_numEntries = 0;          // num of entries inside stsz atom (uint32_t)
    541     uint32_t        m_stsz_position = 0;            // pos of stsz atom within file
    542     bool            m_f_metadata = false;           // assume stream without metadata
    543     bool            m_f_unsync = false;             // set within ID3 tag but not used
    544     bool            m_f_exthdr = false;             // ID3 extended header
    545     bool            m_f_ssl = false;
    546     bool            m_f_running = false;
    547     bool            m_f_firstCall = false;          // InitSequence for processWebstream and processLokalFile
    548     bool            m_f_chunked = false ;           // Station provides chunked transfer
    549     bool            m_f_firstmetabyte = false;      // True if first metabyte (counter)
    550     bool            m_f_playing = false;            // valid mp3 stream recognized
    551     bool            m_f_tts = false;                // text to speech
    552     bool            m_f_loop = false;               // Set if audio file should loop
    553     bool            m_f_forceMono = false;          // if true stereo -> mono
    554     bool            m_f_internalDAC = false;        // false: output vis I2S, true output via internal DAC
    555     bool            m_f_rtsp = false;               // set if RTSP is used (m3u8 stream)
    556     bool            m_f_m3u8data = false;           // used in processM3U8entries
    557     bool            m_f_Log = false;                // set in platformio.ini  -DAUDIO_LOG and -DCORE_DEBUG_LEVEL=3 or 4
    558     bool            m_f_continue = false;           // next m3u8 chunk is available
    559     bool            m_f_ts = true;                  // transport stream
    560     uint8_t         m_f_channelEnabled = 3;         // internal DAC, both channels
    561     uint32_t        m_audioFileDuration = 0;
    562     float           m_audioCurrentTime = 0;
    563     uint32_t        m_audioDataStart = 0;           // in bytes
    564     size_t          m_audioDataSize = 0;            //
    565     float           m_filterBuff[3][2][2][2];       // IIR filters memory for Audio DSP
    566     size_t          m_i2s_bytesWritten = 0;         // set in i2s_write() but not used
    567     size_t          m_file_size = 0;                // size of the file
    568     uint16_t        m_filterFrequency[2];
    569     int8_t          m_gain0 = 0;                    // cut or boost filters (EQ)
    570     int8_t          m_gain1 = 0;
    571     int8_t          m_gain2 = 0;
    572 
    573     pid_array       m_pidsOfPMT;
    574     int16_t         m_pidOfAAC;
    575     uint8_t         m_packetBuff[m_tsPacketSize];
    576     int16_t         m_pesDataLength = 0;
    577 };
    578 
    579 //----------------------------------------------------------------------------------------------------------------------