Update of /cvsroot/alsa/alsa-oss/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv4048
Added Files: .cvsignore Makefile.am mmap_test.c Log Message: Copied mmap_test from alsa-driver/test directory --- NEW FILE: .cvsignore --- Makefile Makefile.in .deps .libs *.lo *.la --- NEW FILE: Makefile.am --- check_PROGRAMS=mmap_test mmap_test_redir mmap_test_redir_LDADD=../oss-redir/libossredir.la INCLUDES=-I$(top_srcdir)/oss-redir CFLAGS=-static -Wall -pipe -g EXTRA_DIST= test_mmap_test: mmap_test_redir OSS_REDIRECTOR=libalsatoss.so mmap_test_redir --- NEW FILE: mmap_test.c --- /* * 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; int frag = 0xffff000c; /* Max # periods of 2^13=8k bytes */ fd_set writeset; close(0); if ((fd=open("/dev/dsp", O_RDWR, 0))==-1) { perror("/dev/dsp"); exit(-1); } /* * Then setup sampling parameters. Just sampling rate in this case. */ tmp = 48000; 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 (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. */ /* 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. */ ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &frag); /* * Compute total size of the buffer. It's important to use this value * in mmap() call. */ if (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; #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; 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; 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 (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); printf( ">>>> open (2)\n" ); fflush( stdout ); if ((fd=open("/dev/dsp", O_RDWR, 0))==-1) { perror("/dev/dsp"); exit(-1); } close( fd ); 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