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