mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-10-29 05:40:25 -04:00
PCM loopback API improved and added back the functionality.
Some mmap() changes for the OSS emulation.
This commit is contained in:
parent
3239ca9940
commit
f5e461caa3
4 changed files with 182 additions and 34 deletions
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue