|  | @@ -82,7 +82,7 @@ static log_level 	*loglevel = &raop_loglevel;
 | 
	
		
			
				|  |  |  #define RTP_SYNC	(0x01)
 | 
	
		
			
				|  |  |  #define NTP_SYNC	(0x02)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -#define RESEND_TO	200
 | 
	
		
			
				|  |  | +#define RESEND_TO	250
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  enum { DATA = 0, CONTROL, TIMING };
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -149,6 +149,7 @@ typedef struct rtp_s {
 | 
	
		
			
				|  |  |  	struct alac_codec_s *alac_codec;
 | 
	
		
			
				|  |  |  	int flush_seqno;
 | 
	
		
			
				|  |  |  	bool playing;
 | 
	
		
			
				|  |  | +    int stalled;
 | 
	
		
			
				|  |  |  	raop_data_cb_t data_cb;
 | 
	
		
			
				|  |  |  	raop_cmd_cb_t cmd_cb;
 | 
	
		
			
				|  |  |  } rtp_t;
 | 
	
	
		
			
				|  | @@ -466,26 +467,27 @@ static void buffer_put_packet(rtp_t *ctx, seq_t seqno, unsigned rtptime, bool fi
 | 
	
		
			
				|  |  |  		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)) {
 | 
	
		
			
				|  |  | -		seq_t i;
 | 
	
		
			
				|  |  | -		u32_t now;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  		// newer than expected
 | 
	
		
			
				|  |  |  		if (ctx->latency && seq_order(ctx->latency / ctx->frame_size, seqno - ctx->ab_write - 1)) {
 | 
	
		
			
				|  |  | -			// only get rtp latency-1 frames back (last one is seqno)
 | 
	
		
			
				|  |  | -			LOG_WARN("[%p] too many missing frames %hu seq: %hu, (W:%hu R:%hu)", ctx, seqno - ctx->ab_write - 1, seqno, ctx->ab_write, ctx->ab_read);
 | 
	
		
			
				|  |  | -			ctx->ab_write = seqno - ctx->latency / ctx->frame_size;
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		// need to request re-send and adjust timing of gaps
 | 
	
		
			
				|  |  | -		rtp_request_resend(ctx, ctx->ab_write + 1, seqno-1);
 | 
	
		
			
				|  |  | -		for (now = gettime_ms(), i = ctx->ab_write + 1; seq_order(i, seqno); i++) {
 | 
	
		
			
				|  |  | -			ctx->audio_buffer[BUFIDX(i)].rtptime = rtptime - (seqno-i)*ctx->frame_size;
 | 
	
		
			
				|  |  | -			ctx->audio_buffer[BUFIDX(i)].last_resend = now;
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | +			// this is a shitstorm, reset buffer
 | 
	
		
			
				|  |  | +            LOG_WARN("[%p] too many missing frames %hu seq: %hu, (W:%hu R:%hu)", ctx, seqno - ctx->ab_write - 1, seqno, ctx->ab_write, ctx->ab_read);
 | 
	
		
			
				|  |  | +            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);
 | 
	
		
			
				|  |  | +            
 | 
	
		
			
				|  |  | +            // resend date is after all requests have been sent
 | 
	
		
			
				|  |  | +            u32_t now = gettime_ms();
 | 
	
		
			
				|  |  | +            
 | 
	
		
			
				|  |  | +            // set expected timing of missed frames for buffer_push_packet and set last_resend date
 | 
	
		
			
				|  |  | +            for (seq_t i = ctx->ab_write + 1; seq_order(i, seqno); i++) {
 | 
	
		
			
				|  |  | +                ctx->audio_buffer[BUFIDX(i)].rtptime = rtptime - (seqno-i)*ctx->frame_size;
 | 
	
		
			
				|  |  | +                ctx->audio_buffer[BUFIDX(i)].last_resend = now;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            LOG_DEBUG("[%p]: packet newer seqno:%hu rtptime:%u (W:%hu R:%hu)", ctx, seqno, rtptime, ctx->ab_write, ctx->ab_read);            
 | 
	
		
			
				|  |  | +        }        
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -		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)) {
 | 
	
	
		
			
				|  | @@ -524,10 +526,9 @@ static void buffer_put_packet(rtp_t *ctx, seq_t seqno, unsigned rtptime, bool fi
 | 
	
		
			
				|  |  |  static void buffer_push_packet(rtp_t *ctx) {
 | 
	
		
			
				|  |  |  	abuf_t *curframe = NULL;
 | 
	
		
			
				|  |  |  	u32_t now, playtime, hold = max((ctx->latency * 1000) / (8 * RAOP_SAMPLE_RATE), 100);
 | 
	
		
			
				|  |  | -	int i;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	// not ready to play yet
 | 
	
		
			
				|  |  | -	if (!ctx->playing ||  ctx->synchro.status != (RTP_SYNC | NTP_SYNC)) return;
 | 
	
		
			
				|  |  | +	if (!ctx->playing || ctx->synchro.status != (RTP_SYNC | NTP_SYNC)) return;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	// there is always at least one frame in the buffer
 | 
	
		
			
				|  |  |  	do {
 | 
	
	
		
			
				|  | @@ -573,10 +574,11 @@ static void buffer_push_packet(rtp_t *ctx) {
 | 
	
		
			
				|  |  |  	LOG_SDEBUG("playtime %u %d [W:%hu R:%hu] %d", playtime, playtime - now, ctx->ab_write, ctx->ab_read, curframe->ready);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	// each missing packet will be requested up to (latency_frames / 16) times
 | 
	
		
			
				|  |  | -	for (i = 0; seq_order(ctx->ab_read + i, ctx->ab_write); i += 16) {
 | 
	
		
			
				|  |  | +	for (int i = 0; seq_order(ctx->ab_read + i, ctx->ab_write); i += 16) {
 | 
	
		
			
				|  |  |  		abuf_t *frame = ctx->audio_buffer + BUFIDX(ctx->ab_read + i);
 | 
	
		
			
				|  |  |  		if (!frame->ready && now - frame->last_resend > RESEND_TO) {
 | 
	
		
			
				|  |  | -			rtp_request_resend(ctx, ctx->ab_read + i, ctx->ab_read + i);
 | 
	
		
			
				|  |  | +            // stop if one fails
 | 
	
		
			
				|  |  | +			if (!rtp_request_resend(ctx, ctx->ab_read + i, ctx->ab_read + i)) break;
 | 
	
		
			
				|  |  |  			frame->last_resend = now;
 | 
	
		
			
				|  |  |  		}
 | 
	
		
			
				|  |  |  	}
 | 
	
	
		
			
				|  | @@ -613,7 +615,10 @@ static void rtp_thread_func(void *arg) {
 | 
	
		
			
				|  |  |  		FD_ZERO(&fds);
 | 
	
		
			
				|  |  |  		for (i = 0; i < 3; i++)	{ FD_SET(ctx->rtp_sockets[i].sock, &fds); }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -		if (select(sock + 1, &fds, NULL, NULL, &timeout) <= 0) continue;
 | 
	
		
			
				|  |  | +		if (select(sock + 1, &fds, NULL, NULL, &timeout) <= 0) {
 | 
	
		
			
				|  |  | +            if (ctx->stalled++ == 30*10) ctx->cmd_cb(RAOP_STALLED);
 | 
	
		
			
				|  |  | +            continue;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  		for (i = 0; i < 3; i++)
 | 
	
		
			
				|  |  |  			if (FD_ISSET(ctx->rtp_sockets[i].sock, &fds)) idx = i;
 | 
	
	
		
			
				|  | @@ -631,6 +636,7 @@ static void rtp_thread_func(void *arg) {
 | 
	
		
			
				|  |  |  		}
 | 
	
		
			
				|  |  |  		
 | 
	
		
			
				|  |  |  		assert(plen <= MAX_PACKET);
 | 
	
		
			
				|  |  | +        ctx->stalled = 0;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  		type = packet[1] & ~0x80;
 | 
	
		
			
				|  |  |  		pktp = packet;
 | 
	
	
		
			
				|  | @@ -823,6 +829,7 @@ static bool rtp_request_resend(rtp_t *ctx, seq_t first, seq_t last) {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	if (sizeof(req) != sendto(ctx->rtp_sockets[CONTROL].sock, req, sizeof(req), MSG_DONTWAIT, (struct sockaddr*) &ctx->rtp_host, sizeof(ctx->rtp_host))) {
 | 
	
		
			
				|  |  |  		LOG_WARN("[%p]: SENDTO failed (%s)", ctx, strerror(errno));
 | 
	
		
			
				|  |  | +        return false;
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	return true;
 |