mirror of
https://github.com/sle118/squeezelite-esp32.git
synced 2025-12-26 17:38:29 +03:00
Compare commits
7 Commits
SqueezeAmp
...
I2S-4MFlas
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cb47ec855b | ||
|
|
787a5d9a6e | ||
|
|
7b9deb795c | ||
|
|
4b1f8a8d4b | ||
|
|
4f8661100b | ||
|
|
6b2eb1b3c0 | ||
|
|
f3593fa2f4 |
11
CHANGELOG
11
CHANGELOG
@@ -1,8 +1,17 @@
|
||||
2024-01-27
|
||||
- complete libflac fix and add chaining enablement
|
||||
- fixed stream Ogg demux issue with unknown granule
|
||||
|
||||
2024-01-19
|
||||
- fixed libflac with OggFlac
|
||||
- AirPlay missed frame logging
|
||||
|
||||
2024-01-16
|
||||
- catch-up with cspot latest
|
||||
- refactor airplay flush/first packet
|
||||
- new libFLAC that supports multi-stream OggFlac
|
||||
- fix output threshold
|
||||
- log missed frames
|
||||
|
||||
2024-01-10
|
||||
- add OggFlac to stream metadata
|
||||
@@ -26,7 +35,7 @@
|
||||
- force gpio_pad_select_gpio in dac_controlset in case somebody uses UART gpio's (or other pre-programmed)
|
||||
|
||||
2023-11-08
|
||||
- execute dac_controlset even whne there is no i2s (for gpio)
|
||||
- execute dac_controlset even when there is no i2s (for gpio)
|
||||
|
||||
2023-11-07
|
||||
- led-vu gain + misc fixes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* libFLAC - Free Lossless Audio Codec library
|
||||
* Copyright (C) 2000-2009 Josh Coalson
|
||||
* Copyright (C) 2011-2022 Xiph.Org Foundation
|
||||
* Copyright (C) 2011-2023 Xiph.Org Foundation
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -782,6 +782,25 @@ FLAC_API void FLAC__stream_decoder_delete(FLAC__StreamDecoder *decoder);
|
||||
*/
|
||||
FLAC_API FLAC__bool FLAC__stream_decoder_set_ogg_serial_number(FLAC__StreamDecoder *decoder, long serial_number);
|
||||
|
||||
/** Set the "allow Ogg chaining" flag. If set, the Ogg decoder will
|
||||
* prepare to receive a new stream once the last Ogg page arrives for
|
||||
* the stream encapsulating the FLAC audio data. This can be used to
|
||||
* support chained Ogg FLAC streams; a new \c STREAMINFO signals the
|
||||
* beginning of a new stream.
|
||||
*
|
||||
* \note
|
||||
* This function has no effect with native FLAC decoding.
|
||||
*
|
||||
* \default \c false
|
||||
* \param decoder A decoder instance to set.
|
||||
* \param allow Whether to allow chained streams.
|
||||
* \assert
|
||||
* \code decoder != NULL \endcode
|
||||
* \retval FLAC__bool
|
||||
* \c false if the decoder is already initialized, else \c true.
|
||||
*/
|
||||
FLAC_API FLAC__bool FLAC__stream_decoder_set_ogg_chaining(FLAC__StreamDecoder* decoder, FLAC__bool value);
|
||||
|
||||
/** Set the "MD5 signature checking" flag. If \c true, the decoder will
|
||||
* compute the MD5 signature of the unencoded audio data while decoding
|
||||
* and compare it to the signature from the STREAMINFO block, if it
|
||||
@@ -906,6 +925,17 @@ FLAC_API FLAC__StreamDecoderState FLAC__stream_decoder_get_state(const FLAC__Str
|
||||
*/
|
||||
FLAC_API const char *FLAC__stream_decoder_get_resolved_state_string(const FLAC__StreamDecoder *decoder);
|
||||
|
||||
/** Get the "allow Ogg chaining" flag as described in
|
||||
* \code FLAC__stream_decoder_set_ogg_chaining \endcode.
|
||||
*
|
||||
* \param decoder A decoder instance to query.
|
||||
* \assert
|
||||
* \code decoder != NULL \endcode
|
||||
* \retval FLAC__bool
|
||||
* See above.
|
||||
*/
|
||||
FLAC_API FLAC__bool FLAC__stream_decoder_get_ogg_chaining(const FLAC__StreamDecoder* decoder);
|
||||
|
||||
/** Get the "MD5 signature checking" flag.
|
||||
* This is the value of the setting, not whether or not the decoder is
|
||||
* currently checking the MD5 (remember, it can be turned off automatically
|
||||
|
||||
Binary file not shown.
@@ -96,6 +96,7 @@ typedef struct __attribute__((__packed__)) audio_buffer_entry { // decoded aud
|
||||
u16_t len;
|
||||
u8_t ready;
|
||||
u8_t allocated;
|
||||
u8_t missed;
|
||||
} abuf_t;
|
||||
|
||||
typedef struct rtp_s {
|
||||
@@ -477,10 +478,11 @@ static void buffer_put_packet(rtp_t *ctx, seq_t seqno, unsigned rtptime, bool fi
|
||||
u32_t playtime = ctx->synchro.time + ((rtptime - ctx->synchro.rtp) * 10) / (RAOP_SAMPLE_RATE / 100);
|
||||
ctx->cmd_cb(RAOP_PLAY, playtime);
|
||||
}
|
||||
|
||||
abuf = ctx->audio_buffer + BUFIDX(seqno);
|
||||
|
||||
if (seqno == (u16_t) (ctx->ab_write+1)) {
|
||||
// expected packet
|
||||
abuf = ctx->audio_buffer + BUFIDX(seqno);
|
||||
ctx->ab_write = seqno;
|
||||
LOG_SDEBUG("packet expected seqno:%hu rtptime:%u (W:%hu R:%hu)", seqno, rtptime, ctx->ab_write, ctx->ab_read);
|
||||
} else if (seq_order(ctx->ab_write, seqno)) {
|
||||
@@ -504,16 +506,15 @@ static void buffer_put_packet(rtp_t *ctx, seq_t seqno, unsigned rtptime, bool fi
|
||||
LOG_DEBUG("[%p]: packet newer seqno:%hu rtptime:%u (W:%hu R:%hu)", ctx, seqno, rtptime, ctx->ab_write, ctx->ab_read);
|
||||
}
|
||||
|
||||
abuf = ctx->audio_buffer + BUFIDX(seqno);
|
||||
ctx->ab_write = seqno;
|
||||
} else if (seq_order(ctx->ab_read, seqno + 1)) {
|
||||
// recovered packet, not yet sent
|
||||
abuf = ctx->audio_buffer + BUFIDX(seqno);
|
||||
ctx->resent_rec++;
|
||||
LOG_DEBUG("[%p]: packet recovered seqno:%hu rtptime:%u (W:%hu R:%hu)", ctx, seqno, rtptime, ctx->ab_write, ctx->ab_read);
|
||||
} else {
|
||||
// too late
|
||||
LOG_DEBUG("[%p]: packet too late seqno:%hu rtptime:%u (W:%hu R:%hu)", ctx, seqno, rtptime, ctx->ab_write, ctx->ab_read);
|
||||
// too late
|
||||
if (abuf->missed) LOG_INFO("[%p]: packet too late seqno:%hu rtptime:%u (W:%hu R:%hu)", ctx, seqno, rtptime, ctx->ab_write, ctx->ab_read);
|
||||
abuf = NULL;
|
||||
}
|
||||
|
||||
if (ctx->in_frames++ > 1000) {
|
||||
@@ -524,6 +525,7 @@ static void buffer_put_packet(rtp_t *ctx, seq_t seqno, unsigned rtptime, bool fi
|
||||
if (abuf) {
|
||||
alac_decode(ctx, abuf->data, data, len, &abuf->len);
|
||||
abuf->ready = 1;
|
||||
abuf->missed = 0;
|
||||
// this is the local rtptime when this frame is expected to play
|
||||
abuf->rtptime = rtptime;
|
||||
buffer_push_packet(ctx);
|
||||
@@ -567,6 +569,7 @@ static void buffer_push_packet(rtp_t *ctx) {
|
||||
LOG_DEBUG("[%p]: created zero frame (W:%hu R:%hu)", ctx, ctx->ab_write, ctx->ab_read);
|
||||
ctx->data_cb(silence_frame, ctx->frame_size * 4, playtime);
|
||||
ctx->silent_frames++;
|
||||
curframe->missed = 1;
|
||||
}
|
||||
} else if (curframe->ready) {
|
||||
ctx->data_cb((const u8_t*) curframe->data, curframe->len, playtime);
|
||||
|
||||
@@ -70,6 +70,7 @@ struct flac {
|
||||
);
|
||||
FLAC__bool (* FLAC__stream_decoder_process_single)(FLAC__StreamDecoder *decoder);
|
||||
FLAC__StreamDecoderState (* FLAC__stream_decoder_get_state)(const FLAC__StreamDecoder *decoder);
|
||||
FLAC__bool (*FLAC__stream_decoder_set_ogg_chaining)(FLAC__StreamDecoder* decoder, FLAC__bool allow);
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -140,8 +141,8 @@ static FLAC__StreamDecoderWriteStatus write_cb(const FLAC__StreamDecoder *decode
|
||||
FLAC__int32 *rptr = (FLAC__int32 *)buffer[channels > 1 ? 1 : 0];
|
||||
|
||||
if (decode.new_stream) {
|
||||
LOG_INFO("setting track_start");
|
||||
LOCK_O;
|
||||
LOG_INFO("setting track_start");
|
||||
output.track_start = outputbuf->writep;
|
||||
decode.new_stream = false;
|
||||
|
||||
@@ -256,6 +257,7 @@ static void flac_open(u8_t sample_size, u8_t sample_rate, u8_t channels, u8_t en
|
||||
|
||||
if ( f->container == 'o' ) {
|
||||
LOG_INFO("ogg/flac container - using init_ogg_stream");
|
||||
FLAC(f, stream_decoder_set_ogg_chaining, f->decoder, true);
|
||||
FLAC(f, stream_decoder_init_ogg_stream, f->decoder, &read_cb, NULL, NULL, NULL, NULL, &write_cb, NULL, &error_cb, NULL);
|
||||
} else {
|
||||
FLAC(f, stream_decoder_init_stream, f->decoder, &read_cb, NULL, NULL, NULL, NULL, &write_cb, NULL, &error_cb, NULL);
|
||||
@@ -298,6 +300,7 @@ static bool load_flac() {
|
||||
f->FLAC__stream_decoder_init_ogg_stream = dlsym(handle, "FLAC__stream_decoder_init_ogg_stream");
|
||||
f->FLAC__stream_decoder_process_single = dlsym(handle, "FLAC__stream_decoder_process_single");
|
||||
f->FLAC__stream_decoder_get_state = dlsym(handle, "FLAC__stream_decoder_get_state");
|
||||
f->FLAC__stream_decoder_set_ogg_chaining = dlsym(handle, "FLAC__stream_decoder_set_ogg_chaining");
|
||||
|
||||
if ((err = dlerror()) != NULL) {
|
||||
LOG_INFO("dlerror: %s", err);
|
||||
|
||||
@@ -194,7 +194,7 @@ static int read_opus_header(void) {
|
||||
// nothing has been found and we have no more bytes, come back later
|
||||
if (status <= 0) break;
|
||||
|
||||
// always set stream serialno if we have a new one
|
||||
// always set stream serialno if we have a new one (no multiplexed streams)
|
||||
if (OG(&go, page_bos, &u->page)) OG(&go, stream_reset_serialno, &u->state, OG(&go, page_serialno, &u->page));
|
||||
|
||||
// bring new page in if we want it (otherwise we're just skipping)
|
||||
|
||||
@@ -439,7 +439,7 @@ void output_init_i2s(log_level level, char *device, unsigned output_buf_size, ch
|
||||
static DRAM_ATTR StaticTask_t xTaskBuffer __attribute__ ((aligned (4)));
|
||||
static EXT_RAM_ATTR StackType_t xStack[OUTPUT_THREAD_STACK_SIZE] __attribute__ ((aligned (4)));
|
||||
output_i2s_task = xTaskCreateStaticPinnedToCore( (TaskFunction_t) output_thread_i2s, "output_i2s", OUTPUT_THREAD_STACK_SIZE,
|
||||
NULL, CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT + 1, xStack, &xTaskBuffer, 0 );
|
||||
NULL, CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT + 10, xStack, &xTaskBuffer, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -414,8 +414,8 @@ static void process_strm(u8_t *pkt, int len) {
|
||||
output.fade_secs = strm->transition_period;
|
||||
output.invert = (strm->flags & 0x03) == 0x03;
|
||||
output.channels = (strm->flags & 0x0c) >> 2;
|
||||
UNLOCK_O;
|
||||
LOG_DEBUG("set fade: %u, channels: %u, invert: %u", output.fade_mode, output.channels, output.invert);
|
||||
UNLOCK_O;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -63,9 +63,9 @@ struct EXT_RAM_ATTR streamstate stream;
|
||||
|
||||
static EXT_RAM_ATTR struct {
|
||||
bool flac;
|
||||
u64_t serial;
|
||||
enum { OGG_OFF, OGG_SYNC, OGG_HEADER, OGG_SEGMENTS, OGG_PAGE } state;
|
||||
size_t want, miss, match;
|
||||
u64_t granule;
|
||||
u8_t* data, segments[255];
|
||||
#pragma pack(push, 1)
|
||||
struct {
|
||||
@@ -237,19 +237,22 @@ static void stream_ogg(size_t n) {
|
||||
// calculate size of page using lacing values
|
||||
for (size_t i = 0; i < ogg.want; i++) ogg.miss += ogg.data[i];
|
||||
ogg.want = ogg.miss;
|
||||
|
||||
// acquire serial number when we are looking for headers and hit a bos
|
||||
if (ogg.serial == ULLONG_MAX && (ogg.header.type & 0x02)) ogg.serial = ogg.header.serial;
|
||||
|
||||
if (ogg.header.granule == 0 || (ogg.header.granule == -1 && ogg.granule == 0)) {
|
||||
// granule 0 means a new stream, so let's look into it
|
||||
ogg.state = OGG_PAGE;
|
||||
ogg.data = malloc(ogg.want);
|
||||
} else {
|
||||
// we have overshot and missed header, reset serial number to restart search (O and -1 are le/be)
|
||||
if (ogg.header.serial == ogg.serial && ogg.header.granule && ogg.header.granule != -1) ogg.serial = ULLONG_MAX;
|
||||
|
||||
// not our serial (the above protected us from granule > 0)
|
||||
if (ogg.header.serial != ogg.serial) {
|
||||
// otherwise, jump over data
|
||||
ogg.state = OGG_SYNC;
|
||||
ogg.data = NULL;
|
||||
} else {
|
||||
ogg.state = OGG_PAGE;
|
||||
ogg.data = malloc(ogg.want);
|
||||
}
|
||||
|
||||
// memorize granule for next page
|
||||
if (ogg.header.granule != -1) ogg.granule = ogg.header.granule;
|
||||
break;
|
||||
case OGG_PAGE: {
|
||||
char** tag = (char* []){ "\x3vorbis", "OpusTags", NULL };
|
||||
@@ -289,6 +292,7 @@ static void stream_ogg(size_t n) {
|
||||
}
|
||||
|
||||
ogg.flac = false;
|
||||
ogg.serial = ULLONG_MAX;
|
||||
stream.meta_send = true;
|
||||
wake_controller();
|
||||
LOG_INFO("Ogg metadata length: %u", stream.header_len - 3);
|
||||
@@ -736,6 +740,7 @@ void stream_sock(u32_t ip, u16_t port, bool use_ssl, bool use_ogg, const char *h
|
||||
ogg.miss = ogg.match = 0;
|
||||
ogg.state = use_ogg ? OGG_SYNC : OGG_OFF;
|
||||
ogg.flac = false;
|
||||
ogg.serial = ULLONG_MAX;
|
||||
|
||||
UNLOCK;
|
||||
}
|
||||
|
||||
@@ -201,7 +201,7 @@ static int read_vorbis_header(void) {
|
||||
// nothing has been found and we have no more bytes, come back later
|
||||
if (status <= 0) break;
|
||||
|
||||
// always set stream serialno if we have a new one
|
||||
// always set stream serialno if we have a new one (no multiplexed streams)
|
||||
if (OG(&go, page_bos, &v->page)) OG(&go, stream_reset_serialno, &v->state, OG(&go, page_serialno, &v->page));
|
||||
|
||||
// bring new page in if we want it (otherwise we're just skipping)
|
||||
|
||||
BIN
server_certs/DigiCertGlobalRootCA.crt.77
Normal file
BIN
server_certs/DigiCertGlobalRootCA.crt.77
Normal file
Binary file not shown.
BIN
server_certs/DigiCertGlobalRootCA.crt.78
Normal file
BIN
server_certs/DigiCertGlobalRootCA.crt.78
Normal file
Binary file not shown.
BIN
server_certs/r2m01.cer.49
Normal file
BIN
server_certs/r2m01.cer.49
Normal file
Binary file not shown.
BIN
server_certs/r2m01.cer.50
Normal file
BIN
server_certs/r2m01.cer.50
Normal file
Binary file not shown.
Reference in New Issue
Block a user