rawmidi: Add rawmidi framing API

Optionally, incoming rawmidi bytes can be put inside a frame of type
snd_rawmidi_framing_tstamp_t.
The main current benefit is that can enable in-kernel timestamping of
incoming bytes, and that timestamp is likely to be more precise than
what userspace can offer.

Tstamp type framing requires a kernel >= 5.14 and a buffer size that
is a multiple of sizeof(snd_rawmidi_framing_tstamp_t). It is only
available on input streams.

Signed-off-by: David Henningsson <coding@diwic.se>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
David Henningsson 2021-08-17 16:21:12 +02:00 committed by Takashi Iwai
parent 23a191a82c
commit 95eb312fad
5 changed files with 153 additions and 2 deletions

View file

@ -118,6 +118,15 @@ hw:soundwave,1,2
hw:DEV=1,CARD=soundwave,SUBDEV=2
\endcode
\section rawmidi_framing Framing of rawmidi data
Optionally, incoming rawmidi bytes can be put inside a frame of type snd_rawmidi_framing_tstamp_t.
The main current benefit is that can enable in-kernel timestamping of incoming bytes, and that
timestamp is likely to be more precise than what userspace can offer.
Tstamp type framing requires a kernel >= 5.14 and a buffer size that is a multiple of
sizeof(snd_rawmidi_framing_tstamp_t). It is only available on input streams.
\section rawmidi_examples Examples
The full featured examples with cross-links:
@ -154,6 +163,7 @@ static int snd_rawmidi_params_default(snd_rawmidi_t *rawmidi, snd_rawmidi_params
params->buffer_size = page_size();
params->avail_min = 1;
params->no_active_sensing = 1;
params->mode = 0;
return 0;
}
@ -811,6 +821,77 @@ int snd_rawmidi_params_get_no_active_sensing(const snd_rawmidi_params_t *params)
return params->no_active_sensing;
}
/**
* \brief enable or disable rawmidi framing
* \param rawmidi RawMidi handle
* \param params pointer to snd_rawmidi_params_t structure
* \param val type of rawmidi framing
* \return 0 on success, otherwise a negative error code.
*
* Notable error codes:
* -EINVAL - "val" is invalid
* -ENOTSUP - Kernel is too old to support framing.
*
*/
int snd_rawmidi_params_set_framing_type(const snd_rawmidi_t *rawmidi, snd_rawmidi_params_t *params, snd_rawmidi_framing_t val)
{
assert(rawmidi && params);
if (val > SNDRV_RAWMIDI_MODE_FRAMING_MASK >> SNDRV_RAWMIDI_MODE_FRAMING_SHIFT)
return -EINVAL;
if (val != SNDRV_RAWMIDI_MODE_FRAMING_NONE &&
(rawmidi->version < SNDRV_PROTOCOL_VERSION(2, 0, 2) || rawmidi->stream != SND_RAWMIDI_STREAM_INPUT))
return -ENOTSUP;
params->mode = (params->mode & ~SNDRV_RAWMIDI_MODE_FRAMING_MASK) + (val << SNDRV_RAWMIDI_MODE_FRAMING_SHIFT);
return 0;
}
/**
* \brief get current framing type
* \param params pointer to snd_rawmidi_params_t structure
* \return the current type (0 = no framing, 1 = tstamp type framing)
*/
snd_rawmidi_framing_t snd_rawmidi_params_get_framing_type(const snd_rawmidi_params_t *params)
{
assert(params);
return (params->mode & SNDRV_RAWMIDI_MODE_FRAMING_MASK) >> SNDRV_RAWMIDI_MODE_FRAMING_SHIFT;
}
/**
* \brief sets clock type for tstamp type framing
* \param rawmidi RawMidi handle
* \param params pointer to snd_rawmidi_params_t structure
* \param val one of the SND_RAWMIDI_CLOCK_* constants
* \return 0 on success, otherwise a negative error code.
*
* Notable error codes:
* -EINVAL - "val" is invalid
* -ENOTSUP - Kernel is too old to support framing.
*
*/
int snd_rawmidi_params_set_clock_type(const snd_rawmidi_t *rawmidi, snd_rawmidi_params_t *params, snd_rawmidi_clock_t val)
{
assert(rawmidi && params);
if (val > SNDRV_RAWMIDI_MODE_CLOCK_MASK >> SNDRV_RAWMIDI_MODE_CLOCK_SHIFT)
return -EINVAL;
if (val != SNDRV_RAWMIDI_MODE_CLOCK_NONE &&
(rawmidi->version < SNDRV_PROTOCOL_VERSION(2, 0, 2) || rawmidi->stream != SND_RAWMIDI_STREAM_INPUT))
return -ENOTSUP;
params->mode = (params->mode & ~SNDRV_RAWMIDI_MODE_CLOCK_MASK) + (val << SNDRV_RAWMIDI_MODE_CLOCK_SHIFT);
return 0;
}
/**
* \brief get current clock type (for tstamp type framing)
* \param params pointer to snd_rawmidi_params_t structure
* \return the current clock type (one of the SND_RAWMIDI_CLOCK_* constants)
*/
snd_rawmidi_clock_t snd_rawmidi_params_get_clock_type(const snd_rawmidi_params_t *params)
{
assert(params);
return (params->mode & SNDRV_RAWMIDI_MODE_CLOCK_MASK) >> SNDRV_RAWMIDI_MODE_CLOCK_SHIFT;
}
/**
* \brief set parameters about rawmidi stream
* \param rawmidi RawMidi handle
@ -828,6 +909,7 @@ int snd_rawmidi_params(snd_rawmidi_t *rawmidi, snd_rawmidi_params_t * params)
rawmidi->buffer_size = params->buffer_size;
rawmidi->avail_min = params->avail_min;
rawmidi->no_active_sensing = params->no_active_sensing;
rawmidi->params_mode = rawmidi->version < SNDRV_PROTOCOL_VERSION(2, 0, 2) ? 0 : params->mode;
return 0;
}
@ -844,6 +926,7 @@ int snd_rawmidi_params_current(snd_rawmidi_t *rawmidi, snd_rawmidi_params_t *par
params->buffer_size = rawmidi->buffer_size;
params->avail_min = rawmidi->avail_min;
params->no_active_sensing = rawmidi->no_active_sensing;
params->mode = rawmidi->params_mode;
return 0;
}

View file

@ -285,6 +285,7 @@ int snd_rawmidi_hw_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp,
rmidi->poll_fd = fd;
rmidi->ops = &snd_rawmidi_hw_ops;
rmidi->private_data = hw;
rmidi->version = ver;
hw->open++;
*inputp = rmidi;
}
@ -300,6 +301,7 @@ int snd_rawmidi_hw_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp,
rmidi->poll_fd = fd;
rmidi->ops = &snd_rawmidi_hw_ops;
rmidi->private_data = hw;
rmidi->version = ver;
hw->open++;
*outputp = rmidi;
}

View file

@ -42,12 +42,14 @@ struct _snd_rawmidi {
snd_rawmidi_type_t type;
snd_rawmidi_stream_t stream;
int mode;
int version;
int poll_fd;
const snd_rawmidi_ops_t *ops;
void *private_data;
size_t buffer_size;
size_t avail_min;
unsigned int no_active_sensing: 1;
int params_mode;
};
int snd_rawmidi_hw_open(snd_rawmidi_t **input, snd_rawmidi_t **output,