mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	alsa: clamp the period size to something sensible
some clients (sweep) want to negotiate the smallest possible period size we can support, which is expressed in bytes and independent of samplerate, format and number of channels. For files with high samplerate and channelcount, this results in periods of 8 frames, which is too small to handle. Instead round up the period size to something we can likely handle, taking into account the samplerate and number of channels.
This commit is contained in:
		
							parent
							
								
									7af81f8080
								
							
						
					
					
						commit
						7e513ea243
					
				
					 1 changed files with 29 additions and 15 deletions
				
			
		| 
						 | 
					@ -45,6 +45,8 @@
 | 
				
			||||||
#define MAX_CHANNELS	32
 | 
					#define MAX_CHANNELS	32
 | 
				
			||||||
#define MAX_RATE	(48000*8)
 | 
					#define MAX_RATE	(48000*8)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MIN_PERIOD	64
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct {
 | 
					typedef struct {
 | 
				
			||||||
	snd_pcm_ioplug_t io;
 | 
						snd_pcm_ioplug_t io;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -189,9 +191,9 @@ snd_pcm_pipewire_process_playback(snd_pcm_pipewire_t *pw, struct pw_buffer *b)
 | 
				
			||||||
	nbytes = SPA_MIN(avail, maxsize - offset);
 | 
						nbytes = SPA_MIN(avail, maxsize - offset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ptr = SPA_MEMBER(d[0].data, offset, void);
 | 
						ptr = SPA_MEMBER(d[0].data, offset, void);
 | 
				
			||||||
	pw_log_trace("%d %d %d %d %p %d", nbytes, avail, filled, offset, ptr, io->state);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	nframes = nbytes / bpf;
 | 
						nframes = nbytes / bpf;
 | 
				
			||||||
 | 
						pw_log_trace("%d %d %lu %d %d %p %d", nbytes, avail, nframes, filled, offset, ptr, io->state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (channel = 0; channel < io->channels; channel++) {
 | 
						for (channel = 0; channel < io->channels; channel++) {
 | 
				
			||||||
		pwareas[channel].addr = ptr;
 | 
							pwareas[channel].addr = ptr;
 | 
				
			||||||
| 
						 | 
					@ -317,10 +319,15 @@ static void on_stream_format_changed(void *data, const struct spa_pod *format)
 | 
				
			||||||
        uint8_t buffer[4096];
 | 
					        uint8_t buffer[4096];
 | 
				
			||||||
        struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
 | 
					        struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
 | 
				
			||||||
	uint32_t stride = (io->channels * pw->sample_bits) / 8;
 | 
						uint32_t stride = (io->channels * pw->sample_bits) / 8;
 | 
				
			||||||
	uint32_t buffers = SPA_CLAMP(io->buffer_size / io->period_size, MIN_BUFFERS, MAX_BUFFERS);
 | 
						uint32_t buffers;
 | 
				
			||||||
	uint32_t size = io->period_size * stride;
 | 
						uint32_t size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_log_info("buffers %lu %lu %u %u %u", io->buffer_size, io->period_size, buffers, stride, size);
 | 
						io->period_size = pw->min_avail;
 | 
				
			||||||
 | 
						buffers = SPA_CLAMP(io->buffer_size / io->period_size, MIN_BUFFERS, MAX_BUFFERS);
 | 
				
			||||||
 | 
						size = io->period_size * stride;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pw_log_info("buffer_size:%lu period_size:%lu buffers:%u stride:%u size:%u min_avail:%lu",
 | 
				
			||||||
 | 
								io->buffer_size, io->period_size, buffers, stride, size, pw->min_avail);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	params[n_params++] = spa_pod_builder_object(&b,
 | 
						params[n_params++] = spa_pod_builder_object(&b,
 | 
				
			||||||
	                SPA_TYPE_OBJECT_ParamBuffers, SPA_PARAM_Buffers,
 | 
						                SPA_TYPE_OBJECT_ParamBuffers, SPA_PARAM_Buffers,
 | 
				
			||||||
| 
						 | 
					@ -367,10 +374,20 @@ static int snd_pcm_pipewire_prepare(snd_pcm_ioplug_t *io)
 | 
				
			||||||
	struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
 | 
						struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
 | 
				
			||||||
	struct pw_properties *props;
 | 
						struct pw_properties *props;
 | 
				
			||||||
	int res;
 | 
						int res;
 | 
				
			||||||
 | 
						uint32_t min_period;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_thread_loop_lock(pw->main_loop);
 | 
						pw_thread_loop_lock(pw->main_loop);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_log_debug("prepare %d %p %lu", pw->error, pw->stream, io->period_size);
 | 
						snd_pcm_sw_params_alloca(&swparams);
 | 
				
			||||||
 | 
						if ((res = snd_pcm_sw_params_current(io->pcm, swparams)) == 0)
 | 
				
			||||||
 | 
							snd_pcm_sw_params_get_avail_min(swparams, &pw->min_avail);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							pw->min_avail = io->period_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						min_period = (MIN_PERIOD * io->rate / 48000);
 | 
				
			||||||
 | 
						pw->min_avail = SPA_MAX(pw->min_avail, min_period);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pw_log_debug("prepare %d %p %lu %ld", pw->error, pw->stream, io->period_size, pw->min_avail);
 | 
				
			||||||
	if (!pw->error && pw->stream != NULL)
 | 
						if (!pw->error && pw->stream != NULL)
 | 
				
			||||||
		goto done;
 | 
							goto done;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -380,7 +397,8 @@ static int snd_pcm_pipewire_prepare(snd_pcm_ioplug_t *io)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	props = pw_properties_new("client.api", "alsa", NULL);
 | 
						props = pw_properties_new("client.api", "alsa", NULL);
 | 
				
			||||||
	pw_properties_setf(props, "node.latency", "%lu/%u", io->period_size, io->rate);
 | 
					
 | 
				
			||||||
 | 
						pw_properties_setf(props, "node.latency", "%lu/%u", pw->min_avail, io->rate);
 | 
				
			||||||
	pw_properties_set(props, PW_NODE_PROP_MEDIA, "Audio");
 | 
						pw_properties_set(props, PW_NODE_PROP_MEDIA, "Audio");
 | 
				
			||||||
	pw_properties_set(props, PW_NODE_PROP_CATEGORY,
 | 
						pw_properties_set(props, PW_NODE_PROP_CATEGORY,
 | 
				
			||||||
			io->stream == SND_PCM_STREAM_PLAYBACK ?
 | 
								io->stream == SND_PCM_STREAM_PLAYBACK ?
 | 
				
			||||||
| 
						 | 
					@ -410,12 +428,6 @@ static int snd_pcm_pipewire_prepare(snd_pcm_ioplug_t *io)
 | 
				
			||||||
done:
 | 
					done:
 | 
				
			||||||
	pw->hw_ptr = 0;
 | 
						pw->hw_ptr = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	snd_pcm_sw_params_alloca(&swparams);
 | 
					 | 
				
			||||||
	if ((res = snd_pcm_sw_params_current(io->pcm, swparams)) == 0)
 | 
					 | 
				
			||||||
		snd_pcm_sw_params_get_avail_min(swparams, &pw->min_avail);
 | 
					 | 
				
			||||||
	else
 | 
					 | 
				
			||||||
		pw->min_avail = io->period_size;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	pw_thread_loop_unlock(pw->main_loop);
 | 
						pw_thread_loop_unlock(pw->main_loop);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
| 
						 | 
					@ -505,7 +517,7 @@ static int snd_pcm_pipewire_hw_params(snd_pcm_ioplug_t * io,
 | 
				
			||||||
	snd_pcm_pipewire_t *pw = io->private_data;
 | 
						snd_pcm_pipewire_t *pw = io->private_data;
 | 
				
			||||||
	bool planar;
 | 
						bool planar;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_log_debug("hw_params");
 | 
						pw_log_debug("hw_params %lu %lu", io->buffer_size, io->period_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch(io->access) {
 | 
						switch(io->access) {
 | 
				
			||||||
	case SND_PCM_ACCESS_MMAP_INTERLEAVED:
 | 
						case SND_PCM_ACCESS_MMAP_INTERLEAVED:
 | 
				
			||||||
| 
						 | 
					@ -722,10 +734,12 @@ static int pipewire_set_hw_constraint(snd_pcm_pipewire_t *pw)
 | 
				
			||||||
						   1, MAX_CHANNELS)) < 0 ||
 | 
											   1, MAX_CHANNELS)) < 0 ||
 | 
				
			||||||
	    (err = snd_pcm_ioplug_set_param_minmax(&pw->io, SND_PCM_IOPLUG_HW_RATE,
 | 
						    (err = snd_pcm_ioplug_set_param_minmax(&pw->io, SND_PCM_IOPLUG_HW_RATE,
 | 
				
			||||||
						   1, MAX_RATE)) < 0 ||
 | 
											   1, MAX_RATE)) < 0 ||
 | 
				
			||||||
 | 
						    (err = snd_pcm_ioplug_set_param_minmax(&pw->io, SND_PCM_IOPLUG_HW_BUFFER_BYTES,
 | 
				
			||||||
 | 
					                                                   16*1024, 4*1024*1024)) < 0 ||
 | 
				
			||||||
	    (err = snd_pcm_ioplug_set_param_minmax(&pw->io, SND_PCM_IOPLUG_HW_PERIOD_BYTES,
 | 
						    (err = snd_pcm_ioplug_set_param_minmax(&pw->io, SND_PCM_IOPLUG_HW_PERIOD_BYTES,
 | 
				
			||||||
                                                   128, 64*1024)) < 0 ||
 | 
					                                                   128, 2*1024*1024)) < 0 ||
 | 
				
			||||||
	    (err = snd_pcm_ioplug_set_param_minmax(&pw->io, SND_PCM_IOPLUG_HW_PERIODS,
 | 
						    (err = snd_pcm_ioplug_set_param_minmax(&pw->io, SND_PCM_IOPLUG_HW_PERIODS,
 | 
				
			||||||
						   2, 64)) < 0)
 | 
											   3, 64)) < 0)
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue