Plugin updates. The action callback has a new argument.

The mmap plugin is updated to accept frags_min & frags_max. Also,
SND_PCM_STOP_ROLLOVER behaves much better.
This commit is contained in:
Jaroslav Kysela 2000-03-21 17:36:27 +00:00
parent 43041cbe78
commit 54d348c4d7
5 changed files with 137 additions and 34 deletions

View file

@ -86,7 +86,9 @@ struct snd_stru_pcm_plugin {
char *dst_ptr, size_t dst_size);
ssize_t (*src_size)(snd_pcm_plugin_t *plugin, size_t dst_size);
ssize_t (*dst_size)(snd_pcm_plugin_t *plugin, size_t src_size);
int (*action)(snd_pcm_plugin_t *plugin, snd_pcm_plugin_action_t action);
int (*action)(snd_pcm_plugin_t *plugin,
snd_pcm_plugin_action_t action,
unsigned long data);
snd_pcm_plugin_t *prev;
snd_pcm_plugin_t *next;
void *private_data;

View file

@ -200,7 +200,8 @@ int snd_pcm_plugin_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info)
return 0;
}
static int snd_pcm_plugin_action(snd_pcm_t *pcm, int channel, int action)
static int snd_pcm_plugin_action(snd_pcm_t *pcm, int channel, int action,
unsigned long data)
{
snd_pcm_plugin_t *plugin;
int err;
@ -208,7 +209,7 @@ static int snd_pcm_plugin_action(snd_pcm_t *pcm, int channel, int action)
plugin = pcm->plugin_first[channel];
while (plugin) {
if (plugin->action) {
if ((err = plugin->action(plugin, action))<0)
if ((err = plugin->action(plugin, action, data))<0)
return err;
}
plugin = plugin->next;
@ -295,7 +296,7 @@ int snd_pcm_plugin_params(snd_pcm_t *pcm, snd_pcm_channel_params_t *params)
err = snd_pcm_channel_params(pcm, &hwparams);
if (err < 0)
return err;
err = snd_pcm_plugin_action(pcm, hwparams.channel, INIT);
err = snd_pcm_plugin_action(pcm, hwparams.channel, INIT, (long)&hwparams);
if (err < 0)
return err;
return 0;
@ -347,7 +348,7 @@ int snd_pcm_plugin_prepare(snd_pcm_t *pcm, int channel)
{
int err;
if ((err = snd_pcm_plugin_action(pcm, channel, PREPARE))<0)
if ((err = snd_pcm_plugin_action(pcm, channel, PREPARE, 0))<0)
return err;
return snd_pcm_channel_prepare(pcm, channel);
}
@ -356,7 +357,7 @@ int snd_pcm_plugin_playback_drain(snd_pcm_t *pcm)
{
int err;
if ((err = snd_pcm_plugin_action(pcm, SND_PCM_CHANNEL_PLAYBACK, DRAIN))<0)
if ((err = snd_pcm_plugin_action(pcm, SND_PCM_CHANNEL_PLAYBACK, DRAIN, 0))<0)
return err;
return snd_pcm_playback_drain(pcm);
}
@ -366,7 +367,7 @@ int snd_pcm_plugin_flush(snd_pcm_t *pcm, int channel)
int err;
pdprintf("flush\n");
if ((err = snd_pcm_plugin_action(pcm, channel, FLUSH))<0)
if ((err = snd_pcm_plugin_action(pcm, channel, FLUSH, 0))<0)
return err;
return snd_pcm_channel_flush(pcm, channel);
}

View file

@ -509,7 +509,9 @@ static ssize_t adpcm_transfer(snd_pcm_plugin_t * plugin,
}
}
static int adpcm_action(snd_pcm_plugin_t * plugin, snd_pcm_plugin_action_t action)
static int adpcm_action(snd_pcm_plugin_t * plugin,
snd_pcm_plugin_action_t action,
unsigned long udata)
{
struct adpcm_private_data *data;

View file

@ -37,8 +37,34 @@ struct mmap_private_data {
snd_pcm_mmap_control_t *control;
char *buffer;
int frag;
int start_mode, stop_mode;
int frags, frags_used;
int frags_min, frags_max;
unsigned int lastblock;
};
static int playback_ok(struct mmap_private_data *data)
{
snd_pcm_mmap_control_t *control = data->control;
int delta = control->status.block;
if (delta < data->lastblock) {
delta += (~0 - data->lastblock) + 1;
} else {
delta -= data->lastblock;
}
data->frags_used -= delta;
if (data->frags_used < 0) {
/* correction for rollover */
data->frag += -data->frags_used;
data->frag %= data->frags;
data->frags_used = 0;
}
data->lastblock += delta;
return data->frags_used <= data->frags_max &&
(data->frags - data->frags_used) >= data->frags_min;
}
static int poll_playback(snd_pcm_t *pcm)
{
int err;
@ -53,17 +79,23 @@ static int poll_playback(snd_pcm_t *pcm)
return err < 0 ? err : 0;
}
static int query_playback(struct mmap_private_data *data,
snd_pcm_mmap_control_t *control,
int not_use_poll)
static int query_playback(struct mmap_private_data *data, int not_use_poll)
{
snd_pcm_mmap_control_t *control = data->control;
int err;
switch (control->status.status) {
case SND_PCM_STATUS_PREPARED:
err = snd_pcm_channel_go(data->pcm, data->channel);
if (err < 0)
return err;
if (data->start_mode == SND_PCM_START_GO)
return -EAGAIN;
if ((data->start_mode == SND_PCM_START_DATA &&
playback_ok(data)) ||
(data->start_mode == SND_PCM_START_FULL &&
data->frags_used == data->frags)) {
err = snd_pcm_channel_go(data->pcm, data->channel);
if (err < 0)
return err;
}
break;
case SND_PCM_STATUS_RUNNING:
if (!not_use_poll) {
@ -81,6 +113,27 @@ static int query_playback(struct mmap_private_data *data,
return 0;
}
static int capture_ok(struct mmap_private_data *data)
{
snd_pcm_mmap_control_t *control = data->control;
int delta = control->status.block;
if (delta < data->lastblock) {
delta += (~0 - data->lastblock) + 1;
} else {
delta -= data->lastblock;
}
data->frags_used += delta;
if (data->frags_used > data->frags) {
/* correction for rollover */
data->frag += data->frags_used - data->frags;
data->frag %= data->frags;
data->frags_used = data->frags;
}
data->lastblock += delta;
return data->frags_used >= data->frags_min;
}
static int poll_capture(snd_pcm_t *pcm)
{
int err;
@ -95,21 +148,22 @@ static int poll_capture(snd_pcm_t *pcm)
return err < 0 ? err : 0;
}
static int query_capture(struct mmap_private_data *data,
snd_pcm_mmap_control_t *control,
int not_use_poll)
static int query_capture(struct mmap_private_data *data, int not_use_poll)
{
snd_pcm_mmap_control_t *control = data->control;
int err;
switch (control->status.status) {
case SND_PCM_STATUS_PREPARED:
if (data->start_mode != SND_PCM_START_DATA)
return -EAGAIN;
err = snd_pcm_channel_go(data->pcm, data->channel);
if (err < 0)
return err;
break;
case SND_PCM_STATUS_RUNNING:
if (!not_use_poll) {
control->status.expblock = control->status.block + 1;
control->status.expblock = control->status.block + data->frags_min;
err = poll_capture(data->pcm);
if (err < 0)
return err;
@ -142,8 +196,8 @@ static int mmap_transfer_src_ptr(snd_pcm_plugin_t *plugin, char **buffer, size_t
*buffer = data->buffer + control->fragments[data->frag].addr;
if (data->channel == SND_PCM_CHANNEL_PLAYBACK) {
/* wait until the block is not free */
while (control->fragments[data->frag].data) {
err = query_playback(data, control, 0);
while (!playback_ok(data)) {
err = query_playback(data, 0);
if (err < 0)
return err;
}
@ -181,8 +235,8 @@ static ssize_t mmap_transfer(snd_pcm_plugin_t *plugin,
return -EINVAL;
}
if (data->channel == SND_PCM_CHANNEL_PLAYBACK) {
while (control->fragments[data->frag].data) {
err = query_playback(data, control, 0);
while (!playback_ok(data)) {
err = query_playback(data, 0);
if (err < 0)
return err;
}
@ -192,13 +246,14 @@ static ssize_t mmap_transfer(snd_pcm_plugin_t *plugin,
memcpy(addr, dst_ptr, dst_size);
control->fragments[data->frag++].data = 1;
data->frag %= control->status.frags;
data->frags_used++;
} else {
int frag;
for (voice = 0; voice < control->status.voices; voice++) {
frag = data->frag + (voice * (control->status.frags / control->status.voices));
frag = data->frag + (voice * data->frags);
while (control->fragments[frag].data) {
err = query_playback(data, control, 1);
err = query_playback(data, 1);
if (err < 0)
return err;
}
@ -209,12 +264,13 @@ static ssize_t mmap_transfer(snd_pcm_plugin_t *plugin,
dst_ptr += control->status.frag_size;
}
data->frag++;
data->frag %= control->status.frags;
data->frag %= data->frags;
data->frags_used++;
}
return dst_size;
} else if (data->channel == SND_PCM_CHANNEL_CAPTURE) {
while (!control->fragments[data->frag].data) {
err = query_capture(data, control, 0);
while (!capture_ok(data)) {
err = query_capture(data, 0);
if (err < 0)
return err;
}
@ -224,20 +280,26 @@ static ssize_t mmap_transfer(snd_pcm_plugin_t *plugin,
memcpy(dst_ptr, addr, dst_size);
control->fragments[data->frag++].data = 0;
data->frag %= control->status.frags;
data->frags_used--;
} else {
int frag;
for (voice = 0; voice < control->status.voices; voice++) {
frag = data->frag + (voice * data->frags);
while (!control->fragments[data->frag].data) {
err = query_capture(data, control, 1);
err = query_capture(data, 1);
if (err < 0)
return err;
}
addr = data->buffer + control->fragments[data->frag].addr;
addr = data->buffer + control->fragments[frag].addr;
if (dst_ptr != addr)
memcpy(dst_ptr, addr, control->status.frag_size);
control->fragments[data->frag++].data = 0;
data->frag %= control->status.frags;
control->fragments[frag].data = 0;
dst_ptr += control->status.frag_size;
}
data->frag++;
data->frag %= data->frags;
data->frags_used--;
}
return dst_size;
} else {
@ -245,7 +307,9 @@ static ssize_t mmap_transfer(snd_pcm_plugin_t *plugin,
}
}
static int mmap_action(snd_pcm_plugin_t *plugin, snd_pcm_plugin_action_t action)
static int mmap_action(snd_pcm_plugin_t *plugin,
snd_pcm_plugin_action_t action,
unsigned long udata)
{
struct mmap_private_data *data;
@ -253,15 +317,47 @@ static int mmap_action(snd_pcm_plugin_t *plugin, snd_pcm_plugin_action_t action)
return -EINVAL;
data = (struct mmap_private_data *)snd_pcm_plugin_extra_data(plugin);
if (action == INIT) {
snd_pcm_channel_params_t *params;
snd_pcm_channel_setup_t setup;
int result, frags;
if (data->control)
snd_pcm_munmap(data->pcm, data->channel);
return snd_pcm_mmap(data->pcm, data->channel, &data->control, (void **)&data->buffer);
result = snd_pcm_mmap(data->pcm, data->channel, &data->control, (void **)&data->buffer);
if (result < 0)
return result;
params = (snd_pcm_channel_params_t *)udata;
data->start_mode = params->start_mode;
data->stop_mode = params->stop_mode;
memset(&setup, 0, sizeof(setup));
setup.channel = data->channel;
if ((result = snd_pcm_channel_setup(data->pcm, &setup)) < 0)
return result;
data->frags = setup.buf.block.frags;
data->frags_min = setup.buf.block.frags_min;
data->frags_max = setup.buf.block.frags_max;
if (data->frags_min < 0)
data->frags_min = 0;
if (data->frags_min >= setup.buf.block.frags)
data->frags_min = setup.buf.block.frags - 1;
if (data->frags_max < 0)
data->frags_max = setup.buf.block.frags + data->frags_max;
if (data->frags_max < data->frags_min)
data->frags_max = data->frags_min;
if (data->frags_max < 1)
data->frags_max = 1;
if (data->frags_max > setup.buf.block.frags)
data->frags_max = setup.buf.block.frags;
return 0;
} else if (action == PREPARE) {
data->frag = 0;
data->lastblock = 0;
} else if (action == DRAIN && data->channel == SND_PCM_CHANNEL_PLAYBACK) {
data->frag = 0;
data->lastblock = 0;
} else if (action == FLUSH) {
data->frag = 0;
data->lastblock = 0;
}
return 0; /* silenty ignore other actions */
}

View file

@ -336,7 +336,9 @@ static ssize_t rate_transfer(snd_pcm_plugin_t *plugin,
return rate_dst_size(plugin, src_size);
}
static int rate_action(snd_pcm_plugin_t *plugin, snd_pcm_plugin_action_t action)
static int rate_action(snd_pcm_plugin_t *plugin,
snd_pcm_plugin_action_t action,
unsigned long udata)
{
struct rate_private_data *data;
int voice;