mirror of
https://github.com/sle118/squeezelite-esp32.git
synced 2026-01-27 12:50:49 +03:00
See CHANGELOG - release
This commit is contained in:
@@ -126,11 +126,6 @@ typedef struct rtp_s {
|
||||
u32_t rtp, time;
|
||||
u8_t status;
|
||||
} synchro;
|
||||
struct {
|
||||
u32_t time;
|
||||
seq_t seqno;
|
||||
u32_t rtptime;
|
||||
} record;
|
||||
int latency; // rtp hold depth in samples
|
||||
u32_t resent_req, resent_rec; // total resent + recovered frames
|
||||
u32_t silent_frames; // total silence frames
|
||||
@@ -147,8 +142,8 @@ typedef struct rtp_s {
|
||||
#endif
|
||||
|
||||
struct alac_codec_s *alac_codec;
|
||||
int flush_seqno;
|
||||
bool playing;
|
||||
int first_seqno;
|
||||
enum { RTP_WAIT, RTP_STREAM, RTP_PLAY } state;
|
||||
int stalled;
|
||||
raop_data_cb_t data_cb;
|
||||
raop_cmd_cb_t cmd_cb;
|
||||
@@ -231,7 +226,7 @@ rtp_resp_t rtp_init(struct in_addr host, int latency, char *aeskey, char *aesiv,
|
||||
ctx->rtp_host.sin_family = AF_INET;
|
||||
ctx->rtp_host.sin_addr.s_addr = INADDR_ANY;
|
||||
pthread_mutex_init(&ctx->ab_mutex, 0);
|
||||
ctx->flush_seqno = -1;
|
||||
ctx->first_seqno = -1;
|
||||
ctx->latency = latency;
|
||||
ctx->ab_read = ctx->ab_write;
|
||||
|
||||
@@ -339,24 +334,23 @@ void rtp_end(rtp_t *ctx)
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
bool rtp_flush(rtp_t *ctx, unsigned short seqno, unsigned int rtptime, bool exit_locked)
|
||||
{
|
||||
bool rc = true;
|
||||
u32_t now = gettime_ms();
|
||||
{
|
||||
pthread_mutex_lock(&ctx->ab_mutex);
|
||||
|
||||
// always store flush seqno as we only want stricly above it, even when equal to RECORD
|
||||
ctx->first_seqno = seqno;
|
||||
bool flushed = false;
|
||||
|
||||
if (now < ctx->record.time + 250 || (ctx->record.seqno == seqno && ctx->record.rtptime == rtptime)) {
|
||||
rc = false;
|
||||
LOG_ERROR("[%p]: FLUSH ignored as same as RECORD (%hu - %u)", ctx, seqno, rtptime);
|
||||
} else {
|
||||
pthread_mutex_lock(&ctx->ab_mutex);
|
||||
buffer_reset(ctx->audio_buffer);
|
||||
ctx->playing = false;
|
||||
ctx->flush_seqno = seqno;
|
||||
if (!exit_locked) pthread_mutex_unlock(&ctx->ab_mutex);
|
||||
// no need to stop playing if recent or equal to record - but first_seqno is needed
|
||||
if (ctx->state == RTP_PLAY) {
|
||||
buffer_reset(ctx->audio_buffer);
|
||||
ctx->state = RTP_WAIT;
|
||||
flushed = true;
|
||||
LOG_INFO("[%p]: FLUSH packets below %hu - %u", ctx, seqno, rtptime);
|
||||
}
|
||||
|
||||
LOG_INFO("[%p]: flush %hu %u", ctx, seqno, rtptime);
|
||||
|
||||
return rc;
|
||||
|
||||
if (!exit_locked || !flushed) pthread_mutex_unlock(&ctx->ab_mutex);
|
||||
return flushed;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
@@ -367,11 +361,9 @@ void rtp_flush_release(rtp_t *ctx) {
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void rtp_record(rtp_t *ctx, unsigned short seqno, unsigned rtptime) {
|
||||
ctx->record.seqno = seqno;
|
||||
ctx->record.rtptime = rtptime;
|
||||
ctx->record.time = gettime_ms();
|
||||
|
||||
LOG_INFO("[%p]: record %hu %u", ctx, seqno, rtptime);
|
||||
ctx->first_seqno = (seqno || rtptime) ? seqno : -1;
|
||||
ctx->state = RTP_WAIT;
|
||||
LOG_INFO("[%p]: record %hu - %u", ctx, seqno, rtptime);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
@@ -442,26 +434,50 @@ static void alac_decode(rtp_t *ctx, s16_t *dest, char *buf, int len, u16_t *outs
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void buffer_put_packet(rtp_t *ctx, seq_t seqno, unsigned rtptime, bool first, char *data, int len) {
|
||||
abuf_t *abuf = NULL;
|
||||
u32_t playtime;
|
||||
|
||||
pthread_mutex_lock(&ctx->ab_mutex);
|
||||
|
||||
if (!ctx->playing) {
|
||||
if ((ctx->flush_seqno == -1 || seq_order(ctx->flush_seqno, seqno)) &&
|
||||
(ctx->synchro.status & RTP_SYNC) && (ctx->synchro.status & NTP_SYNC)) {
|
||||
ctx->ab_write = seqno-1;
|
||||
ctx->ab_read = seqno;
|
||||
ctx->flush_seqno = -1;
|
||||
ctx->playing = true;
|
||||
ctx->resent_req = ctx->resent_rec = ctx->silent_frames = ctx->discarded = 0;
|
||||
playtime = ctx->synchro.time + ((rtptime - ctx->synchro.rtp) * 10) / (RAOP_SAMPLE_RATE / 100);
|
||||
ctx->cmd_cb(RAOP_PLAY, playtime);
|
||||
} else {
|
||||
pthread_mutex_unlock(&ctx->ab_mutex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* if we have received a RECORD with a seqno, then this is the first allowed rtp sequence number
|
||||
* and we are in RTP_WAIT state. If seqno was 0, then we are waiting for a flush that will tell
|
||||
* us what should be our first allowed packet but we must accept everything, wait and clean when
|
||||
* we the it arrives. This means that first packet moves us to RTP_STREAM state where we accept
|
||||
* frames but wait for the FLUSH. If this was a FLUSH while playing, then we are also in RTP_WAIT
|
||||
* state but we do have an allowed seqno and we should not accept any frame before we have it */
|
||||
|
||||
// if we have a pending first seqno and we are below, always ignore it
|
||||
if (ctx->first_seqno != -1 && seq_order(seqno, ctx->first_seqno)) {
|
||||
pthread_mutex_unlock(&ctx->ab_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctx->state == RTP_WAIT) {
|
||||
ctx->ab_write = seqno - 1;
|
||||
ctx->ab_read = ctx->ab_write + 1;
|
||||
ctx->resent_req = ctx->resent_rec = ctx->silent_frames = ctx->discarded = 0;
|
||||
if (ctx->first_seqno != -1) {
|
||||
LOG_INFO("[%p]: 1st accepted packet:%d, now playing", ctx, seqno);
|
||||
ctx->state = RTP_PLAY;
|
||||
ctx->first_seqno = -1;
|
||||
u32_t playtime = ctx->synchro.time + ((rtptime - ctx->synchro.rtp) * 10) / (RAOP_SAMPLE_RATE / 100);
|
||||
ctx->cmd_cb(RAOP_PLAY, playtime);
|
||||
} else {
|
||||
ctx->state = RTP_STREAM;
|
||||
LOG_INFO("[%p]: 1st accepted packet:%hu, waiting for FLUSH", ctx, seqno);
|
||||
}
|
||||
} else if (ctx->state == RTP_STREAM && ctx->first_seqno != -1 && seq_order(ctx->first_seqno, seqno + 1)) {
|
||||
// now we're talking, but first discard all packets with a seqno below first_seqno AND not ready
|
||||
while (seq_order(ctx->ab_read, ctx->first_seqno) ||
|
||||
!ctx->audio_buffer[BUFIDX(ctx->ab_read)].ready) {
|
||||
ctx->audio_buffer[BUFIDX(ctx->ab_read)].ready = false;
|
||||
ctx->ab_read++;
|
||||
}
|
||||
LOG_INFO("[%p]: done waiting for FLUSH with packet:%d, now playing starting:%hu", ctx, seqno, ctx->ab_read);
|
||||
ctx->state = RTP_PLAY;
|
||||
ctx->first_seqno = -1;
|
||||
u32_t playtime = ctx->synchro.time + ((rtptime - ctx->synchro.rtp) * 10) / (RAOP_SAMPLE_RATE / 100);
|
||||
ctx->cmd_cb(RAOP_PLAY, playtime);
|
||||
}
|
||||
|
||||
if (seqno == (u16_t) (ctx->ab_write+1)) {
|
||||
// expected packet
|
||||
abuf = ctx->audio_buffer + BUFIDX(seqno);
|
||||
@@ -475,7 +491,7 @@ static void buffer_put_packet(rtp_t *ctx, seq_t seqno, unsigned rtptime, bool fi
|
||||
ctx->ab_read = seqno;
|
||||
} else {
|
||||
// request re-send missed frames and evaluate resent date as a whole *after*
|
||||
rtp_request_resend(ctx, ctx->ab_write + 1, seqno-1);
|
||||
if (ctx->state == RTP_PLAY) rtp_request_resend(ctx, ctx->ab_write + 1, seqno-1);
|
||||
|
||||
// resend date is after all requests have been sent
|
||||
u32_t now = gettime_ms();
|
||||
@@ -528,7 +544,7 @@ static void buffer_push_packet(rtp_t *ctx) {
|
||||
u32_t now, playtime, hold = max((ctx->latency * 1000) / (8 * RAOP_SAMPLE_RATE), 100);
|
||||
|
||||
// not ready to play yet
|
||||
if (!ctx->playing || ctx->synchro.status != (RTP_SYNC | NTP_SYNC)) return;
|
||||
if (ctx->state != RTP_PLAY || ctx->synchro.status != (RTP_SYNC | NTP_SYNC)) return;
|
||||
|
||||
// there is always at least one frame in the buffer
|
||||
do {
|
||||
|
||||
Reference in New Issue
Block a user