Browse Source

Merge remote-tracking branch 'origin/master' into master-cmake

Sebastien 5 năm trước cách đây
mục cha
commit
c578803b62

+ 55 - 40
components/squeezelite/decode_external.c

@@ -43,14 +43,16 @@ static bool enable_bt_sink;
 static bool enable_airplay;
 
 #define RAOP_OUTPUT_SIZE 	(RAOP_SAMPLE_RATE * 2 * 2 * 2 * 1.2)
-#define SYNC_NB				5
+#define SYNC_WIN_RUN	32
+#define SYNC_WIN_CHECK	8
+#define SYNC_WIN_START	2
 
 static raop_event_t	raop_state;
 
-static struct {
-	bool enabled, start;
-	s32_t error[SYNC_NB];
-	u32_t idx, len;
+static EXT_RAM_ATTR struct {
+	bool enabled;
+	int sum, count, win, errors[SYNC_WIN_RUN];
+	u32_t len;
 	u32_t start_time, playtime;
 } raop_sync;
 
@@ -60,6 +62,7 @@ static struct {
 static void sink_data_handler(const uint8_t *data, uint32_t len)
 {
     size_t bytes, space;
+	int wait = 5;
 		
 	// would be better to lock output, but really, it does not matter
 	if (!output.external) {
@@ -92,8 +95,12 @@ static void sink_data_handler(const uint8_t *data, uint32_t len)
 		UNLOCK_O;
 		
 		// allow i2s to empty the buffer if needed
-		if (len && !space) usleep(50000);
+		if (len && !space && wait--) usleep(20000);
 	}	
+	
+	if (!wait) {
+		LOG_WARN("Waited too long, dropping frames");
+	}
 }
 
 /****************************************************************************************
@@ -191,51 +198,59 @@ static bool raop_sink_cmd_handler(raop_event_t event, va_list args)
 	switch (event) {
 		case RAOP_TIMING: {
 			u32_t ms, now = gettime_ms();
-			s32_t sync_nb, error = 0;
-			
+			int error;
+									
 			if (!raop_sync.enabled || output.state < OUTPUT_RUNNING || output.frames_played_dmp < output.device_frames) break;
 			
 			// first must make sure we started on time
-			if (raop_sync.start) {
+			if (raop_sync.win == SYNC_WIN_START) {
 				// how many ms have we really played
 				ms = now - output.updated + ((u64_t) (output.frames_played_dmp - output.device_frames) * 1000) / RAOP_SAMPLE_RATE;
-				raop_sync.error[raop_sync.idx] = ms - (now - raop_sync.start_time); 
-				sync_nb = 2;
-				LOG_INFO("backend played %u, desired %u, (delta:%d)", ms, now - raop_sync.start_time, raop_sync.error[raop_sync.idx]);
+				error = ms - (now - raop_sync.start_time);
+				LOG_INFO("backend played %u, desired %u, (delta:%d)", ms, now - raop_sync.start_time, ms - (now - raop_sync.start_time));
 			} else {	
 				// in how many ms will the most recent block play 
 				ms = ((u64_t) ((_buf_used(outputbuf) - raop_sync.len) / BYTES_PER_FRAME + output.device_frames + output.frames_in_process) * 1000) / RAOP_SAMPLE_RATE - (now - output.updated);
-				raop_sync.error[raop_sync.idx] = (raop_sync.playtime - now) - ms;
-				if (abs(raop_sync.error[raop_sync.idx]) > 1000) {
-					LOG_INFO("erroneous sync point %d", raop_sync.error[raop_sync.idx]);
-					raop_sync.error[raop_sync.idx] = raop_sync.error[raop_sync.idx] > 0 ? 1000 : -1000;
+				error = (raop_sync.playtime - now) - ms;
+				
+				// make sure impact of erroneous point is limited, but taken into account 
+				if (abs(error) > 1000) {
+					LOG_INFO("limiting erroneous sync point %d", error);
+					error = (error > 0) ? SYNC_WIN_RUN : -SYNC_WIN_RUN;
 				}
-				sync_nb = SYNC_NB;
-				LOG_DEBUG("head local:%u, remote:%u (delta:%d)", ms, raop_sync.playtime - now, raop_sync.error[raop_sync.idx]);
+								
+				LOG_DEBUG("head local:%u, remote:%u (delta:%d)", ms, raop_sync.playtime - now, error);
 				LOG_DEBUG("obuf:%u, sync_len:%u, devframes:%u, inproc:%u", _buf_used(outputbuf), raop_sync.len, output.device_frames, output.frames_in_process);
 			}	
 			
-			// calculate the average error
-			for (int i = 0; i < sync_nb; i++) error += raop_sync.error[i];
-			error /= sync_nb;
-			raop_sync.idx = (raop_sync.idx + 1) % sync_nb;
+			// calculate sum, error and update sliding window
+			raop_sync.errors[raop_sync.count++ % raop_sync.win] = error;
+			raop_sync.sum += error;
+			error = raop_sync.sum / min(raop_sync.count, raop_sync.win);
 			
-			// need at least nb_sync measures done to exit quick mode
-			if (raop_sync.start && !raop_sync.idx && abs(error) < 10) raop_sync.start = false;
+			// move to normal mode if possible
+			if (raop_sync.win == SYNC_WIN_START && raop_sync.count >= SYNC_WIN_START && abs(error) < 10) raop_sync.win = SYNC_WIN_RUN;
+
+			// wait till e have enough data or there is a strong deviation
+			if ((raop_sync.count >= raop_sync.win && abs(error) > 10) || (raop_sync.count >= SYNC_WIN_CHECK && abs(error) > 100)) { 
 			
-			// correct if needed
-			if (error < -10) {
-				output.skip_frames = (abs(error) * RAOP_SAMPLE_RATE) / 1000;
-				output.state = OUTPUT_SKIP_FRAMES;					
-				memset(raop_sync.error, 0, sizeof(raop_sync.error));
-				LOG_INFO("skipping %u frames", output.skip_frames);
-			} else if (error > 10) {
-				output.pause_frames = (abs(error) * RAOP_SAMPLE_RATE) / 1000;
-				output.state = OUTPUT_PAUSE_FRAMES;
-				memset(raop_sync.error, 0, sizeof(raop_sync.error));
-				LOG_INFO("pausing for %u frames", output.pause_frames);
-			}
-				
+				// correct if needed
+				if (error < 0) {
+					output.skip_frames = -(error * RAOP_SAMPLE_RATE) / 1000;
+					output.state = OUTPUT_SKIP_FRAMES;					
+					LOG_INFO("skipping %u frames", output.skip_frames);
+				} else {
+					output.pause_frames = (error * RAOP_SAMPLE_RATE) / 1000;
+					output.state = OUTPUT_PAUSE_FRAMES;
+					LOG_INFO("pausing for %u frames", output.pause_frames);
+				}
+
+				// reset sliding window		
+				raop_sync.sum = raop_sync.count = 0;
+				memset(raop_sync.errors, 0, sizeof(raop_sync.errors));
+											
+			}	
+
 			break;
 		}
 		case RAOP_SETUP:
@@ -250,9 +265,9 @@ static bool raop_sink_cmd_handler(raop_event_t event, va_list args)
 		case RAOP_STREAM:
 			LOG_INFO("Stream", NULL);
 			raop_state = event;
-			memset(raop_sync.error, 0, sizeof(raop_sync.error));
-			raop_sync.idx = 0;
-			raop_sync.start = true;		
+			raop_sync.win = SYNC_WIN_START;
+			raop_sync.sum = raop_sync.count = 0 ;
+			memset(raop_sync.errors, 0, sizeof(raop_sync.errors));
 			raop_sync.enabled = !strcasestr(output.device, "BT");
 			output.next_sample_rate = output.current_sample_rate = RAOP_SAMPLE_RATE;
 			break;

+ 6 - 1
components/squeezelite/display.c

@@ -525,13 +525,18 @@ static void grfb_handler(u8_t *data, int len) {
 	
 	pkt->brightness = htons(pkt->brightness);
 	
-	LOG_INFO("brightness %hu", pkt->brightness);
+	xSemaphoreTake(displayer.mutex, portMAX_DELAY);
+	
 	if (pkt->brightness < 0) {
 		GDS_DisplayOff(display); 
 	} else {
 		GDS_DisplayOn(display);
 		GDS_SetContrast(display, pkt->brightness);
 	}
+	
+	xSemaphoreGive(displayer.mutex);
+	
+	LOG_INFO("brightness %hu", pkt->brightness);
 }
 
 /****************************************************************************************

+ 2 - 2
components/squeezelite/output_i2s.c

@@ -384,7 +384,7 @@ static void *output_thread_i2s(void *arg) {
 	int discard = 0;
 	uint32_t fullness = gettime_ms();
 	bool synced;
-	output_state state = OUTPUT_OFF;
+	output_state state = OUTPUT_OFF - 1;
 	char *sbuf = NULL;
 	
 	// spdif needs 16 bytes per frame : 32 bits/sample, 2 channels, BMC encoded
@@ -423,7 +423,7 @@ static void *output_thread_i2s(void *arg) {
 				adac->power(ADAC_STANDBY);
 				count = 0;
 			}
-			usleep(200000);
+			usleep(100000);
 			continue;
 		} else if (output.state == OUTPUT_STOPPED) {
 			synced = false;