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.cpp (226272B)
1 /* 2 * Audio.cpp 3 * 4 * Created on: Oct 26.2018 5 * 6 * Version 2.0.7 7 * Updated on: Nov 22.2022 8 * Author: Wolle (schreibfaul1) 9 * 10 */ 11 #include "Audio.h" 12 #include "mp3_decoder/mp3_decoder.h" 13 #include "aac_decoder/aac_decoder.h" 14 #include "flac_decoder/flac_decoder.h" 15 16 #ifndef AUDIO_NO_SD_FS 17 #ifdef SDFATFS_USED 18 fs::SDFATFS SD_SDFAT; 19 #endif 20 #endif // AUDIO_NO_SD_FS 21 22 //--------------------------------------------------------------------------------------------------------------------- 23 AudioBuffer::AudioBuffer(size_t maxBlockSize) { 24 // if maxBlockSize isn't set use defaultspace (1600 bytes) is enough for aac and mp3 player 25 if(maxBlockSize) m_resBuffSizeRAM = maxBlockSize; 26 if(maxBlockSize) m_maxBlockSize = maxBlockSize; 27 } 28 29 AudioBuffer::~AudioBuffer() { 30 if(m_buffer) 31 free(m_buffer); 32 m_buffer = NULL; 33 } 34 35 void AudioBuffer::setBufsize(int ram, int psram) { 36 if (ram > -1) // -1 == default / no change 37 m_buffSizeRAM = ram; 38 if (psram > -1) 39 m_buffSizePSRAM = psram; 40 } 41 42 size_t AudioBuffer::init() { 43 if(m_buffer) free(m_buffer); 44 m_buffer = NULL; 45 if(psramInit() && m_buffSizePSRAM > 0) { 46 // PSRAM found, AudioBuffer will be allocated in PSRAM 47 m_f_psram = true; 48 m_buffSize = m_buffSizePSRAM; 49 m_buffer = (uint8_t*) ps_calloc(m_buffSize, sizeof(uint8_t)); 50 m_buffSize = m_buffSizePSRAM - m_resBuffSizePSRAM; 51 } 52 if(m_buffer == NULL) { 53 // PSRAM not found, not configured or not enough available 54 m_f_psram = false; 55 m_buffSize = m_buffSizeRAM; 56 m_buffer = (uint8_t*) calloc(m_buffSize, sizeof(uint8_t)); 57 m_buffSize = m_buffSizeRAM - m_resBuffSizeRAM; 58 } 59 if(!m_buffer) 60 return 0; 61 m_f_init = true; 62 resetBuffer(); 63 return m_buffSize; 64 } 65 66 void AudioBuffer::changeMaxBlockSize(uint16_t mbs){ 67 m_maxBlockSize = mbs; 68 return; 69 } 70 71 uint16_t AudioBuffer::getMaxBlockSize(){ 72 return m_maxBlockSize; 73 } 74 75 size_t AudioBuffer::freeSpace() { 76 if(m_readPtr >= m_writePtr) { 77 m_freeSpace = (m_readPtr - m_writePtr); 78 } else { 79 m_freeSpace = (m_endPtr - m_writePtr) + (m_readPtr - m_buffer); 80 } 81 if(m_f_start) 82 m_freeSpace = m_buffSize; 83 return m_freeSpace - 1; 84 } 85 86 size_t AudioBuffer::writeSpace() { 87 if(m_readPtr >= m_writePtr) { 88 m_writeSpace = (m_readPtr - m_writePtr - 1); // readPtr must not be overtaken 89 } else { 90 if(getReadPos() == 0) 91 m_writeSpace = (m_endPtr - m_writePtr - 1); 92 else 93 m_writeSpace = (m_endPtr - m_writePtr); 94 } 95 if(m_f_start) 96 m_writeSpace = m_buffSize - 1; 97 return m_writeSpace; 98 } 99 100 size_t AudioBuffer::bufferFilled() { 101 if(m_writePtr >= m_readPtr) { 102 m_dataLength = (m_writePtr - m_readPtr); 103 } else { 104 m_dataLength = (m_endPtr - m_readPtr) + (m_writePtr - m_buffer); 105 } 106 return m_dataLength; 107 } 108 109 void AudioBuffer::bytesWritten(size_t bw) { 110 m_writePtr += bw; 111 if(m_writePtr == m_endPtr) { 112 m_writePtr = m_buffer; 113 } 114 if(bw && m_f_start) 115 m_f_start = false; 116 } 117 118 void AudioBuffer::bytesWasRead(size_t br) { 119 m_readPtr += br; 120 if(m_readPtr >= m_endPtr) { 121 size_t tmp = m_readPtr - m_endPtr; 122 m_readPtr = m_buffer + tmp; 123 } 124 } 125 126 uint8_t* AudioBuffer::getWritePtr() { 127 return m_writePtr; 128 } 129 130 uint8_t* AudioBuffer::getReadPtr() { 131 size_t len = m_endPtr - m_readPtr; 132 if(len < m_maxBlockSize) { // be sure the last frame is completed 133 memcpy(m_endPtr, m_buffer, m_maxBlockSize - len); // cpy from m_buffer to m_endPtr with len 134 } 135 return m_readPtr; 136 } 137 138 void AudioBuffer::resetBuffer() { 139 m_writePtr = m_buffer; 140 m_readPtr = m_buffer; 141 m_endPtr = m_buffer + m_buffSize; 142 m_f_start = true; 143 // memset(m_buffer, 0, m_buffSize); //Clear Inputbuffer 144 } 145 146 uint32_t AudioBuffer::getWritePos() { 147 return m_writePtr - m_buffer; 148 } 149 150 uint32_t AudioBuffer::getReadPos() { 151 return m_readPtr - m_buffer; 152 } 153 //--------------------------------------------------------------------------------------------------------------------- 154 Audio::Audio(bool internalDAC /* = false */, uint8_t channelEnabled /* = I2S_DAC_CHANNEL_BOTH_EN */, uint8_t i2sPort) { 155 156 // build-in-DAC works only with ESP32 (ESP32-S3 has no build-in-DAC) 157 // build-in-DAC last working Arduino Version: 2.0.0-RC2 158 // possible values for channelEnabled are: 159 // I2S_DAC_CHANNEL_DISABLE = 0, Disable I2S built-in DAC signals 160 // I2S_DAC_CHANNEL_RIGHT_EN = 1, Enable I2S built-in DAC right channel, maps to DAC channel 1 on GPIO25 161 // I2S_DAC_CHANNEL_LEFT_EN = 2, Enable I2S built-in DAC left channel, maps to DAC channel 2 on GPIO26 162 // I2S_DAC_CHANNEL_BOTH_EN = 0x3, Enable both of the I2S built-in DAC channels. 163 // I2S_DAC_CHANNEL_MAX = 0x4, I2S built-in DAC mode max index 164 #ifdef AUDIO_LOG 165 m_f_Log = true; 166 #endif 167 168 if(psramInit()) {m_chbufSize = 4096; m_chbuf = (char*)ps_malloc(m_chbufSize);} 169 else {m_chbufSize = 512 + 64; m_chbuf = (char*)malloc(m_chbufSize);} 170 171 clientsecure.setInsecure(); // if that can't be resolved update to ESP32 Arduino version 1.0.5-rc05 or higher 172 m_f_channelEnabled = channelEnabled; 173 m_f_internalDAC = internalDAC; 174 //i2s configuration 175 m_i2s_num = i2sPort; // i2s port number 176 m_i2s_config.sample_rate = 16000; 177 m_i2s_config.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT; 178 m_i2s_config.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT; 179 m_i2s_config.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1; // interrupt priority 180 m_i2s_config.dma_buf_count = 16; 181 m_i2s_config.dma_buf_len = 512; 182 m_i2s_config.use_apll = APLL_DISABLE; // must be disabled in V2.0.1-RC1 183 m_i2s_config.tx_desc_auto_clear = true; // new in V1.0.1 184 m_i2s_config.fixed_mclk = I2S_PIN_NO_CHANGE; 185 186 187 if (internalDAC) { 188 189 #ifdef CONFIG_IDF_TARGET_ESP32 // ESP32S3 has no DAC 190 191 log_i("internal DAC"); 192 m_i2s_config.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN ); 193 194 #if ESP_ARDUINO_VERSION_MAJOR >= 2 195 #if ESP_ARDUINO_VERSION_PATCH == 0 196 m_i2s_config.communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_STAND_I2S); // vers == 2.0.0 197 #else 198 // V2.0.1 ... V2.0.4 will not work 199 m_i2s_config.communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_STAND_MSB); // vers >= 2.0.5 200 #endif 201 #else 202 m_i2s_config.communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S_MSB); 203 #endif 204 205 i2s_driver_install((i2s_port_t)m_i2s_num, &m_i2s_config, 0, NULL); 206 i2s_set_dac_mode((i2s_dac_mode_t)m_f_channelEnabled); 207 if(m_f_channelEnabled != I2S_DAC_CHANNEL_BOTH_EN) { 208 m_f_forceMono = true; 209 } 210 211 #endif 212 213 } 214 else { 215 m_i2s_config.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX); 216 217 #if ESP_ARDUINO_VERSION_MAJOR >= 2 218 m_i2s_config.communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_STAND_I2S); // Arduino vers. > 2.0.0 219 #else 220 m_i2s_config.communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB); 221 #endif 222 223 i2s_driver_install((i2s_port_t)m_i2s_num, &m_i2s_config, 0, NULL); 224 m_f_forceMono = false; 225 } 226 227 i2s_zero_dma_buffer((i2s_port_t) m_i2s_num); 228 229 for(int i = 0; i <3; i++) { 230 m_filter[i].a0 = 1; 231 m_filter[i].a1 = 0; 232 m_filter[i].a2 = 0; 233 m_filter[i].b1 = 0; 234 m_filter[i].b2 = 0; 235 } 236 } 237 //--------------------------------------------------------------------------------------------------------------------- 238 void Audio::setBufsize(int rambuf_sz, int psrambuf_sz) { 239 if(InBuff.isInitialized()) { 240 log_e("Audio::setBufsize must not be called after audio is initialized"); 241 return; 242 } 243 InBuff.setBufsize(rambuf_sz, psrambuf_sz); 244 }; 245 246 void Audio::initInBuff() { 247 if(!InBuff.isInitialized()) { 248 size_t size = InBuff.init(); 249 if (size > 0) { 250 AUDIO_INFO("PSRAM %sfound, inputBufferSize: %u bytes", InBuff.havePSRAM()?"":"not ", size - 1); 251 } 252 } 253 changeMaxBlockSize(1600); // default size mp3 or aac 254 } 255 256 //--------------------------------------------------------------------------------------------------------------------- 257 esp_err_t Audio::I2Sstart(uint8_t i2s_num) { 258 // It is not necessary to call this function after i2s_driver_install() (it is started automatically), 259 // however it is necessary to call it after i2s_stop() 260 return i2s_start((i2s_port_t) i2s_num); 261 } 262 263 esp_err_t Audio::I2Sstop(uint8_t i2s_num) { 264 return i2s_stop((i2s_port_t) i2s_num); 265 } 266 //--------------------------------------------------------------------------------------------------------------------- 267 esp_err_t Audio::i2s_mclk_pin_select(const uint8_t pin) { 268 // IDF >= 4.4 use setPinout(BCLK, LRC, DOUT, DIN, MCK) only, i2s_mclk_pin_select() is no longer needed 269 270 if(pin != 0 && pin != 1 && pin != 3) { 271 log_e("Only support GPIO0/GPIO1/GPIO3, gpio_num:%d", pin); 272 return ESP_ERR_INVALID_ARG; 273 } 274 275 #ifdef CONFIG_IDF_TARGET_ESP32 276 switch(pin){ 277 case 0: 278 PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_CLK_OUT1); 279 WRITE_PERI_REG(PIN_CTRL, 0xFFF0); 280 break; 281 case 1: 282 PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD_CLK_OUT3); 283 WRITE_PERI_REG(PIN_CTRL, 0xF0F0); 284 break; 285 case 3: 286 PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD_CLK_OUT2); 287 WRITE_PERI_REG(PIN_CTRL, 0xFF00); 288 break; 289 default: 290 break; 291 } 292 #endif 293 294 return ESP_OK; 295 } 296 //--------------------------------------------------------------------------------------------------------------------- 297 Audio::~Audio() { 298 //I2Sstop(m_i2s_num); 299 //InBuff.~AudioBuffer(); #215 the AudioBuffer is automatically destroyed by the destructor 300 setDefaults(); 301 if(m_playlistBuff) {free(m_playlistBuff); m_playlistBuff = NULL;} 302 i2s_driver_uninstall((i2s_port_t)m_i2s_num); // #215 free I2S buffer 303 if(m_chbuf) {free(m_chbuf); m_chbuf = NULL;} 304 } 305 //--------------------------------------------------------------------------------------------------------------------- 306 void Audio::setDefaults() { 307 stopSong(); 308 initInBuff(); // initialize InputBuffer if not already done 309 InBuff.resetBuffer(); 310 MP3Decoder_FreeBuffers(); 311 FLACDecoder_FreeBuffers(); 312 AACDecoder_FreeBuffers(); 313 if(m_playlistBuff) {free(m_playlistBuff); m_playlistBuff = NULL;} // free if stream is not m3u8 314 vector_clear_and_shrink(m_playlistURL); 315 vector_clear_and_shrink(m_playlistContent); 316 m_hashQueue.clear(); m_hashQueue.shrink_to_fit(); // uint32_t vector 317 client.stop(); 318 client.flush(); // release memory 319 clientsecure.stop(); 320 clientsecure.flush(); 321 _client = static_cast<WiFiClient*>(&client); /* default to *something* so that no NULL deref can happen */ 322 playI2Sremains(); 323 ts_parsePacket(0, 0, 0); // reset ts routine 324 325 AUDIO_INFO("buffers freed, free Heap: %u bytes", ESP.getFreeHeap()); 326 327 m_f_chunked = false; // Assume not chunked 328 m_f_firstmetabyte = false; 329 m_f_playing = false; 330 m_f_ssl = false; 331 m_f_metadata = false; 332 m_f_tts = false; 333 m_f_firstCall = true; // InitSequence for processWebstream and processLokalFile 334 m_f_running = false; 335 m_f_loop = false; // Set if audio file should loop 336 m_f_unsync = false; // set within ID3 tag but not used 337 m_f_exthdr = false; // ID3 extended header 338 m_f_rtsp = false; // RTSP (m3u8)stream 339 m_f_m3u8data = false; // set again in processM3U8entries() if necessary 340 m_f_continue = false; 341 m_f_ts = false; 342 343 m_streamType = ST_NONE; 344 m_codec = CODEC_NONE; 345 m_playlistFormat = FORMAT_NONE; 346 m_datamode = AUDIO_NONE; 347 m_audioCurrentTime = 0; // Reset playtimer 348 m_audioFileDuration = 0; 349 m_audioDataStart = 0; 350 m_audioDataSize = 0; 351 m_avr_bitrate = 0; // the same as m_bitrate if CBR, median if VBR 352 m_bitRate = 0; // Bitrate still unknown 353 m_bytesNotDecoded = 0; // counts all not decodable bytes 354 m_chunkcount = 0; // for chunked streams 355 m_contentlength = 0; // If Content-Length is known, count it 356 m_curSample = 0; 357 m_metaint = 0; // No metaint yet 358 m_LFcount = 0; // For end of header detection 359 m_controlCounter = 0; // Status within readID3data() and readWaveHeader() 360 m_channels = 2; // assume stereo #209 361 m_streamTitleHash = 0; 362 m_file_size = 0; 363 m_ID3Size = 0; 364 } 365 366 //--------------------------------------------------------------------------------------------------------------------- 367 void Audio::setConnectionTimeout(uint16_t timeout_ms, uint16_t timeout_ms_ssl){ 368 if(timeout_ms) m_timeout_ms = timeout_ms; 369 if(timeout_ms_ssl) m_timeout_ms_ssl = timeout_ms_ssl; 370 } 371 372 //--------------------------------------------------------------------------------------------------------------------- 373 bool Audio::connecttohost(const char* host, const char* user, const char* pwd) { 374 // user and pwd for authentification only, can be empty 375 376 if(host == NULL) { 377 AUDIO_INFO("Hostaddress is empty"); 378 return false; 379 } 380 381 uint16_t lenHost = strlen(host); 382 383 if(lenHost >= 512 - 10) { 384 AUDIO_INFO("Hostaddress is too long"); 385 return false; 386 } 387 388 int idx = indexOf(host, "http"); 389 char* l_host = (char*)malloc(lenHost + 10); 390 if(idx < 0){strcpy(l_host, "http://"); strcat(l_host, host); } // amend "http;//" if not found 391 else {strcpy(l_host, (host + idx));} // trim left if necessary 392 393 char* h_host = NULL; // pointer of l_host without http:// or https:// 394 if(startsWith(l_host, "https")) h_host = strdup(l_host + 8); 395 else h_host = strdup(l_host + 7); 396 397 // initializationsequence 398 int16_t pos_slash; // position of "/" in hostname 399 int16_t pos_colon; // position of ":" in hostname 400 int16_t pos_ampersand; // position of "&" in hostname 401 uint16_t port = 80; // port number 402 403 // In the URL there may be an extension, like noisefm.ru:8000/play.m3u&t=.m3u 404 pos_slash = indexOf(h_host, "/", 0); 405 pos_colon = indexOf(h_host, ":", 0); 406 if(isalpha(h_host[pos_colon + 1])) pos_colon = -1; // no portnumber follows 407 pos_ampersand = indexOf(h_host, "&", 0); 408 409 char *hostwoext = NULL; // "skonto.ls.lv:8002" in "skonto.ls.lv:8002/mp3" 410 char *extension = NULL; // "/mp3" in "skonto.ls.lv:8002/mp3" 411 412 if(pos_slash > 1) { 413 hostwoext = (char*)malloc(pos_slash + 1); 414 memcpy(hostwoext, h_host, pos_slash); 415 hostwoext[pos_slash] = '\0'; 416 uint16_t extLen = urlencode_expected_len(h_host + pos_slash); 417 extension = (char *)malloc(extLen + 20); 418 memcpy(extension, h_host + pos_slash, extLen); 419 urlencode(extension, extLen, true); 420 } 421 else{ // url has no extension 422 hostwoext = strdup(h_host); 423 extension = strdup("/"); 424 } 425 426 if((pos_colon >= 0) && ((pos_ampersand == -1) || (pos_ampersand > pos_colon))){ 427 port = atoi(h_host + pos_colon + 1);// Get portnumber as integer 428 hostwoext[pos_colon] = '\0';// Host without portnumber 429 } 430 431 AUDIO_INFO("Connect to new host: \"%s\"", l_host); 432 setDefaults(); // no need to stop clients if connection is established (default is true) 433 434 if(startsWith(l_host, "https")) m_f_ssl = true; 435 else m_f_ssl = false; 436 437 // authentification 438 uint8_t auth = strlen(user) + strlen(pwd); 439 char toEncode[auth + 4]; 440 toEncode[0] = '\0'; 441 strcat(toEncode, user); 442 strcat(toEncode, ":"); 443 strcat(toEncode, pwd); 444 char authorization[base64_encode_expected_len(strlen(toEncode)) + 1]; 445 authorization[0] = '\0'; 446 b64encode((const char*)toEncode, strlen(toEncode), authorization); 447 448 // AUDIO_INFO("Connect to \"%s\" on port %d, extension \"%s\"", hostwoext, port, extension); 449 450 char rqh[strlen(h_host) + strlen(authorization) + 200]; // http request header 451 rqh[0] = '\0'; 452 453 strcat(rqh, "GET "); 454 strcat(rqh, extension); 455 strcat(rqh, " HTTP/1.1\r\n"); 456 strcat(rqh, "Host: "); 457 strcat(rqh, hostwoext); 458 strcat(rqh, "\r\n"); 459 strcat(rqh, "Icy-MetaData:1\r\n"); 460 strcat(rqh, "Authorization: Basic "); 461 strcat(rqh, authorization); 462 strcat(rqh, "\r\n"); 463 strcat(rqh, "Accept-Encoding: identity;q=1,*;q=0\r\n"); 464 // strcat(rqh, "User-Agent: Mozilla/5.0\r\n"); #363 465 strcat(rqh, "Connection: keep-alive\r\n\r\n"); 466 467 if(ESP_ARDUINO_VERSION_MAJOR == 2 && ESP_ARDUINO_VERSION_MINOR == 0 && ESP_ARDUINO_VERSION_PATCH >= 3){ 468 m_timeout_ms_ssl = UINT16_MAX; // bug in v2.0.3 if hostwoext is a IPaddr not a name 469 m_timeout_ms = UINT16_MAX; // [WiFiClient.cpp:253] connect(): select returned due to timeout 250 ms for fd 48 470 } 471 bool res = true; // no need to reconnect if connection exists 472 473 if(m_f_ssl){ _client = static_cast<WiFiClient*>(&clientsecure); if(port == 80) port = 443;} 474 else { _client = static_cast<WiFiClient*>(&client);} 475 476 uint32_t t = millis(); 477 if(m_f_Log) AUDIO_INFO("connect to %s on port %d path %s", hostwoext, port, extension); 478 res = _client->connect(hostwoext, port, m_f_ssl ? m_timeout_ms_ssl : m_timeout_ms); 479 if(res){ 480 uint32_t dt = millis() - t; 481 strcpy(m_lastHost, l_host); 482 AUDIO_INFO("%s has been established in %u ms, free Heap: %u bytes", 483 m_f_ssl?"SSL":"Connection", dt, ESP.getFreeHeap()); 484 m_f_running = true; 485 } 486 487 m_expectedCodec = CODEC_NONE; 488 m_expectedPlsFmt = FORMAT_NONE; 489 490 if(res){ 491 _client->print(rqh); 492 if(endsWith(extension, ".mp3")) m_expectedCodec = CODEC_MP3; 493 if(endsWith(extension, ".aac")) m_expectedCodec = CODEC_AAC; 494 if(endsWith(extension, ".wav")) m_expectedCodec = CODEC_WAV; 495 if(endsWith(extension, ".m4a")) m_expectedCodec = CODEC_M4A; 496 if(endsWith(extension, ".flac")) m_expectedCodec = CODEC_FLAC; 497 if(endsWith(extension, ".asx")) m_expectedPlsFmt = FORMAT_ASX; 498 if(endsWith(extension, ".m3u")) m_expectedPlsFmt = FORMAT_M3U; 499 if(endsWith(extension, ".m3u8")) m_expectedPlsFmt = FORMAT_M3U8; 500 if(endsWith(extension, ".pls")) m_expectedPlsFmt = FORMAT_PLS; 501 502 setDatamode(HTTP_RESPONSE_HEADER); // Handle header 503 m_streamType = ST_WEBSTREAM; 504 } 505 else{ 506 AUDIO_INFO("Request %s failed!", l_host); 507 if(audio_showstation) audio_showstation(""); 508 if(audio_showstreamtitle) audio_showstreamtitle(""); 509 if(audio_icydescription) audio_icydescription(""); 510 if(audio_icyurl) audio_icyurl(""); 511 m_lastHost[0] = 0; 512 } 513 if(hostwoext) {free(hostwoext); hostwoext = NULL;} 514 if(extension) {free(extension); extension = NULL;} 515 if(l_host ) {free(l_host); l_host = NULL;} 516 if(h_host ) {free(h_host); h_host = NULL;} 517 return res; 518 } 519 //--------------------------------------------------------------------------------------------------------------------- 520 bool Audio::httpPrint(const char* host) { 521 // user and pwd for authentification only, can be empty 522 523 if(host == NULL) { 524 AUDIO_INFO("Hostaddress is empty"); 525 return false; 526 } 527 528 char* h_host = NULL; // pointer of l_host without http:// or https:// 529 if(m_f_ssl) h_host = strdup(host + 8); 530 else h_host = strdup(host + 7); 531 532 int16_t pos_slash; // position of "/" in hostname 533 int16_t pos_colon; // position of ":" in hostname 534 int16_t pos_ampersand; // position of "&" in hostname 535 uint16_t port = 80; // port number 536 537 // In the URL there may be an extension, like noisefm.ru:8000/play.m3u&t=.m3u 538 pos_slash = indexOf(h_host, "/", 0); 539 pos_colon = indexOf(h_host, ":", 0); 540 if(isalpha(h_host[pos_colon + 1])) pos_colon = -1; // no portnumber follows 541 pos_ampersand = indexOf(h_host, "&", 0); 542 543 char *hostwoext = NULL; // "skonto.ls.lv:8002" in "skonto.ls.lv:8002/mp3" 544 char *extension = NULL; // "/mp3" in "skonto.ls.lv:8002/mp3" 545 546 if(pos_slash > 1) { 547 hostwoext = (char*)malloc(pos_slash + 1); 548 memcpy(hostwoext, h_host, pos_slash); 549 hostwoext[pos_slash] = '\0'; 550 uint16_t extLen = urlencode_expected_len(h_host + pos_slash); 551 extension = (char *)malloc(extLen + 20); 552 memcpy(extension, h_host + pos_slash, extLen); 553 urlencode(extension, extLen, true); 554 } 555 else{ // url has no extension 556 hostwoext = strdup(h_host); 557 extension = strdup("/"); 558 } 559 560 if((pos_colon >= 0) && ((pos_ampersand == -1) || (pos_ampersand > pos_colon))){ 561 port = atoi(h_host + pos_colon + 1);// Get portnumber as integer 562 hostwoext[pos_colon] = '\0';// Host without portnumber 563 } 564 565 AUDIO_INFO("new request: \"%s\"", host); 566 567 char rqh[strlen(h_host) + 200]; // http request header 568 rqh[0] = '\0'; 569 570 strcat(rqh, "GET "); 571 strcat(rqh, extension); 572 strcat(rqh, " HTTP/1.1\r\n"); 573 strcat(rqh, "Host: "); 574 strcat(rqh, hostwoext); 575 strcat(rqh, "\r\n"); 576 strcat(rqh, "Accept-Encoding: identity;q=1,*;q=0\r\n"); 577 // strcat(rqh, "User-Agent: Mozilla/5.0\r\n"); #363 578 strcat(rqh, "Connection: keep-alive\r\n\r\n"); 579 580 if(m_f_ssl){ _client = static_cast<WiFiClient*>(&clientsecure); if(port == 80) port = 443;} 581 else { _client = static_cast<WiFiClient*>(&client);} 582 583 if(!_client->connected()){ 584 AUDIO_INFO("The host has disconnected, reconnecting"); 585 if(!_client->connect(hostwoext, port)){ 586 log_e("connection lost"); 587 stopSong(); 588 return false; 589 } 590 } 591 _client->print(rqh); 592 593 if(endsWith(extension, ".mp3")) m_expectedCodec = CODEC_MP3; 594 if(endsWith(extension, ".aac")) m_expectedCodec = CODEC_AAC; 595 if(endsWith(extension, ".wav")) m_expectedCodec = CODEC_WAV; 596 if(endsWith(extension, ".m4a")) m_expectedCodec = CODEC_M4A; 597 if(endsWith(extension, ".flac")) m_expectedCodec = CODEC_FLAC; 598 if(endsWith(extension, ".asx")) m_expectedPlsFmt = FORMAT_ASX; 599 if(endsWith(extension, ".m3u")) m_expectedPlsFmt = FORMAT_M3U; 600 if(endsWith(extension, ".m3u8")) m_expectedPlsFmt = FORMAT_M3U8; 601 if(endsWith(extension, ".pls")) m_expectedPlsFmt = FORMAT_PLS; 602 603 setDatamode(HTTP_RESPONSE_HEADER); // Handle header 604 m_streamType = ST_WEBSTREAM; 605 m_contentlength = 0; 606 m_f_chunked = false; 607 608 if(hostwoext) {free(hostwoext); hostwoext = NULL;} 609 if(extension) {free(extension); extension = NULL;} 610 if(h_host ) {free(h_host); h_host = NULL;} 611 return true; 612 } 613 //--------------------------------------------------------------------------------------------------------------------- 614 bool Audio::setFileLoop(bool input){ 615 if(m_codec == CODEC_M4A) return 0; 616 m_f_loop = input; 617 return input; 618 } 619 //--------------------------------------------------------------------------------------------------------------------- 620 void Audio::UTF8toASCII(char* str){ 621 622 #ifdef SDFATFS_USED 623 //UTF8->UTF16 (lowbyte) 624 const uint8_t ascii[60] = { 625 //129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148 // UTF8(C3) 626 // Ä Å Æ Ç É Ñ // CHAR 627 000, 000, 000, 0xC4, 143, 0xC6,0xC7, 000,0xC9,000, 000, 000, 000, 000, 000, 000, 0xD1, 000, 000, 000, // ASCII (Latin1) 628 //149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168 629 // Ö Ü ß à ä å æ è 630 000, 0xD6,000, 000, 000, 000, 000, 0xDC, 000, 000, 0xDF,0xE0, 000, 000, 000,0xE4,0xE5,0xE6, 000,0xE8, 631 //169, 170, 171, 172. 173. 174. 175, 176, 177, 179, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188 632 // ê ë ì î ï ñ ò ô ö ù û ü 633 000, 0xEA, 0xEB,0xEC, 000,0xEE,0xEB, 000,0xF1,0xF2, 000,0xF4, 000,0xF6, 000, 000,0xF9, 000,0xFB,0xFC}; 634 #else 635 const uint8_t ascii[60] = { 636 //129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148 // UTF8(C3) 637 // Ä Å Æ Ç É Ñ // CHAR 638 000, 000, 000, 142, 143, 146, 128, 000, 144, 000, 000, 000, 000, 000, 000, 000, 165, 000, 000, 000, // ASCII 639 //149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168 640 // Ö Ü ß à ä å æ è 641 000, 153, 000, 000, 000, 000, 000, 154, 000, 000, 225, 133, 000, 000, 000, 132, 134, 145, 000, 138, 642 //169, 170, 171, 172. 173. 174. 175, 176, 177, 179, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188 643 // ê ë ì î ï ñ ò ô ö ù û ü 644 000, 136, 137, 141, 000, 140, 139, 000, 164, 149, 000, 147, 000, 148, 000, 000, 151, 000, 150, 129}; 645 #endif 646 647 uint16_t i = 0, j=0, s = 0; 648 bool f_C3_seen = false; 649 650 while(str[i] != 0) { // convert UTF8 to ASCII 651 if(str[i] == 195){ // C3 652 i++; 653 f_C3_seen = true; 654 continue; 655 } 656 str[j] = str[i]; 657 if(str[j] > 128 && str[j] < 189 && f_C3_seen == true) { 658 s = ascii[str[j] - 129]; 659 if(s != 0) str[j] = s; // found a related ASCII sign 660 f_C3_seen = false; 661 } 662 i++; j++; 663 } 664 str[j] = 0; 665 } 666 #ifndef AUDIO_NO_SD_FS 667 //--------------------------------------------------------------------------------------------------------------------- 668 bool Audio::connecttoSD(const char* path, uint32_t resumeFilePos) { 669 return connecttoFS(SD, path, resumeFilePos); 670 } 671 //--------------------------------------------------------------------------------------------------------------------- 672 bool Audio::connecttoFS(fs::FS &fs, const char* path, uint32_t resumeFilePos) { 673 674 if(strlen(path)>255) return false; 675 676 m_resumeFilePos = resumeFilePos; 677 char audioName[256]; 678 setDefaults(); // free buffers an set defaults 679 memcpy(audioName, path, strlen(path)+1); 680 if(audioName[0] != '/'){ 681 for(int i = 255; i > 0; i--){ 682 audioName[i] = audioName[i-1]; 683 } 684 audioName[0] = '/'; 685 } 686 687 AUDIO_INFO("Reading file: \"%s\"", audioName); vTaskDelay(2); 688 689 if(fs.exists(audioName)) { 690 audiofile = fs.open(audioName); // #86 691 } 692 else { 693 UTF8toASCII(audioName); 694 if(fs.exists(audioName)) { 695 audiofile = fs.open(audioName); 696 } 697 } 698 699 if(!audiofile) { 700 if(audio_info) {vTaskDelay(2); audio_info("Failed to open file for reading");} 701 return false; 702 } 703 704 setDatamode(AUDIO_LOCALFILE); 705 m_file_size = audiofile.size();//TEST loop 706 707 char* afn = NULL; // audioFileName 708 709 #ifdef SDFATFS_USED 710 audiofile.getName(m_chbuf, sizeof(m_chbuf)); 711 afn = strdup(m_chbuf); 712 #else 713 afn = strdup(audiofile.name()); 714 #endif 715 716 uint8_t dotPos = lastIndexOf(afn, "."); 717 for(uint8_t i = dotPos + 1; i < strlen(afn); i++){ 718 afn[i] = toLowerCase(afn[i]); 719 } 720 721 if(endsWith(afn, ".mp3")) m_codec = CODEC_MP3; // m_codec is by default CODEC_NONE 722 if(endsWith(afn, ".m4a")) m_codec = CODEC_M4A; 723 if(endsWith(afn, ".aac")) m_codec = CODEC_AAC; 724 if(endsWith(afn, ".wav")) m_codec = CODEC_WAV; 725 if(endsWith(afn, ".flac")) m_codec = CODEC_FLAC; 726 727 if(m_codec == CODEC_NONE) AUDIO_INFO("The %s format is not supported", afn + dotPos); 728 729 if(afn) {free(afn); afn = NULL;} 730 731 bool ret = initializeDecoder(); 732 if(ret) m_f_running = true; 733 else audiofile.close(); 734 return ret; 735 } 736 #endif // AUDIO_NO_SD_FS 737 //--------------------------------------------------------------------------------------------------------------------- 738 bool Audio::connecttospeech(const char* speech, const char* lang){ 739 740 setDefaults(); 741 char host[] = "translate.google.com.vn"; 742 char path[] = "/translate_tts"; 743 744 uint16_t speechLen = strlen(speech); 745 uint16_t speechBuffLen = speechLen + 300; 746 memcpy(m_lastHost, speech, 256); 747 char* speechBuff = (char*)malloc(speechBuffLen); 748 if(!speechBuff) {log_e("out of memory"); return false;} 749 memcpy(speechBuff, speech, speechLen); 750 speechBuff[speechLen] = '\0'; 751 urlencode(speechBuff, speechBuffLen); 752 753 char resp[strlen(speechBuff) + 200] = ""; 754 strcat(resp, "GET "); 755 strcat(resp, path); 756 strcat(resp, "?ie=UTF-8&tl="); 757 strcat(resp, lang); 758 strcat(resp, "&client=tw-ob&q="); 759 strcat(resp, speechBuff); 760 strcat(resp, " HTTP/1.1\r\n"); 761 strcat(resp, "Host: "); 762 strcat(resp, host); 763 strcat(resp, "\r\n"); 764 strcat(resp, "User-Agent: Mozilla/5.0 \r\n"); 765 strcat(resp, "Accept-Encoding: identity\r\n"); 766 strcat(resp, "Accept: text/html\r\n"); 767 strcat(resp, "Connection: close\r\n\r\n"); 768 769 if(speechBuff){free(speechBuff); speechBuff = NULL;} 770 _client = static_cast<WiFiClient*>(&client); 771 if(!_client->connect(host, 80)) { 772 log_e("Connection failed"); 773 return false; 774 } 775 _client->print(resp); 776 777 m_streamType = ST_WEBFILE; 778 m_f_running = true; 779 m_f_ssl = false; 780 m_f_tts = true; 781 setDatamode(HTTP_RESPONSE_HEADER); 782 783 return true; 784 } 785 //--------------------------------------------------------------------------------------------------------------------- 786 bool Audio::connecttomarytts(const char* speech, const char* lang, const char* voice){ 787 788 //lang: fr, te, ru, en_US, en_GB, sv, lb, tr, de, it 789 790 //voice: upmc-pierre-hsmm fr male hmm 791 // upmc-pierre fr male unitselection general 792 // upmc-jessica-hsmm fr female hmm 793 // upmc-jessica fr female unitselection general 794 // marylux lb female unitselection general 795 // istc-lucia-hsmm it female hmm 796 // enst-dennys-hsmm fr male hmm 797 // enst-camille-hsmm fr female hmm 798 // enst-camille fr female unitselection general 799 // dfki-spike-hsmm en_GB male hmm 800 // dfki-spike en_GB male unitselection general 801 // dfki-prudence-hsmm en_GB female hmm 802 // dfki-prudence en_GB female unitselection general 803 // dfki-poppy-hsmm en_GB female hmm 804 // dfki-poppy en_GB female unitselection general 805 // dfki-pavoque-styles de male unitselection general 806 // dfki-pavoque-neutral-hsmm de male hmm 807 // dfki-pavoque-neutral de male unitselection general 808 // dfki-ot-hsmm tr male hmm 809 // dfki-ot tr male unitselection general 810 // dfki-obadiah-hsmm en_GB male hmm 811 // dfki-obadiah en_GB male unitselection general 812 // cmu-slt-hsmm en_US female hmm 813 // cmu-slt en_US female unitselection general 814 // cmu-rms-hsmm en_US male hmm 815 // cmu-rms en_US male unitselection general 816 // cmu-nk-hsmm te female hmm 817 // cmu-bdl-hsmm en_US male hmm 818 // cmu-bdl en_US male unitselection general 819 // bits4 de female unitselection general 820 // bits3-hsmm de male hmm 821 // bits3 de male unitselection general 822 // bits2 de male unitselection general 823 // bits1-hsmm de female hmm 824 // bits1 de female unitselection general 825 826 setDefaults(); 827 char host[] = "mary.dfki.de"; 828 char path[] = "/process"; 829 int port = 59125; 830 831 uint16_t speechLen = strlen(speech); 832 uint16_t speechBuffLen = speechLen + 300; 833 memcpy(m_lastHost, speech, 256); 834 char* speechBuff = (char*)malloc(speechBuffLen); 835 if(!speechBuff) {log_e("out of memory"); return false;} 836 memcpy(speechBuff, speech, speechLen); 837 speechBuff[speechLen] = '\0'; 838 urlencode(speechBuff, speechBuffLen); 839 840 char resp[strlen(speechBuff) + 200] = ""; 841 strcat(resp, "GET "); 842 strcat(resp, path); 843 strcat(resp, "?INPUT_TEXT="); 844 strcat(resp, speechBuff); 845 strcat(resp, "&INPUT_TYPE=TEXT"); 846 strcat(resp, "&OUTPUT_TYPE=AUDIO"); 847 strcat(resp, "&AUDIO=WAVE_FILE"); 848 strcat(resp, "&LOCALE="); 849 strcat(resp, lang); 850 strcat(resp, "&VOICE="); 851 strcat(resp, voice); 852 strcat(resp, " HTTP/1.1\r\n"); 853 strcat(resp, "Host: "); 854 strcat(resp, host); 855 strcat(resp, "\r\n"); 856 strcat(resp, "User-Agent: Mozilla/5.0 \r\n"); 857 strcat(resp, "Accept-Encoding: identity\r\n"); 858 strcat(resp, "Accept: text/html\r\n"); 859 strcat(resp, "Connection: close\r\n\r\n"); 860 861 if(speechBuff){free(speechBuff); speechBuff = NULL;} 862 _client = static_cast<WiFiClient*>(&client); 863 if(!_client->connect(host, port)) { 864 log_e("Connection failed"); 865 return false; 866 } 867 _client->print(resp); 868 869 m_streamType = ST_WEBFILE; 870 m_f_running = true; 871 m_f_ssl = false; 872 m_f_tts = true; 873 setDatamode(HTTP_RESPONSE_HEADER); 874 875 return true; 876 } 877 //--------------------------------------------------------------------------------------------------------------------- 878 void Audio::urlencode(char* buff, uint16_t buffLen, bool spacesOnly) { 879 880 uint16_t len = strlen(buff); 881 uint8_t* tmpbuff = (uint8_t*)malloc(buffLen); 882 if(!tmpbuff) {log_e("out of memory"); return;} 883 char c; 884 char code0; 885 char code1; 886 uint16_t j = 0; 887 for(int i = 0; i < len; i++) { 888 c = buff[i]; 889 if(isalnum(c)) tmpbuff[j++] = c; 890 else if(spacesOnly){ 891 if(c == ' '){ 892 tmpbuff[j++] = '%'; 893 tmpbuff[j++] = '2'; 894 tmpbuff[j++] = '0'; 895 } 896 else{ 897 tmpbuff[j++] = c; 898 } 899 } 900 else { 901 code1 = (c & 0xf) + '0'; 902 if((c & 0xf) > 9) code1 = (c & 0xf) - 10 + 'A'; 903 c = (c >> 4) & 0xf; 904 code0 = c + '0'; 905 if(c > 9) code0 = c - 10 + 'A'; 906 tmpbuff[j++] = '%'; 907 tmpbuff[j++] = code0; 908 tmpbuff[j++] = code1; 909 } 910 if(j == buffLen - 1){ 911 log_e("out of memory"); 912 break; 913 } 914 } 915 memcpy(buff, tmpbuff, j); 916 buff[j] ='\0'; 917 free(tmpbuff); 918 } 919 //--------------------------------------------------------------------------------------------------------------------- 920 void Audio::showID3Tag(const char* tag, const char* value){ 921 922 m_chbuf[0] = 0; 923 // V2.2 924 if(!strcmp(tag, "CNT")) sprintf(m_chbuf, "Play counter: %s", value); 925 // if(!strcmp(tag, "COM")) sprintf(m_chbuf, "Comments: %s", value); 926 if(!strcmp(tag, "CRA")) sprintf(m_chbuf, "Audio encryption: %s", value); 927 if(!strcmp(tag, "CRM")) sprintf(m_chbuf, "Encrypted meta frame: %s", value); 928 if(!strcmp(tag, "ETC")) sprintf(m_chbuf, "Event timing codes: %s", value); 929 if(!strcmp(tag, "EQU")) sprintf(m_chbuf, "Equalization: %s", value); 930 if(!strcmp(tag, "IPL")) sprintf(m_chbuf, "Involved people list: %s", value); 931 if(!strcmp(tag, "PIC")) sprintf(m_chbuf, "Attached picture: %s", value); 932 if(!strcmp(tag, "SLT")) sprintf(m_chbuf, "Synchronized lyric/text: %s", value); 933 // if(!strcmp(tag, "TAL")) sprintf(m_chbuf, "Album/Movie/Show title: %s", value); 934 if(!strcmp(tag, "TBP")) sprintf(m_chbuf, "BPM (Beats Per Minute): %s", value); 935 if(!strcmp(tag, "TCM")) sprintf(m_chbuf, "Composer: %s", value); 936 if(!strcmp(tag, "TCO")) sprintf(m_chbuf, "Content type: %s", value); 937 if(!strcmp(tag, "TCR")) sprintf(m_chbuf, "Copyright message: %s", value); 938 if(!strcmp(tag, "TDA")) sprintf(m_chbuf, "Date: %s", value); 939 if(!strcmp(tag, "TDY")) sprintf(m_chbuf, "Playlist delay: %s", value); 940 if(!strcmp(tag, "TEN")) sprintf(m_chbuf, "Encoded by: %s", value); 941 if(!strcmp(tag, "TFT")) sprintf(m_chbuf, "File type: %s", value); 942 if(!strcmp(tag, "TIM")) sprintf(m_chbuf, "Time: %s", value); 943 if(!strcmp(tag, "TKE")) sprintf(m_chbuf, "Initial key: %s", value); 944 if(!strcmp(tag, "TLA")) sprintf(m_chbuf, "Language(s): %s", value); 945 if(!strcmp(tag, "TLE")) sprintf(m_chbuf, "Length: %s", value); 946 if(!strcmp(tag, "TMT")) sprintf(m_chbuf, "Media type: %s", value); 947 if(!strcmp(tag, "TOA")) sprintf(m_chbuf, "Original artist(s)/performer(s): %s", value); 948 if(!strcmp(tag, "TOF")) sprintf(m_chbuf, "Original filename: %s", value); 949 if(!strcmp(tag, "TOL")) sprintf(m_chbuf, "Original Lyricist(s)/text writer(s): %s", value); 950 if(!strcmp(tag, "TOR")) sprintf(m_chbuf, "Original release year: %s", value); 951 if(!strcmp(tag, "TOT")) sprintf(m_chbuf, "Original album/Movie/Show title: %s", value); 952 if(!strcmp(tag, "TP1")) sprintf(m_chbuf, "Lead artist(s)/Lead performer(s)/Soloist(s)/Performing group: %s", value); 953 if(!strcmp(tag, "TP2")) sprintf(m_chbuf, "Band/Orchestra/Accompaniment: %s", value); 954 if(!strcmp(tag, "TP3")) sprintf(m_chbuf, "Conductor/Performer refinement: %s", value); 955 if(!strcmp(tag, "TP4")) sprintf(m_chbuf, "Interpreted, remixed, or otherwise modified by: %s", value); 956 if(!strcmp(tag, "TPA")) sprintf(m_chbuf, "Part of a set: %s", value); 957 if(!strcmp(tag, "TPB")) sprintf(m_chbuf, "Publisher: %s", value); 958 if(!strcmp(tag, "TRC")) sprintf(m_chbuf, "ISRC (International Standard Recording Code): %s", value); 959 if(!strcmp(tag, "TRD")) sprintf(m_chbuf, "Recording dates: %s", value); 960 if(!strcmp(tag, "TRK")) sprintf(m_chbuf, "Track number/Position in set: %s", value); 961 if(!strcmp(tag, "TSI")) sprintf(m_chbuf, "Size: %s", value); 962 if(!strcmp(tag, "TSS")) sprintf(m_chbuf, "Software/hardware and settings used for encoding: %s", value); 963 if(!strcmp(tag, "TT1")) sprintf(m_chbuf, "Content group description: %s", value); 964 if(!strcmp(tag, "TT2")) sprintf(m_chbuf, "Title/Songname/Content description: %s", value); 965 if(!strcmp(tag, "TT3")) sprintf(m_chbuf, "Subtitle/Description refinement: %s", value); 966 if(!strcmp(tag, "TXT")) sprintf(m_chbuf, "Lyricist/text writer: %s", value); 967 if(!strcmp(tag, "TXX")) sprintf(m_chbuf, "User defined text information frame: %s", value); 968 if(!strcmp(tag, "TYE")) sprintf(m_chbuf, "Year: %s", value); 969 if(!strcmp(tag, "UFI")) sprintf(m_chbuf, "Unique file identifier: %s", value); 970 if(!strcmp(tag, "ULT")) sprintf(m_chbuf, "Unsychronized lyric/text transcription: %s", value); 971 if(!strcmp(tag, "WAF")) sprintf(m_chbuf, "Official audio file webpage: %s", value); 972 if(!strcmp(tag, "WAR")) sprintf(m_chbuf, "Official artist/performer webpage: %s", value); 973 if(!strcmp(tag, "WAS")) sprintf(m_chbuf, "Official audio source webpage: %s", value); 974 if(!strcmp(tag, "WCM")) sprintf(m_chbuf, "Commercial information: %s", value); 975 if(!strcmp(tag, "WCP")) sprintf(m_chbuf, "Copyright/Legal information: %s", value); 976 if(!strcmp(tag, "WPB")) sprintf(m_chbuf, "Publishers official webpage: %s", value); 977 if(!strcmp(tag, "WXX")) sprintf(m_chbuf, "User defined URL link frame: %s", value); 978 979 // V2.3 V2.4 tags 980 // if(!strcmp(tag, "COMM")) sprintf(m_chbuf, "Comment: %s", value); 981 if(!strcmp(tag, "OWNE")) sprintf(m_chbuf, "Ownership: %s", value); 982 // if(!strcmp(tag, "PRIV")) sprintf(m_chbuf, "Private: %s", value); 983 if(!strcmp(tag, "SYLT")) sprintf(m_chbuf, "SynLyrics: %s", value); 984 if(!strcmp(tag, "TALB")) sprintf(m_chbuf, "Album: %s", value); 985 if(!strcmp(tag, "TBPM")) sprintf(m_chbuf, "BeatsPerMinute: %s", value); 986 if(!strcmp(tag, "TCMP")) sprintf(m_chbuf, "Compilation: %s", value); 987 if(!strcmp(tag, "TCOM")) sprintf(m_chbuf, "Composer: %s", value); 988 if(!strcmp(tag, "TCON")) sprintf(m_chbuf, "ContentType: %s", value); 989 if(!strcmp(tag, "TCOP")) sprintf(m_chbuf, "Copyright: %s", value); 990 if(!strcmp(tag, "TDAT")) sprintf(m_chbuf, "Date: %s", value); 991 if(!strcmp(tag, "TEXT")) sprintf(m_chbuf, "Lyricist: %s", value); 992 if(!strcmp(tag, "TIME")) sprintf(m_chbuf, "Time: %s", value); 993 if(!strcmp(tag, "TIT1")) sprintf(m_chbuf, "Grouping: %s", value); 994 if(!strcmp(tag, "TIT2")) sprintf(m_chbuf, "Title: %s", value); 995 if(!strcmp(tag, "TIT3")) sprintf(m_chbuf, "Subtitle: %s", value); 996 if(!strcmp(tag, "TLAN")) sprintf(m_chbuf, "Language: %s", value); 997 if(!strcmp(tag, "TLEN")) sprintf(m_chbuf, "Length (ms): %s", value); 998 if(!strcmp(tag, "TMED")) sprintf(m_chbuf, "Media: %s", value); 999 if(!strcmp(tag, "TOAL")) sprintf(m_chbuf, "OriginalAlbum: %s", value); 1000 if(!strcmp(tag, "TOPE")) sprintf(m_chbuf, "OriginalArtist: %s", value); 1001 if(!strcmp(tag, "TORY")) sprintf(m_chbuf, "OriginalReleaseYear: %s", value); 1002 if(!strcmp(tag, "TPE1")) sprintf(m_chbuf, "Artist: %s", value); 1003 if(!strcmp(tag, "TPE2")) sprintf(m_chbuf, "Band: %s", value); 1004 if(!strcmp(tag, "TPE3")) sprintf(m_chbuf, "Conductor: %s", value); 1005 if(!strcmp(tag, "TPE4")) sprintf(m_chbuf, "InterpretedBy: %s", value); 1006 if(!strcmp(tag, "TPOS")) sprintf(m_chbuf, "PartOfSet: %s", value); 1007 if(!strcmp(tag, "TPUB")) sprintf(m_chbuf, "Publisher: %s", value); 1008 if(!strcmp(tag, "TRCK")) sprintf(m_chbuf, "Track: %s", value); 1009 if(!strcmp(tag, "TSSE")) sprintf(m_chbuf, "SettingsForEncoding: %s", value); 1010 if(!strcmp(tag, "TRDA")) sprintf(m_chbuf, "RecordingDates: %s", value); 1011 if(!m_f_m3u8data) if(!strcmp(tag, "TXXX")) sprintf(m_chbuf, "UserDefinedText: %s", value); 1012 if(!strcmp(tag, "TYER")) sprintf(m_chbuf, "Year: %s", value); 1013 if(!strcmp(tag, "USER")) sprintf(m_chbuf, "TermsOfUse: %s", value); 1014 if(!strcmp(tag, "USLT")) sprintf(m_chbuf, "Lyrics: %s", value); 1015 if(!strcmp(tag, "WOAR")) sprintf(m_chbuf, "OfficialArtistWebpage: %s", value); 1016 if(!strcmp(tag, "XDOR")) sprintf(m_chbuf, "OriginalReleaseTime: %s", value); 1017 1018 latinToUTF8(m_chbuf, sizeof(m_chbuf)); 1019 if(m_chbuf[0] != 0) if(audio_id3data) audio_id3data(m_chbuf); 1020 } 1021 //--------------------------------------------------------------------------------------------------------------------- 1022 void Audio::unicode2utf8(char* buff, uint32_t len){ 1023 // converts unicode in UTF-8, buff contains the string to be converted up to len 1024 // range U+1 ... U+FFFF 1025 uint8_t* tmpbuff = (uint8_t*)malloc(len * 2); 1026 if(!tmpbuff) {log_e("out of memory"); return;} 1027 bool bitorder = false; 1028 uint16_t j = 0; 1029 uint16_t k = 0; 1030 uint16_t m = 0; 1031 uint8_t uni_h = 0; 1032 uint8_t uni_l = 0; 1033 1034 while(m < len - 1) { 1035 if((buff[m] == 0xFE) && (buff[m + 1] == 0xFF)) { 1036 bitorder = true; 1037 j = m + 2; 1038 } // LSB/MSB 1039 if((buff[m] == 0xFF) && (buff[m + 1] == 0xFE)) { 1040 bitorder = false; 1041 j = m + 2; 1042 } // MSB/LSB 1043 m++; 1044 } // seek for last bitorder 1045 m = 0; 1046 if(j > 0) { 1047 for(k = j; k < len; k += 2) { 1048 if(bitorder == true) { 1049 uni_h = (uint8_t)buff[k]; 1050 uni_l = (uint8_t)buff[k + 1]; 1051 } 1052 else { 1053 uni_l = (uint8_t)buff[k]; 1054 uni_h = (uint8_t)buff[k + 1]; 1055 } 1056 1057 uint16_t uni_hl = ((uni_h << 8) | uni_l); 1058 1059 if (uni_hl < 0X80){ 1060 tmpbuff[m] = uni_l; 1061 m++; 1062 } 1063 else if (uni_hl < 0X800) { 1064 tmpbuff[m]= ((uni_hl >> 6) | 0XC0); 1065 m++; 1066 tmpbuff[m] =((uni_hl & 0X3F) | 0X80); 1067 m++; 1068 } 1069 else { 1070 tmpbuff[m] = ((uni_hl >> 12) | 0XE0); 1071 m++; 1072 tmpbuff[m] = (((uni_hl >> 6) & 0X3F) | 0X80); 1073 m++; 1074 tmpbuff[m] = ((uni_hl & 0X3F) | 0X80); 1075 m++; 1076 } 1077 } 1078 } 1079 buff[m] = 0; 1080 memcpy(buff, tmpbuff, m); 1081 if(tmpbuff){free(tmpbuff); tmpbuff = NULL;} 1082 } 1083 //--------------------------------------------------------------------------------------------------------------------- 1084 bool Audio::latinToUTF8(char* buff, size_t bufflen){ 1085 // most stations send strings in UTF-8 but a few sends in latin. To standardize this, all latin strings are 1086 // converted to UTF-8. If UTF-8 is already present, nothing is done and true is returned. 1087 // A conversion to UTF-8 extends the string. Therefore it is necessary to know the buffer size. If the converted 1088 // string does not fit into the buffer, false is returned 1089 // utf8 bytelength: >=0xF0 3 bytes, >=0xE0 2 bytes, >=0xC0 1 byte, e.g. e293ab is ⓫ 1090 1091 uint16_t pos = 0; 1092 uint8_t ext_bytes = 0; 1093 uint16_t len = strlen(buff); 1094 uint8_t c; 1095 1096 while(pos < len){ 1097 c = buff[pos]; 1098 if(c >= 0xC2) { // is UTF8 char 1099 pos++; 1100 if(c >= 0xC0 && buff[pos] < 0x80) {ext_bytes++; pos++;} 1101 if(c >= 0xE0 && buff[pos] < 0x80) {ext_bytes++; pos++;} 1102 if(c >= 0xF0 && buff[pos] < 0x80) {ext_bytes++; pos++;} 1103 } 1104 else pos++; 1105 } 1106 if(!ext_bytes) return true; // is UTF-8, do nothing 1107 1108 pos = 0; 1109 1110 while(buff[pos] != 0){ 1111 len = strlen(buff); 1112 if(buff[pos] >= 0x80 && buff[pos+1] < 0x80){ // is not UTF8, is latin? 1113 for(int i = len+1; i > pos; i--){ 1114 buff[i+1] = buff[i]; 1115 } 1116 uint8_t c = buff[pos]; 1117 buff[pos++] = 0xc0 | ((c >> 6) & 0x1f); // 2+1+5 bits 1118 buff[pos++] = 0x80 | ((char)c & 0x3f); // 1+1+6 bits 1119 } 1120 pos++; 1121 if(pos > bufflen -3){ 1122 buff[bufflen -1] = '\0'; 1123 return false; // do not overwrite 1124 } 1125 } 1126 return true; 1127 } 1128 //--------------------------------------------------------------------------------------------------------------------- 1129 size_t Audio::readAudioHeader(uint32_t bytes){ 1130 size_t bytesReaded = 0; 1131 if(m_codec == CODEC_WAV){ 1132 int res = read_WAV_Header(InBuff.getReadPtr(), bytes); 1133 if(res >= 0) bytesReaded = res; 1134 else{ // error, skip header 1135 m_controlCounter = 100; 1136 } 1137 } 1138 if(m_codec == CODEC_MP3){ 1139 int res = read_ID3_Header(InBuff.getReadPtr(), bytes); 1140 if(res >= 0) bytesReaded = res; 1141 else{ // error, skip header 1142 m_controlCounter = 100; 1143 } 1144 } 1145 if(m_codec == CODEC_M4A){ 1146 int res = read_M4A_Header(InBuff.getReadPtr(), bytes); 1147 if(res >= 0) bytesReaded = res; 1148 else{ // error, skip header 1149 m_controlCounter = 100; 1150 } 1151 } 1152 if(m_codec == CODEC_AAC){ 1153 // stream only, no header 1154 m_audioDataSize = getFileSize(); 1155 m_controlCounter = 100; 1156 } 1157 if(m_codec == CODEC_FLAC){ 1158 int res = read_FLAC_Header(InBuff.getReadPtr(), bytes); 1159 if(res >= 0) bytesReaded = res; 1160 else{ // error, skip header 1161 stopSong(); 1162 m_controlCounter = 100; 1163 } 1164 } 1165 if(!isRunning()){ 1166 log_e("Processing stopped due to invalid audio header"); 1167 return 0; 1168 } 1169 return bytesReaded; 1170 } 1171 //--------------------------------------------------------------------------------------------------------------------- 1172 int Audio::read_WAV_Header(uint8_t* data, size_t len) { 1173 static size_t headerSize; 1174 static uint32_t cs = 0; 1175 static uint8_t bts = 0; 1176 1177 if(m_controlCounter == 0){ 1178 m_controlCounter ++; 1179 if((*data != 'R') || (*(data + 1) != 'I') || (*(data + 2) != 'F') || (*(data + 3) != 'F')) { 1180 AUDIO_INFO("file has no RIFF tag"); 1181 headerSize = 0; 1182 return -1; //false; 1183 } 1184 else{ 1185 headerSize = 4; 1186 return 4; // ok 1187 } 1188 } 1189 1190 if(m_controlCounter == 1){ 1191 m_controlCounter ++; 1192 cs = (uint32_t) (*data + (*(data + 1) << 8) + (*(data + 2) << 16) + (*(data + 3) << 24) - 8); 1193 headerSize += 4; 1194 return 4; // ok 1195 } 1196 1197 if(m_controlCounter == 2){ 1198 m_controlCounter ++; 1199 if((*data != 'W') || (*(data + 1) != 'A') || (*(data + 2) != 'V') || (*(data + 3) != 'E')) { 1200 AUDIO_INFO("format tag is not WAVE"); 1201 return -1;//false; 1202 } 1203 else { 1204 headerSize += 4; 1205 return 4; 1206 } 1207 } 1208 1209 if(m_controlCounter == 3){ 1210 if((*data == 'f') && (*(data + 1) == 'm') && (*(data + 2) == 't')) { 1211 m_controlCounter ++; 1212 headerSize += 4; 1213 return 4; 1214 } 1215 else{ 1216 headerSize += 4; 1217 return 4; 1218 } 1219 } 1220 1221 if(m_controlCounter == 4){ 1222 m_controlCounter ++; 1223 cs = (uint32_t) (*data + (*(data + 1) << 8)); 1224 if(cs > 40) return -1; //false, something going wrong 1225 bts = cs - 16; // bytes to skip if fmt chunk is >16 1226 headerSize += 4; 1227 return 4; 1228 } 1229 1230 if(m_controlCounter == 5){ 1231 m_controlCounter ++; 1232 uint16_t fc = (uint16_t) (*(data + 0) + (*(data + 1) << 8)); // Format code 1233 uint16_t nic = (uint16_t) (*(data + 2) + (*(data + 3) << 8)); // Number of interleaved channels 1234 uint32_t sr = (uint32_t) (*(data + 4) + (*(data + 5) << 8) + 1235 (*(data + 6) << 16) + (*(data + 7) << 24)); // Samplerate 1236 uint32_t dr = (uint32_t) (*(data + 8) + (*(data + 9) << 8) + 1237 (*(data + 10) << 16) + (*(data + 11) << 24)); // Datarate 1238 uint16_t dbs = (uint16_t) (*(data + 12) + (*(data + 13) << 8)); // Data block size 1239 uint16_t bps = (uint16_t) (*(data + 14) + (*(data + 15) << 8)); // Bits per sample 1240 1241 AUDIO_INFO("FormatCode: %u", fc); 1242 // AUDIO_INFO("Channel: %u", nic); 1243 // AUDIO_INFO("SampleRate: %u", sr); 1244 AUDIO_INFO("DataRate: %u", dr); 1245 AUDIO_INFO("DataBlockSize: %u", dbs); 1246 AUDIO_INFO("BitsPerSample: %u", bps); 1247 1248 if((bps != 8) && (bps != 16)){ 1249 AUDIO_INFO("BitsPerSample is %u, must be 8 or 16" , bps); 1250 stopSong(); 1251 return -1; 1252 } 1253 if((nic != 1) && (nic != 2)){ 1254 AUDIO_INFO("num channels is %u, must be 1 or 2" , nic); audio_info(m_chbuf); 1255 stopSong(); 1256 return -1; 1257 } 1258 if(fc != 1) { 1259 AUDIO_INFO("format code is not 1 (PCM)"); 1260 stopSong(); 1261 return -1 ; //false; 1262 } 1263 setBitsPerSample(bps); 1264 setChannels(nic); 1265 setSampleRate(sr); 1266 setBitrate(nic * sr * bps); 1267 // AUDIO_INFO("BitRate: %u", m_bitRate); 1268 headerSize += 16; 1269 return 16; // ok 1270 } 1271 1272 if(m_controlCounter == 6){ 1273 m_controlCounter ++; 1274 headerSize += bts; 1275 return bts; // skip to data 1276 } 1277 1278 if(m_controlCounter == 7){ 1279 if((*(data + 0) == 'd') && (*(data + 1) == 'a') && (*(data + 2) == 't') && (*(data + 3) == 'a')){ 1280 m_controlCounter ++; 1281 vTaskDelay(30); 1282 headerSize += 4; 1283 return 4; 1284 } 1285 else{ 1286 headerSize ++; 1287 return 1; 1288 } 1289 } 1290 1291 if(m_controlCounter == 8){ 1292 m_controlCounter ++; 1293 size_t cs = *(data + 0) + (*(data + 1) << 8) + (*(data + 2) << 16) + (*(data + 3) << 24); //read chunkSize 1294 headerSize += 4; 1295 if(getDatamode() == AUDIO_LOCALFILE) m_contentlength = getFileSize(); 1296 if(cs){ 1297 m_audioDataSize = cs - 44; 1298 } 1299 else { // sometimes there is nothing here 1300 if(getDatamode() == AUDIO_LOCALFILE) m_audioDataSize = getFileSize() - headerSize; 1301 if(m_streamType == ST_WEBFILE) m_audioDataSize = m_contentlength - headerSize; 1302 } 1303 AUDIO_INFO("Audio-Length: %u", m_audioDataSize); 1304 return 4; 1305 } 1306 m_controlCounter = 100; // header succesfully read 1307 m_audioDataStart = headerSize; 1308 return 0; 1309 } 1310 //--------------------------------------------------------------------------------------------------------------------- 1311 int Audio::read_FLAC_Header(uint8_t *data, size_t len) { 1312 static size_t headerSize; 1313 static size_t retvalue = 0; 1314 static bool f_lastMetaBlock; 1315 1316 if(retvalue) { 1317 if(retvalue > len) { // if returnvalue > bufferfillsize 1318 if(len > InBuff.getMaxBlockSize()) len = InBuff.getMaxBlockSize(); 1319 retvalue -= len; // and wait for more bufferdata 1320 return len; 1321 } 1322 else { 1323 size_t tmp = retvalue; 1324 retvalue = 0; 1325 return tmp; 1326 } 1327 return 0; 1328 } 1329 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1330 if(m_controlCounter == FLAC_BEGIN) { // init 1331 headerSize = 0; 1332 retvalue = 0; 1333 m_audioDataStart = 0; 1334 f_lastMetaBlock = false; 1335 m_controlCounter = FLAC_MAGIC; 1336 if(getDatamode() == AUDIO_LOCALFILE){ 1337 m_contentlength = getFileSize(); 1338 AUDIO_INFO("Content-Length: %u", m_contentlength); 1339 } 1340 return 0; 1341 } 1342 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1343 if(m_controlCounter == FLAC_MAGIC) { /* check MAGIC STRING */ 1344 if(specialIndexOf(data, "fLaC", 10) != 0) { 1345 log_e("Magic String 'fLaC' not found in header"); 1346 stopSong(); 1347 return -1; 1348 } 1349 m_controlCounter = FLAC_MBH; 1350 headerSize = 4; 1351 retvalue = 4; 1352 return 0; 1353 } 1354 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1355 if(m_controlCounter == FLAC_MBH) { /* METADATA_BLOCK_HEADER */ 1356 uint8_t blockType = *data; 1357 if(!f_lastMetaBlock){ 1358 if(blockType & 128) {f_lastMetaBlock = true;} 1359 blockType &= 127; 1360 if(blockType == 0) m_controlCounter = FLAC_SINFO; 1361 if(blockType == 1) m_controlCounter = FLAC_PADDING; 1362 if(blockType == 2) m_controlCounter = FLAC_APP; 1363 if(blockType == 3) m_controlCounter = FLAC_SEEK; 1364 if(blockType == 4) m_controlCounter = FLAC_VORBIS; 1365 if(blockType == 5) m_controlCounter = FLAC_CUESHEET; 1366 if(blockType == 6) m_controlCounter = FLAC_PICTURE; 1367 headerSize += 1; 1368 retvalue = 1; 1369 return 0; 1370 } 1371 m_controlCounter = FLAC_OKAY; 1372 m_audioDataStart = headerSize; 1373 m_audioDataSize = m_contentlength - m_audioDataStart; 1374 AUDIO_INFO("Audio-Length: %u", m_audioDataSize); 1375 retvalue = 0; 1376 return 0; 1377 } 1378 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1379 if(m_controlCounter == FLAC_SINFO) { /* Stream info block */ 1380 size_t l = bigEndian(data, 3); 1381 vTaskDelay(2); 1382 m_flacMaxBlockSize = bigEndian(data + 5, 2); 1383 AUDIO_INFO("FLAC maxBlockSize: %u", m_flacMaxBlockSize); 1384 vTaskDelay(2); 1385 m_flacMaxFrameSize = bigEndian(data + 10, 3); 1386 if(m_flacMaxFrameSize){ 1387 AUDIO_INFO("FLAC maxFrameSize: %u", m_flacMaxFrameSize); 1388 } 1389 else { 1390 AUDIO_INFO("FLAC maxFrameSize: N/A"); 1391 } 1392 if(m_flacMaxFrameSize > InBuff.getMaxBlockSize()) { 1393 log_e("FLAC maxFrameSize too large!"); 1394 stopSong(); 1395 return -1; 1396 } 1397 // InBuff.changeMaxBlockSize(m_flacMaxFrameSize); 1398 vTaskDelay(2); 1399 uint32_t nextval = bigEndian(data + 13, 3); 1400 m_flacSampleRate = nextval >> 4; 1401 AUDIO_INFO("FLAC sampleRate: %u", m_flacSampleRate); 1402 vTaskDelay(2); 1403 m_flacNumChannels = ((nextval & 0x06) >> 1) + 1; 1404 AUDIO_INFO("FLAC numChannels: %u", m_flacNumChannels); 1405 vTaskDelay(2); 1406 uint8_t bps = (nextval & 0x01) << 4; 1407 bps += (*(data +16) >> 4) + 1; 1408 m_flacBitsPerSample = bps; 1409 if((bps != 8) && (bps != 16)){ 1410 log_e("bits per sample must be 8 or 16, is %i", bps); 1411 stopSong(); 1412 return -1; 1413 } 1414 AUDIO_INFO("FLAC bitsPerSample: %u", m_flacBitsPerSample); 1415 m_flacTotalSamplesInStream = bigEndian(data + 17, 4); 1416 if(m_flacTotalSamplesInStream){ 1417 AUDIO_INFO("total samples in stream: %u", m_flacTotalSamplesInStream); 1418 } 1419 else{ 1420 AUDIO_INFO("total samples in stream: N/A"); 1421 } 1422 if(bps != 0 && m_flacTotalSamplesInStream) { 1423 AUDIO_INFO("audio file duration: %u seconds", m_flacTotalSamplesInStream / m_flacSampleRate); 1424 } 1425 m_controlCounter = FLAC_MBH; // METADATA_BLOCK_HEADER 1426 retvalue = l + 3; 1427 headerSize += retvalue; 1428 return 0; 1429 } 1430 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1431 if(m_controlCounter == FLAC_PADDING) { /* PADDING */ 1432 size_t l = bigEndian(data, 3); 1433 m_controlCounter = FLAC_MBH; 1434 retvalue = l + 3; 1435 headerSize += retvalue; 1436 return 0; 1437 } 1438 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1439 if(m_controlCounter == FLAC_APP) { /* APPLICATION */ 1440 size_t l = bigEndian(data, 3); 1441 m_controlCounter = FLAC_MBH; 1442 retvalue = l + 3; 1443 headerSize += retvalue; 1444 return 0; 1445 } 1446 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1447 if(m_controlCounter == FLAC_SEEK) { /* SEEKTABLE */ 1448 size_t l = bigEndian(data, 3); 1449 m_controlCounter = FLAC_MBH; 1450 retvalue = l + 3; 1451 headerSize += retvalue; 1452 return 0; 1453 } 1454 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1455 if(m_controlCounter == FLAC_VORBIS) { /* VORBIS COMMENT */ // field names 1456 const char fn[7][12] = {"TITLE", "VERSION", "ALBUM", "TRACKNUMBER", "ARTIST", "PERFORMER", "GENRE"}; 1457 int offset; 1458 size_t l = bigEndian(data, 3); 1459 1460 for(int i = 0; i < 7; i++){ 1461 offset = specialIndexOf(data, fn[i], len); 1462 if(offset >= 0){ 1463 sprintf(m_chbuf, "%s: %s", fn[i], data + offset + strlen(fn[i]) + 1); 1464 m_chbuf[strlen(m_chbuf) - 1] = 0; 1465 for(int i=0; i<strlen(m_chbuf);i++){ 1466 if(m_chbuf[i] == 255) m_chbuf[i] = 0; 1467 } 1468 if(audio_id3data) audio_id3data(m_chbuf); 1469 } 1470 } 1471 m_controlCounter = FLAC_MBH; 1472 retvalue = l + 3; 1473 headerSize += retvalue; 1474 return 0; 1475 } 1476 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1477 if(m_controlCounter == FLAC_CUESHEET) { /* CUESHEET */ 1478 size_t l = bigEndian(data, 3); 1479 m_controlCounter = FLAC_MBH; 1480 retvalue = l + 3; 1481 headerSize += retvalue; 1482 return 0; 1483 } 1484 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1485 if(m_controlCounter == FLAC_PICTURE) { /* PICTURE */ 1486 size_t l = bigEndian(data, 3); 1487 m_controlCounter = FLAC_MBH; 1488 retvalue = l + 3; 1489 headerSize += retvalue; 1490 return 0; 1491 } 1492 return 0; 1493 } 1494 //--------------------------------------------------------------------------------------------------------------------- 1495 int Audio::read_ID3_Header(uint8_t *data, size_t len) { 1496 1497 static size_t id3Size; 1498 static size_t headerSize; 1499 static uint8_t ID3version; 1500 static int ehsz = 0; 1501 static char tag[5]; 1502 static char frameid[5]; 1503 static size_t framesize = 0; 1504 static bool compressed = false; 1505 static bool APIC_seen = false; 1506 static size_t APIC_size = 0; 1507 static uint32_t APIC_pos = 0; 1508 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1509 if(m_controlCounter == 0){ /* read ID3 tag and ID3 header size */ 1510 if(getDatamode() == AUDIO_LOCALFILE){ 1511 ID3version = 0; 1512 m_contentlength = getFileSize(); 1513 AUDIO_INFO("Content-Length: %u", m_contentlength); 1514 } 1515 m_controlCounter ++; 1516 APIC_seen = false; 1517 headerSize = 0; 1518 ehsz = 0; 1519 if(specialIndexOf(data, "ID3", 4) != 0) { // ID3 not found 1520 if(!m_f_m3u8data) AUDIO_INFO("file has no mp3 tag, skip metadata"); 1521 m_audioDataSize = m_contentlength; 1522 if(!m_f_m3u8data) AUDIO_INFO("Audio-Length: %u", m_audioDataSize); 1523 return -1; // error, no ID3 signature found 1524 } 1525 ID3version = *(data + 3); 1526 switch(ID3version){ 1527 case 2: 1528 m_f_unsync = (*(data + 5) & 0x80); 1529 m_f_exthdr = false; 1530 break; 1531 case 3: 1532 case 4: 1533 m_f_unsync = (*(data + 5) & 0x80); // bit7 1534 m_f_exthdr = (*(data + 5) & 0x40); // bit6 extended header 1535 break; 1536 }; 1537 id3Size = bigEndian(data + 6, 4, 7); // ID3v2 size 4 * %0xxxxxxx (shift left seven times!!) 1538 id3Size += 10; 1539 1540 // Every read from now may be unsync'd 1541 if(!m_f_m3u8data) AUDIO_INFO("ID3 framesSize: %i", id3Size); 1542 if(!m_f_m3u8data) AUDIO_INFO("ID3 version: 2.%i", ID3version); 1543 1544 if(ID3version == 2){ 1545 m_controlCounter = 10; 1546 } 1547 headerSize = id3Size; 1548 m_ID3Size = id3Size; 1549 headerSize -= 10; 1550 1551 return 10; 1552 } 1553 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1554 if(m_controlCounter == 1){ // compute extended header size if exists 1555 m_controlCounter ++; 1556 if(m_f_exthdr) { 1557 AUDIO_INFO("ID3 extended header"); 1558 ehsz = bigEndian(data, 4); 1559 headerSize -= 4; 1560 ehsz -= 4; 1561 return 4; 1562 } 1563 else{ 1564 if(!m_f_m3u8data) AUDIO_INFO("ID3 normal frames"); 1565 return 0; 1566 } 1567 } 1568 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1569 if(m_controlCounter == 2){ // skip extended header if exists 1570 if(ehsz > 256) { 1571 ehsz -=256; 1572 headerSize -= 256; 1573 return 256;} // Throw it away 1574 else { 1575 m_controlCounter ++; 1576 headerSize -= ehsz; 1577 return ehsz;} // Throw it away 1578 } 1579 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1580 if(m_controlCounter == 3){ // read a ID3 frame, get the tag 1581 if(headerSize == 0){ 1582 m_controlCounter = 99; 1583 return 0; 1584 } 1585 m_controlCounter ++; 1586 frameid[0] = *(data + 0); 1587 frameid[1] = *(data + 1); 1588 frameid[2] = *(data + 2); 1589 frameid[3] = *(data + 3); 1590 frameid[4] = 0; 1591 for(uint8_t i = 0; i < 4; i++) tag[i] = frameid[i]; // tag = frameid 1592 1593 headerSize -= 4; 1594 if(frameid[0] == 0 && frameid[1] == 0 && frameid[2] == 0 && frameid[3] == 0) { 1595 // We're in padding 1596 m_controlCounter = 98; // all ID3 metadata processed 1597 } 1598 return 4; 1599 } 1600 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1601 if(m_controlCounter == 4){ // get the frame size 1602 m_controlCounter = 6; 1603 1604 if(ID3version == 4){ 1605 framesize = bigEndian(data, 4, 7); // << 7 1606 } 1607 else { 1608 framesize = bigEndian(data, 4); // << 8 1609 } 1610 headerSize -= 4; 1611 uint8_t flag = *(data + 4); // skip 1st flag 1612 (void) flag; 1613 headerSize--; 1614 compressed = (*(data + 5)) & 0x80; // Frame is compressed using [#ZLIB zlib] with 4 bytes for 'decompressed 1615 // size' appended to the frame header. 1616 headerSize--; 1617 uint32_t decompsize = 0; 1618 if(compressed){ 1619 if(m_f_Log) log_i("iscompressed"); 1620 decompsize = bigEndian(data + 6, 4); 1621 headerSize -= 4; 1622 (void) decompsize; 1623 if(m_f_Log) log_i("decompsize=%u", decompsize); 1624 return 6 + 4; 1625 } 1626 return 6; 1627 } 1628 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1629 if(m_controlCounter == 5){ // If the frame is larger than 256 bytes, skip the rest 1630 if(framesize > 256){ 1631 framesize -= 256; 1632 headerSize -= 256; 1633 return 256; 1634 } 1635 else { 1636 m_controlCounter = 3; // check next frame 1637 headerSize -= framesize; 1638 return framesize; 1639 } 1640 } 1641 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1642 if(m_controlCounter == 6){ // Read the value 1643 m_controlCounter = 5; // only read 256 bytes 1644 char value[256]; 1645 char ch = *(data + 0); 1646 // $00 – ISO-8859-1 (LATIN-1, Identical to ASCII for values smaller than 0x80). 1647 // $01 – UCS-2 encoded Unicode with BOM, in ID3v2.2 and ID3v2.3. 1648 // $02 – UTF-16BE encoded Unicode without BOM, in ID3v2.4. 1649 // $03 – UTF-8 encoded Unicode, in ID3v2.4. 1650 bool isUnicode = (ch==1) ? true : false; 1651 1652 if(startsWith(tag, "APIC")) { // a image embedded in file, passing it to external function 1653 isUnicode = false; 1654 if(getDatamode() == AUDIO_LOCALFILE){ 1655 APIC_seen = true; 1656 APIC_pos = id3Size - headerSize; 1657 APIC_size = framesize; 1658 } 1659 return 0; 1660 } 1661 1662 size_t fs = framesize; 1663 if(fs >255) fs = 255; 1664 for(int i=0; i<fs; i++){ 1665 value[i] = *(data + i); 1666 } 1667 framesize -= fs; 1668 headerSize -= fs; 1669 value[fs] = 0; 1670 if(isUnicode && fs > 1) { 1671 unicode2utf8(value, fs); // convert unicode to utf-8 U+0020...U+07FF 1672 } 1673 if(!isUnicode){ 1674 uint16_t j = 0, k = 0; 1675 j = 0; 1676 k = 0; 1677 while(j < fs) { 1678 if(value[j] == 0x0A) value[j] = 0x20; // replace LF by space 1679 if(value[j] > 0x1F) { 1680 value[k] = value[j]; 1681 k++; 1682 } 1683 j++; 1684 } //remove non printables 1685 if(k>0) value[k] = 0; else value[0] = 0; // new termination 1686 } 1687 showID3Tag(tag, value); 1688 return fs; 1689 } 1690 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1691 1692 // -- section V2.2 only , greater Vers above ---- 1693 if(m_controlCounter == 10){ // frames in V2.2, 3bytes identifier, 3bytes size descriptor 1694 frameid[0] = *(data + 0); 1695 frameid[1] = *(data + 1); 1696 frameid[2] = *(data + 2); 1697 frameid[3] = 0; 1698 for(uint8_t i = 0; i < 4; i++) tag[i] = frameid[i]; // tag = frameid 1699 headerSize -= 3; 1700 size_t len = bigEndian(data + 3, 3); 1701 headerSize -= 3; 1702 headerSize -= len; 1703 char value[256]; 1704 size_t tmp = len; 1705 if(tmp > 254) tmp = 254; 1706 memcpy(value, (data + 7), tmp); 1707 value[tmp+1] = 0; 1708 m_chbuf[0] = 0; 1709 1710 showID3Tag(tag, value); 1711 if(len == 0) m_controlCounter = 98; 1712 1713 return 3 + 3 + len; 1714 } 1715 // -- end section V2.2 ----------- 1716 1717 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1718 if(m_controlCounter == 98){ // skip all ID3 metadata (mostly spaces) 1719 if(headerSize > 256) { 1720 headerSize -=256; 1721 return 256; 1722 } // Throw it away 1723 else { 1724 m_controlCounter = 99; 1725 return headerSize; 1726 } // Throw it away 1727 } 1728 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1729 if(m_controlCounter == 99){ // exist another ID3tag? 1730 m_audioDataStart += id3Size; 1731 vTaskDelay(30); 1732 if((*(data + 0) == 'I') && (*(data + 1) == 'D') && (*(data + 2) == '3')) { 1733 m_controlCounter = 0; 1734 return 0; 1735 } 1736 else { 1737 m_controlCounter = 100; // ok 1738 m_audioDataSize = m_contentlength - m_audioDataStart; 1739 if(!m_f_m3u8data) AUDIO_INFO("Audio-Length: %u", m_audioDataSize); 1740 #ifndef AUDIO_NO_SD_FS 1741 if(APIC_seen && audio_id3image){ 1742 size_t pos = audiofile.position(); 1743 audio_id3image(audiofile, APIC_pos, APIC_size); 1744 audiofile.seek(pos); // the filepointer could have been changed by the user, set it back 1745 } 1746 #endif // AUDIO_NO_SD_FS 1747 return 0; 1748 } 1749 } 1750 return 0; 1751 } 1752 //--------------------------------------------------------------------------------------------------------------------- 1753 int Audio::read_M4A_Header(uint8_t *data, size_t len) { 1754 /* 1755 ftyp 1756 | - moov -> trak -> ... -> mp4a contains raw block parameters 1757 | L... -> ilst contains artist, composer .... 1758 free (optional) // jump to another atoms at the end of mdat 1759 | 1760 mdat contains the audio data */ 1761 1762 1763 static size_t headerSize = 0; 1764 static size_t retvalue = 0; 1765 static size_t atomsize = 0; 1766 static size_t audioDataPos = 0; 1767 1768 if(retvalue) { 1769 if(retvalue > len) { // if returnvalue > bufferfillsize 1770 if(len > InBuff.getMaxBlockSize()) len = InBuff.getMaxBlockSize(); 1771 retvalue -= len; // and wait for more bufferdata 1772 return len; 1773 } 1774 else { 1775 size_t tmp = retvalue; 1776 retvalue = 0; 1777 return tmp; 1778 } 1779 return 0; 1780 } 1781 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1782 if(m_controlCounter == M4A_BEGIN) { // init 1783 headerSize = 0; 1784 retvalue = 0; 1785 atomsize = 0; 1786 audioDataPos = 0; 1787 m_controlCounter = M4A_FTYP; 1788 return 0; 1789 } 1790 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1791 if(m_controlCounter == M4A_FTYP) { /* check_m4a_file */ 1792 atomsize = bigEndian(data, 4); // length of first atom 1793 if(specialIndexOf(data, "ftyp", 10) != 4) { 1794 log_e("atom 'type' not found in header"); 1795 stopSong(); 1796 return -1; 1797 } 1798 int m4a = specialIndexOf(data, "M4A ", 20); 1799 int isom = specialIndexOf(data, "isom", 20); 1800 1801 if((m4a !=8) && (isom != 8)){ 1802 log_e("subtype 'MA4 ' or 'isom' expected, but found '%s '", (data + 8)); 1803 stopSong(); 1804 return -1; 1805 } 1806 1807 m_controlCounter = M4A_CHK; 1808 retvalue = atomsize; 1809 headerSize = atomsize; 1810 return 0; 1811 } 1812 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1813 if(m_controlCounter == M4A_CHK) { /* check Tag */ 1814 atomsize = bigEndian(data, 4); // length of this atom 1815 if(specialIndexOf(data, "moov", 10) == 4) { 1816 m_controlCounter = M4A_MOOV; 1817 return 0; 1818 } 1819 else if(specialIndexOf(data, "free", 10) == 4) { 1820 retvalue = atomsize; 1821 headerSize += atomsize; 1822 return 0; 1823 } 1824 else if(specialIndexOf(data, "mdat", 10) == 4) { 1825 m_controlCounter = M4A_MDAT; 1826 return 0; 1827 } 1828 else { 1829 char atomName[5]; 1830 (void)atomName; 1831 atomName[0] = *data; 1832 atomName[1] = *(data + 1); 1833 atomName[2] = *(data + 2); 1834 atomName[3] = *(data + 3); 1835 atomName[4] = 0; 1836 1837 if(m_f_Log) log_i("atom %s found", atomName); 1838 1839 retvalue = atomsize; 1840 headerSize += atomsize; 1841 return 0; 1842 } 1843 } 1844 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1845 if(m_controlCounter == M4A_MOOV) { // moov 1846 // we are looking for track and ilst 1847 if(specialIndexOf(data, "trak", len) > 0){ 1848 int offset = specialIndexOf(data, "trak", len); 1849 retvalue = offset; 1850 atomsize -= offset; 1851 headerSize += offset; 1852 m_controlCounter = M4A_TRAK; 1853 return 0; 1854 } 1855 if(specialIndexOf(data, "ilst", len) > 0){ 1856 int offset = specialIndexOf(data, "ilst", len); 1857 retvalue = offset; 1858 atomsize -= offset; 1859 headerSize += offset; 1860 m_controlCounter = M4A_ILST; 1861 return 0; 1862 1863 } 1864 if (atomsize > len -10){atomsize -= (len -10); headerSize += (len -10); retvalue = (len -10);} 1865 else {m_controlCounter = M4A_CHK; retvalue = atomsize; headerSize += atomsize;} 1866 return 0; 1867 } 1868 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1869 if(m_controlCounter == M4A_TRAK) { // trak 1870 if(specialIndexOf(data, "esds", len) > 0){ 1871 int esds = specialIndexOf(data, "esds", len); // Packaging/Encapsulation And Setup Data 1872 uint8_t *pos = data + esds; 1873 uint8_t len_of_OD = *(pos + 12); // length of this OD (which includes the next 2 tags) 1874 (void)len_of_OD; 1875 uint8_t len_of_ESD = *(pos + 20); // length of this Elementary Stream Descriptor 1876 (void)len_of_ESD; 1877 uint8_t audioType = *(pos + 21); 1878 1879 if (audioType == 0x40) {AUDIO_INFO("AudioType: MPEG4 / Audio");} // ObjectTypeIndication 1880 else if(audioType == 0x66) {AUDIO_INFO("AudioType: MPEG2 / Audio");} 1881 else if(audioType == 0x69) {AUDIO_INFO("AudioType: MPEG2 / Audio Part 3");} // Backward Compatible Audio 1882 else if(audioType == 0x6B) {AUDIO_INFO("AudioType: MPEG1 / Audio");} 1883 else {AUDIO_INFO("unknown Audio Type %x", audioType);} 1884 1885 uint8_t streamType = *(pos + 22); 1886 streamType = streamType >> 2; // 6 bits 1887 if(streamType!= 5) { log_e("Streamtype is not audio!"); } 1888 1889 uint32_t maxBr = bigEndian(pos + 26, 4); // max bitrate 1890 AUDIO_INFO("max bitrate: %i", maxBr); 1891 1892 uint32_t avrBr = bigEndian(pos + 30, 4); // avg bitrate 1893 AUDIO_INFO("avr bitrate: %i", avrBr); 1894 1895 uint16_t ASC = bigEndian(pos + 39, 2); 1896 1897 uint8_t objectType = ASC >> 11; // first 5 bits 1898 1899 if (objectType == 1) {AUDIO_INFO("AudioObjectType: AAC Main");} // Audio Object Types 1900 else if(objectType == 2) {AUDIO_INFO("AudioObjectType: AAC Low Complexity");} 1901 else if(objectType == 3) {AUDIO_INFO("AudioObjectType: AAC Scalable Sample Rate");} 1902 else if(objectType == 4) {AUDIO_INFO("AudioObjectType: AAC Long Term Prediction");} 1903 else if(objectType == 5) {AUDIO_INFO("AudioObjectType: AAC Spectral Band Replication");} 1904 else if(objectType == 6) {AUDIO_INFO("AudioObjectType: AAC Scalable");} 1905 else {AUDIO_INFO("unknown Audio Type %x", audioType);} 1906 1907 const uint32_t samplingFrequencies[13] = { 1908 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350 1909 }; 1910 uint8_t sRate = (ASC & 0x0600) >> 7; // next 4 bits Sampling Frequencies 1911 AUDIO_INFO("Sampling Frequency: %u",samplingFrequencies[sRate]); 1912 1913 uint8_t chConfig = (ASC & 0x78) >> 3; // next 4 bits 1914 if(chConfig == 0) AUDIO_INFO("Channel Configurations: AOT Specifc Config"); 1915 if(chConfig == 1) AUDIO_INFO("Channel Configurations: front-center"); 1916 if(chConfig == 2) AUDIO_INFO("Channel Configurations: front-left, front-right"); 1917 if(chConfig > 2) { log_e("Channel Configurations with more than 2 channels is not allowed!"); } 1918 1919 uint8_t frameLengthFlag = (ASC & 0x04); 1920 uint8_t dependsOnCoreCoder = (ASC & 0x02); 1921 (void)dependsOnCoreCoder; 1922 uint8_t extensionFlag = (ASC & 0x01); 1923 (void)extensionFlag; 1924 1925 if(frameLengthFlag == 0) AUDIO_INFO("AAC FrameLength: 1024 bytes"); 1926 if(frameLengthFlag == 1) AUDIO_INFO("AAC FrameLength: 960 bytes"); 1927 } 1928 if(specialIndexOf(data, "mp4a", len) > 0){ 1929 int offset = specialIndexOf(data, "mp4a", len); 1930 int channel = bigEndian(data + offset + 20, 2); // audio parameter must be set before starting 1931 int bps = bigEndian(data + offset + 22, 2); // the aac decoder. There are RAW blocks only in m4a 1932 int srate = bigEndian(data + offset + 26, 4); // 1933 setBitsPerSample(bps); 1934 setChannels(channel); 1935 setSampleRate(srate); 1936 setBitrate(bps * channel * srate); 1937 AUDIO_INFO("ch; %i, bps: %i, sr: %i", channel, bps, srate); 1938 if(audioDataPos && getDatamode() == AUDIO_LOCALFILE) { 1939 m_controlCounter = M4A_AMRDY; 1940 setFilePos(audioDataPos); 1941 return 0; 1942 } 1943 } 1944 m_controlCounter = M4A_MOOV; 1945 return 0; 1946 } 1947 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1948 if(m_controlCounter == M4A_ILST) { // ilst 1949 const char info[12][6] = { "nam\0", "ART\0", "alb\0", "too\0", "cmt\0", "wrt\0", 1950 "tmpo\0", "trkn\0","day\0", "cpil\0", "aART\0", "gen\0"}; 1951 int offset; 1952 for(int i=0; i < 12; i++){ 1953 offset = specialIndexOf(data, info[i], len, true); // seek info[] with '\0' 1954 if(offset>0) { 1955 offset += 19; if(*(data + offset) == 0) offset ++; 1956 char value[256]; 1957 size_t tmp = strlen((const char*)data + offset); 1958 if(tmp > 254) tmp = 254; 1959 memcpy(value, (data + offset), tmp); 1960 value[tmp] = 0; 1961 m_chbuf[0] = 0; 1962 if(i == 0) sprintf(m_chbuf, "Title: %s", value); 1963 if(i == 1) sprintf(m_chbuf, "Artist: %s", value); 1964 if(i == 2) sprintf(m_chbuf, "Album: %s", value); 1965 if(i == 3) sprintf(m_chbuf, "Encoder: %s", value); 1966 if(i == 4) sprintf(m_chbuf, "Comment: %s", value); 1967 if(i == 5) sprintf(m_chbuf, "Composer: %s", value); 1968 if(i == 6) sprintf(m_chbuf, "BPM: %s", value); 1969 if(i == 7) sprintf(m_chbuf, "Track Number: %s", value); 1970 if(i == 8) sprintf(m_chbuf, "Year: %s", value); 1971 if(i == 9) sprintf(m_chbuf, "Compile: %s", value); 1972 if(i == 10) sprintf(m_chbuf, "Album Artist: %s", value); 1973 if(i == 11) sprintf(m_chbuf, "Types of: %s", value); 1974 if(m_chbuf[0] != 0) { 1975 if(audio_id3data) audio_id3data(m_chbuf); 1976 } 1977 } 1978 } 1979 m_controlCounter = M4A_MOOV; 1980 return 0; 1981 } 1982 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1983 if(m_controlCounter == M4A_MDAT) { // mdat 1984 m_audioDataSize = bigEndian(data, 4) -8; // length of this atom - strlen(M4A_MDAT) 1985 AUDIO_INFO( "Audio-Length: %u",m_audioDataSize); 1986 retvalue = 8; 1987 headerSize += 8; 1988 m_controlCounter = M4A_AMRDY; // last step before starting the audio 1989 return 0; 1990 } 1991 1992 if(m_controlCounter == M4A_AMRDY){ // almost ready 1993 m_audioDataStart = headerSize; 1994 // m_contentlength = headerSize + m_audioDataSize; // after this mdat atom there may be other atoms 1995 if(getDatamode() == AUDIO_LOCALFILE){ 1996 AUDIO_INFO("Content-Length: %u", m_contentlength); 1997 } 1998 m_controlCounter = M4A_OKAY; // that's all 1999 return 0; 2000 } 2001 // this section should never be reached 2002 log_e("error"); 2003 return 0; 2004 } 2005 //--------------------------------------------------------------------------------------------------------------------- 2006 int Audio::read_OGG_Header(uint8_t *data, size_t len){ 2007 static size_t retvalue = 0; 2008 static size_t pageLen = 0; 2009 static bool f_firstPacket = false; 2010 2011 if(retvalue) { 2012 if(retvalue > len) { // if returnvalue > bufferfillsize 2013 if(len > InBuff.getMaxBlockSize()) len = InBuff.getMaxBlockSize(); 2014 retvalue -= len; // and wait for more bufferdata 2015 return len; 2016 } 2017 else { 2018 size_t tmp = retvalue; 2019 retvalue = 0; 2020 return tmp; 2021 } 2022 return 0; 2023 } 2024 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2025 if(m_controlCounter == OGG_BEGIN) { // init 2026 retvalue = 0; 2027 m_audioDataStart = 0; 2028 f_firstPacket = true; 2029 m_controlCounter = OGG_MAGIC; 2030 if(getDatamode() == AUDIO_LOCALFILE){ 2031 m_contentlength = getFileSize(); 2032 AUDIO_INFO("Content-Length: %u", m_contentlength); 2033 } 2034 return 0; 2035 } 2036 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2037 if(m_controlCounter == OGG_MAGIC) { /* check MAGIC STRING */ 2038 if(specialIndexOf(data, "OggS", 10) != 0) { 2039 log_e("Magic String 'OggS' not found in header"); 2040 stopSong(); 2041 return -1; 2042 } 2043 m_controlCounter = OGG_HEADER; 2044 retvalue = 4; 2045 return 0; 2046 } 2047 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2048 if(m_controlCounter == OGG_HEADER) { /* check OGG PAGE HEADER */ 2049 uint8_t i = 0; 2050 uint8_t ssv = *(data + i); // stream_structure_version 2051 (void)ssv; 2052 i++; 2053 uint8_t htf = *(data + i); // header_type_flag 2054 (void)htf; 2055 i++; 2056 uint32_t tmp = bigEndian(data + i, 4); // absolute granule position 2057 uint64_t agp = (uint64_t) tmp << 32; 2058 i += 4; 2059 agp += bigEndian(data + i, 4); 2060 i += 4; 2061 uint32_t ssnr = bigEndian(data + i, 4); // stream serial number 2062 (void)ssnr; 2063 i += 4; 2064 uint32_t psnr = bigEndian(data + i, 4); // page sequence no 2065 (void)psnr; 2066 i += 4; 2067 uint32_t pchk = bigEndian(data + i, 4); // page checksum 2068 (void)pchk; 2069 i += 4; 2070 uint8_t psegm = *(data + i); 2071 i++; 2072 uint8_t psegmBuff[256]; 2073 pageLen = 0; 2074 for(uint8_t j = 0; j < psegm; j++){ 2075 psegmBuff[j] = *(data + i); 2076 pageLen += psegmBuff[j]; 2077 i++; 2078 } 2079 retvalue = i; 2080 if(agp == 0){ 2081 if(f_firstPacket == true){ 2082 f_firstPacket = false; 2083 m_controlCounter = OGG_FIRST; // ogg first pages 2084 } 2085 else{ 2086 retvalue += pageLen; 2087 m_controlCounter = OGG_MAGIC; 2088 } 2089 } 2090 else{ 2091 if(m_codec == CODEC_OGG_FLAC){ 2092 m_controlCounter = OGG_AMRDY; 2093 } 2094 else { 2095 AUDIO_INFO("unknown format"); 2096 stopSong(); 2097 return -1; 2098 } 2099 } 2100 return 0; 2101 } 2102 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2103 if(m_controlCounter == OGG_FIRST) { /* check OGG FIRST PAGES (has no streaming content) */ 2104 uint8_t i = 0; 2105 uint8_t obp = *(data + i); // oneBytePacket shold be 0x7F 2106 (void)obp; 2107 i++; 2108 if(specialIndexOf(data + i, "FLAC", 10) == 0){ 2109 } 2110 else{ 2111 log_e("ogg/flac support only"); // ogg/vorbis or ogg//opus not supported yet 2112 stopSong(); 2113 return -1; 2114 } 2115 i += 4; 2116 uint8_t major_vers = *(data + i); 2117 (void)major_vers; 2118 i++; 2119 uint8_t minor_vers = *(data + i); 2120 (void)minor_vers; 2121 i++; 2122 uint16_t nonah = bigEndian(data + i, 2); // number of non audio headers (0x00 = unknown) 2123 (void)nonah; 2124 i += 2; 2125 if(specialIndexOf(data + i, "fLaC", 10) == 0){ 2126 m_codec = CODEC_OGG_FLAC; 2127 } 2128 i += 4; 2129 // STREAMINFO metadata block begins 2130 uint32_t mblen = bigEndian(data + i, 4); 2131 (void)mblen; 2132 i += 4; // skip metadata block header + length 2133 i += 2; // skip minimun block size 2134 m_flacMaxBlockSize = bigEndian(data + i, 2); 2135 i += 2; 2136 vTaskDelay(2); 2137 AUDIO_INFO("FLAC maxBlockSize: %u", m_flacMaxBlockSize); 2138 i += 3; // skip minimun frame size 2139 vTaskDelay(2); 2140 m_flacMaxFrameSize = bigEndian(data + i, 3); 2141 i += 3; 2142 if(m_flacMaxFrameSize){ 2143 AUDIO_INFO("FLAC maxFrameSize: %u", m_flacMaxFrameSize); 2144 } 2145 else { 2146 AUDIO_INFO("FLAC maxFrameSize: N/A"); 2147 } 2148 if(m_flacMaxFrameSize > InBuff.getMaxBlockSize()) { 2149 log_e("FLAC maxFrameSize too large!"); 2150 stopSong(); 2151 return -1; 2152 } 2153 vTaskDelay(2); 2154 uint32_t nextval = bigEndian(data + i, 3); 2155 i += 3; 2156 m_flacSampleRate = nextval >> 4; 2157 AUDIO_INFO("FLAC sampleRate: %u", m_flacSampleRate); 2158 vTaskDelay(2); 2159 m_flacNumChannels = ((nextval & 0x06) >> 1) + 1; 2160 AUDIO_INFO("FLAC numChannels: %u", m_flacNumChannels); 2161 if(m_flacNumChannels != 1 && m_flacNumChannels != 2){ 2162 vTaskDelay(2); 2163 AUDIO_INFO("numChannels must be 1 or 2"); 2164 stopSong(); 2165 return -1; 2166 } 2167 vTaskDelay(2); 2168 uint8_t bps = (nextval & 0x01) << 4; 2169 bps += (*(data +i) >> 4) + 1; 2170 i++; 2171 m_flacBitsPerSample = bps; 2172 if((bps != 8) && (bps != 16)){ 2173 log_e("bits per sample must be 8 or 16, is %i", bps); 2174 stopSong(); 2175 return -1; 2176 } 2177 AUDIO_INFO("FLAC bitsPerSample: %u", m_flacBitsPerSample); 2178 m_flacTotalSamplesInStream = bigEndian(data + i, 4); 2179 i++; 2180 if(m_flacTotalSamplesInStream) { 2181 AUDIO_INFO("total samples in stream: %u", m_flacTotalSamplesInStream); 2182 } 2183 else { 2184 AUDIO_INFO("total samples in stream: N/A"); 2185 } 2186 if(bps != 0 && m_flacTotalSamplesInStream) { 2187 AUDIO_INFO("audio file duration: %u seconds", m_flacTotalSamplesInStream / m_flacSampleRate); 2188 } 2189 m_controlCounter = OGG_MAGIC; 2190 retvalue = pageLen; 2191 return 0; 2192 } 2193 if(m_controlCounter == OGG_AMRDY){ // ogg almost ready 2194 if(!psramFound()){ 2195 AUDIO_INFO("FLAC works only with PSRAM!"); 2196 m_f_running = false; stopSong(); 2197 return -1; 2198 } 2199 if(!FLACDecoder_AllocateBuffers()) {m_f_running = false; stopSong(); return -1;} 2200 InBuff.changeMaxBlockSize(m_frameSizeFLAC); 2201 AUDIO_INFO("FLACDecoder has been initialized, free Heap: %u bytes", ESP.getFreeHeap()); 2202 2203 m_controlCounter = OGG_OKAY; // 100 2204 retvalue = 0; 2205 return 0; 2206 } 2207 return 0; 2208 } 2209 //--------------------------------------------------------------------------------------------------------------------- 2210 size_t Audio::process_m3u8_ID3_Header(uint8_t* packet){ 2211 uint8_t ID3version; 2212 size_t id3Size; 2213 bool m_f_unsync = false, m_f_exthdr = false; 2214 uint64_t current_timestamp = 0; 2215 2216 (void) m_f_unsync; // suppress -Wunused-variable 2217 (void) current_timestamp; // suppress -Wunused-variable 2218 2219 if(specialIndexOf(packet, "ID3", 4) != 0) { // ID3 not found 2220 if(m_f_Log) log_i("m3u8 file has no mp3 tag"); 2221 return 0; // error, no ID3 signature found 2222 } 2223 ID3version = *(packet + 3); 2224 switch(ID3version){ 2225 case 2: 2226 m_f_unsync = (*(packet + 5) & 0x80); 2227 m_f_exthdr = false; 2228 break; 2229 case 3: 2230 case 4: 2231 m_f_unsync = (*(packet + 5) & 0x80); // bit7 2232 m_f_exthdr = (*(packet + 5) & 0x40); // bit6 extended header 2233 break; 2234 }; 2235 id3Size = bigEndian(&packet[6], 4, 7); // ID3v2 size 4 * %0xxxxxxx (shift left seven times!!) 2236 id3Size += 10; 2237 if(m_f_Log) log_i("ID3 framesSize: %i", id3Size); 2238 if(m_f_Log) log_i("ID3 version: 2.%i", ID3version); 2239 2240 if(m_f_exthdr) { 2241 log_e("ID3 extended header in m3u8 files not supported"); 2242 return 0; 2243 } 2244 if(m_f_Log) log_i("ID3 normal frames"); 2245 2246 if(specialIndexOf(&packet[10], "PRIV", 5) != 0) { // tag PRIV not found 2247 log_e("tag PRIV in m3u8 Id3 Header not found"); 2248 return 0; 2249 } 2250 // if tag PRIV exists assume content is "com.apple.streaming.transportStreamTimestamp" 2251 // a time stamp is expected in the header. 2252 2253 current_timestamp = (double)bigEndian(&packet[69], 4) / 90000; // seconds 2254 2255 return id3Size; 2256 } 2257 //--------------------------------------------------------------------------------------------------------------------- 2258 uint32_t Audio::stopSong() { 2259 uint32_t pos = 0; 2260 if(m_f_running) { 2261 m_f_running = false; 2262 #ifndef AUDIO_NO_SD_FS 2263 if(getDatamode() == AUDIO_LOCALFILE){ 2264 m_streamType = ST_NONE; 2265 pos = getFilePos() - inBufferFilled(); 2266 audiofile.close(); 2267 AUDIO_INFO("Closing audio file"); 2268 } 2269 #endif // AUDIO_NO_SD_FS 2270 } 2271 #ifndef AUDIO_NO_SD_FS 2272 if(audiofile){ 2273 // added this before putting 'm_f_localfile = false' in stopSong(); shoulf never occur.... 2274 audiofile.close(); 2275 AUDIO_INFO("Closing audio file"); 2276 log_w("Closing audio file"); // for debug 2277 } 2278 #endif // AUDIO_NO_SD_FS 2279 memset(m_outBuff, 0, sizeof(m_outBuff)); //Clear OutputBuffer 2280 i2s_zero_dma_buffer((i2s_port_t) m_i2s_num); 2281 return pos; 2282 } 2283 //--------------------------------------------------------------------------------------------------------------------- 2284 void Audio::playI2Sremains() { // returns true if all dma_buffs flushed 2285 if(!getSampleRate()) setSampleRate(96000); 2286 if(!getChannels()) setChannels(2); 2287 if(getBitsPerSample() > 8) memset(m_outBuff, 0, sizeof(m_outBuff)); //Clear OutputBuffer (signed) 2288 else memset(m_outBuff, 128, sizeof(m_outBuff)); //Clear OutputBuffer (unsigned, PCM 8u) 2289 2290 m_validSamples = m_i2s_config.dma_buf_len * m_i2s_config.dma_buf_count; 2291 while(m_validSamples) { 2292 playChunk(); 2293 } 2294 i2s_zero_dma_buffer((i2s_port_t) m_i2s_num); 2295 return; 2296 } 2297 //--------------------------------------------------------------------------------------------------------------------- 2298 bool Audio::pauseResume() { 2299 bool retVal = false; 2300 if(getDatamode() == AUDIO_LOCALFILE || m_streamType == ST_WEBSTREAM) { 2301 m_f_running = !m_f_running; 2302 retVal = true; 2303 if(!m_f_running) { 2304 memset(m_outBuff, 0, sizeof(m_outBuff)); //Clear OutputBuffer 2305 i2s_zero_dma_buffer((i2s_port_t) m_i2s_num); 2306 } 2307 } 2308 return retVal; 2309 } 2310 //--------------------------------------------------------------------------------------------------------------------- 2311 bool Audio::playChunk() { 2312 // If we've got data, try and pump it out.. 2313 int16_t sample[2]; 2314 if(getBitsPerSample() == 8) { 2315 if(getChannels() == 1) { 2316 while(m_validSamples) { 2317 uint8_t x = m_outBuff[m_curSample] & 0x00FF; 2318 uint8_t y = (m_outBuff[m_curSample] & 0xFF00) >> 8; 2319 sample[LEFTCHANNEL] = x; 2320 sample[RIGHTCHANNEL] = x; 2321 while(1) { 2322 if(playSample(sample)) break; 2323 } // Can't send? 2324 sample[LEFTCHANNEL] = y; 2325 sample[RIGHTCHANNEL] = y; 2326 while(1) { 2327 if(playSample(sample)) break; 2328 } // Can't send? 2329 m_validSamples--; 2330 m_curSample++; 2331 } 2332 } 2333 if(getChannels() == 2) { 2334 while(m_validSamples) { 2335 uint8_t x = m_outBuff[m_curSample] & 0x00FF; 2336 uint8_t y = (m_outBuff[m_curSample] & 0xFF00) >> 8; 2337 if(!m_f_forceMono) { // stereo mode 2338 sample[LEFTCHANNEL] = x; 2339 sample[RIGHTCHANNEL] = y; 2340 } 2341 else { // force mono 2342 uint8_t xy = (x + y) / 2; 2343 sample[LEFTCHANNEL] = xy; 2344 sample[RIGHTCHANNEL] = xy; 2345 } 2346 2347 while(1) { 2348 if(playSample(sample)) break; 2349 } // Can't send? 2350 m_validSamples--; 2351 m_curSample++; 2352 } 2353 } 2354 m_curSample = 0; 2355 return true; 2356 } 2357 if(getBitsPerSample() == 16) { 2358 if(getChannels() == 1) { 2359 while(m_validSamples) { 2360 sample[LEFTCHANNEL] = m_outBuff[m_curSample]; 2361 sample[RIGHTCHANNEL] = m_outBuff[m_curSample]; 2362 if(!playSample(sample)) { 2363 log_e("can't send"); 2364 return false; 2365 } // Can't send 2366 m_validSamples--; 2367 m_curSample++; 2368 } 2369 } 2370 if(getChannels() == 2) { 2371 m_curSample = 0; 2372 while(m_validSamples) { 2373 if(!m_f_forceMono) { // stereo mode 2374 sample[LEFTCHANNEL] = m_outBuff[m_curSample * 2]; 2375 sample[RIGHTCHANNEL] = m_outBuff[m_curSample * 2 + 1]; 2376 } 2377 else { // mono mode, #100 2378 int16_t xy = (m_outBuff[m_curSample * 2] + m_outBuff[m_curSample * 2 + 1]) / 2; 2379 sample[LEFTCHANNEL] = xy; 2380 sample[RIGHTCHANNEL] = xy; 2381 } 2382 playSample(sample); 2383 m_validSamples--; 2384 m_curSample++; 2385 } 2386 } 2387 m_curSample = 0; 2388 return true; 2389 } 2390 log_e("BitsPer Sample must be 8 or 16!"); 2391 m_validSamples = 0; 2392 stopSong(); 2393 return false; 2394 } 2395 //--------------------------------------------------------------------------------------------------------------------- 2396 void Audio::loop() { 2397 2398 if(!m_f_running) return; 2399 2400 if(m_playlistFormat != FORMAT_M3U8){ // normal process 2401 switch(getDatamode()){ 2402 case AUDIO_LOCALFILE: 2403 #ifndef AUDIO_NO_SD_FS 2404 processLocalFile(); 2405 #endif // AUDIO_NO_SD_FS 2406 break; 2407 case HTTP_RESPONSE_HEADER: 2408 parseHttpResponseHeader(); 2409 break; 2410 case AUDIO_PLAYLISTINIT: 2411 readPlayListData(); 2412 break; 2413 case AUDIO_PLAYLISTDATA: 2414 if(m_playlistFormat == FORMAT_M3U) connecttohost(parsePlaylist_M3U()); 2415 if(m_playlistFormat == FORMAT_PLS) connecttohost(parsePlaylist_PLS()); 2416 if(m_playlistFormat == FORMAT_ASX) connecttohost(parsePlaylist_ASX()); 2417 break; 2418 case AUDIO_DATA: 2419 if(m_streamType == ST_WEBSTREAM) processWebStream(); 2420 if(m_streamType == ST_WEBFILE) processWebFile(); 2421 break; 2422 } 2423 } 2424 else { // m3u8 datastream only 2425 static bool f_noNewHost = false; 2426 static int32_t remaintime, timestamp1, timestamp2; // m3u8 time management 2427 const char* host; 2428 2429 switch(getDatamode()){ 2430 case HTTP_RESPONSE_HEADER: 2431 playAudioData(); // fill I2S DMA buffer 2432 parseHttpResponseHeader(); 2433 m_codec = CODEC_AAC; 2434 break; 2435 case AUDIO_PLAYLISTINIT: 2436 readPlayListData(); 2437 break; 2438 case AUDIO_PLAYLISTDATA: 2439 host = parsePlaylist_M3U8(); 2440 m_f_m3u8data = true; 2441 if(host){ 2442 f_noNewHost = false; 2443 timestamp1 = millis(); 2444 httpPrint(host); 2445 } 2446 else { 2447 f_noNewHost = true; 2448 timestamp2 = millis() + remaintime; 2449 setDatamode(AUDIO_DATA); //fake datamode, we have no new audiosequence yet, so let audio run 2450 } 2451 break; 2452 case AUDIO_DATA: 2453 if(m_f_ts) processWebStreamTS(); // aac or aacp with ts packets 2454 else processWebStreamHLS(); // aac or aacp normal stream 2455 if(f_noNewHost){ 2456 m_f_continue = false; 2457 if(timestamp2 < millis()) { 2458 httpPrint(m_lastHost); 2459 remaintime = 1000; 2460 } 2461 } 2462 else{ 2463 if(m_f_continue){ // processWebStream() needs more data 2464 remaintime = (int32_t)(m_m3u8_targetDuration * 1000) - (millis() - timestamp1); 2465 // if(m_m3u8_targetDuration < 10) remaintime += 1000; 2466 m_f_continue = false; 2467 setDatamode(AUDIO_PLAYLISTDATA); 2468 } 2469 } 2470 break; 2471 } 2472 } 2473 } 2474 //--------------------------------------------------------------------------------------------------------------------- 2475 bool Audio::readPlayListData() { 2476 2477 if(getDatamode() != AUDIO_PLAYLISTINIT) return false; 2478 if(_client->available() == 0) return false; 2479 2480 uint32_t chunksize = 0; uint8_t readedBytes = 0; 2481 if(m_f_chunked) chunksize = chunkedDataTransfer(&readedBytes); 2482 2483 // reads the content of the playlist and stores it in the vector m_contentlength 2484 // m_contentlength is a table of pointers to the lines 2485 char pl[512]; // playlistLine 2486 uint32_t ctl = 0; 2487 int lines = 0; 2488 // delete all memory in m_playlistContent 2489 if(m_playlistFormat == FORMAT_M3U8 && !psramFound()){log_e("m3u8 playlists requires PSRAM enabled!");} 2490 vector_clear_and_shrink(m_playlistContent); 2491 while(true){ // outer while 2492 2493 uint32_t ctime = millis(); 2494 uint32_t timeout = 2000; // ms 2495 2496 while(true) { // inner while 2497 uint16_t pos = 0; 2498 while(_client->available()){ // super inner while :-)) 2499 pl[pos] = _client->read(); 2500 ctl++; 2501 if(pl[pos] == '\n') {pl[pos] = '\0'; pos++; break;} 2502 // if(pl[pos] == '&' ) {pl[pos] = '\0'; pos++; break;} 2503 if(pl[pos] == '\r') {pl[pos] = '\0'; pos++; continue;;} 2504 pos++; 2505 if(pos == 511){ pos--; continue;} 2506 if(pos == 510) {pl[pos] = '\0';} 2507 if(ctl == chunksize) {pl[pos] = '\0'; break;} 2508 if(ctl == m_contentlength) {pl[pos] = '\0'; break;} 2509 } 2510 if(ctl == chunksize) break; 2511 if(ctl == m_contentlength) break; 2512 if(pos) {pl[pos] = '\0'; break;} 2513 2514 if(ctime + timeout < millis()) { 2515 log_e("timeout"); 2516 for(int i = 0; i<m_playlistContent.size(); i++) log_e("pl%i = %s", i, m_playlistContent[i]); 2517 goto exit;} 2518 } // inner while 2519 2520 if(startsWith(pl, "<!DOCTYPE")) {AUDIO_INFO("url is a webpage!"); goto exit;} 2521 if(startsWith(pl, "<html")) {AUDIO_INFO("url is a webpage!"); goto exit;} 2522 if(strlen(pl) > 0) m_playlistContent.push_back(strdup((const char*)pl)); 2523 if(m_playlistContent.size() == 100){ 2524 if(m_f_Log) log_i("the maximum number of lines in the playlist has been reached"); 2525 break; 2526 } 2527 // termination conditions 2528 // 1. The http response header returns a value for contentLength -> read chars until contentLength is reached 2529 // 2. no contentLength, but Transfer-Encoding:chunked -> compute chunksize and read until chunksize is reached 2530 // 3. no chunksize and no contentlengt, but Connection: close -> read all available chars 2531 if(ctl == m_contentlength){while(_client->available()) _client->read(); break;} // read '\n\n' if exists 2532 if(ctl == chunksize) {while(_client->available()) _client->read(); break;} 2533 if(!_client->connected() && _client->available() == 0) break; 2534 2535 } // outer while 2536 lines = m_playlistContent.size(); 2537 for (int i = 0; i < lines ; i++) { // print all string in first vector of 'arr' 2538 if(m_f_Log) log_i("pl=%i \"%s\"", i, m_playlistContent[i]); 2539 } 2540 setDatamode(AUDIO_PLAYLISTDATA); 2541 return true; 2542 2543 exit: 2544 vector_clear_and_shrink(m_playlistContent); 2545 m_f_running = false; 2546 setDatamode(AUDIO_NONE); 2547 return false; 2548 } 2549 //---------------------------------------------------------------------------------------------------------------------- 2550 const char* Audio::parsePlaylist_M3U(){ 2551 uint8_t lines = m_playlistContent.size(); 2552 int pos = 0; 2553 char* host = nullptr; 2554 2555 for(int i= 0; i < lines; i++){ 2556 if(indexOf(m_playlistContent[i], "#EXTINF:") >= 0) { // Info? 2557 pos = indexOf(m_playlistContent[i], ","); // Comma in this line? 2558 if(pos > 0) { 2559 // Show artist and title if present in metadata 2560 AUDIO_INFO(m_playlistContent[i] + pos + 1); 2561 } 2562 continue; 2563 } 2564 if(startsWith(m_playlistContent[i], "#")) { // Commentline? 2565 continue; 2566 } 2567 2568 pos = indexOf(m_playlistContent[i], "http://:@", 0); // ":@"?? remove that! 2569 if(pos >= 0) { 2570 AUDIO_INFO("Entry in playlist found: %s", (m_playlistContent[i] + pos + 9)); 2571 host = m_playlistContent[i] + pos + 9; 2572 break; 2573 } 2574 // AUDIO_INFO("Entry in playlist found: %s", pl); 2575 pos = indexOf(m_playlistContent[i], "http", 0); // Search for "http" 2576 if(pos >= 0) { // Does URL contain "http://"? 2577 // log_e("%s pos=%i", m_playlistContent[i], pos); 2578 host = m_playlistContent[i] + pos; // Yes, set new host 2579 break; 2580 } 2581 } 2582 vector_clear_and_shrink(m_playlistContent); 2583 return host; 2584 } 2585 //---------------------------------------------------------------------------------------------------------------------- 2586 const char* Audio::parsePlaylist_PLS(){ 2587 uint8_t lines = m_playlistContent.size(); 2588 int pos = 0; 2589 char* host = nullptr; 2590 2591 for(int i= 0; i < lines; i++){ 2592 if(i == 0){ 2593 if(strlen(m_playlistContent[0]) == 0) goto exit; // empty line 2594 if(strcmp(m_playlistContent[0] , "[playlist]") != 0){ // first entry in valid pls 2595 setDatamode(HTTP_RESPONSE_HEADER); // pls is not valid 2596 AUDIO_INFO("pls is not valid, switch to HTTP_RESPONSE_HEADER"); 2597 goto exit; 2598 } 2599 continue; 2600 } 2601 if(startsWith(m_playlistContent[i], "File1")) { 2602 if(host) continue; // we have already a url 2603 pos = indexOf(m_playlistContent[i], "http", 0); // File1=http://streamplus30.leonex.de:14840/; 2604 if(pos >= 0) { // yes, URL contains "http"? 2605 host = m_playlistContent[i] + pos; // Now we have an URL for a stream in host. 2606 } 2607 continue; 2608 } 2609 if(startsWith(m_playlistContent[i], "Title1")) { // Title1=Antenne Tirol 2610 const char* plsStationName = (m_playlistContent[i] + 7); 2611 if(audio_showstation) audio_showstation(plsStationName); 2612 AUDIO_INFO("StationName: \"%s\"", plsStationName); 2613 continue; 2614 } 2615 if(startsWith(m_playlistContent[i], "Length1")){ 2616 continue; 2617 } 2618 if(indexOf(m_playlistContent[i], "Invalid username") >= 0){ // Unable to access account: 2619 goto exit; // Invalid username or password 2620 } 2621 } 2622 return host; 2623 2624 exit: 2625 m_f_running = false; 2626 stopSong(); 2627 vector_clear_and_shrink(m_playlistContent); 2628 setDatamode(AUDIO_NONE); 2629 return nullptr; 2630 } 2631 //---------------------------------------------------------------------------------------------------------------------- 2632 const char* Audio::parsePlaylist_ASX(){ // Advanced Stream Redirector 2633 uint8_t lines = m_playlistContent.size(); 2634 bool f_entry = false; 2635 int pos = 0; 2636 char* host = nullptr; 2637 2638 for(int i= 0; i < lines; i++){ 2639 int p1 = indexOf(m_playlistContent[i], "<", 0); 2640 int p2 = indexOf(m_playlistContent[i], ">", 1); 2641 if(p1 >= 0 && p2 > p1){ // #196 set all between "< ...> to lowercase 2642 for(uint8_t j = p1; j < p2; j++){ 2643 m_playlistContent[i][j] = toLowerCase(m_playlistContent[i][j]); 2644 } 2645 } 2646 if(indexOf(m_playlistContent[i], "<entry>") >= 0) f_entry = true; // found entry tag (returns -1 if not found) 2647 if(f_entry) { 2648 if(indexOf(m_playlistContent[i], "ref href") > 0) { // <ref href="http://87.98.217.63:24112/stream" /> 2649 pos = indexOf(m_playlistContent[i], "http", 0); 2650 if(pos > 0) { 2651 host = (m_playlistContent[i] + pos); // http://87.98.217.63:24112/stream" /> 2652 int pos1 = indexOf(host, "\"", 0); // http://87.98.217.63:24112/stream 2653 if(pos1 > 0) host[pos1] = '\0'; // Now we have an URL for a stream in host. 2654 } 2655 } 2656 } 2657 pos = indexOf(m_playlistContent[i], "<title>", 0); 2658 if(pos >= 0) { 2659 char* plsStationName = (m_playlistContent[i] + pos + 7); // remove <Title> 2660 pos = indexOf(plsStationName, "</", 0); 2661 if(pos >= 0){ 2662 *(plsStationName +pos) = 0; // remove </Title> 2663 } 2664 if(audio_showstation) audio_showstation(plsStationName); 2665 AUDIO_INFO("StationName: \"%s\"", plsStationName); 2666 } 2667 2668 if(indexOf(m_playlistContent[i], "http") == 0 && !f_entry) { //url only in asx 2669 host = m_playlistContent[i]; 2670 } 2671 } 2672 return host; 2673 } 2674 //---------------------------------------------------------------------------------------------------------------------- 2675 const char* Audio::parsePlaylist_M3U8(){ 2676 uint8_t lines = m_playlistContent.size(); 2677 bool f_begin = false; 2678 uint8_t occurence = 0; 2679 if(lines){ 2680 for(int i= 0; i < lines; i++){ 2681 if(strlen(m_playlistContent[i]) == 0) continue; // empty line 2682 if(startsWith(m_playlistContent[i], "#EXTM3U")){ // what we expected 2683 f_begin = true; 2684 continue; 2685 } 2686 if(!f_begin) continue; 2687 2688 // example: redirection 2689 // #EXTM3U 2690 // #EXT-X-STREAM-INF:BANDWIDTH=22050,CODECS="mp4a.40.2" 2691 // http://ample.revma.ihrhls.com/zc7729/63_sdtszizjcjbz02/playlist.m3u8 2692 if(startsWith(m_playlistContent[i],"#EXT-X-STREAM-INF:")){ 2693 if(occurence > 0) break; // no more than one #EXT-X-STREAM-INF: (can have different BANDWIDTH) 2694 occurence++; 2695 if((!endsWith(m_playlistContent[i+1], "m3u8" ) && indexOf(m_playlistContent[i+1], "m3u8?") == -1)){ 2696 // we have a new m3u8 playlist, skip to next line 2697 int pos = indexOf(m_playlistContent[i], "CODECS=\"mp4a", 18); 2698 // 'mp4a.40.01' AAC Main 2699 // 'mp4a.40.02' AAC LC (Low Complexity) 2700 // 'mp4a.40.03' AAC SSR (Scalable Sampling Rate) ?? 2701 // 'mp4a.40.03' AAC LTP (Long Term Prediction) ?? 2702 // 'mp4a.40.03' SBR (Spectral Band Replication) 2703 if(pos < 0){ // not found 2704 int pos1 = indexOf(m_playlistContent[i], "CODECS=", 18); 2705 if(pos1 < 0) pos1 = 0; 2706 log_e("codec %s in m3u8 playlist not supported", m_playlistContent[i] + pos1); 2707 goto exit; 2708 } 2709 } 2710 i++; // next line 2711 if(i == lines) continue; // and exit for() 2712 2713 char* tmp = nullptr; 2714 if(!startsWith(m_playlistContent[i], "http")){ 2715 //http://livees.com/prog_index.m3u8 and prog_index48347.aac --> http://livees.com/prog_index48347.aac 2716 //http://livees.com/prog_index.m3u8 and chunklist022.m3u8 --> http://livees.com/chunklist022.m3u8 2717 tmp = (char*)malloc(strlen(m_lastHost)+ strlen(m_playlistContent[i])); 2718 strcpy(tmp, m_lastHost); 2719 int idx = lastIndexOf(tmp, "/"); 2720 strcpy(tmp + idx + 1, m_playlistContent[i]); 2721 } 2722 else{ 2723 tmp = strdup(m_playlistContent[i]); 2724 } 2725 if(m_playlistContent[i]){free(m_playlistContent[i]); m_playlistContent[i] = NULL;} 2726 m_playlistContent[i] = strdup(tmp); 2727 strcpy(m_lastHost, tmp); 2728 if(tmp){free(tmp); tmp = NULL;} 2729 if(m_f_Log) log_i("redirect %s", m_playlistContent[i]); 2730 return m_playlistContent[i]; // it's a redirection, a new m3u8 playlist 2731 } 2732 2733 // example: audio chunks 2734 // #EXTM3U 2735 // #EXT-X-TARGETDURATION:10 2736 // #EXT-X-MEDIA-SEQUENCE:163374040 2737 // #EXT-X-DISCONTINUITY 2738 // #EXTINF:10,title="text=\"Spot Block End\" amgTrackId=\"9876543\"",artist=" ",url="length=\"00:00:00\"" 2739 // http://n3fa-e2.revma.ihrhls.com/zc7729/63_sdtszizjcjbz02/main/163374038.aac 2740 // #EXTINF:10,title="text=\"Spot Block End\" amgTrackId=\"9876543\"",artist=" ",url="length=\"00:00:00\"" 2741 // http://n3fa-e2.revma.ihrhls.com/zc7729/63_sdtszizjcjbz02/main/163374039.aac 2742 if(startsWith(m_playlistContent[i], "#EXT-X-MEDIA-SEQUENCE:")){ 2743 // do nothing, because MEDIA-SECUENCE is not set sometimes 2744 } 2745 static uint16_t targetDuration = 0; 2746 if(startsWith(m_playlistContent[i], "#EXT-X-TARGETDURATION:")) { 2747 targetDuration = atoi(m_playlistContent[i] + 22); 2748 } 2749 if(targetDuration) m_m3u8_targetDuration = targetDuration; 2750 if(m_f_Log) log_i("m_m3u8_targetDuration %d", m_m3u8_targetDuration); 2751 2752 if(startsWith(m_playlistContent[i],"#EXTINF")) { 2753 if(STfromEXTINF(m_playlistContent[i])) showstreamtitle(m_chbuf); 2754 i++; 2755 if(i == lines) continue; // and exit for() 2756 2757 char* tmp = nullptr; 2758 if(!startsWith(m_playlistContent[i], "http")){ 2759 //http://livees.com/prog_index.m3u8 and prog_index48347.aac --> http://livees.com/prog_index48347.aac 2760 tmp = (char*)malloc(strlen(m_lastHost)+ strlen(m_playlistContent[i])); 2761 strcpy(tmp, m_lastHost); 2762 int idx = lastIndexOf(tmp, "/"); 2763 strcpy(tmp + idx + 1, m_playlistContent[i]); 2764 } 2765 else{ 2766 tmp = strdup(m_playlistContent[i]); 2767 } 2768 2769 uint32_t hash = simpleHash(tmp); 2770 if(m_hashQueue.size() == 0){ 2771 m_hashQueue.insert(m_hashQueue.begin(), hash); 2772 m_playlistURL.insert(m_playlistURL.begin(), strdup(tmp)); 2773 } 2774 else{ 2775 bool known = false; 2776 for(int i = 0; i< m_hashQueue.size(); i++){ 2777 if(hash == m_hashQueue[i]){ 2778 if(m_f_Log) log_i("file already known %s", tmp); 2779 known = true; 2780 } 2781 } 2782 if(!known){ 2783 m_hashQueue.insert(m_hashQueue.begin(), hash); 2784 m_playlistURL.insert(m_playlistURL.begin(), strdup(tmp)); 2785 } 2786 } 2787 2788 if(m_hashQueue.size() > 20) m_hashQueue.pop_back(); 2789 2790 if(tmp){free(tmp); tmp = NULL;} 2791 2792 if(m_playlistURL.size() == 20){ 2793 ESP_LOGD("", "can't stuff anymore"); 2794 break; 2795 } 2796 continue; 2797 } 2798 } 2799 vector_clear_and_shrink(m_playlistContent); //clear after reading everything, m_playlistContent.size is now 0 2800 } 2801 2802 if(m_playlistURL.size() > 0){ 2803 if(m_playlistBuff) {free(m_playlistBuff); m_playlistBuff = NULL;} 2804 2805 if(m_playlistURL[m_playlistURL.size() -1]) { 2806 m_playlistBuff = strdup(m_playlistURL[m_playlistURL.size() -1]); 2807 free( m_playlistURL[m_playlistURL.size() -1]); 2808 m_playlistURL[m_playlistURL.size() -1] = NULL; 2809 m_playlistURL.pop_back(); 2810 m_playlistURL.shrink_to_fit(); 2811 } 2812 if(m_f_Log) log_i("now playing %s", m_playlistBuff); 2813 return m_playlistBuff; 2814 } 2815 else{ 2816 return NULL; 2817 } 2818 exit: 2819 stopSong(); 2820 return NULL; 2821 } 2822 //--------------------------------------------------------------------------------------------------------------------- 2823 bool Audio::STfromEXTINF(char* str){ 2824 // the result is copied in chbuf!! 2825 // extraxt StreamTitle from m3u #EXTINF line to icy-format 2826 // orig: #EXTINF:10,title="text="TitleName",artist="ArtistName" 2827 // conv: StreamTitle=TitleName - ArtistName 2828 // orig: #EXTINF:10,title="text=\"Spot Block End\" amgTrackId=\"9876543\"",artist=" ",url="length=\"00:00:00\"" 2829 // conv: StreamTitle=text=\"Spot Block End\" amgTrackId=\"9876543\" - 2830 2831 int t1, t2, t3, n0 = 0, n1 = 0, n2 = 0; 2832 2833 t1 = indexOf(str, "title", 0); 2834 if(t1 > 0){ 2835 strcpy(m_chbuf, "StreamTitle="); n0 = 12; 2836 t2 = t1 + 7; // title=" 2837 t3 = indexOf(str, "\"", t2); 2838 while(str[t3 - 1] == '\\'){ 2839 t3 = indexOf(str, "\"", t3 + 1); 2840 } 2841 if(t2 < 0 || t2 > t3) return false; 2842 n1 = t3 - t2; 2843 strncpy(m_chbuf + n0, str + t2, n1); 2844 m_chbuf[n1] = '\0'; 2845 } 2846 2847 t1 = indexOf(str, "artist", 0); 2848 if(t1 > 0){ 2849 strcpy(m_chbuf + n0 + n1, " - "); n1 += 3; 2850 t2 = indexOf(str, "=\"", t1); t2 += 2; 2851 t3 = indexOf(str, "\"", t2); 2852 if(t2 < 0 || t2 > t3) return false; 2853 n2 = t3 - t2; 2854 strncpy(m_chbuf + n0 + n1, str + t2, n2); 2855 m_chbuf[n0 + n1 + n2] = '\0'; 2856 m_chbuf[n2] = '\0'; 2857 } 2858 return true; 2859 } 2860 #ifndef AUDIO_NO_SD_FS 2861 //--------------------------------------------------------------------------------------------------------------------- 2862 void Audio::processLocalFile() { 2863 2864 if(!(audiofile && m_f_running && getDatamode() == AUDIO_LOCALFILE)) return; // guard 2865 2866 const uint32_t maxFrameSize = InBuff.getMaxBlockSize(); // every mp3/aac frame is not bigger 2867 static bool f_stream; 2868 static bool f_fileDataComplete; 2869 static uint32_t byteCounter; // count received data 2870 uint32_t availableBytes = 0; 2871 2872 if(m_f_firstCall) { // runs only one time per connection, prepare for start 2873 m_f_firstCall = false; 2874 f_stream = false; 2875 f_fileDataComplete = false; 2876 byteCounter = 0; 2877 return; 2878 } 2879 2880 availableBytes = 16 * 1024; // set some large value 2881 2882 availableBytes = min(availableBytes, InBuff.writeSpace()); 2883 availableBytes = min(availableBytes, audiofile.size() - byteCounter); 2884 if(m_contentlength){ 2885 if(m_contentlength > getFilePos()) availableBytes = min(availableBytes, m_contentlength - getFilePos()); 2886 } 2887 if(m_audioDataSize){ 2888 availableBytes = min(availableBytes, m_audioDataSize + m_audioDataStart - byteCounter); 2889 } 2890 2891 int32_t bytesAddedToBuffer = audiofile.read(InBuff.getWritePtr(), availableBytes); 2892 2893 if(bytesAddedToBuffer > 0) { 2894 byteCounter += bytesAddedToBuffer; // Pull request #42 2895 InBuff.bytesWritten(bytesAddedToBuffer); 2896 } 2897 if(!f_stream){ 2898 if(m_controlCounter != 100) { 2899 if(InBuff.bufferFilled() > maxFrameSize){ // read the file header first 2900 InBuff.bytesWasRead(readAudioHeader(InBuff.bufferFilled())); 2901 } 2902 return; 2903 } 2904 else{ 2905 if((InBuff.freeSpace() > maxFrameSize) && (m_file_size - byteCounter) > maxFrameSize){ 2906 // fill the buffer before playing 2907 return; 2908 } 2909 2910 f_stream = true; 2911 AUDIO_INFO("stream ready"); 2912 if(m_f_Log) log_i("m_audioDataStart %d", m_audioDataStart); 2913 } 2914 } 2915 2916 if(m_resumeFilePos){ 2917 if(m_resumeFilePos < m_audioDataStart) m_resumeFilePos = m_audioDataStart; 2918 if(m_resumeFilePos > m_file_size) m_resumeFilePos = m_file_size; 2919 if(m_codec == CODEC_M4A) m_resumeFilePos = m4a_correctResumeFilePos(m_resumeFilePos); 2920 if(m_codec == CODEC_WAV) {while((m_resumeFilePos % 4) != 0) m_resumeFilePos++;} // must be divisible by four 2921 if(m_codec == CODEC_FLAC) {m_resumeFilePos = flac_correctResumeFilePos(m_resumeFilePos); FLACDecoderReset();} 2922 if(m_codec == CODEC_MP3) {m_resumeFilePos = mp3_correctResumeFilePos(m_resumeFilePos);} 2923 if(m_avr_bitrate) m_audioCurrentTime = ((m_resumeFilePos - m_audioDataStart) / m_avr_bitrate) * 8; 2924 audiofile.seek(m_resumeFilePos); 2925 InBuff.resetBuffer(); 2926 byteCounter = m_resumeFilePos; 2927 2928 if(m_f_Log){ 2929 log_i("m_resumeFilePos %d", m_resumeFilePos); 2930 log_i("m_audioDataStart %d", m_audioDataStart); 2931 log_i("m_audioCurrentTime %f", (double)m_audioCurrentTime); 2932 log_i("m_file_size %d", m_file_size); 2933 } 2934 m_resumeFilePos = 0; 2935 f_stream = false; 2936 } 2937 2938 // end of file reached? - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2939 if(f_fileDataComplete && InBuff.bufferFilled() < InBuff.getMaxBlockSize()){ 2940 if(InBuff.bufferFilled()){ 2941 if(!readID3V1Tag()){ 2942 int bytesDecoded = sendBytes(InBuff.getReadPtr(), InBuff.bufferFilled()); 2943 if(bytesDecoded > 2){InBuff.bytesWasRead(bytesDecoded); return;} 2944 } 2945 } 2946 playI2Sremains(); 2947 2948 if(m_f_loop && f_stream){ //eof 2949 AUDIO_INFO("loop from: %u to: %u", getFilePos(), m_audioDataStart); //TEST loop 2950 setFilePos(m_audioDataStart); 2951 if(m_codec == CODEC_FLAC) FLACDecoderReset(); 2952 /* 2953 The current time of the loop mode is not reset, 2954 which will cause the total audio duration to be exceeded. 2955 For example: current time ====progress bar====> total audio duration 2956 3:43 ====================> 3:33 2957 */ 2958 m_audioCurrentTime = 0; 2959 byteCounter = m_audioDataStart; 2960 f_fileDataComplete = false; 2961 return; 2962 } //TEST loop 2963 2964 #ifdef SDFATFS_USED 2965 audiofile.getName(m_chbuf, sizeof(m_chbuf)); 2966 char *afn =strdup(m_chbuf); 2967 #else 2968 char *afn =strdup(audiofile.name()); // store temporary the name 2969 #endif 2970 2971 stopSong(); 2972 if(m_codec == CODEC_MP3) MP3Decoder_FreeBuffers(); 2973 if(m_codec == CODEC_AAC) AACDecoder_FreeBuffers(); 2974 if(m_codec == CODEC_M4A) AACDecoder_FreeBuffers(); 2975 if(m_codec == CODEC_FLAC) FLACDecoder_FreeBuffers(); 2976 AUDIO_INFO("End of file \"%s\"", afn); 2977 if(audio_eof_mp3) audio_eof_mp3(afn); 2978 if(afn) {free(afn); afn = NULL;} 2979 return; 2980 } 2981 2982 if(byteCounter == audiofile.size()) {f_fileDataComplete = true;} 2983 if(byteCounter == m_audioDataSize + m_audioDataStart){f_fileDataComplete = true;} 2984 2985 // play audio data - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2986 if(f_stream){ 2987 static uint8_t cnt = 0; 2988 uint8_t compression; 2989 if(m_codec == CODEC_WAV) compression = 1; 2990 else if(m_codec == CODEC_FLAC) compression = 2; 2991 else compression = 3; 2992 cnt++; 2993 if(cnt == compression){playAudioData(); cnt = 0;} 2994 } 2995 return; 2996 } 2997 #endif // AUDIO_NO_SD_FS 2998 //---------------------------------------------------------------------------------------------------------------------- 2999 void Audio::processWebStream() { 3000 3001 const uint16_t maxFrameSize = InBuff.getMaxBlockSize(); // every mp3/aac frame is not bigger 3002 static bool f_stream; // first audio data received 3003 static uint32_t chunkSize; // chunkcount read from stream 3004 3005 // first call, set some values to default - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 3006 if(m_f_firstCall) { // runs only ont time per connection, prepare for start 3007 m_f_firstCall = false; 3008 f_stream = false; 3009 chunkSize = 0; 3010 m_metacount = m_metaint; 3011 readMetadata(0, true); // reset all static vars 3012 } 3013 3014 if(getDatamode() != AUDIO_DATA) return; // guard 3015 uint32_t availableBytes = _client->available(); // available from stream 3016 // chunked data tramsfer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 3017 if(m_f_chunked && availableBytes){ 3018 uint8_t readedBytes = 0; 3019 if(!chunkSize) chunkSize = chunkedDataTransfer(&readedBytes); 3020 availableBytes = min(availableBytes, chunkSize); 3021 } 3022 // we have metadata - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 3023 if(m_f_metadata && availableBytes){ 3024 if(m_metacount == 0) {chunkSize -= readMetadata(availableBytes); return;} 3025 availableBytes = min(availableBytes, m_metacount); 3026 } 3027 3028 slowStreamDetection(InBuff.bufferFilled(), maxFrameSize); 3029 if(f_stream) lostStreamDetection(availableBytes); 3030 3031 // buffer fill routine - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 3032 if(availableBytes) { 3033 availableBytes = min(availableBytes, InBuff.writeSpace()); 3034 int16_t bytesAddedToBuffer = _client->read(InBuff.getWritePtr(), availableBytes); 3035 3036 if(bytesAddedToBuffer > 0) { 3037 if(m_f_metadata) m_metacount -= bytesAddedToBuffer; 3038 if(m_f_chunked) chunkSize -= bytesAddedToBuffer; 3039 InBuff.bytesWritten(bytesAddedToBuffer); 3040 } 3041 3042 if(InBuff.bufferFilled() > maxFrameSize && !f_stream) { // waiting for buffer filled 3043 f_stream = true; // ready to play the audio data 3044 AUDIO_INFO("stream ready"); 3045 } 3046 if(!f_stream) return; 3047 } 3048 3049 // play audio data - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 3050 if(f_stream){ 3051 static uint8_t cnt = 0; 3052 cnt++; 3053 if(cnt == 3){playAudioData(); cnt = 0;} 3054 } 3055 } 3056 //--------------------------------------------------------------------------------------------------------------------- 3057 void Audio::processWebFile() { 3058 3059 const uint32_t maxFrameSize = InBuff.getMaxBlockSize(); // every mp3/aac frame is not bigger 3060 static bool f_stream; // first audio data received 3061 static bool f_webFileDataComplete; // all file data received 3062 static uint32_t byteCounter; // count received data 3063 static uint32_t chunkSize; // chunkcount read from stream 3064 static size_t audioDataCount; // counts the decoded audiodata only 3065 3066 // first call, set some values to default - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 3067 if(m_f_firstCall) { // runs only ont time per connection, prepare for start 3068 m_f_firstCall = false; 3069 f_webFileDataComplete = false; 3070 f_stream = false; 3071 byteCounter = 0; 3072 chunkSize = 0; 3073 audioDataCount = 0; 3074 } 3075 3076 if(!m_contentlength && !m_f_tts) {log_e("webfile without contentlength!"); stopSong(); return;} // guard 3077 3078 uint32_t availableBytes = _client->available(); // available from stream 3079 3080 // chunked data tramsfer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 3081 if(m_f_chunked){ 3082 uint8_t readedBytes = 0; 3083 if(!chunkSize) chunkSize = chunkedDataTransfer(&readedBytes); 3084 availableBytes = min(availableBytes, chunkSize); 3085 if(m_f_tts) m_contentlength = chunkSize; 3086 } 3087 3088 // if the buffer is often almost empty issue a warning - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 3089 if(!f_webFileDataComplete && f_stream){ 3090 slowStreamDetection(InBuff.bufferFilled(), maxFrameSize); 3091 } 3092 3093 availableBytes = min(InBuff.writeSpace(), availableBytes); 3094 availableBytes = min(m_contentlength - byteCounter, availableBytes); 3095 if(m_audioDataSize) availableBytes = min(m_audioDataSize - (byteCounter - m_audioDataStart), availableBytes); 3096 3097 int16_t bytesAddedToBuffer = _client->read(InBuff.getWritePtr(), availableBytes); 3098 3099 if(bytesAddedToBuffer > 0) { 3100 byteCounter += bytesAddedToBuffer; // Pull request #42 3101 if(m_f_chunked) m_chunkcount -= bytesAddedToBuffer; 3102 if(m_controlCounter == 100) audioDataCount += bytesAddedToBuffer; 3103 InBuff.bytesWritten(bytesAddedToBuffer); 3104 } 3105 3106 if(InBuff.bufferFilled() > maxFrameSize && !f_stream) { // waiting for buffer filled 3107 f_stream = true; // ready to play the audio data 3108 uint16_t filltime = millis() - m_t0; 3109 AUDIO_INFO("stream ready\nbuffer filled in %d ms", filltime); 3110 } 3111 3112 if(!f_stream) return; 3113 3114 // we have a webfile, read the file header first - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 3115 if(m_controlCounter != 100){ 3116 InBuff.bytesWasRead(readAudioHeader(availableBytes)); 3117 return; 3118 } 3119 3120 // end of webfile reached? - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 3121 if(f_webFileDataComplete && InBuff.bufferFilled() < InBuff.getMaxBlockSize()){ 3122 if(InBuff.bufferFilled()){ 3123 if(!readID3V1Tag()){ 3124 int bytesDecoded = sendBytes(InBuff.getReadPtr(), InBuff.bufferFilled()); 3125 if(bytesDecoded > 2){InBuff.bytesWasRead(bytesDecoded); return;} 3126 } 3127 } 3128 playI2Sremains(); 3129 stopSong(); // Correct close when play known length sound #74 and before callback #11 3130 if(m_f_tts){ 3131 AUDIO_INFO("End of speech: \"%s\"", m_lastHost); 3132 if(audio_eof_speech) audio_eof_speech(m_lastHost); 3133 } 3134 else{ 3135 AUDIO_INFO("End of webstream: \"%s\"", m_lastHost); 3136 if(audio_eof_stream) audio_eof_stream(m_lastHost); 3137 } 3138 return; 3139 } 3140 3141 if(byteCounter == m_contentlength) {f_webFileDataComplete = true;} 3142 if(byteCounter - m_audioDataStart == m_audioDataSize) {f_webFileDataComplete = true;} 3143 3144 // play audio data - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 3145 if(f_stream){ 3146 static uint8_t cnt = 0; 3147 uint8_t compression; 3148 if(m_codec == CODEC_WAV) compression = 1; 3149 if(m_codec == CODEC_FLAC) compression = 2; 3150 else compression = 6; 3151 cnt++; 3152 if(cnt == compression){playAudioData(); cnt = 0;} 3153 } 3154 return; 3155 } 3156 //--------------------------------------------------------------------------------------------------------------------- 3157 void Audio::processWebStreamTS() { 3158 3159 const uint16_t maxFrameSize = InBuff.getMaxBlockSize(); // every mp3/aac frame is not bigger 3160 uint32_t availableBytes; // available bytes in stream 3161 static bool f_tmr_1s; 3162 static bool f_stream; // first audio data received 3163 static bool f_firstPacket; 3164 static uint32_t byteCounter; // count received data 3165 static uint32_t tmr_1s; // timer 1 sec 3166 static uint32_t loopCnt; // count loops if clientbuffer is empty 3167 static uint8_t ts_packet[188]; // m3u8 transport stream is 188 bytes long 3168 uint8_t ts_packetStart = 0; 3169 uint8_t ts_packetLength = 0; 3170 static uint8_t ts_packetPtr = 0; 3171 const uint8_t ts_packetsize = 188; 3172 static size_t chunkSize = 0; 3173 3174 // first call, set some values to default - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 3175 if(m_f_firstCall) { // runs only ont time per connection, prepare for start 3176 f_stream = false; 3177 f_firstPacket = true; 3178 byteCounter = 0; 3179 chunkSize = 0; 3180 loopCnt = 0; 3181 tmr_1s = millis(); 3182 m_t0 = millis(); 3183 ts_packetPtr = 0; 3184 m_controlCounter = 0; 3185 m_f_firstCall = false; 3186 } 3187 3188 if(getDatamode() != AUDIO_DATA) return; // guard 3189 3190 if(InBuff.freeSpace() < maxFrameSize && f_stream){playAudioData(); return;} 3191 3192 availableBytes = _client->available(); 3193 if(availableBytes){ 3194 uint8_t readedBytes = 0; 3195 if(m_f_chunked) chunkSize = chunkedDataTransfer(&readedBytes); 3196 int res = _client->read(ts_packet + ts_packetPtr, ts_packetsize - ts_packetPtr); 3197 if(res > 0){ 3198 ts_packetPtr += res; 3199 byteCounter += res; 3200 if(ts_packetPtr < ts_packetsize) return; 3201 ts_packetPtr = 0; 3202 if(f_firstPacket){ // search for ID3 Header in the first packet 3203 f_firstPacket = false; 3204 uint8_t ID3_HeaderSize = process_m3u8_ID3_Header(ts_packet); 3205 if(ID3_HeaderSize > ts_packetsize){ 3206 log_e("ID3 Header is too big"); 3207 stopSong(); 3208 return; 3209 } 3210 if(ID3_HeaderSize){ 3211 memcpy(ts_packet, &ts_packet[ID3_HeaderSize], ts_packetsize - ID3_HeaderSize); 3212 ts_packetPtr = ts_packetsize - ID3_HeaderSize; 3213 return; 3214 } 3215 } 3216 ts_parsePacket(&ts_packet[0], &ts_packetStart, &ts_packetLength); 3217 3218 if(ts_packetLength) { 3219 size_t ws = InBuff.writeSpace(); 3220 if(ws >= ts_packetLength){ 3221 memcpy(InBuff.getWritePtr(), ts_packet + ts_packetStart, ts_packetLength); 3222 InBuff.bytesWritten(ts_packetLength); 3223 } 3224 else{ 3225 memcpy(InBuff.getWritePtr(), ts_packet + ts_packetStart, ws); 3226 InBuff.bytesWritten(ws); 3227 memcpy(InBuff.getWritePtr(), &ts_packet[ws + ts_packetStart], ts_packetLength -ws); 3228 InBuff.bytesWritten(ts_packetLength -ws); 3229 } 3230 } 3231 if(byteCounter == m_contentlength || byteCounter == chunkSize){ 3232 byteCounter = 0; 3233 m_f_continue = true; 3234 } 3235 if(byteCounter > m_contentlength) log_e("byteCounter overflow"); 3236 } 3237 3238 } 3239 3240 // timer, triggers every second - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 3241 if((tmr_1s + 1000) < millis()) { 3242 f_tmr_1s = true; // flag will be set every second for one loop only 3243 tmr_1s = millis(); 3244 } 3245 3246 // if the buffer is often almost empty issue a warning - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 3247 if(InBuff.bufferFilled() < maxFrameSize && f_stream){ 3248 static uint8_t cnt_slow = 0; 3249 cnt_slow ++; 3250 if(f_tmr_1s) { 3251 if(cnt_slow > 50 && audio_info) audio_info("slow stream, dropouts are possible"); 3252 f_tmr_1s = false; 3253 cnt_slow = 0; 3254 } 3255 } 3256 3257 // if the buffer can't filled for several seconds try a new connection - - - - - - - - - - - - - - - - - - - - - - 3258 if(f_stream && !availableBytes){ 3259 loopCnt++; 3260 if(loopCnt > 200000) { // wait several seconds 3261 loopCnt = 0; 3262 AUDIO_INFO("Stream lost -> try new connection"); 3263 httpPrint(m_lastHost); 3264 return; 3265 } 3266 } 3267 if(availableBytes) loopCnt = 0; 3268 3269 // buffer fill routine - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 3270 if(true) { // statement has no effect 3271 if(InBuff.bufferFilled() > maxFrameSize && !f_stream) { // waiting for buffer filled 3272 f_stream = true; // ready to play the audio data 3273 uint16_t filltime = millis() - m_t0; 3274 if(m_f_Log) AUDIO_INFO("stream ready"); 3275 if(m_f_Log) AUDIO_INFO("buffer filled in %d ms", filltime); 3276 } 3277 if(!f_stream) return; 3278 } 3279 3280 // play audio data - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 3281 if(f_stream){ 3282 static uint8_t cnt = 0; 3283 cnt++; 3284 if(cnt == 6){playAudioData(); cnt = 0;} 3285 } 3286 return; 3287 } 3288 //--------------------------------------------------------------------------------------------------------------------- 3289 void Audio::processWebStreamHLS() { 3290 3291 const uint16_t maxFrameSize = InBuff.getMaxBlockSize(); // every mp3/aac frame is not bigger 3292 const uint16_t ID3BuffSize = 1024; 3293 uint32_t availableBytes; // available bytes in stream 3294 static bool f_tmr_1s; 3295 static bool f_stream; // first audio data received 3296 static bool firstBytes; 3297 static uint32_t byteCounter; // count received data 3298 static size_t chunkSize = 0; 3299 static uint32_t tmr_1s; // timer 1 sec 3300 static uint32_t loopCnt; // count loops if clientbuffer is empty 3301 static uint16_t ID3WritePtr; 3302 static uint16_t ID3ReadPtr; 3303 static uint8_t* ID3Buff; 3304 3305 // first call, set some values to default - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 3306 if(m_f_firstCall) { // runs only ont time per connection, prepare for start 3307 f_stream = false; 3308 byteCounter = 0; 3309 chunkSize = 0; 3310 loopCnt = 0; 3311 ID3WritePtr = 0; 3312 ID3ReadPtr = 0; 3313 tmr_1s = millis(); 3314 m_t0 = millis(); 3315 m_f_firstCall = false; 3316 firstBytes = true; 3317 ID3Buff = (uint8_t*)malloc(ID3BuffSize); 3318 m_controlCounter = 0; 3319 } 3320 3321 if(getDatamode() != AUDIO_DATA) return; // guard 3322 3323 availableBytes = _client->available(); 3324 if(availableBytes){ // an ID3 header could come here 3325 uint8_t readedBytes = 0; 3326 3327 if(m_f_chunked && !chunkSize) {chunkSize = chunkedDataTransfer(&readedBytes); byteCounter += readedBytes;} 3328 3329 if(firstBytes){ 3330 if(ID3WritePtr < ID3BuffSize){ 3331 ID3WritePtr += _client->readBytes(&ID3Buff[ID3WritePtr], ID3BuffSize - ID3WritePtr); 3332 return; 3333 } 3334 if(m_controlCounter < 100){ 3335 int res = read_ID3_Header(&ID3Buff[ID3ReadPtr], ID3BuffSize - ID3ReadPtr); 3336 if(res >= 0) ID3ReadPtr += res; 3337 if(ID3ReadPtr > ID3BuffSize) {log_e("buffer overflow"); stopSong(); return;} 3338 return; 3339 } 3340 if(m_controlCounter != 100) return; 3341 3342 size_t ws = InBuff.writeSpace(); 3343 if(ws >= ID3BuffSize - ID3ReadPtr){ 3344 memcpy(InBuff.getWritePtr(), &ID3Buff[ID3ReadPtr], ID3BuffSize - ID3ReadPtr); 3345 InBuff.bytesWritten(ID3BuffSize - ID3ReadPtr); 3346 } 3347 else{ 3348 memcpy(InBuff.getWritePtr(), &ID3Buff[ID3ReadPtr], ws); 3349 InBuff.bytesWritten(ws); 3350 memcpy(InBuff.getWritePtr(), &ID3Buff[ws + ID3ReadPtr], ID3BuffSize - (ID3ReadPtr + ws)); 3351 InBuff.bytesWritten(ID3BuffSize - (ID3ReadPtr + ws)); 3352 } 3353 if(ID3Buff) free(ID3Buff); 3354 byteCounter += ID3BuffSize; 3355 ID3Buff = NULL; 3356 firstBytes = false; 3357 } 3358 3359 size_t bytesWasWritten = 0; 3360 if(InBuff.writeSpace() >= availableBytes){ 3361 bytesWasWritten = _client->read(InBuff.getWritePtr(), availableBytes); 3362 } 3363 else{ 3364 bytesWasWritten = _client->read(InBuff.getWritePtr(), InBuff.writeSpace()); 3365 } 3366 InBuff.bytesWritten(bytesWasWritten); 3367 3368 byteCounter += bytesWasWritten; 3369 if(byteCounter == m_contentlength || byteCounter == chunkSize){ 3370 byteCounter = 0; 3371 m_f_continue = true; 3372 } 3373 } 3374 3375 // timer, triggers every second - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 3376 if((tmr_1s + 1000) < millis()) { 3377 f_tmr_1s = true; // flag will be set every second for one loop only 3378 tmr_1s = millis(); 3379 } 3380 3381 // if the buffer is often almost empty issue a warning - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 3382 if(InBuff.bufferFilled() < maxFrameSize && f_stream){ 3383 static uint8_t cnt_slow = 0; 3384 cnt_slow ++; 3385 if(f_tmr_1s) { 3386 if(cnt_slow > 25 && audio_info) audio_info("slow stream, dropouts are possible"); 3387 f_tmr_1s = false; 3388 cnt_slow = 0; 3389 } 3390 } 3391 3392 // if the buffer can't filled for several seconds try a new connection - - - - - - - - - - - - - - - - - - - - - - 3393 if(f_stream && !availableBytes){ 3394 loopCnt++; 3395 if(loopCnt > 200000) { // wait several seconds 3396 loopCnt = 0; 3397 AUDIO_INFO("Stream lost -> try new connection"); 3398 httpPrint(m_lastHost); 3399 return; 3400 } 3401 } 3402 if(availableBytes) loopCnt = 0; 3403 3404 if(InBuff.bufferFilled() > maxFrameSize && !f_stream) { // waiting for buffer filled 3405 f_stream = true; // ready to play the audio data 3406 uint16_t filltime = millis() - m_t0; 3407 if(m_f_Log) AUDIO_INFO("stream ready"); 3408 if(m_f_Log) AUDIO_INFO("buffer filled in %d ms", filltime); 3409 } 3410 3411 // play audio data - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 3412 if(f_stream){ 3413 static uint8_t cnt = 0; 3414 cnt++; 3415 if(cnt == 1){playAudioData(); cnt = 0;} 3416 } 3417 return; 3418 } 3419 //--------------------------------------------------------------------------------------------------------------------- 3420 void Audio::playAudioData(){ 3421 3422 if(InBuff.bufferFilled() < InBuff.getMaxBlockSize()) return; // guard 3423 3424 int bytesDecoded = sendBytes(InBuff.getReadPtr(), InBuff.getMaxBlockSize()); 3425 3426 if(bytesDecoded < 0) { // no syncword found or decode error, try next chunk 3427 log_i("err bytesDecoded %i", bytesDecoded); 3428 uint8_t next = 200; 3429 if(InBuff.bufferFilled() < next) next = InBuff.bufferFilled(); 3430 InBuff.bytesWasRead(next); // try next chunk 3431 m_bytesNotDecoded += next; 3432 } 3433 else { 3434 if(bytesDecoded > 0) {InBuff.bytesWasRead(bytesDecoded); return;} 3435 if(bytesDecoded == 0) return; // syncword at pos0 found 3436 } 3437 3438 return; 3439 } 3440 //--------------------------------------------------------------------------------------------------------------------- 3441 bool Audio::parseHttpResponseHeader() { // this is the response to a GET / request 3442 3443 if(getDatamode() != HTTP_RESPONSE_HEADER) return false; 3444 if(_client->available() == 0) return false; 3445 3446 char rhl[512]; // responseHeaderline 3447 bool ct_seen = false; 3448 uint32_t ctime = millis(); 3449 uint32_t timeout = 2500; // ms 3450 3451 while(true){ // outer while 3452 uint16_t pos = 0; 3453 if((millis() - ctime) > timeout) { 3454 log_e("timeout"); 3455 goto exit; 3456 } 3457 while(_client->available()){ 3458 uint8_t b = _client->read(); 3459 if(b == '\n') { 3460 if(!pos){ // empty line received, is the last line of this responseHeader 3461 if(ct_seen) goto lastToDo; 3462 else goto exit; 3463 } 3464 break; 3465 } 3466 if(b == '\r') rhl[pos] = 0; 3467 if(b < 0x20) continue; 3468 rhl[pos] = b; 3469 pos++; 3470 if(pos == 511){pos = 510; continue;} 3471 if(pos == 510){ 3472 rhl[pos] = '\0'; 3473 if(m_f_Log) log_i("responseHeaderline overflow"); 3474 } 3475 } // inner while 3476 3477 if(!pos){vTaskDelay(3); continue;} 3478 3479 if(m_f_Log) {log_i("httpResponseHeader: %s", rhl);} 3480 3481 int16_t posColon = indexOf(rhl, ":", 0); // lowercase all letters up to the colon 3482 if(posColon >= 0) { 3483 for(int i=0; i< posColon; i++) { 3484 rhl[i] = toLowerCase(rhl[i]); 3485 } 3486 } 3487 3488 if(startsWith(rhl, "HTTP/")){ // HTTP status error code 3489 char statusCode[5]; 3490 statusCode[0] = rhl[9]; 3491 statusCode[1] = rhl[10]; 3492 statusCode[2] = rhl[11]; 3493 statusCode[3] = '\0'; 3494 int sc = atoi(statusCode); 3495 if(sc > 310){ // e.g. HTTP/1.1 301 Moved Permanently 3496 if(audio_showstreamtitle) audio_showstreamtitle(rhl); 3497 goto exit; 3498 } 3499 } 3500 3501 else if(startsWith(rhl, "content-type:")){ // content-type: text/html; charset=UTF-8 3502 int idx = indexOf(rhl + 13, ";"); 3503 if(idx >0) rhl[13 + idx] = '\0'; 3504 if(parseContentType(rhl + 13)) ct_seen = true; 3505 else goto exit; 3506 } 3507 3508 else if(startsWith(rhl, "location:")) { 3509 int pos = indexOf(rhl, "http", 0); 3510 if(pos >= 0){ 3511 const char* c_host = (rhl + pos); 3512 if(strcmp(c_host, m_lastHost) != 0) { // prevent a loop 3513 int pos_slash = indexOf(c_host, "/", 9); 3514 if(pos_slash > 9){ 3515 if(!strncmp(c_host, m_lastHost, pos_slash)){ 3516 AUDIO_INFO("redirect to new extension at existing host \"%s\"", c_host); 3517 if(m_playlistFormat == FORMAT_M3U8) { 3518 strcpy(m_lastHost, c_host); 3519 m_f_m3u8data = true; 3520 } 3521 httpPrint(c_host); 3522 while(_client->available()) _client->read(); // empty client buffer 3523 return true; 3524 } 3525 } 3526 AUDIO_INFO("redirect to new host \"%s\"", c_host); 3527 connecttohost(c_host); 3528 return true; 3529 } 3530 } 3531 } 3532 3533 else if(startsWith(rhl, "content-encoding:")){ 3534 if(indexOf(rhl, "gzip")){ 3535 AUDIO_INFO("can't extract gzip"); 3536 goto exit; 3537 } 3538 } 3539 3540 else if(startsWith(rhl, "content-disposition:")) { 3541 int pos1, pos2; // pos3; 3542 // e.g we have this headerline: content-disposition: attachment; filename=stream.asx 3543 // filename is: "stream.asx" 3544 pos1 = indexOf(rhl, "filename=", 0); 3545 if(pos1 > 0){ 3546 pos1 += 9; 3547 if(rhl[pos1] == '\"') pos1++; // remove '\"' around filename if present 3548 pos2 = strlen(rhl); 3549 if(rhl[pos2 - 1] == '\"') rhl[pos2 - 1] = '\0'; 3550 } 3551 AUDIO_INFO("Filename is %s", rhl + pos1); 3552 } 3553 3554 // if(startsWith(rhl, "set-cookie:") || 3555 // startsWith(rhl, "pragma:") || 3556 // startsWith(rhl, "expires:") || 3557 // startsWith(rhl, "cache-control:") || 3558 // startsWith(rhl, "icy-pub:") || 3559 // startsWith(rhl, "p3p:") || 3560 // startsWith(rhl, "accept-ranges:") ){ 3561 // ; // do nothing 3562 // } 3563 3564 else if(startsWith(rhl, "connection:")) { 3565 if(indexOf(rhl, "close", 0) >= 0) {; /* do nothing */} 3566 } 3567 3568 else if(startsWith(rhl, "icy-genre:")) { 3569 ; // do nothing Ambient, Rock, etc 3570 } 3571 3572 else if(startsWith(rhl, "icy-br:")) { 3573 const char* c_bitRate = (rhl + 7); 3574 int32_t br = atoi(c_bitRate); // Found bitrate tag, read the bitrate in Kbit 3575 br = br * 1000; 3576 setBitrate(br); 3577 sprintf(m_chbuf, "%d", getBitRate()); 3578 if(audio_bitrate) audio_bitrate(m_chbuf); 3579 } 3580 3581 else if(startsWith(rhl, "icy-metaint:")) { 3582 const char* c_metaint = (rhl + 12); 3583 int32_t i_metaint = atoi(c_metaint); 3584 m_metaint = i_metaint; 3585 if(m_metaint) m_f_metadata = true; // Multimediastream 3586 } 3587 3588 else if(startsWith(rhl, "icy-name:")) { 3589 char* c_icyname = (rhl + 9); // Get station name 3590 trim(c_icyname); 3591 if(strlen(c_icyname) > 0) { 3592 if(!m_f_Log) AUDIO_INFO("icy-name: %s", c_icyname); 3593 if(audio_showstation) audio_showstation(c_icyname); 3594 } 3595 } 3596 3597 else if(startsWith(rhl, "content-length:")) { 3598 const char* c_cl = (rhl + 15); 3599 int32_t i_cl = atoi(c_cl); 3600 m_contentlength = i_cl; 3601 m_streamType = ST_WEBFILE; // Stream comes from a fileserver 3602 if(m_f_Log) AUDIO_INFO("content-length: %i", m_contentlength); 3603 } 3604 3605 else if(startsWith(rhl, "icy-description:")) { 3606 const char* c_idesc = (rhl + 16); 3607 while(c_idesc[0] == ' ') c_idesc++; 3608 latinToUTF8(rhl, sizeof(rhl)); // if already UTF-0 do nothing, otherwise convert to UTF-8 3609 if(audio_icydescription) audio_icydescription(c_idesc); 3610 } 3611 3612 else if((startsWith(rhl, "transfer-encoding:"))){ 3613 if(endsWith(rhl, "chunked") || endsWith(rhl, "Chunked") ) { // Station provides chunked transfer 3614 m_f_chunked = true; 3615 if(!m_f_Log) AUDIO_INFO("chunked data transfer"); 3616 m_chunkcount = 0; // Expect chunkcount in DATA 3617 } 3618 } 3619 3620 else if(startsWith(rhl, "icy-url:")) { 3621 char* icyurl = (rhl + 8); 3622 trim(icyurl); 3623 if(audio_icyurl) audio_icyurl(icyurl); 3624 } 3625 3626 else if(startsWith(rhl, "www-authenticate:")) { 3627 AUDIO_INFO("authentification failed, wrong credentials?"); 3628 goto exit; 3629 } 3630 else {;} 3631 } // outer while 3632 3633 exit: // termination condition 3634 if(audio_showstation) audio_showstation(""); 3635 if(audio_icydescription) audio_icydescription(""); 3636 if(audio_icyurl) audio_icyurl(""); 3637 m_lastHost[0] = '\0'; 3638 setDatamode(AUDIO_NONE); 3639 stopSong(); 3640 return false; 3641 3642 lastToDo: 3643 if(m_codec != CODEC_NONE){ 3644 setDatamode(AUDIO_DATA); // Expecting data now 3645 if(!initializeDecoder()) return false; 3646 if(m_f_Log) {log_i("Switch to DATA, metaint is %d", m_metaint);} 3647 if(m_playlistFormat != FORMAT_M3U8 && audio_lasthost) audio_lasthost(m_lastHost); 3648 m_controlCounter = 0; 3649 m_f_firstCall = true; 3650 } 3651 else if(m_playlistFormat != FORMAT_NONE){ 3652 setDatamode(AUDIO_PLAYLISTINIT); // playlist expected 3653 if(m_f_Log) {log_i("now parse playlist");} 3654 } 3655 else{ 3656 AUDIO_INFO("unknown content found at: %s", m_lastHost); 3657 goto exit; 3658 } 3659 return true; 3660 } 3661 //--------------------------------------------------------------------------------------------------------------------- 3662 bool Audio:: initializeDecoder(){ 3663 switch(m_codec){ 3664 case CODEC_MP3: 3665 if(!MP3Decoder_AllocateBuffers()) goto exit; 3666 AUDIO_INFO("MP3Decoder has been initialized, free Heap: %u bytes", ESP.getFreeHeap()); 3667 InBuff.changeMaxBlockSize(m_frameSizeMP3); 3668 break; 3669 case CODEC_AAC: 3670 if(!AACDecoder_IsInit()){ 3671 if(!AACDecoder_AllocateBuffers()) goto exit; 3672 AUDIO_INFO("AACDecoder has been initialized, free Heap: %u bytes", ESP.getFreeHeap()); 3673 InBuff.changeMaxBlockSize(m_frameSizeAAC); 3674 } 3675 break; 3676 case CODEC_M4A: 3677 if(!AACDecoder_IsInit()){ 3678 if(!AACDecoder_AllocateBuffers()) goto exit; 3679 AUDIO_INFO("AACDecoder has been initialized, free Heap: %u bytes", ESP.getFreeHeap()); 3680 InBuff.changeMaxBlockSize(m_frameSizeAAC); 3681 } 3682 break; 3683 case CODEC_FLAC: 3684 if(!psramFound()){ 3685 AUDIO_INFO("FLAC works only with PSRAM!"); 3686 goto exit; 3687 } 3688 if(!FLACDecoder_AllocateBuffers()) goto exit; 3689 InBuff.changeMaxBlockSize(m_frameSizeFLAC); 3690 AUDIO_INFO("FLACDecoder has been initialized, free Heap: %u bytes", ESP.getFreeHeap()); 3691 break; 3692 case CODEC_WAV: 3693 InBuff.changeMaxBlockSize(m_frameSizeWav); 3694 break; 3695 case CODEC_OGG: 3696 m_codec = CODEC_OGG; 3697 AUDIO_INFO("ogg not supported"); 3698 goto exit; 3699 break; 3700 default: 3701 goto exit; 3702 break; 3703 } 3704 return true; 3705 3706 exit: 3707 stopSong(); 3708 return false; 3709 } 3710 //--------------------------------------------------------------------------------------------------------------------- 3711 bool Audio::parseContentType(char* ct) { 3712 3713 enum : int {CT_NONE, CT_MP3, CT_AAC, CT_M4A, CT_WAV, CT_OGG, CT_FLAC, CT_PLS, CT_M3U, CT_ASX, 3714 CT_M3U8, CT_TXT, CT_AACP}; 3715 3716 strlwr(ct); 3717 trim(ct); 3718 3719 m_codec = CODEC_NONE; 3720 int ct_val = CT_NONE; 3721 3722 if(!strcmp(ct, "audio/mpeg")) ct_val = CT_MP3; 3723 else if(!strcmp(ct, "audio/mpeg3")) ct_val = CT_MP3; 3724 else if(!strcmp(ct, "audio/x-mpeg")) ct_val = CT_MP3; 3725 else if(!strcmp(ct, "audio/x-mpeg-3")) ct_val = CT_MP3; 3726 else if(!strcmp(ct, "audio/mp3")) ct_val = CT_MP3; 3727 3728 else if(!strcmp(ct, "audio/aac")) ct_val = CT_AAC; 3729 else if(!strcmp(ct, "audio/x-aac")) ct_val = CT_AAC; 3730 else if(!strcmp(ct, "audio/aacp")){ ct_val = CT_AAC; if(m_playlistFormat == FORMAT_M3U8) m_f_ts = true;} 3731 else if(!strcmp(ct, "video/mp2t")){ ct_val = CT_AAC; m_f_ts = true;} // assume AAC transport stream 3732 else if(!strcmp(ct, "audio/mp4")) ct_val = CT_M4A; 3733 else if(!strcmp(ct, "audio/m4a")) ct_val = CT_M4A; 3734 else if(!strcmp(ct, "audio/x-m4a")) ct_val = CT_M4A; 3735 3736 else if(!strcmp(ct, "audio/wav")) ct_val = CT_WAV; 3737 else if(!strcmp(ct, "audio/x-wav")) ct_val = CT_WAV; 3738 3739 else if(!strcmp(ct, "audio/flac")) ct_val = CT_FLAC; 3740 3741 else if(!strcmp(ct, "audio/scpls")) ct_val = CT_PLS; 3742 else if(!strcmp(ct, "audio/x-scpls")) ct_val = CT_PLS; 3743 else if(!strcmp(ct, "application/pls+xml")) ct_val = CT_PLS; 3744 else if(!strcmp(ct, "audio/mpegurl")) {ct_val = CT_M3U; if(m_expectedPlsFmt == FORMAT_M3U8) ct_val = CT_M3U8;} 3745 else if(!strcmp(ct, "audio/x-mpegurl")) ct_val = CT_M3U; 3746 else if(!strcmp(ct, "audio/ms-asf")) ct_val = CT_ASX; 3747 else if(!strcmp(ct, "video/x-ms-asf")) ct_val = CT_ASX; 3748 else if(!strcmp(ct, "audio/x-ms-asx")) ct_val = CT_ASX; // #413 3749 3750 else if(!strcmp(ct, "application/ogg")) ct_val = CT_OGG; 3751 else if(!strcmp(ct, "application/vnd.apple.mpegurl")) ct_val = CT_M3U8; 3752 else if(!strcmp(ct, "application/x-mpegurl")) ct_val =CT_M3U8; 3753 3754 else if(!strcmp(ct, "application/octet-stream")) ct_val = CT_TXT; // ??? listen.radionomy.com/1oldies before redirection 3755 else if(!strcmp(ct, "text/html")) ct_val = CT_TXT; 3756 else if(!strcmp(ct, "text/plain")) ct_val = CT_TXT; 3757 3758 else if(ct_val == CT_NONE){ 3759 AUDIO_INFO("ContentType %s not supported", ct); 3760 return false; // nothing valid had been seen 3761 } 3762 else {;} 3763 3764 switch(ct_val){ 3765 case CT_MP3: 3766 m_codec = CODEC_MP3; 3767 if(m_f_Log) { log_i("ContentType %s, format is mp3", ct); } //ok is likely mp3 3768 break; 3769 case CT_AAC: 3770 m_codec = CODEC_AAC; 3771 if(m_f_Log) { log_i("ContentType %s, format is aac", ct); } 3772 break; 3773 case CT_M4A: 3774 m_codec = CODEC_M4A; 3775 if(m_f_Log) { log_i("ContentType %s, format is aac", ct); } 3776 break; 3777 case CT_FLAC: 3778 m_codec = CODEC_FLAC; 3779 if(m_f_Log) { log_i("ContentType %s, format is flac", ct); } 3780 break; 3781 case CT_WAV: 3782 m_codec = CODEC_WAV; 3783 if(m_f_Log) { log_i("ContentType %s, format is wav", ct); } 3784 break; 3785 case CT_OGG: 3786 m_codec = CODEC_OGG; 3787 if(m_f_Log) { log_i("ContentType %s found", ct); } 3788 break; 3789 3790 case CT_PLS: 3791 m_playlistFormat = FORMAT_PLS; 3792 break; 3793 case CT_M3U: 3794 m_playlistFormat = FORMAT_M3U; 3795 break; 3796 case CT_ASX: 3797 m_playlistFormat = FORMAT_ASX; 3798 break; 3799 case CT_M3U8: 3800 m_playlistFormat = FORMAT_M3U8; 3801 break; 3802 case CT_TXT: // overwrite text/plain 3803 if(m_expectedCodec == CODEC_AAC){ m_codec = CODEC_AAC; if(m_f_Log) log_i("set ct from M3U8 to AAC");} 3804 if(m_expectedCodec == CODEC_MP3){ m_codec = CODEC_MP3; if(m_f_Log) log_i("set ct from M3U8 to MP3");} 3805 3806 if(m_expectedPlsFmt == FORMAT_ASX){ m_playlistFormat = FORMAT_ASX; if(m_f_Log) log_i("set playlist format to ASX");} 3807 if(m_expectedPlsFmt == FORMAT_M3U){ m_playlistFormat = FORMAT_M3U; if(m_f_Log) log_i("set playlist format to M3U");} 3808 if(m_expectedPlsFmt == FORMAT_M3U8){m_playlistFormat = FORMAT_M3U8; if(m_f_Log) log_i("set playlist format to M3U8");} 3809 if(m_expectedPlsFmt == FORMAT_PLS){ m_playlistFormat = FORMAT_PLS; if(m_f_Log) log_i("set playlist format to PLS");} 3810 break; 3811 default: 3812 AUDIO_INFO("%s, unsupported audio format", ct); 3813 return false; 3814 break; 3815 } 3816 return true; 3817 } 3818 //--------------------------------------------------------------------------------------------------------------------- 3819 void Audio::showstreamtitle(const char* ml) { 3820 // example for ml: 3821 // StreamTitle='Oliver Frank - Mega Hitmix';StreamUrl='www.radio-welle-woerthersee.at'; 3822 // or adw_ad='true';durationMilliseconds='10135';adId='34254';insertionType='preroll'; 3823 3824 int16_t idx1, idx2, idx4, idx5, idx6, idx7, titleLen = 0, artistLen = 0; 3825 uint16_t i = 0, hash = 0; 3826 3827 idx1 = indexOf(ml, "StreamTitle=", 0); // Streamtitle found 3828 if(idx1 >= 0){ 3829 if(indexOf(ml, "xml version=", 12) > 0){ 3830 3831 /* e.g. xmlStreamTitle 3832 StreamTitle='<?xml version="1.0" encoding="utf-8"?><RadioInfo><Table><DB_ALBUM_ID>37364</DB_ALBUM_ID> 3833 <DB_ALBUM_IMAGE>00000037364.jpg</DB_ALBUM_IMAGE><DB_ALBUM_NAME>Boyfriend</DB_ALBUM_NAME> 3834 <DB_ALBUM_TYPE>Single</DB_ALBUM_TYPE><DB_DALET_ARTIST_NAME>DOVE CAMERON</DB_DALET_ARTIST_NAME> 3835 <DB_DALET_ITEM_CODE>CD4161</DB_DALET_ITEM_CODE><DB_DALET_TITLE_NAME>BOYFRIEND</DB_DALET_TITLE_NAME> 3836 <DB_FK_SITE_ID>2</DB_FK_SITE_ID><DB_IS_MUSIC>1</DB_IS_MUSIC><DB_LEAD_ARTIST_ID>26303</DB_LEAD_ARTIST_ID> 3837 <DB_LEAD_ARTIST_NAME>Dove Cameron</DB_LEAD_ARTIST_NAME><DB_RADIO_IMAGE>cidadefm.jpg</DB_RADIO_IMAGE> 3838 <DB_RADIO_NAME>Cidade</DB_RADIO_NAME><DB_SONG_ID>120126</DB_SONG_ID><DB_SONG_LYRIC>60981</DB_SONG_LYRIC> 3839 <DB_SONG_NAME>Boyfriend</DB_SONG_NAME></Table><AnimadorInfo><TITLE>Cidade</TITLE> 3840 <START_TIME_UTC>2022-11-15T22:00:00+00:00</START_TIME_UTC><END_TIME_UTC>2022-11-16T06:59:59+00:00 3841 </END_TIME_UTC><SHOW_NAME>Cidade</SHOW_NAME><SHOW_HOURS>22h às 07h</SHOW_HOURS><SHOW_PANEL>0</SHOW_PANEL> 3842 </AnimadorInfo></RadioInfo>';StreamUrl=''; 3843 */ 3844 3845 idx4 = indexOf(ml, "<DB_DALET_TITLE_NAME>"); 3846 idx5 = indexOf(ml, "</DB_DALET_TITLE_NAME>"); 3847 3848 idx6 = indexOf(ml, "<DB_LEAD_ARTIST_NAME>"); 3849 idx7 = indexOf(ml, "</DB_LEAD_ARTIST_NAME>"); 3850 3851 if(idx4 == -1 || idx5 == -1) return; 3852 idx4 += 21; // <DB_DALET_TITLE_NAME> 3853 titleLen = idx5 - idx4; 3854 3855 if(idx6 != -1 && idx7 != -1){ 3856 idx6 += 21; // <DB_LEAD_ARTIST_NAME> 3857 artistLen = idx7 - idx6; 3858 } 3859 3860 char *title = NULL; 3861 title = (char*)malloc(titleLen + artistLen + 4); 3862 memcpy(title, ml + idx4, titleLen); title[titleLen] = '\0'; 3863 3864 char *artist = NULL; 3865 if(artistLen){ 3866 memcpy(title + titleLen, " - ", 3); 3867 memcpy(title + titleLen + 3, ml + idx6, artistLen); title[titleLen + 3 + artistLen] = '\0'; 3868 } 3869 3870 3871 if(title) if(audio_showstreamtitle) audio_showstreamtitle(title); 3872 if(title) {free(title); title = NULL;} 3873 if(artist) {free(artist); artist = NULL;} 3874 return; 3875 } 3876 3877 idx2 = indexOf(ml, ";", idx1); 3878 char *sTit; 3879 if(idx2 >= 0){sTit = strndup(ml + idx1, idx2 + 1); sTit[idx2] = '\0';} 3880 else sTit = strdup(ml); 3881 3882 while(i < strlen(sTit)){hash += sTit[i] * i+1; i++;} 3883 3884 if(m_streamTitleHash != hash){ 3885 m_streamTitleHash = hash; 3886 AUDIO_INFO("%s", sTit); 3887 uint8_t pos = 12; // remove "StreamTitle=" 3888 if(sTit[pos] == '\'') pos++; // remove leading \' 3889 if(sTit[strlen(sTit) - 1] == '\'') sTit[strlen(sTit) -1] = '\0'; // remove trailing \' 3890 if(audio_showstreamtitle) audio_showstreamtitle(sTit + pos); 3891 } 3892 if(sTit) {free(sTit); sTit = NULL;} 3893 } 3894 3895 idx1 = indexOf(ml, "StreamUrl=", 0); 3896 idx2 = indexOf(ml, ";", idx1); 3897 if(idx1 >= 0 && idx2 > idx1){ // StreamURL found 3898 uint16_t len = idx2 - idx1; 3899 char *sUrl; 3900 sUrl = strndup(ml + idx1, len + 1); sUrl[len] = '\0'; 3901 3902 while(i < strlen(sUrl)){hash += sUrl[i] * i+1; i++;} 3903 if(m_streamTitleHash != hash){ 3904 m_streamTitleHash = hash; 3905 AUDIO_INFO("%s", sUrl); 3906 } 3907 if(sUrl) {free(sUrl); sUrl = NULL;} 3908 } 3909 3910 idx1 = indexOf(ml, "adw_ad=", 0); 3911 if(idx1 >= 0){ // Advertisement found 3912 idx1 = indexOf(ml, "durationMilliseconds=", 0); 3913 idx2 = indexOf(ml, ";", idx1); 3914 if(idx1 >= 0 && idx2 > idx1){ 3915 uint16_t len = idx2 - idx1; 3916 char *sAdv; 3917 sAdv = strndup(ml + idx1, len + 1); sAdv[len] = '\0'; 3918 AUDIO_INFO("%s", sAdv); 3919 uint8_t pos = 21; // remove "StreamTitle=" 3920 if(sAdv[pos] == '\'') pos++; // remove leading \' 3921 if(sAdv[strlen(sAdv) - 1] == '\'') sAdv[strlen(sAdv) -1] = '\0'; // remove trailing \' 3922 if(audio_commercial) audio_commercial(sAdv + pos); 3923 if(sAdv){free(sAdv); sAdv = NULL;} 3924 } 3925 } 3926 } 3927 //--------------------------------------------------------------------------------------------------------------------- 3928 void Audio::showCodecParams(){ 3929 // print Codec Parameter (mp3, aac) in audio_info() 3930 3931 AUDIO_INFO("Channels: %i", getChannels()); 3932 AUDIO_INFO("SampleRate: %i", getSampleRate()); 3933 AUDIO_INFO("BitsPerSample: %i", getBitsPerSample()); 3934 if(getBitRate()) {AUDIO_INFO("BitRate: %i", getBitRate());} 3935 else {AUDIO_INFO("BitRate: N/A");} 3936 3937 if(m_codec == CODEC_AAC || m_codec == CODEC_M4A){ 3938 uint8_t answ; 3939 if((answ = AACGetFormat()) < 4){ 3940 const char hf[4][8] = {"unknown", "ADTS", "ADIF", "RAW"}; 3941 sprintf(m_chbuf, "AAC HeaderFormat: %s", hf[answ]); 3942 audio_info(m_chbuf); 3943 } 3944 if(answ == 1){ // ADTS Header 3945 const char co[2][23] = {"MPEG-4", "MPEG-2"}; 3946 sprintf(m_chbuf, "AAC Codec: %s", co[AACGetID()]); 3947 audio_info(m_chbuf); 3948 if(AACGetProfile() <5){ 3949 const char pr[4][23] = {"Main", "LowComplexity", "Scalable Sampling Rate", "reserved"}; 3950 sprintf(m_chbuf, "AAC Profile: %s", pr[answ]); 3951 audio_info(m_chbuf); 3952 } 3953 } 3954 } 3955 } 3956 //--------------------------------------------------------------------------------------------------------------------- 3957 int Audio::findNextSync(uint8_t* data, size_t len){ 3958 // Mp3 and aac audio data are divided into frames. At the beginning of each frame there is a sync word. 3959 // The sync word is 0xFFF. This is followed by information about the structure of the frame. 3960 // Wav files have no frames 3961 // Return: 0 the synchronous word was found at position 0 3962 // > 0 is the offset to the next sync word 3963 // -1 the sync word was not found within the block with the length len 3964 3965 int nextSync; 3966 static uint32_t swnf = 0; 3967 if(m_codec == CODEC_WAV) { 3968 m_f_playing = true; nextSync = 0; 3969 } 3970 if(m_codec == CODEC_MP3) { 3971 nextSync = MP3FindSyncWord(data, len); 3972 } 3973 if(m_codec == CODEC_AAC) { 3974 nextSync = AACFindSyncWord(data, len); 3975 } 3976 if(m_codec == CODEC_M4A) { 3977 AACSetRawBlockParams(0, 2,44100, 1); m_f_playing = true; nextSync = 0; 3978 } 3979 if(m_codec == CODEC_FLAC) { 3980 FLACSetRawBlockParams(m_flacNumChannels, m_flacSampleRate, 3981 m_flacBitsPerSample, m_flacTotalSamplesInStream, m_audioDataSize); 3982 nextSync = FLACFindSyncWord(data, len); 3983 } 3984 if(m_codec == CODEC_OGG_FLAC) { 3985 FLACSetRawBlockParams(m_flacNumChannels, m_flacSampleRate, 3986 m_flacBitsPerSample, m_flacTotalSamplesInStream, m_audioDataSize); 3987 nextSync = FLACFindSyncWord(data, len); 3988 } 3989 if(nextSync == -1) { 3990 if(audio_info && swnf == 0) audio_info("syncword not found"); 3991 if(m_codec == CODEC_OGG_FLAC){ 3992 nextSync = len; 3993 } 3994 else { 3995 swnf++; // syncword not found counter, can be multimediadata 3996 } 3997 } 3998 if (nextSync == 0){ 3999 if(audio_info && swnf>0){ 4000 sprintf(m_chbuf, "syncword not found %i times", swnf); 4001 audio_info(m_chbuf); 4002 swnf = 0; 4003 } 4004 else { 4005 if(audio_info) audio_info("syncword found at pos 0"); 4006 } 4007 } 4008 if(nextSync > 0){ 4009 AUDIO_INFO("syncword found at pos %i", nextSync); 4010 } 4011 return nextSync; 4012 } 4013 //--------------------------------------------------------------------------------------------------------------------- 4014 int Audio::sendBytes(uint8_t* data, size_t len) { 4015 int bytesLeft; 4016 static bool f_setDecodeParamsOnce = true; 4017 int nextSync = 0; 4018 if(!m_f_playing) { 4019 f_setDecodeParamsOnce = true; 4020 nextSync = findNextSync(data, len); 4021 if(nextSync == 0) { m_f_playing = true;} 4022 return nextSync; 4023 } 4024 // m_f_playing is true at this pos 4025 bytesLeft = len; 4026 int ret = 0; 4027 int bytesDecoded = 0; 4028 4029 switch(m_codec){ 4030 case CODEC_WAV: memmove(m_outBuff, data , len); //copy len data in outbuff and set validsamples and bytesdecoded=len 4031 if(getBitsPerSample() == 16) m_validSamples = len / (2 * getChannels()); 4032 if(getBitsPerSample() == 8 ) m_validSamples = len / 2; 4033 bytesLeft = 0; break; 4034 case CODEC_MP3: ret = MP3Decode(data, &bytesLeft, m_outBuff, 0); break; 4035 case CODEC_AAC: ret = AACDecode(data, &bytesLeft, m_outBuff); break; 4036 case CODEC_M4A: ret = AACDecode(data, &bytesLeft, m_outBuff); break; 4037 case CODEC_FLAC: ret = FLACDecode(data, &bytesLeft, m_outBuff); break; 4038 case CODEC_OGG_FLAC: ret = FLACDecode(data, &bytesLeft, m_outBuff); break; // FLAC webstream wrapped in OGG 4039 default: {log_e("no valid codec found codec = %d", m_codec); stopSong();} 4040 } 4041 4042 bytesDecoded = len - bytesLeft; 4043 if(bytesDecoded == 0 && ret == 0){ // unlikely framesize 4044 if(audio_info) audio_info("framesize is 0, start decoding again"); 4045 m_f_playing = false; // seek for new syncword 4046 // we're here because there was a wrong sync word 4047 // so skip two sync bytes and seek for next 4048 return 1; 4049 } 4050 if(ret < 0) { // Error, skip the frame... 4051 if(m_f_Log) if(m_codec == CODEC_M4A){log_i("begin not found"); return 1;} 4052 i2s_zero_dma_buffer((i2s_port_t)m_i2s_num); 4053 if(!getChannels() && (ret == -2)) { 4054 ; // suppress errorcode MAINDATA_UNDERFLOW 4055 } 4056 else { 4057 if(m_codec == CODEC_MP3 && ret == -2){ ; } // do nothing (suppress MAINDATA_UNDERFLOW) 4058 else{ 4059 printDecodeError(ret); 4060 m_f_playing = false; // seek for new syncword 4061 } 4062 } 4063 if(!bytesDecoded) bytesDecoded = 2; 4064 return bytesDecoded; 4065 } 4066 else{ // ret>=0 4067 if(f_setDecodeParamsOnce){ 4068 f_setDecodeParamsOnce = false; 4069 m_PlayingStartTime = millis(); 4070 4071 if(m_codec == CODEC_MP3){ 4072 setChannels(MP3GetChannels()); 4073 setSampleRate(MP3GetSampRate()); 4074 setBitsPerSample(MP3GetBitsPerSample()); 4075 setBitrate(MP3GetBitrate()); 4076 } 4077 if(m_codec == CODEC_AAC || m_codec == CODEC_M4A){ 4078 setChannels(AACGetChannels()); 4079 setSampleRate(AACGetSampRate()); 4080 setBitsPerSample(AACGetBitsPerSample()); 4081 setBitrate(AACGetBitrate()); 4082 } 4083 if(m_codec == CODEC_FLAC || m_codec == CODEC_OGG_FLAC){ 4084 setChannels(FLACGetChannels()); 4085 setSampleRate(FLACGetSampRate()); 4086 setBitsPerSample(FLACGetBitsPerSample()); 4087 setBitrate(FLACGetBitRate()); 4088 } 4089 showCodecParams(); 4090 } 4091 if(m_codec == CODEC_MP3){ 4092 m_validSamples = MP3GetOutputSamps() / getChannels(); 4093 } 4094 if((m_codec == CODEC_AAC) || (m_codec == CODEC_M4A)){ 4095 m_validSamples = AACGetOutputSamps() / getChannels(); 4096 } 4097 if((m_codec == CODEC_FLAC) || (m_codec == CODEC_OGG_FLAC)){ 4098 m_validSamples = FLACGetOutputSamps() / getChannels(); 4099 } 4100 } 4101 compute_audioCurrentTime(bytesDecoded); 4102 4103 if(audio_process_extern){ 4104 bool continueI2S = false; 4105 audio_process_extern(m_outBuff, m_validSamples, &continueI2S); 4106 if(!continueI2S){ 4107 return bytesDecoded; 4108 } 4109 } 4110 while(m_validSamples) { 4111 playChunk(); 4112 } 4113 return bytesDecoded; 4114 } 4115 //--------------------------------------------------------------------------------------------------------------------- 4116 void Audio::compute_audioCurrentTime(int bd) { 4117 static uint16_t loop_counter = 0; 4118 static int old_bitrate = 0; 4119 static uint64_t sum_bitrate = 0; 4120 static boolean f_CBR = true; // constant bitrate 4121 4122 if(m_codec == CODEC_MP3) {setBitrate(MP3GetBitrate()) ;} // if not CBR, bitrate can be changed 4123 if(m_codec == CODEC_M4A) {setBitrate(AACGetBitrate()) ;} // if not CBR, bitrate can be changed 4124 if(m_codec == CODEC_AAC) {setBitrate(AACGetBitrate()) ;} // if not CBR, bitrate can be changed 4125 if(m_codec == CODEC_FLAC){setBitrate(FLACGetBitRate());} // if not CBR, bitrate can be changed 4126 if(!getBitRate()) return; 4127 4128 //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 4129 if(m_avr_bitrate == 0) { // first time 4130 loop_counter = 0; 4131 old_bitrate = 0; 4132 sum_bitrate = 0; 4133 f_CBR = true; 4134 m_avr_bitrate = getBitRate(); 4135 old_bitrate = getBitRate(); 4136 } 4137 if(!m_avr_bitrate) return; 4138 //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 4139 4140 if(loop_counter < 1000) loop_counter ++; 4141 4142 if((old_bitrate != getBitRate()) && f_CBR) { 4143 if(audio_info) audio_info("VBR recognized, audioFileDuration is estimated"); 4144 f_CBR = false; // variable bitrate 4145 } 4146 old_bitrate = getBitRate(); 4147 4148 if(!f_CBR) { 4149 if(loop_counter > 20 && loop_counter < 200) { 4150 // if VBR: m_avr_bitrate is average of the first values of m_bitrate 4151 sum_bitrate += getBitRate(); 4152 m_avr_bitrate = sum_bitrate / (loop_counter - 20); 4153 if(loop_counter == 199 && m_resumeFilePos){ 4154 m_audioCurrentTime = ((getFilePos() - m_audioDataStart - inBufferFilled()) / m_avr_bitrate) * 8; // #293 4155 } 4156 } 4157 } 4158 else { 4159 if(loop_counter == 2){ 4160 m_avr_bitrate = getBitRate(); 4161 if(m_resumeFilePos){ // if connecttoFS() is called with resumeFilePos != 0 4162 m_audioCurrentTime = ((getFilePos() - m_audioDataStart - inBufferFilled()) / m_avr_bitrate) * 8; // #293 4163 } 4164 } 4165 } 4166 m_audioCurrentTime += ((float)bd / m_avr_bitrate) * 8; 4167 } 4168 //--------------------------------------------------------------------------------------------------------------------- 4169 void Audio::printDecodeError(int r) { 4170 const char *e; 4171 4172 if(m_codec == CODEC_MP3){ 4173 switch(r){ 4174 case ERR_MP3_NONE: e = "NONE"; break; 4175 case ERR_MP3_INDATA_UNDERFLOW: e = "INDATA_UNDERFLOW"; break; 4176 case ERR_MP3_MAINDATA_UNDERFLOW: e = "MAINDATA_UNDERFLOW"; break; 4177 case ERR_MP3_FREE_BITRATE_SYNC: e = "FREE_BITRATE_SYNC"; break; 4178 case ERR_MP3_OUT_OF_MEMORY: e = "OUT_OF_MEMORY"; break; 4179 case ERR_MP3_NULL_POINTER: e = "NULL_POINTER"; break; 4180 case ERR_MP3_INVALID_FRAMEHEADER: e = "INVALID_FRAMEHEADER"; break; 4181 case ERR_MP3_INVALID_SIDEINFO: e = "INVALID_SIDEINFO"; break; 4182 case ERR_MP3_INVALID_SCALEFACT: e = "INVALID_SCALEFACT"; break; 4183 case ERR_MP3_INVALID_HUFFCODES: e = "INVALID_HUFFCODES"; break; 4184 case ERR_MP3_INVALID_DEQUANTIZE: e = "INVALID_DEQUANTIZE"; break; 4185 case ERR_MP3_INVALID_IMDCT: e = "INVALID_IMDCT"; break; 4186 case ERR_MP3_INVALID_SUBBAND: e = "INVALID_SUBBAND"; break; 4187 default: e = "ERR_UNKNOWN"; 4188 } 4189 AUDIO_INFO("MP3 decode error %d : %s", r, e); 4190 } 4191 if(m_codec == CODEC_AAC){ 4192 switch(r){ 4193 case ERR_AAC_NONE: e = "NONE"; break; 4194 case ERR_AAC_INDATA_UNDERFLOW: e = "INDATA_UNDERFLOW"; break; 4195 case ERR_AAC_NULL_POINTER: e = "NULL_POINTER"; break; 4196 case ERR_AAC_INVALID_ADTS_HEADER: e = "INVALID_ADTS_HEADER"; break; 4197 case ERR_AAC_INVALID_ADIF_HEADER: e = "INVALID_ADIF_HEADER"; break; 4198 case ERR_AAC_INVALID_FRAME: e = "INVALID_FRAME"; break; 4199 case ERR_AAC_MPEG4_UNSUPPORTED: e = "MPEG4_UNSUPPORTED"; break; 4200 case ERR_AAC_CHANNEL_MAP: e = "CHANNEL_MAP"; break; 4201 case ERR_AAC_SYNTAX_ELEMENT: e = "SYNTAX_ELEMENT"; break; 4202 case ERR_AAC_DEQUANT: e = "DEQUANT"; break; 4203 case ERR_AAC_STEREO_PROCESS: e = "STEREO_PROCESS"; break; 4204 case ERR_AAC_PNS: e = "PNS"; break; 4205 case ERR_AAC_SHORT_BLOCK_DEINT: e = "SHORT_BLOCK_DEINT"; break; 4206 case ERR_AAC_TNS: e = "TNS"; break; 4207 case ERR_AAC_IMDCT: e = "IMDCT"; break; 4208 case ERR_AAC_SBR_INIT: e = "SBR_INIT"; break; 4209 case ERR_AAC_SBR_BITSTREAM: e = "SBR_BITSTREAM"; break; 4210 case ERR_AAC_SBR_DATA: e = "SBR_DATA"; break; 4211 case ERR_AAC_SBR_PCM_FORMAT: e = "SBR_PCM_FORMAT"; break; 4212 case ERR_AAC_SBR_NCHANS_TOO_HIGH: e = "SBR_NCHANS_TOO_HIGH"; break; 4213 case ERR_AAC_SBR_SINGLERATE_UNSUPPORTED: e = "BR_SINGLERATE_UNSUPPORTED"; break; 4214 case ERR_AAC_NCHANS_TOO_HIGH: e = "NCHANS_TOO_HIGH"; break; 4215 case ERR_AAC_RAWBLOCK_PARAMS: e = "RAWBLOCK_PARAMS"; break; 4216 default: e = "ERR_UNKNOWN"; 4217 } 4218 AUDIO_INFO("AAC decode error %d : %s", r, e); 4219 } 4220 if(m_codec == CODEC_FLAC){ 4221 switch(r){ 4222 case ERR_FLAC_NONE: e = "NONE"; break; 4223 case ERR_FLAC_BLOCKSIZE_TOO_BIG: e = "BLOCKSIZE TOO BIG"; break; 4224 case ERR_FLAC_RESERVED_BLOCKSIZE_UNSUPPORTED: e = "Reserved Blocksize unsupported"; break; 4225 case ERR_FLAC_SYNC_CODE_NOT_FOUND: e = "SYNC CODE NOT FOUND"; break; 4226 case ERR_FLAC_UNKNOWN_CHANNEL_ASSIGNMENT: e = "UNKNOWN CHANNEL ASSIGNMENT"; break; 4227 case ERR_FLAC_RESERVED_CHANNEL_ASSIGNMENT: e = "RESERVED CHANNEL ASSIGNMENT"; break; 4228 case ERR_FLAC_RESERVED_SUB_TYPE: e = "RESERVED SUB TYPE"; break; 4229 case ERR_FLAC_PREORDER_TOO_BIG: e = "PREORDER TOO BIG"; break; 4230 case ERR_FLAC_RESERVED_RESIDUAL_CODING: e = "RESERVED RESIDUAL CODING"; break; 4231 case ERR_FLAC_WRONG_RICE_PARTITION_NR: e = "WRONG RICE PARTITION NR"; break; 4232 case ERR_FLAC_BITS_PER_SAMPLE_TOO_BIG: e = "BITS PER SAMPLE > 16"; break; 4233 case ERR_FLAG_BITS_PER_SAMPLE_UNKNOWN: e = "BITS PER SAMPLE UNKNOWN"; break; 4234 default: e = "ERR_UNKNOWN"; 4235 } 4236 AUDIO_INFO("FLAC decode error %d : %s", r, e); 4237 } 4238 } 4239 //--------------------------------------------------------------------------------------------------------------------- 4240 bool Audio::setPinout(uint8_t BCLK, uint8_t LRC, uint8_t DOUT, int8_t DIN, int8_t MCK) { 4241 4242 m_pin_config.bck_io_num = BCLK; 4243 m_pin_config.ws_io_num = LRC; // wclk 4244 m_pin_config.data_out_num = DOUT; 4245 m_pin_config.data_in_num = DIN; 4246 #if(ESP_IDF_VERSION_MAJOR >= 4 && ESP_IDF_VERSION_MINOR >= 4) 4247 m_pin_config.mck_io_num = MCK; 4248 #endif 4249 4250 const esp_err_t result = i2s_set_pin((i2s_port_t) m_i2s_num, &m_pin_config); 4251 return (result == ESP_OK); 4252 } 4253 //--------------------------------------------------------------------------------------------------------------------- 4254 uint32_t Audio::getFileSize() { 4255 #ifdef AUDIO_NO_SD_FS 4256 return 0; 4257 #else 4258 if(!audiofile) return 0; 4259 return audiofile.size(); 4260 #endif // AUDIO_NO_SD_FS 4261 } 4262 //--------------------------------------------------------------------------------------------------------------------- 4263 uint32_t Audio::getFilePos() { 4264 #ifdef AUDIO_NO_SD_FS 4265 return 0; 4266 #else 4267 if(!audiofile) return 0; 4268 return audiofile.position(); 4269 #endif // AUDIO_NO_SD_FS 4270 } 4271 //--------------------------------------------------------------------------------------------------------------------- 4272 uint32_t Audio::getAudioDataStartPos() { 4273 #ifdef AUDIO_NO_SD_FS 4274 return 0; 4275 #else 4276 if(!audiofile) return 0; 4277 return m_audioDataStart; 4278 #endif // AUDIO_NO_SD_FS 4279 } 4280 //--------------------------------------------------------------------------------------------------------------------- 4281 uint32_t Audio::getAudioFileDuration() { 4282 #ifndef AUDIO_NO_SD_FS 4283 if(getDatamode() == AUDIO_LOCALFILE) {if(!audiofile) return 0;} 4284 #endif 4285 if(m_streamType == ST_WEBFILE) {if(!m_contentlength) return 0;} 4286 4287 if (m_avr_bitrate && m_codec == CODEC_MP3) m_audioFileDuration = 8 * (m_audioDataSize / m_avr_bitrate); // #289 4288 else if(m_avr_bitrate && m_codec == CODEC_WAV) m_audioFileDuration = 8 * (m_audioDataSize / m_avr_bitrate); 4289 else if(m_avr_bitrate && m_codec == CODEC_M4A) m_audioFileDuration = 8 * (m_audioDataSize / m_avr_bitrate); 4290 else if(m_avr_bitrate && m_codec == CODEC_AAC) m_audioFileDuration = 8 * (m_audioDataSize / m_avr_bitrate); 4291 else if( m_codec == CODEC_FLAC) m_audioFileDuration = FLACGetAudioFileDuration(); 4292 else return 0; 4293 return m_audioFileDuration; 4294 } 4295 //--------------------------------------------------------------------------------------------------------------------- 4296 uint32_t Audio::getAudioCurrentTime() { // return current time in seconds 4297 return (uint32_t) m_audioCurrentTime; 4298 } 4299 //--------------------------------------------------------------------------------------------------------------------- 4300 bool Audio::setAudioPlayPosition(uint16_t sec){ 4301 // Jump to an absolute position in time within an audio file 4302 // e.g. setAudioPlayPosition(300) sets the pointer at pos 5 min 4303 // works only with format mp3 or wav 4304 if(m_codec == CODEC_M4A) return false; 4305 if(sec > getAudioFileDuration()) sec = getAudioFileDuration(); 4306 uint32_t filepos = m_audioDataStart + (m_avr_bitrate * sec / 8); 4307 4308 return setFilePos(filepos); 4309 } 4310 //--------------------------------------------------------------------------------------------------------------------- 4311 uint32_t Audio::getTotalPlayingTime() { 4312 // Is set to zero by a connectToXXX() and starts as soon as the first audio data is available, 4313 // the time counting is not interrupted by a 'pause / resume' and is not reset by a fileloop 4314 return millis() - m_PlayingStartTime; 4315 } 4316 //--------------------------------------------------------------------------------------------------------------------- 4317 bool Audio::setTimeOffset(int sec){ 4318 // fast forward or rewind the current position in seconds 4319 // audiosource must be a mp3, aac or wav file 4320 4321 #ifndef AUDIO_NO_SD_FS 4322 4323 if(!audiofile || !m_avr_bitrate) return false; 4324 4325 uint32_t oneSec = m_avr_bitrate / 8; // bytes decoded in one sec 4326 int32_t offset = oneSec * sec; // bytes to be wind/rewind 4327 uint32_t startAB = m_audioDataStart; // audioblock begin 4328 uint32_t endAB = m_audioDataStart + m_audioDataSize; // audioblock end 4329 4330 if(m_codec == CODEC_MP3 || m_codec == CODEC_AAC || m_codec == CODEC_WAV || m_codec == CODEC_FLAC){ 4331 int32_t pos = getFilePos(); 4332 pos += offset; 4333 if(pos < (int32_t)startAB) pos = startAB; 4334 if(pos >= (int32_t)endAB) pos = endAB; 4335 setFilePos(pos); 4336 return true; 4337 } 4338 #endif // AUDIO_NO_SD_FS 4339 return false; 4340 } 4341 //--------------------------------------------------------------------------------------------------------------------- 4342 bool Audio::setFilePos(uint32_t pos) { 4343 #ifdef AUDIO_NO_SD_FS 4344 return false; 4345 #else 4346 if(!audiofile) return false; 4347 if(pos < m_audioDataStart) pos = m_audioDataStart; // issue #96 4348 if(pos > m_file_size) pos = m_file_size; 4349 m_resumeFilePos = pos; 4350 return true; 4351 #endif // AUDIO_NO_SD_FS 4352 } 4353 //--------------------------------------------------------------------------------------------------------------------- 4354 bool Audio::audioFileSeek(const float speed) { 4355 // 0.5 is half speed 4356 // 1.0 is normal speed 4357 // 1.5 is one and half speed 4358 if((speed > 1.5f) || (speed < 0.25f)) return false; 4359 4360 uint32_t srate = getSampleRate() * speed; 4361 i2s_set_sample_rates((i2s_port_t)m_i2s_num, srate); 4362 return true; 4363 } 4364 //--------------------------------------------------------------------------------------------------------------------- 4365 bool Audio::setSampleRate(uint32_t sampRate) { 4366 if(!sampRate) sampRate = 16000; // fuse, if there is no value -> set default #209 4367 i2s_set_sample_rates((i2s_port_t)m_i2s_num, sampRate); 4368 m_sampleRate = sampRate; 4369 IIR_calculateCoefficients(m_gain0, m_gain1, m_gain2); // must be recalculated after each samplerate change 4370 return true; 4371 } 4372 uint32_t Audio::getSampleRate(){ 4373 return m_sampleRate; 4374 } 4375 //--------------------------------------------------------------------------------------------------------------------- 4376 bool Audio::setBitsPerSample(int bits) { 4377 if((bits != 16) && (bits != 8)) return false; 4378 m_bitsPerSample = bits; 4379 return true; 4380 } 4381 uint8_t Audio::getBitsPerSample(){ 4382 return m_bitsPerSample; 4383 } 4384 //--------------------------------------------------------------------------------------------------------------------- 4385 bool Audio::setChannels(int ch) { 4386 if((ch < 1) || (ch > 2)) return false; 4387 m_channels = ch; 4388 return true; 4389 } 4390 uint8_t Audio::getChannels(){ 4391 if (m_channels == 0) { // this should not happen! #209 4392 m_channels = 2; 4393 } 4394 return m_channels; 4395 } 4396 //--------------------------------------------------------------------------------------------------------------------- 4397 bool Audio::setBitrate(int br){ 4398 m_bitRate = br; 4399 if(br)return true; 4400 return false; 4401 } 4402 uint32_t Audio::getBitRate(bool avg){ 4403 if (avg) 4404 return m_avr_bitrate; 4405 return m_bitRate; 4406 } 4407 //--------------------------------------------------------------------------------------------------------------------- 4408 void Audio::setI2SCommFMT_LSB(bool commFMT) { 4409 // false: I2S communication format is by default I2S_COMM_FORMAT_I2S_MSB, right->left (AC101, PCM5102A) 4410 // true: changed to I2S_COMM_FORMAT_I2S_LSB for some DACs (PT8211) 4411 // Japanese or called LSBJ (Least Significant Bit Justified) format 4412 4413 if (commFMT) { 4414 if(m_f_Log) log_i("commFMT LSB"); 4415 4416 #if ESP_ARDUINO_VERSION_MAJOR >= 2 4417 m_i2s_config.communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_STAND_MSB); // v >= 2.0.0 4418 #else 4419 m_i2s_config.communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_LSB); 4420 #endif 4421 4422 } 4423 else { 4424 if(m_f_Log) log_i("commFMT MSB"); 4425 4426 #if ESP_ARDUINO_VERSION_MAJOR >= 2 4427 m_i2s_config.communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_STAND_I2S); // vers >= 2.0.0 4428 #else 4429 m_i2s_config.communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB); 4430 #endif 4431 4432 } 4433 AUDIO_INFO("commFMT = %i", m_i2s_config.communication_format); 4434 i2s_driver_uninstall((i2s_port_t)m_i2s_num); 4435 i2s_driver_install ((i2s_port_t)m_i2s_num, &m_i2s_config, 0, NULL); 4436 } 4437 //--------------------------------------------------------------------------------------------------------------------- 4438 bool Audio::playSample(int16_t sample[2]) { 4439 4440 if (getBitsPerSample() == 8) { // Upsample from unsigned 8 bits to signed 16 bits 4441 sample[LEFTCHANNEL] = ((sample[LEFTCHANNEL] & 0xff) -128) << 8; 4442 sample[RIGHTCHANNEL] = ((sample[RIGHTCHANNEL] & 0xff) -128) << 8; 4443 } 4444 4445 sample[LEFTCHANNEL] = sample[LEFTCHANNEL] >> 1; // half Vin so we can boost up to 6dB in filters 4446 sample[RIGHTCHANNEL] = sample[RIGHTCHANNEL] >> 1; 4447 4448 // Filterchain, can commented out if not used 4449 sample = IIR_filterChain0(sample); 4450 sample = IIR_filterChain1(sample); 4451 sample = IIR_filterChain2(sample); 4452 //------------------------------------------- 4453 4454 uint32_t s32 = Gain(sample); // vosample2lume; 4455 4456 if(audio_process_i2s){ 4457 // process audio sample just before writing to i2s 4458 bool continueI2S = false; 4459 audio_process_i2s(&s32, &continueI2S); 4460 if(!continueI2S){ 4461 return true; 4462 } 4463 } 4464 4465 if(m_f_internalDAC) { 4466 s32 += 0x80008000; 4467 } 4468 m_i2s_bytesWritten = 0; 4469 esp_err_t err = i2s_write((i2s_port_t) m_i2s_num, (const char*) &s32, sizeof(uint32_t), &m_i2s_bytesWritten, 100); 4470 if(err != ESP_OK) { 4471 log_e("ESP32 Errorcode %i", err); 4472 return false; 4473 } 4474 if(m_i2s_bytesWritten < 4) { 4475 log_e("Can't stuff any more in I2S..."); // increase waitingtime or outputbuffer 4476 return false; 4477 } 4478 return true; 4479 } 4480 //--------------------------------------------------------------------------------------------------------------------- 4481 void Audio::setTone(int8_t gainLowPass, int8_t gainBandPass, int8_t gainHighPass){ 4482 // see https://www.earlevel.com/main/2013/10/13/biquad-calculator-v2/ 4483 // values can be between -40 ... +6 (dB) 4484 4485 m_gain0 = gainLowPass; 4486 m_gain1 = gainBandPass; 4487 m_gain2 = gainHighPass; 4488 4489 IIR_calculateCoefficients(m_gain0, m_gain1, m_gain2); 4490 4491 /* 4492 This will cause a clicking sound when adjusting the EQ. 4493 Because when the EQ is adjusted, the IIR filter will be cleared and played, 4494 mixed in the audio data frame, and a click-like sound will be produced. 4495 */ 4496 /* 4497 int16_t tmp[2]; tmp[0] = 0; tmp[1]= 0; 4498 4499 IIR_filterChain0(tmp, true ); // flush the filter 4500 IIR_filterChain1(tmp, true ); // flush the filter 4501 IIR_filterChain2(tmp, true ); // flush the filter 4502 */ 4503 } 4504 //--------------------------------------------------------------------------------------------------------------------- 4505 void Audio::forceMono(bool m) { // #100 mono option 4506 m_f_forceMono = m; // false stereo, true mono 4507 } 4508 //--------------------------------------------------------------------------------------------------------------------- 4509 void Audio::setBalance(int8_t bal){ // bal -16...16 4510 if(bal < -16) bal = -16; 4511 if(bal > 16) bal = 16; 4512 m_balance = bal; 4513 } 4514 //--------------------------------------------------------------------------------------------------------------------- 4515 void Audio::setVolume(uint8_t vol) { // vol 22 steps, 0...21 4516 if(vol > 21) vol = 21; 4517 m_vol = volumetable[vol]; 4518 } 4519 //--------------------------------------------------------------------------------------------------------------------- 4520 uint8_t Audio::getVolume() { 4521 for(uint8_t i = 0; i < 22; i++) { 4522 if(volumetable[i] == m_vol) return i; 4523 } 4524 m_vol = 12; // if m_vol not found in table 4525 return m_vol; 4526 } 4527 //--------------------------------------------------------------------------------------------------------------------- 4528 uint8_t Audio::getI2sPort() { 4529 return m_i2s_num; 4530 } 4531 //--------------------------------------------------------------------------------------------------------------------- 4532 int32_t Audio::Gain(int16_t s[2]) { 4533 int32_t v[2]; 4534 float step = (float)m_vol /64; 4535 uint8_t l = 0, r = 0; 4536 4537 if(m_balance < 0){ 4538 step = step * (float)(abs(m_balance) * 4); 4539 l = (uint8_t)(step); 4540 } 4541 if(m_balance > 0){ 4542 step = step * m_balance * 4; 4543 r = (uint8_t)(step); 4544 } 4545 4546 v[LEFTCHANNEL] = (s[LEFTCHANNEL] * (m_vol - l)) >> 6; 4547 v[RIGHTCHANNEL]= (s[RIGHTCHANNEL] * (m_vol - r)) >> 6; 4548 4549 return (v[LEFTCHANNEL] << 16) | (v[RIGHTCHANNEL] & 0xffff); 4550 } 4551 //--------------------------------------------------------------------------------------------------------------------- 4552 uint32_t Audio::inBufferFilled() { 4553 // current audio input buffer fillsize in bytes 4554 return InBuff.bufferFilled(); 4555 } 4556 //--------------------------------------------------------------------------------------------------------------------- 4557 uint32_t Audio::inBufferFree() { 4558 // current audio input buffer free space in bytes 4559 return InBuff.freeSpace(); 4560 } 4561 //--------------------------------------------------------------------------------------------------------------------- 4562 // *** D i g i t a l b i q u a d r a t i c f i l t e r *** 4563 //--------------------------------------------------------------------------------------------------------------------- 4564 void Audio::IIR_calculateCoefficients(int8_t G0, int8_t G1, int8_t G2){ // Infinite Impulse Response (IIR) filters 4565 4566 // G1 - gain low shelf set between -40 ... +6 dB 4567 // G2 - gain peakEQ set between -40 ... +6 dB 4568 // G3 - gain high shelf set between -40 ... +6 dB 4569 // https://www.earlevel.com/main/2012/11/26/biquad-c-source-code/ 4570 4571 if(getSampleRate() < 1000) return; // fuse 4572 4573 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 4574 4575 if(G0 < -40) G0 = -40; // -40dB -> Vin*0.01 4576 if(G0 > 6) G0 = 6; // +6dB -> Vin*2 4577 if(G1 < -40) G1 = -40; 4578 if(G1 > 6) G1 = 6; 4579 if(G2 < -40) G2 = -40; 4580 if(G2 > 6) G2 = 6; 4581 4582 const float FcLS = 500; // Frequency LowShelf[Hz] 4583 const float FcPKEQ = 3000; // Frequency PeakEQ[Hz] 4584 const float FcHS = 6000; // Frequency HighShelf[Hz] 4585 4586 float K, norm, Q, Fc, V ; 4587 4588 // LOWSHELF 4589 Fc = (float)FcLS / (float)getSampleRate(); // Cutoff frequency 4590 K = tanf((float)PI * Fc); 4591 V = powf(10, fabs(G0) / 20.0); 4592 4593 if (G0 >= 0) { // boost 4594 norm = 1 / (1 + sqrtf(2) * K + K * K); 4595 m_filter[LOWSHELF].a0 = (1 + sqrtf(2*V) * K + V * K * K) * norm; 4596 m_filter[LOWSHELF].a1 = 2 * (V * K * K - 1) * norm; 4597 m_filter[LOWSHELF].a2 = (1 - sqrtf(2*V) * K + V * K * K) * norm; 4598 m_filter[LOWSHELF].b1 = 2 * (K * K - 1) * norm; 4599 m_filter[LOWSHELF].b2 = (1 - sqrtf(2) * K + K * K) * norm; 4600 } 4601 else { // cut 4602 norm = 1 / (1 + sqrtf(2*V) * K + V * K * K); 4603 m_filter[LOWSHELF].a0 = (1 + sqrtf(2) * K + K * K) * norm; 4604 m_filter[LOWSHELF].a1 = 2 * (K * K - 1) * norm; 4605 m_filter[LOWSHELF].a2 = (1 - sqrtf(2) * K + K * K) * norm; 4606 m_filter[LOWSHELF].b1 = 2 * (V * K * K - 1) * norm; 4607 m_filter[LOWSHELF].b2 = (1 - sqrtf(2*V) * K + V * K * K) * norm; 4608 } 4609 4610 // PEAK EQ 4611 Fc = (float)FcPKEQ / (float)getSampleRate(); // Cutoff frequency 4612 K = tanf((float)PI * Fc); 4613 V = powf(10, fabs(G1) / 20.0); 4614 Q = 2.5; // Quality factor 4615 if (G1 >= 0) { // boost 4616 norm = 1 / (1 + 1/Q * K + K * K); 4617 m_filter[PEAKEQ].a0 = (1 + V/Q * K + K * K) * norm; 4618 m_filter[PEAKEQ].a1 = 2 * (K * K - 1) * norm; 4619 m_filter[PEAKEQ].a2 = (1 - V/Q * K + K * K) * norm; 4620 m_filter[PEAKEQ].b1 = m_filter[PEAKEQ].a1; 4621 m_filter[PEAKEQ].b2 = (1 - 1/Q * K + K * K) * norm; 4622 } 4623 else { // cut 4624 norm = 1 / (1 + V/Q * K + K * K); 4625 m_filter[PEAKEQ].a0 = (1 + 1/Q * K + K * K) * norm; 4626 m_filter[PEAKEQ].a1 = 2 * (K * K - 1) * norm; 4627 m_filter[PEAKEQ].a2 = (1 - 1/Q * K + K * K) * norm; 4628 m_filter[PEAKEQ].b1 = m_filter[PEAKEQ].a1; 4629 m_filter[PEAKEQ].b2 = (1 - V/Q * K + K * K) * norm; 4630 } 4631 4632 // HIGHSHELF 4633 Fc = (float)FcHS / (float)getSampleRate(); // Cutoff frequency 4634 K = tanf((float)PI * Fc); 4635 V = powf(10, fabs(G2) / 20.0); 4636 if (G2 >= 0) { // boost 4637 norm = 1 / (1 + sqrtf(2) * K + K * K); 4638 m_filter[HIFGSHELF].a0 = (V + sqrtf(2*V) * K + K * K) * norm; 4639 m_filter[HIFGSHELF].a1 = 2 * (K * K - V) * norm; 4640 m_filter[HIFGSHELF].a2 = (V - sqrtf(2*V) * K + K * K) * norm; 4641 m_filter[HIFGSHELF].b1 = 2 * (K * K - 1) * norm; 4642 m_filter[HIFGSHELF].b2 = (1 - sqrtf(2) * K + K * K) * norm; 4643 } 4644 else { 4645 norm = 1 / (V + sqrtf(2*V) * K + K * K); 4646 m_filter[HIFGSHELF].a0 = (1 + sqrtf(2) * K + K * K) * norm; 4647 m_filter[HIFGSHELF].a1 = 2 * (K * K - 1) * norm; 4648 m_filter[HIFGSHELF].a2 = (1 - sqrtf(2) * K + K * K) * norm; 4649 m_filter[HIFGSHELF].b1 = 2 * (K * K - V) * norm; 4650 m_filter[HIFGSHELF].b2 = (V - sqrtf(2*V) * K + K * K) * norm; 4651 } 4652 4653 // log_i("LS a0=%f, a1=%f, a2=%f, b1=%f, b2=%f", m_filter[0].a0, m_filter[0].a1, m_filter[0].a2, 4654 // m_filter[0].b1, m_filter[0].b2); 4655 // log_i("EQ a0=%f, a1=%f, a2=%f, b1=%f, b2=%f", m_filter[1].a0, m_filter[1].a1, m_filter[1].a2, 4656 // m_filter[1].b1, m_filter[1].b2); 4657 // log_i("HS a0=%f, a1=%f, a2=%f, b1=%f, b2=%f", m_filter[2].a0, m_filter[2].a1, m_filter[2].a2, 4658 // m_filter[2].b1, m_filter[2].b2); 4659 } 4660 //--------------------------------------------------------------------------------------------------------------------- 4661 int16_t* Audio::IIR_filterChain0(int16_t iir_in[2], bool clear){ // Infinite Impulse Response (IIR) filters 4662 4663 uint8_t z1 = 0, z2 = 1; 4664 enum: uint8_t {in = 0, out = 1}; 4665 float inSample[2]; 4666 float outSample[2]; 4667 static int16_t iir_out[2]; 4668 4669 if(clear){ 4670 memset(m_filterBuff, 0, sizeof(m_filterBuff)); // zero IIR filterbuffer 4671 iir_out[0] = 0; 4672 iir_out[1] = 0; 4673 iir_in[0] = 0; 4674 iir_in[1] = 0; 4675 } 4676 4677 inSample[LEFTCHANNEL] = (float)(iir_in[LEFTCHANNEL]); 4678 inSample[RIGHTCHANNEL] = (float)(iir_in[RIGHTCHANNEL]); 4679 4680 outSample[LEFTCHANNEL] = m_filter[0].a0 * inSample[LEFTCHANNEL] 4681 + m_filter[0].a1 * m_filterBuff[0][z1][in] [LEFTCHANNEL] 4682 + m_filter[0].a2 * m_filterBuff[0][z2][in] [LEFTCHANNEL] 4683 - m_filter[0].b1 * m_filterBuff[0][z1][out][LEFTCHANNEL] 4684 - m_filter[0].b2 * m_filterBuff[0][z2][out][LEFTCHANNEL]; 4685 4686 m_filterBuff[0][z2][in] [LEFTCHANNEL] = m_filterBuff[0][z1][in][LEFTCHANNEL]; 4687 m_filterBuff[0][z1][in] [LEFTCHANNEL] = inSample[LEFTCHANNEL]; 4688 m_filterBuff[0][z2][out][LEFTCHANNEL] = m_filterBuff[0][z1][out][LEFTCHANNEL]; 4689 m_filterBuff[0][z1][out][LEFTCHANNEL] = outSample[LEFTCHANNEL]; 4690 iir_out[LEFTCHANNEL] = (int16_t)outSample[LEFTCHANNEL]; 4691 4692 4693 outSample[RIGHTCHANNEL] = m_filter[0].a0 * inSample[RIGHTCHANNEL] 4694 + m_filter[0].a1 * m_filterBuff[0][z1][in] [RIGHTCHANNEL] 4695 + m_filter[0].a2 * m_filterBuff[0][z2][in] [RIGHTCHANNEL] 4696 - m_filter[0].b1 * m_filterBuff[0][z1][out][RIGHTCHANNEL] 4697 - m_filter[0].b2 * m_filterBuff[0][z2][out][RIGHTCHANNEL]; 4698 4699 m_filterBuff[0][z2][in] [RIGHTCHANNEL] = m_filterBuff[0][z1][in][RIGHTCHANNEL]; 4700 m_filterBuff[0][z1][in] [RIGHTCHANNEL] = inSample[RIGHTCHANNEL]; 4701 m_filterBuff[0][z2][out][RIGHTCHANNEL] = m_filterBuff[0][z1][out][RIGHTCHANNEL]; 4702 m_filterBuff[0][z1][out][RIGHTCHANNEL] = outSample[RIGHTCHANNEL]; 4703 iir_out[RIGHTCHANNEL] = (int16_t) outSample[RIGHTCHANNEL]; 4704 4705 return iir_out; 4706 } 4707 //--------------------------------------------------------------------------------------------------------------------- 4708 int16_t* Audio::IIR_filterChain1(int16_t iir_in[2], bool clear){ // Infinite Impulse Response (IIR) filters 4709 4710 uint8_t z1 = 0, z2 = 1; 4711 enum: uint8_t {in = 0, out = 1}; 4712 float inSample[2]; 4713 float outSample[2]; 4714 static int16_t iir_out[2]; 4715 4716 if(clear){ 4717 memset(m_filterBuff, 0, sizeof(m_filterBuff)); // zero IIR filterbuffer 4718 iir_out[0] = 0; 4719 iir_out[1] = 0; 4720 iir_in[0] = 0; 4721 iir_in[1] = 0; 4722 } 4723 4724 inSample[LEFTCHANNEL] = (float)(iir_in[LEFTCHANNEL]); 4725 inSample[RIGHTCHANNEL] = (float)(iir_in[RIGHTCHANNEL]); 4726 4727 outSample[LEFTCHANNEL] = m_filter[1].a0 * inSample[LEFTCHANNEL] 4728 + m_filter[1].a1 * m_filterBuff[1][z1][in] [LEFTCHANNEL] 4729 + m_filter[1].a2 * m_filterBuff[1][z2][in] [LEFTCHANNEL] 4730 - m_filter[1].b1 * m_filterBuff[1][z1][out][LEFTCHANNEL] 4731 - m_filter[1].b2 * m_filterBuff[1][z2][out][LEFTCHANNEL]; 4732 4733 m_filterBuff[1][z2][in] [LEFTCHANNEL] = m_filterBuff[1][z1][in][LEFTCHANNEL]; 4734 m_filterBuff[1][z1][in] [LEFTCHANNEL] = inSample[LEFTCHANNEL]; 4735 m_filterBuff[1][z2][out][LEFTCHANNEL] = m_filterBuff[1][z1][out][LEFTCHANNEL]; 4736 m_filterBuff[1][z1][out][LEFTCHANNEL] = outSample[LEFTCHANNEL]; 4737 iir_out[LEFTCHANNEL] = (int16_t)outSample[LEFTCHANNEL]; 4738 4739 4740 outSample[RIGHTCHANNEL] = m_filter[1].a0 * inSample[RIGHTCHANNEL] 4741 + m_filter[1].a1 * m_filterBuff[1][z1][in] [RIGHTCHANNEL] 4742 + m_filter[1].a2 * m_filterBuff[1][z2][in] [RIGHTCHANNEL] 4743 - m_filter[1].b1 * m_filterBuff[1][z1][out][RIGHTCHANNEL] 4744 - m_filter[1].b2 * m_filterBuff[1][z2][out][RIGHTCHANNEL]; 4745 4746 m_filterBuff[1][z2][in] [RIGHTCHANNEL] = m_filterBuff[1][z1][in][RIGHTCHANNEL]; 4747 m_filterBuff[1][z1][in] [RIGHTCHANNEL] = inSample[RIGHTCHANNEL]; 4748 m_filterBuff[1][z2][out][RIGHTCHANNEL] = m_filterBuff[1][z1][out][RIGHTCHANNEL]; 4749 m_filterBuff[1][z1][out][RIGHTCHANNEL] = outSample[RIGHTCHANNEL]; 4750 iir_out[RIGHTCHANNEL] = (int16_t) outSample[RIGHTCHANNEL]; 4751 4752 return iir_out; 4753 } 4754 //--------------------------------------------------------------------------------------------------------------------- 4755 int16_t* Audio::IIR_filterChain2(int16_t iir_in[2], bool clear){ // Infinite Impulse Response (IIR) filters 4756 4757 uint8_t z1 = 0, z2 = 1; 4758 enum: uint8_t {in = 0, out = 1}; 4759 float inSample[2]; 4760 float outSample[2]; 4761 static int16_t iir_out[2]; 4762 4763 if(clear){ 4764 memset(m_filterBuff, 0, sizeof(m_filterBuff)); // zero IIR filterbuffer 4765 iir_out[0] = 0; 4766 iir_out[1] = 0; 4767 iir_in[0] = 0; 4768 iir_in[1] = 0; 4769 } 4770 4771 inSample[LEFTCHANNEL] = (float)(iir_in[LEFTCHANNEL]); 4772 inSample[RIGHTCHANNEL] = (float)(iir_in[RIGHTCHANNEL]); 4773 4774 outSample[LEFTCHANNEL] = m_filter[2].a0 * inSample[LEFTCHANNEL] 4775 + m_filter[2].a1 * m_filterBuff[2][z1][in] [LEFTCHANNEL] 4776 + m_filter[2].a2 * m_filterBuff[2][z2][in] [LEFTCHANNEL] 4777 - m_filter[2].b1 * m_filterBuff[2][z1][out][LEFTCHANNEL] 4778 - m_filter[2].b2 * m_filterBuff[2][z2][out][LEFTCHANNEL]; 4779 4780 m_filterBuff[2][z2][in] [LEFTCHANNEL] = m_filterBuff[2][z1][in][LEFTCHANNEL]; 4781 m_filterBuff[2][z1][in] [LEFTCHANNEL] = inSample[LEFTCHANNEL]; 4782 m_filterBuff[2][z2][out][LEFTCHANNEL] = m_filterBuff[2][z1][out][LEFTCHANNEL]; 4783 m_filterBuff[2][z1][out][LEFTCHANNEL] = outSample[LEFTCHANNEL]; 4784 iir_out[LEFTCHANNEL] = (int16_t)outSample[LEFTCHANNEL]; 4785 4786 4787 outSample[RIGHTCHANNEL] = m_filter[2].a0 * inSample[RIGHTCHANNEL] 4788 + m_filter[2].a1 * m_filterBuff[2][z1][in] [RIGHTCHANNEL] 4789 + m_filter[2].a2 * m_filterBuff[2][z2][in] [RIGHTCHANNEL] 4790 - m_filter[2].b1 * m_filterBuff[2][z1][out][RIGHTCHANNEL] 4791 - m_filter[2].b2 * m_filterBuff[2][z2][out][RIGHTCHANNEL]; 4792 4793 m_filterBuff[2][z2][in] [RIGHTCHANNEL] = m_filterBuff[2][z1][in][RIGHTCHANNEL]; 4794 m_filterBuff[2][z1][in] [RIGHTCHANNEL] = inSample[RIGHTCHANNEL]; 4795 m_filterBuff[2][z2][out][RIGHTCHANNEL] = m_filterBuff[2][z1][out][RIGHTCHANNEL]; 4796 m_filterBuff[2][z1][out][RIGHTCHANNEL] = outSample[RIGHTCHANNEL]; 4797 iir_out[RIGHTCHANNEL] = (int16_t) outSample[RIGHTCHANNEL]; 4798 4799 return iir_out; 4800 } 4801 //---------------------------------------------------------------------------------------------------------------------- 4802 // AAC - T R A N S P O R T S T R E A M 4803 //---------------------------------------------------------------------------------------------------------------------- 4804 bool Audio::ts_parsePacket(uint8_t* packet, uint8_t* packetStart, uint8_t* packetLength) { 4805 4806 const uint8_t TS_PACKET_SIZE = 188; 4807 const uint8_t PAYLOAD_SIZE = 184; 4808 const uint8_t PID_ARRAY_LEN = 4; 4809 4810 (void) PAYLOAD_SIZE; // suppress [-Wunused-variable] 4811 4812 typedef struct{ 4813 int number= 0; 4814 int pids[PID_ARRAY_LEN]; 4815 } pid_array; 4816 4817 static pid_array pidsOfPMT; 4818 static int PES_DataLength = 0; 4819 static int pidOfAAC = 0; 4820 4821 if(packet == NULL){ 4822 if(m_f_Log) log_i("parseTS reset"); 4823 for(int i = 0; i < PID_ARRAY_LEN; i++) pidsOfPMT.pids[i] = 0; 4824 PES_DataLength = 0; 4825 pidOfAAC = 0; 4826 return true; 4827 } 4828 4829 // -------------------------------------------------------------------------------------------------------- 4830 // 0. Byte SyncByte | 0 | 1 | 0 | 0 | 0 | 1 | 1 | 1 | always bit pattern of 0x47 4831 //--------------------------------------------------------------------------------------------------------- 4832 // 1. Byte |PUSI|TP| |PID|PID|PID|PID|PID| 4833 //--------------------------------------------------------------------------------------------------------- 4834 // 2. Byte |PID|PID|PID|PID|PID|PID|PID|PID| 4835 //--------------------------------------------------------------------------------------------------------- 4836 // 3. Byte |TSC|TSC|AFC|AFC|CC |CC |CC |CC | 4837 //--------------------------------------------------------------------------------------------------------- 4838 // 4.-187. Byte |Payload data if AFC==01 or 11 | 4839 //--------------------------------------------------------------------------------------------------------- 4840 4841 // PUSI Payload unit start indicator, set when this packet contains the first byte of a new payload unit. 4842 // The first byte of the payload will indicate where this new payload unit starts. 4843 // TP Transport priority, set when the current packet has a higher priority than other packets with the same PID. 4844 // PID Packet Identifier, describing the payload data. 4845 // TSC Transport scrambling control, '00' = Not scrambled. 4846 // AFC Adaptation field control, 01 – no adaptation field, payload only, 10 – adaptation field only, no payload, 4847 // 11 – adaptation field followed by payload, 00 – RESERVED for future use 4848 // CC Continuity counter, Sequence number of payload packets (0x00 to 0x0F) within each stream (except PID 8191) 4849 4850 if(packet[0] != 0x47) { 4851 log_e("ts SyncByte not found, first bytes are %X %X %X %X", packet[0], packet[1], packet[2], packet[3]); 4852 stopSong(); 4853 return false; 4854 } 4855 int PID = (packet[1] & 0x1F) << 8 | (packet[2] & 0xFF); 4856 if(m_f_Log) log_i("PID: 0x%04X(%d)", PID, PID); 4857 int PUSI = (packet[1] & 0x40) >> 6; 4858 if(m_f_Log) log_i("Payload Unit Start Indicator: %d", PUSI); 4859 int AFC = (packet[3] & 0x30) >> 4; 4860 if(m_f_Log) log_i("Adaption Field Control: %d", AFC); 4861 4862 int AFL = -1; 4863 if((AFC & 0b10) == 0b10) { // AFC '11' Adaptation Field followed 4864 AFL = packet[4] & 0xFF; // Adaptation Field Length 4865 if(m_f_Log) log_i("Adaptation Field Length: %d", AFL); 4866 } 4867 int PLS = PUSI ? 5 : 4; // PayLoadStart, Payload Unit Start Indicator 4868 4869 if(PID == 0) { 4870 // Program Association Table (PAT) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 4871 if(m_f_Log) log_i("PAT"); 4872 pidsOfPMT.number = 0; 4873 pidOfAAC = 0; 4874 int startOfProgramNums = 8; 4875 int lengthOfPATValue = 4; 4876 int sectionLength = ((packet[PLS + 1] & 0x0F) << 8) | (packet[PLS + 2] & 0xFF); 4877 if(m_f_Log) log_i("Section Length: %d", sectionLength); 4878 int program_number, program_map_PID; 4879 int indexOfPids = 0; 4880 (void) program_number; // [-Wunused-but-set-variable] 4881 for(int i = startOfProgramNums; i <= sectionLength; i += lengthOfPATValue) { 4882 program_number = ((packet[PLS + i] & 0xFF) << 8) | (packet[PLS + i + 1] & 0xFF); 4883 program_map_PID = ((packet[PLS + i + 2] & 0x1F) << 8) | (packet[PLS + i + 3] & 0xFF); 4884 if(m_f_Log) log_i("Program Num: 0x%04X(%d) PMT PID: 0x%04X(%d)", program_number, program_number, 4885 program_map_PID, program_map_PID); 4886 pidsOfPMT.pids[indexOfPids++] = program_map_PID; 4887 } 4888 pidsOfPMT.number = indexOfPids; 4889 *packetStart = 0; 4890 *packetLength = 0; 4891 return true; 4892 4893 } 4894 else if(PID == pidOfAAC) { 4895 static uint8_t fillData = 0; 4896 if(m_f_Log) log_i("AAC"); 4897 uint8_t posOfPacketStart = 4; 4898 if(AFL >= 0) {posOfPacketStart = 5 + AFL; 4899 if(m_f_Log) log_i("posOfPacketStart: %d", posOfPacketStart);} 4900 // Packetized Elementary Stream (PES) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 4901 if(m_f_Log) log_i("PES_DataLength %i", PES_DataLength); 4902 if (PES_DataLength > 0) { 4903 *packetStart = posOfPacketStart + fillData; 4904 *packetLength = TS_PACKET_SIZE - posOfPacketStart - fillData; 4905 fillData = 0; 4906 PES_DataLength -= (*packetLength); 4907 return true; 4908 } 4909 else{ 4910 int firstByte = packet[posOfPacketStart] & 0xFF; 4911 int secondByte = packet[posOfPacketStart + 1] & 0xFF; 4912 int thirdByte = packet[posOfPacketStart + 2] & 0xFF; 4913 if(m_f_Log) log_i("First 3 bytes: %02X %02X %02X", firstByte, secondByte, thirdByte); 4914 if(firstByte == 0x00 && secondByte == 0x00 && thirdByte == 0x01) { // Packet start code prefix 4915 // PES 4916 uint8_t StreamID = packet[posOfPacketStart + 3] & 0xFF; 4917 if(StreamID >= 0xC0 && StreamID <= 0xDF) {;} // okay ist audio stream 4918 if(StreamID >= 0xE0 && StreamID <= 0xEF) {log_e("video stream!"); return false;} 4919 uint8_t PES_HeaderDataLength = packet[posOfPacketStart + 8] & 0xFF; 4920 if(m_f_Log) log_i("PES_headerDataLength %d", PES_HeaderDataLength); 4921 int PES_PacketLength = 4922 ((packet[posOfPacketStart + 4] & 0xFF) << 8) + (packet[posOfPacketStart + 5] & 0xFF); 4923 if(m_f_Log) log_i("PES Packet length: %d", PES_PacketLength); 4924 PES_DataLength = PES_PacketLength; 4925 int startOfData = PES_HeaderDataLength + 9; 4926 if(posOfPacketStart + startOfData >= 188){ // only fillers in packet 4927 if(m_f_Log) log_e("posOfPacketStart + startOfData %i", posOfPacketStart + startOfData); 4928 *packetStart = 0; 4929 *packetLength = 0; 4930 PES_DataLength -= (PES_HeaderDataLength + 3); 4931 fillData = (posOfPacketStart + startOfData) - 188; 4932 if(m_f_Log) log_i("fillData %i", fillData); 4933 return true; 4934 } 4935 if(m_f_Log) log_i("First AAC data byte: %02X", packet[posOfPacketStart + startOfData]); 4936 if(m_f_Log) log_i("Second AAC data byte: %02X", packet[posOfPacketStart + startOfData + 1]); 4937 *packetStart = posOfPacketStart + startOfData; 4938 *packetLength = TS_PACKET_SIZE - posOfPacketStart - startOfData; 4939 PES_DataLength -= (*packetLength); 4940 PES_DataLength -= (PES_HeaderDataLength + 3); 4941 return true; 4942 } 4943 } 4944 *packetStart = 0; 4945 *packetLength = 0; 4946 log_e("PES not found"); 4947 return false; 4948 } 4949 else if(pidsOfPMT.number) { 4950 // Program Map Table (PMT) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 4951 for(int i = 0; i < pidsOfPMT.number; i++) { 4952 if(PID == pidsOfPMT.pids[i]) { 4953 if(m_f_Log) log_i("PMT"); 4954 int staticLengthOfPMT = 12; 4955 int sectionLength = ((packet[PLS + 1] & 0x0F) << 8) | (packet[PLS + 2] & 0xFF); 4956 if(m_f_Log) log_i("Section Length: %d", sectionLength); 4957 int programInfoLength = ((packet[PLS + 10] & 0x0F) << 8) | (packet[PLS + 11] & 0xFF); 4958 if(m_f_Log) log_i("Program Info Length: %d", programInfoLength); 4959 int cursor = staticLengthOfPMT + programInfoLength; 4960 while(cursor < sectionLength - 1) { 4961 int streamType = packet[PLS + cursor] & 0xFF; 4962 int elementaryPID = ((packet[PLS + cursor + 1] & 0x1F) << 8) | (packet[PLS + cursor + 2] & 0xFF); 4963 if(m_f_Log) log_i("Stream Type: 0x%02X Elementary PID: 0x%04X", streamType, elementaryPID); 4964 4965 if(streamType == 0x0F || streamType == 0x11) { 4966 if(m_f_Log) log_i("AAC PID discover"); 4967 pidOfAAC= elementaryPID; 4968 } 4969 int esInfoLength = ((packet[PLS + cursor + 3] & 0x0F) << 8) | (packet[PLS + cursor + 4] & 0xFF); 4970 if(m_f_Log) log_i("ES Info Length: 0x%04X", esInfoLength); 4971 cursor += 5 + esInfoLength; 4972 } 4973 } 4974 } 4975 *packetStart = 0; 4976 *packetLength = 0; 4977 return true; 4978 } 4979 // PES received before PAT and PMT seen 4980 *packetStart = 0; 4981 *packetLength = 0; 4982 return false; 4983 } 4984 //---------------------------------------------------------------------------------------------------------------------- 4985 // W E B S T R E A M - H E L P F U N C T I O N S 4986 //---------------------------------------------------------------------------------------------------------------------- 4987 uint16_t Audio::readMetadata(uint16_t maxBytes, bool first) { 4988 4989 static uint16_t pos_ml = 0; // determines the current position in metaline 4990 static uint16_t metalen = 0; 4991 uint16_t res = 0; 4992 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 4993 if(first){ 4994 pos_ml = 0; 4995 metalen = 0; 4996 return 0; 4997 } 4998 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 4999 if(!maxBytes) return 0; // guard 5000 5001 if(!metalen) { 5002 int b = _client->read(); // First byte of metadata? 5003 metalen = b * 16 ; // New count for metadata including length byte, max 4096 5004 pos_ml = 0; m_chbuf[pos_ml] = 0; // Prepare for new line 5005 res = 1; 5006 } 5007 if(!metalen) {m_metacount = m_metaint; return res;} // metalen is 0 5008 if(metalen < m_chbufSize){ 5009 uint16_t a = _client->readBytes(&m_chbuf[pos_ml], min((uint16_t)(metalen - pos_ml), (uint16_t)(maxBytes -1))); 5010 res += a; 5011 pos_ml += a; 5012 } 5013 else{ // metadata doesn't fit in m_chbuf 5014 uint8_t c = 0; 5015 int8_t i = 0; 5016 while(pos_ml != metalen){ 5017 i = _client->read(&c, 1); // fake read 5018 if(i != -1) {pos_ml++; res++;} 5019 else {return res;} 5020 } 5021 m_metacount = m_metaint; 5022 metalen = 0; 5023 pos_ml = 0; 5024 return res; 5025 } 5026 if(pos_ml == metalen) { 5027 m_chbuf[pos_ml] = '\0'; 5028 if(strlen(m_chbuf)) { // Any info present? 5029 // metaline contains artist and song name. For example: 5030 // "StreamTitle='Don McLean - American Pie';StreamUrl='';" 5031 // Sometimes it is just other info like: 5032 // "StreamTitle='60s 03 05 Magic60s';StreamUrl='';" 5033 // Isolate the StreamTitle, remove leading and trailing quotes if present. 5034 latinToUTF8(m_chbuf, m_chbufSize); // convert to UTF-8 if necessary 5035 int pos = indexOf(m_chbuf, "song_spot", 0); // remove some irrelevant infos 5036 if(pos > 3) { // e.g. song_spot="T" MediaBaseId="0" itunesTrackId="0" 5037 m_chbuf[pos] = 0; 5038 } 5039 showstreamtitle(m_chbuf); // Show artist and title if present in metadata 5040 } 5041 m_metacount = m_metaint; 5042 metalen = 0; 5043 pos_ml = 0; 5044 } 5045 return res; 5046 } 5047 //---------------------------------------------------------------------------------------------------------------------- 5048 size_t Audio::chunkedDataTransfer(uint8_t* bytes){ 5049 uint8_t byteCounter = 0; 5050 size_t chunksize = 0; 5051 int b = 0; 5052 uint32_t ctime = millis(); 5053 uint32_t timeout = 2000; // ms 5054 while(true){ 5055 if(ctime + timeout < millis()) { 5056 log_e("timeout"); 5057 stopSong(); 5058 return 0; 5059 } 5060 b = _client->read(); 5061 byteCounter++; 5062 if(b < 0) continue; // -1 no data available 5063 if(b == '\n') break; 5064 if(b < '0') continue; 5065 // We have received a hexadecimal character. Decode it and add to the result. 5066 b = toupper(b) - '0'; // Be sure we have uppercase 5067 if(b > 9) b = b - 7; // Translate A..F to 10..15 5068 chunksize = (chunksize << 4) + b; 5069 } 5070 if(m_f_Log) log_i("chunksize %d", chunksize); 5071 *bytes = byteCounter; 5072 return chunksize; 5073 } 5074 //---------------------------------------------------------------------------------------------------------------------- 5075 bool Audio::readID3V1Tag(){ 5076 // this is an V1.x id3tag after an audio block, ID3 v1 tags are ASCII 5077 // Version 1.x is a fixed size at the end of the file (128 bytes) after a <TAG> keyword. 5078 if(m_codec != CODEC_MP3) return false; 5079 if(InBuff.bufferFilled() == 128 && startsWith((const char*)InBuff.getReadPtr(), "TAG")){ // maybe a V1.x TAG 5080 char title[31]; 5081 memcpy(title, InBuff.getReadPtr() + 3 + 0, 30); title[30] = '\0'; latinToUTF8(title, sizeof(title)); 5082 char artist[31]; 5083 memcpy(artist, InBuff.getReadPtr() + 3 + 30, 30); artist[30] = '\0'; latinToUTF8(artist, sizeof(artist)); 5084 char album[31]; 5085 memcpy(album, InBuff.getReadPtr() + 3 + 60, 30); album[30] = '\0'; latinToUTF8(album, sizeof(album)); 5086 char year[5]; 5087 memcpy(year, InBuff.getReadPtr() + 3 + 90, 4); year[4] = '\0'; latinToUTF8(year, sizeof(year)); 5088 char comment[31]; 5089 memcpy(comment, InBuff.getReadPtr() + 3 + 94, 30); comment[30] = '\0'; latinToUTF8(comment, sizeof(comment)); 5090 uint8_t zeroByte = *(InBuff.getReadPtr() + 125); 5091 uint8_t track = *(InBuff.getReadPtr() + 126); 5092 uint8_t genre = *(InBuff.getReadPtr() + 127); 5093 if(zeroByte) {AUDIO_INFO("ID3 version: 1");} //[2] 5094 else {AUDIO_INFO("ID3 Version 1.1");} 5095 if(strlen(title)) {sprintf(m_chbuf, "Title: %s", title); if(audio_id3data) audio_id3data(m_chbuf);} 5096 if(strlen(artist)) {sprintf(m_chbuf, "Artist: %s", artist); if(audio_id3data) audio_id3data(m_chbuf);} 5097 if(strlen(album)) {sprintf(m_chbuf, "Album: %s", album); if(audio_id3data) audio_id3data(m_chbuf);} 5098 if(strlen(year)) {sprintf(m_chbuf, "Year: %s", year); if(audio_id3data) audio_id3data(m_chbuf);} 5099 if(strlen(comment)){sprintf(m_chbuf, "Comment: %s", comment); if(audio_id3data) audio_id3data(m_chbuf);} 5100 if(zeroByte == 0) {sprintf(m_chbuf, "Track Number: %d", track); if(audio_id3data) audio_id3data(m_chbuf);} 5101 if(genre < 192) {sprintf(m_chbuf, "Genre: %d", genre); if(audio_id3data) audio_id3data(m_chbuf);} //[1] 5102 return true; 5103 } 5104 if(InBuff.bufferFilled() == 227 && startsWith((const char*)InBuff.getReadPtr(), "TAG+")){ // ID3V1EnhancedTAG 5105 AUDIO_INFO("ID3 version: 1 - Enhanced TAG"); 5106 char title[61]; 5107 memcpy(title, InBuff.getReadPtr() + 4 + 0, 60); title[60] = '\0'; latinToUTF8(title, sizeof(title)); 5108 char artist[61]; 5109 memcpy(artist, InBuff.getReadPtr() + 4 + 60, 60); artist[60] = '\0'; latinToUTF8(artist, sizeof(artist)); 5110 char album[61]; 5111 memcpy(album, InBuff.getReadPtr() + 4 + 120, 60); album[60] = '\0'; latinToUTF8(album, sizeof(album)); 5112 // one byte "speed" 0=unset, 1=slow, 2= medium, 3=fast, 4=hardcore 5113 char genre[31]; 5114 memcpy(genre, InBuff.getReadPtr() + 5 + 180, 30); genre[30] = '\0'; latinToUTF8(genre, sizeof(genre)); 5115 // six bytes "start-time", the start of the music as mmm:ss 5116 // six bytes "end-time", the end of the music as mmm:ss 5117 if(strlen(title)) {sprintf(m_chbuf, "Title: %s", title); if(audio_id3data) audio_id3data(m_chbuf);} 5118 if(strlen(artist)) {sprintf(m_chbuf, "Artist: %s", artist); if(audio_id3data) audio_id3data(m_chbuf);} 5119 if(strlen(album)) {sprintf(m_chbuf, "Album: %s", album); if(audio_id3data) audio_id3data(m_chbuf);} 5120 if(strlen(genre)) {sprintf(m_chbuf, "Genre: %s", genre); if(audio_id3data) audio_id3data(m_chbuf);} 5121 return true; 5122 } 5123 return false; 5124 // [1] https://en.wikipedia.org/wiki/List_of_ID3v1_Genres 5125 // [2] https://en.wikipedia.org/wiki/ID3#ID3v1_and_ID3v1.1[5] 5126 } 5127 //---------------------------------------------------------------------------------------------------------------------- 5128 void Audio::slowStreamDetection(uint32_t inBuffFilled, uint32_t maxFrameSize){ 5129 static uint32_t tmr_1s = millis(); // timer 1 sec 5130 static bool f_tmr_1s = false; 5131 static uint8_t cnt_slow = 0; 5132 if(tmr_1s + 1000 < millis()) {f_tmr_1s = true; tmr_1s = millis();} 5133 if(m_codec == CODEC_WAV) maxFrameSize /= 4; 5134 if(m_codec == CODEC_FLAC) maxFrameSize /= 2; 5135 if(inBuffFilled < maxFrameSize){ 5136 cnt_slow ++; 5137 if(f_tmr_1s) { 5138 if(cnt_slow > 50) AUDIO_INFO("slow stream, dropouts are possible"); 5139 f_tmr_1s = false; 5140 cnt_slow = 0; 5141 } 5142 } 5143 else cnt_slow = 0; 5144 } 5145 //---------------------------------------------------------------------------------------------------------------------- 5146 void Audio::lostStreamDetection(uint32_t bytesAvail){ 5147 static uint32_t loopCnt = 0; 5148 if(!bytesAvail){ 5149 loopCnt++; 5150 if(loopCnt > 200000) { // wait several seconds 5151 loopCnt = 0; 5152 AUDIO_INFO("Stream lost -> try new connection"); 5153 connecttohost(m_lastHost); 5154 return; 5155 } 5156 } 5157 else loopCnt = 0; 5158 } 5159 //---------------------------------------------------------------------------------------------------------------------- 5160 #ifndef AUDIO_NO_SD_FS 5161 void Audio::seek_m4a_stsz(){ 5162 // stsz says what size each sample is in bytes. This is important for the decoder to be able to start at a chunk, 5163 // and then go through each sample by its size. The stsz atom can be behind the audio block. Therefore, searching 5164 // for the stsz atom is only applicable to local files. 5165 5166 /* atom hierarchy (example)_________________________________________________________________________________________ 5167 5168 ftyp -> moov -> trak -> tkhd 5169 free udta mdia -> mdhd 5170 mdat udta hdlr 5171 mvhd minf -> smhd 5172 dinf 5173 stbl -> stsd 5174 stts 5175 stsc 5176 stsz -> determine and return the position and number of entries 5177 stco 5178 __________________________________________________________________________________________________________________*/ 5179 5180 struct m4a_Atom{ 5181 int pos; 5182 int size; 5183 char name[5]; 5184 } atom, at, tmp; 5185 5186 // c99 has no inner functions, lambdas are only allowed from c11, please don't use ancient compiler 5187 auto atomItems = [&](uint32_t startPos){ // lambda, inner function 5188 char tmp[5]; 5189 audiofile.seek(startPos); 5190 audiofile.readBytes(tmp, 4); 5191 atom.size = bigEndian((uint8_t*)tmp, 4); 5192 audiofile.readBytes(atom.name, 4); 5193 atom.name[4] = '\0'; 5194 atom.pos = startPos; 5195 return atom; 5196 }; 5197 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 5198 5199 boolean found = false; 5200 uint32_t seekpos = 0; 5201 uint32_t filesize = getFileSize(); 5202 char name[6][5] = {"moov", "trak", "mdia", "minf", "stbl", "stsz"}; 5203 char noe[4]; 5204 5205 if(!audiofile) return; // guard 5206 5207 at.pos = 0; 5208 at.size = filesize; 5209 seekpos = 0; 5210 5211 for(int i = 0; i< 6; i++){ 5212 found = false; 5213 while(seekpos < at.pos + at.size){ 5214 tmp = atomItems(seekpos); 5215 seekpos += tmp.size; 5216 if(strcmp(tmp.name, name[i]) == 0) {memcpy((void*)&at, (void*)&tmp, sizeof(tmp)); found = true;} 5217 if(m_f_Log) log_i("name %s pos %d, size %d", tmp.name, tmp.pos, tmp.size); 5218 } 5219 if(!found) goto noSuccess; 5220 seekpos = at.pos + 8; // 4 bytes size + 4 bytes name 5221 } 5222 5223 seekpos += 8; // 1 byte version + 3 bytes flags + 4 bytes sample size 5224 audiofile.seek(seekpos); 5225 audiofile.readBytes(noe, 4); //number of entries 5226 m_stsz_numEntries = bigEndian((uint8_t*)noe, 4); 5227 if(m_f_Log) log_i("number of entries in stsz: %d", m_stsz_numEntries); 5228 m_stsz_position = seekpos + 4; 5229 audiofile.seek(0); 5230 return; 5231 5232 noSuccess: 5233 m_stsz_numEntries= 0; 5234 m_stsz_position = 0; 5235 log_e("m4a atom stsz not found"); 5236 audiofile.seek(0); 5237 return; 5238 } 5239 //---------------------------------------------------------------------------------------------------------------------- 5240 uint32_t Audio::m4a_correctResumeFilePos(uint32_t resumeFilePos){ 5241 // In order to jump within an m4a file, the exact beginning of an aac block must be found. Since m4a cannot be 5242 // streamed, i.e. there is no syncword, an imprecise jump can lead to a crash. 5243 5244 if(!m_stsz_position) return m_audioDataStart; // guard 5245 5246 typedef union{ 5247 uint8_t u8[4]; 5248 uint32_t u32; 5249 } tu; 5250 tu uu; 5251 5252 uint32_t i = 0, pos = m_audioDataStart; 5253 audiofile.seek(m_stsz_position); 5254 5255 while(i < m_stsz_numEntries){ 5256 i++; 5257 uu.u8[3] = audiofile.read(); 5258 uu.u8[2] = audiofile.read(); 5259 uu.u8[1] = audiofile.read(); 5260 uu.u8[0] = audiofile.read(); 5261 pos += uu.u32; 5262 if(pos >= resumeFilePos) break; 5263 } 5264 return pos; 5265 } 5266 //---------------------------------------------------------------------------------------------------------------------- 5267 uint32_t Audio::flac_correctResumeFilePos(uint32_t resumeFilePos){ 5268 // The starting point is the next FLAC syncword 5269 uint8_t p1, p2; 5270 boolean found = false; 5271 uint32_t pos = resumeFilePos; 5272 audiofile.seek(pos); 5273 5274 p1 = audiofile.read(); 5275 p2 = audiofile.read(); 5276 pos+=2; 5277 while(!found || pos == m_file_size){ 5278 if(p1 == 0xFF && p2 == 0xF8){found = true; log_i("found"); break;} 5279 p1 = p2; 5280 p2 = audiofile.read(); 5281 pos++; 5282 } 5283 5284 if(found) return (pos - 2); 5285 return m_audioDataStart; 5286 } 5287 //---------------------------------------------------------------------------------------------------------------------- 5288 uint32_t Audio::mp3_correctResumeFilePos(uint32_t resumeFilePos){ 5289 // The starting point is the next MP3 syncword 5290 uint8_t p1, p2; 5291 boolean found = false; 5292 uint32_t pos = resumeFilePos; 5293 audiofile.seek(pos); 5294 5295 p1 = audiofile.read(); 5296 p2 = audiofile.read(); 5297 pos+=2; 5298 while(!found || pos == m_file_size){ 5299 if(p1 == 0xFF && (p2 & 0xF0) == 0xF0){found = true; break;} 5300 p1 = p2; 5301 p2 = audiofile.read(); 5302 pos++; 5303 } 5304 5305 if(found) return (pos - 2); 5306 return m_audioDataStart; 5307 } 5308 //---------------------------------------------------------------------------------------------------------------------- 5309 #endif // AUDIO_NO_SD_FS