Created
March 8, 2017 00:43
-
-
Save takaswie/002deb09f3323527a4bf225749fb965d to your computer and use it in GitHub Desktop.
ALSA timer test program
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <errno.h> | |
#include <string.h> | |
#include <sys/types.h> | |
#include <sys/stat.h> | |
#include <fcntl.h> | |
#include <sys/ioctl.h> | |
#include <unistd.h> | |
#include <limits.h> | |
#include <poll.h> | |
#include <pthread.h> | |
#include <sound/asound.h> | |
static const char *const event_labels[] = { | |
[SNDRV_TIMER_EVENT_RESOLUTION] = "resolution", | |
[SNDRV_TIMER_EVENT_TICK] = "tick", | |
[SNDRV_TIMER_EVENT_START] = "start", | |
[SNDRV_TIMER_EVENT_STOP] = "stop", | |
[SNDRV_TIMER_EVENT_CONTINUE] = "continue", | |
[SNDRV_TIMER_EVENT_PAUSE] = "pause", | |
[SNDRV_TIMER_EVENT_EARLY] = "early", | |
[SNDRV_TIMER_EVENT_SUSPEND] = "suspend", | |
[SNDRV_TIMER_EVENT_RESUME] = "resume", | |
[SNDRV_TIMER_EVENT_MSTART] = "mstart", | |
[SNDRV_TIMER_EVENT_MSTOP] = "mstop", | |
[SNDRV_TIMER_EVENT_MCONTINUE] = "mcontinue", | |
[SNDRV_TIMER_EVENT_MPAUSE] = "mpause", | |
[SNDRV_TIMER_EVENT_MSUSPEND] = "msuspend", | |
[SNDRV_TIMER_EVENT_MRESUME] = "mresume", | |
}; | |
static void *originate_events(void *arg) | |
{ | |
int *fd = arg; | |
sleep(2); | |
if (ioctl(*fd, SNDRV_TIMER_IOCTL_START) < 0) { | |
printf("ioctl(TIMER_START): %s\n", strerror(errno)); | |
return NULL; | |
} | |
printf("Started\n"); | |
sleep(10); | |
if (ioctl(*fd, SNDRV_TIMER_IOCTL_STOP) < 0) { | |
printf("ioctl(TIMER_STOP): %s\n", strerror(errno)); | |
return NULL; | |
} | |
printf("Stopped\n"); | |
return NULL; | |
} | |
static int start_thread(int *fd) | |
{ | |
pthread_t thread; | |
if (pthread_create(&thread, NULL, originate_events, (void *)fd) < 0) { | |
printf("pthread_create(3): %s\n", strerror(errno)); | |
return -errno; | |
} | |
return 0; | |
} | |
static int event_loop(int *fd) | |
{ | |
struct pollfd fds = { | |
.fd = *fd, | |
.events = POLLIN, | |
}; | |
struct snd_timer_tread data; | |
int count; | |
int err; | |
int i; | |
err = start_thread(fd); | |
if (err < 0) | |
return err; | |
while (1) { | |
count = poll(&fds, 1, -1); | |
if (count < 0) { | |
printf("poll(2): %s\n", strerror(errno)); | |
return count; | |
} | |
if (count == 0) | |
continue; | |
if (read(*fd, &data, sizeof(struct snd_timer_tread)) != | |
sizeof(struct snd_timer_tread)) { | |
printf("read(2): %s\n", strerror(errno)); | |
return -errno; | |
} | |
printf("Event:\n"); | |
printf(" event(%08x): ", data.event); | |
printf(" "); | |
for (i = 0; i < sizeof(event_labels)/sizeof(event_labels[0]); ++i) { | |
if (data.event & (1 << i)) | |
printf("%s, ", event_labels[i]); | |
} | |
printf("\n"); | |
printf(" tstamp: %ld.%d\n", | |
data.tstamp.tv_sec, data.tstamp.tv_nsec); | |
printf(" val: %d\n", data.val); | |
} | |
return 0; | |
} | |
static int set_params(int fd) | |
{ | |
/* See SNDRV_TIMER_PSFLG_XXX. */ | |
const char *const flag_labels[] = { | |
[0] = "auto", | |
[1] = "exclusive", | |
[2] = "early-event", | |
}; | |
struct snd_timer_params params = {0}; | |
int i; | |
params.flags = SNDRV_TIMER_PSFLG_AUTO | | |
SNDRV_TIMER_PSFLG_EXCLUSIVE; | |
params.ticks = 500; | |
params.queue_size = 128; | |
params.filter = (1 << SNDRV_TIMER_EVENT_RESOLUTION) | | |
(1 << SNDRV_TIMER_EVENT_TICK) | | |
(1 << SNDRV_TIMER_EVENT_START) | | |
(1 << SNDRV_TIMER_EVENT_STOP) | | |
(1 << SNDRV_TIMER_EVENT_CONTINUE) | | |
(1 << SNDRV_TIMER_EVENT_PAUSE) | | |
(1 << SNDRV_TIMER_EVENT_SUSPEND) | | |
(1 << SNDRV_TIMER_EVENT_RESUME) | | |
(1 << SNDRV_TIMER_EVENT_MSTART) | | |
(1 << SNDRV_TIMER_EVENT_MSTOP) | | |
(1 << SNDRV_TIMER_EVENT_MCONTINUE) | | |
(1 << SNDRV_TIMER_EVENT_MPAUSE) | | |
(1 << SNDRV_TIMER_EVENT_MSUSPEND) | | |
(1 << SNDRV_TIMER_EVENT_MRESUME); | |
if (ioctl(fd, SNDRV_TIMER_IOCTL_PARAMS, ¶ms) < 0) { | |
printf("ioctl(TIMER_PARAMS): %s\n", strerror(errno)); | |
return -errno; | |
} | |
printf("params:\n"); | |
printf(" flags: "); | |
for (i = 0; i < sizeof(flag_labels)/sizeof(flag_labels[0]); ++i) { | |
if (params.flags & (1 << i)) | |
printf("%s, ", flag_labels[i]); | |
} | |
printf("\n"); | |
printf(" ticks: %d\n", params.ticks); | |
printf(" queue-size: %d\n", params.queue_size); | |
printf(" filter(%08x): ", params.filter); | |
for (i = 0; i < sizeof(event_labels)/sizeof(event_labels[0]); ++i) { | |
if (params.filter & (1 << i)) | |
printf("%s, ", event_labels[i]); | |
} | |
printf("\n"); | |
return 0; | |
} | |
int main(void) | |
{ | |
int fd; | |
int flag; | |
struct snd_timer_select select = {0}; | |
int err; | |
fd = open("/dev/snd/timer", O_RDONLY); | |
if (fd < 0) { | |
printf("open(2): %s\n", strerror(errno)); | |
return EXIT_FAILURE; | |
} | |
flag = 1; | |
if (ioctl(fd, SNDRV_TIMER_IOCTL_TREAD, &flag) < 0) { | |
printf("ioctl(TIMER_TREAD): %s\n", strerror(errno)); | |
close(fd); | |
return EXIT_FAILURE; | |
} | |
select.id.dev_class = SNDRV_TIMER_CLASS_PCM; | |
select.id.dev_sclass = 0; | |
select.id.card = 1; | |
select.id.device = 0; | |
select.id.subdevice = 0; | |
if (ioctl(fd, SNDRV_TIMER_IOCTL_SELECT, &select) < 0) { | |
printf("ioctl(TIMER_SELECT): %s\n", strerror(errno)); | |
close(fd); | |
return EXIT_FAILURE; | |
} | |
err = set_params(fd); | |
if (err < 0) { | |
close(fd); | |
return EXIT_FAILURE; | |
} | |
err = event_loop(&fd); | |
close(fd); | |
return EXIT_SUCCESS; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment