mirror of
https://github.com/sle118/squeezelite-esp32.git
synced 2025-12-06 19:47:02 +03:00
bring ogg parsing context purely inside stream.c - release
This commit is contained in:
@@ -580,20 +580,6 @@ struct streamstate {
|
|||||||
u32_t meta_next;
|
u32_t meta_next;
|
||||||
u32_t meta_left;
|
u32_t meta_left;
|
||||||
bool meta_send;
|
bool meta_send;
|
||||||
struct {
|
|
||||||
enum { STREAM_OGG_OFF, STREAM_OGG_SYNC, STREAM_OGG_HEADER, STREAM_OGG_SEGMENTS, STREAM_OGG_PAGE } state;
|
|
||||||
u32_t want, miss, match;
|
|
||||||
u8_t* data, segments[255];
|
|
||||||
#pragma pack(push, 1)
|
|
||||||
struct {
|
|
||||||
char pattern[4];
|
|
||||||
u8_t version, type;
|
|
||||||
u64_t granule;
|
|
||||||
u32_t serial, page, checksum;
|
|
||||||
u8_t count;
|
|
||||||
} header;
|
|
||||||
} ogg;
|
|
||||||
#pragma pack(pop)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void stream_init(log_level level, unsigned stream_buf_size);
|
void stream_init(log_level level, unsigned stream_buf_size);
|
||||||
|
|||||||
@@ -61,6 +61,21 @@ static sockfd fd;
|
|||||||
|
|
||||||
struct EXT_RAM_ATTR streamstate stream;
|
struct EXT_RAM_ATTR streamstate stream;
|
||||||
|
|
||||||
|
static EXT_RAM_ATTR struct {
|
||||||
|
enum { OGG_OFF, OGG_SYNC, OGG_HEADER, OGG_SEGMENTS, OGG_PAGE } state;
|
||||||
|
u32_t want, miss, match;
|
||||||
|
u8_t* data, segments[255];
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
struct {
|
||||||
|
char pattern[4];
|
||||||
|
u8_t version, type;
|
||||||
|
u64_t granule;
|
||||||
|
u32_t serial, page, checksum;
|
||||||
|
u8_t count;
|
||||||
|
} header;
|
||||||
|
#pragma pack(pop)
|
||||||
|
} ogg;
|
||||||
|
|
||||||
#if USE_SSL
|
#if USE_SSL
|
||||||
static SSL_CTX *SSLctx;
|
static SSL_CTX *SSLctx;
|
||||||
SSL *ssl;
|
SSL *ssl;
|
||||||
@@ -148,8 +163,8 @@ static bool running = true;
|
|||||||
static void _disconnect(stream_state state, disconnect_code disconnect) {
|
static void _disconnect(stream_state state, disconnect_code disconnect) {
|
||||||
stream.state = state;
|
stream.state = state;
|
||||||
stream.disconnect = disconnect;
|
stream.disconnect = disconnect;
|
||||||
if (stream.ogg.state == STREAM_OGG_PAGE && stream.ogg.data) free(stream.ogg.data);
|
if (ogg.state == OGG_PAGE && ogg.data) free(ogg.data);
|
||||||
stream.ogg.data = NULL;
|
ogg.data = NULL;
|
||||||
#if USE_SSL
|
#if USE_SSL
|
||||||
if (ssl) {
|
if (ssl) {
|
||||||
SSL_shutdown(ssl);
|
SSL_shutdown(ssl);
|
||||||
@@ -169,74 +184,74 @@ static u32_t memfind(const u8_t* haystack, u32_t n, const char* needle, u32_t le
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void stream_ogg(size_t n) {
|
static void stream_ogg(size_t n) {
|
||||||
if (stream.ogg.state == STREAM_OGG_OFF) return;
|
if (ogg.state == OGG_OFF) return;
|
||||||
u8_t* p = streambuf->writep;
|
u8_t* p = streambuf->writep;
|
||||||
|
|
||||||
while (n) {
|
while (n) {
|
||||||
size_t consumed = min(stream.ogg.miss, n);
|
size_t consumed = min(ogg.miss, n);
|
||||||
|
|
||||||
// copy as many bytes as possible and come back later if we do'nt have enough
|
// copy as many bytes as possible and come back later if we do'nt have enough
|
||||||
if (stream.ogg.data) {
|
if (ogg.data) {
|
||||||
memcpy(stream.ogg.data + stream.ogg.want - stream.ogg.miss, p, consumed);
|
memcpy(ogg.data + ogg.want - ogg.miss, p, consumed);
|
||||||
stream.ogg.miss -= consumed;
|
ogg.miss -= consumed;
|
||||||
if (stream.ogg.miss) return;
|
if (ogg.miss) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// we have what we want, let's parse
|
// we have what we want, let's parse
|
||||||
switch (stream.ogg.state) {
|
switch (ogg.state) {
|
||||||
case STREAM_OGG_SYNC: {
|
case OGG_SYNC: {
|
||||||
stream.ogg.miss -= consumed;
|
ogg.miss -= consumed;
|
||||||
if (consumed) break;
|
if (consumed) break;
|
||||||
|
|
||||||
// we have to memorize position in case any of last 3 bytes match...
|
// we have to memorize position in case any of last 3 bytes match...
|
||||||
int pos = memfind(p, n, "OggS", 4, &stream.ogg.match);
|
int pos = memfind(p, n, "OggS", 4, &ogg.match);
|
||||||
if (stream.ogg.match == 4) {
|
if (ogg.match == 4) {
|
||||||
consumed = pos - stream.ogg.match;
|
consumed = pos - ogg.match;
|
||||||
stream.ogg.state = STREAM_OGG_HEADER;
|
ogg.state = OGG_HEADER;
|
||||||
stream.ogg.miss = stream.ogg.want = sizeof(stream.ogg.header);
|
ogg.miss = ogg.want = sizeof(ogg.header);
|
||||||
stream.ogg.data = (u8_t*) &stream.ogg.header;
|
ogg.data = (u8_t*) &ogg.header;
|
||||||
stream.ogg.match = 0;
|
ogg.match = 0;
|
||||||
} else {
|
} else {
|
||||||
LOG_INFO("OggS not at expected position");
|
LOG_INFO("OggS not at expected position");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case STREAM_OGG_HEADER:
|
case OGG_HEADER:
|
||||||
if (!memcmp(stream.ogg.header.pattern, "OggS", 4)) {
|
if (!memcmp(ogg.header.pattern, "OggS", 4)) {
|
||||||
stream.ogg.miss = stream.ogg.want = stream.ogg.header.count;
|
ogg.miss = ogg.want = ogg.header.count;
|
||||||
stream.ogg.data = stream.ogg.segments;
|
ogg.data = ogg.segments;
|
||||||
stream.ogg.state = STREAM_OGG_SEGMENTS;
|
ogg.state = OGG_SEGMENTS;
|
||||||
} else {
|
} else {
|
||||||
stream.ogg.state = STREAM_OGG_SYNC;
|
ogg.state = OGG_SYNC;
|
||||||
stream.ogg.data = NULL;
|
ogg.data = NULL;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case STREAM_OGG_SEGMENTS:
|
case OGG_SEGMENTS:
|
||||||
// calculate size of page using lacing values
|
// calculate size of page using lacing values
|
||||||
for (int i = 0; i < stream.ogg.want; i++) stream.ogg.miss += stream.ogg.data[i];
|
for (int i = 0; i < ogg.want; i++) ogg.miss += ogg.data[i];
|
||||||
stream.ogg.want = stream.ogg.miss;
|
ogg.want = ogg.miss;
|
||||||
|
|
||||||
if (stream.ogg.header.granule == 0) {
|
if (ogg.header.granule == 0) {
|
||||||
// granule 0 means a new stream, so let's look into it
|
// granule 0 means a new stream, so let's look into it
|
||||||
stream.ogg.state = STREAM_OGG_PAGE;
|
ogg.state = OGG_PAGE;
|
||||||
stream.ogg.data = malloc(stream.ogg.want);
|
ogg.data = malloc(ogg.want);
|
||||||
} else {
|
} else {
|
||||||
// otherwise, jump over data
|
// otherwise, jump over data
|
||||||
stream.ogg.state = STREAM_OGG_SYNC;
|
ogg.state = OGG_SYNC;
|
||||||
stream.ogg.data = NULL;
|
ogg.data = NULL;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case STREAM_OGG_PAGE: {
|
case OGG_PAGE: {
|
||||||
u32_t offset = 0;
|
u32_t offset = 0;
|
||||||
|
|
||||||
// try to find one of valid Ogg pattern (vorbis, opus)
|
// try to find one of valid Ogg pattern (vorbis, opus)
|
||||||
for (char** tag = (char*[]) { "\x3vorbis", "OpusTags", NULL }; *tag; tag++, offset = 0) {
|
for (char** tag = (char*[]) { "\x3vorbis", "OpusTags", NULL }; *tag; tag++, offset = 0) {
|
||||||
u32_t pos = memfind(stream.ogg.data, stream.ogg.want, *tag, strlen(*tag), &offset);
|
u32_t pos = memfind(ogg.data, ogg.want, *tag, strlen(*tag), &offset);
|
||||||
if (offset != strlen(*tag)) continue;
|
if (offset != strlen(*tag)) continue;
|
||||||
|
|
||||||
// u32:len,char[]:vendorId, u32:N, N x (u32:len,char[]:comment)
|
// u32:len,char[]:vendorId, u32:N, N x (u32:len,char[]:comment)
|
||||||
char* p = (char*) stream.ogg.data + pos;
|
char* p = (char*) ogg.data + pos;
|
||||||
p += *p + 4;
|
p += *p + 4;
|
||||||
u32_t count = *p;
|
u32_t count = *p;
|
||||||
p += 4;
|
p += 4;
|
||||||
@@ -264,8 +279,8 @@ static void stream_ogg(size_t n) {
|
|||||||
LOG_INFO("Ogg metadata length: %u", stream.header_len - 3);
|
LOG_INFO("Ogg metadata length: %u", stream.header_len - 3);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
free(stream.ogg.data);
|
free(ogg.data);
|
||||||
stream.ogg.state = STREAM_OGG_SYNC;
|
ogg.state = OGG_SYNC;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -703,8 +718,8 @@ void stream_sock(u32_t ip, u16_t port, char codec, const char *header, size_t he
|
|||||||
stream.bytes = 0;
|
stream.bytes = 0;
|
||||||
stream.threshold = threshold;
|
stream.threshold = threshold;
|
||||||
|
|
||||||
stream.ogg.miss = stream.ogg.match = 0;
|
ogg.miss = ogg.match = 0;
|
||||||
stream.ogg.state = (codec == 'o' || codec == 'p') ? STREAM_OGG_SYNC : STREAM_OGG_OFF;
|
ogg.state = (codec == 'o' || codec == 'p') ? OGG_SYNC : OGG_OFF;
|
||||||
|
|
||||||
UNLOCK;
|
UNLOCK;
|
||||||
}
|
}
|
||||||
@@ -725,8 +740,8 @@ bool stream_disconnect(void) {
|
|||||||
disc = true;
|
disc = true;
|
||||||
}
|
}
|
||||||
stream.state = STOPPED;
|
stream.state = STOPPED;
|
||||||
if (stream.ogg.state == STREAM_OGG_PAGE && stream.ogg.data) free(stream.ogg.data);
|
if (ogg.state == OGG_PAGE && ogg.data) free(ogg.data);
|
||||||
stream.ogg.data = NULL;
|
ogg.data = NULL;
|
||||||
UNLOCK;
|
UNLOCK;
|
||||||
return disc;
|
return disc;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user