diff --git a/components/squeezelite/squeezelite.h b/components/squeezelite/squeezelite.h index 7df800d0..5d2a4669 100644 --- a/components/squeezelite/squeezelite.h +++ b/components/squeezelite/squeezelite.h @@ -580,20 +580,6 @@ struct streamstate { u32_t meta_next; u32_t meta_left; 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); diff --git a/components/squeezelite/stream.c b/components/squeezelite/stream.c index bc97fc5e..a6525642 100644 --- a/components/squeezelite/stream.c +++ b/components/squeezelite/stream.c @@ -61,6 +61,21 @@ static sockfd fd; 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 static SSL_CTX *SSLctx; SSL *ssl; @@ -148,8 +163,8 @@ static bool running = true; static void _disconnect(stream_state state, disconnect_code disconnect) { stream.state = state; stream.disconnect = disconnect; - if (stream.ogg.state == STREAM_OGG_PAGE && stream.ogg.data) free(stream.ogg.data); - stream.ogg.data = NULL; + if (ogg.state == OGG_PAGE && ogg.data) free(ogg.data); + ogg.data = NULL; #if USE_SSL if (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) { - if (stream.ogg.state == STREAM_OGG_OFF) return; + if (ogg.state == OGG_OFF) return; u8_t* p = streambuf->writep; 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 - if (stream.ogg.data) { - memcpy(stream.ogg.data + stream.ogg.want - stream.ogg.miss, p, consumed); - stream.ogg.miss -= consumed; - if (stream.ogg.miss) return; + if (ogg.data) { + memcpy(ogg.data + ogg.want - ogg.miss, p, consumed); + ogg.miss -= consumed; + if (ogg.miss) return; } // we have what we want, let's parse - switch (stream.ogg.state) { - case STREAM_OGG_SYNC: { - stream.ogg.miss -= consumed; + switch (ogg.state) { + case OGG_SYNC: { + ogg.miss -= consumed; if (consumed) break; // we have to memorize position in case any of last 3 bytes match... - int pos = memfind(p, n, "OggS", 4, &stream.ogg.match); - if (stream.ogg.match == 4) { - consumed = pos - stream.ogg.match; - stream.ogg.state = STREAM_OGG_HEADER; - stream.ogg.miss = stream.ogg.want = sizeof(stream.ogg.header); - stream.ogg.data = (u8_t*) &stream.ogg.header; - stream.ogg.match = 0; + int pos = memfind(p, n, "OggS", 4, &ogg.match); + if (ogg.match == 4) { + consumed = pos - ogg.match; + ogg.state = OGG_HEADER; + ogg.miss = ogg.want = sizeof(ogg.header); + ogg.data = (u8_t*) &ogg.header; + ogg.match = 0; } else { LOG_INFO("OggS not at expected position"); return; } break; } - case STREAM_OGG_HEADER: - if (!memcmp(stream.ogg.header.pattern, "OggS", 4)) { - stream.ogg.miss = stream.ogg.want = stream.ogg.header.count; - stream.ogg.data = stream.ogg.segments; - stream.ogg.state = STREAM_OGG_SEGMENTS; + case OGG_HEADER: + if (!memcmp(ogg.header.pattern, "OggS", 4)) { + ogg.miss = ogg.want = ogg.header.count; + ogg.data = ogg.segments; + ogg.state = OGG_SEGMENTS; } else { - stream.ogg.state = STREAM_OGG_SYNC; - stream.ogg.data = NULL; + ogg.state = OGG_SYNC; + ogg.data = NULL; } break; - case STREAM_OGG_SEGMENTS: + case OGG_SEGMENTS: // calculate size of page using lacing values - for (int i = 0; i < stream.ogg.want; i++) stream.ogg.miss += stream.ogg.data[i]; - stream.ogg.want = stream.ogg.miss; + for (int i = 0; i < ogg.want; i++) ogg.miss += ogg.data[i]; + 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 - stream.ogg.state = STREAM_OGG_PAGE; - stream.ogg.data = malloc(stream.ogg.want); + ogg.state = OGG_PAGE; + ogg.data = malloc(ogg.want); } else { // otherwise, jump over data - stream.ogg.state = STREAM_OGG_SYNC; - stream.ogg.data = NULL; + ogg.state = OGG_SYNC; + ogg.data = NULL; } break; - case STREAM_OGG_PAGE: { + case OGG_PAGE: { u32_t offset = 0; // try to find one of valid Ogg pattern (vorbis, opus) 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; // 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; u32_t count = *p; p += 4; @@ -264,8 +279,8 @@ static void stream_ogg(size_t n) { LOG_INFO("Ogg metadata length: %u", stream.header_len - 3); break; } - free(stream.ogg.data); - stream.ogg.state = STREAM_OGG_SYNC; + free(ogg.data); + ogg.state = OGG_SYNC; break; } 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.threshold = threshold; - stream.ogg.miss = stream.ogg.match = 0; - stream.ogg.state = (codec == 'o' || codec == 'p') ? STREAM_OGG_SYNC : STREAM_OGG_OFF; + ogg.miss = ogg.match = 0; + ogg.state = (codec == 'o' || codec == 'p') ? OGG_SYNC : OGG_OFF; UNLOCK; } @@ -725,8 +740,8 @@ bool stream_disconnect(void) { disc = true; } stream.state = STOPPED; - if (stream.ogg.state == STREAM_OGG_PAGE && stream.ogg.data) free(stream.ogg.data); - stream.ogg.data = NULL; + if (ogg.state == OGG_PAGE && ogg.data) free(ogg.data); + ogg.data = NULL; UNLOCK; return disc; }