OSDN Git Service

PCM loopback API improved and added back the functionality.
authorJaroslav Kysela <perex@perex.cz>
Tue, 30 Nov 1999 09:25:59 +0000 (09:25 +0000)
committerJaroslav Kysela <perex@perex.cz>
Tue, 30 Nov 1999 09:25:59 +0000 (09:25 +0000)
Some mmap() changes for the OSS emulation.

include/mixer.h
include/pcm.h
src/pcm/pcm_loopback.c
test/loopback.c

index 07fa48b..f705fed 100644 (file)
@@ -6,7 +6,7 @@
  ****************************************************************************/
 
 typedef struct snd_mixer_callbacks {
-       void *private_data;     /* should be used by an application */
+       void *private_data;     /* should be used with an application */
        void (*rebuild) (void *private_data);
        void (*element) (void *private_data, int cmd, snd_mixer_eid_t *eid);
        void (*group) (void *private_data, int cmd, snd_mixer_gid_t *gid);
index 2c06d76..c4fb558 100644 (file)
@@ -144,13 +144,23 @@ int snd_pcm_plugin_build_voices(int src_format, int src_voices,
 extern "C" {
 #endif
 
-int snd_pcm_loopback_open(snd_pcm_loopback_t **handle, int card, int device, int subchn, int mode);
+typedef struct snd_pcm_loopback_callbacks {
+       void *private_data;             /* should be used with an application */
+       size_t max_buffer_size;         /* zero = default (64kB) */
+       void (*data) (void *private_data, char *buffer, size_t count);
+       void (*position_change) (void *private_data, unsigned int pos);
+       void (*format_change) (void *private_data, snd_pcm_format_t *format);
+       char *reserved[32];             /* reserved for the future use - must be NULL!!! */
+} snd_pcm_loopback_callbacks_t;
+
+int snd_pcm_loopback_open(snd_pcm_loopback_t **handle, int card, int device, int subdev, int mode);
 int snd_pcm_loopback_close(snd_pcm_loopback_t *handle);
 int snd_pcm_loopback_file_descriptor(snd_pcm_loopback_t *handle);
 int snd_pcm_loopback_block_mode(snd_pcm_loopback_t *handle, int enable);
 int snd_pcm_loopback_stream_mode(snd_pcm_loopback_t *handle, int mode);
 int snd_pcm_loopback_format(snd_pcm_loopback_t *handle, snd_pcm_format_t * format);
-ssize_t snd_pcm_loopback_read(snd_pcm_loopback_t *handle, void *buffer, size_t size);
+int snd_pcm_loopback_status(snd_pcm_loopback_t *handle, snd_pcm_loopback_status_t * status);
+ssize_t snd_pcm_loopback_read(snd_pcm_loopback_t *handle, snd_pcm_loopback_callbacks_t * callbacks);
 
 #ifdef __cplusplus
 }
index d9b0354..5aaea00 100644 (file)
 #include "asoundlib.h"
 
 #define SND_FILE_PCM_LB                "/proc/asound/%i/pcmloopD%iS%i%s"
-#define SND_PCM_LB_VERSION_MAX SND_PROTOCOL_VERSION( 1, 0, 0 )
+#define SND_PCM_LB_VERSION_MAX SND_PROTOCOL_VERSION(2, 0, 0)
 
 struct snd_pcm_loopback {
        int card;
        int device;
        int fd;
-} ;
+       long mode;
+       size_t buffer_size;
+       char *buffer;
+};
 
 int snd_pcm_loopback_open(snd_pcm_loopback_t **handle, int card, int device, int subchn, int mode)
 {
@@ -70,39 +73,35 @@ int snd_pcm_loopback_open(snd_pcm_loopback_t **handle, int card, int device, int
        lb->card = card;
        lb->device = device;
        lb->fd = fd;
+       lb->mode = SND_PCM_LB_STREAM_MODE_RAW;
        *handle = lb;
        return 0;
 }
 
-int snd_pcm_loopback_close(snd_pcm_loopback_t *handle)
+int snd_pcm_loopback_close(snd_pcm_loopback_t *lb)
 {
-       snd_pcm_loopback_t *lb;
        int res;
 
-       lb = handle;
        if (!lb)
                return -EINVAL;
+       if (lb->buffer)
+               free(lb->buffer);
        res = close(lb->fd) < 0 ? -errno : 0;
        free(lb);
        return res;
 }
 
-int snd_pcm_loopback_file_descriptor(snd_pcm_loopback_t *handle)
+int snd_pcm_loopback_file_descriptor(snd_pcm_loopback_t *lb)
 {
-       snd_pcm_loopback_t *lb;
-
-       lb = handle;
        if (!lb)
                return -EINVAL;
        return lb->fd;
 }
 
-int snd_pcm_loopback_block_mode(snd_pcm_loopback_t *handle, int enable)
+int snd_pcm_loopback_block_mode(snd_pcm_loopback_t *lb, int enable)
 {
-       snd_pcm_loopback_t *lb;
        long flags;
 
-       lb = handle;
        if (!lb)
                return -EINVAL;
        if ((flags = fcntl(lb->fd, F_GETFL)) < 0)
@@ -116,24 +115,19 @@ int snd_pcm_loopback_block_mode(snd_pcm_loopback_t *handle, int enable)
        return 0;
 }
 
-int snd_pcm_loopback_stream_mode(snd_pcm_loopback_t *handle, int mode)
+int snd_pcm_loopback_stream_mode(snd_pcm_loopback_t *lb, int mode)
 {
-       snd_pcm_loopback_t *lb;
-       long lmode = mode;
-
-       lb = handle;
-       if (!lb)
+       if (!lb || (mode != SND_PCM_LB_STREAM_MODE_RAW &&
+                   mode != SND_PCM_LB_STREAM_MODE_PACKET))
                return -EINVAL;
-       if (ioctl(lb->fd, SND_PCM_LB_IOCTL_STREAM_MODE, &lmode) < 0)
+       lb->mode = mode;
+       if (ioctl(lb->fd, SND_PCM_LB_IOCTL_STREAM_MODE, &lb->mode) < 0)
                return -errno;
        return 0;
 }
 
-int snd_pcm_loopback_format(snd_pcm_loopback_t *handle, snd_pcm_format_t * format)
+int snd_pcm_loopback_format(snd_pcm_loopback_t *lb, snd_pcm_format_t * format)
 {
-       snd_pcm_loopback_t *lb;
-
-       lb = handle;
        if (!lb)
                return -EINVAL;
        if (ioctl(lb->fd, SND_PCM_LB_IOCTL_FORMAT, format) < 0)
@@ -141,16 +135,101 @@ int snd_pcm_loopback_format(snd_pcm_loopback_t *handle, snd_pcm_format_t * forma
        return 0;
 }
 
-ssize_t snd_pcm_loopback_read(snd_pcm_loopback_t *handle, void *buffer, size_t size)
+int snd_pcm_loopback_status(snd_pcm_loopback_t *lb, snd_pcm_loopback_status_t * status)
 {
-       snd_pcm_loopback_t *lb;
-       ssize_t result;
-
-       lb = handle;
        if (!lb)
                return -EINVAL;
-       result = read(lb->fd, buffer, size);
-       if (result < 0)
+       if (ioctl(lb->fd, SND_PCM_LB_IOCTL_FORMAT, status) < 0)
                return -errno;
+       return 0;
+}
+
+ssize_t snd_pcm_loopback_read(snd_pcm_loopback_t *lb, snd_pcm_loopback_callbacks_t *callbacks)
+{
+       ssize_t result = 0, res, count;
+       size_t size;
+       char *buf;
+       snd_pcm_loopback_header_t header;
+
+       if (!lb || !callbacks)
+               return -EINVAL;
+       if (callbacks->max_buffer_size == 0)
+               size = 64 * 1024;
+       else
+               size = callbacks->max_buffer_size < 16 ? 16 : callbacks->max_buffer_size;
+       while (1) {
+               if (lb->mode == SND_PCM_LB_STREAM_MODE_RAW) {
+                       header.size = size;
+                       header.type = SND_PCM_LB_TYPE_DATA;
+               } else {
+                       res = read(lb->fd, &header, sizeof(header));
+                       if (res < 0)
+                               return -errno;
+                       if (res == 0)
+                               break;
+                       if (res != sizeof(header))
+                               return -EBADFD;
+                       result += res;
+               }
+               switch (header.type) {
+               case SND_PCM_LB_TYPE_DATA:
+                       if (lb->buffer_size < size) {
+                               buf = (char *) realloc(lb->buffer, size);
+                               if (buf == NULL)
+                                       return -ENOMEM;
+                               lb->buffer = buf;
+                               lb->buffer_size = size;
+                       } else {
+                               buf = lb->buffer;
+                       }
+                       while (header.size > 0) {
+                               count = header.size;
+                               if (count > size)
+                                       count = size;
+                               res = read(lb->fd, buf, count);
+                               if (res < 0)
+                                       return -errno;
+                               result += res;
+                               if (lb->mode == SND_PCM_LB_STREAM_MODE_PACKET && res != count)
+                                       return -EBADFD;
+                               if (res == 0)
+                                       break;
+                               if (callbacks->data)
+                                       callbacks->data(callbacks->private_data, buf, res);
+                               if (res < count && lb->mode == SND_PCM_LB_STREAM_MODE_RAW)
+                                       break;
+                               header.size -= res;
+                       }
+                       break;
+               case SND_PCM_LB_TYPE_FORMAT:
+                       {
+                               snd_pcm_format_t format;
+                               
+                               res = read(lb->fd, &format, sizeof(format));
+                               if (res < 0)
+                                       return -errno;
+                               result += res;
+                               if (res != sizeof(format))
+                                       return -EBADFD;
+                               if (callbacks->format_change)
+                                       callbacks->format_change(callbacks->private_data, &format);
+                       }
+                       break;
+               case SND_PCM_LB_TYPE_POSITION:
+                       {
+                               unsigned int pos;
+                               
+                               res = read(lb->fd, &pos, sizeof(pos));
+                               if (res < 0)
+                                       return -errno;
+                               result += res;
+                               if (res != sizeof(pos))
+                                       return -EBADFD;
+                               if (callbacks->position_change)
+                                       callbacks->position_change(callbacks->private_data, pos);
+                       }
+                       break;
+               }
+       }
        return result;
 }
index f39c2d0..d9e0cdb 100644 (file)
@@ -3,16 +3,75 @@
 #include <string.h>
 #include "../include/asoundlib.h"
 
+#define CARD   0
+#define DEVICE 0
+#define SUBDEV 0
+#define MODE   SND_PCM_LB_STREAM_MODE_PACKET
+
+static void show_format1(const char *prefix, snd_pcm_format_t *format)
+{
+       printf("%sinterleave = %i, rate = %i, voices = %i, format = %i\n",
+                       prefix,
+                       format->interleave ? 1 : 0,
+                       format->rate,
+                       format->voices,
+                       format->format);
+}
+
+static void show_format(snd_pcm_loopback_t *handle)
+{
+       snd_pcm_format_t format;
+       int err;
+
+       err = snd_pcm_loopback_format(handle, &format);
+       if (err < 0) {
+               fprintf(stderr, "format failed: %s\n", snd_strerror(err));
+               exit(0);
+       }
+       show_format1("Format: ", &format);
+}
+
+static void data(void *private_data, char *buf, size_t count)
+{
+       printf("DATA> count = %li\n", (long)count);
+}
+
+static void format_change(void *private_data, snd_pcm_format_t *format)
+{
+       show_format1("Format change> ", format);
+}
+
+static void position_change(void *private_data, unsigned int pos)
+{
+       printf("Position change> %u\n", pos);
+}
+
 int main(int argc, char *argv[])
 {
        int err;
+       ssize_t res;
        snd_pcm_loopback_t *handle;
+       snd_pcm_loopback_callbacks_t callbacks;
 
-       err = snd_pcm_loopback_open(&handle, 0, 0, SND_PCM_LB_OPEN_PLAYBACK);
+       err = snd_pcm_loopback_open(&handle, CARD, DEVICE, SUBDEV, SND_PCM_LB_OPEN_PLAYBACK);
        if (err < 0) {
                fprintf(stderr, "open error: %s\n", snd_strerror(err));
                exit(0);
        }
+       err = snd_pcm_loopback_stream_mode(handle, MODE);
+       if (err < 0) {
+               fprintf(stderr, "stream mode setup failed: %s\n", snd_strerror(err));
+               exit(0);
+       }
+       show_format(handle);
+       memset(&callbacks, 0, sizeof(callbacks));
+       callbacks.data = data;
+       callbacks.format_change = format_change;        
+       callbacks.position_change = position_change;
+       while ((res = snd_pcm_loopback_read(handle, &callbacks)) >= 0) {
+               if (res > 0)
+                       printf("Read ok.. - %i\n", res);
+       }
        snd_pcm_loopback_close(handle);
        return 0;
 }