Update of /cvsroot/alsa/alsa-oss/test
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv7159/test

Modified Files:
        mmap_test.c 
Log Message:
Converted mmap_test to normal coding style; some mmap cleanups

Index: mmap_test.c
===================================================================
RCS file: /cvsroot/alsa/alsa-oss/test/mmap_test.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- mmap_test.c 12 Feb 2004 17:16:07 -0000      1.2
+++ mmap_test.c 12 Feb 2004 18:51:37 -0000      1.3
@@ -1,297 +1,149 @@
-/*

- * This is a simple program which demonstrates use of mmapped DMA buffer

- * of the sound driver directly from application program.

- *

- * This sample program works (currently) only with Linux, FreeBSD and BSD/OS

- * (FreeBSD and BSD/OS require OSS version 3.8-beta16 or later.

- *

- * Note! Don't use mmapped DMA buffers (direct audio) unless you have

- * very good reasons to do it. Programs using this feature will not

- * work with all soundcards. GUS (GF1) is one of them (GUS MAX works).

- *

- * This program requires version 3.5-beta7 or later of OSS

- * (3.8-beta16 or later in FreeBSD and BSD/OS).

- */

-

-#include <stdio.h>

-#include <unistd.h>

-#include <fcntl.h>

-#include <sys/types.h>

-#include <sys/mman.h>

-#include <sys/soundcard.h>

-#include <sys/time.h>

-

-main()

-{

-       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;

-

+#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 */

-

-       fd_set writeset;

-

-       close(0);

-       if ((fd=oss_pcm_open("/dev/dsp", O_RDWR, 0))==-1)

-       {

-               perror("/dev/dsp");

-               exit(-1);

-       }

-/*

- * Then setup sampling parameters. Just sampling rate in this case.

- */

-

-       tmp = 48000;

-       oss_pcm_ioctl(fd, SNDCTL_DSP_SPEED, &tmp);

-       printf("Speed set to %d\n", tmp);

-

-/*

- * Load some test data.

- */

-

-  sl = sp = 0;

-  if ((sd=open("smpl", O_RDONLY, 0))!=-1)

-  {

-       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)==-1)

-       {

-               perror("/dev/dsp");

-               fprintf(stderr, "Sorry but your sound driver is too old\n");

-               exit(-1);

-       }

-

-/*

- * Check that the device has capability to do this. Currently just

- * CS4231 based cards will work.

- *

- * The application should also check for DSP_CAP_MMAP bit but this

- * version of driver doesn't have it yet.

- */

-/*     oss_pcm_ioctl(fd, SNDCTL_DSP_SETSYNCRO, 0); */

-

-/*

- * You need version 3.5-beta7 or later of the sound driver before next

- * two lines compile. There is no point to modify this program to

- * compile with older driver versions since they don't have working

- * mmap() support.

- */

-       if (!(caps & DSP_CAP_TRIGGER) ||

-           !(caps & DSP_CAP_MMAP))

-       {

-               fprintf(stderr, "Sorry but your soundcard can't do this\n");

-               exit(-1);

-       }

-

-/*

- * Select the period size. This is propably important only when

- * the program uses select(). Period size defines how often

- * select call returns.

- */

-

-       oss_pcm_ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &frag);

-

-/*

- * Compute total size of the buffer. It's important to use this value

- * in mmap() call.

- */

-

-       if (oss_pcm_ioctl(fd, SNDCTL_DSP_GETOSPACE, &info)==-1)

-       {

-               perror("GETOSPACE");

-               exit(-1);

-       }

-

-       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 );
-

-/*

- * Call mmap().

- * 

- * IMPORTANT NOTE!!!!!!!!!!!

- *

- * Full duplex audio devices have separate input and output buffers. 

- * It is not possible to map both of them at the same mmap() call. The buffer

- * is selected based on the prot argument in the following way:

- *

- * - PROT_READ (alone) selects the input buffer.

- * - PROT_WRITE (alone) selects the output buffer.

- * - PROT_WRITE|PROT_READ together select the output buffer. This combination

- *   is required in BSD to make the buffer accessible. With just PROT_WRITE

- *   every attempt to access the returned buffer will result in segmentation/bus

- *   error. PROT_READ|PROT_WRITE is also permitted in Linux with OSS version

- *   3.8-beta16 and later (earlier versions don't accept it).

- *

- * Non duplex devices have just one buffer. When an application wants to do both

- * input and output it's recommended that the device is closed and re-opened when

- * switching between modes. PROT_READ|PROT_WRITE can be used to open the buffer

- * for both input and output (with OSS 3.8-beta16 and later) but the result may be

- * unpredictable.

- */

-

-#if 1
-       if ((buf=mmap(NULL, sz, PROT_WRITE, MAP_FILE|MAP_SHARED, fd, 0))==(caddr_t)-1)

