mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-10-31 22:25:35 -04:00
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:
parent
23a191a82c
commit
95eb312fad
5 changed files with 153 additions and 2 deletions
|
|
@ -79,6 +79,39 @@ typedef enum _snd_rawmidi_type {
|
||||||
SND_RAWMIDI_TYPE_VIRTUAL
|
SND_RAWMIDI_TYPE_VIRTUAL
|
||||||
} snd_rawmidi_type_t;
|
} snd_rawmidi_type_t;
|
||||||
|
|
||||||
|
/** Type of clock used with rawmidi tstamp framing */
|
||||||
|
typedef enum _snd_rawmidi_clock {
|
||||||
|
SND_RAWMIDI_CLOCK_NONE = 0,
|
||||||
|
SND_RAWMIDI_CLOCK_REALTIME = 1,
|
||||||
|
SND_RAWMIDI_CLOCK_MONOTONIC = 2,
|
||||||
|
SND_RAWMIDI_CLOCK_MONOTONIC_RAW = 3,
|
||||||
|
} snd_rawmidi_clock_t;
|
||||||
|
|
||||||
|
/** Enable or disable rawmidi framing */
|
||||||
|
typedef enum _snd_rawmidi_framing {
|
||||||
|
SND_RAWMIDI_FRAMING_NONE = 0,
|
||||||
|
SND_RAWMIDI_FRAMING_TSTAMP = 1,
|
||||||
|
} snd_rawmidi_framing_t;
|
||||||
|
|
||||||
|
#define SND_RAWMIDI_FRAME_TYPE_DEFAULT 0
|
||||||
|
|
||||||
|
#define SND_RAWMIDI_FRAMING_DATA_LENGTH 16
|
||||||
|
|
||||||
|
/** Incoming RawMidi bytes is put inside this container if tstamp type framing is enabled. */
|
||||||
|
typedef struct _snd_rawmidi_framing_tstamp {
|
||||||
|
/**
|
||||||
|
* For now, frame_type is always SND_RAWMIDI_FRAME_TYPE_DEFAULT.
|
||||||
|
* Midi 2.0 is expected to add new types here.
|
||||||
|
* Applications are expected to skip unknown frame types.
|
||||||
|
*/
|
||||||
|
__u8 frame_type;
|
||||||
|
__u8 length; /* number of valid bytes in data field */
|
||||||
|
__u8 reserved[2];
|
||||||
|
__u32 tv_nsec; /* nanoseconds */
|
||||||
|
__u64 tv_sec; /* seconds */
|
||||||
|
__u8 data[SND_RAWMIDI_FRAMING_DATA_LENGTH];
|
||||||
|
} snd_rawmidi_framing_tstamp_t;
|
||||||
|
|
||||||
int snd_rawmidi_open(snd_rawmidi_t **in_rmidi, snd_rawmidi_t **out_rmidi,
|
int snd_rawmidi_open(snd_rawmidi_t **in_rmidi, snd_rawmidi_t **out_rmidi,
|
||||||
const char *name, int mode);
|
const char *name, int mode);
|
||||||
int snd_rawmidi_open_lconf(snd_rawmidi_t **in_rmidi, snd_rawmidi_t **out_rmidi,
|
int snd_rawmidi_open_lconf(snd_rawmidi_t **in_rmidi, snd_rawmidi_t **out_rmidi,
|
||||||
|
|
@ -126,6 +159,11 @@ int snd_rawmidi_params_set_avail_min(snd_rawmidi_t *rmidi, snd_rawmidi_params_t
|
||||||
size_t snd_rawmidi_params_get_avail_min(const snd_rawmidi_params_t *params);
|
size_t snd_rawmidi_params_get_avail_min(const snd_rawmidi_params_t *params);
|
||||||
int snd_rawmidi_params_set_no_active_sensing(snd_rawmidi_t *rmidi, snd_rawmidi_params_t *params, int val);
|
int snd_rawmidi_params_set_no_active_sensing(snd_rawmidi_t *rmidi, snd_rawmidi_params_t *params, int val);
|
||||||
int snd_rawmidi_params_get_no_active_sensing(const snd_rawmidi_params_t *params);
|
int snd_rawmidi_params_get_no_active_sensing(const snd_rawmidi_params_t *params);
|
||||||
|
int snd_rawmidi_params_set_framing_type(const snd_rawmidi_t *rawmidi, snd_rawmidi_params_t *params, snd_rawmidi_framing_t val);
|
||||||
|
snd_rawmidi_framing_t snd_rawmidi_params_get_framing_type(const snd_rawmidi_params_t *params);
|
||||||
|
int snd_rawmidi_params_set_clock_type(const snd_rawmidi_t *rawmidi, snd_rawmidi_params_t *params, snd_rawmidi_clock_t val);
|
||||||
|
snd_rawmidi_clock_t snd_rawmidi_params_get_clock_type(const snd_rawmidi_params_t *params);
|
||||||
|
|
||||||
int snd_rawmidi_params(snd_rawmidi_t *rmidi, snd_rawmidi_params_t * params);
|
int snd_rawmidi_params(snd_rawmidi_t *rmidi, snd_rawmidi_params_t * params);
|
||||||
int snd_rawmidi_params_current(snd_rawmidi_t *rmidi, snd_rawmidi_params_t *params);
|
int snd_rawmidi_params_current(snd_rawmidi_t *rmidi, snd_rawmidi_params_t *params);
|
||||||
size_t snd_rawmidi_status_sizeof(void);
|
size_t snd_rawmidi_status_sizeof(void);
|
||||||
|
|
|
||||||
|
|
@ -702,7 +702,7 @@ enum {
|
||||||
* Raw MIDI section - /dev/snd/midi??
|
* Raw MIDI section - /dev/snd/midi??
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define SNDRV_RAWMIDI_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 1)
|
#define SNDRV_RAWMIDI_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 2)
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
SNDRV_RAWMIDI_STREAM_OUTPUT = 0,
|
SNDRV_RAWMIDI_STREAM_OUTPUT = 0,
|
||||||
|
|
@ -728,12 +728,38 @@ struct snd_rawmidi_info {
|
||||||
unsigned char reserved[64]; /* reserved for future use */
|
unsigned char reserved[64]; /* reserved for future use */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define SNDRV_RAWMIDI_MODE_FRAMING_MASK (7<<0)
|
||||||
|
#define SNDRV_RAWMIDI_MODE_FRAMING_SHIFT 0
|
||||||
|
#define SNDRV_RAWMIDI_MODE_FRAMING_NONE (0<<0)
|
||||||
|
#define SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP (1<<0)
|
||||||
|
#define SNDRV_RAWMIDI_MODE_CLOCK_MASK (7<<3)
|
||||||
|
#define SNDRV_RAWMIDI_MODE_CLOCK_SHIFT 3
|
||||||
|
#define SNDRV_RAWMIDI_MODE_CLOCK_NONE (0<<3)
|
||||||
|
#define SNDRV_RAWMIDI_MODE_CLOCK_REALTIME (1<<3)
|
||||||
|
#define SNDRV_RAWMIDI_MODE_CLOCK_MONOTONIC (2<<3)
|
||||||
|
#define SNDRV_RAWMIDI_MODE_CLOCK_MONOTONIC_RAW (3<<3)
|
||||||
|
|
||||||
|
#define SNDRV_RAWMIDI_FRAMING_DATA_LENGTH 16
|
||||||
|
|
||||||
|
struct snd_rawmidi_framing_tstamp {
|
||||||
|
/* For now, frame_type is always 0. Midi 2.0 is expected to add new
|
||||||
|
* types here. Applications are expected to skip unknown frame types.
|
||||||
|
*/
|
||||||
|
__u8 frame_type;
|
||||||
|
__u8 length; /* number of valid bytes in data field */
|
||||||
|
__u8 reserved[2];
|
||||||
|
__u32 tv_nsec; /* nanoseconds */
|
||||||
|
__u64 tv_sec; /* seconds */
|
||||||
|
__u8 data[SNDRV_RAWMIDI_FRAMING_DATA_LENGTH];
|
||||||
|
} __packed;
|
||||||
|
|
||||||
struct snd_rawmidi_params {
|
struct snd_rawmidi_params {
|
||||||
int stream;
|
int stream;
|
||||||
size_t buffer_size; /* queue size in bytes */
|
size_t buffer_size; /* queue size in bytes */
|
||||||
size_t avail_min; /* minimum avail bytes for wakeup */
|
size_t avail_min; /* minimum avail bytes for wakeup */
|
||||||
unsigned int no_active_sensing: 1; /* do not send active sensing byte in close() */
|
unsigned int no_active_sensing: 1; /* do not send active sensing byte in close() */
|
||||||
unsigned char reserved[16]; /* reserved for future use */
|
unsigned int mode; /* For input data only, frame incoming data */
|
||||||
|
unsigned char reserved[12]; /* reserved for future use */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct snd_rawmidi_status {
|
struct snd_rawmidi_status {
|
||||||
|
|
|
||||||
|
|
@ -118,6 +118,15 @@ hw:soundwave,1,2
|
||||||
hw:DEV=1,CARD=soundwave,SUBDEV=2
|
hw:DEV=1,CARD=soundwave,SUBDEV=2
|
||||||
\endcode
|
\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
|
\section rawmidi_examples Examples
|
||||||
|
|
||||||
The full featured examples with cross-links:
|
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->buffer_size = page_size();
|
||||||
params->avail_min = 1;
|
params->avail_min = 1;
|
||||||
params->no_active_sensing = 1;
|
params->no_active_sensing = 1;
|
||||||
|
params->mode = 0;
|
||||||
return 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;
|
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
|
* \brief set parameters about rawmidi stream
|
||||||
* \param rawmidi RawMidi handle
|
* \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->buffer_size = params->buffer_size;
|
||||||
rawmidi->avail_min = params->avail_min;
|
rawmidi->avail_min = params->avail_min;
|
||||||
rawmidi->no_active_sensing = params->no_active_sensing;
|
rawmidi->no_active_sensing = params->no_active_sensing;
|
||||||
|
rawmidi->params_mode = rawmidi->version < SNDRV_PROTOCOL_VERSION(2, 0, 2) ? 0 : params->mode;
|
||||||
return 0;
|
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->buffer_size = rawmidi->buffer_size;
|
||||||
params->avail_min = rawmidi->avail_min;
|
params->avail_min = rawmidi->avail_min;
|
||||||
params->no_active_sensing = rawmidi->no_active_sensing;
|
params->no_active_sensing = rawmidi->no_active_sensing;
|
||||||
|
params->mode = rawmidi->params_mode;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -285,6 +285,7 @@ int snd_rawmidi_hw_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp,
|
||||||
rmidi->poll_fd = fd;
|
rmidi->poll_fd = fd;
|
||||||
rmidi->ops = &snd_rawmidi_hw_ops;
|
rmidi->ops = &snd_rawmidi_hw_ops;
|
||||||
rmidi->private_data = hw;
|
rmidi->private_data = hw;
|
||||||
|
rmidi->version = ver;
|
||||||
hw->open++;
|
hw->open++;
|
||||||
*inputp = rmidi;
|
*inputp = rmidi;
|
||||||
}
|
}
|
||||||
|
|
@ -300,6 +301,7 @@ int snd_rawmidi_hw_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp,
|
||||||
rmidi->poll_fd = fd;
|
rmidi->poll_fd = fd;
|
||||||
rmidi->ops = &snd_rawmidi_hw_ops;
|
rmidi->ops = &snd_rawmidi_hw_ops;
|
||||||
rmidi->private_data = hw;
|
rmidi->private_data = hw;
|
||||||
|
rmidi->version = ver;
|
||||||
hw->open++;
|
hw->open++;
|
||||||
*outputp = rmidi;
|
*outputp = rmidi;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,12 +42,14 @@ struct _snd_rawmidi {
|
||||||
snd_rawmidi_type_t type;
|
snd_rawmidi_type_t type;
|
||||||
snd_rawmidi_stream_t stream;
|
snd_rawmidi_stream_t stream;
|
||||||
int mode;
|
int mode;
|
||||||
|
int version;
|
||||||
int poll_fd;
|
int poll_fd;
|
||||||
const snd_rawmidi_ops_t *ops;
|
const snd_rawmidi_ops_t *ops;
|
||||||
void *private_data;
|
void *private_data;
|
||||||
size_t buffer_size;
|
size_t buffer_size;
|
||||||
size_t avail_min;
|
size_t avail_min;
|
||||||
unsigned int no_active_sensing: 1;
|
unsigned int no_active_sensing: 1;
|
||||||
|
int params_mode;
|
||||||
};
|
};
|
||||||
|
|
||||||
int snd_rawmidi_hw_open(snd_rawmidi_t **input, snd_rawmidi_t **output,
|
int snd_rawmidi_hw_open(snd_rawmidi_t **input, snd_rawmidi_t **output,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue