Skip to content

Instantly share code, notes, and snippets.

@a3f
Created July 5, 2021 16:59
Show Gist options
  • Save a3f/baefc6364acb47e89cce5a90f4491c23 to your computer and use it in GitHub Desktop.
Save a3f/baefc6364acb47e89cce5a90f4491c23 to your computer and use it in GitHub Desktop.
Poor man's strace for SNDRV_PCM_IOCTL_SYNC_PTR and brethern
#define _GNU_SOURCE
#include <sound/asound.h>
#include <linux/ioctl.h>
#include <stdio.h>
#include <dlfcn.h>
#define report(...) fprintf(stderr, __VA_ARGS__)
static void decode_pcm_state(snd_pcm_state_t state)
{
switch (state) {
case SNDRV_PCM_STATE_OPEN:
report("stream is open\n");
break;
case SNDRV_PCM_STATE_SETUP:
report("stream has a setup\n");
break;
case SNDRV_PCM_STATE_PREPARED:
report("stream is ready to start\n");
break;
case SNDRV_PCM_STATE_RUNNING:
report("stream is running\n");
break;
case SNDRV_PCM_STATE_XRUN:
report("stream reached an xrun\n");
break;
case SNDRV_PCM_STATE_DRAINING:
report("stream is draining\n");
break;
case SNDRV_PCM_STATE_PAUSED:
report("stream is paused\n");
break;
case SNDRV_PCM_STATE_SUSPENDED:
report("hardware is suspended\n");
break;
case SNDRV_PCM_STATE_DISCONNECTED:
report("hardware is disconnected\n");
break;
default:
report("%d\n", state);
}
}
static void decode_tstamp(const struct timespec *tstamp)
{
report("%ld.%ld\n", (long)tstamp->tv_sec, tstamp->tv_nsec);
}
static void decode_u32_array(const __u32 *array, unsigned len)
{
while (len--)
report("0x%08x ", *array++);
}
static void decode_pcm_info(const struct snd_pcm_info *info)
{
report("device=%u\nsubdevice=%u\nstream=%d\ncard=%d\nid=%.64s\nname=%.80s\n"
"subname=%.32s\ndev_class=%d\ndev_subclass=%d\nsubdevices_count=%u\n"
"subdevices_avail=%u\nsync=",
info->device,
info->subdevice,
info->stream,
info->card,
info->id,
info->name,
info->subname,
info->dev_class,
info->dev_subclass,
info->subdevices_count,
info->subdevices_avail);
decode_u32_array(info->sync.id32, 4);
report("\n");
}
static void decode_snd_interval(const struct snd_interval *interval)
{
report("min=%u max=%u openmin=%u openmax=%u integer=%u empty=%u ",
interval->min,
interval->max,
interval->openmin,
interval->openmax,
interval->integer,
interval->empty);
}
static void decode_hw_params(const struct snd_pcm_hw_params *params)
{
report("flags=%u\nmasks={\n", params->flags);
report("\t[ACCESS] = {\n");
decode_u32_array(params->masks[SNDRV_PCM_HW_PARAM_ACCESS].bits, 8);
report("}\n\t[FORMAT] = {\n");
decode_u32_array(params->masks[SNDRV_PCM_HW_PARAM_FORMAT].bits, 8);
report("}\n\t[SUBFORMAT] = {\n");
decode_u32_array(params->masks[SNDRV_PCM_HW_PARAM_SUBFORMAT].bits, 8);
report("}\n}");
report("intervals={\n");
report("\t[SAMPLE_BITS] = { ");
decode_snd_interval(&params->intervals[SNDRV_PCM_HW_PARAM_ACCESS]);
report("}\n\t[FRAME_BITS] = { ");
decode_snd_interval(&params->intervals[SNDRV_PCM_HW_PARAM_FORMAT]);
report("}\n\t[CHANNELS] = { ");
decode_snd_interval(&params->intervals[SNDRV_PCM_HW_PARAM_SUBFORMAT]);
report("}\n\t[RATE] = { ");
decode_snd_interval(&params->intervals[SNDRV_PCM_HW_PARAM_SUBFORMAT]);
report("}\n\t[PERIOD_TIME] = { ");
decode_snd_interval(&params->intervals[SNDRV_PCM_HW_PARAM_SUBFORMAT]);
report("}\n\t[PERIOD_SIZE] = { ");
decode_snd_interval(&params->intervals[SNDRV_PCM_HW_PARAM_SUBFORMAT]);
report("}\n\t[PERIOD_BYTES] = { ");
decode_snd_interval(&params->intervals[SNDRV_PCM_HW_PARAM_SUBFORMAT]);
report("}\n\t[PERIODS] = { ");
decode_snd_interval(&params->intervals[SNDRV_PCM_HW_PARAM_SUBFORMAT]);
report("}\n\t[BUFFER_TIME] = { ");
decode_snd_interval(&params->intervals[SNDRV_PCM_HW_PARAM_SUBFORMAT]);
report("}\n\t[BUFFER_SIZE] = { ");
decode_snd_interval(&params->intervals[SNDRV_PCM_HW_PARAM_SUBFORMAT]);
report("}\n\t[BUFFER_BYTES] = { ");
decode_snd_interval(&params->intervals[SNDRV_PCM_HW_PARAM_SUBFORMAT]);
report("}\n\t[TICK_TIME] = { ");
decode_snd_interval(&params->intervals[SNDRV_PCM_HW_PARAM_SUBFORMAT]);
report("}\n}");
report("rmask=%x\ncmask=%x\ninfo=%x\nmsbits=%x\nrate_num=%u\n"
"rate_den=%u\nfifio_size=%llu\n",
params->rmask,
params->cmask,
params->info,
params->msbits,
params->rate_num,
params->rate_den,
(unsigned long long)params->fifo_size);
}
static void decode_sw_params(const struct snd_pcm_sw_params *params)
{
report("tstamp_mode=%d\nperiod_step=%u\nsleep_min=%u\navail_min=%lu\n", params->tstamp_mode,
params->period_step, params->sleep_min, params->avail_min);
report("xfer_align=%lu\ntart_threshold=%lu\nstop_threshold=%lu\nsilence_threshold=%lu\n",
params->xfer_align,
params->start_threshold,
params->stop_threshold,
params->silence_threshold);
report("silence_size=%lu\nboundary=%lu\nproto=%u\ntstamp_type=%u\n",
params->silence_size,
params->boundary,
params->proto,
params->tstamp_type);
}
static void decode_pcm_status(const struct snd_pcm_status *status)
{
report("state=");
decode_pcm_state(status->state);
report("trigger_tstamp=");
decode_tstamp(&status->trigger_tstamp);
report("tstamp=");
decode_tstamp(&status->tstamp);
report("\nappl_ptr=%lu\nhw_ptr=%lu\ndelay=%lu\navail=%lu\navail_max=%lu\noverrange=%lu\n",
status->appl_ptr,
status->hw_ptr,
status->delay,
status->avail,
status->avail_max,
status->overrange);
report("suspended_state=");
decode_pcm_state(status->suspended_state);
report("audio_tstamp=");
decode_tstamp(&status->audio_tstamp);
report("driver_tstamp=");
decode_tstamp(&status->driver_tstamp);
}
static void decode_mmap_control64(const struct snd_pcm_mmap_control *control)
{
report("appl_ptr=%lu avail_min=%lu\n", control->appl_ptr, control->avail_min);
}
static void decode_mmap_status64(const struct snd_pcm_mmap_status *status)
{
report("\tstate=");
decode_pcm_state(status->state);
report("\thw_ptr=%lu\n", status->hw_ptr);
report("\ttstamp=");
decode_tstamp(&status->tstamp);
report("\tsuspended_state=");
decode_pcm_state(status->suspended_state);
report("\taudio_tstamp=");
decode_tstamp(&status->audio_tstamp);
}
static void decode_sync_ptr(const struct snd_pcm_sync_ptr *ptr)
{
report("flags=%08x\n", ptr->flags);
report("status=\n");
decode_mmap_status64(&ptr->s.status);
report("control=");
decode_mmap_control64(&ptr->c.control);
}
int ioctl(int fd, unsigned long request, void *argp)
{
static int (*original_fn)(int fd, unsigned long request, void *argp);
int ret;
if (!original_fn)
original_fn = dlsym(RTLD_NEXT, __func__);
switch(request) {
/* IOR */
case SNDRV_CTL_IOCTL_CARD_INFO:
report("### IOCTL(%i, %s, %p)\n", fd, "SNDRV_CTL_IOCTL_CARD_INFO", argp);
break;
case SNDRV_CTL_IOCTL_PCM_INFO:
report("### IOCTL(%i, %s, %p)\n", fd, "SNDRV_CTL_IOCTL_PCM_INFO", argp);
decode_pcm_info(argp);
break;
case SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE:
report("### IOCTL(%i, %s, %p)\n", fd, "SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE", argp);
break;
case SNDRV_CTL_IOCTL_PVERSION:
report("### IOCTL(%i, %s, %p)\n", fd, "SNDRV_CTL_IOCTL_PVERSION", argp);
break;
case SNDRV_PCM_IOCTL_PVERSION:
report("### IOCTL(%i, %s, %p)\n", fd, "SNDRV_PCM_IOCTL_PVERSION", argp);
break;
case SNDRV_PCM_IOCTL_CHANNEL_INFO:
report("### IOCTL(%i, %s, %p)\n", fd, "SNDRV_PCM_IOCTL_CHANNEL_INFO", argp);
break;
case SNDRV_PCM_IOCTL_LINK:
report("### IOCTL(%i, %s)\n", fd, "SNDRV_PCM_IOCTL_LINK");
report("link=%i\n", (int)(unsigned long)argp);
break;
case SNDRV_PCM_IOCTL_HW_PARAMS:
report("### IOCTL(%i, %s, %p)\n", fd, "SNDRV_PCM_IOCTL_HW_PARAMS", argp);
decode_hw_params(argp);
break;
case SNDRV_PCM_IOCTL_HW_REFINE:
report("### IOCTL(%i, %s, %p)\n", fd, "SNDRV_PCM_IOCTL_HW_REFINE", argp);
decode_hw_params(argp);
break;
case SNDRV_PCM_IOCTL_INFO:
report("### IOCTL(%i, %s, %p)\n", fd, "SNDRV_PCM_IOCTL_INFO", argp);
decode_pcm_info(argp);
break;
case SNDRV_PCM_IOCTL_STATUS_EXT:
report("### IOCTL(%i, %s, %p)\n", fd, "SNDRV_PCM_IOCTL_STATUS_EXT", argp);
decode_pcm_status(argp);
break;
case SNDRV_PCM_IOCTL_SW_PARAMS:
report("### IOCTL(%i, %s, %p)\n", fd, "SNDRV_PCM_IOCTL_SW_PARAMS", argp);
decode_sw_params(argp);
break;
case SNDRV_PCM_IOCTL_SYNC_PTR:
report("### IOCTL(%i, %s)\n", fd, "SNDRV_PCM_IOCTL_SYNC_PTR");
decode_sync_ptr(argp);
break;
case SNDRV_PCM_IOCTL_TTSTAMP:
report("### IOCTL(%i, %s)\n", fd, "SNDRV_PCM_IOCTL_TTSTAMP");
report("stamp=%i\n", *(int *)argp);
break;
case SNDRV_PCM_IOCTL_USER_PVERSION:
report("### IOCTL(%i, %s)\n", fd, "SNDRV_PCM_IOCTL_USER_PVERSION");
report("version=%i\n", *(int *)argp);
break;
case SNDRV_PCM_IOCTL_DROP:
report("### IOCTL(%i, %s)\n", fd, "SNDRV_PCM_IOCTL_DROP");
break;
case SNDRV_PCM_IOCTL_START:
report("### IOCTL(%i, %s)\n", fd, "SNDRV_PCM_IOCTL_START");
break;
case SNDRV_PCM_IOCTL_PREPARE:
report("### IOCTL(%i, %s)\n", fd, "SNDRV_PCM_IOCTL_PREPARE");
break;
}
ret = original_fn(fd, request, argp);
report("\t ... = %d\n", ret);
switch(request) {
/* IOW */
const struct snd_ctl_card_info *card_info;
const struct snd_pcm_channel_info *channel_info;
case SNDRV_CTL_IOCTL_CARD_INFO:
card_info = argp;
report("card=%u\nid=%.16s\ndriver=%.16s\nname=%.32s\nlongname=%.80s\nmixername=%.80s\ncomponents=%.128s\n",
card_info->card, card_info->id, card_info->name, card_info->longname,
card_info->mixername, card_info->components);
break;
case SNDRV_CTL_IOCTL_PCM_INFO:
decode_pcm_info(argp);
break;
case SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE:
report("device=%i\n", *(int *)argp);
break;
case SNDRV_CTL_IOCTL_PVERSION:
report("version=%i\n", *(int *)argp);
break;
case SNDRV_PCM_IOCTL_PVERSION:
report("version=%i\n", *(int *)argp);
break;
case SNDRV_PCM_IOCTL_CHANNEL_INFO:
channel_info = argp;
report("channel=%llu\noffset=%lu\nfirst=%u\nstep=%u\n",
channel_info->channel,
(long long)channel_info->offset,
channel_info->first,
channel_info->step);
break;
case SNDRV_PCM_IOCTL_HW_PARAMS:
decode_hw_params(argp);
break;
case SNDRV_PCM_IOCTL_HW_REFINE:
decode_hw_params(argp);
break;
case SNDRV_PCM_IOCTL_INFO:
decode_pcm_info(argp);
break;
case SNDRV_PCM_IOCTL_STATUS_EXT:
decode_pcm_status(argp);
break;
case SNDRV_PCM_IOCTL_SW_PARAMS:
decode_sw_params(argp);
break;
case SNDRV_PCM_IOCTL_SYNC_PTR:
decode_sync_ptr(argp);
break;
case SNDRV_PCM_IOCTL_DROP:
case SNDRV_PCM_IOCTL_START:
case SNDRV_PCM_IOCTL_PREPARE:
/* no args */
break;
case SNDRV_PCM_IOCTL_TTSTAMP:
case SNDRV_PCM_IOCTL_USER_PVERSION:
case SNDRV_PCM_IOCTL_LINK:
/* write-only */
break;
}
return ret;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment