]> git.alsa-project.org Git - alsa-oss.git/commitdiff
Converted mmap_test to normal coding style; some mmap cleanups
authorJaroslav Kysela <perex@perex.cz>
Thu, 12 Feb 2004 18:51:37 +0000 (18:51 +0000)
committerJaroslav Kysela <perex@perex.cz>
Thu, 12 Feb 2004 18:51:37 +0000 (18:51 +0000)
alsa/alsa-oss.c
alsa/pcm.c
test/mmap_test.c

index 835075590c012ffbd53fbad6a1bab47282808d51..cedd80ec7e01b41f51436629063e8798d97ad364 100644 (file)
@@ -147,7 +147,7 @@ static void *bad_mmap(void *addr ATTRIBUTE_UNUSED, size_t len ATTRIBUTE_UNUSED,
                      int fd ATTRIBUTE_UNUSED, off_t offset ATTRIBUTE_UNUSED)
 {
        errno = EBADFD;
-       return NULL;
+       return MAP_FAILED;
 }
 
 static int bad_munmap(void* addr ATTRIBUTE_UNUSED, size_t len ATTRIBUTE_UNUSED)
index 1abec35cf5742993bde016e817b5ddcd9380dd94..197d40a187821fb89f516b4c2b2c9c4407eb594f 100644 (file)
@@ -1192,7 +1192,7 @@ void * lib_oss_pcm_mmap(void *addr ATTRIBUTE_UNUSED, size_t len ATTRIBUTE_UNUSED
 
        if (dsp == NULL) {
                errno = -EBADFD;
-               return NULL;
+               return MAP_FAILED;
        }
        switch (prot & (PROT_READ | PROT_WRITE)) {
        case PROT_READ:
index 179225a69a74a6713af472037ec5b1b53fc28a12..665b004edf4a46b7d068fa68337c019809cb2022 100644 (file)
-/*\r
- * This is a simple program which demonstrates use of mmapped DMA buffer\r
- * of the sound driver directly from application program.\r
- *\r
- * This sample program works (currently) only with Linux, FreeBSD and BSD/OS\r
- * (FreeBSD and BSD/OS require OSS version 3.8-beta16 or later.\r
- *\r
- * Note! Don't use mmapped DMA buffers (direct audio) unless you have\r
- * very good reasons to do it. Programs using this feature will not\r
- * work with all soundcards. GUS (GF1) is one of them (GUS MAX works).\r
- *\r
- * This program requires version 3.5-beta7 or later of OSS\r
- * (3.8-beta16 or later in FreeBSD and BSD/OS).\r
- */\r
-\r
-#include <stdio.h>\r
-#include <unistd.h>\r
-#include <fcntl.h>\r
-#include <sys/types.h>\r
-#include <sys/mman.h>\r
-#include <sys/soundcard.h>\r
-#include <sys/time.h>\r
-\r
-main()\r
-{\r
-       int fd, sz, fsz, i, tmp, n, l, have_data=0, nfrag;\r
-        int caps, idx;\r
-\r
-       int sd, sl=0, sp;\r
-\r
-       unsigned char data[500000], *dp = data;\r
-\r
-       struct buffmem_desc imemd, omemd;\r
-        caddr_t buf;\r
-       struct timeval tim;\r
-\r
-       unsigned char *op;\r
-       \r
-        struct audio_buf_info info;\r
-\r
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/soundcard.h>
+#include <sys/time.h>
+#include <oss-redir.h>
+
+int main(void)
+{
+       int fd, sz, fsz, i, tmp, n, l, have_data=0, nfrag;
+        int caps, idx;
+
+       int sd, sl=0, sp;
+
+       unsigned char data[500000], *dp = data;
+
+       struct buffmem_desc imemd, omemd;
+        caddr_t buf;
+       struct timeval tim;
+
+       unsigned char *op;
+       
+        struct audio_buf_info info;
+
        int frag = 0xffff000c;  /* Max # periods of 2^13=8k bytes */\r
-\r
-       fd_set writeset;\r
-\r
-       close(0);\r
-       if ((fd=oss_pcm_open("/dev/dsp", O_RDWR, 0))==-1)\r
-       {\r
-               perror("/dev/dsp");\r
-               exit(-1);\r
-       }\r
-/*\r
- * Then setup sampling parameters. Just sampling rate in this case.\r
- */\r
-\r
-       tmp = 48000;\r
-       oss_pcm_ioctl(fd, SNDCTL_DSP_SPEED, &tmp);\r
-       printf("Speed set to %d\n", tmp);\r
-\r
-/*\r
- * Load some test data.\r
- */\r
-\r
-  sl = sp = 0;\r
-  if ((sd=open("smpl", O_RDONLY, 0))!=-1)\r
-  {\r
-       sl = read(sd, data, sizeof(data));\r
-       printf("%d bytes read from file.\n", sl);\r
-       close(sd);\r
-  }\r
-  else perror("smpl");\r
-\r
-       if (oss_pcm_ioctl(fd, SNDCTL_DSP_GETCAPS, &caps)==-1)\r
-       {\r
-               perror("/dev/dsp");\r
-               fprintf(stderr, "Sorry but your sound driver is too old\n");\r
-               exit(-1);\r
-       }\r
-\r
-/*\r
- * Check that the device has capability to do this. Currently just\r
- * CS4231 based cards will work.\r
- *\r
- * The application should also check for DSP_CAP_MMAP bit but this\r
- * version of driver doesn't have it yet.\r
- */\r
-/*     oss_pcm_ioctl(fd, SNDCTL_DSP_SETSYNCRO, 0); */\r
-\r
-/*\r
- * You need version 3.5-beta7 or later of the sound driver before next\r
- * two lines compile. There is no point to modify this program to\r
- * compile with older driver versions since they don't have working\r
- * mmap() support.\r
- */\r
-       if (!(caps & DSP_CAP_TRIGGER) ||\r
-           !(caps & DSP_CAP_MMAP))\r
-       {\r
-               fprintf(stderr, "Sorry but your soundcard can't do this\n");\r
-               exit(-1);\r
-       }\r
-\r
-/*\r
- * Select the period size. This is propably important only when\r
- * the program uses select(). Period size defines how often\r
- * select call returns.\r
- */\r
-\r
-       oss_pcm_ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &frag);\r
-\r
-/*\r
- * Compute total size of the buffer. It's important to use this value\r
- * in mmap() call.\r
- */\r
-\r
-       if (oss_pcm_ioctl(fd, SNDCTL_DSP_GETOSPACE, &info)==-1)\r
-       {\r
-               perror("GETOSPACE");\r
-               exit(-1);\r
-       }\r
-\r
-       sz = info.fragstotal * info.fragsize;\r
-       fsz = info.fragsize;\r
-       printf( "info.fragstotal = %i\n", info.fragstotal );
-       printf( "info.fragsize = %i\n", info.fragsize );
-       printf( "info.periods = %i\n", info.fragments );
-       printf( "info.bytes = %i\n", info.bytes );
-\r
-/*\r
- * Call mmap().\r
- * \r
- * IMPORTANT NOTE!!!!!!!!!!!\r
- *\r
- * Full duplex audio devices have separate input and output buffers. \r
- * It is not possible to map both of them at the same mmap() call. The buffer\r
- * is selected based on the prot argument in the following way:\r
- *\r
- * - PROT_READ (alone) selects the input buffer.\r
- * - PROT_WRITE (alone) selects the output buffer.\r
- * - PROT_WRITE|PROT_READ together select the output buffer. This combination\r
- *   is required in BSD to make the buffer accessible. With just PROT_WRITE\r
- *   every attempt to access the returned buffer will result in segmentation/bus\r
- *   error. PROT_READ|PROT_WRITE is also permitted in Linux with OSS version\r
- *   3.8-beta16 and later (earlier versions don't accept it).\r
- *\r
- * Non duplex devices have just one buffer. When an application wants to do both\r
- * input and output it's recommended that the device is closed and re-opened when\r
- * switching between modes. PROT_READ|PROT_WRITE can be used to open the buffer\r
- * for both input and output (with OSS 3.8-beta16 and later) but the result may be\r
- * unpredictable.\r
- */\r
-\r
-#if 1
-       if ((buf=mmap(NULL, sz, PROT_WRITE, MAP_FILE|MAP_SHARED, fd, 0))==(caddr_t)-1)\r
-       {\r
-               perror("mmap (write)");\r
-               exit(-1);\r
-       }\r
-       printf("mmap (out) returned %08x\n", buf);\r
-#else
-        buf=data;
+
+       fd_set writeset;
+
+       if ((fd=oss_pcm_open("/dev/dsp", O_RDWR, 0))==-1) {
+               perror("/dev/dsp");
+               exit(-1);
+       }
+       tmp = 48000;
+       if (oss_pcm_ioctl(fd, SNDCTL_DSP_SPEED, &tmp) < 0) {
+               perror("SNDCTL_DSP_SPEED\n");
+               exit(EXIT_FAILURE);
+       }
+       printf("Speed set to %d\n", tmp);
+
+       sl = sp = 0;
+       if ((sd=open("smpl", O_RDONLY, 0)) >= 0) {
+               sl = read(sd, data, sizeof(data));
+               printf("%d bytes read from file.\n", sl);
+               close(sd);
+       } else
+               perror("smpl");
+
+       if (oss_pcm_ioctl(fd, SNDCTL_DSP_GETCAPS, &caps) < 0) {
+               perror("/dev/dsp");
+               fprintf(stderr, "Sorry but your sound driver is too old\n");
+               exit(EXIT_FAILURE);
+       }
+       if (!(caps & DSP_CAP_TRIGGER) ||
+           !(caps & DSP_CAP_MMAP))
+       {
+               fprintf(stderr, "Sorry but your soundcard can't do this\n");
+               exit(EXIT_FAILURE);
+       }
+       if (oss_pcm_ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &frag) < 0)
+               perror("SNDCTL_DSP_SETFRAGMENT");
+       if (oss_pcm_ioctl(fd, SNDCTL_DSP_GETOSPACE, &info) < 0) {
+               perror("SNDCTL_DSP_GETOSPACE");
+               exit(EXIT_FAILURE);
+       }
+       sz = info.fragstotal * info.fragsize;
+       fsz = info.fragsize;
+       printf("info.fragstotal = %i\n", info.fragstotal);
+       printf("info.fragsize = %i\n", info.fragsize);
+       printf("info.periods = %i\n", info.fragments);
+       printf("info.bytes = %i\n", info.bytes);
+       if ((buf=mmap(NULL, sz, PROT_WRITE, MAP_FILE|MAP_SHARED, fd, 0))==MAP_FAILED) {
+               perror("mmap (write)");
+               exit(-1);
+       }
+       printf("mmap (out) returned %08x\n", buf);
+       op=buf;
+
+       tmp = 0;
+       if (oss_pcm_ioctl(fd, SNDCTL_DSP_SETTRIGGER, &tmp) < 0) {
+               perror("SNDCTL_DSP_SETTRIGGER");
+               exit(EXIT_FAILURE);
+       }
+       printf("Trigger set to %08x\n", tmp);
+
+       tmp = PCM_ENABLE_OUTPUT;
+       if (oss_pcm_ioctl(fd, SNDCTL_DSP_SETTRIGGER, &tmp) < 0) {
+               perror("SNDCTL_DSP_SETTRIGGER");
+               exit(EXIT_FAILURE);
+       }
+       printf("Trigger set to %08x\n", tmp);
+
+       nfrag = 0;
+       for (idx=0; idx<40; idx++) {
+               struct count_info count;
+               int p, l, extra;
+
+               FD_ZERO(&writeset);
+               FD_SET(fd, &writeset);
+
+               tim.tv_sec = 10;
+               tim.tv_usec= 0;
+
+               select(fd+1, NULL, &writeset, NULL, NULL);
+               if (oss_pcm_ioctl(fd, SNDCTL_DSP_GETOPTR, &count) < 0) {
+                       perror("GETOPTR");
+                       exit(EXIT_FAILURE);
+               }
+               nfrag += count.blocks;
+#ifdef VERBOSE
+               printf("Total: %09d, Period: %03d, Ptr: %06d", count.bytes, nfrag, count.ptr);\r
+               fflush(stdout);
+#endif
+               count.ptr = (count.ptr/fsz)*fsz;
+
+#ifdef VERBOSE
+               printf(" memcpy(%6d, %4d)\n", (dp-data), fsz);
+               fflush(stdout);
 #endif
-       op=buf;\r
-\r
-/*\r
- * op contains now a pointer to the DMA buffer\r
- */\r
-\r
-/*\r
- * Then it's time to start the engine. The driver doesn't allow read() and/or\r
- * write() when the buffer is mapped. So the only way to start operation is\r
- * to togle device's enable bits. First set them off. Setting them on enables\r
- * recording and/or playback.\r
- */\r
-\r
-       tmp = 0;\r
-       oss_pcm_ioctl(fd, SNDCTL_DSP_SETTRIGGER, &tmp);\r
-       printf("Trigger set to %08x\n", tmp);\r
-\r
-/*\r
- * It might be usefull to write some data to the buffer before starting.\r
- */\r
-\r
-       tmp = PCM_ENABLE_OUTPUT;\r
-       oss_pcm_ioctl(fd, SNDCTL_DSP_SETTRIGGER, &tmp);\r
-       printf("Trigger set to %08x\n", tmp);\r
-\r
-/*\r
- * The machine is up and running now. Use SNDCTL_DSP_GETOPTR to get the\r
- * buffer status.\r
- *\r
- * NOTE! The driver empties each buffer fragmen after they have been\r
- * played. This prevents looping sound if there are some performance problems\r
- * in the application side. For similar reasons it recommended that the\r
- * application uses some amout of play ahead. It can rewrite the unplayed\r
- * data later if necessary.\r
- */\r
-\r
-       nfrag = 0;\r
-       for (idx=0; idx<40; idx++)\r
-       {\r
-               struct count_info count;\r
-               int p, l, extra;\r
-\r
-               FD_ZERO(&writeset);\r
-               FD_SET(fd, &writeset);\r
-\r
-               tim.tv_sec = 10;\r
-               tim.tv_usec= 0;\r
-\r
-               select(fd+1, NULL, &writeset, NULL, NULL);\r
-/*\r
- * SNDCTL_DSP_GETOPTR (and GETIPTR as well) return three items. The\r
- * bytes field returns number of bytes played since start. It can be used\r
- * as a real time clock.\r
- *\r
- * The blocks field returns number of period transitions (interrupts) since\r
- * previous GETOPTR call. It can be used as a method to detect underrun \r
- * situations.\r
- *\r
- * The ptr field is the DMA pointer inside the buffer area (in bytes from\r
- * the beginning of total buffer area).\r
- */\r
-\r
-               if (oss_pcm_ioctl(fd, SNDCTL_DSP_GETOPTR, &count)==-1)\r
-               {\r
-                       perror("GETOPTR");\r
-                       exit(-1);\r
-               }\r
-\r
-               nfrag += count.blocks;\r
-\r
-#ifdef VERBOSE\r
-\r
-               printf("Total: %09d, Period: %03d, Ptr: %06d",\r
-                       count.bytes, nfrag, count.ptr);\r
-               fflush(stdout);\r
-#endif\r
-\r
-/*\r
- * Caution! This version doesn't check for bounds of the DMA\r
- * memory area. It's possible that the returned pointer value is not aligned\r
- * to period boundaries. It may be several samples behind the boundary\r
- * in case there was extra delay between the actual hardware interrupt and\r
- * the time when DSP_GETOPTR was called.\r
- *\r
- * Don't just call memcpy() with length set to 'period_size' without\r
- * first checking that the transfer really fits to the buffer area.\r
- * A mistake of just one byte causes seg fault. It may be easiest just\r
- * to align the returned pointer value to period boundary before using it.\r
- *\r
- * It would be very good idea to write few extra samples to next period\r
- * too. Otherwise several (uninitialized) samples from next period\r
- * will get played before your program gets chance to initialize them.\r
- * Take in count the fact thaat there are other processes batling about\r
- * the same CPU. This effect is likely to be very annoying if period\r
- * size is decreased too much.\r
- */\r
-\r
-/*\r
- * Just a minor clarification to the above. The following line alings\r
- * the pointer to period boundaries. Note! Don't trust that period\r
- * size is always a power of 2. It may not be so in future.\r
- */\r
-               count.ptr = (count.ptr/fsz)*fsz;\r
-\r
-#ifdef VERBOSE\r
-               printf(" memcpy(%6d, %4d)\n", (dp-data), fsz);\r
-               fflush(stdout);\r
-#endif\r
-\r
-/*\r
+
+/*
  * Set few bytes in the beginning of next period too.\r
- */\r
-               if ((count.ptr+fsz+16) < sz)    /* Last period? */\r
-                  extra = 16;\r
-               else\r
-                  extra = 0;\r
-\r
-               memcpy(op+count.ptr, dp, fsz+extra);\r
-               \r
-               dp += fsz;\r
-               if (dp > (data+sl-fsz))\r
-                  dp = data;\r
-       }\r
-\r
-       close(fd);
+ */
+               if ((count.ptr+fsz+16) < sz)    /* Last period? */
+                  extra = 16;
+               else
+                  extra = 0;
+
+               memcpy(op+count.ptr, dp, fsz+extra);
 
-       printf( ">>>> open (2)\n" ); fflush( stdout );
+               dp += fsz;
+               if (dp > (data+sl-fsz))
+                  dp = data;
+       }
 
-       if ((fd=oss_pcm_open("/dev/dsp", O_RDWR, 0))==-1)\r
-       {\r
-               perror("/dev/dsp");\r
-               exit(-1);\r
-       }\r
-       close( fd );        
+       close(fd);
+
+       printf("second open test:\n");
+       if ((fd=oss_pcm_open("/dev/dsp", O_RDWR, 0))==-1) {
+               perror("/dev/dsp");
+               exit(-1);
+       }
+       close(fd);
+       printf("second open test passed\n");
 
-       exit(0);\r
-}\r
+       exit(0);
+}