From: Jaroslav Kysela Date: Wed, 18 Feb 2004 20:17:05 +0000 (+0000) Subject: - a try to let OSS mmap mode work with dmix plugin X-Git-Tag: v1.0.3~26 X-Git-Url: https://git.alsa-project.org/?a=commitdiff_plain;h=35c2566eba40f10cff57c49402affd89595a381d;p=alsa-oss.git - a try to let OSS mmap mode work with dmix plugin - call avail_update in GETIPTR and GETOPTR functions (fixme) - fixed/enhanced semantics of select_prepare (should work now) --- diff --git a/alsa/alsa-oss-emul.h b/alsa/alsa-oss-emul.h index 0c64400..5fbd906 100644 --- a/alsa/alsa-oss-emul.h +++ b/alsa/alsa-oss-emul.h @@ -68,10 +68,10 @@ extern ssize_t lib_oss_pcm_write(int fd, const void *buf, size_t count); 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, ...); diff --git a/alsa/alsa-oss.c b/alsa/alsa-oss.c index cedd80e..5dcfc3e 100644 --- a/alsa/alsa-oss.c +++ b/alsa/alsa-oss.c @@ -72,6 +72,7 @@ static ops_t ops[FD_CLASSES]; typedef struct { fd_class_t class; + int oflags; void *mmap_area; } fd_t; @@ -90,6 +91,8 @@ static int oss_pcm_fcntl(int fd, int cmd, ...) 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) { @@ -119,6 +122,8 @@ static int oss_mixer_fcntl(int fd, int cmd, ...) va_end(args); switch (cmd) { + case F_GETFL: + return fds[fd]->oflags; default: DEBUG("mixer_fcntl(%d, ", fd); result = _fcntl(fd, cmd, arg); @@ -200,6 +205,7 @@ int open(const char *file, int oflag, ...) 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)) { @@ -212,6 +218,7 @@ int open(const char *file, int oflag, ...) return -1; } fds[fd]->class = FD_OSS_MIXER; + fds[fd]->oflags = oflag; } } else { fd = _open(file, oflag, mode); @@ -376,8 +383,15 @@ int poll(struct pollfd *pfds, unsigned long nfds, int timeout) 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; } @@ -454,21 +468,25 @@ int select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, 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)); @@ -480,9 +498,26 @@ int select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, 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; } @@ -530,15 +565,19 @@ int select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, 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; } diff --git a/alsa/pcm.c b/alsa/pcm.c index 7ad7e66..a881f61 100644 --- a/alsa/pcm.c +++ b/alsa/pcm.c @@ -522,8 +522,14 @@ static int oss_dsp_open(int card, int device, int oflag, mode_t mode) 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; @@ -680,11 +686,14 @@ static void oss_dsp_mmap_update(oss_dsp_t *dsp, snd_pcm_stream_t stream, } #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 @@ -692,6 +701,8 @@ static void oss_dsp_mmap_update(oss_dsp_t *dsp, snd_pcm_stream_t stream, 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, @@ -1027,6 +1038,7 @@ int lib_oss_pcm_ioctl(int fd, unsigned long cmd, ...) 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; @@ -1066,6 +1078,7 @@ int lib_oss_pcm_ioctl(int fd, unsigned long cmd, ...) 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; @@ -1264,10 +1277,10 @@ int lib_oss_pcm_munmap(void *addr, size_t len) 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; @@ -1278,6 +1291,10 @@ int lib_oss_pcm_select_prepare(int fd, fd_set *readfds, fd_set *writefds, fd_set 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; @@ -1294,6 +1311,8 @@ int lib_oss_pcm_select_prepare(int fd, fd_set *readfds, fd_set *writefds, fd_set 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) @@ -1312,7 +1331,7 @@ int lib_oss_pcm_select_prepare(int fd, fd_set *readfds, fd_set *writefds, fd_set } } } - return 0; + return maxfd; } int lib_oss_pcm_select_result(int fd, fd_set *readfds, fd_set *writefds, fd_set *exceptfds) @@ -1363,7 +1382,7 @@ int lib_oss_pcm_select_result(int fd, fd_set *readfds, fd_set *writefds, fd_set result |= OSS_WAIT_EVENT_ERROR; if (revents & POLLIN) result |= OSS_WAIT_EVENT_READ; - if (revents & POLLIN) + if (revents & POLLOUT) result |= OSS_WAIT_EVENT_WRITE; } } @@ -1394,10 +1413,10 @@ extern int lib_oss_pcm_poll_fds(int fd) 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; @@ -1408,6 +1427,10 @@ int lib_oss_pcm_poll_prepare(int fd, struct pollfd *ufds) 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; @@ -1419,8 +1442,9 @@ int lib_oss_pcm_poll_prepare(int fd, struct pollfd *ufds) return -1; } ufds += count; + result += count; } - return 0; + return result; } int lib_oss_pcm_poll_result(int fd, struct pollfd *ufds) diff --git a/oss-redir/oss-redir.c b/oss-redir/oss-redir.c index 666eda3..8b4888d 100644 --- a/oss-redir/oss-redir.c +++ b/oss-redir/oss-redir.c @@ -50,10 +50,10 @@ ssize_t (*oss_pcm_write)(int fd, const void *buf, size_t count); 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); @@ -75,21 +75,21 @@ static int native_pcm_nonblock(int fd, int nonblock) 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) @@ -114,13 +114,14 @@ static int native_pcm_poll_fds(int fd) 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) diff --git a/oss-redir/oss-redir.h b/oss-redir/oss-redir.h index 53c40e4..4e22831 100644 --- a/oss-redir/oss-redir.h +++ b/oss-redir/oss-redir.h @@ -41,10 +41,10 @@ extern ssize_t (*oss_pcm_write)(int fd, const void *buf, size_t count); 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, ...); diff --git a/test/osstest.c b/test/osstest.c index 0a24048..a77332c 100644 --- a/test/osstest.c +++ b/test/osstest.c @@ -25,6 +25,7 @@ static audio_buf_info ispace; static int bufsize; static int fragsize; static char *wbuf, *rbuf; +static int loop = 40; static void help(void) { @@ -155,13 +156,14 @@ int main(int argc, char *argv[]) {"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': @@ -187,6 +189,9 @@ int main(int argc, char *argv[]) case 'F': frag = atoi(optarg); break; + case 'L': + loop = atoi(optarg); + break; case 'v': verbose = 1; break; @@ -208,17 +213,18 @@ int main(int argc, char *argv[]) nfrag = 0; - for (idx=0; idx<40; idx++) { + for (idx=0; idx