Skip to content

Instantly share code, notes, and snippets.

@takaswie
Created March 8, 2017 00:43
Show Gist options
  • Save takaswie/002deb09f3323527a4bf225749fb965d to your computer and use it in GitHub Desktop.
Save takaswie/002deb09f3323527a4bf225749fb965d to your computer and use it in GitHub Desktop.
ALSA timer test program
#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, &params) < 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