]> git.alsa-project.org Git - alsa-lib.git/commitdiff
Plugin updates. The action callback has a new argument.
authorJaroslav Kysela <perex@perex.cz>
Tue, 21 Mar 2000 17:36:27 +0000 (17:36 +0000)
committerJaroslav Kysela <perex@perex.cz>
Tue, 21 Mar 2000 17:36:27 +0000 (17:36 +0000)
The mmap plugin is updated to accept frags_min & frags_max. Also,
SND_PCM_STOP_ROLLOVER behaves much better.

include/pcm.h
src/pcm/pcm_plugin.c
src/pcm/plugin/adpcm.c
src/pcm/plugin/mmap.c
src/pcm/plugin/rate.c

index d20e69144863b73e5646ddbcd1c772493aadfd2e..edcd5dca581d828990930960a318907742a3fa99 100644 (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;
index 341a7c4223aa34476b6a06d43c83091d09aeffc0..ef1952ec97180866be161c926f107eb802043546 100644 (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);
 }
index 39be8db428abe07357108f006006400d1f408a5a..870691d418b2ad730b7e19b41ac979ecce9fe091 100644 (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;
 
index c949649267aaa1d5a0819bd3004b0cb7d4bdc078..91f56c4a2b88b68c5cc7b38d16ae88690624abf8 100644 (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 */
 }
index edd2f6f388f0c95e60817cdd5a102c427e6024ce..6cfe29b3d8f6ae86c6894930c47086241ac21821 100644 (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;