|
Packit Service |
a9274b |
// SPDX-License-Identifier: GPL-2.0
|
|
Packit Service |
a9274b |
//
|
|
Packit Service |
a9274b |
// xfer-libasound-irq-rw.c - IRQ-based scheduling model for read/write operation.
|
|
Packit Service |
a9274b |
//
|
|
Packit Service |
a9274b |
// Copyright (c) 2018 Takashi Sakamoto <o-takashi@sakamocchi.jp>
|
|
Packit Service |
a9274b |
//
|
|
Packit Service |
a9274b |
// Licensed under the terms of the GNU General Public License, version 2.
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
#include "xfer-libasound.h"
|
|
Packit Service |
a9274b |
#include "misc.h"
|
|
Packit Service |
a9274b |
#include "frame-cache.h"
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
struct rw_closure {
|
|
Packit Service |
a9274b |
snd_pcm_access_t access;
|
|
Packit Service |
a9274b |
int (*process_frames)(struct libasound_state *state,
|
|
Packit Service |
a9274b |
snd_pcm_state_t status, unsigned int *frame_count,
|
|
Packit Service |
a9274b |
struct mapper_context *mapper,
|
|
Packit Service |
a9274b |
struct container_context *cntrs);
|
|
Packit Service |
a9274b |
struct frame_cache cache;
|
|
Packit Service |
a9274b |
};
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
static int wait_for_avail(struct libasound_state *state)
|
|
Packit Service |
a9274b |
{
|
|
Packit Service |
a9274b |
unsigned int msec_per_buffer;
|
|
Packit Service |
a9274b |
unsigned short revents;
|
|
Packit Service |
a9274b |
unsigned short event;
|
|
Packit Service |
a9274b |
int err;
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
// Wait during msec equivalent to all audio data frames in buffer
|
|
Packit Service |
a9274b |
// instead of period, for safe.
|
|
Packit Service |
a9274b |
err = snd_pcm_hw_params_get_buffer_time(state->hw_params,
|
|
Packit Service |
a9274b |
&msec_per_buffer, NULL);
|
|
Packit Service |
a9274b |
if (err < 0)
|
|
Packit Service |
a9274b |
return err;
|
|
Packit Service |
a9274b |
msec_per_buffer /= 1000;
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
// Wait for hardware IRQ when no available space.
|
|
Packit Service |
a9274b |
err = xfer_libasound_wait_event(state, msec_per_buffer, &revents);
|
|
Packit Service |
a9274b |
if (err < 0)
|
|
Packit Service |
a9274b |
return err;
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
// TODO: error reporting.
|
|
Packit Service |
a9274b |
if (revents & POLLERR)
|
|
Packit Service |
a9274b |
return -EIO;
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
if (snd_pcm_stream(state->handle) == SND_PCM_STREAM_CAPTURE)
|
|
Packit Service |
a9274b |
event = POLLIN;
|
|
Packit Service |
a9274b |
else
|
|
Packit Service |
a9274b |
event = POLLOUT;
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
if (!(revents & event))
|
|
Packit Service |
a9274b |
return -EAGAIN;
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
return 0;
|
|
Packit Service |
a9274b |
}
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
static int read_frames(struct libasound_state *state, unsigned int *frame_count,
|
|
Packit Service |
a9274b |
unsigned int avail_count, struct mapper_context *mapper,
|
|
Packit Service |
a9274b |
struct container_context *cntrs)
|
|
Packit Service |
a9274b |
{
|
|
Packit Service |
a9274b |
struct rw_closure *closure = state->private_data;
|
|
Packit Service |
a9274b |
snd_pcm_sframes_t handled_frame_count;
|
|
Packit Service |
a9274b |
unsigned int consumed_count;
|
|
Packit Service |
a9274b |
int err;
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
// Trim according up to expected frame count.
|
|
Packit Service |
a9274b |
if (*frame_count < avail_count)
|
|
Packit Service |
a9274b |
avail_count = *frame_count;
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
// Cache required amount of frames.
|
|
Packit Service |
a9274b |
if (avail_count > frame_cache_get_count(&closure->cache)) {
|
|
Packit Service |
a9274b |
avail_count -= frame_cache_get_count(&closure->cache);
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
// Execute write operation according to the shape of buffer.
|
|
Packit Service |
a9274b |
// These operations automatically start the substream.
|
|
Packit Service |
a9274b |
if (closure->access == SND_PCM_ACCESS_RW_INTERLEAVED) {
|
|
Packit Service |
a9274b |
handled_frame_count = snd_pcm_readi(state->handle,
|
|
Packit Service |
a9274b |
closure->cache.buf_ptr,
|
|
Packit Service |
a9274b |
avail_count);
|
|
Packit Service |
a9274b |
} else {
|
|
Packit Service |
a9274b |
handled_frame_count = snd_pcm_readn(state->handle,
|
|
Packit Service |
a9274b |
closure->cache.buf_ptr,
|
|
Packit Service |
a9274b |
avail_count);
|
|
Packit Service |
a9274b |
}
|
|
Packit Service |
a9274b |
if (handled_frame_count < 0) {
|
|
Packit Service |
a9274b |
err = handled_frame_count;
|
|
Packit Service |
a9274b |
return err;
|
|
Packit Service |
a9274b |
}
|
|
Packit Service |
a9274b |
frame_cache_increase_count(&closure->cache, handled_frame_count);
|
|
Packit Service |
a9274b |
avail_count = frame_cache_get_count(&closure->cache);
|
|
Packit Service |
a9274b |
}
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
// Write out to file descriptors.
|
|
Packit Service |
a9274b |
consumed_count = avail_count;
|
|
Packit Service |
a9274b |
err = mapper_context_process_frames(mapper, closure->cache.buf,
|
|
Packit Service |
a9274b |
&consumed_count, cntrs);
|
|
Packit Service |
a9274b |
if (err < 0)
|
|
Packit Service |
a9274b |
return err;
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
frame_cache_reduce(&closure->cache, consumed_count);
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
*frame_count = consumed_count;
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
return 0;
|
|
Packit Service |
a9274b |
}
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
static int r_process_frames_blocking(struct libasound_state *state,
|
|
Packit Service |
a9274b |
snd_pcm_state_t status,
|
|
Packit Service |
a9274b |
unsigned int *frame_count,
|
|
Packit Service |
a9274b |
struct mapper_context *mapper,
|
|
Packit Service |
a9274b |
struct container_context *cntrs)
|
|
Packit Service |
a9274b |
{
|
|
Packit Service |
a9274b |
snd_pcm_sframes_t avail;
|
|
Packit Service |
a9274b |
snd_pcm_uframes_t avail_count;
|
|
Packit Service |
a9274b |
int err = 0;
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
if (status == SND_PCM_STATE_RUNNING) {
|
|
Packit Service |
a9274b |
// Check available space on the buffer.
|
|
Packit Service |
a9274b |
avail = snd_pcm_avail(state->handle);
|
|
Packit Service |
a9274b |
if (avail < 0) {
|
|
Packit Service |
a9274b |
err = avail;
|
|
Packit Service |
a9274b |
goto error;
|
|
Packit Service |
a9274b |
}
|
|
Packit Service |
a9274b |
avail_count = (snd_pcm_uframes_t)avail;
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
if (avail_count == 0) {
|
|
Packit Service |
a9274b |
// Request data frames so that blocking is just
|
|
Packit Service |
a9274b |
// released.
|
|
Packit Service |
a9274b |
err = snd_pcm_sw_params_get_avail_min(state->sw_params,
|
|
Packit Service |
a9274b |
&avail_count);
|
|
Packit Service |
a9274b |
if (err < 0)
|
|
Packit Service |
a9274b |
goto error;
|
|
Packit Service |
a9274b |
}
|
|
Packit Service |
a9274b |
} else {
|
|
Packit Service |
a9274b |
// Request data frames so that the PCM substream starts.
|
|
Packit Service |
a9274b |
snd_pcm_uframes_t frame_count;
|
|
Packit Service |
a9274b |
err = snd_pcm_sw_params_get_start_threshold(state->sw_params,
|
|
Packit Service |
a9274b |
&frame_count);
|
|
Packit Service |
a9274b |
if (err < 0)
|
|
Packit Service |
a9274b |
goto error;
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
avail_count = (unsigned int)frame_count;
|
|
Packit Service |
a9274b |
}
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
err = read_frames(state, frame_count, avail_count, mapper, cntrs);
|
|
Packit Service |
a9274b |
if (err < 0)
|
|
Packit Service |
a9274b |
goto error;
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
return 0;
|
|
Packit Service |
a9274b |
error:
|
|
Packit Service |
a9274b |
*frame_count = 0;
|
|
Packit Service |
a9274b |
return err;
|
|
Packit Service |
a9274b |
}
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
static int r_process_frames_nonblocking(struct libasound_state *state,
|
|
Packit Service |
a9274b |
snd_pcm_state_t status,
|
|
Packit Service |
a9274b |
unsigned int *frame_count,
|
|
Packit Service |
a9274b |
struct mapper_context *mapper,
|
|
Packit Service |
a9274b |
struct container_context *cntrs)
|
|
Packit Service |
a9274b |
{
|
|
Packit Service |
a9274b |
snd_pcm_sframes_t avail;
|
|
Packit Service |
a9274b |
snd_pcm_uframes_t avail_count;
|
|
Packit Service |
a9274b |
int err = 0;
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
if (status != SND_PCM_STATE_RUNNING) {
|
|
Packit Service |
a9274b |
err = snd_pcm_start(state->handle);
|
|
Packit Service |
a9274b |
if (err < 0)
|
|
Packit Service |
a9274b |
goto error;
|
|
Packit Service |
a9274b |
}
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
if (state->use_waiter) {
|
|
Packit Service |
a9274b |
err = wait_for_avail(state);
|
|
Packit Service |
a9274b |
if (err < 0)
|
|
Packit Service |
a9274b |
goto error;
|
|
Packit Service |
a9274b |
}
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
// Check available space on the buffer.
|
|
Packit Service |
a9274b |
avail = snd_pcm_avail(state->handle);
|
|
Packit Service |
a9274b |
if (avail < 0) {
|
|
Packit Service |
a9274b |
err = avail;
|
|
Packit Service |
a9274b |
goto error;
|
|
Packit Service |
a9274b |
}
|
|
Packit Service |
a9274b |
avail_count = (snd_pcm_uframes_t)avail;
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
if (avail_count == 0) {
|
|
Packit Service |
a9274b |
// Let's go to a next iteration.
|
|
Packit Service |
a9274b |
err = 0;
|
|
Packit Service |
a9274b |
goto error;
|
|
Packit Service |
a9274b |
}
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
err = read_frames(state, frame_count, avail_count, mapper, cntrs);
|
|
Packit Service |
a9274b |
if (err < 0)
|
|
Packit Service |
a9274b |
goto error;
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
return 0;
|
|
Packit Service |
a9274b |
error:
|
|
Packit Service |
a9274b |
*frame_count = 0;
|
|
Packit Service |
a9274b |
return err;
|
|
Packit Service |
a9274b |
}
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
static int write_frames(struct libasound_state *state,
|
|
Packit Service |
a9274b |
unsigned int *frame_count, unsigned int avail_count,
|
|
Packit Service |
a9274b |
struct mapper_context *mapper,
|
|
Packit Service |
a9274b |
struct container_context *cntrs)
|
|
Packit Service |
a9274b |
{
|
|
Packit Service |
a9274b |
struct rw_closure *closure = state->private_data;
|
|
Packit Service |
a9274b |
snd_pcm_uframes_t consumed_count;
|
|
Packit Service |
a9274b |
snd_pcm_sframes_t handled_frame_count;
|
|
Packit Service |
a9274b |
int err;
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
// Trim according up to expected frame count.
|
|
Packit Service |
a9274b |
if (*frame_count < avail_count)
|
|
Packit Service |
a9274b |
avail_count = *frame_count;
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
// Cache required amount of frames.
|
|
Packit Service |
a9274b |
if (avail_count > frame_cache_get_count(&closure->cache)) {
|
|
Packit Service |
a9274b |
avail_count -= frame_cache_get_count(&closure->cache);
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
// Read frames to transfer.
|
|
Packit Service |
a9274b |
err = mapper_context_process_frames(mapper,
|
|
Packit Service |
a9274b |
closure->cache.buf_ptr, &avail_count, cntrs);
|
|
Packit Service |
a9274b |
if (err < 0)
|
|
Packit Service |
a9274b |
return err;
|
|
Packit Service |
a9274b |
frame_cache_increase_count(&closure->cache, avail_count);
|
|
Packit Service |
a9274b |
avail_count = frame_cache_get_count(&closure->cache);
|
|
Packit Service |
a9274b |
}
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
// Execute write operation according to the shape of buffer. These
|
|
Packit Service |
a9274b |
// operations automatically start the stream.
|
|
Packit Service |
a9274b |
consumed_count = avail_count;
|
|
Packit Service |
a9274b |
if (closure->access == SND_PCM_ACCESS_RW_INTERLEAVED) {
|
|
Packit Service |
a9274b |
handled_frame_count = snd_pcm_writei(state->handle,
|
|
Packit Service |
a9274b |
closure->cache.buf, consumed_count);
|
|
Packit Service |
a9274b |
} else {
|
|
Packit Service |
a9274b |
handled_frame_count = snd_pcm_writen(state->handle,
|
|
Packit Service |
a9274b |
closure->cache.buf, consumed_count);
|
|
Packit Service |
a9274b |
}
|
|
Packit Service |
a9274b |
if (handled_frame_count < 0) {
|
|
Packit Service |
a9274b |
err = handled_frame_count;
|
|
Packit Service |
a9274b |
return err;
|
|
Packit Service |
a9274b |
}
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
consumed_count = handled_frame_count;
|
|
Packit Service |
a9274b |
frame_cache_reduce(&closure->cache, consumed_count);
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
*frame_count = consumed_count;
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
return 0;
|
|
Packit Service |
a9274b |
}
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
static int w_process_frames_blocking(struct libasound_state *state,
|
|
Packit Service |
a9274b |
snd_pcm_state_t status,
|
|
Packit Service |
a9274b |
unsigned int *frame_count,
|
|
Packit Service |
a9274b |
struct mapper_context *mapper,
|
|
Packit Service |
a9274b |
struct container_context *cntrs)
|
|
Packit Service |
a9274b |
{
|
|
Packit Service |
a9274b |
snd_pcm_sframes_t avail;
|
|
Packit Service |
a9274b |
unsigned int avail_count;
|
|
Packit Service |
a9274b |
int err;
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
if (status == SND_PCM_STATE_RUNNING) {
|
|
Packit Service |
a9274b |
// Check available space on the buffer.
|
|
Packit Service |
a9274b |
avail = snd_pcm_avail(state->handle);
|
|
Packit Service |
a9274b |
if (avail < 0) {
|
|
Packit Service |
a9274b |
err = avail;
|
|
Packit Service |
a9274b |
goto error;
|
|
Packit Service |
a9274b |
}
|
|
Packit Service |
a9274b |
avail_count = (unsigned int)avail;
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
if (avail_count == 0) {
|
|
Packit Service |
a9274b |
// Fill with data frames so that blocking is just
|
|
Packit Service |
a9274b |
// released.
|
|
Packit Service |
a9274b |
snd_pcm_uframes_t avail_min;
|
|
Packit Service |
a9274b |
err = snd_pcm_sw_params_get_avail_min(state->sw_params,
|
|
Packit Service |
a9274b |
&avail_min);
|
|
Packit Service |
a9274b |
if (err < 0)
|
|
Packit Service |
a9274b |
goto error;
|
|
Packit Service |
a9274b |
avail_count = (unsigned int)avail_min;
|
|
Packit Service |
a9274b |
}
|
|
Packit Service |
a9274b |
} else {
|
|
Packit Service |
a9274b |
snd_pcm_uframes_t frames_for_start_threshold;
|
|
Packit Service |
a9274b |
snd_pcm_uframes_t frames_per_period;
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
// Fill with data frames so that the PCM substream starts.
|
|
Packit Service |
a9274b |
err = snd_pcm_sw_params_get_start_threshold(state->sw_params,
|
|
Packit Service |
a9274b |
&frames_for_start_threshold);
|
|
Packit Service |
a9274b |
if (err < 0)
|
|
Packit Service |
a9274b |
goto error;
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
// But the above number can be too small and cause XRUN because
|
|
Packit Service |
a9274b |
// I/O operation is done per period.
|
|
Packit Service |
a9274b |
err = snd_pcm_hw_params_get_period_size(state->hw_params,
|
|
Packit Service |
a9274b |
&frames_per_period, NULL);
|
|
Packit Service |
a9274b |
if (err < 0)
|
|
Packit Service |
a9274b |
goto error;
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
// Use larger one to prevent from both of XRUN and successive
|
|
Packit Service |
a9274b |
// blocking.
|
|
Packit Service |
a9274b |
if (frames_for_start_threshold > frames_per_period)
|
|
Packit Service |
a9274b |
avail_count = (unsigned int)frames_for_start_threshold;
|
|
Packit Service |
a9274b |
else
|
|
Packit Service |
a9274b |
avail_count = (unsigned int)frames_per_period;
|
|
Packit Service |
a9274b |
}
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
err = write_frames(state, frame_count, avail_count, mapper, cntrs);
|
|
Packit Service |
a9274b |
if (err < 0)
|
|
Packit Service |
a9274b |
goto error;
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
return 0;
|
|
Packit Service |
a9274b |
error:
|
|
Packit Service |
a9274b |
*frame_count = 0;
|
|
Packit Service |
a9274b |
return err;
|
|
Packit Service |
a9274b |
}
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
static int w_process_frames_nonblocking(struct libasound_state *state,
|
|
Packit Service |
a9274b |
snd_pcm_state_t status,
|
|
Packit Service |
a9274b |
unsigned int *frame_count,
|
|
Packit Service |
a9274b |
struct mapper_context *mapper,
|
|
Packit Service |
a9274b |
struct container_context *cntrs)
|
|
Packit Service |
a9274b |
{
|
|
Packit Service |
a9274b |
snd_pcm_sframes_t avail;
|
|
Packit Service |
a9274b |
unsigned int avail_count;
|
|
Packit Service |
a9274b |
int err;
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
if (state->use_waiter) {
|
|
Packit Service |
a9274b |
err = wait_for_avail(state);
|
|
Packit Service |
a9274b |
if (err < 0)
|
|
Packit Service |
a9274b |
goto error;
|
|
Packit Service |
a9274b |
}
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
// Check available space on the buffer.
|
|
Packit Service |
a9274b |
avail = snd_pcm_avail(state->handle);
|
|
Packit Service |
a9274b |
if (avail < 0) {
|
|
Packit Service |
a9274b |
err = avail;
|
|
Packit Service |
a9274b |
goto error;
|
|
Packit Service |
a9274b |
}
|
|
Packit Service |
a9274b |
avail_count = (unsigned int)avail;
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
if (avail_count == 0) {
|
|
Packit Service |
a9274b |
// Let's go to a next iteration.
|
|
Packit Service |
a9274b |
err = 0;
|
|
Packit Service |
a9274b |
goto error;
|
|
Packit Service |
a9274b |
}
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
err = write_frames(state, frame_count, avail_count, mapper, cntrs);
|
|
Packit Service |
a9274b |
if (err < 0)
|
|
Packit Service |
a9274b |
goto error;
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
// NOTE: The substream starts automatically when the accumulated number
|
|
Packit Service |
a9274b |
// of queued data frame exceeds start_threshold.
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
return 0;
|
|
Packit Service |
a9274b |
error:
|
|
Packit Service |
a9274b |
*frame_count = 0;
|
|
Packit Service |
a9274b |
return err;
|
|
Packit Service |
a9274b |
}
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
static int irq_rw_pre_process(struct libasound_state *state)
|
|
Packit Service |
a9274b |
{
|
|
Packit Service |
a9274b |
struct rw_closure *closure = state->private_data;
|
|
Packit Service |
a9274b |
snd_pcm_format_t format;
|
|
Packit Service |
a9274b |
snd_pcm_uframes_t frames_per_buffer;
|
|
Packit Service |
a9274b |
int bytes_per_sample;
|
|
Packit Service |
a9274b |
unsigned int samples_per_frame;
|
|
Packit Service |
a9274b |
int err;
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
err = snd_pcm_hw_params_get_format(state->hw_params, &format);
|
|
Packit Service |
a9274b |
if (err < 0)
|
|
Packit Service |
a9274b |
return err;
|
|
Packit Service |
a9274b |
bytes_per_sample = snd_pcm_format_physical_width(format) / 8;
|
|
Packit Service |
a9274b |
if (bytes_per_sample <= 0)
|
|
Packit Service |
a9274b |
return -ENXIO;
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
err = snd_pcm_hw_params_get_channels(state->hw_params,
|
|
Packit Service |
a9274b |
&samples_per_frame);
|
|
Packit Service |
a9274b |
if (err < 0)
|
|
Packit Service |
a9274b |
return err;
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
err = snd_pcm_hw_params_get_buffer_size(state->hw_params,
|
|
Packit Service |
a9274b |
&frames_per_buffer);
|
|
Packit Service |
a9274b |
if (err < 0)
|
|
Packit Service |
a9274b |
return err;
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
err = snd_pcm_hw_params_get_access(state->hw_params, &closure->access);
|
|
Packit Service |
a9274b |
if (err < 0)
|
|
Packit Service |
a9274b |
return err;
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
err = frame_cache_init(&closure->cache, closure->access,
|
|
Packit Service |
a9274b |
bytes_per_sample, samples_per_frame,
|
|
Packit Service |
a9274b |
frames_per_buffer);
|
|
Packit Service |
a9274b |
if (err < 0)
|
|
Packit Service |
a9274b |
return err;
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
if (snd_pcm_stream(state->handle) == SND_PCM_STREAM_CAPTURE) {
|
|
Packit Service |
a9274b |
if (state->nonblock)
|
|
Packit Service |
a9274b |
closure->process_frames = r_process_frames_nonblocking;
|
|
Packit Service |
a9274b |
else
|
|
Packit Service |
a9274b |
closure->process_frames = r_process_frames_blocking;
|
|
Packit Service |
a9274b |
} else {
|
|
Packit Service |
a9274b |
if (state->nonblock)
|
|
Packit Service |
a9274b |
closure->process_frames = w_process_frames_nonblocking;
|
|
Packit Service |
a9274b |
else
|
|
Packit Service |
a9274b |
closure->process_frames = w_process_frames_blocking;
|
|
Packit Service |
a9274b |
}
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
return 0;
|
|
Packit Service |
a9274b |
}
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
static int irq_rw_process_frames(struct libasound_state *state,
|
|
Packit Service |
a9274b |
unsigned int *frame_count,
|
|
Packit Service |
a9274b |
struct mapper_context *mapper,
|
|
Packit Service |
a9274b |
struct container_context *cntrs)
|
|
Packit Service |
a9274b |
{
|
|
Packit Service |
a9274b |
struct rw_closure *closure = state->private_data;
|
|
Packit Service |
a9274b |
snd_pcm_state_t status;
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
// Need to recover the stream.
|
|
Packit Service |
a9274b |
status = snd_pcm_state(state->handle);
|
|
Packit Service |
a9274b |
if (status != SND_PCM_STATE_RUNNING && status != SND_PCM_STATE_PREPARED)
|
|
Packit Service |
a9274b |
return -EPIPE;
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
// NOTE: Actually, status can be shift always.
|
|
Packit Service |
a9274b |
return closure->process_frames(state, status, frame_count, mapper, cntrs);
|
|
Packit Service |
a9274b |
}
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
static void irq_rw_post_process(struct libasound_state *state)
|
|
Packit Service |
a9274b |
{
|
|
Packit Service |
a9274b |
struct rw_closure *closure = state->private_data;
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
frame_cache_destroy(&closure->cache);
|
|
Packit Service |
a9274b |
}
|
|
Packit Service |
a9274b |
|
|
Packit Service |
a9274b |
const struct xfer_libasound_ops xfer_libasound_irq_rw_ops = {
|
|
Packit Service |
a9274b |
.pre_process = irq_rw_pre_process,
|
|
Packit Service |
a9274b |
.process_frames = irq_rw_process_frames,
|
|
Packit Service |
a9274b |
.post_process = irq_rw_post_process,
|
|
Packit Service |
a9274b |
.private_size = sizeof(struct rw_closure),
|
|
Packit Service |
a9274b |
};
|