Closed VaAndCob closed 2 weeks ago
Nobody has asked about this yet. I can add that, but I don't have the opportunity to test it.
Nobody has asked about this yet. I can add that, but I don't have the opportunity to test it.
Firstly, I have to thank you a lot for this library, it makes a lot easier for many applications. this is what I added to audio.h and audio.ccp (by reuse and modify your sketch)
// LINE voice message
bool Audio::lineVoiceMessage(String messageId, const char* token) {
String host_chr = "https://api-data.line.me/v2/bot/message/" + messageId + "/content";
// Now you can convert 'host' to a C-string if needed
const char* host = host_chr.c_str();
xSemaphoreTake(mutex_playAudioData, portMAX_DELAY);
if(host == NULL) {
AUDIO_INFO("Hostaddress is empty");
stopSong();
xSemaphoreGive(mutex_playAudioData);
return false;
}
uint16_t lenHost = strlen(host);
if(lenHost >= 512 - 10) {
AUDIO_INFO("Hostaddress is too long");
stopSong();
xSemaphoreGive(mutex_playAudioData);
return false;
}
/**/
int idx = indexOf(host, "http");
char* l_host = (char*)malloc(lenHost + 10);
if(idx < 0) {
strcpy(l_host, "http://");
strcat(l_host, host);
} // amend "http;//" if not found
else { strcpy(l_host, (host + idx)); } // trim left if necessary
char* h_host = NULL; // pointer of l_host without http:// or https://
if(startsWith(l_host, "https")) h_host = strdup(l_host + 8);
else h_host = strdup(l_host + 7);
// initializationsequence
int16_t pos_slash; // position of "/" in hostname
int16_t pos_colon; // position of ":" in hostname
int16_t pos_ampersand; // position of "&" in hostname
uint16_t port = 80; // port number
// In the URL there may be an extension, like noisefm.ru:8000/play.m3u&t=.m3u
pos_slash = indexOf(h_host, "/", 0);
pos_colon = indexOf(h_host, ":", 0);
if(isalpha(h_host[pos_colon + 1])) pos_colon = -1; // no portnumber follows
pos_ampersand = indexOf(h_host, "&", 0);
char* hostwoext = NULL; // "skonto.ls.lv:8002" in "skonto.ls.lv:8002/mp3"
char* extension = NULL; // "/mp3" in "skonto.ls.lv:8002/mp3"
if(pos_slash > 1) {
hostwoext = (char*)malloc(pos_slash + 1);
memcpy(hostwoext, h_host, pos_slash);
hostwoext[pos_slash] = '\0';
uint16_t extLen = urlencode_expected_len(h_host + pos_slash);
extension = (char*)malloc(extLen + 20);
memcpy(extension, h_host + pos_slash, extLen);
urlencode(extension, extLen, true);
}
else { // url has no extension
hostwoext = strdup(h_host);
extension = strdup("/");
}
if((pos_colon >= 0) && ((pos_ampersand == -1) || (pos_ampersand > pos_colon))) {
port = atoi(h_host + pos_colon + 1); // Get portnumber as integer
hostwoext[pos_colon] = '\0'; // Host without portnumber
}
setDefaults(); // no need to stop clients if connection is established (default is true)
if(startsWith(l_host, "https")) m_f_ssl = true;
else m_f_ssl = false;
// AUDIO_INFO("Connect to \"%s\" on port %d, extension \"%s\"", hostwoext, port, extension);
// optional basic authorization
uint16_t auth = strlen(token);
char authorization[auth + 1];
authorization[0] = '\0';
strcat(authorization, token);
// AUDIO_INFO("Connect to \"%s\" on port %d, extension \"%s\"", hostwoext, port, extension);
char rqh[strlen(h_host) + strlen(authorization) + 220]; // http request header
rqh[0] = '\0';
strcat(rqh, "GET ");
strcat(rqh, extension);
strcat(rqh, " HTTP/1.1\r\n");
strcat(rqh, "Host: ");
strcat(rqh, hostwoext);
strcat(rqh, "\r\n");
if(auth > 0) {
strcat(rqh, "Authorization: Bearer ");
strcat(rqh, authorization);
strcat(rqh, "\r\n");
}
strcat(rqh, "Content-Type: application/json\r\n\r\n");
Serial.println(rqh);
bool res = true; // no need to reconnect if connection exists
if(m_f_ssl) {
_client = static_cast<WiFiClient*>(&clientsecure);
if(port == 80) port = 443;
}
else { _client = static_cast<WiFiClient*>(&client); }
uint32_t t = millis();
AUDIO_INFO("connect to: \"%s\" on port %d path \"%s\"", hostwoext, port, extension);
_client->setTimeout(m_f_ssl ? m_timeout_ms_ssl : m_timeout_ms);
res = _client->connect(hostwoext, port);
if(res) {
uint32_t dt = millis() - t;
strcpy(m_lastHost, l_host);
AUDIO_INFO("%s has been established in %lu ms, free Heap: %lu bytes", m_f_ssl ? "SSL" : "Connection", (long unsigned int)dt, (long unsigned int)ESP.getFreeHeap());
m_f_running = true;
}
m_expectedCodec = CODEC_NONE;
m_expectedPlsFmt = FORMAT_NONE;
if(res) {
Serial.println("Host connected");
// log_i("connecttohost(): %s", rqh);
_client->print(rqh);
if(endsWith(extension, ".mp3" )) m_expectedCodec = CODEC_MP3;
if(endsWith(extension, ".aac" )) m_expectedCodec = CODEC_AAC;
if(endsWith(extension, ".wav" )) m_expectedCodec = CODEC_WAV;
if(endsWith(extension, ".m4a" )) m_expectedCodec = CODEC_M4A;
if(endsWith(extension, ".ogg" )) m_expectedCodec = CODEC_OGG;
if(endsWith(extension, ".flac")) m_expectedCodec = CODEC_FLAC;
if(endsWith(extension, "-flac")) m_expectedCodec = CODEC_FLAC;
if(endsWith(extension, ".opus")) m_expectedCodec = CODEC_OPUS;
if(endsWith(extension, "/opus")) m_expectedCodec = CODEC_OPUS;
if(endsWith(extension, ".asx" )) m_expectedPlsFmt = FORMAT_ASX;
if(endsWith(extension, ".m3u" )) m_expectedPlsFmt = FORMAT_M3U;
if(endsWith(extension, ".pls" )) m_expectedPlsFmt = FORMAT_PLS;
if(endsWith(extension, ".m3u8")) {
m_expectedPlsFmt = FORMAT_M3U8;
if(audio_lasthost) audio_lasthost(host);
}
setDatamode(HTTP_RESPONSE_HEADER); // Handle header
m_streamType = ST_WEBSTREAM;
}
else {
Serial.println("Request failed");
AUDIO_INFO("Request %s failed!", l_host);
if(audio_showstation) audio_showstation("");
if(audio_showstreamtitle) audio_showstreamtitle("");
if(audio_icydescription) audio_icydescription("");
if(audio_icyurl) audio_icyurl("");
m_lastHost[0] = 0;
}
if(hostwoext) {
free(hostwoext);
hostwoext = NULL;
}
if(extension) {
free(extension);
extension = NULL;
}
if(l_host) {
free(l_host);
l_host = NULL;
}
if(h_host) {
free(h_host);
h_host = NULL;
}
xSemaphoreGive(mutex_playAudioData);
return res;
}
and this is the result, I think it works but the download audio file (.m4a) doesn't play.
GET /v2/bot/message/524574436284957095/content HTTP/1.1 Host: api-data.line.me Authorization: Bearer eFC+Tj5hJrxLMxHDo6vL Content-Type: application/json
info connect to: "api-data.line.me" on port 443 path "/v2/bot/message/524574436284957095/content" info SSL has been established in 1809 ms, free Heap: 96532 bytes Host connected info AACDecoder has been initialized, free Heap: 97748 bytes , free stack 2668 DWORDs info unknown Audio Type 0 info max bitrate: 1073743106 info avr bitrate: 336070145 info unknown ObjectType e, stop info Sampling Frequency: 44100 info ch; 1, bps: 16, sr: 16000
I have downloaded this audio.m4a file to my PC and it can be played with a music player, I also tried saving this file to the SD card and playing it with the SD card, but it still did not play.
I'm unsure if the audio file has missing info, etc. I also attached an example m4a file in case you will be kind enough to test it. audio.zip
Thank you.
The audio.m4a file is within the specification, but differs from the "usual" m4a files when analysing the m4a header. I have extended the routine for reading the m4a header. The file can now be played.
Thank you so much, it works for now.. I download m4a file to littleFS and playback. but the problem is the speed is slower than usual. it's like 0.5 time speed or lower
Downloaded 1024 bytes... Downloaded 1024 bytes... Downloaded 1024 bytes... Downloaded 1024 bytes... Downloaded 534 bytes... File '/voicemessage.m4a' saved, size: 9750 bytes Playing the audio file... info buffers freed, free Heap: 93868 bytes info Reading file: "/voicemessage.m4a" info AACDecoder has been initialized, free Heap: 92952 bytes , free stack 2908 DWORDs info ch; 1, bps: 16, sr: 16000 info AudioType: MPEG4 / Audio info max bitrate: 16384 info avg bitrate: 16384 info AudioObjectType: AAC Low Complexity info Sampling Frequency: 16000 info Channel Configurations: front-center info AAC FrameLength: 1024 bytes info ch; 1, bps: 16, sr: 16000 info Audio-Length: 8705 info Content-Length: 9750 info stream ready info syncword found at pos 0 info Channels: 1 info SampleRate: 16000 info BitsPerSample: 16 info BitRate: 16375 info Closing audio file "voicemessage.m4a" voicemessage.m4a info End of file "voicemessage.m4a"
oh and if possible you can add a function to play stream from https get with authorization: bearer would be very appreaciate
Can you please attach the file, the last one was too short to recognise. Maybe there is a problem with mono? I don't want to write a separate function for the "bearer", maybe we can send the token as a user in connecttohost()?
Can you please attach the file, the last one was too short to recognise. Maybe there is a problem with mono? I don't want to write a separate function for the "bearer", maybe we can send the token as a user in connecttohost()?
that would be great, just adding a Bearer parameter into this function connecttohost() is ok.
the m4a file is Stereo, Sampling rate 32000Hz, 32 bps here is an example of voice sound I downloaded from Line application. whenever I download from Line server and save to LittleFS as .m4a file extension, then play with audio.connecttoFS function. the sound volume is low and the speed is slow, (sounds like a monster LOL)
one more question. Is it capable of playing m4a streaming from the host? Any limitation?
thank :)
one more thing, I notice the m4a information from success play file vs no sound file as below. SUCCESS PLAYED
File '/voicemessage.m4a' saved, size: 11626 bytes Playing the audio file... info PSRAM found, inputBufferSize: 638965 bytes info buffers freed, free Heap: 94252 bytes info Reading file: "/voicemessage.m4a" info AACDecoder has been initialized, free Heap: 93336 bytes , free stack 3004 DWORDs info ch; 2, bps: 16, sr: 16000 info AudioType: MPEG4 / Audio info max bitrate: 16295 info avg bitrate: 16295 info AudioObjectType: AAC Low Complexity info Sampling Frequency: 16000 info Channel Configurations: front-center info AAC FrameLength: 1024 bytes info ch; 2, bps: 16, sr: 16000 info Audio-Length: 10506 info Content-Length: 11634 info stream ready info syncword found at pos 0 info Channels: 1 info SampleRate: 16000 info BitsPerSample: 16 info BitRate: 23875 info Closing audio file "voicemessage.m4a" voicemessage.m4a info End of file "voicemessage.m4a"
//---------------------- NO SOUND
File '/voicemessage.m4a' saved, size: 16007 bytes Playing the audio file... info buffers freed, free Heap: 89492 bytes info Reading file: "/voicemessage.m4a" info AACDecoder has been initialized, free Heap: 88576 bytes , free stack 3004 DWORDs info ch; 1, bps: 16, sr: 16000 info AudioType: MPEG4 / Audio info max bitrate: 16384 info avg bitrate: 16384 info AudioObjectType: AAC Low Complexity info Sampling Frequency: 16000 info Channel Configurations: front-center info AAC FrameLength: 1024 bytes info ch; 1, bps: 16, sr: 16000
//---------------- So I guessed it the m4a file itself that I downloaded from Line server that might be missing information to get the encoder play it correctly..
This issue is stale because it has been open for 30 days with no activity.
This issue was closed because it has been inactive for 14 days since being marked as stale.
How can I play streaming with request header "Authorization: Bearer {accesstoken}" ? audio.connecttohost(url, accesstoken) something like this