mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04:00
alsa: add read/write access mode
Add support for read/write access mode when mmap is not available. See #526
This commit is contained in:
parent
c430b1de58
commit
18b5199d44
3 changed files with 189 additions and 95 deletions
|
|
@ -646,7 +646,7 @@ static int impl_node_process(void *object)
|
|||
SPA_FLAG_CLEAR(b->flags, BUFFER_FLAG_OUT);
|
||||
input->buffer_id = SPA_ID_INVALID;
|
||||
|
||||
spa_alsa_write(this, 0);
|
||||
spa_alsa_write(this);
|
||||
|
||||
input->status = SPA_STATUS_OK;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -258,7 +258,6 @@ static void sanitize_map(snd_pcm_chmap_t* map)
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
|
|
@ -320,13 +319,15 @@ spa_alsa_enum_format(struct state *state, int seq, uint32_t start, uint32_t num,
|
|||
const struct format_info *fi = &format_info[i];
|
||||
|
||||
if (snd_pcm_format_mask_test(fmask, fi->format)) {
|
||||
if (snd_pcm_access_mask_test(amask, SND_PCM_ACCESS_MMAP_INTERLEAVED) &&
|
||||
if ((snd_pcm_access_mask_test(amask, SND_PCM_ACCESS_MMAP_INTERLEAVED) ||
|
||||
snd_pcm_access_mask_test(amask, SND_PCM_ACCESS_RW_INTERLEAVED)) &&
|
||||
(state->default_format == 0 || state->default_format == fi->spa_format)) {
|
||||
if (j++ == 0)
|
||||
spa_pod_builder_id(&b, fi->spa_format);
|
||||
spa_pod_builder_id(&b, fi->spa_format);
|
||||
}
|
||||
if (snd_pcm_access_mask_test(amask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED) &&
|
||||
if ((snd_pcm_access_mask_test(amask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED) ||
|
||||
snd_pcm_access_mask_test(amask, SND_PCM_ACCESS_RW_NONINTERLEAVED)) &&
|
||||
fi->spa_pformat != SPA_AUDIO_FORMAT_UNKNOWN &&
|
||||
(state->default_format == 0 || state->default_format == fi->spa_pformat)) {
|
||||
if (j++ == 0)
|
||||
|
|
@ -487,6 +488,7 @@ int spa_alsa_set_format(struct state *state, struct spa_audio_info *fmt, uint32_
|
|||
int err, dir;
|
||||
snd_pcm_hw_params_t *params;
|
||||
snd_pcm_format_t format;
|
||||
snd_pcm_access_mask_t *amask;
|
||||
struct spa_audio_info_raw *info = &fmt->info.raw;
|
||||
snd_pcm_t *hndl;
|
||||
unsigned int periods;
|
||||
|
|
@ -511,17 +513,34 @@ int spa_alsa_set_format(struct state *state, struct spa_audio_info *fmt, uint32_
|
|||
}
|
||||
|
||||
/* set the interleaved/planar read/write format */
|
||||
CHECK(snd_pcm_hw_params_set_access(hndl, params,
|
||||
snd_pcm_access_mask_alloca(&amask);
|
||||
snd_pcm_hw_params_get_access_mask(params, amask);
|
||||
|
||||
if ((err = snd_pcm_hw_params_set_access(hndl, params,
|
||||
planar ? SND_PCM_ACCESS_MMAP_NONINTERLEAVED
|
||||
: SND_PCM_ACCESS_MMAP_INTERLEAVED), "set_access");
|
||||
: SND_PCM_ACCESS_MMAP_INTERLEAVED)) < 0) {
|
||||
spa_log_debug(state->log, NAME" %p: MMAP not possible: %s", state,
|
||||
snd_strerror(err));
|
||||
if ((err = snd_pcm_hw_params_set_access(hndl, params,
|
||||
planar ? SND_PCM_ACCESS_RW_NONINTERLEAVED
|
||||
: SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
|
||||
spa_log_error(state->log, NAME" %p: RW not possible: %s", state,
|
||||
snd_strerror(err));
|
||||
return err;
|
||||
}
|
||||
state->use_mmap = false;
|
||||
} else {
|
||||
state->use_mmap = true;
|
||||
}
|
||||
|
||||
/* disable ALSA wakeups, we use a timer */
|
||||
if (snd_pcm_hw_params_can_disable_period_wakeup(params))
|
||||
CHECK(snd_pcm_hw_params_set_period_wakeup(hndl, params, 0), "set_period_wakeup");
|
||||
|
||||
/* set the sample format */
|
||||
spa_log_debug(state->log, NAME" %p: Stream parameters are %iHz, %s %s, %i channels",
|
||||
spa_log_debug(state->log, NAME" %p: Stream parameters are %iHz fmt:%s access:%s-%s channels:%i",
|
||||
state, info->rate, snd_pcm_format_name(format),
|
||||
state->use_mmap ? "mmap" : "rw",
|
||||
planar ? "planar" : "interleaved", info->channels);
|
||||
CHECK(snd_pcm_hw_params_set_format(hndl, params, format), "set_format");
|
||||
|
||||
|
|
@ -553,6 +572,7 @@ int spa_alsa_set_format(struct state *state, struct spa_audio_info *fmt, uint32_
|
|||
state->channels = info->channels;
|
||||
state->rate = info->rate;
|
||||
state->frame_size = snd_pcm_format_physical_width(format) / 8;
|
||||
state->planar = planar;
|
||||
state->blocks = 1;
|
||||
if (planar)
|
||||
state->blocks *= info->channels;
|
||||
|
|
@ -589,11 +609,13 @@ int spa_alsa_set_format(struct state *state, struct spa_audio_info *fmt, uint32_
|
|||
state->headroom = is_batch ? period_size : 0;
|
||||
periods = state->buffer_frames / state->period_frames;
|
||||
|
||||
spa_log_info(state->log, NAME" %s (%s): format:%s %s rate:%d channels:%d "
|
||||
spa_log_info(state->log, NAME" %s (%s): format:%s access:%s-%s rate:%d channels:%d "
|
||||
"buffer frames %lu, period frames %lu, periods %u, frame_size %zd",
|
||||
state->props.device,
|
||||
state->stream == SND_PCM_STREAM_CAPTURE ? "capture" : "playback",
|
||||
snd_pcm_format_name(state->format), planar ? "planar" : "interleaved",
|
||||
snd_pcm_format_name(state->format),
|
||||
state->use_mmap ? "mmap" : "rw",
|
||||
planar ? "planar" : "interleaved",
|
||||
state->rate, state->channels, state->buffer_frames, state->period_frames,
|
||||
periods, state->frame_size);
|
||||
|
||||
|
|
@ -647,6 +669,62 @@ static int set_timeout(struct state *state, uint64_t time)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int spa_alsa_silence(struct state *state, snd_pcm_uframes_t silence)
|
||||
{
|
||||
snd_pcm_t *hndl = state->hndl;
|
||||
const snd_pcm_channel_area_t *my_areas;
|
||||
snd_pcm_uframes_t frames, offset;
|
||||
int i, res;
|
||||
|
||||
if (state->use_mmap) {
|
||||
frames = state->buffer_frames;
|
||||
|
||||
if (SPA_UNLIKELY((res = snd_pcm_mmap_begin(hndl, &my_areas, &offset, &frames)) < 0)) {
|
||||
spa_log_error(state->log, NAME" %p: snd_pcm_mmap_begin error: %s",
|
||||
state, snd_strerror(res));
|
||||
return res;
|
||||
}
|
||||
silence = SPA_MIN(silence, frames);
|
||||
|
||||
spa_log_trace_fp(state->log, NAME" %p: silence %ld", state, silence);
|
||||
snd_pcm_areas_silence(my_areas, offset, state->channels, silence, state->format);
|
||||
|
||||
if (SPA_UNLIKELY((res = snd_pcm_mmap_commit(hndl, offset, silence)) < 0)) {
|
||||
spa_log_error(state->log, NAME" %p: snd_pcm_mmap_commit error: %s",
|
||||
state, snd_strerror(res));
|
||||
return res;
|
||||
}
|
||||
} else {
|
||||
uint8_t buffer[silence * state->frame_size];
|
||||
memset(buffer, 0, silence * state->frame_size);
|
||||
|
||||
if (state->planar) {
|
||||
void *bufs[state->channels];
|
||||
for (i = 0; i < state->channels; i++)
|
||||
bufs[i] = buffer;
|
||||
snd_pcm_writen(hndl, bufs, silence);
|
||||
} else {
|
||||
snd_pcm_writei(hndl, buffer, silence);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int do_start(struct state *state)
|
||||
{
|
||||
int res;
|
||||
if (SPA_UNLIKELY(!state->alsa_started)) {
|
||||
spa_log_trace(state->log, NAME" %p: snd_pcm_start", state);
|
||||
if ((res = snd_pcm_start(state->hndl)) < 0) {
|
||||
spa_log_error(state->log, NAME" %p: snd_pcm_start: %s",
|
||||
state, snd_strerror(res));
|
||||
return res;
|
||||
}
|
||||
state->alsa_started = true;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int alsa_recover(struct state *state, int err)
|
||||
{
|
||||
int res, st;
|
||||
|
|
@ -700,17 +778,12 @@ recover:
|
|||
}
|
||||
spa_dll_init(&state->dll);
|
||||
state->alsa_recovering = true;
|
||||
state->alsa_started = false;
|
||||
|
||||
if (state->stream == SND_PCM_STREAM_CAPTURE) {
|
||||
if ((res = snd_pcm_start(state->hndl)) < 0) {
|
||||
spa_log_error(state->log, NAME" %p: snd_pcm_start: %s",
|
||||
state, snd_strerror(res));
|
||||
return res;
|
||||
}
|
||||
state->alsa_started = true;
|
||||
do_start(state);
|
||||
} else {
|
||||
state->alsa_started = false;
|
||||
spa_alsa_write(state, state->threshold * 2);
|
||||
spa_alsa_silence(state, state->threshold * 2);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -826,13 +899,13 @@ static int update_time(struct state *state, uint64_t nsec, snd_pcm_sframes_t del
|
|||
return 0;
|
||||
}
|
||||
|
||||
int spa_alsa_write(struct state *state, snd_pcm_uframes_t silence)
|
||||
int spa_alsa_write(struct state *state)
|
||||
{
|
||||
snd_pcm_t *hndl = state->hndl;
|
||||
const snd_pcm_channel_area_t *my_areas;
|
||||
snd_pcm_uframes_t written, frames, offset, off, to_write, total_written;
|
||||
snd_pcm_sframes_t commitres;
|
||||
int res;
|
||||
int res = 0;
|
||||
|
||||
if (SPA_LIKELY(state->position && state->duration != state->position->clock.duration)) {
|
||||
state->duration = state->position->clock.duration;
|
||||
|
|
@ -869,18 +942,22 @@ int spa_alsa_write(struct state *state, snd_pcm_uframes_t silence)
|
|||
|
||||
total_written = 0;
|
||||
again:
|
||||
frames = state->buffer_frames;
|
||||
if (SPA_UNLIKELY((res = snd_pcm_mmap_begin(hndl, &my_areas, &offset, &frames)) < 0)) {
|
||||
spa_log_error(state->log, NAME" %p: snd_pcm_mmap_begin error: %s",
|
||||
state, snd_strerror(res));
|
||||
return res;
|
||||
}
|
||||
spa_log_trace_fp(state->log, NAME" %p: begin %ld %ld %d %ld",
|
||||
state, offset, frames, state->threshold, silence);
|
||||
|
||||
silence = SPA_MIN(silence, frames);
|
||||
frames = state->buffer_frames;
|
||||
if (state->use_mmap) {
|
||||
if (SPA_UNLIKELY((res = snd_pcm_mmap_begin(hndl, &my_areas, &offset, &frames)) < 0)) {
|
||||
spa_log_error(state->log, NAME" %p: snd_pcm_mmap_begin error: %s",
|
||||
state, snd_strerror(res));
|
||||
return res;
|
||||
}
|
||||
spa_log_trace_fp(state->log, NAME" %p: begin %ld %ld %d",
|
||||
state, offset, frames, state->threshold);
|
||||
off = offset;
|
||||
} else {
|
||||
off = 0;
|
||||
}
|
||||
|
||||
to_write = frames;
|
||||
off = offset;
|
||||
written = 0;
|
||||
|
||||
while (!spa_list_is_empty(&state->ready) && to_write > 0) {
|
||||
|
|
@ -907,14 +984,35 @@ again:
|
|||
l0 = SPA_MIN(n_bytes, maxsize - offs);
|
||||
l1 = n_bytes - l0;
|
||||
|
||||
for (i = 0; i < b->buf->n_datas; i++) {
|
||||
dst = SPA_MEMBER(my_areas[i].addr, off * state->frame_size, uint8_t);
|
||||
src = d[i].data;
|
||||
if (SPA_LIKELY(state->use_mmap)) {
|
||||
for (i = 0; i < b->buf->n_datas; i++) {
|
||||
dst = SPA_MEMBER(my_areas[i].addr, off * state->frame_size, uint8_t);
|
||||
src = d[i].data;
|
||||
|
||||
spa_memcpy(dst, src + offs, l0);
|
||||
if (SPA_UNLIKELY(l1 > 0))
|
||||
spa_memcpy(dst + l0, src, l1);
|
||||
spa_memcpy(dst, src + offs, l0);
|
||||
if (SPA_UNLIKELY(l1 > 0))
|
||||
spa_memcpy(dst + l0, src, l1);
|
||||
}
|
||||
} else {
|
||||
if (state->planar) {
|
||||
void *bufs[b->buf->n_datas];
|
||||
|
||||
for (i = 0; i < b->buf->n_datas; i++)
|
||||
bufs[i] = SPA_MEMBER(d[i].data, offs, void);
|
||||
snd_pcm_writen(hndl, bufs, l0 / state->frame_size);
|
||||
if (SPA_UNLIKELY(l1 > 0)) {
|
||||
for (i = 0; i < b->buf->n_datas; i++)
|
||||
bufs[i] = d[i].data;
|
||||
snd_pcm_writen(hndl, bufs, l1 / state->frame_size);
|
||||
}
|
||||
} else {
|
||||
src = d[0].data;
|
||||
snd_pcm_writei(hndl, src + offs, l0 / state->frame_size);
|
||||
if (SPA_UNLIKELY(l1 > 0))
|
||||
snd_pcm_writei(hndl, src, l1 / state->frame_size);
|
||||
}
|
||||
}
|
||||
|
||||
state->ready_offset += n_bytes;
|
||||
|
||||
if (state->ready_offset >= size) {
|
||||
|
|
@ -930,32 +1028,24 @@ again:
|
|||
written += n_frames;
|
||||
off += n_frames;
|
||||
to_write -= n_frames;
|
||||
if (silence > n_frames)
|
||||
silence -= n_frames;
|
||||
else
|
||||
silence = 0;
|
||||
}
|
||||
|
||||
if (SPA_UNLIKELY(silence > 0)) {
|
||||
spa_log_trace_fp(state->log, NAME" %p: silence %ld", state, silence);
|
||||
snd_pcm_areas_silence(my_areas, off, state->channels, silence, state->format);
|
||||
written += silence;
|
||||
}
|
||||
|
||||
spa_log_trace_fp(state->log, NAME" %p: commit %ld %ld %"PRIi64,
|
||||
state, offset, written, state->sample_count);
|
||||
total_written += written;
|
||||
|
||||
if (SPA_UNLIKELY((commitres = snd_pcm_mmap_commit(hndl, offset, written)) < 0)) {
|
||||
spa_log_error(state->log, NAME" %p: snd_pcm_mmap_commit error: %s",
|
||||
state, snd_strerror(commitres));
|
||||
if (commitres != -EPIPE && commitres != -ESTRPIPE)
|
||||
return res;
|
||||
}
|
||||
if (state->use_mmap) {
|
||||
if (SPA_UNLIKELY((commitres = snd_pcm_mmap_commit(hndl, offset, written)) < 0)) {
|
||||
spa_log_error(state->log, NAME" %p: snd_pcm_mmap_commit error: %s",
|
||||
state, snd_strerror(commitres));
|
||||
if (commitres != -EPIPE && commitres != -ESTRPIPE)
|
||||
return res;
|
||||
}
|
||||
|
||||
if (commitres > 0 && written != (snd_pcm_uframes_t) commitres) {
|
||||
spa_log_warn(state->log, NAME" %p: mmap_commit wrote %ld instead of %ld",
|
||||
state, commitres, written);
|
||||
if (commitres > 0 && written != (snd_pcm_uframes_t) commitres) {
|
||||
spa_log_warn(state->log, NAME" %p: mmap_commit wrote %ld instead of %ld",
|
||||
state, commitres, written);
|
||||
}
|
||||
}
|
||||
|
||||
if (!spa_list_is_empty(&state->ready) && written > 0)
|
||||
|
|
@ -963,15 +1053,9 @@ again:
|
|||
|
||||
state->sample_count += total_written;
|
||||
|
||||
if (SPA_UNLIKELY(!state->alsa_started && total_written > 0)) {
|
||||
spa_log_trace(state->log, NAME" %p: snd_pcm_start %lu", state, written);
|
||||
if ((res = snd_pcm_start(hndl)) < 0) {
|
||||
spa_log_error(state->log, NAME" %p: snd_pcm_start: %s",
|
||||
state, snd_strerror(res));
|
||||
return res;
|
||||
}
|
||||
state->alsa_started = true;
|
||||
}
|
||||
if (SPA_UNLIKELY(!state->alsa_started && total_written > 0))
|
||||
do_start(state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1035,15 +1119,23 @@ push_frames(struct state *state,
|
|||
d[i].chunk->stride = state->frame_size;
|
||||
}
|
||||
} else {
|
||||
void *bufs[b->buf->n_datas];
|
||||
for (i = 0; i < b->buf->n_datas; i++) {
|
||||
memset(d[i].data, 0, n_bytes);
|
||||
bufs[i] = d[i].data;
|
||||
d[i].chunk->offset = 0;
|
||||
d[i].chunk->size = n_bytes;
|
||||
d[i].chunk->stride = state->frame_size;
|
||||
}
|
||||
if (state->planar) {
|
||||
snd_pcm_readn(state->hndl, bufs, total_frames);
|
||||
} else {
|
||||
snd_pcm_readi(state->hndl, bufs[0], total_frames);
|
||||
}
|
||||
}
|
||||
spa_list_append(&state->ready, &b->link);
|
||||
}
|
||||
if (my_areas == NULL)
|
||||
snd_pcm_rewind(state->hndl, keep);
|
||||
return total_frames - keep;
|
||||
}
|
||||
|
||||
|
|
@ -1055,7 +1147,7 @@ int spa_alsa_read(struct state *state, snd_pcm_uframes_t silence)
|
|||
const snd_pcm_channel_area_t *my_areas;
|
||||
snd_pcm_uframes_t read, frames, offset;
|
||||
snd_pcm_sframes_t commitres;
|
||||
int res;
|
||||
int res = 0;
|
||||
|
||||
if (state->position) {
|
||||
if (state->duration != state->position->clock.duration) {
|
||||
|
|
@ -1111,33 +1203,38 @@ int spa_alsa_read(struct state *state, snd_pcm_uframes_t silence)
|
|||
if (frames == 0)
|
||||
frames = state->threshold + state->delay;
|
||||
|
||||
|
||||
to_read = state->buffer_frames;
|
||||
if ((res = snd_pcm_mmap_begin(hndl, &my_areas, &offset, &to_read)) < 0) {
|
||||
spa_log_error(state->log, NAME" %p: snd_pcm_mmap_begin error: %s",
|
||||
state, snd_strerror(res));
|
||||
return res;
|
||||
if (state->use_mmap) {
|
||||
to_read = state->buffer_frames;
|
||||
if ((res = snd_pcm_mmap_begin(hndl, &my_areas, &offset, &to_read)) < 0) {
|
||||
spa_log_error(state->log, NAME" %p: snd_pcm_mmap_begin error: %s",
|
||||
state, snd_strerror(res));
|
||||
return res;
|
||||
}
|
||||
spa_log_trace_fp(state->log, NAME" %p: begin offs:%ld frames:%ld to_read:%ld thres:%d", state,
|
||||
offset, frames, to_read, state->threshold);
|
||||
} else {
|
||||
my_areas = NULL;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
spa_log_trace_fp(state->log, NAME" %p: begin offs:%ld frames:%ld to_read:%ld thres:%d", state,
|
||||
offset, frames, to_read, state->threshold);
|
||||
|
||||
read = push_frames(state, my_areas, offset, frames, state->delay);
|
||||
|
||||
spa_log_trace_fp(state->log, NAME" %p: commit offs:%ld read:%ld count:%"PRIi64, state,
|
||||
offset, read, state->sample_count);
|
||||
total_read += read;
|
||||
|
||||
if ((commitres = snd_pcm_mmap_commit(hndl, offset, read)) < 0) {
|
||||
spa_log_error(state->log, NAME" %p: snd_pcm_mmap_commit error: %s",
|
||||
state, snd_strerror(commitres));
|
||||
if (commitres != -EPIPE && commitres != -ESTRPIPE)
|
||||
return res;
|
||||
}
|
||||
if (state->use_mmap) {
|
||||
spa_log_trace_fp(state->log, NAME" %p: commit offs:%ld read:%ld count:%"PRIi64, state,
|
||||
offset, read, state->sample_count);
|
||||
if ((commitres = snd_pcm_mmap_commit(hndl, offset, read)) < 0) {
|
||||
spa_log_error(state->log, NAME" %p: snd_pcm_mmap_commit error: %s",
|
||||
state, snd_strerror(commitres));
|
||||
if (commitres != -EPIPE && commitres != -ESTRPIPE)
|
||||
return res;
|
||||
}
|
||||
|
||||
if (commitres > 0 && read != (snd_pcm_uframes_t) commitres) {
|
||||
spa_log_warn(state->log, NAME" %p: mmap_commit read %ld instead of %ld",
|
||||
state, commitres, read);
|
||||
if (commitres > 0 && read != (snd_pcm_uframes_t) commitres) {
|
||||
spa_log_warn(state->log, NAME" %p: mmap_commit read %ld instead of %ld",
|
||||
state, commitres, read);
|
||||
}
|
||||
}
|
||||
|
||||
state->sample_count += total_read;
|
||||
|
|
@ -1169,7 +1266,7 @@ static int handle_play(struct state *state, uint64_t nsec,
|
|||
res = spa_node_call_ready(&state->callbacks, SPA_STATUS_NEED_DATA);
|
||||
}
|
||||
else {
|
||||
res = spa_alsa_write(state, 0);
|
||||
res = spa_alsa_write(state);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
|
@ -1349,17 +1446,12 @@ int spa_alsa_start(struct state *state)
|
|||
reset_buffers(state);
|
||||
state->alsa_sync = true;
|
||||
state->alsa_recovering = false;
|
||||
state->alsa_started = false;
|
||||
|
||||
if (state->stream == SND_PCM_STREAM_PLAYBACK) {
|
||||
state->alsa_started = false;
|
||||
spa_alsa_write(state, state->threshold * 2);
|
||||
spa_alsa_silence(state, state->threshold * 2);
|
||||
} else {
|
||||
if ((err = snd_pcm_start(state->hndl)) < 0) {
|
||||
spa_log_error(state->log, NAME" %p: snd_pcm_start: %s", state,
|
||||
snd_strerror(err));
|
||||
return err;
|
||||
}
|
||||
state->alsa_started = true;
|
||||
do_start(state);
|
||||
}
|
||||
|
||||
set_timers(state);
|
||||
|
|
|
|||
|
|
@ -159,6 +159,8 @@ struct state {
|
|||
unsigned int following:1;
|
||||
unsigned int matching:1;
|
||||
unsigned int resample:1;
|
||||
unsigned int use_mmap:1;
|
||||
unsigned int planar:1;
|
||||
|
||||
int64_t sample_count;
|
||||
|
||||
|
|
@ -186,7 +188,7 @@ int spa_alsa_reassign_follower(struct state *state);
|
|||
int spa_alsa_pause(struct state *state);
|
||||
int spa_alsa_close(struct state *state);
|
||||
|
||||
int spa_alsa_write(struct state *state, snd_pcm_uframes_t silence);
|
||||
int spa_alsa_write(struct state *state);
|
||||
int spa_alsa_read(struct state *state, snd_pcm_uframes_t silence);
|
||||
|
||||
void spa_alsa_recycle_buffer(struct state *state, uint32_t buffer_id);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue