Created
July 5, 2021 16:59
-
-
Save a3f/baefc6364acb47e89cce5a90f4491c23 to your computer and use it in GitHub Desktop.
Poor man's strace for SNDRV_PCM_IOCTL_SYNC_PTR and brethern
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
#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(¶ms->intervals[SNDRV_PCM_HW_PARAM_ACCESS]); | |
report("}\n\t[FRAME_BITS] = { "); | |
decode_snd_interval(¶ms->intervals[SNDRV_PCM_HW_PARAM_FORMAT]); | |
report("}\n\t[CHANNELS] = { "); | |
decode_snd_interval(¶ms->intervals[SNDRV_PCM_HW_PARAM_SUBFORMAT]); | |
report("}\n\t[RATE] = { "); | |
decode_snd_interval(¶ms->intervals[SNDRV_PCM_HW_PARAM_SUBFORMAT]); | |
report("}\n\t[PERIOD_TIME] = { "); | |
decode_snd_interval(¶ms->intervals[SNDRV_PCM_HW_PARAM_SUBFORMAT]); | |
report("}\n\t[PERIOD_SIZE] = { "); | |
decode_snd_interval(¶ms->intervals[SNDRV_PCM_HW_PARAM_SUBFORMAT]); | |
report("}\n\t[PERIOD_BYTES] = { "); | |
decode_snd_interval(¶ms->intervals[SNDRV_PCM_HW_PARAM_SUBFORMAT]); | |
report("}\n\t[PERIODS] = { "); | |
decode_snd_interval(¶ms->intervals[SNDRV_PCM_HW_PARAM_SUBFORMAT]); | |
report("}\n\t[BUFFER_TIME] = { "); | |
decode_snd_interval(¶ms->intervals[SNDRV_PCM_HW_PARAM_SUBFORMAT]); | |
report("}\n\t[BUFFER_SIZE] = { "); | |
decode_snd_interval(¶ms->intervals[SNDRV_PCM_HW_PARAM_SUBFORMAT]); | |
report("}\n\t[BUFFER_BYTES] = { "); | |
decode_snd_interval(¶ms->intervals[SNDRV_PCM_HW_PARAM_SUBFORMAT]); | |
report("}\n\t[TICK_TIME] = { "); | |
decode_snd_interval(¶ms->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