struct _snd_async_handler {
enum {
SND_ASYNC_HANDLER_GENERIC,
- SND_ASYNC_HANDLER_PCM,
SND_ASYNC_HANDLER_CTL,
+ SND_ASYNC_HANDLER_PCM,
+ SND_ASYNC_HANDLER_TIMER,
} type;
int fd;
union {
- snd_pcm_t *pcm;
snd_ctl_t *ctl;
+ snd_pcm_t *pcm;
+ snd_timer_t *timer;
} u;
snd_async_callback_t callback;
void *private_data;
int snd_timer_open(snd_timer_t **handle, const char *name, int mode);
int snd_timer_open_lconf(snd_timer_t **handle, const char *name, int mode, snd_config_t *lconf);
int snd_timer_close(snd_timer_t *handle);
+int snd_async_add_timer_handler(snd_async_handler_t **handler, snd_timer_t *timer,
+ snd_async_callback_t callback, void *private_data);
+snd_timer_t *snd_async_handler_get_timer(snd_async_handler_t *handler);
int snd_timer_poll_descriptors_count(snd_timer_t *handle);
int snd_timer_poll_descriptors(snd_timer_t *handle, struct pollfd *pfds, unsigned int space);
int snd_timer_poll_descriptors_revents(snd_timer_t *timer, struct pollfd *pfds, unsigned int nfds, unsigned short *revents);
snd_pcm_parse_control_id;
+ snd_async_add_timer_handler;
+ snd_async_handler_get_timer;
+
snd_timer_ginfo_sizeof;
snd_timer_ginfo_malloc;
snd_timer_ginfo_free;
{
int err;
assert(timer);
+ while (!list_empty(&timer->async_handlers)) {
+ snd_async_handler_t *h = list_entry(timer->async_handlers.next, snd_async_handler_t, hlist);
+ snd_async_del_handler(h);
+ }
if ((err = timer->ops->close(timer)) < 0)
return err;
if (timer->name)
return timer->type;
}
+/**
+ * \brief Add an async handler for a timer
+ * \param handler Returned handler handle
+ * \param timer timer handle
+ * \param callback Callback function
+ * \param private_data Callback private data
+ * \return 0 otherwise a negative error code on failure
+ *
+ * The asynchronous callback is called when new timer event occurs.
+ */
+int snd_async_add_timer_handler(snd_async_handler_t **handler, snd_timer_t *timer,
+ snd_async_callback_t callback, void *private_data)
+{
+ int err;
+ int was_empty;
+ snd_async_handler_t *h;
+ err = snd_async_add_handler(&h, timer->poll_fd,
+ callback, private_data);
+ if (err < 0)
+ return err;
+ h->type = SND_ASYNC_HANDLER_TIMER;
+ h->u.timer = timer;
+ was_empty = list_empty(&timer->async_handlers);
+ list_add_tail(&h->hlist, &timer->async_handlers);
+ if (was_empty) {
+ err = snd_timer_async(timer, snd_async_handler_get_signo(h), getpid());
+ if (err < 0) {
+ snd_async_del_handler(h);
+ return err;
+ }
+ }
+ *handler = h;
+ return 0;
+}
+
+/**
+ * \brief Return timer handle related to an async handler
+ * \param handler Async handler handle
+ * \return timer handle
+ */
+snd_timer_t *snd_async_handler_get_timer(snd_async_handler_t *handler)
+{
+ if (handler->type != SND_ASYNC_HANDLER_TIMER) {
+ SNDMSG("invalid handler type %d", handler->type);
+ return NULL;
+ }
+ return handler->u.timer;
+}
+
/**
* \brief get count of poll descriptors for timer handle
* \param timer timer handle
tmr->name = strdup(name);
tmr->poll_fd = fd;
tmr->ops = &snd_timer_hw_ops;
+ INIT_LIST_HEAD(&tmr->async_handlers);
*handle = tmr;
return 0;
}
int poll_fd;
snd_timer_ops_t *ops;
void *private_data;
+ struct list_head async_handlers;
};
int snd_timer_hw_open(snd_timer_t **handle, const char *name, int dev_class, int dev_sclass, int card, int device, int subdevice, int mode);
free(fds);
}
+static void async_callback(snd_async_handler_t *ahandler)
+{
+ snd_timer_t *handle = snd_async_handler_get_timer(ahandler);
+ int *acount = snd_async_handler_get_callback_private(ahandler);
+ snd_timer_read_t tr;
+
+ while (snd_timer_read(handle, &tr, sizeof(tr)) == sizeof(tr)) {
+ printf("TIMER: resolution = %uns, ticks = %u\n",
+ tr.resolution, tr.ticks);
+ }
+ (*acount)++;
+}
+
int main(int argc, char *argv[])
{
int idx, err;
int device = SND_TIMER_GLOBAL_SYSTEM;
int subdevice = 0;
int list = 0;
+ int async = 0;
+ int acount = 0;
snd_timer_t *handle;
snd_timer_id_t *id;
snd_timer_info_t *info;
snd_timer_params_t *params;
char timername[64];
+ snd_async_handler_t *ahandler;
snd_timer_id_alloca(&id);
snd_timer_info_alloca(&info);
subdevice = atoi(argv[idx]+10);
} else if (!strcmp(argv[idx], "list")) {
list = 1;
+ } else if (!strcmp(argv[idx], "async")) {
+ async = 1;
}
idx++;
}
exit(0);
}
show_status(handle);
+ if (async) {
+ err = snd_async_add_timer_handler(&ahandler, handle, async_callback, &acount);
+ if (err < 0) {
+ fprintf(stderr, "unable to add async handler %i (%s)\n", err, snd_strerror(err));
+ exit(EXIT_FAILURE);
+ }
+ }
if ((err = snd_timer_start(handle)) < 0) {
fprintf(stderr, "timer start %i (%s)\n", err, snd_strerror(err));
exit(EXIT_FAILURE);
}
- read_loop(handle, 25, snd_timer_info_is_slave(info) ? 10000 : 25);
+ if (async) {
+ /* because all other work is done in the signal handler,
+ suspend the process */
+ while (acount < 25)
+ sleep(1);
+ snd_timer_stop(handle);
+ } else {
+ read_loop(handle, 25, snd_timer_info_is_slave(info) ? 10000 : 25);
+ }
show_status(handle);
snd_timer_close(handle);
printf("Done\n");