]> git.alsa-project.org Git - alsa-oss.git/commitdiff
- a try to let OSS mmap mode work with dmix plugin
authorJaroslav Kysela <perex@perex.cz>
Wed, 18 Feb 2004 20:17:05 +0000 (20:17 +0000)
committerJaroslav Kysela <perex@perex.cz>
Wed, 18 Feb 2004 20:17:05 +0000 (20:17 +0000)
- call avail_update in GETIPTR and GETOPTR functions (fixme)
- fixed/enhanced semantics of select_prepare (should work now)

alsa/alsa-oss-emul.h
alsa/alsa-oss.c
alsa/pcm.c
oss-redir/oss-redir.c
oss-redir/oss-redir.h
test/osstest.c

index 0c644005d47c0a7f7d4d488390a31897f1eb3ebb..5fbd906dce5994b526a416353921ba93efc8df1f 100644 (file)
@@ -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, ...);
index cedd80ec7e01b41f51436629063e8798d97ad364..5dcfc3edd66aae5e09ab96f0abf51af74af5f1a4 100644 (file)
@@ -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;
                }
index 7ad7e6680c816c253d0c3c35f16890f1a6bb1029..a881f61828a52334972612cd749d423bea8fd0eb 100644 (file)
@@ -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)
index 666eda37e377838beb2b4b30274ee116eb2650fa..8b4888da803573c4c3dde35929eb47702d71a874 100644 (file)
@@ -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)
index 53c40e42b9d9c76df4e9659d19a17fe4fde481fc..4e228317b104b85e3b4357264d458cc94047c6ca 100644 (file)
@@ -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, ...);
index 0a24048fb4194b15a2d2c3b7ad77eee6575b1876..a77332ccf9c8e9eba1f997f2219b124705b36127 100644 (file)
@@ -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<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);