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 | ||||
| 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; | ||||
| 	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; | ||||
| 	int32_t filled; | ||||
| 	void *ptr; | ||||
|         unsigned int channel; | ||||
| 	struct spa_data *d; | ||||
| 
 | ||||
| 	bps = io->channels * pw->sample_bits; | ||||
| 	bpf = bps / 8; | ||||
| 
 | ||||
| 	pwareas = alloca(io->channels * sizeof(snd_pcm_channel_area_t)); | ||||
| 	void *ptr; | ||||
| 
 | ||||
| 	d = b->buffer->datas; | ||||
| 	pwareas = alloca(io->channels * sizeof(snd_pcm_channel_area_t)); | ||||
| 
 | ||||
| 	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); | ||||
| 	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); | ||||
| 
 | ||||
| 	if (pw->blocks == 1) { | ||||
| 		ptr = SPA_MEMBER(d[0].data, d[0].chunk->offset, void); | ||||
| 		for (channel = 0; channel < io->channels; channel++) { | ||||
| 			pwareas[channel].addr = ptr; | ||||
| 			pwareas[channel].first = channel * pw->sample_bits; | ||||
| 		pwareas[channel].step = bps; | ||||
| 			pwareas[channel].step = io->channels * pw->sample_bits; | ||||
| 		} | ||||
| 		if (io->stream == SND_PCM_STREAM_PLAYBACK) | ||||
| 			d[0].chunk->size = nframes * pw->stride; | ||||
|         } else { | ||||
| 		for (channel = 0; channel < io->channels; channel++) { | ||||
| 			ptr = SPA_MEMBER(d[channel].data, d[channel].chunk->offset, void); | ||||
| 			pwareas[channel].addr = ptr; | ||||
| 			pwareas[channel].first = 0; | ||||
| 			pwareas[channel].step = pw->sample_bits; | ||||
| 			if (io->stream == SND_PCM_STREAM_PLAYBACK) | ||||
| 				d[channel].chunk->size = nframes * pw->stride; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	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; | ||||
| 	} | ||||
| 	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; | ||||
| 
 | ||||
| 	areas = snd_pcm_ioplug_mmap_areas(io); | ||||
|                         xfer = nframes; | ||||
|                         if (xfer > *hw_avail) | ||||
|                                 xfer = *hw_avail; | ||||
| 
 | ||||
| 	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, | ||||
|                         if (io->stream == SND_PCM_STREAM_PLAYBACK) | ||||
|                                 snd_pcm_areas_copy_wrap(pwareas, 0, nframes, | ||||
|                                                         areas, offset, | ||||
| 				   io->channels, frames, io->format); | ||||
|                                                         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); | ||||
| 
 | ||||
| 		pw->hw_ptr += frames; | ||||
| 		if (pw->hw_ptr > pw->boundary) | ||||
| 			pw->hw_ptr -= pw->boundary; | ||||
|                         hw_ptr += xfer; | ||||
|                         if (hw_ptr > pw->boundary) | ||||
|                                 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; | ||||
| 
 | ||||
| 			snd_pcm_areas_silence(pwareas, xfer, io->channels, | ||||
|                                               frames, io->format); | ||||
| 			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; | ||||
| 	void *ptr; | ||||
| 
 | ||||
| 	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].chunk->size; | ||||
| 	avail = SPA_MIN(maxsize, *hw_avail * bpf); | ||||
| 	index = d[0].chunk->offset; | ||||
| 
 | ||||
| 	if (avail < maxsize) | ||||
| 		if (io->state == SND_PCM_STATE_RUNNING || | ||||
| 		    io->state == SND_PCM_STATE_DRAINING) { | ||||
| 			/* report Xrun to user application */ | ||||
| 			pw->xrun_detected = true; | ||||
| 
 | ||||
| 	do { | ||||
| 	avail = SPA_MIN(avail, pw->min_avail * bpf); | ||||
| 	offset = index % maxsize; | ||||
| 	nbytes = SPA_MIN(avail, maxsize - offset); | ||||
| 	ptr = SPA_MEMBER(d[0].data, offset, void); | ||||
| 
 | ||||
| 	pw_log_trace(NAME" %p: %d %ld %d %d %d %p", pw, maxsize, *hw_avail, nbytes, avail, offset, ptr); | ||||
| 	nframes = nbytes / bpf; | ||||
| 
 | ||||
| 	for (channel = 0; channel < io->channels; channel++) { | ||||
| 		pwareas[channel].addr = ptr; | ||||
| 		pwareas[channel].first = channel * pw->sample_bits; | ||||
| 		pwareas[channel].step = bps; | ||||
| 		} | ||||
| 
 | ||||
| 	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(areas, offset, | ||||
| 				   pwareas, xfer, | ||||
| 				   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; | ||||
| 	avail -= nbytes; | ||||
| 	index += nbytes; | ||||
| 	} while (avail > 0); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
|  | @ -380,10 +318,7 @@ static void on_stream_process(void *data) | |||
| 	if (b == NULL) | ||||
| 		return; | ||||
| 
 | ||||
| 	if (io->stream == SND_PCM_STREAM_PLAYBACK) | ||||
| 		snd_pcm_pipewire_process_playback(pw, b, &hw_avail); | ||||
| 	else | ||||
| 		snd_pcm_pipewire_process_record(pw, b, &hw_avail); | ||||
| 	snd_pcm_pipewire_process(pw, b, &hw_avail); | ||||
| 
 | ||||
| 	pw_stream_queue_buffer(pw->stream, b); | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Wim Taymans
						Wim Taymans