You can now also play MP3s streamed from the internet. (Very rough & wonky code. More or less proof-of-concept right now.)

This commit is contained in:
Fabian Schlenz 2019-11-20 06:13:15 +01:00
parent 94489618ca
commit b989784fb9
5 changed files with 96 additions and 6 deletions

View File

@ -3,19 +3,21 @@
#include <Arduino.h>
#include <SD.h>
#include "config.h"
#include <HTTPClient.h>
class DataSource {
private:
public:
DataSource() {};
~DataSource() {};
virtual ~DataSource() {};
virtual size_t read(uint8_t* buf, size_t len) = 0;
virtual uint8_t read() = 0;
virtual size_t position() = 0;
virtual void seek(size_t position) = 0;
virtual size_t size() = 0;
virtual void close() = 0;
virtual void skip_id3_tag();
virtual void skip_id3_tag() {};
virtual bool usable() = 0;
};
class SDDataSource : public DataSource {
@ -31,4 +33,23 @@ public:
size_t size();
void close();
void skip_id3_tag();
bool usable();
};
class HTTPSDataSource : public DataSource {
private:
WiFiClient* _stream = NULL;
HTTPClient* _http = NULL;
uint32_t _length;
uint32_t _position;
public:
HTTPSDataSource(String url, uint32_t offset=0);
~HTTPSDataSource();
size_t read(uint8_t* buf, size_t len);
uint8_t read();
size_t position();
void seek(size_t position);
size_t size();
void close();
bool usable();
};

View File

@ -11,7 +11,7 @@ private:
bool _shuffled = false;
std::vector<String> _files;
public:
Playlist(String path);
Playlist(String path, bool is_url=false);
void start();
bool has_track_next();
bool has_track_prev();

View File

@ -9,6 +9,7 @@ size_t SDDataSource::position() { return _file.position(); }
void SDDataSource::seek(size_t position) { _file.seek(position); }
size_t SDDataSource::size() { return _file.size(); }
void SDDataSource::close() { _file.close(); }
bool SDDataSource::usable() { return _file; }
void SDDataSource::skip_id3_tag() {
uint32_t original_position = _file.position();
@ -33,3 +34,61 @@ void SDDataSource::skip_id3_tag() {
_file.seek(original_position);
}
}
////////////// HTTPSDataSource //////////////
HTTPSDataSource::HTTPSDataSource(String url, uint32_t offset) {
uint8_t tries_left = 5;
int status;
do {
if (tries_left == 0) {
ERROR("Redirection loop? Cancelling!\n");
return;
}
tries_left--;
DEBUG("Connecting to %s...\n", url.c_str());
if (_http) delete _http;
_http = new HTTPClient();
const char* headers[] = {"location"};
_http->collectHeaders(headers, 1);
bool result = _http->begin(url);
DEBUG("HTTP->begin result: %d\n", result);
if (!result) return;
status = _http->GET();
DEBUG("Status code: %d\n", status);
if (status == HTTP_CODE_FOUND || status==HTTP_CODE_MOVED_PERMANENTLY || status==HTTP_CODE_TEMPORARY_REDIRECT) {
if (_http->hasHeader("Location")) {
url = _http->header("Location");
} else if (_http->hasHeader("location")) {
url = _http->header("location");
} else {
ERROR("Got redirection HTTP code, but could not find Location header.\n");
for(int i=0; i<_http->headers(); i++) {
DEBUG(" Header: %s=%s\n", _http->headerName(i).c_str(), _http->header(i).c_str());
}
return;
}
} else if (status != HTTP_CODE_OK) {
DEBUG("Unexpected HTTP return code. Cancelling.\n");
return;
}
} while (status != HTTP_CODE_OK);
_length = _http->getSize();
DEBUG("Content-Length: %d\n", _length);
_stream = _http->getStreamPtr();
}
HTTPSDataSource::~HTTPSDataSource() {
if (_stream) _stream->stop();
_http->end();
delete _stream;
delete _http;
}
bool HTTPSDataSource::usable() { return _http && _stream; }
size_t HTTPSDataSource::read(uint8_t* buf, size_t len) { size_t result = _stream->read(buf, len); _position += result; return result; }
uint8_t HTTPSDataSource::read() { _position++; return _stream->read(); }
size_t HTTPSDataSource::position() { return _position; }
void HTTPSDataSource::seek(size_t position) { return; /* TODO */ }
size_t HTTPSDataSource::size() { return _length; }
void HTTPSDataSource::close() { _stream->stop(); }

View File

@ -545,10 +545,16 @@ bool Player::play() {
void Player::_play_file(String file, uint32_t file_offset) {
INFO("play_file('%s', %d)\n", file.c_str(), file_offset);
_spi->select_sd();
_file = new SDDataSource(file);
if (file.startsWith("/")) {
_file = new SDDataSource(file);
} else if (file.startsWith("https://")) {
_file = new HTTPSDataSource(file);
} else {
return;
}
_file_size = _file->size();
_spi->select_sd(false);
if (!_file) {
if (!_file || !_file->usable()) {
DEBUG("Could not open file %s", file.c_str());
return;
}

View File

@ -5,7 +5,11 @@
#include <algorithm>
#include <ArduinoJson.h>
Playlist::Playlist(String path) {
Playlist::Playlist(String path, bool is_url) {
if (is_url) {
_files.push_back(path);
return;
}
// Add files to _files
SPIMaster::select_sd();
TRACE("Examining folder %s...\n", path.c_str());