v0.7.355
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,7 @@
|
||||
* vs1053_ext.h
|
||||
*
|
||||
* Created on: Jul 09.2017
|
||||
* Updated on: Feb 11 2022
|
||||
* Updated on: Aug 15.2022
|
||||
* Author: Wolle
|
||||
*/
|
||||
|
||||
@@ -10,13 +10,15 @@
|
||||
#define _vs1053_ext
|
||||
|
||||
#ifndef AUDIOBUFFER_MULTIPLIER
|
||||
#define AUDIOBUFFER_MULTIPLIER 13
|
||||
#define AUDIOBUFFER_MULTIPLIER 12
|
||||
#endif
|
||||
|
||||
#define VS1053VOLM 128 // 128 or 96 only
|
||||
#define VS1053VOL(v) (VS1053VOLM==128?log10(((float)v+1)) * 50.54571334 + 128:log10(((float)v+1)) * 64.54571334 + 96)
|
||||
|
||||
|
||||
#include "Arduino.h"
|
||||
#include <vector>
|
||||
#include "libb64/cencode.h"
|
||||
#include "SPI.h"
|
||||
#include "SD.h"
|
||||
@@ -44,6 +46,8 @@ extern __attribute__((weak)) void audio_icydescription(const char*);
|
||||
extern __attribute__((weak)) void audio_lasthost(const char*);
|
||||
extern __attribute__((weak)) void audio_eof_stream(const char*); // The webstream comes to an end
|
||||
|
||||
#define AUDIO_INFO(...) {char buff[512 + 64]; sprintf(buff,__VA_ARGS__); if(audio_info) audio_info(buff);}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
class AudioBuffer {
|
||||
@@ -92,6 +96,7 @@ public:
|
||||
|
||||
protected:
|
||||
const size_t m_buffSizePSRAM = 300000; // most webstreams limit the advance to 100...300Kbytes
|
||||
//const size_t m_buffSizeRAM = 1600 * 10;
|
||||
const size_t m_buffSizeRAM = 1600 * AUDIOBUFFER_MULTIPLIER;
|
||||
size_t m_buffSize = 0;
|
||||
size_t m_freeSpace = 0;
|
||||
@@ -113,18 +118,22 @@ class Audio : private AudioBuffer{
|
||||
AudioBuffer InBuff; // instance of input buffer
|
||||
|
||||
private:
|
||||
WiFiClient client;
|
||||
WiFiClientSecure clientsecure;
|
||||
WiFiClient client; // @suppress("Abstract class cannot be instantiated")
|
||||
WiFiClientSecure clientsecure; // @suppress("Abstract class cannot be instantiated")
|
||||
WiFiClient* _client = nullptr;
|
||||
File audiofile;
|
||||
|
||||
std::vector<char*> m_playlistContent; // m3u8 playlist buffer
|
||||
std::vector<char*> m_playlistURL; // m3u8 streamURLs buffer
|
||||
std::vector<uint32_t> m_hashQueue;
|
||||
|
||||
private:
|
||||
enum : int { VS1053_NONE, VS1053_HEADER , VS1053_DATA, VS1053_METADATA, VS1053_PLAYLISTINIT,
|
||||
VS1053_PLAYLISTHEADER, VS1053_PLAYLISTDATA, VS1053_SWM, VS1053_OGG};
|
||||
enum : int { FORMAT_NONE = 0, FORMAT_M3U = 1, FORMAT_PLS = 2, FORMAT_ASX = 3};
|
||||
enum : int { AUDIO_NONE, HTTP_RESPONSE_HEADER , AUDIO_DATA, AUDIO_LOCALFILE, AUDIO_METADATA, AUDIO_PLAYLISTINIT,
|
||||
AUDIO_PLAYLISTHEADER, AUDIO_PLAYLISTDATA, VS1053_SWM, VS1053_OGG};
|
||||
enum : int { FORMAT_NONE = 0, FORMAT_M3U = 1, FORMAT_PLS = 2, FORMAT_ASX = 3, FORMAT_M3U8 = 4};
|
||||
|
||||
enum : int { CODEC_NONE, CODEC_WAV, CODEC_MP3, CODEC_AAC, CODEC_M4A, CODEC_FLAC, CODEC_OGG,
|
||||
CODEC_OGG_FLAC, CODEC_OGG_OPUS};
|
||||
enum : int { ST_NONE = 0, ST_WEBFILE = 1, ST_WEBSTREAM = 2};
|
||||
|
||||
private:
|
||||
uint8_t cs_pin ; // Pin where CS line is connected
|
||||
@@ -159,11 +168,16 @@ private:
|
||||
const uint8_t SM_LINE1 = 14 ; // Bitnumber in SCI_MODE for Line input
|
||||
|
||||
SPIClass* spi_VS1053 = NULL;
|
||||
SPISettings VS1053_SPI; // SPI settings for this slave
|
||||
SPISettings VS1053_SPI_DATA; // SPI settings normal speed
|
||||
SPISettings VS1053_SPI_CTL; // SPI settings control mode
|
||||
|
||||
char chbuf[512];
|
||||
char m_lastHost[256]; // Store the last URL to a webstream
|
||||
char* m_playlistBuff = NULL; // stores playlistdata
|
||||
uint8_t m_codec = CODEC_NONE; //
|
||||
uint8_t m_expectedCodec = CODEC_NONE; // set in connecttohost (e.g. http://url.mp3 -> CODEC_MP3)
|
||||
uint8_t m_expectedPlsFmt = FORMAT_NONE; // set in connecttohost (e.g. streaming01.m3u) -> FORMAT_M3U)
|
||||
uint8_t m_streamType = ST_NONE;
|
||||
uint8_t m_rev=0; // Revision
|
||||
uint8_t m_playlistFormat = 0; // M3U, PLS, ASX
|
||||
size_t m_file_size = 0; // size of the file
|
||||
@@ -178,15 +192,23 @@ private:
|
||||
bool m_f_firstchunk=true; // First chunk as input
|
||||
bool m_f_swm = true; // Stream without metadata
|
||||
bool m_f_tts = false; // text to speech
|
||||
bool m_f_Log = false; // set in platformio.ini -DAUDIO_LOG and -DCORE_DEBUG_LEVEL=3 or 4
|
||||
bool m_f_continue = false; // next m3u8 chunk is available
|
||||
bool m_f_ts = true; // transport stream
|
||||
bool m_f_webfile = false;
|
||||
bool m_f_firstCall = false; // InitSequence for processWebstream and processLokalFile
|
||||
int m_LFcount; // Detection of end of header
|
||||
uint32_t m_chunkcount = 0 ; // Counter for chunked transfer
|
||||
uint32_t m_contentlength = 0;
|
||||
uint32_t m_resumeFilePos = 0;
|
||||
uint32_t m_metaint = 0; // Number of databytes between metadata
|
||||
uint32_t m_t0 = 0; // store millis(), is needed for a small delay
|
||||
uint16_t m_bitrate = 0; // Bitrate in kb/sec
|
||||
int16_t m_btp=0; // Bytes to play
|
||||
uint16_t m_streamTitleHash = 0; // remember streamtitle, ignore multiple occurence in metadata
|
||||
uint16_t m_streamUrlHash = 0; // remember streamURL, ignore multiple occurence in metadata
|
||||
uint16_t m_timeout_ms = 250;
|
||||
uint16_t m_timeout_ms_ssl = 2700;
|
||||
int m_metacount=0; // Number of bytes in metadata
|
||||
int m_controlCounter = 0; // Status within readID3data() and readWaveHeader()
|
||||
bool m_firstmetabyte=false; // True if first metabyte (counter)
|
||||
@@ -203,8 +225,8 @@ private:
|
||||
88,90,91,92,93,94,95,96,97,98,99,100}; //22 elements
|
||||
protected:
|
||||
inline void DCS_HIGH() {(dcs_pin&0x20) ? GPIO.out1_w1ts.data = 1 << (dcs_pin - 32) : GPIO.out_w1ts = 1 << dcs_pin;}
|
||||
inline void DCS_LOW() {(dcs_pin&0x20) ? GPIO.out1_w1tc.data = 1 << (dcs_pin - 32) : GPIO.out_w1tc = 1 << dcs_pin;}
|
||||
inline void CS_HIGH() {( cs_pin&0x20) ? GPIO.out1_w1ts.data = 1 << ( cs_pin - 32) : GPIO.out_w1ts = 1 << cs_pin;}
|
||||
inline void DCS_LOW() {(dcs_pin&0x20) ? GPIO.out1_w1tc.data = 1 << (dcs_pin - 32) : GPIO.out_w1tc = 1 << dcs_pin;}
|
||||
inline void CS_HIGH() {( cs_pin&0x20) ? GPIO.out1_w1ts.data = 1 << ( cs_pin - 32) : GPIO.out_w1ts = 1 << cs_pin;}
|
||||
inline void CS_LOW() {( cs_pin&0x20) ? GPIO.out1_w1tc.data = 1 << ( cs_pin - 32) : GPIO.out_w1tc = 1 << cs_pin;}
|
||||
inline void await_data_request() {while(!digitalRead(dreq_pin)) NOP();} // Very short delay
|
||||
inline bool data_request() {return(digitalRead(dreq_pin) == HIGH);}
|
||||
@@ -231,10 +253,15 @@ protected:
|
||||
void showID3Tag(const char* tag, const char* value);
|
||||
void processLocalFile();
|
||||
void processWebStream();
|
||||
void processPlayListData();
|
||||
bool parseContentType(const char* ct);
|
||||
size_t chunkedDataTransfer();
|
||||
bool readPlayListData();
|
||||
const char* parsePlaylist_M3U();
|
||||
const char* parsePlaylist_PLS();
|
||||
const char* parsePlaylist_ASX();
|
||||
// const char* parsePlaylist_M3U8();
|
||||
bool parseContentType(char* ct);
|
||||
bool latinToUTF8(char* buff, size_t bufflen);
|
||||
void processAudioHeaderData();
|
||||
bool parseHttpResponseHeader();
|
||||
bool readMetadata(uint8_t b, bool first = false);
|
||||
void UTF8toASCII(char* str);
|
||||
void unicode2utf8(char* buff, uint32_t len);
|
||||
@@ -242,26 +269,31 @@ protected:
|
||||
void loadUserCode();
|
||||
|
||||
|
||||
|
||||
public:
|
||||
// Constructor. Only sets pin values. Doesn't touch the chip. Be sure to call begin()!
|
||||
//Audio(uint8_t _cs_pin, uint8_t _dcs_pin, uint8_t _dreq_pin, uint8_t spi, uint8_t mosi, uint8_t miso, uint8_t sclk);
|
||||
Audio ( uint8_t _cs_pin, uint8_t _dcs_pin, uint8_t _dreq_pin, uint8_t spi = VSPI, uint8_t mosi = 23, uint8_t miso = 19, uint8_t sclk = 18);
|
||||
~Audio();
|
||||
|
||||
void begin() ; // Begin operation. Sets pins correctly and prepares SPI bus.
|
||||
void stop_mp3client();
|
||||
uint32_t stop_mp3client();
|
||||
void setVolume(uint8_t vol); // Set the player volume.Level from 0-21, higher is louder.
|
||||
void setTone(int8_t* rtone); // Set the player baas/treble, 4 nibbles for treble gain/freq and bass gain/freq
|
||||
uint8_t getVolume(); // Get the current volume setting, higher is louder.
|
||||
void printDetails(const char* str); // Print configuration details to serial output.
|
||||
const char* printVersion(); // Print ID and version of vs1053 chip
|
||||
uint8_t printVersion(); // Returns version of vs1053 chip
|
||||
uint32_t printChipID(); // Returns chipID of vs1053 chip
|
||||
void softReset() ; // Do a soft reset
|
||||
void loop();
|
||||
void loop();
|
||||
void setConnectionTimeout(uint16_t timeout_ms, uint16_t timeout_ms_ssl);
|
||||
bool connecttohost(String host);
|
||||
bool connecttohost(const char* host, const char* user = "", const char* pwd = "");
|
||||
bool connecttoSD(String sdfile);
|
||||
bool connecttoSD(const char* sdfile);
|
||||
bool connecttoFS(fs::FS &fs, const char* path);
|
||||
bool connecttoSD(String sdfile, uint32_t resumeFilePos = 0);
|
||||
bool connecttoSD(const char* sdfile, uint32_t resumeFilePos = 0);
|
||||
bool connecttoFS(fs::FS &fs, const char* path, uint32_t resumeFilePos = 0);
|
||||
bool connecttospeech(const char* speech, const char* lang);
|
||||
bool isRunning() {return m_f_running;}
|
||||
uint32_t getFileSize();
|
||||
uint32_t getFilePos();
|
||||
uint32_t getAudioDataStartPos();
|
||||
@@ -269,17 +301,17 @@ public:
|
||||
SemaphoreHandle_t mutex_pl=NULL;
|
||||
size_t bufferFilled();
|
||||
size_t bufferFree();
|
||||
uint32_t inBufferFilled(); // returns the number of stored bytes in the inputbuffer
|
||||
uint32_t inBufferFree(); // returns the number of free bytes in the inputbuffer
|
||||
bool isRunning() {/*Serial.printf("m_f_running=%d\n", m_f_running); */return m_f_running;}
|
||||
void setBalance(int8_t bal = 0);
|
||||
void setTone(int8_t gainLowPass, int8_t gainBandPass, int8_t gainHighPass);
|
||||
size_t inBufferFilled(){ return bufferFilled(); }
|
||||
size_t inBufferFree(){ return bufferFree(); }
|
||||
void setBalance(int8_t bal = 0);
|
||||
void setTone(int8_t gainLowPass, int8_t gainBandPass, int8_t gainHighPass);
|
||||
void setDefaults();
|
||||
void forceMono(bool m) {} // TODO
|
||||
/* VU METER */
|
||||
void setVUmeter();
|
||||
void getVUlevel();
|
||||
uint8_t vuLeft, vuRight;
|
||||
|
||||
// implement several function with respect to the index of string
|
||||
bool startsWith (const char* base, const char* str) { return (strstr(base, str) - base) == 0;}
|
||||
bool endsWith (const char* base, const char* str) {
|
||||
@@ -287,17 +319,27 @@ public:
|
||||
int slen = strlen(str);
|
||||
return (blen >= slen) && (0 == strcmp(base + blen - slen, str));
|
||||
}
|
||||
int indexOf (const char* base, const char* str, int startIndex) {
|
||||
int result;
|
||||
int baselen = strlen(base);
|
||||
if (strlen(str) > baselen || startIndex > baselen) result = -1;
|
||||
else {
|
||||
char* pos = strstr(base + startIndex, str);
|
||||
if (pos == NULL) result = -1;
|
||||
else result = pos - base;
|
||||
}
|
||||
return result;
|
||||
|
||||
int indexOf (const char* base, const char* str, int startIndex = 0) {
|
||||
//fb
|
||||
const char *p = base;
|
||||
for (; startIndex > 0; startIndex--)
|
||||
if (*p++ == '\0') return -1;
|
||||
char* pos = strstr(p, str);
|
||||
if (pos == nullptr) return -1;
|
||||
return pos - base;
|
||||
}
|
||||
|
||||
int indexOf (const char* base, char ch, int startIndex = 0) {
|
||||
//fb
|
||||
const char *p = base;
|
||||
for (; startIndex > 0; startIndex--)
|
||||
if (*p++ == '\0') return -1;
|
||||
char *pos = strchr(p, ch);
|
||||
if (pos == nullptr) return -1;
|
||||
return pos - base;
|
||||
}
|
||||
|
||||
int lastIndexOf(const char* base, const char* str) {
|
||||
int res = -1, result = -1;
|
||||
int lenBase = strlen(base);
|
||||
@@ -355,19 +397,40 @@ public:
|
||||
}
|
||||
return expectedLen;
|
||||
}
|
||||
void trim(char* s){
|
||||
uint8_t l = 0;
|
||||
while(isspace(*(s + l))) l++;
|
||||
for(uint16_t i = 0; i< strlen(s) - l; i++) *(s + i) = *(s + i + l); // ltrim
|
||||
char* back = s + strlen(s);
|
||||
while(isspace(*--back));
|
||||
*(back + 1) = '\0'; // rtrim
|
||||
|
||||
void trim(char *s) {
|
||||
//fb trim in place
|
||||
char *pe;
|
||||
char *p = s;
|
||||
while ( isspace(*p) ) p++; //left
|
||||
pe = p; //right
|
||||
while ( *pe != '\0' ) pe++;
|
||||
do {
|
||||
pe--;
|
||||
} while ( (pe > p) && isspace(*pe) );
|
||||
if (p == s) {
|
||||
*++pe = '\0';
|
||||
} else { //move
|
||||
while ( p <= pe ) *s++ = *p++;
|
||||
*s = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
void vector_clear_and_shrink(std::vector<char*>&vec){
|
||||
uint size = vec.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
if(vec[i]){
|
||||
free(vec[i]);
|
||||
vec[i] = NULL;
|
||||
}
|
||||
}
|
||||
vec.clear();
|
||||
vec.shrink_to_fit();
|
||||
}
|
||||
|
||||
inline uint8_t getDatamode(){return m_datamode;}
|
||||
inline void setDatamode(uint8_t dm){m_datamode=dm;}
|
||||
inline uint32_t streamavail() {if(m_f_ssl==false) return client.available(); else return clientsecure.available();}
|
||||
inline uint32_t streamavail(){ return _client ? _client->available() : 0;}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user