|
3 | 3 | audio.cpp |
4 | 4 |
|
5 | 5 | Created on: Oct 28.2018 */char audioI2SVers[] ="\ |
6 | | - Version 3.4.0h "; |
7 | | -/* Updated on: Jul 26.2025 |
| 6 | + Version 3.4.0i "; |
| 7 | +/* Updated on: Jul 28.2025 |
8 | 8 |
|
9 | 9 | Author: Wolle (schreibfaul1) |
10 | 10 | Audio library for ESP32, ESP32-S3 or ESP32-P4 |
@@ -791,15 +791,15 @@ bool Audio::httpPrint(const char* host) { |
791 | 791 | rqh.append("\r\n"); |
792 | 792 | rqh.append("Icy-MetaData:1\r\n"); |
793 | 793 | rqh.append("Icy-MetaData:2\r\n"); |
794 | | - rqh.append("Accept: */*\r\n"); |
| 794 | + rqh.append("Accept:*/*\r\n"); |
795 | 795 | rqh.append("User-Agent: VLC/3.0.21 LibVLC/3.0.21 AppleWebKit/537.36 (KHTML, like Gecko)\r\n"); |
796 | 796 | rqh.append("Accept-Encoding: identity;q=1,*;q=0\r\n"); |
797 | 797 | rqh.append("Connection: keep-alive\r\n\r\n"); |
798 | 798 |
|
799 | 799 | AUDIO_INFO("next URL: \"%s\"", c_host.get()); |
800 | 800 |
|
801 | 801 | if(f_equal == false){ |
802 | | - _client->stop(); |
| 802 | + if(_client->connected()) _client->stop(); |
803 | 803 | } |
804 | 804 | if(!_client->connected() ) { |
805 | 805 | if(m_f_ssl) { _client = static_cast<WiFiClient*>(&clientsecure); if(m_f_ssl && port == 80) port = 443;} |
@@ -836,101 +836,79 @@ bool Audio::httpPrint(const char* host) { |
836 | 836 | return true; |
837 | 837 | } |
838 | 838 | //------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
839 | | -bool Audio::httpRange(const char* host, uint32_t range){ |
| 839 | +bool Audio::httpRange(uint32_t seek, uint32_t length){ |
840 | 840 |
|
841 | 841 | if(!m_f_running) return false; |
842 | | - if(host == NULL) { |
843 | | - AUDIO_INFO("Hostaddress is empty"); |
844 | | - stopSong(); |
845 | | - return false; |
846 | | - } |
847 | | - ps_ptr<char>c_host; |
848 | | - c_host.copy_from(host); |
849 | | - ps_ptr<char> h_host; // copy of host without http:// or https:// |
850 | | - |
851 | | - if(startsWith(host, "https")) m_f_ssl = true; |
852 | | - else m_f_ssl = false; |
853 | | - |
854 | | - if(m_f_ssl) h_host.assign(host + 8); |
855 | | - else h_host.assign(host + 7); |
856 | | - |
857 | | - int16_t pos_slash; // position of "/" in hostname |
858 | | - int16_t pos_colon; // position of ":" in hostname |
859 | | - int16_t pos_ampersand; // position of "&" in hostname |
860 | | - uint16_t port = 80; // port number |
861 | | - |
862 | | - // In the URL there may be an extension, like noisefm.ru:8000/play.m3u&t=.m3u |
863 | | - pos_slash = h_host.index_of( "/", 0); |
864 | | - pos_colon = h_host.index_of( ":", 0); |
865 | | - if(isalpha(h_host[pos_colon + 1])) pos_colon = -1; // no portnumber follows |
866 | | - pos_ampersand = h_host.index_of( "&", 0); |
867 | | - |
868 | | - ps_ptr<char> hostwoext; // "skonto.ls.lv:8002" in "skonto.ls.lv:8002/mp3" |
869 | | - ps_ptr<char> extension; // "/mp3" in "skonto.ls.lv:8002/mp3" |
870 | | - |
871 | | - if(pos_slash > 1) { |
872 | | - hostwoext.alloc(pos_slash + 1, "hostwoext"); |
873 | | - memcpy(hostwoext.get(), h_host.get(), pos_slash); |
874 | | - hostwoext[pos_slash] = '\0'; |
875 | | - extension = urlencode(h_host.get() + pos_slash, true); |
876 | | - } |
877 | | - else { // url has no extension |
878 | | - hostwoext.append(h_host.get()); |
879 | | - extension.append("/"); |
880 | | - } |
881 | | - |
882 | | - if((pos_colon >= 0) && ((pos_ampersand == -1) || (pos_ampersand > pos_colon))) { |
883 | | - port = atoi(h_host.get() + pos_colon + 1); // Get portnumber as integer |
884 | | - hostwoext[pos_colon] = '\0'; // Host without portnumber |
885 | | - } |
886 | | - |
887 | | - char rqh[strlen(h_host.get()) + strlen(host) + 300]; // http request header |
888 | | - rqh[0] = '\0'; |
889 | | - char ch_range[12]; |
890 | | - ltoa(range, ch_range, 10); |
891 | | - AUDIO_INFO("skip to position: %li", (long int)range); |
892 | | - strcat(rqh, "GET "); |
893 | | - strcat(rqh, extension.c_get()); |
894 | | - strcat(rqh, " HTTP/1.1\r\n"); |
895 | | - strcat(rqh, "Host: "); |
896 | | - strcat(rqh, hostwoext.c_get()); |
897 | | - strcat(rqh, "\r\n"); |
898 | | - strcat(rqh, "Icy-MetaData:1\r\n"); |
899 | | - strcat(rqh, "Icy-MetaData:2\r\n"); |
900 | | - strcat(rqh, "Range: bytes="); |
901 | | - strcat(rqh, (const char*)ch_range); |
902 | | - strcat(rqh, "-\r\n"); |
903 | | - strcat(rqh, "Referer: "); |
904 | | - strcat(rqh, host); |
905 | | - strcat(rqh, "\r\n"); |
906 | | - strcat(rqh, "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36\r\n"); |
907 | | - strcat(rqh, "Connection: keep-alive\r\n\r\n"); |
908 | 842 |
|
| 843 | + uint16_t port = 0; // port number |
| 844 | + ps_ptr<char> c_host; // copy of host |
| 845 | + ps_ptr<char> hwoe; // host without extension |
| 846 | + ps_ptr<char> extension; // extension |
| 847 | + ps_ptr<char> query_string; // parameter |
| 848 | + ps_ptr<char> path; // extension + '?' + parameter |
| 849 | + ps_ptr<char> rqh; // request header |
| 850 | + ps_ptr<char> cur_hwoe; // m_currenthost without extension |
| 851 | + ps_ptr<char> range; // e.g. "Range: bytes=124-" |
| 852 | + |
| 853 | + c_host.clone_from(m_currentHost); |
| 854 | + c_host.trim(); |
| 855 | + auto dismantledHost = dismantle_host(c_host.get()); |
| 856 | + |
| 857 | +// https://edge.live.mp3.mdn.newmedia.nacamar.net:8000/ps-charivariwb/livestream.mp3;?user=ps-charivariwb;&pwd=ps-charivariwb------- |
| 858 | +// | | | | | |
| 859 | +// | | | | | (query string) |
| 860 | +// ssl?| |<-----host without extension-------->|port|<----- --extension----------->|<-first parameter->|<-second parameter->....... |
| 861 | +// | |
| 862 | +// |<-----------------------------path-------------------------------------------> |
| 863 | + |
| 864 | + m_f_ssl = dismantledHost.ssl; |
| 865 | + port = dismantledHost.port; |
| 866 | + if(dismantledHost.hwoe.valid()) hwoe.clone_from(dismantledHost.hwoe); |
| 867 | + if(dismantledHost.extension.valid()) extension.clone_from(dismantledHost.extension); |
| 868 | + if(dismantledHost.query_string.valid()) query_string.clone_from(dismantledHost.query_string); |
| 869 | + |
| 870 | + if(extension.valid()) path.assign(extension.get()); |
| 871 | + if(query_string.valid()){path.append("?"); path.append(query_string.get());} |
| 872 | + if(!hwoe.valid()) hwoe.assign(""); |
| 873 | + if(!extension.valid()) extension.assign(""); |
| 874 | + if(!path.valid()) path.assign(""); |
| 875 | + |
| 876 | + path = urlencode(path.get(), true); |
| 877 | + |
| 878 | + if(!m_currentHost.valid()) m_currentHost.assign(""); |
| 879 | + auto dismantledLastHost = dismantle_host(m_currentHost.get()); |
| 880 | + cur_hwoe.clone_from(dismantledLastHost.hwoe); |
| 881 | + |
| 882 | + if(length == UINT32_MAX) range.assignf("Range: bytes=%li-\r\n",seek); |
| 883 | + else range.assignf("Range: bytes=%li-%li\r\n",seek, length); |
| 884 | + |
| 885 | + rqh.assignf("GET /%s HTTP/1.1\r\n", path.get()); |
| 886 | + rqh.appendf("Host: %s\r\n", hwoe.get()); |
| 887 | + rqh.append("Accept: */*\r\n"); |
| 888 | + rqh.append("Accept-Encoding: identity;q=1,*;q=0\r\n"); |
| 889 | + rqh.append("Cache-Control: no-cache\r\n"); |
| 890 | + rqh.append("Connection: keep-alive\r\n"); |
| 891 | + rqh.appendf(range.c_get()); |
| 892 | + rqh.appendf("Referer: %s\r\n", m_currentHost.c_get()); |
| 893 | + rqh.append("Sec-GPC: 1\r\n"); |
| 894 | + rqh.append("User-Agent: VLC/3.0.21 LibVLC/3.0.21 AppleWebKit/537.36 (KHTML, like Gecko)\r\n\r\n"); |
| 895 | + |
| 896 | + if(_client->connected()) {_client->stop();} |
909 | 897 | if(m_f_ssl) { _client = static_cast<WiFiClient*>(&clientsecure); if(m_f_ssl && port == 80) port = 443;} |
910 | 898 | else { _client = static_cast<WiFiClient*>(&client); } |
911 | | - // AUDIO_INFO("The host has disconnected, reconnecting"); |
912 | 899 |
|
913 | | - if(!_client->connect(hostwoext.get(), port)) { |
| 900 | + if(!_client->connect(hwoe.get(), port)) { |
914 | 901 | AUDIO_LOG_ERROR("connection lost %s", c_host.c_get()); |
915 | 902 | stopSong(); |
916 | 903 | return false; |
917 | 904 | } |
918 | | -; |
919 | | - _client->print(rqh); |
920 | 905 |
|
921 | | - if(extension.ends_with_icase(".mp3")) m_expectedCodec = CODEC_MP3; |
922 | | - if(extension.ends_with_icase(".aac")) m_expectedCodec = CODEC_AAC; |
923 | | - if(extension.ends_with_icase(".wav")) m_expectedCodec = CODEC_WAV; |
924 | | - if(extension.ends_with_icase(".m4a")) m_expectedCodec = CODEC_M4A; |
925 | | - if(extension.ends_with_icase(".flac")) m_expectedCodec = CODEC_FLAC; |
926 | | - if(extension.ends_with_icase(".asx")) m_expectedPlsFmt = FORMAT_ASX; |
927 | | - if(extension.ends_with_icase(".m3u")) m_expectedPlsFmt = FORMAT_M3U; |
928 | | - if(extension.contains(".m3u8")) m_expectedPlsFmt = FORMAT_M3U8; |
929 | | - if(extension.ends_with_icase(".pls")) m_expectedPlsFmt = FORMAT_PLS; |
| 906 | + // AUDIO_LOG_INFO("rqh \n%s", rqh.get()); |
930 | 907 |
|
931 | | - m_dataMode = HTTP_RANGE_HEADER; // Handle header |
| 908 | + _client->print(rqh.c_get()); |
| 909 | + |
| 910 | + m_dataMode = HTTP_RANGE_HEADER; |
932 | 911 | m_streamType = ST_WEBFILE; |
933 | | - m_f_chunked = false; |
934 | 912 | return true; |
935 | 913 | } |
936 | 914 | //------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
@@ -1914,93 +1892,8 @@ int Audio::read_ID3_Header(uint8_t* data, size_t len) { |
1914 | 1892 | return 0; |
1915 | 1893 | } |
1916 | 1894 |
|
1917 | | - if( // any lyrics embedded in file, passing it to external function |
1918 | | - startsWith(m_ID3Hdr.tag, "SYLT") || startsWith(m_ID3Hdr.tag, "USLT")) { |
1919 | | - if(m_dataMode == AUDIO_LOCALFILE || (m_streamType == ST_WEBFILE && m_f_acceptRanges)) { |
1920 | | - ps_ptr<char> tmp; |
1921 | | - ps_ptr<char> content_descriptor; |
1922 | | - ps_ptr<char> syltBuff; |
1923 | | - bool isBigEndian = true; |
1924 | | - size_t len = 0; |
1925 | | - int idx = 0; |
1926 | | - |
1927 | | - m_ID3Hdr.SYLT.seen = true; |
1928 | | - m_ID3Hdr.SYLT.pos = m_ID3Hdr.id3Size - m_ID3Hdr.remainingHeaderBytes; |
1929 | | - m_ID3Hdr.SYLT.size = m_ID3Hdr.framesize; |
1930 | | - |
1931 | | - syltBuff.alloc(m_ID3Hdr.SYLT.size, "syltBuff"); |
1932 | | - |
1933 | | - if(m_streamType == ST_WEBFILE && m_f_acceptRanges){ |
1934 | | - uint32_t pos = m_pwf.byteCounter; |
1935 | | - // log_w("m_audiofile.position() %i, m_ID3Hdr.SYLT.pos %i", pos, m_ID3Hdr.SYLT.pos); |
1936 | | - bool res; |
1937 | | - res = httpRange(m_currentHost.c_get(), m_ID3Hdr.SYLT.pos); |
1938 | | - if(!res) AUDIO_LOG_ERROR("http range request was not successful"); |
1939 | | - res = parseHttpRangeHeader(); |
1940 | | - if(!res) AUDIO_LOG_ERROR("http range response was not successful"); |
1941 | | - uint16_t bytesWritten = 0; |
1942 | | - while(bytesWritten < m_ID3Hdr.SYLT.size){ |
1943 | | - bytesWritten += _client->read((uint8_t*)syltBuff.get() + bytesWritten, m_ID3Hdr.SYLT.size); |
1944 | | - } |
1945 | | - res = httpRange(m_currentHost.c_get(), pos); |
1946 | | - if(!res) AUDIO_LOG_ERROR("http range request was not successful"); |
1947 | | - res = parseHttpRangeHeader(); |
1948 | | - if(!res) AUDIO_LOG_ERROR("http range response was not successful"); |
1949 | | - } |
1950 | | - if(m_dataMode == AUDIO_LOCALFILE){ |
1951 | | - uint32_t pos = m_audiofile.position(); |
1952 | | - // log_w("m_audiofile.position() %i, m_ID3Hdr.SYLT.pos %i", pos, m_ID3Hdr.SYLT.pos); |
1953 | | - m_audiofile.seek(m_ID3Hdr.SYLT.pos); |
1954 | | - uint16_t bytesWritten = 0; |
1955 | | - while(bytesWritten < m_ID3Hdr.SYLT.size){ |
1956 | | - bytesWritten += m_audiofile.read((uint8_t*)syltBuff.get() + bytesWritten, m_ID3Hdr.SYLT.size); |
1957 | | - } |
1958 | | - m_audiofile.seek(pos); |
1959 | | - } |
1960 | | - // syltBuff.hex_dump(10); |
1961 | | - |
1962 | | - m_ID3Hdr.SYLT.text_encoding = syltBuff[0]; // 0=ISO-8859-1, 1=UTF-16, 2=UTF-16BE, 3=UTF-8 |
1963 | | - if(m_ID3Hdr.SYLT.text_encoding == 1) isBigEndian = false; |
1964 | | - if(m_ID3Hdr.SYLT.text_encoding > 3){AUDIO_LOG_ERROR("unknown text encoding: %i", m_ID3Hdr.SYLT.text_encoding), m_ID3Hdr.SYLT.text_encoding = 0;} |
1965 | | - char encodingTab [4][12] = {"ISO-8859-1", "UTF-16", "UTF-16BE", "UTF-8"}; |
1966 | | - memcpy(m_ID3Hdr.SYLT.lang, syltBuff.get() + 1, 3); m_ID3Hdr.SYLT.lang[3] = '\0'; |
1967 | | - AUDIO_INFO("Lyrics: text_encoding: %s, language: %s, size %i", encodingTab[m_ID3Hdr.SYLT.text_encoding], m_ID3Hdr.SYLT.lang, m_ID3Hdr.SYLT.size); |
1968 | | - m_ID3Hdr.SYLT.time_stamp_format = syltBuff[4]; |
1969 | | - m_ID3Hdr.SYLT.content_type = syltBuff[5]; |
1970 | | - |
1971 | | - idx = 6; |
1972 | | - |
1973 | | - if(m_ID3Hdr.SYLT.text_encoding == 0 || m_ID3Hdr.SYLT.text_encoding == 3){ // utf-8 |
1974 | | - len = content_descriptor.copy_from((const char*)(syltBuff.get() + idx), "content_descriptor"); |
1975 | | - } |
1976 | | - else{ // utf-16 |
1977 | | - len = content_descriptor.copy_from_utf16((const uint8_t*)(syltBuff.get() + idx), isBigEndian, "content_descriptor"); |
1978 | | - } |
1979 | | - if(len > 2) AUDIO_INFO("Lyrics: content_descriptor: %s", content_descriptor.c_get()); |
1980 | | - idx += len; |
1981 | | - |
1982 | | - while (idx < m_ID3Hdr.SYLT.size) { |
1983 | | - // UTF-16LE, UTF-16BE |
1984 | | - if (m_ID3Hdr.SYLT.text_encoding == 1 || m_ID3Hdr.SYLT.text_encoding == 2) { |
1985 | | - idx += tmp.copy_from_utf16((const uint8_t*)(syltBuff.get() + idx), isBigEndian, "sylt-text"); |
1986 | | - } else { |
1987 | | - // ISO-8859-1 / UTF-8 |
1988 | | - idx += tmp.copy_from((const char*)syltBuff.get() + idx, "sylt-text"); |
1989 | | - } |
1990 | | - if (tmp.starts_with("\n")) tmp.remove_before(1); |
1991 | | - m_syltLines.push_back(std::move(tmp)); |
1992 | | - |
1993 | | - if (idx + 4 > m_ID3Hdr.SYLT.size) break; // no more 4 bytes? |
1994 | | - |
1995 | | - uint32_t timestamp = bigEndian((uint8_t*)syltBuff.get() + idx, 4); |
1996 | | - m_syltTimeStamp.push_back(timestamp); |
1997 | | - |
1998 | | - idx += 4; |
1999 | | - } |
2000 | | - for(int i = 0; i < m_syltLines.size(); i++){ |
2001 | | - AUDIO_INFO("%07i ms, %s", m_syltTimeStamp[i], m_syltLines[i].c_get()); |
2002 | | - } |
2003 | | - } |
| 1895 | + if(startsWith(m_ID3Hdr.tag, "SYLT") || startsWith(m_ID3Hdr.tag, "USLT")) { // any lyrics embedded in file, passing it to external function |
| 1896 | + m_controlCounter = 7; |
2004 | 1897 | return 0; |
2005 | 1898 | } |
2006 | 1899 |
|
@@ -2086,6 +1979,92 @@ int Audio::read_ID3_Header(uint8_t* data, size_t len) { |
2086 | 1979 | } |
2087 | 1980 | return fs; |
2088 | 1981 | } |
| 1982 | + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 1983 | + if(m_controlCounter == 7) { // SYLT |
| 1984 | + m_controlCounter = 5; |
| 1985 | + if(m_dataMode == AUDIO_LOCALFILE || (m_streamType == ST_WEBFILE && m_f_acceptRanges)) { |
| 1986 | + ps_ptr<char> tmp; |
| 1987 | + ps_ptr<char> content_descriptor; |
| 1988 | + ps_ptr<char> syltBuff; |
| 1989 | + bool isBigEndian = true; |
| 1990 | + size_t len = 0; |
| 1991 | + int idx = 0; |
| 1992 | + m_ID3Hdr.SYLT.seen = true; |
| 1993 | + m_ID3Hdr.SYLT.pos = m_ID3Hdr.id3Size - m_ID3Hdr.remainingHeaderBytes; |
| 1994 | + m_ID3Hdr.SYLT.size = m_ID3Hdr.framesize; |
| 1995 | + syltBuff.alloc(m_ID3Hdr.SYLT.size + 1, "syltBuff"); |
| 1996 | + if(m_streamType == ST_WEBFILE && m_f_acceptRanges){ |
| 1997 | + uint32_t pos = m_pwf.byteCounter; |
| 1998 | + // log_w("m_audiofile.position() %i, m_ID3Hdr.SYLT.pos %i", pos, m_ID3Hdr.SYLT.pos); |
| 1999 | + bool res; |
| 2000 | + res = httpRange(m_ID3Hdr.SYLT.pos, m_ID3Hdr.SYLT.pos + m_ID3Hdr.SYLT.size); |
| 2001 | + if(res == false){AUDIO_LOG_ERROR("http range request was not successful"); return 0;} |
| 2002 | + res = parseHttpRangeHeader(); |
| 2003 | + if(res == false){AUDIO_LOG_ERROR("http range response was not successful"); return 0;} |
| 2004 | + uint16_t bytesWritten = 0; |
| 2005 | + while(bytesWritten < m_ID3Hdr.SYLT.size){ |
| 2006 | + bytesWritten += _client->read((uint8_t*)syltBuff.get() + bytesWritten, m_ID3Hdr.SYLT.size); |
| 2007 | + } |
| 2008 | + res = httpRange(pos); |
| 2009 | + if(!res){AUDIO_LOG_ERROR("http range request was not successful"); return 0;} |
| 2010 | + res = parseHttpRangeHeader(); |
| 2011 | + if(!res){AUDIO_LOG_ERROR("http range response was not successful"); return 0;} |
| 2012 | + // return 0; |
| 2013 | + } |
| 2014 | + if(m_dataMode == AUDIO_LOCALFILE){ |
| 2015 | + uint32_t pos = m_audiofile.position(); |
| 2016 | + // log_w("m_audiofile.position() %i, m_ID3Hdr.SYLT.pos %i", pos, m_ID3Hdr.SYLT.pos); |
| 2017 | + m_audiofile.seek(m_ID3Hdr.SYLT.pos); |
| 2018 | + uint16_t bytesWritten = 0; |
| 2019 | + while(bytesWritten < m_ID3Hdr.SYLT.size){ |
| 2020 | + bytesWritten += m_audiofile.read((uint8_t*)syltBuff.get() + bytesWritten, m_ID3Hdr.SYLT.size); |
| 2021 | + } |
| 2022 | + m_audiofile.seek(pos); |
| 2023 | + } |
| 2024 | + // syltBuff.hex_dump(10); |
| 2025 | + m_ID3Hdr.SYLT.text_encoding = syltBuff[0]; // 0=ISO-8859-1, 1=UTF-16, 2=UTF-16BE, 3=UTF-8 |
| 2026 | + if(m_ID3Hdr.SYLT.text_encoding == 1) isBigEndian = false; |
| 2027 | + if(m_ID3Hdr.SYLT.text_encoding > 3){AUDIO_LOG_ERROR("unknown text encoding: %i", m_ID3Hdr.SYLT.text_encoding), m_ID3Hdr.SYLT.text_encoding = 0;} |
| 2028 | + char encodingTab [4][12] = {"ISO-8859-1", "UTF-16", "UTF-16BE", "UTF-8"}; |
| 2029 | + memcpy(m_ID3Hdr.SYLT.lang, syltBuff.get() + 1, 3); m_ID3Hdr.SYLT.lang[3] = '\0'; |
| 2030 | + AUDIO_INFO("Lyrics: text_encoding: %s, language: %s, size %i", encodingTab[m_ID3Hdr.SYLT.text_encoding], m_ID3Hdr.SYLT.lang, m_ID3Hdr.SYLT.size); |
| 2031 | + m_ID3Hdr.SYLT.time_stamp_format = syltBuff[4]; |
| 2032 | + m_ID3Hdr.SYLT.content_type = syltBuff[5]; |
| 2033 | + idx = 6; |
| 2034 | + if(m_ID3Hdr.SYLT.text_encoding == 0 || m_ID3Hdr.SYLT.text_encoding == 3){ // utf-8 |
| 2035 | + len = content_descriptor.copy_from((const char*)(syltBuff.get() + idx), "content_descriptor"); |
| 2036 | + } |
| 2037 | + else{ // utf-16 |
| 2038 | + len = content_descriptor.copy_from_utf16((const uint8_t*)(syltBuff.get() + idx), isBigEndian, "content_descriptor"); |
| 2039 | + } |
| 2040 | + if(len > 2) AUDIO_INFO("Lyrics: content_descriptor: %s", content_descriptor.c_get()); |
| 2041 | + idx += len; |
| 2042 | + while (idx < m_ID3Hdr.SYLT.size) { |
| 2043 | + // UTF-16LE, UTF-16BE |
| 2044 | + if (m_ID3Hdr.SYLT.text_encoding == 1 || m_ID3Hdr.SYLT.text_encoding == 2) { |
| 2045 | + idx += tmp.copy_from_utf16((const uint8_t*)(syltBuff.get() + idx), isBigEndian, "sylt-text"); |
| 2046 | + } else { |
| 2047 | + // ISO-8859-1 / UTF-8 |
| 2048 | + idx += tmp.copy_from((const char*)syltBuff.get() + idx, "sylt-text"); |
| 2049 | + } |
| 2050 | + if (tmp.starts_with("\n")) tmp.remove_before(1); |
| 2051 | + m_syltLines.push_back(std::move(tmp)); |
| 2052 | + if (idx + 4 > m_ID3Hdr.SYLT.size) break; // no more 4 bytes? |
| 2053 | + uint32_t timestamp = bigEndian((uint8_t*)syltBuff.get() + idx, 4); |
| 2054 | + m_syltTimeStamp.push_back(timestamp); |
| 2055 | + idx += 4; |
| 2056 | + } |
| 2057 | + for(int i = 0; i < m_syltLines.size(); i++){ |
| 2058 | + AUDIO_INFO("%07i ms, %s", m_syltTimeStamp[i], m_syltLines[i].c_get()); |
| 2059 | + } |
| 2060 | + } |
| 2061 | + return 0; |
| 2062 | + } |
| 2063 | + |
| 2064 | + |
| 2065 | + |
| 2066 | + |
| 2067 | + |
2089 | 2068 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
2090 | 2069 |
|
2091 | 2070 | // --- section V2.2 only , greater Vers above ---- |
@@ -4392,7 +4371,7 @@ bool Audio::parseHttpRangeHeader() { // this is the response to a Range request |
4392 | 4371 | vTaskDelay(5); |
4393 | 4372 | continue; |
4394 | 4373 | } |
4395 | | - |
| 4374 | + // AUDIO_LOG_WARN("rh %s", rhl.c_get()); |
4396 | 4375 | if(rhl.starts_with_icase("HTTP/")) { // HTTP status error code |
4397 | 4376 | char statusCode[5]; |
4398 | 4377 | statusCode[0] = rhl[9]; |
|
0 commit comments