mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-10-29 05:40:27 -04:00 
			
		
		
		
	alsa: rework process function to support planar formats
This commit is contained in:
		
							parent
							
								
									bfc91c27a6
								
							
						
					
					
						commit
						64ee110356
					
				
					 1 changed files with 72 additions and 137 deletions
				
			
		|  | @ -176,157 +176,95 @@ static snd_pcm_sframes_t snd_pcm_pipewire_pointer(snd_pcm_ioplug_t *io) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int | static int | ||||||
| snd_pcm_pipewire_process_playback(snd_pcm_pipewire_t *pw, struct pw_buffer *b, snd_pcm_uframes_t *hw_avail) | snd_pcm_pipewire_process(snd_pcm_pipewire_t *pw, struct pw_buffer *b, snd_pcm_uframes_t *hw_avail) | ||||||
| { | { | ||||||
| 	snd_pcm_ioplug_t *io = &pw->io; | 	snd_pcm_ioplug_t *io = &pw->io; | ||||||
| 	const snd_pcm_channel_area_t *areas; |  | ||||||
| 	snd_pcm_channel_area_t *pwareas; | 	snd_pcm_channel_area_t *pwareas; | ||||||
| 	snd_pcm_uframes_t xfer = 0; |         snd_pcm_uframes_t xfer = 0; | ||||||
| 	unsigned int channel, bps, bpf; |  | ||||||
| 	snd_pcm_uframes_t nframes; | 	snd_pcm_uframes_t nframes; | ||||||
| 	uint32_t offset, index = 0, nbytes, avail, maxsize; |         unsigned int channel; | ||||||
| 	int32_t filled; |  | ||||||
| 	void *ptr; |  | ||||||
| 	struct spa_data *d; |  | ||||||
| 
 |  | ||||||
| 	bps = io->channels * pw->sample_bits; |  | ||||||
| 	bpf = bps / 8; |  | ||||||
| 
 |  | ||||||
| 	pwareas = alloca(io->channels * sizeof(snd_pcm_channel_area_t)); |  | ||||||
| 
 |  | ||||||
| 	d = b->buffer->datas; |  | ||||||
| 
 |  | ||||||
| 	maxsize = d[0].maxsize; |  | ||||||
| 
 |  | ||||||
| 	filled = 0; |  | ||||||
| 	index = 0; |  | ||||||
| 	avail = maxsize - filled; |  | ||||||
| 	avail = SPA_MIN(avail, pw->min_avail * bpf); |  | ||||||
| 	avail = SPA_MIN(avail, *hw_avail * bpf); |  | ||||||
| 
 |  | ||||||
| 	do { |  | ||||||
| 	offset = index % maxsize; |  | ||||||
| 	nbytes = SPA_MIN(avail, maxsize - offset); |  | ||||||
| 
 |  | ||||||
| 	ptr = SPA_MEMBER(d[0].data, offset, void); |  | ||||||
| 
 |  | ||||||
| 	nframes = nbytes / bpf; |  | ||||||
| 	pw_log_trace(NAME" %p: %d %d %lu %d %d %p %d", pw, nbytes, avail, nframes, filled, offset, ptr, io->state); |  | ||||||
| 
 |  | ||||||
| 	for (channel = 0; channel < io->channels; channel++) { |  | ||||||
| 		pwareas[channel].addr = ptr; |  | ||||||
| 		pwareas[channel].first = channel * pw->sample_bits; |  | ||||||
| 		pwareas[channel].step = bps; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if (io->state != SND_PCM_STATE_RUNNING && io->state != SND_PCM_STATE_DRAINING) { |  | ||||||
| 		pw_log_trace(NAME" %p: silence %lu frames %d", pw, nframes, io->state); |  | ||||||
| 		for (channel = 0; channel < io->channels; channel++) |  | ||||||
| 			snd_pcm_area_silence(&pwareas[channel], 0, nframes, io->format); |  | ||||||
| 		goto done; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	areas = snd_pcm_ioplug_mmap_areas(io); |  | ||||||
| 
 |  | ||||||
| 	xfer = 0; |  | ||||||
| 	while (xfer < nframes) { |  | ||||||
| 		snd_pcm_uframes_t frames = nframes - xfer; |  | ||||||
| 		snd_pcm_uframes_t offset = pw->hw_ptr % io->buffer_size; |  | ||||||
| 		snd_pcm_uframes_t cont = io->buffer_size - offset; |  | ||||||
| 
 |  | ||||||
| 		if (cont < frames) |  | ||||||
| 			frames = cont; |  | ||||||
| 
 |  | ||||||
| 		snd_pcm_areas_copy(pwareas, xfer, |  | ||||||
| 				   areas, offset, |  | ||||||
| 				   io->channels, frames, io->format); |  | ||||||
| 
 |  | ||||||
| 		pw->hw_ptr += frames; |  | ||||||
| 		if (pw->hw_ptr > pw->boundary) |  | ||||||
| 			pw->hw_ptr -= pw->boundary; |  | ||||||
| 		xfer += frames; |  | ||||||
| 	} |  | ||||||
| 	*hw_avail -= xfer; |  | ||||||
| 
 |  | ||||||
|       done: |  | ||||||
| 	index += nbytes; |  | ||||||
| 	avail -= nbytes; |  | ||||||
| 	} while (avail > 0); |  | ||||||
| 
 |  | ||||||
| 	d[0].chunk->offset = 0; |  | ||||||
| 	d[0].chunk->size = index; |  | ||||||
| 	d[0].chunk->stride = 0; |  | ||||||
| 
 |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int |  | ||||||
| snd_pcm_pipewire_process_record(snd_pcm_pipewire_t *pw, struct pw_buffer *b, snd_pcm_uframes_t *hw_avail) |  | ||||||
| { |  | ||||||
| 	snd_pcm_ioplug_t *io = &pw->io; |  | ||||||
| 	const snd_pcm_channel_area_t *areas; |  | ||||||
| 	snd_pcm_channel_area_t *pwareas; |  | ||||||
| 	snd_pcm_uframes_t xfer = 0; |  | ||||||
| 	unsigned int channel, bps, bpf; |  | ||||||
| 	snd_pcm_uframes_t nframes; |  | ||||||
| 	uint32_t offset, index = 0, nbytes, avail, maxsize; |  | ||||||
| 	struct spa_data *d; | 	struct spa_data *d; | ||||||
| 	void *ptr; | 	void *ptr; | ||||||
| 
 | 
 | ||||||
| 	bps = io->channels * pw->sample_bits; | 	d = b->buffer->datas; | ||||||
| 	bpf = bps / 8; |  | ||||||
| 
 |  | ||||||
| 	pwareas = alloca(io->channels * sizeof(snd_pcm_channel_area_t)); | 	pwareas = alloca(io->channels * sizeof(snd_pcm_channel_area_t)); | ||||||
| 
 | 
 | ||||||
| 	d = b->buffer->datas; | 	if (io->stream == SND_PCM_STREAM_PLAYBACK) { | ||||||
|  | 		nframes = d[0].maxsize - SPA_MIN(d[0].maxsize, d[0].chunk->offset); | ||||||
|  | 		nframes /= pw->stride; | ||||||
|  | 		nframes = SPA_MIN(nframes, pw->min_avail); | ||||||
|  | 	} else { | ||||||
|  | 		nframes = d[0].chunk->size / pw->stride; | ||||||
|  | 	} | ||||||
|  | 	nframes = SPA_MIN(nframes, *hw_avail); | ||||||
| 
 | 
 | ||||||
| 	maxsize = d[0].chunk->size; | 	if (pw->blocks == 1) { | ||||||
| 	avail = SPA_MIN(maxsize, *hw_avail * bpf); | 		ptr = SPA_MEMBER(d[0].data, d[0].chunk->offset, void); | ||||||
| 	index = d[0].chunk->offset; | 		for (channel = 0; channel < io->channels; channel++) { | ||||||
| 
 | 			pwareas[channel].addr = ptr; | ||||||
| 	if (avail < maxsize) | 			pwareas[channel].first = channel * pw->sample_bits; | ||||||
| 		pw->xrun_detected = true; | 			pwareas[channel].step = io->channels * pw->sample_bits; | ||||||
| 
 | 		} | ||||||
| 	do { | 		if (io->stream == SND_PCM_STREAM_PLAYBACK) | ||||||
| 	avail = SPA_MIN(avail, pw->min_avail * bpf); | 			d[0].chunk->size = nframes * pw->stride; | ||||||
| 	offset = index % maxsize; |         } else { | ||||||
| 	nbytes = SPA_MIN(avail, maxsize - offset); | 		for (channel = 0; channel < io->channels; channel++) { | ||||||
| 	ptr = SPA_MEMBER(d[0].data, offset, void); | 			ptr = SPA_MEMBER(d[channel].data, d[channel].chunk->offset, void); | ||||||
| 
 | 			pwareas[channel].addr = ptr; | ||||||
| 	pw_log_trace(NAME" %p: %d %ld %d %d %d %p", pw, maxsize, *hw_avail, nbytes, avail, offset, ptr); | 			pwareas[channel].first = 0; | ||||||
| 	nframes = nbytes / bpf; | 			pwareas[channel].step = pw->sample_bits; | ||||||
| 
 | 			if (io->stream == SND_PCM_STREAM_PLAYBACK) | ||||||
| 	for (channel = 0; channel < io->channels; channel++) { | 				d[channel].chunk->size = nframes * pw->stride; | ||||||
| 		pwareas[channel].addr = ptr; | 		} | ||||||
| 		pwareas[channel].first = channel * pw->sample_bits; |  | ||||||
| 		pwareas[channel].step = bps; |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	areas = snd_pcm_ioplug_mmap_areas(io); | 	if (io->state == SND_PCM_STATE_RUNNING || | ||||||
|  | 	    io->state == SND_PCM_STATE_DRAINING) { | ||||||
|  | 		snd_pcm_uframes_t hw_ptr = pw->hw_ptr; | ||||||
|  |                 if (*hw_avail > 0) { | ||||||
|  |                         const snd_pcm_channel_area_t *areas = snd_pcm_ioplug_mmap_areas(io); | ||||||
|  |                         const snd_pcm_uframes_t offset = hw_ptr % io->buffer_size; | ||||||
| 
 | 
 | ||||||
| 	xfer = 0; |                         xfer = nframes; | ||||||
| 	while (xfer < nframes) { |                         if (xfer > *hw_avail) | ||||||
| 		snd_pcm_uframes_t frames = nframes - xfer; |                                 xfer = *hw_avail; | ||||||
| 		snd_pcm_uframes_t offset = pw->hw_ptr % io->buffer_size; |  | ||||||
| 		snd_pcm_uframes_t cont = io->buffer_size - offset; |  | ||||||
| 
 | 
 | ||||||
| 		if (cont < frames) |                         if (io->stream == SND_PCM_STREAM_PLAYBACK) | ||||||
| 			frames = cont; |                                 snd_pcm_areas_copy_wrap(pwareas, 0, nframes, | ||||||
|  |                                                         areas, offset, | ||||||
|  |                                                         io->buffer_size, | ||||||
|  |                                                         io->channels, xfer, | ||||||
|  |                                                         io->format); | ||||||
|  |                         else | ||||||
|  |                                 snd_pcm_areas_copy_wrap(areas, offset, | ||||||
|  |                                                         io->buffer_size, | ||||||
|  |                                                         pwareas, 0, nframes, | ||||||
|  |                                                         io->channels, xfer, | ||||||
|  |                                                         io->format); | ||||||
| 
 | 
 | ||||||
| 		snd_pcm_areas_copy(areas, offset, |                         hw_ptr += xfer; | ||||||
| 				   pwareas, xfer, |                         if (hw_ptr > pw->boundary) | ||||||
| 				   io->channels, frames, io->format); |                                 hw_ptr -= pw->boundary; | ||||||
|  |                         pw->hw_ptr = hw_ptr; | ||||||
|  |                 } | ||||||
|  |         } | ||||||
|  |         /* check if requested frames were copied */ | ||||||
|  | 	if (xfer < nframes) { | ||||||
|  | 		/* always fill the not yet written JACK buffer with silence */ | ||||||
|  | 		if (io->stream == SND_PCM_STREAM_PLAYBACK) { | ||||||
|  | 			const snd_pcm_uframes_t frames = nframes - xfer; | ||||||
| 
 | 
 | ||||||
| 		pw->hw_ptr += frames; | 			snd_pcm_areas_silence(pwareas, xfer, io->channels, | ||||||
| 		if (pw->hw_ptr > pw->boundary) |                                               frames, io->format); | ||||||
| 			pw->hw_ptr -= pw->boundary; | 			xfer += frames; | ||||||
| 		xfer += frames; |                 } | ||||||
|  | 		if (io->state == SND_PCM_STATE_RUNNING || | ||||||
|  | 		    io->state == SND_PCM_STATE_DRAINING) { | ||||||
|  | 			/* report Xrun to user application */ | ||||||
|  | 			pw->xrun_detected = true; | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 	*hw_avail -= xfer; | 	*hw_avail -= xfer; | ||||||
| 	avail -= nbytes; |  | ||||||
| 	index += nbytes; |  | ||||||
| 	} while (avail > 0); |  | ||||||
| 
 |  | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -380,10 +318,7 @@ static void on_stream_process(void *data) | ||||||
| 	if (b == NULL) | 	if (b == NULL) | ||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
| 	if (io->stream == SND_PCM_STREAM_PLAYBACK) | 	snd_pcm_pipewire_process(pw, b, &hw_avail); | ||||||
| 		snd_pcm_pipewire_process_playback(pw, b, &hw_avail); |  | ||||||
| 	else |  | ||||||
| 		snd_pcm_pipewire_process_record(pw, b, &hw_avail); |  | ||||||
| 
 | 
 | ||||||
| 	pw_stream_queue_buffer(pw->stream, b); | 	pw_stream_queue_buffer(pw->stream, b); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Wim Taymans
						Wim Taymans