mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	alsa: split irq and timer wakeup functions
Because it's easy to do and avoids some runtime checks.
This commit is contained in:
		
							parent
							
								
									8608c03b76
								
							
						
					
					
						commit
						2833ff1272
					
				
					 1 changed files with 77 additions and 66 deletions
				
			
		| 
						 | 
					@ -3181,56 +3181,10 @@ static uint64_t get_time_ns(struct state *state)
 | 
				
			||||||
	return SPA_TIMESPEC_TO_NSEC(&now);
 | 
						return SPA_TIMESPEC_TO_NSEC(&now);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void alsa_wakeup_event(struct spa_source *source)
 | 
					static inline int alsa_do_wakeup_work(struct state *state, uint64_t current_time)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct state *state = source->data, *follower;
 | 
						struct state *follower;
 | 
				
			||||||
	uint64_t expire, current_time;
 | 
						int res;
 | 
				
			||||||
	int res, suppressed;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (state->disable_tsched) {
 | 
					 | 
				
			||||||
		/* ALSA poll fds need to be "demangled" to know whether it's a real wakeup */
 | 
					 | 
				
			||||||
		int err;
 | 
					 | 
				
			||||||
		unsigned short revents;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		current_time = get_time_ns(state);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		for (int i = 0; i < state->n_fds; i++) {
 | 
					 | 
				
			||||||
			state->pfds[i].revents = state->source[i].rmask;
 | 
					 | 
				
			||||||
			/* Reset so that we only handle all our sources' events once */
 | 
					 | 
				
			||||||
			state->source[i].rmask = 0;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (SPA_UNLIKELY(err = snd_pcm_poll_descriptors_revents(state->hndl,
 | 
					 | 
				
			||||||
						state->pfds, state->n_fds, &revents))) {
 | 
					 | 
				
			||||||
			spa_log_error(state->log, "Could not look up revents: %s",
 | 
					 | 
				
			||||||
					snd_strerror(err));
 | 
					 | 
				
			||||||
			return;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (!revents) {
 | 
					 | 
				
			||||||
			spa_log_trace_fp(state->log, "Woken up with no work to do");
 | 
					 | 
				
			||||||
			return;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if (revents & POLLERR) {
 | 
					 | 
				
			||||||
			spa_log_trace_fp(state->log, "poll error");
 | 
					 | 
				
			||||||
			if ((res = alsa_recover(state)) < 0)
 | 
					 | 
				
			||||||
				return;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		if (SPA_LIKELY(state->started)) {
 | 
					 | 
				
			||||||
			if (SPA_UNLIKELY((res = spa_system_timerfd_read(state->data_system,
 | 
					 | 
				
			||||||
						state->timerfd, &expire)) < 0)) {
 | 
					 | 
				
			||||||
			/* we can get here when the timer is changed since the last
 | 
					 | 
				
			||||||
				 * timerfd wakeup, for example by do_reassign_follower() executed
 | 
					 | 
				
			||||||
				 * in the same epoll wakeup cycle */
 | 
					 | 
				
			||||||
				if (res != -EAGAIN)
 | 
					 | 
				
			||||||
					spa_log_warn(state->log, "%p: error reading timerfd: %s",
 | 
					 | 
				
			||||||
							state, spa_strerror(res));
 | 
					 | 
				
			||||||
				return;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		current_time = state->next_time;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* first do all the sync */
 | 
						/* first do all the sync */
 | 
				
			||||||
	if (state->stream == SND_PCM_STREAM_CAPTURE)
 | 
						if (state->stream == SND_PCM_STREAM_CAPTURE)
 | 
				
			||||||
| 
						 | 
					@ -3239,7 +3193,7 @@ static void alsa_wakeup_event(struct spa_source *source)
 | 
				
			||||||
		res = alsa_write_sync(state, current_time);
 | 
							res = alsa_write_sync(state, current_time);
 | 
				
			||||||
	/* we can get -EAGAIN when we need to wait some more */
 | 
						/* we can get -EAGAIN when we need to wait some more */
 | 
				
			||||||
	if (SPA_UNLIKELY(res == -EAGAIN))
 | 
						if (SPA_UNLIKELY(res == -EAGAIN))
 | 
				
			||||||
		goto done;
 | 
							return res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spa_list_for_each(follower, &state->rt.followers, rt.driver_link) {
 | 
						spa_list_for_each(follower, &state->rt.followers, rt.driver_link) {
 | 
				
			||||||
		if (follower == state)
 | 
							if (follower == state)
 | 
				
			||||||
| 
						 | 
					@ -3262,8 +3216,66 @@ static void alsa_wakeup_event(struct spa_source *source)
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		capture_ready(state);
 | 
							capture_ready(state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
done:
 | 
						return 0;
 | 
				
			||||||
	if (!state->disable_tsched) {
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void alsa_irq_wakeup_event(struct spa_source *source)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct state *state = source->data;
 | 
				
			||||||
 | 
						uint64_t current_time;
 | 
				
			||||||
 | 
						int res, err;
 | 
				
			||||||
 | 
						unsigned short revents;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						current_time = get_time_ns(state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (int i = 0; i < state->n_fds; i++) {
 | 
				
			||||||
 | 
							state->pfds[i].revents = state->source[i].rmask;
 | 
				
			||||||
 | 
							/* Reset so that we only handle all our sources' events once */
 | 
				
			||||||
 | 
							state->source[i].rmask = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* ALSA poll fds need to be "demangled" to know whether it's a real wakeup */
 | 
				
			||||||
 | 
						if (SPA_UNLIKELY(err = snd_pcm_poll_descriptors_revents(state->hndl,
 | 
				
			||||||
 | 
										state->pfds, state->n_fds, &revents))) {
 | 
				
			||||||
 | 
							spa_log_error(state->log, "Could not look up revents: %s",
 | 
				
			||||||
 | 
									snd_strerror(err));
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!revents) {
 | 
				
			||||||
 | 
							spa_log_trace_fp(state->log, "Woken up with no work to do");
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (revents & POLLERR) {
 | 
				
			||||||
 | 
							spa_log_trace_fp(state->log, "poll error");
 | 
				
			||||||
 | 
							if ((res = alsa_recover(state)) < 0)
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						alsa_do_wakeup_work(state, current_time);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void alsa_timer_wakeup_event(struct spa_source *source)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct state *state = source->data;
 | 
				
			||||||
 | 
						uint64_t expire, current_time;
 | 
				
			||||||
 | 
						int res, suppressed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (SPA_LIKELY(state->started)) {
 | 
				
			||||||
 | 
							if (SPA_UNLIKELY((res = spa_system_timerfd_read(state->data_system,
 | 
				
			||||||
 | 
										state->timerfd, &expire)) < 0)) {
 | 
				
			||||||
 | 
							/* we can get here when the timer is changed since the last
 | 
				
			||||||
 | 
								 * timerfd wakeup, for example by do_reassign_follower() executed
 | 
				
			||||||
 | 
								 * in the same epoll wakeup cycle */
 | 
				
			||||||
 | 
								if (res != -EAGAIN)
 | 
				
			||||||
 | 
									spa_log_warn(state->log, "%p: error reading timerfd: %s",
 | 
				
			||||||
 | 
											state, spa_strerror(res));
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						current_time = state->next_time;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						alsa_do_wakeup_work(state, current_time);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (state->next_time > current_time + SPA_NSEC_PER_SEC ||
 | 
						if (state->next_time > current_time + SPA_NSEC_PER_SEC ||
 | 
				
			||||||
	    current_time > state->next_time + SPA_NSEC_PER_SEC) {
 | 
						    current_time > state->next_time + SPA_NSEC_PER_SEC) {
 | 
				
			||||||
		if ((suppressed = spa_ratelimit_test(&state->rate_limit, current_time)) >= 0) {
 | 
							if ((suppressed = spa_ratelimit_test(&state->rate_limit, current_time)) >= 0) {
 | 
				
			||||||
| 
						 | 
					@ -3277,7 +3289,6 @@ done:
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	set_timeout(state, state->next_time);
 | 
						set_timeout(state, state->next_time);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void remove_sources(struct state *state)
 | 
					static void remove_sources(struct state *state)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -3386,7 +3397,7 @@ int spa_alsa_start(struct state *state)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!state->disable_tsched) {
 | 
						if (!state->disable_tsched) {
 | 
				
			||||||
		/* Timer-based scheduling */
 | 
							/* Timer-based scheduling */
 | 
				
			||||||
		state->source[0].func = alsa_wakeup_event;
 | 
							state->source[0].func = alsa_timer_wakeup_event;
 | 
				
			||||||
		state->source[0].data = state;
 | 
							state->source[0].data = state;
 | 
				
			||||||
		state->source[0].fd = state->timerfd;
 | 
							state->source[0].fd = state->timerfd;
 | 
				
			||||||
		state->source[0].mask = SPA_IO_IN;
 | 
							state->source[0].mask = SPA_IO_IN;
 | 
				
			||||||
| 
						 | 
					@ -3415,7 +3426,7 @@ int spa_alsa_start(struct state *state)
 | 
				
			||||||
		/* We only add the source to the data loop if we're driving.
 | 
							/* We only add the source to the data loop if we're driving.
 | 
				
			||||||
		 * This is done in setup_sources() */
 | 
							 * This is done in setup_sources() */
 | 
				
			||||||
		for (int i = 0; i < state->n_fds; i++) {
 | 
							for (int i = 0; i < state->n_fds; i++) {
 | 
				
			||||||
			state->source[i].func = alsa_wakeup_event;
 | 
								state->source[i].func = alsa_irq_wakeup_event;
 | 
				
			||||||
			state->source[i].data = state;
 | 
								state->source[i].data = state;
 | 
				
			||||||
			state->source[i].fd = state->pfds[i].fd;
 | 
								state->source[i].fd = state->pfds[i].fd;
 | 
				
			||||||
			state->source[i].mask = state->pfds[i].events;
 | 
								state->source[i].mask = state->pfds[i].events;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue