PCM loopback API improved and added back the functionality.

Some mmap() changes for the OSS emulation.
This commit is contained in:
Jaroslav Kysela 1999-11-30 09:25:59 +00:00
parent 3239ca9940
commit f5e461caa3
4 changed files with 182 additions and 34 deletions

View file

@ -29,13 +29,16 @@
#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;
}