mirror of
https://gitlab.freedesktop.org/pipewire/pipewire
synced 2024-07-22 18:54:36 +00:00
alsa: rework process function to support planar formats
This commit is contained in:
parent
bfc91c27a6
commit
64ee110356
|
@ -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 xfer = 0;
|
||||
snd_pcm_uframes_t nframes;
|
||||
uint32_t offset, index = 0, nbytes, avail, maxsize;
|
||||
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;
|
||||
unsigned int channel;
|
||||
struct spa_data *d;
|
||||
void *ptr;
|
||||
|
||||
bps = io->channels * pw->sample_bits;
|
||||
bpf = bps / 8;
|
||||
|
||||
d = b->buffer->datas;
|
||||
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;
|
||||
avail = SPA_MIN(maxsize, *hw_avail * bpf);
|
||||
index = d[0].chunk->offset;
|
||||
|
||||
if (avail < maxsize)
|
||||
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;
|
||||
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 = 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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
xfer = nframes;
|
||||
if (xfer > *hw_avail)
|
||||
xfer = *hw_avail;
|
||||
|
||||
if (cont < frames)
|
||||
frames = cont;
|
||||
if (io->stream == SND_PCM_STREAM_PLAYBACK)
|
||||
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,
|
||||
pwareas, xfer,
|
||||
io->channels, frames, io->format);
|
||||
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;
|
||||
|
||||
pw->hw_ptr += frames;
|
||||
if (pw->hw_ptr > pw->boundary)
|
||||
pw->hw_ptr -= pw->boundary;
|
||||
xfer += frames;
|
||||
snd_pcm_areas_silence(pwareas, xfer, io->channels,
|
||||
frames, io->format);
|
||||
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;
|
||||
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…
Reference in a new issue