Index: share/examples/sound/oss/audio.c =================================================================== --- share/examples/sound/oss/audio.c +++ share/examples/sound/oss/audio.c @@ -29,18 +29,26 @@ * SUCH DAMAGE. */ +#include +#include #include #include -#include #include +#include #include #include #include #include +#define EXAMPLE_LOOP 0 +#define EXAMPLE_SELECT 1 +#define EXAMPLE_POLL 2 +#define EXAMPLE_KQUEUE 3 +#define EXAMPLE_MMAP 4 + #ifndef SAMPLE_SIZE -#define SAMPLE_SIZE 16 +#define SAMPLE_SIZE 32 #endif /* Format can be unsigned, in which case replace S with U */ @@ -76,6 +84,8 @@ int sample_size; int chsamples; int mmap; + int caps; + void *mbuf; oss_audioinfo audio_info; audio_buf_info buffer_info; } config_t; @@ -246,13 +256,47 @@ } config->sample_count = config->buffer_info.bytes / config->sample_size; config->chsamples = config->sample_count / config->channels; + + /* Get device capabilities */ + tmp = config->caps; + if (ioctl(config->fd, SNDCTL_DSP_GETCAPS, &tmp) == 0) + config->caps = tmp; + else + config->caps = 0; +} + +int +process_audio(config_t *config, int8_t *ibuf, int8_t *obuf, sample_t *channels, int bytes) +{ + int ret; + + ret = read(config->fd, ibuf, bytes); + if (ret < bytes) { + fprintf(stderr, "Requested %d bytes, but read %d!\n", bytes, ret); + return (1); + } + oss_split(config, (sample_t *)ibuf, channels); + /* All processing will happen here */ + oss_merge(config, channels, (sample_t *)obuf); + ret = write(config->fd, obuf, bytes); + if (ret < bytes) { + fprintf(stderr, "Requested %d bytes, but wrote %d!\n", bytes, ret); + return (1); + } + return (0); +} + +int +has_capability(config_t *config, int capabilities) { + return ((config->caps & capabilities) == capabilities); } int main(int argc, char *argv[]) { - int ret, bytes; + int fd, ret, bytes, example; int8_t *ibuf, *obuf; + sample_t *channels; config_t config = { .device = "/dev/dsp", .channels = -1, @@ -262,18 +306,37 @@ .sample_size = sizeof(sample_t), .buffer_info.fragments = -1, .mmap = 0, + .caps = 0, }; + if (argc != 2) + errx(1, "Usage: %s ", argv[0]); + + if (strcmp(argv[1], "loop") == 0) + example = EXAMPLE_LOOP; + else if (strcmp(argv[1], "select") == 0) + example = EXAMPLE_SELECT; + else if (strcmp(argv[1], "poll") == 0) + example = EXAMPLE_POLL; + else if (strcmp(argv[1], "kqueue") == 0) + example = EXAMPLE_KQUEUE; + else if (strcmp(argv[1], "mmap") == 0) { + example = EXAMPLE_MMAP; + config.mmap = 1; + } + else + errx(1, "Unknown example: %s", argv[1]); + /* Initialize device */ oss_init(&config); + bytes = config.buffer_info.bytes; /* * Allocate input and output buffers so that their size match frag_size */ - bytes = config.buffer_info.bytes; ibuf = malloc(bytes); obuf = malloc(bytes); - sample_t *channels = malloc(bytes); + channels = malloc(bytes); printf("bytes: %d, fragments: %d, fragsize: %d, fragstotal: %d, " "samples: %d\n", @@ -281,24 +344,72 @@ config.buffer_info.fragsize, config.buffer_info.fragstotal, config.sample_count); - /* Minimal engine: read input and copy it to the output */ - for (;;) { - ret = read(config.fd, ibuf, bytes); - if (ret < bytes) { - fprintf(stderr, "Requested %d bytes, but read %d!\n", - bytes, ret); - break; + if (example == EXAMPLE_LOOP) { + for (;;) { + printf("Loop processing\n"); + if (process_audio(&config, ibuf, obuf, channels, bytes) != 0) + break; } - oss_split(&config, (sample_t *)ibuf, channels); - /* All processing will happen here */ - oss_merge(&config, channels, (sample_t *)obuf); - ret = write(config.fd, obuf, bytes); - if (ret < bytes) { - fprintf(stderr, "Requested %d bytes, but wrote %d!\n", - bytes, ret); - break; + } else if (example == EXAMPLE_SELECT) { + fd_set fds; + + for (;;) { + printf("Select processing\n"); + FD_ZERO(&fds); + FD_SET(config.fd, &fds); + ret = select(config.fd + 1, &fds, NULL, NULL, NULL); + if (FD_ISSET(config.fd, &fds)) + if (process_audio(&config, ibuf, obuf, channels, bytes) != 0) + break; } - } + } else if (example == EXAMPLE_POLL) { + struct pollfd pfds[1]; + + for (;;) { + printf("Poll processing\n"); + pfds[0].fd = config.fd; + pfds[0].events = POLLIN; + ret = poll(pfds, sizeof(pfds) / sizeof(struct pollfd), -1); + if (pfds[0].revents != 0) + if (process_audio(&config, ibuf, obuf, channels, bytes) != 0) + break; + } + } else if (example == EXAMPLE_KQUEUE) { + int kq; + struct kevent event = {}; + + kq = kqueue(); + if (kq == -1) + errx(1, "Failed to allocate kqueue"); + EV_SET(&event, fd, EVFILT_WRITE, EV_ADD | EV_CLEAR, NOTE_WRITE, 0, 0); + ret = kevent(kq, &event, 1, 0, 0, 0); + if (ret == -1) + errx(1, "Failed to register kevent"); + for (;;) { + printf("Kqueue processing\n"); + ret = kevent(kq, 0, 0, &event, 1, 0); + if (ret == -1 || event.data == 0) + break; + if (event.flags & EV_ERROR) + errx(1, "Event error: %s", strerror(event.data)); + if (process_audio(&config, ibuf, obuf, channels, bytes) != 0) + break; + } + close(kq); + } else if (example == EXAMPLE_MMAP) { + if (!has_capability(&config, PCM_CAP_MMAP)) + errx(1, "Memory map not supported by device"); + config.mbuf = mmap(NULL, config.buffer_info.bytes, PROT_READ, MAP_SHARED, config.fd, 0); + if (config.mbuf == MAP_FAILED) + errx(1, "Memory map failed"); + // for (;;) { + // printf("Memory-mapped processing\n"); + // } + if (munmap(config.mbuf, config.buffer_info.bytes) != 0) + errx(1, "Memory unmap failed"); + config.mbuf = NULL; + } else + errx(1, "Unknown example id: %d", example); /* Cleanup */ free(channels);