You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
/*
AudioFileSourceHTTPStream
Connect to a HTTP based streaming service
Copyright (C) 2017 Earle F. Philhower, III
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <Arduino.h>
#ifdef ESP8266
#include <ESP8266HTTPClient.h>
#else
#include <HTTPClient.h>
#endif
#include "AudioFileSource.h"
class AudioFileSourceHTTPStream : public AudioFileSource {
friend class AudioFileSourceICYStream;
public:
AudioFileSourceHTTPStream();
AudioFileSourceHTTPStream(const char *url);
virtual ~AudioFileSourceHTTPStream() override;
virtual bool open(const char *url) override;
bool post(const char *url, const char *payload, const char *contentType);
bool addHeader(const char *name, const char *value);
bool setCACert(const char *cert);
bool reconnect();
virtual uint32_t read(void *data, uint32_t len) override;
virtual uint32_t readNonBlock(void *data, uint32_t len) override;
virtual bool seek(int32_t pos, int dir) override;
virtual bool close() override;
virtual bool isOpen() override;
virtual uint32_t getSize() override;
virtual uint32_t getPos() override;
bool SetReconnect(int tries, int delayms) {
reconnectTries = tries;
reconnectDelayMs = delayms;
return true;
}
void useHTTP10() {
http.useHTTP10(true);
}
enum { STATUS_HTTPFAIL = 2, STATUS_DISCONNECTED, STATUS_RECONNECTING, STATUS_RECONNECTED, STATUS_NODATA };
private:
virtual uint32_t readInternal(void *data, uint32_t len, bool nonBlock);
enum RequestType {
REQ_GET,
REQ_POST
};
RequestType reqType = REQ_GET;
String postPayload;
String postContentType;
struct HeaderItem {
String name;
String value;
};
HeaderItem headers[10];
int headerCount = 0;
#if defined(ESP_ARDUINO_VERSION_MAJOR) && ESP_ARDUINO_VERSION_MAJOR >= 3
NetworkClientSecure client;
#else
WiFiClientSecure client;
#endif
HTTPClient http;
int pos;
int size;
int reconnectTries;
int reconnectDelayMs = 500;
char saveURL[128];
bool cert = false;
};
AudioFileSourceHTTPStream.cpp
/*
AudioFileSourceHTTPStream
Streaming HTTP source
Copyright (C) 2017 Earle F. Philhower, III
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "AudioFileSourceHTTPStream.h"
AudioFileSourceHTTPStream::AudioFileSourceHTTPStream() {
pos = 0;
reconnectTries = 0;
saveURL[0] = 0;
}
AudioFileSourceHTTPStream::AudioFileSourceHTTPStream(const char *url) {
saveURL[0] = 0;
reconnectTries = 0;
open(url);
}
bool AudioFileSourceHTTPStream::open(const char *url) {
reqType = REQ_GET;
pos = 0;
#ifdef ESP8266
client.setBufferSizes(4096, 512);
#endif
if (!cert) {
client.setInsecure();
}
http.begin(client, url);
for (int i = 0; i < headerCount; i++) {
http.addHeader(headers[i].name.c_str(), headers[i].value.c_str());
}
http.setTimeout(120000);
http.setReuse(true);
#ifndef ESP32
http.setFollowRedirects(HTTPC_FORCE_FOLLOW_REDIRECTS);
#endif
int code = http.GET();
if (code != HTTP_CODE_OK) {
http.end();
cb.st(STATUS_HTTPFAIL, PSTR("Can't open HTTP request"));
return false;
}
size = http.getSize();
strncpy(saveURL, url, sizeof(saveURL));
saveURL[sizeof(saveURL) - 1] = 0;
return true;
}
bool AudioFileSourceHTTPStream::post(const char *url, const char *payload, const char *contentType = "application/json") {
reqType = REQ_POST;
postPayload = payload;
postContentType = contentType;
pos = 0;
#ifdef ESP8266
client.setBufferSizes(4096, 512);
#endif
if (!cert) {
client.setInsecure();
}
http.begin(client, url);
for (int i = 0; i < headerCount; i++) {
http.addHeader(headers[i].name.c_str(), headers[i].value.c_str());
}
http.addHeader("Content-Type", contentType);
http.setTimeout(120000);
http.setReuse(true);
#ifndef ESP32
http.setFollowRedirects(HTTPC_FORCE_FOLLOW_REDIRECTS);
#endif
int code = http.POST((uint8_t*)payload, strlen(payload));
if (code != HTTP_CODE_OK) {
http.end();
cb.st(STATUS_HTTPFAIL, PSTR("HTTP POST failed"));
return false;
}
size = http.getSize();
strncpy(saveURL, url, sizeof(saveURL));
saveURL[sizeof(saveURL) - 1] = 0;
return true;
}
AudioFileSourceHTTPStream::~AudioFileSourceHTTPStream() {
http.end();
}
bool AudioFileSourceHTTPStream::addHeader(const char *name, const char *value) {
if (headerCount < 10) {
headers[headerCount].name = name;
headers[headerCount].value = value;
headerCount++;
}
return true;
}
bool AudioFileSourceHTTPStream::setCACert(const char *certificate) {
cert = true;
client.setCACert(certificate);
return true;
}
uint32_t AudioFileSourceHTTPStream::read(void *data, uint32_t len) {
if (data == NULL) {
audioLogger->printf_P(PSTR("ERROR! AudioFileSourceHTTPStream::read passed NULL data\n"));
return 0;
}
return readInternal(data, len, false);
}
uint32_t AudioFileSourceHTTPStream::readNonBlock(void *data, uint32_t len) {
if (data == NULL) {
audioLogger->printf_P(PSTR("ERROR! AudioFileSourceHTTPStream::readNonBlock passed NULL data\n"));
return 0;
}
return readInternal(data, len, true);
}
bool AudioFileSourceHTTPStream::reconnect() {
pos = 0;
if (reqType == REQ_GET) {
return open(saveURL);
}
if (reqType == REQ_POST) {
return post(saveURL, postPayload.c_str(), postContentType.c_str());
}
return false;
}
uint32_t AudioFileSourceHTTPStream::readInternal(void *data, uint32_t len, bool nonBlock) {
retry:
if (!http.connected()) {
cb.st(STATUS_DISCONNECTED, PSTR("Stream disconnected"));
http.end();
for (int i = 0; i < reconnectTries; i++) {
char buff[64];
sprintf_P(buff, PSTR("Attempting to reconnect, try %d"), i);
cb.st(STATUS_RECONNECTING, buff);
delay(reconnectDelayMs);
if (reconnect()) {
cb.st(STATUS_RECONNECTED, PSTR("Stream reconnected"));
break;
}
}
if (!http.connected()) {
cb.st(STATUS_DISCONNECTED, PSTR("Unable to reconnect"));
return 0;
}
}
if ((size > 0) && (pos >= size)) {
return 0;
}
#if defined(ESP_ARDUINO_VERSION_MAJOR) && ESP_ARDUINO_VERSION_MAJOR >= 3
NetworkClient *stream = http.getStreamPtr();
#else
WiFiClient *stream = http.getStreamPtr();
#endif
// Can't read past EOF...
if ((size > 0) && (len > (uint32_t)(pos - size))) {
len = pos - size;
}
if (!nonBlock) {
int start = millis();
while ((stream->available() < (int)len) && (millis() - start < 1500)) {
yield();
}
}
size_t avail = stream->available();
if (!nonBlock && !avail) {
cb.st(STATUS_NODATA, PSTR("No stream data available"));
http.end();
goto retry;
}
if (avail == 0) {
return 0;
}
if (avail < len) {
len = avail;
}
int read = stream->read(reinterpret_cast<uint8_t*>(data), len);
pos += read;
return read;
}
bool AudioFileSourceHTTPStream::seek(int32_t pos, int dir) {
audioLogger->printf_P(PSTR("ERROR! AudioFileSourceHTTPStream::seek not implemented!"));
(void) pos;
(void) dir;
return false;
}
bool AudioFileSourceHTTPStream::close() {
http.end();
return true;
}
bool AudioFileSourceHTTPStream::isOpen() {
return http.connected();
}
uint32_t AudioFileSourceHTTPStream::getSize() {
return size;
}
uint32_t AudioFileSourceHTTPStream::getPos() {
return pos;
}
Board: ESP32 devkit v1
ESP32 Core: 3.3.6
I have modified this files to work with https.I have also added a post() function, but when I flash to my esp it just jitters at first then completely stops and MP3 decoder shows no error
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
AudioFileSourceHTTPStream.h
AudioFileSourceHTTPStream.cpp
Board: ESP32 devkit v1
ESP32 Core: 3.3.6
I have modified this files to work with https.I have also added a post() function, but when I flash to my esp it just jitters at first then completely stops and MP3 decoder shows no error
And I have used
audioLogger = &SerialStill none of the audio logs are being printed.
Beta Was this translation helpful? Give feedback.
All reactions