mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-10-29 05:40:27 -04:00 
			
		
		
		
	alsa: pass current_time around in get_status()
Pass the current time around in various functions. Make a higher precission htimestamp based get_delay() function. Seems to work fine for playback but not for capturee.
This commit is contained in:
		
							parent
							
								
									3cba294b65
								
							
						
					
					
						commit
						f636603844
					
				
					 2 changed files with 73 additions and 30 deletions
				
			
		|  | @ -1670,10 +1670,10 @@ recover: | ||||||
| 	return do_start(state); | 	return do_start(state); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int get_status(struct state *state, snd_pcm_uframes_t *delay, snd_pcm_uframes_t *target) | static int get_avail(struct state *state, uint64_t current_time) | ||||||
| { | { | ||||||
| 	snd_pcm_sframes_t avail; |  | ||||||
| 	int res; | 	int res; | ||||||
|  | 	snd_pcm_sframes_t avail; | ||||||
| 
 | 
 | ||||||
| 	if (SPA_UNLIKELY((avail = snd_pcm_avail(state->hndl)) < 0)) { | 	if (SPA_UNLIKELY((avail = snd_pcm_avail(state->hndl)) < 0)) { | ||||||
| 		if ((res = alsa_recover(state, avail)) < 0) | 		if ((res = alsa_recover(state, avail)) < 0) | ||||||
|  | @ -1686,6 +1686,48 @@ static int get_status(struct state *state, snd_pcm_uframes_t *delay, snd_pcm_ufr | ||||||
| 	} else { | 	} else { | ||||||
| 		state->alsa_recovering = false; | 		state->alsa_recovering = false; | ||||||
| 	} | 	} | ||||||
|  | 	return avail; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #if 0 | ||||||
|  | static int get_avail_htimestamp(struct state *state, uint64_t current_time) | ||||||
|  | { | ||||||
|  | 	int res; | ||||||
|  | 	snd_pcm_uframes_t avail; | ||||||
|  | 	snd_htimestamp_t tstamp; | ||||||
|  | 	uint64_t then; | ||||||
|  | 
 | ||||||
|  | 	if ((res = snd_pcm_htimestamp(state->hndl, &avail, &tstamp)) < 0) { | ||||||
|  | 		if ((res = alsa_recover(state, avail)) < 0) | ||||||
|  | 			return res; | ||||||
|  | 		if ((res = snd_pcm_htimestamp(state->hndl, &avail, &tstamp)) < 0) { | ||||||
|  | 			spa_log_warn(state->log, "%s: snd_pcm_htimestamp error: %s", | ||||||
|  | 				state->props.device, snd_strerror(res)); | ||||||
|  | 			avail = state->threshold * 2; | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 		state->alsa_recovering = false; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if ((then = SPA_TIMESPEC_TO_NSEC(&tstamp)) != 0) { | ||||||
|  | 		if (then < current_time) | ||||||
|  | 			avail += (current_time - then) * state->rate / SPA_NSEC_PER_SEC; | ||||||
|  | 		else | ||||||
|  | 			avail -= (then - current_time) * state->rate / SPA_NSEC_PER_SEC; | ||||||
|  | 	} | ||||||
|  | 	return SPA_MIN(avail, state->buffer_frames); | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | static int get_status(struct state *state, uint64_t current_time, | ||||||
|  | 		snd_pcm_uframes_t *delay, snd_pcm_uframes_t *target) | ||||||
|  | { | ||||||
|  | 	int avail; | ||||||
|  | 
 | ||||||
|  | 	if ((avail = get_avail(state, current_time)) < 0) | ||||||
|  | 		return avail; | ||||||
|  | 
 | ||||||
|  | 	avail = SPA_MIN(avail, (int)state->buffer_frames); | ||||||
| 
 | 
 | ||||||
| 	*target = state->threshold + state->headroom; | 	*target = state->threshold + state->headroom; | ||||||
| 
 | 
 | ||||||
|  | @ -1706,7 +1748,7 @@ static int get_status(struct state *state, snd_pcm_uframes_t *delay, snd_pcm_ufr | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int update_time(struct state *state, uint64_t nsec, snd_pcm_sframes_t delay, | static int update_time(struct state *state, uint64_t current_time, snd_pcm_sframes_t delay, | ||||||
| 		snd_pcm_sframes_t target, bool follower) | 		snd_pcm_sframes_t target, bool follower) | ||||||
| { | { | ||||||
| 	double err, corr; | 	double err, corr; | ||||||
|  | @ -1719,8 +1761,8 @@ static int update_time(struct state *state, uint64_t nsec, snd_pcm_sframes_t del | ||||||
| 
 | 
 | ||||||
| 	if (SPA_UNLIKELY(state->dll.bw == 0.0)) { | 	if (SPA_UNLIKELY(state->dll.bw == 0.0)) { | ||||||
| 		spa_dll_set_bw(&state->dll, SPA_DLL_BW_MAX, state->threshold, state->rate); | 		spa_dll_set_bw(&state->dll, SPA_DLL_BW_MAX, state->threshold, state->rate); | ||||||
| 		state->next_time = nsec; | 		state->next_time = current_time; | ||||||
| 		state->base_time = nsec; | 		state->base_time = current_time; | ||||||
| 	} | 	} | ||||||
| 	diff = (int32_t) (state->last_threshold - state->threshold); | 	diff = (int32_t) (state->last_threshold - state->threshold); | ||||||
| 
 | 
 | ||||||
|  | @ -1758,7 +1800,7 @@ static int update_time(struct state *state, uint64_t nsec, snd_pcm_sframes_t del | ||||||
| 	state->next_time += state->threshold / corr * 1e9 / state->rate; | 	state->next_time += state->threshold / corr * 1e9 / state->rate; | ||||||
| 
 | 
 | ||||||
| 	if (SPA_LIKELY(!follower && state->clock)) { | 	if (SPA_LIKELY(!follower && state->clock)) { | ||||||
| 		state->clock->nsec = nsec; | 		state->clock->nsec = current_time; | ||||||
| 		state->clock->position += state->duration; | 		state->clock->position += state->duration; | ||||||
| 		state->clock->duration = state->duration; | 		state->clock->duration = state->duration; | ||||||
| 		state->clock->delay = delay + state->delay; | 		state->clock->delay = delay + state->delay; | ||||||
|  | @ -1767,7 +1809,7 @@ static int update_time(struct state *state, uint64_t nsec, snd_pcm_sframes_t del | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	spa_log_trace_fp(state->log, "%p: follower:%d %"PRIu64" %f %ld %f %f %u", | 	spa_log_trace_fp(state->log, "%p: follower:%d %"PRIu64" %f %ld %f %f %u", | ||||||
| 			state, follower, nsec, corr, delay, err, state->threshold * corr, | 			state, follower, current_time, corr, delay, err, state->threshold * corr, | ||||||
| 			state->threshold); | 			state->threshold); | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
|  | @ -1820,10 +1862,12 @@ int spa_alsa_write(struct state *state) | ||||||
| 	check_position_config(state); | 	check_position_config(state); | ||||||
| 
 | 
 | ||||||
| 	if (state->following && state->alsa_started) { | 	if (state->following && state->alsa_started) { | ||||||
| 		uint64_t nsec; | 		uint64_t current_time; | ||||||
| 		snd_pcm_uframes_t delay, target; | 		snd_pcm_uframes_t delay, target; | ||||||
| 
 | 
 | ||||||
| 		if (SPA_UNLIKELY((res = get_status(state, &delay, &target)) < 0)) | 		current_time = state->position->clock.nsec; | ||||||
|  | 
 | ||||||
|  | 		if (SPA_UNLIKELY((res = get_status(state, current_time, &delay, &target)) < 0)) | ||||||
| 			return res; | 			return res; | ||||||
| 
 | 
 | ||||||
| 		if (SPA_UNLIKELY(!state->alsa_recovering && delay > target + state->threshold)) { | 		if (SPA_UNLIKELY(!state->alsa_recovering && delay > target + state->threshold)) { | ||||||
|  | @ -1842,8 +1886,7 @@ int spa_alsa_write(struct state *state) | ||||||
| 			state->alsa_sync = false; | 			state->alsa_sync = false; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		nsec = state->position->clock.nsec; | 		if (SPA_UNLIKELY((res = update_time(state, current_time, delay, target, true)) < 0)) | ||||||
| 		if (SPA_UNLIKELY((res = update_time(state, nsec, delay, target, true)) < 0)) |  | ||||||
| 			return res; | 			return res; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -2075,11 +2118,13 @@ int spa_alsa_read(struct state *state) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (state->following && state->alsa_started) { | 	if (state->following && state->alsa_started) { | ||||||
| 		uint64_t nsec; | 		uint64_t current_time; | ||||||
| 		snd_pcm_uframes_t delay, target; | 		snd_pcm_uframes_t delay, target; | ||||||
| 		uint32_t threshold = state->threshold; | 		uint32_t threshold = state->threshold; | ||||||
| 
 | 
 | ||||||
| 		if ((res = get_status(state, &delay, &target)) < 0) | 		current_time = state->position->clock.nsec; | ||||||
|  | 
 | ||||||
|  | 		if ((res = get_status(state, current_time, &delay, &target)) < 0) | ||||||
| 			return res; | 			return res; | ||||||
| 
 | 
 | ||||||
| 		if (!state->alsa_recovering && (delay < target / 2 || delay > target * 2)) { | 		if (!state->alsa_recovering && (delay < target / 2 || delay > target * 2)) { | ||||||
|  | @ -2100,8 +2145,7 @@ int spa_alsa_read(struct state *state) | ||||||
| 			state->alsa_sync = false; | 			state->alsa_sync = false; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		nsec = state->position->clock.nsec; | 		if ((res = update_time(state, current_time, delay, target, true)) < 0) | ||||||
| 		if ((res = update_time(state, nsec, delay, target, true)) < 0) |  | ||||||
| 			return res; | 			return res; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -2180,7 +2224,7 @@ int spa_alsa_skip(struct state *state) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| static int handle_play(struct state *state, uint64_t nsec, | static int handle_play(struct state *state, uint64_t current_time, | ||||||
| 		snd_pcm_uframes_t delay, snd_pcm_uframes_t target) | 		snd_pcm_uframes_t delay, snd_pcm_uframes_t target) | ||||||
| { | { | ||||||
| 	int res; | 	int res; | ||||||
|  | @ -2189,11 +2233,11 @@ static int handle_play(struct state *state, uint64_t nsec, | ||||||
| 		spa_log_trace(state->log, "%p: early wakeup %lu %lu", state, delay, target); | 		spa_log_trace(state->log, "%p: early wakeup %lu %lu", state, delay, target); | ||||||
| 		if (delay > target * 3) | 		if (delay > target * 3) | ||||||
| 			delay = target * 3; | 			delay = target * 3; | ||||||
| 		state->next_time = nsec + (delay - target) * SPA_NSEC_PER_SEC / state->rate; | 		state->next_time = current_time + (delay - target) * SPA_NSEC_PER_SEC / state->rate; | ||||||
| 		return -EAGAIN; | 		return -EAGAIN; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (SPA_UNLIKELY((res = update_time(state, nsec, delay, target, false)) < 0)) | 	if (SPA_UNLIKELY((res = update_time(state, current_time, delay, target, false)) < 0)) | ||||||
| 		return res; | 		return res; | ||||||
| 
 | 
 | ||||||
| 	if (spa_list_is_empty(&state->ready)) { | 	if (spa_list_is_empty(&state->ready)) { | ||||||
|  | @ -2211,7 +2255,7 @@ static int handle_play(struct state *state, uint64_t nsec, | ||||||
| 	return res; | 	return res; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int handle_capture(struct state *state, uint64_t nsec, | static int handle_capture(struct state *state, uint64_t current_time, | ||||||
| 		snd_pcm_uframes_t delay, snd_pcm_uframes_t target) | 		snd_pcm_uframes_t delay, snd_pcm_uframes_t target) | ||||||
| { | { | ||||||
| 	int res; | 	int res; | ||||||
|  | @ -2219,12 +2263,12 @@ static int handle_capture(struct state *state, uint64_t nsec, | ||||||
| 
 | 
 | ||||||
| 	if (SPA_UNLIKELY(delay < target)) { | 	if (SPA_UNLIKELY(delay < target)) { | ||||||
| 		spa_log_trace(state->log, "%p: early wakeup %ld %ld", state, delay, target); | 		spa_log_trace(state->log, "%p: early wakeup %ld %ld", state, delay, target); | ||||||
| 		state->next_time = nsec + (target - delay) * SPA_NSEC_PER_SEC / | 		state->next_time = current_time + (target - delay) * SPA_NSEC_PER_SEC / | ||||||
| 			state->rate; | 			state->rate; | ||||||
| 		return -EAGAIN; | 		return -EAGAIN; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (SPA_UNLIKELY(res = update_time(state, nsec, delay, target, false)) < 0) | 	if (SPA_UNLIKELY(res = update_time(state, current_time, delay, target, false)) < 0) | ||||||
| 		return res; | 		return res; | ||||||
| 
 | 
 | ||||||
| 	if ((res = spa_alsa_read(state)) < 0) | 	if ((res = spa_alsa_read(state)) < 0) | ||||||
|  | @ -2257,17 +2301,17 @@ static void alsa_on_timeout_event(struct spa_source *source) | ||||||
| { | { | ||||||
| 	struct state *state = source->data; | 	struct state *state = source->data; | ||||||
| 	snd_pcm_uframes_t delay, target; | 	snd_pcm_uframes_t delay, target; | ||||||
| 	uint64_t expire; | 	uint64_t expire, current_time; | ||||||
| 
 | 
 | ||||||
| 	if (SPA_UNLIKELY(state->started && spa_system_timerfd_read(state->data_system, state->timerfd, &expire) < 0)) | 	if (SPA_UNLIKELY(state->started && spa_system_timerfd_read(state->data_system, state->timerfd, &expire) < 0)) | ||||||
| 		spa_log_warn(state->log, "%p: error reading timerfd: %m", state); | 		spa_log_warn(state->log, "%p: error reading timerfd: %m", state); | ||||||
| 
 | 
 | ||||||
| 	check_position_config(state); | 	check_position_config(state); | ||||||
| 
 | 
 | ||||||
| 	if (SPA_UNLIKELY(get_status(state, &delay, &target) < 0)) | 	current_time = state->next_time; | ||||||
| 		return; |  | ||||||
| 
 | 
 | ||||||
| 	state->current_time = state->next_time; | 	if (SPA_UNLIKELY(get_status(state, current_time, &delay, &target) < 0)) | ||||||
|  | 		return; | ||||||
| 
 | 
 | ||||||
| #ifndef FASTPATH | #ifndef FASTPATH | ||||||
| 	if (SPA_UNLIKELY(spa_log_level_enabled(state->log, SPA_LOG_LEVEL_TRACE))) { | 	if (SPA_UNLIKELY(spa_log_level_enabled(state->log, SPA_LOG_LEVEL_TRACE))) { | ||||||
|  | @ -2277,15 +2321,15 @@ static void alsa_on_timeout_event(struct spa_source *source) | ||||||
| 		    return; | 		    return; | ||||||
| 		nsec = SPA_TIMESPEC_TO_NSEC(&now); | 		nsec = SPA_TIMESPEC_TO_NSEC(&now); | ||||||
| 		spa_log_trace_fp(state->log, "%p: timeout %lu %lu %"PRIu64" %"PRIu64" %"PRIi64 | 		spa_log_trace_fp(state->log, "%p: timeout %lu %lu %"PRIu64" %"PRIu64" %"PRIi64 | ||||||
| 				" %d %"PRIi64, state, delay, target, nsec, state->current_time, | 				" %d %"PRIi64, state, delay, target, nsec, nsec, | ||||||
| 				nsec - state->current_time, state->threshold, state->sample_count); | 				nsec - current_time, state->threshold, state->sample_count); | ||||||
| 	} | 	} | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| 	if (state->stream == SND_PCM_STREAM_PLAYBACK) | 	if (state->stream == SND_PCM_STREAM_PLAYBACK) | ||||||
| 		handle_play(state, state->current_time, delay, target); | 		handle_play(state, current_time, delay, target); | ||||||
| 	else | 	else | ||||||
| 		handle_capture(state, state->current_time, delay, target); | 		handle_capture(state, current_time, delay, target); | ||||||
| 
 | 
 | ||||||
| 	set_timeout(state, state->next_time); | 	set_timeout(state, state->next_time); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -210,7 +210,6 @@ struct state { | ||||||
| 	int64_t sample_count; | 	int64_t sample_count; | ||||||
| 
 | 
 | ||||||
| 	int64_t sample_time; | 	int64_t sample_time; | ||||||
| 	uint64_t current_time; |  | ||||||
| 	uint64_t next_time; | 	uint64_t next_time; | ||||||
| 	uint64_t base_time; | 	uint64_t base_time; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Wim Taymans
						Wim Taymans