extern void * lib_oss_pcm_mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
extern int lib_oss_pcm_munmap(void *start, size_t length);
extern int lib_oss_pcm_ioctl(int fd, unsigned long int request, ...);
-extern int lib_oss_pcm_select_prepare(int fd, fd_set *readfds, fd_set *writefds, fd_set *exceptfds);
+extern int lib_oss_pcm_select_prepare(int fd, int fmode, fd_set *readfds, fd_set *writefds, fd_set *exceptfds);
extern int lib_oss_pcm_select_result(int fd, fd_set *readfds, fd_set *writefds, fd_set *exceptfds);
extern int lib_oss_pcm_poll_fds(int fd);
-extern int lib_oss_pcm_poll_prepare(int fd, struct pollfd *ufds);
+extern int lib_oss_pcm_poll_prepare(int fd, int fmode, struct pollfd *ufds);
extern int lib_oss_pcm_poll_result(int fd, struct pollfd *ufds);
extern int lib_oss_mixer_open(const char *pathname, int flags, ...);
typedef struct {
fd_class_t class;
+ int oflags;
void *mmap_area;
} fd_t;
va_end(args);
switch (cmd) {
+ case F_GETFL:
+ return fds[fd]->oflags;
case F_SETFL:
result = lib_oss_pcm_nonblock(fd, (arg & O_NONBLOCK) ? 1 : 0);
if (result < 0) {
va_end(args);
switch (cmd) {
+ case F_GETFL:
+ return fds[fd]->oflags;
default:
DEBUG("mixer_fcntl(%d, ", fd);
result = _fcntl(fd, cmd, arg);
return -1;
}
fds[fd]->class = FD_OSS_DSP;
+ fds[fd]->oflags = oflag;
poll_fds_add += lib_oss_pcm_poll_fds(fd);
}
} else if (!strncmp(file, "/dev/mixer", 10)) {
return -1;
}
fds[fd]->class = FD_OSS_MIXER;
+ fds[fd]->oflags = oflag;
}
} else {
fd = _open(file, oflag, mode);
switch (fds[fd]->class) {
case FD_OSS_DSP:
{
- lib_oss_pcm_poll_prepare(fd, &pfds1[nfds1]);
- nfds1 += lib_oss_pcm_poll_fds(fd);
+ unsigned short events = pfds[k].events;
+ int fmode = 0;
+ if (events & (POLLIN|POLLOUT))
+ fmode = O_RDWR;
+ else if (events & POLLIN)
+ fmode = O_RDONLY;
+ else
+ fmode = O_WRONLY;
+ nfds1 += lib_oss_pcm_poll_prepare(fd, fmode, &pfds1[nfds1]);
direct = 0;
break;
}
int count, count1;
int fd;
int direct = 1;
+
if (rfds) {
_rfds1 = *rfds;
- rfds1 = &_rfds1;
- } else
- rfds1 = NULL;
+ } else {
+ FD_ZERO(&_rfds1);
+ }
+ rfds1 = &_rfds1;
if (wfds) {
_wfds1 = *wfds;
- wfds1 = &_wfds1;
- } else
- wfds1 = NULL;
+ } else {
+ FD_ZERO(&_wfds1);
+ }
+ wfds1 = &_wfds1;
if (efds) {
_efds1 = *efds;
efds1 = &_efds1;
- } else
+ } else {
efds1 = NULL;
+ }
for (fd = 0; fd < nfds; ++fd) {
int r = (rfds && FD_ISSET(fd, rfds));
int w = (wfds && FD_ISSET(fd, wfds));
switch (fds[fd]->class) {
case FD_OSS_DSP:
{
- lib_oss_pcm_select_prepare(fd, r ? rfds1 : NULL,
- w ? wfds1 : NULL,
- e ? efds1 : NULL);
+ int res, fmode = 0;
+
+ if (r & w)
+ fmode = O_RDWR;
+ else if (r)
+ fmode = O_RDONLY;
+ else
+ fmode = O_WRONLY;
+ res = lib_oss_pcm_select_prepare(fd, fmode, rfds1, wfds1,
+ e ? efds1 : NULL);
+ if (res < 0)
+ return -1;
+ if (nfds1 < res + 1)
+ nfds1 = res + 1;
+ if (r)
+ FD_CLR(fd, rfds1);
+ if (w)
+ FD_CLR(fd, wfds1);
+ if (e)
+ FD_CLR(fd, efds1);
direct = 0;
break;
}
if (result < 0 && e) {
FD_SET(fd, efds);
e1 = 1;
- } else if (result & OSS_WAIT_EVENT_ERROR) {
- FD_SET(fd, efds);
- e1 = 1;
- } else if (result & OSS_WAIT_EVENT_READ) {
- FD_SET(fd, rfds);
- r1 = 1;
- } else if (result & OSS_WAIT_EVENT_WRITE) {
- FD_SET(fd, wfds);
- w1 = 1;
+ } else {
+ if (result & OSS_WAIT_EVENT_ERROR) {
+ FD_SET(fd, efds);
+ e1 = 1;
+ }
+ if (result & OSS_WAIT_EVENT_READ) {
+ FD_SET(fd, rfds);
+ r1 = 1;
+ }
+ if (result & OSS_WAIT_EVENT_WRITE) {
+ FD_SET(fd, wfds);
+ w1 = 1;
+ }
}
break;
}
if (!(streams & (1 << k)))
continue;
result = snd_pcm_open(&dsp->streams[k].pcm, name, k, pcm_mode);
- if (result < 0)
+ if (result < 0) {
+ if (k == 1 && dsp->streams[0].pcm != NULL) {
+ dsp->streams[1].pcm = NULL;
+ streams &= ~(1 << SND_PCM_STREAM_CAPTURE);
+ result = 0;
+ }
break;
+ }
}
if (result < 0) {
result = 0;
}
#if USE_REWIND
err = snd_pcm_rewind(pcm, str->alsa.buffer_size);
- if (err < 0)
- return;
- size = str->mmap_advance;
-// fprintf(stderr, "delay=%ld rewind=%ld forward=%ld offset=%ld\n",
-// delay, err, size, snd_pcm_mmap_offset(pcm));
+ if (err < 0) {
+ /* fallback to not very accurate method */
+ size = str->mmap_advance - delay;
+ } else {
+ size = str->mmap_advance;
+ }
+// fprintf(stderr, "delay=%ld rewind=%ld forward=%ld\n",
+// delay, err, size);
#else
size = str->mmap_advance - delay;
#endif
snd_pcm_uframes_t ofs;
snd_pcm_uframes_t frames = size;
snd_pcm_mmap_begin(pcm, &areas, &ofs, &frames);
+ if (frames == 0)
+ break;
// fprintf(stderr, "copy %ld %ld %d\n", ofs, frames, dsp->format);
snd_pcm_areas_copy(areas, ofs, str->mmap_areas, ofs,
dsp->channels, frames,
oss_dsp_mmap_update(dsp, SND_PCM_STREAM_CAPTURE, delay);
}
/* FIXME */
+ snd_pcm_avail_update(pcm);
hw_ptr = _snd_pcm_mmap_hw_ptr(pcm);
info->bytes = hw_ptr;
info->bytes *= str->frame_bytes;
oss_dsp_mmap_update(dsp, SND_PCM_STREAM_PLAYBACK, delay);
}
/* FIXME */
+ snd_pcm_avail_update(pcm);
hw_ptr = _snd_pcm_mmap_hw_ptr(pcm);
info->bytes = hw_ptr;
info->bytes *= str->frame_bytes;
return 0;
}
-int lib_oss_pcm_select_prepare(int fd, fd_set *readfds, fd_set *writefds, fd_set *exceptfds)
+int lib_oss_pcm_select_prepare(int fd, int fmode, fd_set *readfds, fd_set *writefds, fd_set *exceptfds)
{
oss_dsp_t *dsp = look_for_dsp(fd);
- int k;
+ int k, maxfd = -1;
if (dsp == NULL) {
errno = EBADFD;
int err, count;
if (!pcm)
continue;
+ if ((fmode & O_ACCMODE) == O_RDONLY && snd_pcm_stream(pcm) == SND_PCM_STREAM_PLAYBACK)
+ continue;
+ if ((fmode & O_ACCMODE) == O_WRONLY && snd_pcm_stream(pcm) == SND_PCM_STREAM_CAPTURE)
+ continue;
count = snd_pcm_poll_descriptors_count(pcm);
if (count < 0) {
errno = -count;
for (j = 0; j < count; j++) {
int fd = ufds[j].fd;
unsigned short events = ufds[j].events;
+ if (maxfd < fd)
+ maxfd = fd;
if (readfds) {
FD_CLR(fd, readfds);
if (events & POLLIN)
}
}
}
- return 0;
+ return maxfd;
}
int lib_oss_pcm_select_result(int fd, fd_set *readfds, fd_set *writefds, fd_set *exceptfds)
result |= OSS_WAIT_EVENT_ERROR;
if (revents & POLLIN)
result |= OSS_WAIT_EVENT_READ;
- if (revents & POLLIN)
+ if (revents & POLLOUT)
result |= OSS_WAIT_EVENT_WRITE;
}
}
return result;
}
-int lib_oss_pcm_poll_prepare(int fd, struct pollfd *ufds)
+int lib_oss_pcm_poll_prepare(int fd, int fmode, struct pollfd *ufds)
{
oss_dsp_t *dsp = look_for_dsp(fd);
- int k;
+ int k, result = 0;
if (dsp == NULL) {
errno = EBADFD;
int err, count;
if (!pcm)
continue;
+ if ((fmode & O_ACCMODE) == O_RDONLY && snd_pcm_stream(pcm) == SND_PCM_STREAM_PLAYBACK)
+ continue;
+ if ((fmode & O_ACCMODE) == O_WRONLY && snd_pcm_stream(pcm) == SND_PCM_STREAM_CAPTURE)
+ continue;
count = snd_pcm_poll_descriptors_count(pcm);
if (count < 0) {
errno = -count;
return -1;
}
ufds += count;
+ result += count;
}
- return 0;
+ return result;
}
int lib_oss_pcm_poll_result(int fd, struct pollfd *ufds)
void * (*oss_pcm_mmap)(void *start, size_t length, int prot, int flags, int fd, off_t offset);
int (*oss_pcm_munmap)(void *start, size_t length);
int (*oss_pcm_ioctl)(int fd, unsigned long int request, ...);
-int (*oss_pcm_select_prepare)(int fd, fd_set *readfds, fd_set *writefds, fd_set *exceptfds);
+int (*oss_pcm_select_prepare)(int fd, int fmode, fd_set *readfds, fd_set *writefds, fd_set *exceptfds);
int (*oss_pcm_select_result)(int fd, fd_set *readfds, fd_set *writefds, fd_set *exceptfds);
int (*oss_pcm_poll_fds)(int fd);
-int (*oss_pcm_poll_prepare)(int fd, struct pollfd *ufds);
+int (*oss_pcm_poll_prepare)(int fd, int fmode, struct pollfd *ufds);
int (*oss_pcm_poll_result)(int fd, struct pollfd *ufds);
static int (*x_oss_mixer_open)(const char *pathname, int flags);
return 0;
}
-static int native_pcm_select_prepare(int fd, fd_set *readfds, fd_set *writefds, fd_set *exceptfds)
+static int native_pcm_select_prepare(int fd, int fmode, fd_set *readfds, fd_set *writefds, fd_set *exceptfds)
{
if (fd < 0)
return -EINVAL;
- if (readfds) {
+ if ((fmode & O_ACCMODE) != O_WRONLY && readfds) {
FD_SET(fd, readfds);
if (exceptfds)
FD_SET(fd, exceptfds);
}
- if (writefds) {
+ if ((fmode & O_ACCMODE) != O_RDONLY && writefds) {
FD_SET(fd, writefds);
if (exceptfds)
FD_SET(fd, exceptfds);
}
- return 0;
+ return fd;
}
static int native_pcm_select_result(int fd, fd_set *readfds, fd_set *writefds, fd_set *exceptfds)
return 1;
}
-static int native_pcm_poll_prepare(int fd, struct pollfd *ufds)
+static int native_pcm_poll_prepare(int fd, int fmode, struct pollfd *ufds)
{
if (fd < 0)
return -EINVAL;
ufds->fd = fd;
- ufds->events = POLLIN | POLLOUT | POLLERR;
- return 0;
+ ufds->events = ((fmode & O_ACCMODE) == O_WRONLY ? 0 : POLLIN) |
+ ((fmode & O_ACCMODE) == O_RDONLY ? 0 : POLLOUT) | POLLERR;
+ return 1;
}
static int native_pcm_poll_result(int fd, struct pollfd *ufds)
extern void * (*oss_pcm_mmap)(void *start, size_t length, int prot, int flags, int fd, off_t offset);
extern int (*oss_pcm_munmap)(void *start, size_t length);
extern int (*oss_pcm_ioctl)(int fd, unsigned long int request, ...);
-extern int (*oss_pcm_select_prepare)(int fd, fd_set *readfds, fd_set *writefds, fd_set *exceptfds);
+extern int (*oss_pcm_select_prepare)(int fd, int fmode, fd_set *readfds, fd_set *writefds, fd_set *exceptfds);
extern int (*oss_pcm_select_result)(int fd, fd_set *readfds, fd_set *writefds, fd_set *exceptfds);
extern int (*oss_pcm_poll_fds)(int fd);
-extern int (*oss_pcm_poll_prepare)(int fd, struct pollfd *ufds);
+extern int (*oss_pcm_poll_prepare)(int fd, int fmode, struct pollfd *ufds);
extern int (*oss_pcm_poll_result)(int fd, struct pollfd *ufds);
extern int oss_mixer_open(const char *pathname, int flags, ...);
static int bufsize;
static int fragsize;
static char *wbuf, *rbuf;
+static int loop = 40;
static void help(void)
{
{"rate", 1, NULL, 'r'},
{"channels", 1, NULL, 'c'},
{"frag", 1, NULL, 'F'},
+ {"loop", 1, NULL, 'L'},
{NULL, 0, NULL, 0},
};
morehelp = 0;
while (1) {
int c;
- if ((c = getopt_long(argc, argv, "hD:M:r:c:F:v", long_option, NULL)) < 0)
+ if ((c = getopt_long(argc, argv, "hD:M:r:c:F:L:v", long_option, NULL)) < 0)
break;
switch (c) {
case 'h':
case 'F':
frag = atoi(optarg);
break;
+ case 'L':
+ loop = atoi(optarg);
+ break;
case 'v':
verbose = 1;
break;
nfrag = 0;
- for (idx=0; idx<40; idx++) {
+ for (idx=0; idx<loop; idx++) {
struct count_info count;
- int res;
+ int res, maxfd;
FD_ZERO(&writeset);
- FD_SET(fd, &writeset);
+ FD_ZERO(&readset);
+ maxfd = oss_pcm_select_prepare(fd, omode, &readset, &writeset, NULL);
tim.tv_sec = 10;
- tim.tv_usec= 0;
+ tim.tv_usec = 0;
- res = select(fd+1, NULL, &writeset, NULL, &tim);
+ res = select(maxfd + 1, &readset, &writeset, NULL, &tim);
#ifdef VERBOSE
printf("Select returned: %03d\n", res);
fflush(stdout);