mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-12-15 08:56:38 -05: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