mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-10-29 05:40:27 -04:00 
			
		
		
		
	alsa: have slaved sink
When we are slaved, calculate our rate difference with the master
This commit is contained in:
		
							parent
							
								
									6f555c63e2
								
							
						
					
					
						commit
						416b9c254e
					
				
					 2 changed files with 56 additions and 19 deletions
				
			
		|  | @ -537,9 +537,35 @@ int spa_alsa_write(struct state *state, snd_pcm_uframes_t silence) | ||||||
| { | { | ||||||
| 	snd_pcm_t *hndl = state->hndl; | 	snd_pcm_t *hndl = state->hndl; | ||||||
| 	const snd_pcm_channel_area_t *my_areas; | 	const snd_pcm_channel_area_t *my_areas; | ||||||
| 	snd_pcm_uframes_t written, frames = state->buffer_frames, offset, off, to_write; | 	snd_pcm_uframes_t written, frames, offset, off, to_write; | ||||||
| 	int res; | 	int res; | ||||||
| 
 | 
 | ||||||
|  | 	if (state->position) | ||||||
|  | 		state->threshold = state->position->size; | ||||||
|  | 
 | ||||||
|  | 	if (state->slaved) { | ||||||
|  | 		double dts, pts, rate_diff = 1.0; | ||||||
|  | 		struct timespec now; | ||||||
|  | 		snd_pcm_sframes_t avail; | ||||||
|  | 
 | ||||||
|  | 		if ((res = get_status(state, &avail, &now)) < 0) | ||||||
|  | 			return res; | ||||||
|  | 
 | ||||||
|  | 		state->now = now; | ||||||
|  | 		state->filled = state->buffer_frames - avail; | ||||||
|  | 
 | ||||||
|  | 		dts = ((state->position->clock.position - state->filled) * 1000000ll / state->rate); | ||||||
|  | 		pts = dll_update(&state->dll, dts, state->threshold); | ||||||
|  | 		rate_diff = state->dll.T * state->rate / 1000000.f; | ||||||
|  | 
 | ||||||
|  | 		if (state->bw != 0.05 && state->sample_count / state->rate > 4) { | ||||||
|  | 			state->bw = 0.05; | ||||||
|  | 			dll_bandwidth(&state->dll, state->threshold, state->rate, state->bw); | ||||||
|  | 		} | ||||||
|  | 		spa_log_trace(state->log, "slave %f %f %f", dts, pts, rate_diff); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	frames = state->buffer_frames; | ||||||
| 	if ((res = snd_pcm_mmap_begin(hndl, &my_areas, &offset, &frames)) < 0) { | 	if ((res = snd_pcm_mmap_begin(hndl, &my_areas, &offset, &frames)) < 0) { | ||||||
| 		spa_log_error(state->log, "snd_pcm_mmap_begin error: %s", snd_strerror(res)); | 		spa_log_error(state->log, "snd_pcm_mmap_begin error: %s", snd_strerror(res)); | ||||||
| 		return res; | 		return res; | ||||||
|  | @ -717,11 +743,11 @@ static void alsa_on_playback_timeout_event(struct spa_source *source) | ||||||
| 	if ((res = get_status(state, &avail, &now)) < 0) | 	if ((res = get_status(state, &avail, &now)) < 0) | ||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
|  | 	state->now = now; | ||||||
|  | 
 | ||||||
| 	if (state->position) | 	if (state->position) | ||||||
| 		state->threshold = state->position->size; | 		state->threshold = state->position->size; | ||||||
| 
 | 
 | ||||||
| 	state->now = now; |  | ||||||
| 
 |  | ||||||
| 	if (avail > state->buffer_frames) | 	if (avail > state->buffer_frames) | ||||||
| 		avail = state->buffer_frames; | 		avail = state->buffer_frames; | ||||||
| 
 | 
 | ||||||
|  | @ -866,7 +892,13 @@ int spa_alsa_start(struct state *state, bool xrun_recover) | ||||||
| 	if (state->position) | 	if (state->position) | ||||||
| 		state->threshold = state->position->size; | 		state->threshold = state->position->size; | ||||||
| 
 | 
 | ||||||
| 	state->bw = 1.0; | 	state->slaved = false; | ||||||
|  | 	if (state->position && state->clock) { | ||||||
|  | 		if (state->position->clock.id != state->clock->id) | ||||||
|  | 			state->slaved = true; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	state->bw = 0.128; | ||||||
| 	dll_init(&state->dll, state->threshold, state->rate, state->bw); | 	dll_init(&state->dll, state->threshold, state->rate, state->bw); | ||||||
| 
 | 
 | ||||||
| 	spa_log_debug(state->log, "alsa %p: start %d", state, state->threshold); | 	spa_log_debug(state->log, "alsa %p: start %d", state, state->threshold); | ||||||
|  | @ -880,16 +912,18 @@ int spa_alsa_start(struct state *state, bool xrun_recover) | ||||||
| 		return err; | 		return err; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (state->stream == SND_PCM_STREAM_PLAYBACK) { | 	if (!state->slaved) { | ||||||
| 		state->source.func = alsa_on_playback_timeout_event; | 		if (state->stream == SND_PCM_STREAM_PLAYBACK) { | ||||||
| 	} else { | 			state->source.func = alsa_on_playback_timeout_event; | ||||||
| 		state->source.func = alsa_on_capture_timeout_event; | 		} else { | ||||||
|  | 			state->source.func = alsa_on_capture_timeout_event; | ||||||
|  | 		} | ||||||
|  | 		state->source.data = state; | ||||||
|  | 		state->source.fd = state->timerfd; | ||||||
|  | 		state->source.mask = SPA_IO_IN; | ||||||
|  | 		state->source.rmask = 0; | ||||||
|  | 		spa_loop_add_source(state->data_loop, &state->source); | ||||||
| 	} | 	} | ||||||
| 	state->source.data = state; |  | ||||||
| 	state->source.fd = state->timerfd; |  | ||||||
| 	state->source.mask = SPA_IO_IN; |  | ||||||
| 	state->source.rmask = 0; |  | ||||||
| 	spa_loop_add_source(state->data_loop, &state->source); |  | ||||||
| 
 | 
 | ||||||
| 	if (state->stream == SND_PCM_STREAM_PLAYBACK) { | 	if (state->stream == SND_PCM_STREAM_PLAYBACK) { | ||||||
| 		state->alsa_started = false; | 		state->alsa_started = false; | ||||||
|  | @ -901,12 +935,14 @@ int spa_alsa_start(struct state *state, bool xrun_recover) | ||||||
| 		state->alsa_started = true; | 		state->alsa_started = true; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	clock_gettime(CLOCK_MONOTONIC, &state->now); | 	if (!state->slaved) { | ||||||
| 	ts.it_value.tv_sec = 0; | 		clock_gettime(CLOCK_MONOTONIC, &state->now); | ||||||
| 	ts.it_value.tv_nsec = 1; | 		ts.it_value.tv_sec = 0; | ||||||
| 	ts.it_interval.tv_sec = 0; | 		ts.it_value.tv_nsec = 1; | ||||||
| 	ts.it_interval.tv_nsec = 0; | 		ts.it_interval.tv_sec = 0; | ||||||
| 	timerfd_settime(state->timerfd, 0, &ts, NULL); | 		ts.it_interval.tv_nsec = 0; | ||||||
|  | 		timerfd_settime(state->timerfd, 0, &ts, NULL); | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	state->io->status = SPA_STATUS_OK; | 	state->io->status = SPA_STATUS_OK; | ||||||
| 	state->io->buffer_id = SPA_ID_INVALID; | 	state->io->buffer_id = SPA_ID_INVALID; | ||||||
|  |  | ||||||
|  | @ -122,6 +122,7 @@ struct state { | ||||||
| 	struct spa_source source; | 	struct spa_source source; | ||||||
| 	int timerfd; | 	int timerfd; | ||||||
| 	bool alsa_started; | 	bool alsa_started; | ||||||
|  | 	bool slaved; | ||||||
| 	int threshold; | 	int threshold; | ||||||
| 
 | 
 | ||||||
| 	snd_htimestamp_t now; | 	snd_htimestamp_t now; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Wim Taymans
						Wim Taymans