-       {

-               perror("mmap (write)");

-               exit(-1);

-       }

-       printf("mmap (out) returned %08x\n", buf);

-#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);

+               fflush(stdout);
+#endif
+               count.ptr = (count.ptr/fsz)*fsz;
+
+#ifdef VERBOSE
+               printf(" memcpy(%6d, %4d)\n", (dp-data), fsz);
+               fflush(stdout);
 #endif
-       op=buf;

-

-/*

- * op contains now a pointer to the DMA buffer

- */

-

-/*

- * Then it's time to start the engine. The driver doesn't allow read() and/or

- * write() when the buffer is mapped. So the only way to start operation is

- * to togle device's enable bits. First set them off. Setting them on enables

- * recording and/or playback.

- */

-

-       tmp = 0;

-       oss_pcm_ioctl(fd, SNDCTL_DSP_SETTRIGGER, &tmp);

-       printf("Trigger set to %08x\n", tmp);

-

-/*

- * It might be usefull to write some data to the buffer before starting.

- */

-

-       tmp = PCM_ENABLE_OUTPUT;

-       oss_pcm_ioctl(fd, SNDCTL_DSP_SETTRIGGER, &tmp);

-       printf("Trigger set to %08x\n", tmp);

-

-/*

- * The machine is up and running now. Use SNDCTL_DSP_GETOPTR to get the

- * buffer status.

- *

- * NOTE! The driver empties each buffer fragmen after they have been

- * played. This prevents looping sound if there are some performance problems

- * in the application side. For similar reasons it recommended that the

- * application uses some amout of play ahead. It can rewrite the unplayed

- * data later if necessary.

- */

-

-       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);

-/*

- * SNDCTL_DSP_GETOPTR (and GETIPTR as well) return three items. The

- * bytes field returns number of bytes played since start. It can be used

- * as a real time clock.

- *

- * The blocks field returns number of period transitions (interrupts) since

- * previous GETOPTR call. It can be used as a method to detect underrun 

- * situations.

- *

- * The ptr field is the DMA pointer inside the buffer area (in bytes from

- * the beginning of total buffer area).

- */

-

-               if (oss_pcm_ioctl(fd, SNDCTL_DSP_GETOPTR, &count)==-1)

-               {

-                       perror("GETOPTR");

-                       exit(-1);

-               }

-

-               nfrag += count.blocks;

-

-#ifdef VERBOSE

-

-               printf("Total: %09d, Period: %03d, Ptr: %06d",

-                       count.bytes, nfrag, count.ptr);

-               fflush(stdout);

-#endif

-

-/*

- * Caution! This version doesn't check for bounds of the DMA

- * memory area. It's possible that the returned pointer value is not aligned

- * to period boundaries. It may be several samples behind the boundary

- * in case there was extra delay between the actual hardware interrupt and

- * the time when DSP_GETOPTR was called.

- *

- * Don't just call memcpy() with length set to 'period_size' without

- * first checking that the transfer really fits to the buffer area.

- * A mistake of just one byte causes seg fault. It may be easiest just

- * to align the returned pointer value to period boundary before using it.

- *

- * It would be very good idea to write few extra samples to next period

- * too. Otherwise several (uninitialized) samples from next period

- * will get played before your program gets chance to initialize them.

- * Take in count the fact thaat there are other processes batling about

- * the same CPU. This effect is likely to be very annoying if period

- * size is decreased too much.

- */

-

-/*

- * Just a minor clarification to the above. The following line alings

- * the pointer to period boundaries. Note! Don't trust that period

- * size is always a power of 2. It may not be so in future.

- */

-               count.ptr = (count.ptr/fsz)*fsz;

-

-#ifdef VERBOSE

-               printf(" memcpy(%6d, %4d)\n", (dp-data), fsz);

-               fflush(stdout);

-#endif

-

-/*

+
+/*
  * Set few bytes in the beginning of next period too.

- */

-               if ((count.ptr+fsz+16) < sz)    /* Last period? */

-                  extra = 16;

-               else

-                  extra = 0;

-

-               memcpy(op+count.ptr, dp, fsz+extra);

-               

-               dp += fsz;

-               if (dp > (data+sl-fsz))

-                  dp = data;

-       }

-

-       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)

-       {

-               perror("/dev/dsp");

-               exit(-1);

-       }

-       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);

-}

+       exit(0);
+}



-------------------------------------------------------
SF.Net is sponsored by: Speed Start Your Linux Apps Now.
Build and deploy apps & Web services for Linux with
a free DVD software kit from IBM. Click Now!
http://ads.osdn.com/?ad_id=1356&alloc_id=3438&op=click
_______________________________________________
Alsa-cvslog mailing list
[EMAIL PROTECTED]
https://lists.sourceforge.net/lists/listinfo/alsa-cvslog

Reply via email to