mirror of
https://github.com/sle118/squeezelite-esp32.git
synced 2025-12-15 16:07:05 +03:00
update CSpot
This commit is contained in:
@@ -18,3 +18,8 @@ std::string bell::generateRandomUUID() {
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void bell::freeAndNull(void *&ptr) {
|
||||
free(ptr);
|
||||
ptr = nullptr;
|
||||
}
|
||||
|
||||
@@ -24,7 +24,8 @@ void bell::BinaryReader::skip(size_t pos) {
|
||||
|
||||
int32_t bell::BinaryReader::readInt() {
|
||||
uint8_t b[4];
|
||||
stream->read((uint8_t *) b,4);
|
||||
if (stream->read((uint8_t *) b,4) != 4)
|
||||
return 0;
|
||||
|
||||
return static_cast<int32_t>(
|
||||
(b[3]) |
|
||||
@@ -35,11 +36,12 @@ int32_t bell::BinaryReader::readInt() {
|
||||
|
||||
int16_t bell::BinaryReader::readShort() {
|
||||
uint8_t b[2];
|
||||
stream->read((uint8_t *) b,2);
|
||||
if (stream->read((uint8_t *) b,2) != 2)
|
||||
return 0;
|
||||
|
||||
return static_cast<int16_t>(
|
||||
(b[1]) |
|
||||
(b[1] << 8));
|
||||
(b[0] << 8));
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +51,8 @@ uint32_t bell::BinaryReader::readUInt() {
|
||||
|
||||
uint8_t bell::BinaryReader::readByte() {
|
||||
uint8_t b[1];
|
||||
stream->read((uint8_t *) b,1);
|
||||
if (stream->read((uint8_t *) b,1) != 1)
|
||||
return 0;
|
||||
return b[0];
|
||||
}
|
||||
|
||||
|
||||
@@ -13,9 +13,7 @@ void HTTPClient::HTTPResponse::close() {
|
||||
bufPtr = nullptr;
|
||||
}
|
||||
HTTPClient::HTTPResponse::~HTTPResponse() {
|
||||
socket = nullptr;
|
||||
if (buf)
|
||||
free(buf);
|
||||
this->close();
|
||||
}
|
||||
|
||||
HTTPResponse_t HTTPClient::execute(const struct HTTPRequest &request) {
|
||||
@@ -70,10 +68,12 @@ HTTPResponse_t HTTPClient::executeImpl(const struct HTTPRequest &request, HTTPRe
|
||||
stream << header.first << ": " << header.second << endl;
|
||||
}
|
||||
stream << endl;
|
||||
stream << request.body;
|
||||
if (request.body != nullptr) {
|
||||
stream << request.body;
|
||||
}
|
||||
std::string data = stream.str();
|
||||
|
||||
size_t len = response->socket->write((uint8_t *)data.c_str(), data.size());
|
||||
uint32_t len = response->socket->write((uint8_t *)data.c_str(), data.size());
|
||||
if (len != data.size()) {
|
||||
response->close();
|
||||
BELL_LOG(error, "http", "Writing failed: wrote %d of %d bytes", len, data.size());
|
||||
@@ -91,7 +91,7 @@ HTTPResponse_t HTTPClient::executeImpl(const struct HTTPRequest &request, HTTPRe
|
||||
}
|
||||
|
||||
bool HTTPClient::readHeader(const char *&header, const char *name) {
|
||||
size_t len = strlen(name);
|
||||
uint32_t len = strlen(name);
|
||||
if (strncasecmp(header, name, len) == 0) {
|
||||
header += len;
|
||||
while (*header == ' ')
|
||||
@@ -101,8 +101,13 @@ bool HTTPClient::readHeader(const char *&header, const char *name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t HTTPClient::HTTPResponse::readRaw(char *dst) {
|
||||
size_t len = this->socket->read((uint8_t *)dst, BUF_SIZE);
|
||||
uint32_t HTTPClient::HTTPResponse::readRaw(char *dst) {
|
||||
if (!this->socket)
|
||||
return 0; // socket is already closed, I guess
|
||||
uint32_t len = this->socket->read((uint8_t *)dst, BUF_SIZE);
|
||||
if (len == 0 || len == -1) {
|
||||
isComplete = true;
|
||||
}
|
||||
if (dumpRawFs)
|
||||
dumpRawFs->write(dst, (long)len);
|
||||
// BELL_LOG(debug, "http", "Read %d bytes", len);
|
||||
@@ -111,7 +116,7 @@ size_t HTTPClient::HTTPResponse::readRaw(char *dst) {
|
||||
}
|
||||
|
||||
void HTTPClient::HTTPResponse::readHeaders() {
|
||||
size_t len;
|
||||
uint32_t len;
|
||||
char *line, *lineEnd;
|
||||
bool complete = false;
|
||||
std::string lineBuf;
|
||||
@@ -185,8 +190,8 @@ void HTTPClient::HTTPResponse::readHeaders() {
|
||||
} while (!complete && len); // if len == 0, the connection is closed
|
||||
}
|
||||
|
||||
bool HTTPClient::HTTPResponse::skipRaw(size_t len, bool dontRead) {
|
||||
size_t skip = 0;
|
||||
bool HTTPClient::HTTPResponse::skipRaw(uint32_t len, bool dontRead) {
|
||||
uint32_t skip = 0;
|
||||
if (len > bufRemaining) {
|
||||
skip = len - bufRemaining;
|
||||
len = bufRemaining;
|
||||
@@ -211,16 +216,17 @@ bool HTTPClient::HTTPResponse::skipRaw(size_t len, bool dontRead) {
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t HTTPClient::HTTPResponse::read(char *dst, size_t toRead, bool wait) {
|
||||
uint32_t HTTPClient::HTTPResponse::read(char *dst, uint32_t toRead, bool wait) {
|
||||
if (isComplete) {
|
||||
// end of chunked stream was found OR complete body was read
|
||||
return 0;
|
||||
}
|
||||
auto *dstStart = dst ? dst : nullptr;
|
||||
size_t read = 0;
|
||||
uint32_t read = 0;
|
||||
while (toRead) { // this loop ends after original toRead
|
||||
skipRaw(0); // ensure the buffer contains data, wait if necessary
|
||||
if (isChunked && !chunkRemaining) {
|
||||
// chunked responses (either streaming or not)
|
||||
if (*bufPtr == '0') { // all chunks were read *and emitted*
|
||||
isComplete = true;
|
||||
break;
|
||||
@@ -241,11 +247,15 @@ size_t HTTPClient::HTTPResponse::read(char *dst, size_t toRead, bool wait) {
|
||||
if (!skipRaw(endPtr - bufPtr + 2)) // skip the size and \r\n
|
||||
break; // -> no more data, break out of main loop
|
||||
} else if (contentLength && !chunkRemaining) {
|
||||
// normal responses (having content-length)
|
||||
chunkRemaining = contentLength;
|
||||
} else if (!chunkRemaining) {
|
||||
// fallback for non-chunked streams (without content-length)
|
||||
chunkRemaining = toRead;
|
||||
}
|
||||
|
||||
while (chunkRemaining && toRead) {
|
||||
size_t count = std::min(toRead, std::min(bufRemaining, chunkRemaining));
|
||||
uint32_t count = std::min(toRead, std::min(bufRemaining, chunkRemaining));
|
||||
if (dst) {
|
||||
memcpy(dst, bufPtr, count);
|
||||
dst += count; // move the dst pointer
|
||||
@@ -287,8 +297,8 @@ std::string HTTPClient::HTTPResponse::readToString() {
|
||||
return result;
|
||||
}
|
||||
std::string result;
|
||||
char buffer[BUF_SIZE+1]; // make space for null-terminator
|
||||
size_t len;
|
||||
char buffer[BUF_SIZE + 1]; // make space for null-terminator
|
||||
uint32_t len;
|
||||
do {
|
||||
len = this->read(buffer, BUF_SIZE);
|
||||
buffer[len] = '\0';
|
||||
|
||||
@@ -170,16 +170,23 @@ void bell::HTTPServer::readFromClient(int clientFd) {
|
||||
if (line.find("Content-Length: ") != std::string::npos) {
|
||||
conn.contentLength =
|
||||
std::stoi(line.substr(16, line.size() - 1));
|
||||
//BELL_LOG(info, "http", "Content-Length: %d",
|
||||
// conn.contentLength);
|
||||
}
|
||||
// detect hostname for captive portal
|
||||
if (line.find("Host: connectivitycheck.gstatic.com") != std::string::npos) {
|
||||
conn.isCaptivePortal = true;
|
||||
BELL_LOG(info, "http", "Captive portal request detected");
|
||||
}
|
||||
if (line.size() == 0) {
|
||||
if (conn.contentLength != 0) {
|
||||
conn.isReadingBody = true;
|
||||
goto READBODY;
|
||||
} else {
|
||||
findAndHandleRoute(conn.httpMethod, conn.currentLine,
|
||||
clientFd);
|
||||
if (!conn.isCaptivePortal) {
|
||||
findAndHandleRoute(conn.httpMethod, conn.currentLine, clientFd);
|
||||
} else {
|
||||
this->redirectCaptivePortal(clientFd);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -277,6 +284,21 @@ void bell::HTTPServer::respond(const HTTPResponse &response) {
|
||||
writeResponse(response);
|
||||
}
|
||||
|
||||
void bell::HTTPServer::redirectCaptivePortal(int connectionFd) {
|
||||
std::lock_guard lock(this->responseMutex);
|
||||
std::stringstream stream;
|
||||
stream << "HTTP/1.1 302 Found\r\n";
|
||||
stream << "Server: bell-http\r\n";
|
||||
stream << "Connection: close\r\n";
|
||||
stream << "Location: http://euphonium.audio\r\n\r\n";
|
||||
stream << "Content-Length: 9\r\n";
|
||||
stream << "302 Found";
|
||||
auto responseStr = stream.str();
|
||||
|
||||
write(connectionFd, responseStr.c_str(), responseStr.size());
|
||||
this->closeConnection(connectionFd);
|
||||
}
|
||||
|
||||
void bell::HTTPServer::redirectTo(const std::string & url, int connectionFd) {
|
||||
std::lock_guard lock(this->responseMutex);
|
||||
std::stringstream stream;
|
||||
@@ -407,6 +429,11 @@ void bell::HTTPServer::findAndHandleRoute(std::string &url, std::string &body,
|
||||
if (routeSplit.back().find('*') != std::string::npos &&
|
||||
urlSplit[1] == routeSplit[1]) {
|
||||
matches = true;
|
||||
for (int x = 1; x <= routeSplit.size() - 2; x++) {
|
||||
if (urlSplit[x] != routeSplit[x]) {
|
||||
matches = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (matches) {
|
||||
|
||||
@@ -42,4 +42,11 @@ std::string bell::JSONObject::toString()
|
||||
free(body);
|
||||
return retVal;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<uint8_t> bell::JSONObject::toVector() {
|
||||
char *body = cJSON_Print(this->body);
|
||||
std::vector<uint8_t> res(body, body + strlen(body));
|
||||
free(body);
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -40,7 +40,8 @@ void BufferedAudioSink::feedPCMFramesInternal(const void *pvItem, size_t xItemSi
|
||||
xRingbufferSend(dataBuffer, pvItem, xItemSize, portMAX_DELAY);
|
||||
}
|
||||
|
||||
bool BufferedAudioSink::setRate(uint16_t sampleRate) {
|
||||
i2s_set_sample_rates((i2s_port_t)0, sampleRate);
|
||||
bool BufferedAudioSink::setParams(uint32_t sampleRate, uint8_t channelCount, uint8_t bitDepth) {
|
||||
// TODO override this for sinks with custom mclk
|
||||
i2s_set_clk((i2s_port_t)0, sampleRate, (i2s_bits_per_sample_t)bitDepth, (i2s_channel_t)channelCount);
|
||||
return true;
|
||||
}
|
||||
@@ -72,19 +72,21 @@ SPDIFAudioSink::SPDIFAudioSink(uint8_t spdifPin)
|
||||
spdif_buf_init();
|
||||
spdif_ptr = spdif_buf;
|
||||
this->spdifPin = spdifPin;
|
||||
this->initialize(44100);
|
||||
this->setParams(44100, 16, 2);
|
||||
startI2sFeed(SPDIF_BUF_SIZE * 16);
|
||||
}
|
||||
|
||||
void SPDIFAudioSink::initialize(uint16_t sampleRate) {
|
||||
int sample_rate = sampleRate * 2;
|
||||
bool SPDIFAudioSink::setParams(uint32_t sampleRate, uint8_t channelCount, uint8_t bitDepth) {
|
||||
if (bitDepth != 16 || channelCount != 2) // TODO support mono playback and different bit widths
|
||||
return false;
|
||||
int sample_rate = (int)sampleRate * 2;
|
||||
int bclk = sample_rate * 64 * 2;
|
||||
int mclk = (I2S_BUG_MAGIC / bclk) * bclk;
|
||||
|
||||
i2s_config_t i2s_config = {
|
||||
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX),
|
||||
.sample_rate = (uint32_t) sample_rate,
|
||||
.bits_per_sample = (i2s_bits_per_sample_t)32,
|
||||
.sample_rate = (uint32_t)sample_rate,
|
||||
.bits_per_sample = (i2s_bits_per_sample_t)(bitDepth * 2),
|
||||
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
|
||||
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
|
||||
.intr_alloc_flags = 0,
|
||||
@@ -100,18 +102,14 @@ void SPDIFAudioSink::initialize(uint16_t sampleRate) {
|
||||
.data_out_num = spdifPin,
|
||||
.data_in_num = -1,
|
||||
};
|
||||
i2s_driver_install((i2s_port_t)0, &i2s_config, 0, NULL);
|
||||
i2s_set_pin((i2s_port_t)0, &pin_config);
|
||||
}
|
||||
|
||||
SPDIFAudioSink::~SPDIFAudioSink()
|
||||
{
|
||||
}
|
||||
|
||||
bool SPDIFAudioSink::setRate(uint16_t sampleRate) {
|
||||
i2s_driver_uninstall((i2s_port_t)0);
|
||||
this->initialize(sampleRate);
|
||||
return true;
|
||||
int err = i2s_driver_install((i2s_port_t)0, &i2s_config, 0, nullptr);
|
||||
i2s_set_pin((i2s_port_t)0, &pin_config);
|
||||
return !err;
|
||||
}
|
||||
|
||||
SPDIFAudioSink::~SPDIFAudioSink() {
|
||||
i2s_driver_uninstall((i2s_port_t)0);
|
||||
}
|
||||
|
||||
int num_frames = 0;
|
||||
|
||||
@@ -3,10 +3,13 @@
|
||||
PortAudioSink::PortAudioSink()
|
||||
{
|
||||
Pa_Initialize();
|
||||
this->initialize(44100);
|
||||
this->setParams(44100, 2, 16);
|
||||
}
|
||||
|
||||
void PortAudioSink::initialize(uint16_t sampleRate) {
|
||||
bool PortAudioSink::setParams(uint32_t sampleRate, uint8_t channelCount, uint8_t bitDepth) {
|
||||
if (stream) {
|
||||
Pa_StopStream(stream);
|
||||
}
|
||||
PaStreamParameters outputParameters;
|
||||
outputParameters.device = Pa_GetDefaultOutputDevice();
|
||||
if (outputParameters.device == paNoDevice) {
|
||||
@@ -15,8 +18,24 @@ void PortAudioSink::initialize(uint16_t sampleRate) {
|
||||
}
|
||||
printf("PortAudio: Default audio device not found!\n");
|
||||
|
||||
outputParameters.channelCount = 2; /* stereo output */
|
||||
outputParameters.sampleFormat = paInt16; /* 32 bit floating point output */
|
||||
outputParameters.channelCount = channelCount;
|
||||
switch (bitDepth) {
|
||||
case 32:
|
||||
outputParameters.sampleFormat = paInt32;
|
||||
break;
|
||||
case 24:
|
||||
outputParameters.sampleFormat = paInt24;
|
||||
break;
|
||||
case 16:
|
||||
outputParameters.sampleFormat = paInt16;
|
||||
break;
|
||||
case 8:
|
||||
outputParameters.sampleFormat = paInt8;
|
||||
break;
|
||||
default:
|
||||
outputParameters.sampleFormat = paInt16;
|
||||
break;
|
||||
}
|
||||
outputParameters.suggestedLatency = 0.050;
|
||||
outputParameters.hostApiSpecificStreamInfo = NULL;
|
||||
|
||||
@@ -25,12 +44,13 @@ void PortAudioSink::initialize(uint16_t sampleRate) {
|
||||
NULL,
|
||||
&outputParameters,
|
||||
sampleRate,
|
||||
4096 / 4,
|
||||
4096 / (channelCount * bitDepth / 8),
|
||||
paClipOff,
|
||||
NULL, // blocking api
|
||||
NULL
|
||||
);
|
||||
Pa_StartStream(stream);
|
||||
return !err;
|
||||
}
|
||||
|
||||
PortAudioSink::~PortAudioSink()
|
||||
@@ -39,14 +59,6 @@ PortAudioSink::~PortAudioSink()
|
||||
Pa_Terminate();
|
||||
}
|
||||
|
||||
bool PortAudioSink::setRate(uint16_t sampleRate) {
|
||||
if (Pa_GetStreamInfo(stream)->sampleRate != sampleRate) {
|
||||
Pa_StopStream(stream);
|
||||
this->initialize(sampleRate);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void PortAudioSink::feedPCMFrames(const uint8_t *buffer, size_t bytes)
|
||||
{
|
||||
Pa_WriteStream(stream, buffer, bytes / 4);
|
||||
|
||||
Reference in New Issue
Block a user