[alsa-devel] [Xen-devel][PATCH 0/2] sndif: add explicit back and front synchronization
From: Oleksandr Andrushchenko oleksandr_andrushchenko@epam.com
Hi, all!
Foreword ========
This change is aimed to add support for explicit back and front synchronization during playback and capture in response to comments raised during upstream attempt of the para-virtualized sound frontend driver for Xen [1], [2] and gather opinions from the relevant communities (ALSA, Xen) on the change.
The relevant backend is implemented as a user-space application [3] and uses accompanying helper library [4].
Both frontend driver and backend were tested on real HW running Xen hypervisor (Renesas R-Car ARM based H3/M3 boards, x86) to make sure the proposed solution does work.
Rationale =========
During the first attempt to upstream the Linux front driver [5] number of comments and concerns were raised, one of the biggest flaws in the design were questioned by both Clemens Ladisch [6] and Takashi Sakamoto [7]: the absence of synchronization between frontend and backend during capture/playback. Two options were discussed:
“In design of ALSA PCM core, drivers are expected to synchronize to actual hardwares for semi-realtime data transmission. The synchronization is done by two points: 1) Interrupts to respond events from actual hardwares. 2) Positions of actual data transmission in any serial sound interfaces of actual hardwares. “
and finally a change to the existing protocol was suggested:
“In 'include/xen/interface/io/sndif.h', there's no functionalities I described the above: 1. notifications from DomU to Dom0 about the size of period for interrupts from actual hardwares. Or no way from Dom0 to DomU about the configured size of the period. 2. notifications of the interrupts from actual hardwares to DomU.”
This is implemented as a change to the sndif protocol and allows removing period emulation: 1. Introduced a new event channel from back to front 2. New event with number of bytes played/captured (XENSND_EVT_CUR_POS, to be used for sending snd_pcm_period_elapsed at frontend (in Linux implementation). Sent in bytes, not frames to make the protocol generic and consistent) 3. New request for playback/capture control (XENSND_OP_TRIGGER) with start/pause/stop/resume sub-ops 4. Playback/capture buffer size is set on the backend side via XENSND_FIELD_BUFFER_SIZE XenStore entry
Waiting for your valuable comments,
Thank you, Oleksandr
[1] https://github.com/andr2000/linux/commits/snd_upstream_v1 [2] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/incl... [3] https://github.com/xen-troops/snd_be [4] https://github.com/xen-troops/libxenbe [5] https://lkml.org/lkml/2017/8/7/363 [6] http://mailman.alsa-project.org/pipermail/alsa-devel/2017-August/123617.html [7] http://mailman.alsa-project.org/pipermail/alsa-devel/2017-August/123744.html
Oleksandr Andrushchenko (2): sndif: introduce protocol version sndif: add explicit back and front synchronization
xen/include/public/io/sndif.h | 173 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 170 insertions(+), 3 deletions(-)
From: Oleksandr Andrushchenko oleksandr_andrushchenko@epam.com
Protocol version was referenced in the protocol description, but missed its definition. Fix this by adding a constant for current protocol version.
Signed-off-by: Oleksandr Andrushchenko oleksandr_andrushchenko@epam.com --- xen/include/public/io/sndif.h | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/xen/include/public/io/sndif.h b/xen/include/public/io/sndif.h index c5c1978406b3..b0e6ac35e131 100644 --- a/xen/include/public/io/sndif.h +++ b/xen/include/public/io/sndif.h @@ -38,6 +38,13 @@
/* ****************************************************************************** + * Protocol version + ****************************************************************************** + */ +#define XENSND_PROTOCOL_VERSION "1" + +/* + ****************************************************************************** * Feature and Parameter Negotiation ****************************************************************************** *
On Mon, Feb 05, 2018 at 10:24:59AM +0200, Oleksandr Andrushchenko wrote:
From: Oleksandr Andrushchenko oleksandr_andrushchenko@epam.com
Protocol version was referenced in the protocol description, but missed its definition. Fix this by adding a constant for current protocol version.
Signed-off-by: Oleksandr Andrushchenko oleksandr_andrushchenko@epam.com
Reviewed-by: Konrad Rzeszutek Wilk konrad.wilk@oracle.com
Thank you!
xen/include/public/io/sndif.h | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/xen/include/public/io/sndif.h b/xen/include/public/io/sndif.h index c5c1978406b3..b0e6ac35e131 100644 --- a/xen/include/public/io/sndif.h +++ b/xen/include/public/io/sndif.h @@ -38,6 +38,13 @@
/*
Protocol version
- */
+#define XENSND_PROTOCOL_VERSION "1"
+/*
Feature and Parameter Negotiation
-- 2.7.4
Xen-devel mailing list Xen-devel@lists.xenproject.org https://lists.xenproject.org/mailman/listinfo/xen-devel
From: Oleksandr Andrushchenko oleksandr_andrushchenko@epam.com
In order to provide explicit synchronization between backend and frontend the following changes are introduced in the protocol: - add new ring buffer for sending asynchronous events from backend to frontend to report number of bytes played/captured (XENSND_EVT_CUR_POS) - introduce trigger events for playback control: start/stop/pause/resume - bump protocol version to 2
Signed-off-by: Oleksandr Andrushchenko oleksandr_andrushchenko@epam.com Signed-off-by: Oleksandr Grytsov oleksandr_grytsov@epam.com Cc: Konrad Rzeszutek Wilk konrad.wilk@oracle.com Cc: Takashi Iwai tiwai@suse.de Cc: Takashi Sakamoto o-takashi@sakamocchi.jp Cc: Clemens Ladisch clemens@ladisch.de --- xen/include/public/io/sndif.h | 168 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 164 insertions(+), 4 deletions(-)
diff --git a/xen/include/public/io/sndif.h b/xen/include/public/io/sndif.h index b0e6ac35e131..b4d6c96b40b4 100644 --- a/xen/include/public/io/sndif.h +++ b/xen/include/public/io/sndif.h @@ -41,7 +41,7 @@ * Protocol version ****************************************************************************** */ -#define XENSND_PROTOCOL_VERSION "1" +#define XENSND_PROTOCOL_VERSION "2"
/* ****************************************************************************** @@ -113,6 +113,8 @@ * * /local/domain/1/device/vsnd/0/0/0/ring-ref = "386" * /local/domain/1/device/vsnd/0/0/0/event-channel = "15" + * /local/domain/1/device/vsnd/0/0/0/evt-ring-ref = "1386" + * /local/domain/1/device/vsnd/0/0/0/evt-event-channel = "215" * *------------------------------ Stream 1, capture ---------------------------- * @@ -122,6 +124,8 @@ * * /local/domain/1/device/vsnd/0/0/1/ring-ref = "384" * /local/domain/1/device/vsnd/0/0/1/event-channel = "13" + * /local/domain/1/device/vsnd/0/0/1/evt-ring-ref = "1384" + * /local/domain/1/device/vsnd/0/0/1/evt-event-channel = "213" * *------------------------------- PCM device 1 -------------------------------- * @@ -135,6 +139,8 @@ * * /local/domain/1/device/vsnd/0/1/0/ring-ref = "387" * /local/domain/1/device/vsnd/0/1/0/event-channel = "151" + * /local/domain/1/device/vsnd/0/1/0/evt-ring-ref = "1387" + * /local/domain/1/device/vsnd/0/1/0/evt-event-channel = "351" * *------------------------------- PCM device 2 -------------------------------- * @@ -147,6 +153,8 @@ * * /local/domain/1/device/vsnd/0/2/0/ring-ref = "389" * /local/domain/1/device/vsnd/0/2/0/event-channel = "152" + * /local/domain/1/device/vsnd/0/2/0/evt-ring-ref = "1389" + * /local/domain/1/device/vsnd/0/2/0/evt-event-channel = "452" * ****************************************************************************** * Backend XenBus Nodes @@ -292,6 +300,23 @@ * The Xen grant reference granting permission for the backend to map * a sole page in a single page sized ring buffer. * + *--------------------- Stream Event Transport Parameters --------------------- + * + * This communication path is used to deliver asynchronous events from backend + * to frontend, set up per stream. + * + * evt-event-channel + * Values: <uint32_t> + * + * The identifier of the Xen event channel used to signal activity + * in the ring buffer. + * + * evt-ring-ref + * Values: <uint32_t> + * + * The Xen grant reference granting permission for the backend to map + * a sole page in a single page sized ring buffer. + * ****************************************************************************** * STATE DIAGRAMS ****************************************************************************** @@ -439,6 +464,19 @@ #define XENSND_OP_GET_VOLUME 5 #define XENSND_OP_MUTE 6 #define XENSND_OP_UNMUTE 7 +#define XENSND_OP_TRIGGER 8 + +#define XENSND_OP_TRIGGER_START 0 +#define XENSND_OP_TRIGGER_PAUSE 1 +#define XENSND_OP_TRIGGER_STOP 2 +#define XENSND_OP_TRIGGER_RESUME 3 + +/* + ****************************************************************************** + * EVENT CODES + ****************************************************************************** + */ +#define XENSND_EVT_CUR_POS 0
/* ****************************************************************************** @@ -455,6 +493,8 @@ #define XENSND_FIELD_VCARD_LONG_NAME "long-name" #define XENSND_FIELD_RING_REF "ring-ref" #define XENSND_FIELD_EVT_CHNL "event-channel" +#define XENSND_FIELD_EVT_RING_REF "evt-ring-ref" +#define XENSND_FIELD_EVT_EVT_CHNL "evt-event-channel" #define XENSND_FIELD_DEVICE_NAME "name" #define XENSND_FIELD_TYPE "type" #define XENSND_FIELD_STREAM_UNIQUE_ID "unique-id" @@ -566,9 +606,7 @@ * +----------------+----------------+----------------+----------------+ * | gref_directory | 24 * +----------------+----------------+----------------+----------------+ - * | reserved | 28 - * +----------------+----------------+----------------+----------------+ - * |//////////////////////////////////| + * | period_sz | 28 * +----------------+----------------+----------------+----------------+ * | reserved | 32 * +----------------+----------------+----------------+----------------+ @@ -578,6 +616,14 @@ * pcm_channels - uint8_t, number of channels of this stream, * [channels-min; channels-max] * buffer_sz - uint32_t, buffer size to be allocated, octets + * period_sz - uint32_t, recommended event period size, octets + * This is the recommended (hint) value of the period at which frontend would + * like to receive XENSND_EVT_CUR_POS notifications from the backend when + * stream position advances during playback/capture. + * It shows how many octets are expected to be played/captured before + * sending such an event. + * If set to 0 no XENSND_EVT_CUR_POS events are sent by the backend. + * * gref_directory - grant_ref_t, a reference to the first shared page * describing shared buffer references. At least one page exists. If shared * buffer size (buffer_sz) exceeds what can be addressed by this single page, @@ -592,6 +638,7 @@ struct xensnd_open_req { uint16_t reserved; uint32_t buffer_sz; grant_ref_t gref_directory; + uint32_t period_sz; };
/* @@ -750,8 +797,36 @@ struct xensnd_rw_req { * * The 'struct xensnd_rw_req' is also used for XENSND_OP_SET_VOLUME, * XENSND_OP_GET_VOLUME, XENSND_OP_MUTE, XENSND_OP_UNMUTE. + * + * Request stream running state change - trigger PCM stream running state + * to start, stop, pause or resume: + * + * 0 1 2 3 octet + * +----------------+----------------+----------------+----------------+ + * | id | _OP_TRIGGER | reserved | 4 + * +----------------+----------------+----------------+----------------+ + * | reserved | 8 + * +----------------+----------------+----------------+----------------+ + * | type | 12 + * +----------------+----------------+----------------+----------------+ + * | reserved | 16 + * +----------------+----------------+----------------+----------------+ + * | reserved | 20 + * +----------------+----------------+----------------+----------------+ + * | reserved | 24 + * +----------------+----------------+----------------+----------------+ + * | reserved | 28 + * +----------------+----------------+----------------+----------------+ + * | reserved | 32 + * +----------------+----------------+----------------+----------------+ + * + * type - uint8_t, XENSND_OP_TRIGGER_XXX value */
+struct xensnd_trigger_req { + uint8_t type; +}; + /* *---------------------------------- Responses -------------------------------- * @@ -774,8 +849,51 @@ struct xensnd_rw_req { * id - uint16_t, copied from the request * operation - uint8_t, XENSND_OP_* - copied from request * status - int32_t, response status, zero on success and -XEN_EXX on failure + * + *----------------------------------- Events ---------------------------------- + * + * Events are sent via a shared page allocated by the front and propagated by + * evt-event-channel/evt-ring-ref XenStore entries + * All event packets have the same length (32 octets) + * All event packets have common header: + * 0 1 2 3 octet + * +----------------+----------------+----------------+----------------+ + * | id | type | reserved | 4 + * +----------------+----------------+----------------+----------------+ + * | reserved | 8 + * +----------------+----------------+----------------+----------------+ + * + * id - uint16_t, event id, may be used by front + * type - uint8_t, type of the event + * + * + * Current stream position - event from back to front when stream's + * playback/capture position has advanced: + * 0 1 2 3 octet + * +----------------+----------------+----------------+----------------+ + * | id | _EVT_CUR_POS | reserved | 4 + * +----------------+----------------+----------------+----------------+ + * | reserved | 8 + * +----------------+----------------+----------------+----------------+ + * | position low 32-bit | 12 + * +----------------+----------------+----------------+----------------+ + * | position high 32-bit | 16 + * +----------------+----------------+----------------+----------------+ + * | reserved | 20 + * +----------------+----------------+----------------+----------------+ + * |//////////////////////////////////| + * +----------------+----------------+----------------+----------------+ + * | reserved | 32 + * +----------------+----------------+----------------+----------------+ + * + * position - current value of stream's playback/capture position, octets + * */
+struct xensnd_cur_pos_evt { + uint64_t position; +}; + struct xensnd_req { uint16_t id; uint8_t operation; @@ -783,6 +901,7 @@ struct xensnd_req { union { struct xensnd_open_req open; struct xensnd_rw_req rw; + struct xensnd_trigger_req trigger; uint8_t reserved[24]; } op; }; @@ -795,8 +914,49 @@ struct xensnd_resp { uint8_t reserved1[24]; };
+struct xensnd_evt { + uint16_t id; + uint8_t type; + uint8_t reserved[5]; + union { + struct xensnd_cur_pos_evt cur_pos; + uint8_t reserved[24]; + } op; +}; + DEFINE_RING_TYPES(xen_sndif, struct xensnd_req, struct xensnd_resp);
+/* + ****************************************************************************** + * Back to front events delivery + ****************************************************************************** + * In order to deliver asynchronous events from back to front a shared page is + * allocated by front and its granted reference propagated to back via + * XenStore entries (evt-ring-ref/evt-event-channel). + * This page has a common header used by both front and back to synchronize + * access and control event's ring buffer, while back being a producer of the + * events and front being a consumer. The rest of the page after the header + * is used for event packets. + * + * Upon reception of an event(s) front may confirm its reception + * for either each event, group of events or none. + */ + +struct xensnd_event_page { + uint32_t in_cons; + uint32_t in_prod; + uint8_t reserved[24]; +}; + +#define XENSND_EVENT_PAGE_SIZE 4096 +#define XENSND_IN_RING_OFFS (sizeof(struct xensnd_event_page)) +#define XENSND_IN_RING_SIZE (XENSND_EVENT_PAGE_SIZE - XENSND_IN_RING_OFFS) +#define XENSND_IN_RING_LEN (XENSND_IN_RING_SIZE / sizeof(struct xensnd_evt)) +#define XENSND_IN_RING(page) \ + ((struct xensnd_evt *)((char *)(page) + XENSND_IN_RING_OFFS)) +#define XENSND_IN_RING_REF(page, idx) \ + (XENSND_IN_RING((page))[(idx) % XENSND_IN_RING_LEN]) + #endif /* __XEN_PUBLIC_IO_SNDIF_H__ */
/*
- +----------------+----------------+----------------+----------------+
- | gref_directory | 24
- +----------------+----------------+----------------+----------------+
- | reserved | 28
- +----------------+----------------+----------------+----------------+
- |//////////////////////////////////|
- | period_sz | 28
- +----------------+----------------+----------------+----------------+
- | reserved | 32
- +----------------+----------------+----------------+----------------+
@@ -578,6 +616,14 @@
- pcm_channels - uint8_t, number of channels of this stream,
- [channels-min; channels-max]
- buffer_sz - uint32_t, buffer size to be allocated, octets
- period_sz - uint32_t, recommended event period size, octets
- This is the recommended (hint) value of the period at which frontend would
- like to receive XENSND_EVT_CUR_POS notifications from the backend when
- stream position advances during playback/capture.
- It shows how many octets are expected to be played/captured before
- sending such an event.
- If set to 0 no XENSND_EVT_CUR_POS events are sent by the backend.
I would gate this based on the version. That is if version 0 then this field does not exist.
- gref_directory - grant_ref_t, a reference to the first shared page
- describing shared buffer references. At least one page exists. If shared
- buffer size (buffer_sz) exceeds what can be addressed by this single page,
@@ -592,6 +638,7 @@ struct xensnd_open_req { uint16_t reserved; uint32_t buffer_sz; grant_ref_t gref_directory;
- uint32_t period_sz;
The same here. Just put a comment mentioning the version part.
On 03/02/2018 12:11 AM, Konrad Rzeszutek Wilk wrote:
- +----------------+----------------+----------------+----------------+
- | gref_directory | 24
- +----------------+----------------+----------------+----------------+
- | reserved | 28
- +----------------+----------------+----------------+----------------+
- |//////////////////////////////////|
- | period_sz | 28
- +----------------+----------------+----------------+----------------+
- | reserved | 32
- +----------------+----------------+----------------+----------------+
@@ -578,6 +616,14 @@
- pcm_channels - uint8_t, number of channels of this stream,
- [channels-min; channels-max]
- buffer_sz - uint32_t, buffer size to be allocated, octets
- period_sz - uint32_t, recommended event period size, octets
- This is the recommended (hint) value of the period at which frontend would
- like to receive XENSND_EVT_CUR_POS notifications from the backend when
- stream position advances during playback/capture.
- It shows how many octets are expected to be played/captured before
- sending such an event.
- If set to 0 no XENSND_EVT_CUR_POS events are sent by the backend.
I would gate this based on the version. That is if version 0 then this field does not exist.
Well, by default we have all unused fields set to 0: [1] And for version 1 (or 0, initial) of the protocol it means that period_sz falls into reserved region [2]. With the comment above for version 2 it means that old behavior is in use, e.g. no XENSND_EVT_CUR_POS events are sent by the backend, so we are backward compatible in this case
- gref_directory - grant_ref_t, a reference to the first shared page
- describing shared buffer references. At least one page exists. If shared
- buffer size (buffer_sz) exceeds what can be addressed by this single page,
@@ -592,6 +638,7 @@ struct xensnd_open_req { uint16_t reserved; uint32_t buffer_sz; grant_ref_t gref_directory;
- uint32_t period_sz;
The same here. Just put a comment mentioning the version part.
So, if you still want to gate it, how would you like it? XENSND_PROTOCOL_VERSION was defined as a string "1"/"2" and preprocessor won't allow comparing strings, e.g. you can't do #if XENSND_PROTOCOL_VERSION == "1" So, we might want re-defining XENSND_PROTOCOL_VERSION as an integer in the first patch, so it can be used here. Then, if it is an integer: 1. #if XENSND_PROTOCOL_VERSION != 1 uint32_t period_sz; #endif 2. #if XENSND_PROTOCOL_VERSION > 1 uint32_t period_sz; #endif 3. #if XENSND_PROTOCOL_VERSION == 2 uint32_t period_sz; #endif
Please let me know whether we still want gating and if so in which way.
Thank you, Oleksandr [1] https://elixir.bootlin.com/linux/v4.16-rc3/source/include/xen/interface/io/s... [2] https://elixir.bootlin.com/linux/v4.16-rc3/source/include/xen/interface/io/s...
ping
On 02/05/2018 10:24 AM, Oleksandr Andrushchenko wrote:
From: Oleksandr Andrushchenko oleksandr_andrushchenko@epam.com
Hi, all!
Foreword
This change is aimed to add support for explicit back and front synchronization during playback and capture in response to comments raised during upstream attempt of the para-virtualized sound frontend driver for Xen [1], [2] and gather opinions from the relevant communities (ALSA, Xen) on the change.
The relevant backend is implemented as a user-space application [3] and uses accompanying helper library [4].
Both frontend driver and backend were tested on real HW running Xen hypervisor (Renesas R-Car ARM based H3/M3 boards, x86) to make sure the proposed solution does work.
Rationale
During the first attempt to upstream the Linux front driver [5] number of comments and concerns were raised, one of the biggest flaws in the design were questioned by both Clemens Ladisch [6] and Takashi Sakamoto [7]: the absence of synchronization between frontend and backend during capture/playback. Two options were discussed:
“In design of ALSA PCM core, drivers are expected to synchronize to actual hardwares for semi-realtime data transmission. The synchronization is done by two points:
- Interrupts to respond events from actual hardwares.
- Positions of actual data transmission in any serial sound interfaces of actual hardwares.
“
and finally a change to the existing protocol was suggested:
“In 'include/xen/interface/io/sndif.h', there's no functionalities I described the above:
- notifications from DomU to Dom0 about the size of period for interrupts from actual hardwares. Or no way from Dom0 to DomU about the configured size of the period.
- notifications of the interrupts from actual hardwares to DomU.”
This is implemented as a change to the sndif protocol and allows removing period emulation:
- Introduced a new event channel from back to front
- New event with number of bytes played/captured (XENSND_EVT_CUR_POS, to be used for sending snd_pcm_period_elapsed at frontend (in Linux implementation). Sent in bytes, not frames to make the protocol generic and consistent)
- New request for playback/capture control (XENSND_OP_TRIGGER) with start/pause/stop/resume sub-ops
- Playback/capture buffer size is set on the backend side via XENSND_FIELD_BUFFER_SIZE XenStore entry
Waiting for your valuable comments,
Thank you, Oleksandr
[1] https://github.com/andr2000/linux/commits/snd_upstream_v1 [2] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/incl... [3] https://github.com/xen-troops/snd_be [4] https://github.com/xen-troops/libxenbe [5] https://lkml.org/lkml/2017/8/7/363 [6] http://mailman.alsa-project.org/pipermail/alsa-devel/2017-August/123617.html [7] http://mailman.alsa-project.org/pipermail/alsa-devel/2017-August/123744.html
Oleksandr Andrushchenko (2): sndif: introduce protocol version sndif: add explicit back and front synchronization
xen/include/public/io/sndif.h | 173 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 170 insertions(+), 3 deletions(-)
Hello, Konrad, Takashi, Takashi and Clemens!
Could you please take a look at this series if it meets ALSA expectations on para-virtualized sound for Xen?
Thank you, Oleksandr
On 02/05/2018 10:24 AM, Oleksandr Andrushchenko wrote:
From: Oleksandr Andrushchenko oleksandr_andrushchenko@epam.com
Hi, all!
Foreword
This change is aimed to add support for explicit back and front synchronization during playback and capture in response to comments raised during upstream attempt of the para-virtualized sound frontend driver for Xen [1], [2] and gather opinions from the relevant communities (ALSA, Xen) on the change.
The relevant backend is implemented as a user-space application [3] and uses accompanying helper library [4].
Both frontend driver and backend were tested on real HW running Xen hypervisor (Renesas R-Car ARM based H3/M3 boards, x86) to make sure the proposed solution does work.
Rationale
During the first attempt to upstream the Linux front driver [5] number of comments and concerns were raised, one of the biggest flaws in the design were questioned by both Clemens Ladisch [6] and Takashi Sakamoto [7]: the absence of synchronization between frontend and backend during capture/playback. Two options were discussed:
“In design of ALSA PCM core, drivers are expected to synchronize to actual hardwares for semi-realtime data transmission. The synchronization is done by two points:
- Interrupts to respond events from actual hardwares.
- Positions of actual data transmission in any serial sound interfaces of actual hardwares.
“
and finally a change to the existing protocol was suggested:
“In 'include/xen/interface/io/sndif.h', there's no functionalities I described the above:
- notifications from DomU to Dom0 about the size of period for interrupts from actual hardwares. Or no way from Dom0 to DomU about the configured size of the period.
- notifications of the interrupts from actual hardwares to DomU.”
This is implemented as a change to the sndif protocol and allows removing period emulation:
- Introduced a new event channel from back to front
- New event with number of bytes played/captured (XENSND_EVT_CUR_POS, to be used for sending snd_pcm_period_elapsed at frontend (in Linux implementation). Sent in bytes, not frames to make the protocol generic and consistent)
- New request for playback/capture control (XENSND_OP_TRIGGER) with start/pause/stop/resume sub-ops
- Playback/capture buffer size is set on the backend side via XENSND_FIELD_BUFFER_SIZE XenStore entry
Waiting for your valuable comments,
Thank you, Oleksandr
[1] https://github.com/andr2000/linux/commits/snd_upstream_v1 [2] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/incl... [3] https://github.com/xen-troops/snd_be [4] https://github.com/xen-troops/libxenbe [5] https://lkml.org/lkml/2017/8/7/363 [6] http://mailman.alsa-project.org/pipermail/alsa-devel/2017-August/123617.html [7] http://mailman.alsa-project.org/pipermail/alsa-devel/2017-August/123744.html
Oleksandr Andrushchenko (2): sndif: introduce protocol version sndif: add explicit back and front synchronization
xen/include/public/io/sndif.h | 173 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 170 insertions(+), 3 deletions(-)
Any chance ALSA community may also review the below?
BTW, the driver, with the changes proposed, is at [1]
Thank you,
Oleksandr
On 02/05/2018 10:24 AM, Oleksandr Andrushchenko wrote:
From: Oleksandr Andrushchenko oleksandr_andrushchenko@epam.com
Hi, all!
Foreword
This change is aimed to add support for explicit back and front synchronization during playback and capture in response to comments raised during upstream attempt of the para-virtualized sound frontend driver for Xen [1], [2] and gather opinions from the relevant communities (ALSA, Xen) on the change.
The relevant backend is implemented as a user-space application [3] and uses accompanying helper library [4].
Both frontend driver and backend were tested on real HW running Xen hypervisor (Renesas R-Car ARM based H3/M3 boards, x86) to make sure the proposed solution does work.
Rationale
During the first attempt to upstream the Linux front driver [5] number of comments and concerns were raised, one of the biggest flaws in the design were questioned by both Clemens Ladisch [6] and Takashi Sakamoto [7]: the absence of synchronization between frontend and backend during capture/playback. Two options were discussed:
“In design of ALSA PCM core, drivers are expected to synchronize to actual hardwares for semi-realtime data transmission. The synchronization is done by two points:
- Interrupts to respond events from actual hardwares.
- Positions of actual data transmission in any serial sound interfaces of actual hardwares.
“
and finally a change to the existing protocol was suggested:
“In 'include/xen/interface/io/sndif.h', there's no functionalities I described the above:
- notifications from DomU to Dom0 about the size of period for interrupts from actual hardwares. Or no way from Dom0 to DomU about the configured size of the period.
- notifications of the interrupts from actual hardwares to DomU.”
This is implemented as a change to the sndif protocol and allows removing period emulation:
- Introduced a new event channel from back to front
- New event with number of bytes played/captured (XENSND_EVT_CUR_POS, to be used for sending snd_pcm_period_elapsed at frontend (in Linux implementation). Sent in bytes, not frames to make the protocol generic and consistent)
- New request for playback/capture control (XENSND_OP_TRIGGER) with start/pause/stop/resume sub-ops
- Playback/capture buffer size is set on the backend side via XENSND_FIELD_BUFFER_SIZE XenStore entry
Waiting for your valuable comments,
Thank you, Oleksandr
[1] https://github.com/andr2000/linux/commits/snd_upstream_v1 [2] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/incl... [3] https://github.com/xen-troops/snd_be [4] https://github.com/xen-troops/libxenbe [5] https://lkml.org/lkml/2017/8/7/363 [6] http://mailman.alsa-project.org/pipermail/alsa-devel/2017-August/123617.html [7] http://mailman.alsa-project.org/pipermail/alsa-devel/2017-August/123744.html
Oleksandr Andrushchenko (2): sndif: introduce protocol version sndif: add explicit back and front synchronization
xen/include/public/io/sndif.h | 173 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 170 insertions(+), 3 deletions(-)
[1] https://github.com/andr2000/linux/commits/tiwai_sound_for_next_pv_snd_upstre...
On Mon, 05 Feb 2018 09:24:58 +0100, Oleksandr Andrushchenko wrote:
From: Oleksandr Andrushchenko oleksandr_andrushchenko@epam.com
Hi, all!
Foreword
This change is aimed to add support for explicit back and front synchronization during playback and capture in response to comments raised during upstream attempt of the para-virtualized sound frontend driver for Xen [1], [2] and gather opinions from the relevant communities (ALSA, Xen) on the change.
The relevant backend is implemented as a user-space application [3] and uses accompanying helper library [4].
Both frontend driver and backend were tested on real HW running Xen hypervisor (Renesas R-Car ARM based H3/M3 boards, x86) to make sure the proposed solution does work.
Rationale
During the first attempt to upstream the Linux front driver [5] number of comments and concerns were raised, one of the biggest flaws in the design were questioned by both Clemens Ladisch [6] and Takashi Sakamoto [7]: the absence of synchronization between frontend and backend during capture/playback. Two options were discussed:
“In design of ALSA PCM core, drivers are expected to synchronize to actual hardwares for semi-realtime data transmission. The synchronization is done by two points:
- Interrupts to respond events from actual hardwares.
- Positions of actual data transmission in any serial sound interfaces of actual hardwares.
“
and finally a change to the existing protocol was suggested:
“In 'include/xen/interface/io/sndif.h', there's no functionalities I described the above:
- notifications from DomU to Dom0 about the size of period for interrupts from actual hardwares. Or no way from Dom0 to DomU about the configured size of the period.
- notifications of the interrupts from actual hardwares to DomU.”
This is implemented as a change to the sndif protocol and allows removing period emulation:
- Introduced a new event channel from back to front
- New event with number of bytes played/captured (XENSND_EVT_CUR_POS, to be used for sending snd_pcm_period_elapsed at frontend (in Linux implementation). Sent in bytes, not frames to make the protocol generic and consistent)
- New request for playback/capture control (XENSND_OP_TRIGGER) with start/pause/stop/resume sub-ops
- Playback/capture buffer size is set on the backend side via XENSND_FIELD_BUFFER_SIZE XenStore entry
So the new addition looks serving well for the point that was suggested in the previous thread. As I see no frontend driver implementation, it's hard to tell about the details, but through a quick glance, the protocol should be OK.
Now, going back to a big picture: I took a look at the previous patchset, and wonder what about the hw_params setup. Basically the (frontend) application may request any size of buffer and periods unless the driver sets up the hw constraints at open callback. That is, app may request even the 16 bytes of buffer size, or 1GB of buffer. The periods aren't always integer, so it can be 1024 bytes of buffer with 400 bytes of periods.
And, if such parameters are set up freely in the frontend side, how the backend is supposed to behave? From the frontend POV, it expects receiving the wakeup/notification at each period processing (e.g. 400 bytes in the case above). But, the backend is another application, so how would it work for such requirements? Am I missing something here?
thanks,
Takashi
Waiting for your valuable comments,
Thank you, Oleksandr
[1] https://github.com/andr2000/linux/commits/snd_upstream_v1 [2] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/incl... [3] https://github.com/xen-troops/snd_be [4] https://github.com/xen-troops/libxenbe [5] https://lkml.org/lkml/2017/8/7/363 [6] http://mailman.alsa-project.org/pipermail/alsa-devel/2017-August/123617.html [7] http://mailman.alsa-project.org/pipermail/alsa-devel/2017-August/123744.html
Oleksandr Andrushchenko (2): sndif: introduce protocol version sndif: add explicit back and front synchronization
xen/include/public/io/sndif.h | 173 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 170 insertions(+), 3 deletions(-)
-- 2.7.4
Alsa-devel mailing list Alsa-devel@alsa-project.org http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
On 03/06/2018 12:52 PM, Takashi Iwai wrote:
On Mon, 05 Feb 2018 09:24:58 +0100, Oleksandr Andrushchenko wrote:
From: Oleksandr Andrushchenko oleksandr_andrushchenko@epam.com
Hi, all!
Foreword
This change is aimed to add support for explicit back and front synchronization during playback and capture in response to comments raised during upstream attempt of the para-virtualized sound frontend driver for Xen [1], [2] and gather opinions from the relevant communities (ALSA, Xen) on the change.
The relevant backend is implemented as a user-space application [3] and uses accompanying helper library [4].
Both frontend driver and backend were tested on real HW running Xen hypervisor (Renesas R-Car ARM based H3/M3 boards, x86) to make sure the proposed solution does work.
Rationale
During the first attempt to upstream the Linux front driver [5] number of comments and concerns were raised, one of the biggest flaws in the design were questioned by both Clemens Ladisch [6] and Takashi Sakamoto [7]: the absence of synchronization between frontend and backend during capture/playback. Two options were discussed:
“In design of ALSA PCM core, drivers are expected to synchronize to actual hardwares for semi-realtime data transmission. The synchronization is done by two points:
- Interrupts to respond events from actual hardwares.
- Positions of actual data transmission in any serial sound interfaces of actual hardwares.
“
and finally a change to the existing protocol was suggested:
“In 'include/xen/interface/io/sndif.h', there's no functionalities I described the above:
- notifications from DomU to Dom0 about the size of period for interrupts from actual hardwares. Or no way from Dom0 to DomU about the configured size of the period.
- notifications of the interrupts from actual hardwares to DomU.”
This is implemented as a change to the sndif protocol and allows removing period emulation:
- Introduced a new event channel from back to front
- New event with number of bytes played/captured (XENSND_EVT_CUR_POS, to be used for sending snd_pcm_period_elapsed at frontend (in Linux implementation). Sent in bytes, not frames to make the protocol generic and consistent)
- New request for playback/capture control (XENSND_OP_TRIGGER) with start/pause/stop/resume sub-ops
- Playback/capture buffer size is set on the backend side via XENSND_FIELD_BUFFER_SIZE XenStore entry
So the new addition looks serving well for the point that was suggested in the previous thread. As I see no frontend driver implementation, it's hard to tell about the details, but through a quick glance, the protocol should be OK.
Thank you, the driver is at [1]
Now, going back to a big picture: I took a look at the previous patchset, and wonder what about the hw_params setup. Basically the (frontend) application may request any size of buffer and periods unless the driver sets up the hw constraints at open callback. That is, app may request even the 16 bytes of buffer size, or 1GB of buffer. The periods aren't always integer, so it can be 1024 bytes of buffer with 400 bytes of periods.
And, if such parameters are set up freely in the frontend side, how the backend is supposed to behave? From the frontend POV, it expects receiving the wakeup/notification at each period processing (e.g. 400 bytes in the case above). But, the backend is another application, so how would it work for such requirements? Am I missing something here?
Well, the frontend is not that free to decide as it might look like, e.g. please see [2]. Basically part of hw_params configuration is written to XenStore [3] as a part of domain configuration which depends on system/backend capabilities. E.g., we usually set buffer sizes to match real HW at backend side if we use ALSA and we have more freedom if we use PulseAudio there. Finally, if backend decides that the requested buffer/period sizes are not acceptable it will reject such a configuration.
thanks,
Takashi
Waiting for your valuable comments,
Thank you, Oleksandr
[1] https://github.com/andr2000/linux/commits/snd_upstream_v1 [2] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/incl... [3] https://github.com/xen-troops/snd_be [4] https://github.com/xen-troops/libxenbe [5] https://lkml.org/lkml/2017/8/7/363 [6] http://mailman.alsa-project.org/pipermail/alsa-devel/2017-August/123617.html [7] http://mailman.alsa-project.org/pipermail/alsa-devel/2017-August/123744.html
Oleksandr Andrushchenko (2): sndif: introduce protocol version sndif: add explicit back and front synchronization
xen/include/public/io/sndif.h | 173 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 170 insertions(+), 3 deletions(-)
-- 2.7.4
Alsa-devel mailing list Alsa-devel@alsa-project.org http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
[1] https://github.com/andr2000/linux/commits/tiwai_sound_for_next_pv_snd_upstre... [2] https://github.com/andr2000/linux/blob/tiwai_sound_for_next_pv_snd_upstream_... [3] https://www.mail-archive.com/xen-devel@lists.xen.org/msg124356.html
On Tue, 06 Mar 2018 12:25:07 +0100, Oleksandr Andrushchenko wrote:
On 03/06/2018 12:52 PM, Takashi Iwai wrote:
On Mon, 05 Feb 2018 09:24:58 +0100, Oleksandr Andrushchenko wrote:
From: Oleksandr Andrushchenko oleksandr_andrushchenko@epam.com
Hi, all!
Foreword
This change is aimed to add support for explicit back and front synchronization during playback and capture in response to comments raised during upstream attempt of the para-virtualized sound frontend driver for Xen [1], [2] and gather opinions from the relevant communities (ALSA, Xen) on the change.
The relevant backend is implemented as a user-space application [3] and uses accompanying helper library [4].
Both frontend driver and backend were tested on real HW running Xen hypervisor (Renesas R-Car ARM based H3/M3 boards, x86) to make sure the proposed solution does work.
Rationale
During the first attempt to upstream the Linux front driver [5] number of comments and concerns were raised, one of the biggest flaws in the design were questioned by both Clemens Ladisch [6] and Takashi Sakamoto [7]: the absence of synchronization between frontend and backend during capture/playback. Two options were discussed:
“In design of ALSA PCM core, drivers are expected to synchronize to actual hardwares for semi-realtime data transmission. The synchronization is done by two points:
- Interrupts to respond events from actual hardwares.
- Positions of actual data transmission in any serial sound interfaces of actual hardwares.
“
and finally a change to the existing protocol was suggested:
“In 'include/xen/interface/io/sndif.h', there's no functionalities I described the above:
- notifications from DomU to Dom0 about the size of period for interrupts from actual hardwares. Or no way from Dom0 to DomU about the configured size of the period.
- notifications of the interrupts from actual hardwares to DomU.”
This is implemented as a change to the sndif protocol and allows removing period emulation:
- Introduced a new event channel from back to front
- New event with number of bytes played/captured (XENSND_EVT_CUR_POS, to be used for sending snd_pcm_period_elapsed at frontend (in Linux implementation). Sent in bytes, not frames to make the protocol generic and consistent)
- New request for playback/capture control (XENSND_OP_TRIGGER) with start/pause/stop/resume sub-ops
- Playback/capture buffer size is set on the backend side via XENSND_FIELD_BUFFER_SIZE XenStore entry
So the new addition looks serving well for the point that was suggested in the previous thread. As I see no frontend driver implementation, it's hard to tell about the details, but through a quick glance, the protocol should be OK.
Thank you, the driver is at [1]
Now, going back to a big picture: I took a look at the previous patchset, and wonder what about the hw_params setup. Basically the (frontend) application may request any size of buffer and periods unless the driver sets up the hw constraints at open callback. That is, app may request even the 16 bytes of buffer size, or 1GB of buffer. The periods aren't always integer, so it can be 1024 bytes of buffer with 400 bytes of periods.
And, if such parameters are set up freely in the frontend side, how the backend is supposed to behave? From the frontend POV, it expects receiving the wakeup/notification at each period processing (e.g. 400 bytes in the case above). But, the backend is another application, so how would it work for such requirements? Am I missing something here?
Well, the frontend is not that free to decide as it might look like, e.g. please see [2]. Basically part of hw_params configuration is written to XenStore [3] as a part of domain configuration which depends on system/backend capabilities. E.g., we usually set buffer sizes to match real HW at backend side if we use ALSA and we have more freedom if we use PulseAudio there. Finally, if backend decides that the requested buffer/period sizes are not acceptable it will reject such a configuration.
OK, that restricts minimally. So at least there is the restriction / communication about the buffer size. But it merely means the *maximum* buffer size is set. Application may request still any shorter value than that.
And, there are no restriction about period sizes (except for the periods_max, which is calculated from buffer_bytes_max). That is, application may request any size between them; and it expects the wake up by this value.
I think that's a still missing stone in the design.
thanks,
Takashi
thanks,
Takashi
Waiting for your valuable comments,
Thank you, Oleksandr
[1] https://github.com/andr2000/linux/commits/snd_upstream_v1 [2] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/incl... [3] https://github.com/xen-troops/snd_be [4] https://github.com/xen-troops/libxenbe [5] https://lkml.org/lkml/2017/8/7/363 [6] http://mailman.alsa-project.org/pipermail/alsa-devel/2017-August/123617.html [7] http://mailman.alsa-project.org/pipermail/alsa-devel/2017-August/123744.html
Oleksandr Andrushchenko (2): sndif: introduce protocol version sndif: add explicit back and front synchronization
xen/include/public/io/sndif.h | 173 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 170 insertions(+), 3 deletions(-)
-- 2.7.4
Alsa-devel mailing list Alsa-devel@alsa-project.org http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
[1] https://github.com/andr2000/linux/commits/tiwai_sound_for_next_pv_snd_upstre... [2] https://github.com/andr2000/linux/blob/tiwai_sound_for_next_pv_snd_upstream_... [3] https://www.mail-archive.com/xen-devel@lists.xen.org/msg124356.html
On 03/06/2018 01:32 PM, Takashi Iwai wrote:
On Tue, 06 Mar 2018 12:25:07 +0100, Oleksandr Andrushchenko wrote:
On 03/06/2018 12:52 PM, Takashi Iwai wrote:
On Mon, 05 Feb 2018 09:24:58 +0100, Oleksandr Andrushchenko wrote:
From: Oleksandr Andrushchenko oleksandr_andrushchenko@epam.com
Hi, all!
Foreword
This change is aimed to add support for explicit back and front synchronization during playback and capture in response to comments raised during upstream attempt of the para-virtualized sound frontend driver for Xen [1], [2] and gather opinions from the relevant communities (ALSA, Xen) on the change.
The relevant backend is implemented as a user-space application [3] and uses accompanying helper library [4].
Both frontend driver and backend were tested on real HW running Xen hypervisor (Renesas R-Car ARM based H3/M3 boards, x86) to make sure the proposed solution does work.
Rationale
During the first attempt to upstream the Linux front driver [5] number of comments and concerns were raised, one of the biggest flaws in the design were questioned by both Clemens Ladisch [6] and Takashi Sakamoto [7]: the absence of synchronization between frontend and backend during capture/playback. Two options were discussed:
“In design of ALSA PCM core, drivers are expected to synchronize to actual hardwares for semi-realtime data transmission. The synchronization is done by two points:
- Interrupts to respond events from actual hardwares.
- Positions of actual data transmission in any serial sound interfaces of actual hardwares.
“
and finally a change to the existing protocol was suggested:
“In 'include/xen/interface/io/sndif.h', there's no functionalities I described the above:
- notifications from DomU to Dom0 about the size of period for interrupts from actual hardwares. Or no way from Dom0 to DomU about the configured size of the period.
- notifications of the interrupts from actual hardwares to DomU.”
This is implemented as a change to the sndif protocol and allows removing period emulation:
- Introduced a new event channel from back to front
- New event with number of bytes played/captured (XENSND_EVT_CUR_POS, to be used for sending snd_pcm_period_elapsed at frontend (in Linux implementation). Sent in bytes, not frames to make the protocol generic and consistent)
- New request for playback/capture control (XENSND_OP_TRIGGER) with start/pause/stop/resume sub-ops
- Playback/capture buffer size is set on the backend side via XENSND_FIELD_BUFFER_SIZE XenStore entry
So the new addition looks serving well for the point that was suggested in the previous thread. As I see no frontend driver implementation, it's hard to tell about the details, but through a quick glance, the protocol should be OK.
Thank you, the driver is at [1]
Now, going back to a big picture: I took a look at the previous patchset, and wonder what about the hw_params setup. Basically the (frontend) application may request any size of buffer and periods unless the driver sets up the hw constraints at open callback. That is, app may request even the 16 bytes of buffer size, or 1GB of buffer. The periods aren't always integer, so it can be 1024 bytes of buffer with 400 bytes of periods.
And, if such parameters are set up freely in the frontend side, how the backend is supposed to behave? From the frontend POV, it expects receiving the wakeup/notification at each period processing (e.g. 400 bytes in the case above). But, the backend is another application, so how would it work for such requirements? Am I missing something here?
Well, the frontend is not that free to decide as it might look like, e.g. please see [2]. Basically part of hw_params configuration is written to XenStore [3] as a part of domain configuration which depends on system/backend capabilities. E.g., we usually set buffer sizes to match real HW at backend side if we use ALSA and we have more freedom if we use PulseAudio there. Finally, if backend decides that the requested buffer/period sizes are not acceptable it will reject such a configuration.
OK, that restricts minimally. So at least there is the restriction / communication about the buffer size. But it merely means the *maximum* buffer size is set. Application may request still any shorter value than that.
And, there are no restriction about period sizes (except for the periods_max, which is calculated from buffer_bytes_max). That is, application may request any size between them; and it expects the wake up by this value.
I think that's a still missing stone in the design.
Well, so what would a real HW driver do in that case? My understanding is that in this case SW can still request something that HW can't do and driver will reject such configurations. In my case, the role of that HW driver code which judges on if configuration is acceptable just runs on the backend side, e.g. frontend driver is just a proxy which talks to the backend to check if the backend can do what requested. And it is up to backend to decide.
Does that sound reasonable or you have something else on your mind?
thanks,
Takashi
Thank you, Oleksandr
thanks,
Takashi
Waiting for your valuable comments,
Thank you, Oleksandr
[1] https://github.com/andr2000/linux/commits/snd_upstream_v1 [2] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/incl... [3] https://github.com/xen-troops/snd_be [4] https://github.com/xen-troops/libxenbe [5] https://lkml.org/lkml/2017/8/7/363 [6] http://mailman.alsa-project.org/pipermail/alsa-devel/2017-August/123617.html [7] http://mailman.alsa-project.org/pipermail/alsa-devel/2017-August/123744.html
Oleksandr Andrushchenko (2): sndif: introduce protocol version sndif: add explicit back and front synchronization
xen/include/public/io/sndif.h | 173 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 170 insertions(+), 3 deletions(-)
-- 2.7.4
Alsa-devel mailing list Alsa-devel@alsa-project.org http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
[1] https://github.com/andr2000/linux/commits/tiwai_sound_for_next_pv_snd_upstre... [2] https://github.com/andr2000/linux/blob/tiwai_sound_for_next_pv_snd_upstream_... [3] https://www.mail-archive.com/xen-devel@lists.xen.org/msg124356.html
On Tue, 06 Mar 2018 13:05:16 +0100, Oleksandr Andrushchenko wrote:
On 03/06/2018 01:32 PM, Takashi Iwai wrote:
On Tue, 06 Mar 2018 12:25:07 +0100, Oleksandr Andrushchenko wrote:
On 03/06/2018 12:52 PM, Takashi Iwai wrote:
On Mon, 05 Feb 2018 09:24:58 +0100, Oleksandr Andrushchenko wrote:
From: Oleksandr Andrushchenko oleksandr_andrushchenko@epam.com
Hi, all!
Foreword
This change is aimed to add support for explicit back and front synchronization during playback and capture in response to comments raised during upstream attempt of the para-virtualized sound frontend driver for Xen [1], [2] and gather opinions from the relevant communities (ALSA, Xen) on the change.
The relevant backend is implemented as a user-space application [3] and uses accompanying helper library [4].
Both frontend driver and backend were tested on real HW running Xen hypervisor (Renesas R-Car ARM based H3/M3 boards, x86) to make sure the proposed solution does work.
Rationale
During the first attempt to upstream the Linux front driver [5] number of comments and concerns were raised, one of the biggest flaws in the design were questioned by both Clemens Ladisch [6] and Takashi Sakamoto [7]: the absence of synchronization between frontend and backend during capture/playback. Two options were discussed:
“In design of ALSA PCM core, drivers are expected to synchronize to actual hardwares for semi-realtime data transmission. The synchronization is done by two points:
- Interrupts to respond events from actual hardwares.
- Positions of actual data transmission in any serial sound interfaces of actual hardwares.
“
and finally a change to the existing protocol was suggested:
“In 'include/xen/interface/io/sndif.h', there's no functionalities I described the above:
- notifications from DomU to Dom0 about the size of period for interrupts from actual hardwares. Or no way from Dom0 to DomU about the configured size of the period.
- notifications of the interrupts from actual hardwares to DomU.”
This is implemented as a change to the sndif protocol and allows removing period emulation:
- Introduced a new event channel from back to front
- New event with number of bytes played/captured (XENSND_EVT_CUR_POS, to be used for sending snd_pcm_period_elapsed at frontend (in Linux implementation). Sent in bytes, not frames to make the protocol generic and consistent)
- New request for playback/capture control (XENSND_OP_TRIGGER) with start/pause/stop/resume sub-ops
- Playback/capture buffer size is set on the backend side via XENSND_FIELD_BUFFER_SIZE XenStore entry
So the new addition looks serving well for the point that was suggested in the previous thread. As I see no frontend driver implementation, it's hard to tell about the details, but through a quick glance, the protocol should be OK.
Thank you, the driver is at [1]
Now, going back to a big picture: I took a look at the previous patchset, and wonder what about the hw_params setup. Basically the (frontend) application may request any size of buffer and periods unless the driver sets up the hw constraints at open callback. That is, app may request even the 16 bytes of buffer size, or 1GB of buffer. The periods aren't always integer, so it can be 1024 bytes of buffer with 400 bytes of periods.
And, if such parameters are set up freely in the frontend side, how the backend is supposed to behave? From the frontend POV, it expects receiving the wakeup/notification at each period processing (e.g. 400 bytes in the case above). But, the backend is another application, so how would it work for such requirements? Am I missing something here?
Well, the frontend is not that free to decide as it might look like, e.g. please see [2]. Basically part of hw_params configuration is written to XenStore [3] as a part of domain configuration which depends on system/backend capabilities. E.g., we usually set buffer sizes to match real HW at backend side if we use ALSA and we have more freedom if we use PulseAudio there. Finally, if backend decides that the requested buffer/period sizes are not acceptable it will reject such a configuration.
OK, that restricts minimally. So at least there is the restriction / communication about the buffer size. But it merely means the *maximum* buffer size is set. Application may request still any shorter value than that.
And, there are no restriction about period sizes (except for the periods_max, which is calculated from buffer_bytes_max). That is, application may request any size between them; and it expects the wake up by this value.
I think that's a still missing stone in the design.
Well, so what would a real HW driver do in that case? My understanding is that in this case SW can still request something that HW can't do and driver will reject such configurations. In my case, the role of that HW driver code which judges on if configuration is acceptable just runs on the backend side, e.g. frontend driver is just a proxy which talks to the backend to check if the backend can do what requested. And it is up to backend to decide.
Does that sound reasonable or you have something else on your mind?
Usually the hardware driver knows already the restrictions and sets up the rules via hw constraints at open callback. There are lots of snd_pcm_hw_constraint_*() helpers (and the relevant ones) to give more additional rules for the parameter restrictions. For example, if the periods must be aligned with the buffer size (i.e. buffer_size % period_size == 0) as on many devices, you can call like: snd_pcm_hw_constraint_integer(substream->runtime, SNDRV_PCM_HW_PARAM_PERIODS); in the open callback.
And, now an open question for XEN comes: what kind of restriction should be applied to the frontend. Obviously it depends on the backend, so there must be some communication, and the restriction must be propagated at open, i.e. *before* actually hw_params is performed.
thanks,
Takashi
thanks,
Takashi
Thank you, Oleksandr
thanks,
Takashi
Waiting for your valuable comments,
Thank you, Oleksandr
[1] https://github.com/andr2000/linux/commits/snd_upstream_v1 [2] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/incl... [3] https://github.com/xen-troops/snd_be [4] https://github.com/xen-troops/libxenbe [5] https://lkml.org/lkml/2017/8/7/363 [6] http://mailman.alsa-project.org/pipermail/alsa-devel/2017-August/123617.html [7] http://mailman.alsa-project.org/pipermail/alsa-devel/2017-August/123744.html
Oleksandr Andrushchenko (2): sndif: introduce protocol version sndif: add explicit back and front synchronization
xen/include/public/io/sndif.h | 173 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 170 insertions(+), 3 deletions(-)
-- 2.7.4
Alsa-devel mailing list Alsa-devel@alsa-project.org http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
[1] https://github.com/andr2000/linux/commits/tiwai_sound_for_next_pv_snd_upstre... [2] https://github.com/andr2000/linux/blob/tiwai_sound_for_next_pv_snd_upstream_... [3] https://www.mail-archive.com/xen-devel@lists.xen.org/msg124356.html
On 03/06/2018 02:52 PM, Takashi Iwai wrote:
On Tue, 06 Mar 2018 13:05:16 +0100, Oleksandr Andrushchenko wrote:
On 03/06/2018 01:32 PM, Takashi Iwai wrote:
On Tue, 06 Mar 2018 12:25:07 +0100, Oleksandr Andrushchenko wrote:
On 03/06/2018 12:52 PM, Takashi Iwai wrote:
On Mon, 05 Feb 2018 09:24:58 +0100, Oleksandr Andrushchenko wrote:
From: Oleksandr Andrushchenko oleksandr_andrushchenko@epam.com
Hi, all!
Foreword
This change is aimed to add support for explicit back and front synchronization during playback and capture in response to comments raised during upstream attempt of the para-virtualized sound frontend driver for Xen [1], [2] and gather opinions from the relevant communities (ALSA, Xen) on the change.
The relevant backend is implemented as a user-space application [3] and uses accompanying helper library [4].
Both frontend driver and backend were tested on real HW running Xen hypervisor (Renesas R-Car ARM based H3/M3 boards, x86) to make sure the proposed solution does work.
Rationale
During the first attempt to upstream the Linux front driver [5] number of comments and concerns were raised, one of the biggest flaws in the design were questioned by both Clemens Ladisch [6] and Takashi Sakamoto [7]: the absence of synchronization between frontend and backend during capture/playback. Two options were discussed:
“In design of ALSA PCM core, drivers are expected to synchronize to actual hardwares for semi-realtime data transmission. The synchronization is done by two points:
- Interrupts to respond events from actual hardwares.
- Positions of actual data transmission in any serial sound interfaces of actual hardwares.
“
and finally a change to the existing protocol was suggested:
“In 'include/xen/interface/io/sndif.h', there's no functionalities I described the above:
- notifications from DomU to Dom0 about the size of period for interrupts from actual hardwares. Or no way from Dom0 to DomU about the configured size of the period.
- notifications of the interrupts from actual hardwares to DomU.”
This is implemented as a change to the sndif protocol and allows removing period emulation:
- Introduced a new event channel from back to front
- New event with number of bytes played/captured (XENSND_EVT_CUR_POS, to be used for sending snd_pcm_period_elapsed at frontend (in Linux implementation). Sent in bytes, not frames to make the protocol generic and consistent)
- New request for playback/capture control (XENSND_OP_TRIGGER) with start/pause/stop/resume sub-ops
- Playback/capture buffer size is set on the backend side via XENSND_FIELD_BUFFER_SIZE XenStore entry
So the new addition looks serving well for the point that was suggested in the previous thread. As I see no frontend driver implementation, it's hard to tell about the details, but through a quick glance, the protocol should be OK.
Thank you, the driver is at [1]
Now, going back to a big picture: I took a look at the previous patchset, and wonder what about the hw_params setup. Basically the (frontend) application may request any size of buffer and periods unless the driver sets up the hw constraints at open callback. That is, app may request even the 16 bytes of buffer size, or 1GB of buffer. The periods aren't always integer, so it can be 1024 bytes of buffer with 400 bytes of periods.
And, if such parameters are set up freely in the frontend side, how the backend is supposed to behave? From the frontend POV, it expects receiving the wakeup/notification at each period processing (e.g. 400 bytes in the case above). But, the backend is another application, so how would it work for such requirements? Am I missing something here?
Well, the frontend is not that free to decide as it might look like, e.g. please see [2]. Basically part of hw_params configuration is written to XenStore [3] as a part of domain configuration which depends on system/backend capabilities. E.g., we usually set buffer sizes to match real HW at backend side if we use ALSA and we have more freedom if we use PulseAudio there. Finally, if backend decides that the requested buffer/period sizes are not acceptable it will reject such a configuration.
OK, that restricts minimally. So at least there is the restriction / communication about the buffer size. But it merely means the *maximum* buffer size is set. Application may request still any shorter value than that.
And, there are no restriction about period sizes (except for the periods_max, which is calculated from buffer_bytes_max). That is, application may request any size between them; and it expects the wake up by this value.
I think that's a still missing stone in the design.
Well, so what would a real HW driver do in that case? My understanding is that in this case SW can still request something that HW can't do and driver will reject such configurations. In my case, the role of that HW driver code which judges on if configuration is acceptable just runs on the backend side, e.g. frontend driver is just a proxy which talks to the backend to check if the backend can do what requested. And it is up to backend to decide.
Does that sound reasonable or you have something else on your mind?
Usually the hardware driver knows already the restrictions and sets up the rules via hw constraints at open callback. There are lots of snd_pcm_hw_constraint_*() helpers (and the relevant ones) to give more additional rules for the parameter restrictions. For example, if the periods must be aligned with the buffer size (i.e. buffer_size % period_size == 0) as on many devices, you can call like: snd_pcm_hw_constraint_integer(substream->runtime, SNDRV_PCM_HW_PARAM_PERIODS); in the open callback.
You are right, I saw those in other drivers
And, now an open question for XEN comes: what kind of restriction should be applied to the frontend. Obviously it depends on the backend, so there must be some communication, and the restriction must be propagated at open, i.e. *before* actually hw_params is performed.
Could you please give me a hint of what those restrictions could look like? E.g. map of supported buffer/period sizes, what else?
thanks,
Takashi
Thank you, Oleksandr
thanks,
Takashi
Thank you, Oleksandr
thanks,
Takashi
Waiting for your valuable comments,
Thank you, Oleksandr
[1] https://github.com/andr2000/linux/commits/snd_upstream_v1 [2] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/incl... [3] https://github.com/xen-troops/snd_be [4] https://github.com/xen-troops/libxenbe [5] https://lkml.org/lkml/2017/8/7/363 [6] http://mailman.alsa-project.org/pipermail/alsa-devel/2017-August/123617.html [7] http://mailman.alsa-project.org/pipermail/alsa-devel/2017-August/123744.html
Oleksandr Andrushchenko (2): sndif: introduce protocol version sndif: add explicit back and front synchronization
xen/include/public/io/sndif.h | 173 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 170 insertions(+), 3 deletions(-)
-- 2.7.4
Alsa-devel mailing list Alsa-devel@alsa-project.org http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
[1] https://github.com/andr2000/linux/commits/tiwai_sound_for_next_pv_snd_upstre... [2] https://github.com/andr2000/linux/blob/tiwai_sound_for_next_pv_snd_upstream_... [3] https://www.mail-archive.com/xen-devel@lists.xen.org/msg124356.html
On Tue, 06 Mar 2018 14:30:05 +0100, Oleksandr Andrushchenko wrote:
On 03/06/2018 02:52 PM, Takashi Iwai wrote:
On Tue, 06 Mar 2018 13:05:16 +0100, Oleksandr Andrushchenko wrote:
On 03/06/2018 01:32 PM, Takashi Iwai wrote:
On Tue, 06 Mar 2018 12:25:07 +0100, Oleksandr Andrushchenko wrote:
On 03/06/2018 12:52 PM, Takashi Iwai wrote:
On Mon, 05 Feb 2018 09:24:58 +0100, Oleksandr Andrushchenko wrote: > From: Oleksandr Andrushchenko oleksandr_andrushchenko@epam.com > > Hi, all! > > Foreword > ======== > > This change is aimed to add support for explicit back and front > synchronization during playback and capture in response to comments > raised during upstream attempt of the para-virtualized sound frontend > driver for Xen [1], [2] and gather opinions from the relevant communities > (ALSA, Xen) on the change. > > The relevant backend is implemented as a user-space application [3] > and uses accompanying helper library [4]. > > Both frontend driver and backend were tested on real HW running Xen hypervisor > (Renesas R-Car ARM based H3/M3 boards, x86) to make sure the proposed > solution does work. > > Rationale > ========= > > During the first attempt to upstream the Linux front driver [5] number > of comments and concerns were raised, one of the biggest flaws in the > design were questioned by both Clemens Ladisch [6] and > Takashi Sakamoto [7]: the absence of synchronization between frontend > and backend during capture/playback. Two options were discussed: > > “In design of ALSA PCM core, drivers are expected to synchronize to > actual hardwares for semi-realtime data transmission. The > synchronization is done by two points: > 1) Interrupts to respond events from actual hardwares. > 2) Positions of actual data transmission in any serial sound interfaces > of actual hardwares. > “ > > and finally a change to the existing protocol was suggested: > > “In 'include/xen/interface/io/sndif.h', there's no functionalities I > described the above: > 1. notifications from DomU to Dom0 about the size of period for > interrupts from actual hardwares. Or no way from Dom0 to DomU about > the configured size of the period. > 2. notifications of the interrupts from actual hardwares to DomU.” > > This is implemented as a change to the sndif protocol and allows removing > period emulation: > 1. Introduced a new event channel from back to front > 2. New event with number of bytes played/captured (XENSND_EVT_CUR_POS, > to be used for sending snd_pcm_period_elapsed at frontend (in Linux > implementation). Sent in bytes, not frames to make the protocol > generic and consistent) > 3. New request for playback/capture control (XENSND_OP_TRIGGER) with > start/pause/stop/resume sub-ops > 4. Playback/capture buffer size is set on the backend side via > XENSND_FIELD_BUFFER_SIZE XenStore entry So the new addition looks serving well for the point that was suggested in the previous thread. As I see no frontend driver implementation, it's hard to tell about the details, but through a quick glance, the protocol should be OK.
Thank you, the driver is at [1]
Now, going back to a big picture: I took a look at the previous patchset, and wonder what about the hw_params setup. Basically the (frontend) application may request any size of buffer and periods unless the driver sets up the hw constraints at open callback. That is, app may request even the 16 bytes of buffer size, or 1GB of buffer. The periods aren't always integer, so it can be 1024 bytes of buffer with 400 bytes of periods.
And, if such parameters are set up freely in the frontend side, how the backend is supposed to behave? From the frontend POV, it expects receiving the wakeup/notification at each period processing (e.g. 400 bytes in the case above). But, the backend is another application, so how would it work for such requirements? Am I missing something here?
Well, the frontend is not that free to decide as it might look like, e.g. please see [2]. Basically part of hw_params configuration is written to XenStore [3] as a part of domain configuration which depends on system/backend capabilities. E.g., we usually set buffer sizes to match real HW at backend side if we use ALSA and we have more freedom if we use PulseAudio there. Finally, if backend decides that the requested buffer/period sizes are not acceptable it will reject such a configuration.
OK, that restricts minimally. So at least there is the restriction / communication about the buffer size. But it merely means the *maximum* buffer size is set. Application may request still any shorter value than that.
And, there are no restriction about period sizes (except for the periods_max, which is calculated from buffer_bytes_max). That is, application may request any size between them; and it expects the wake up by this value.
I think that's a still missing stone in the design.
Well, so what would a real HW driver do in that case? My understanding is that in this case SW can still request something that HW can't do and driver will reject such configurations. In my case, the role of that HW driver code which judges on if configuration is acceptable just runs on the backend side, e.g. frontend driver is just a proxy which talks to the backend to check if the backend can do what requested. And it is up to backend to decide.
Does that sound reasonable or you have something else on your mind?
Usually the hardware driver knows already the restrictions and sets up the rules via hw constraints at open callback. There are lots of snd_pcm_hw_constraint_*() helpers (and the relevant ones) to give more additional rules for the parameter restrictions. For example, if the periods must be aligned with the buffer size (i.e. buffer_size % period_size == 0) as on many devices, you can call like: snd_pcm_hw_constraint_integer(substream->runtime, SNDRV_PCM_HW_PARAM_PERIODS); in the open callback.
You are right, I saw those in other drivers
And, now an open question for XEN comes: what kind of restriction should be applied to the frontend. Obviously it depends on the backend, so there must be some communication, and the restriction must be propagated at open, i.e. *before* actually hw_params is performed.
Could you please give me a hint of what those restrictions could look like? E.g. map of supported buffer/period sizes, what else?
Heh, that very much depends on the hardware -- and in this case, on the implementation of the backend.
Practically seen, the buffer and the period size setups are mandatory, yes. Here is the question whether you want to limit them by list (e.g. read via some XENSND_* protocol), or negotiate the size at each hw_params setup (e.g. getting only min/max at open, and at each hw_params call, negotiate with the backend for period and buffer size changes).
The format, the channels and the sample rate are already included in snd_pcm_hardware setup, so this should be OK, unless they have implicit limitations with each other (e.g. some format is available only under some rate).
Maybe the channels need to be revisited, though; usually you can't handle all number of channels between min and max but only even numbers or such.
thanks,
Takashi
On 03/06/2018 03:48 PM, Takashi Iwai wrote:
On Tue, 06 Mar 2018 14:30:05 +0100, Oleksandr Andrushchenko wrote:
On 03/06/2018 02:52 PM, Takashi Iwai wrote:
On Tue, 06 Mar 2018 13:05:16 +0100, Oleksandr Andrushchenko wrote:
On 03/06/2018 01:32 PM, Takashi Iwai wrote:
On Tue, 06 Mar 2018 12:25:07 +0100, Oleksandr Andrushchenko wrote:
On 03/06/2018 12:52 PM, Takashi Iwai wrote: > On Mon, 05 Feb 2018 09:24:58 +0100, > Oleksandr Andrushchenko wrote: >> From: Oleksandr Andrushchenko oleksandr_andrushchenko@epam.com >> >> Hi, all! >> >> Foreword >> ======== >> >> This change is aimed to add support for explicit back and front >> synchronization during playback and capture in response to comments >> raised during upstream attempt of the para-virtualized sound frontend >> driver for Xen [1], [2] and gather opinions from the relevant communities >> (ALSA, Xen) on the change. >> >> The relevant backend is implemented as a user-space application [3] >> and uses accompanying helper library [4]. >> >> Both frontend driver and backend were tested on real HW running Xen hypervisor >> (Renesas R-Car ARM based H3/M3 boards, x86) to make sure the proposed >> solution does work. >> >> Rationale >> ========= >> >> During the first attempt to upstream the Linux front driver [5] number >> of comments and concerns were raised, one of the biggest flaws in the >> design were questioned by both Clemens Ladisch [6] and >> Takashi Sakamoto [7]: the absence of synchronization between frontend >> and backend during capture/playback. Two options were discussed: >> >> “In design of ALSA PCM core, drivers are expected to synchronize to >> actual hardwares for semi-realtime data transmission. The >> synchronization is done by two points: >> 1) Interrupts to respond events from actual hardwares. >> 2) Positions of actual data transmission in any serial sound interfaces >> of actual hardwares. >> “ >> >> and finally a change to the existing protocol was suggested: >> >> “In 'include/xen/interface/io/sndif.h', there's no functionalities I >> described the above: >> 1. notifications from DomU to Dom0 about the size of period for >> interrupts from actual hardwares. Or no way from Dom0 to DomU about >> the configured size of the period. >> 2. notifications of the interrupts from actual hardwares to DomU.” >> >> This is implemented as a change to the sndif protocol and allows removing >> period emulation: >> 1. Introduced a new event channel from back to front >> 2. New event with number of bytes played/captured (XENSND_EVT_CUR_POS, >> to be used for sending snd_pcm_period_elapsed at frontend (in Linux >> implementation). Sent in bytes, not frames to make the protocol >> generic and consistent) >> 3. New request for playback/capture control (XENSND_OP_TRIGGER) with >> start/pause/stop/resume sub-ops >> 4. Playback/capture buffer size is set on the backend side via >> XENSND_FIELD_BUFFER_SIZE XenStore entry > So the new addition looks serving well for the point that was > suggested in the previous thread. As I see no frontend driver > implementation, it's hard to tell about the details, but through a > quick glance, the protocol should be OK. Thank you, the driver is at [1] > Now, going back to a big picture: I took a look at the previous > patchset, and wonder what about the hw_params setup. Basically the > (frontend) application may request any size of buffer and periods > unless the driver sets up the hw constraints at open callback. That > is, app may request even the 16 bytes of buffer size, or 1GB of > buffer. The periods aren't always integer, so it can be 1024 bytes of > buffer with 400 bytes of periods. > > And, if such parameters are set up freely in the frontend side, how > the backend is supposed to behave? From the frontend POV, it expects > receiving the wakeup/notification at each period processing (e.g. 400 > bytes in the case above). But, the backend is another application, so > how would it work for such requirements? Am I missing something here? Well, the frontend is not that free to decide as it might look like, e.g. please see [2]. Basically part of hw_params configuration is written to XenStore [3] as a part of domain configuration which depends on system/backend capabilities. E.g., we usually set buffer sizes to match real HW at backend side if we use ALSA and we have more freedom if we use PulseAudio there. Finally, if backend decides that the requested buffer/period sizes are not acceptable it will reject such a configuration.
OK, that restricts minimally. So at least there is the restriction / communication about the buffer size. But it merely means the *maximum* buffer size is set. Application may request still any shorter value than that.
And, there are no restriction about period sizes (except for the periods_max, which is calculated from buffer_bytes_max). That is, application may request any size between them; and it expects the wake up by this value.
I think that's a still missing stone in the design.
Well, so what would a real HW driver do in that case? My understanding is that in this case SW can still request something that HW can't do and driver will reject such configurations. In my case, the role of that HW driver code which judges on if configuration is acceptable just runs on the backend side, e.g. frontend driver is just a proxy which talks to the backend to check if the backend can do what requested. And it is up to backend to decide.
Does that sound reasonable or you have something else on your mind?
Usually the hardware driver knows already the restrictions and sets up the rules via hw constraints at open callback. There are lots of snd_pcm_hw_constraint_*() helpers (and the relevant ones) to give more additional rules for the parameter restrictions. For example, if the periods must be aligned with the buffer size (i.e. buffer_size % period_size == 0) as on many devices, you can call like: snd_pcm_hw_constraint_integer(substream->runtime, SNDRV_PCM_HW_PARAM_PERIODS); in the open callback.
You are right, I saw those in other drivers
And, now an open question for XEN comes: what kind of restriction should be applied to the frontend. Obviously it depends on the backend, so there must be some communication, and the restriction must be propagated at open, i.e. *before* actually hw_params is performed.
Could you please give me a hint of what those restrictions could look like? E.g. map of supported buffer/period sizes, what else?
Heh, that very much depends on the hardware -- and in this case, on the implementation of the backend.
That is correct, but we try to be backend agnostic, though
Practically seen, the buffer and the period size setups are mandatory, yes. Here is the question whether you want to limit them by list (e.g. read via some XENSND_* protocol), or negotiate the size at each hw_params setup (e.g. getting only min/max at open, and at each hw_params call, negotiate with the backend for period and buffer size changes).
The problem I see here is that at .open real HW driver already knows its constraints and can properly setup. So, in our case at open we should already have all the constraints available to the frontend as well. That will lead to lots of text in domain configuration file if propagated via XenStore (e.g. you have to put all possible combinations of buffers/periods depending on number of channels, sample rates etc., you cannot use logic here as you can in a real HW driver, only values). So, such configuration doesn't seem to be an option here.
If we decide to negotiate the parameters, then it can't be done at .open stage as well, as at this moment we don't know stream parameters yet, e.g. we don't know the number of channels, PCM format etc., so we cannot explain to the backend what we want. Thus, it seems that we need to move the negotiation to .hw_params callback where stream properties are known. But this leaves the only option to ask the backend if it can handle the requested buffer/period and other parameters or not... This is what I do now :(
Am I missing something here?
The format, the channels and the sample rate are already included in snd_pcm_hardware setup, so this should be OK, unless they have implicit limitations with each other (e.g. some format is available only under some rate).
Thank you, this should be up to the one who sets up the domain configuration. Taking into account embedded nature of our use-cases this is almost always doable, as these are defined at system design time, e.g. we define number of channels and their properties depending on domain functionality and needs.
Maybe the channels need to be revisited, though; usually you can't handle all number of channels between min and max but only even numbers or such.
But if backend can implement some fancy stuff with software mixing etc... This is why I didn't limit on that
thanks,
Takashi
Thank you, Oleksandr
On Tue, 06 Mar 2018 15:13:13 +0100, Oleksandr Andrushchenko wrote:
On 03/06/2018 03:48 PM, Takashi Iwai wrote:
On Tue, 06 Mar 2018 14:30:05 +0100, Oleksandr Andrushchenko wrote:
On 03/06/2018 02:52 PM, Takashi Iwai wrote:
On Tue, 06 Mar 2018 13:05:16 +0100, Oleksandr Andrushchenko wrote:
On 03/06/2018 01:32 PM, Takashi Iwai wrote:
On Tue, 06 Mar 2018 12:25:07 +0100, Oleksandr Andrushchenko wrote: > On 03/06/2018 12:52 PM, Takashi Iwai wrote: >> On Mon, 05 Feb 2018 09:24:58 +0100, >> Oleksandr Andrushchenko wrote: >>> From: Oleksandr Andrushchenko oleksandr_andrushchenko@epam.com >>> >>> Hi, all! >>> >>> Foreword >>> ======== >>> >>> This change is aimed to add support for explicit back and front >>> synchronization during playback and capture in response to comments >>> raised during upstream attempt of the para-virtualized sound frontend >>> driver for Xen [1], [2] and gather opinions from the relevant communities >>> (ALSA, Xen) on the change. >>> >>> The relevant backend is implemented as a user-space application [3] >>> and uses accompanying helper library [4]. >>> >>> Both frontend driver and backend were tested on real HW running Xen hypervisor >>> (Renesas R-Car ARM based H3/M3 boards, x86) to make sure the proposed >>> solution does work. >>> >>> Rationale >>> ========= >>> >>> During the first attempt to upstream the Linux front driver [5] number >>> of comments and concerns were raised, one of the biggest flaws in the >>> design were questioned by both Clemens Ladisch [6] and >>> Takashi Sakamoto [7]: the absence of synchronization between frontend >>> and backend during capture/playback. Two options were discussed: >>> >>> “In design of ALSA PCM core, drivers are expected to synchronize to >>> actual hardwares for semi-realtime data transmission. The >>> synchronization is done by two points: >>> 1) Interrupts to respond events from actual hardwares. >>> 2) Positions of actual data transmission in any serial sound interfaces >>> of actual hardwares. >>> “ >>> >>> and finally a change to the existing protocol was suggested: >>> >>> “In 'include/xen/interface/io/sndif.h', there's no functionalities I >>> described the above: >>> 1. notifications from DomU to Dom0 about the size of period for >>> interrupts from actual hardwares. Or no way from Dom0 to DomU about >>> the configured size of the period. >>> 2. notifications of the interrupts from actual hardwares to DomU.” >>> >>> This is implemented as a change to the sndif protocol and allows removing >>> period emulation: >>> 1. Introduced a new event channel from back to front >>> 2. New event with number of bytes played/captured (XENSND_EVT_CUR_POS, >>> to be used for sending snd_pcm_period_elapsed at frontend (in Linux >>> implementation). Sent in bytes, not frames to make the protocol >>> generic and consistent) >>> 3. New request for playback/capture control (XENSND_OP_TRIGGER) with >>> start/pause/stop/resume sub-ops >>> 4. Playback/capture buffer size is set on the backend side via >>> XENSND_FIELD_BUFFER_SIZE XenStore entry >> So the new addition looks serving well for the point that was >> suggested in the previous thread. As I see no frontend driver >> implementation, it's hard to tell about the details, but through a >> quick glance, the protocol should be OK. > Thank you, the driver is at [1] >> Now, going back to a big picture: I took a look at the previous >> patchset, and wonder what about the hw_params setup. Basically the >> (frontend) application may request any size of buffer and periods >> unless the driver sets up the hw constraints at open callback. That >> is, app may request even the 16 bytes of buffer size, or 1GB of >> buffer. The periods aren't always integer, so it can be 1024 bytes of >> buffer with 400 bytes of periods. >> >> And, if such parameters are set up freely in the frontend side, how >> the backend is supposed to behave? From the frontend POV, it expects >> receiving the wakeup/notification at each period processing (e.g. 400 >> bytes in the case above). But, the backend is another application, so >> how would it work for such requirements? Am I missing something here? > Well, the frontend is not that free to decide as it might look like, > e.g. please see [2]. Basically part of hw_params configuration is written > to XenStore [3] as a part of domain configuration which depends on > system/backend > capabilities. E.g., we usually set buffer sizes to match real HW at > backend side > if we use ALSA and we have more freedom if we use PulseAudio there. > Finally, if backend decides that the requested buffer/period sizes are > not acceptable it will reject such a configuration. OK, that restricts minimally. So at least there is the restriction / communication about the buffer size. But it merely means the *maximum* buffer size is set. Application may request still any shorter value than that.
And, there are no restriction about period sizes (except for the periods_max, which is calculated from buffer_bytes_max). That is, application may request any size between them; and it expects the wake up by this value.
I think that's a still missing stone in the design.
Well, so what would a real HW driver do in that case? My understanding is that in this case SW can still request something that HW can't do and driver will reject such configurations. In my case, the role of that HW driver code which judges on if configuration is acceptable just runs on the backend side, e.g. frontend driver is just a proxy which talks to the backend to check if the backend can do what requested. And it is up to backend to decide.
Does that sound reasonable or you have something else on your mind?
Usually the hardware driver knows already the restrictions and sets up the rules via hw constraints at open callback. There are lots of snd_pcm_hw_constraint_*() helpers (and the relevant ones) to give more additional rules for the parameter restrictions. For example, if the periods must be aligned with the buffer size (i.e. buffer_size % period_size == 0) as on many devices, you can call like: snd_pcm_hw_constraint_integer(substream->runtime, SNDRV_PCM_HW_PARAM_PERIODS); in the open callback.
You are right, I saw those in other drivers
And, now an open question for XEN comes: what kind of restriction should be applied to the frontend. Obviously it depends on the backend, so there must be some communication, and the restriction must be propagated at open, i.e. *before* actually hw_params is performed.
Could you please give me a hint of what those restrictions could look like? E.g. map of supported buffer/period sizes, what else?
Heh, that very much depends on the hardware -- and in this case, on the implementation of the backend.
That is correct, but we try to be backend agnostic, though
Practically seen, the buffer and the period size setups are mandatory, yes. Here is the question whether you want to limit them by list (e.g. read via some XENSND_* protocol), or negotiate the size at each hw_params setup (e.g. getting only min/max at open, and at each hw_params call, negotiate with the backend for period and buffer size changes).
The problem I see here is that at .open real HW driver already knows its constraints and can properly setup. So, in our case at open we should already have all the constraints available to the frontend as well. That will lead to lots of text in domain configuration file if propagated via XenStore (e.g. you have to put all possible combinations of buffers/periods depending on number of channels, sample rates etc., you cannot use logic here as you can in a real HW driver, only values). So, such configuration doesn't seem to be an option here.
It depends. If we do limit the configuration intentionally to only some subsets that should suffice for most use cases, then the list would be relatively short.
If we decide to negotiate the parameters, then it can't be done at .open stage as well, as at this moment we don't know stream parameters yet, e.g. we don't know the number of channels, PCM format etc., so we cannot explain to the backend what we want. Thus, it seems that we need to move the negotiation to .hw_params callback where stream properties are known. But this leaves the only option to ask the backend if it can handle the requested buffer/period and other parameters or not... This is what I do now :(
The additional parameter setup can be done via hw_constraints. The hw constraint is basically a function call for each parameter change to narrow down the range of the given parameter.
snd_pcm_hw_constraint_integer() in the above is just an example. The actual function to adjust values can be freely written.
Am I missing something here?
The format, the channels and the sample rate are already included in snd_pcm_hardware setup, so this should be OK, unless they have implicit limitations with each other (e.g. some format is available only under some rate).
Thank you, this should be up to the one who sets up the domain configuration. Taking into account embedded nature of our use-cases this is almost always doable, as these are defined at system design time, e.g. we define number of channels and their properties depending on domain functionality and needs.
Maybe the channels need to be revisited, though; usually you can't handle all number of channels between min and max but only even numbers or such.
But if backend can implement some fancy stuff with software mixing etc... This is why I didn't limit on that
But if the backend doesn't support fancy numbers like 3 channels? That's the same situation as buffer / periods. The frontend needs to know exactly what configuration the backend would allow.
Takashi
On 03/06/2018 04:27 PM, Takashi Iwai wrote:
On Tue, 06 Mar 2018 15:13:13 +0100, Oleksandr Andrushchenko wrote:
On 03/06/2018 03:48 PM, Takashi Iwai wrote:
On Tue, 06 Mar 2018 14:30:05 +0100, Oleksandr Andrushchenko wrote:
On 03/06/2018 02:52 PM, Takashi Iwai wrote:
On Tue, 06 Mar 2018 13:05:16 +0100, Oleksandr Andrushchenko wrote:
On 03/06/2018 01:32 PM, Takashi Iwai wrote: > On Tue, 06 Mar 2018 12:25:07 +0100, > Oleksandr Andrushchenko wrote: >> On 03/06/2018 12:52 PM, Takashi Iwai wrote: >>> On Mon, 05 Feb 2018 09:24:58 +0100, >>> Oleksandr Andrushchenko wrote: >>>> From: Oleksandr Andrushchenko oleksandr_andrushchenko@epam.com >>>> >>>> Hi, all! >>>> >>>> Foreword >>>> ======== >>>> >>>> This change is aimed to add support for explicit back and front >>>> synchronization during playback and capture in response to comments >>>> raised during upstream attempt of the para-virtualized sound frontend >>>> driver for Xen [1], [2] and gather opinions from the relevant communities >>>> (ALSA, Xen) on the change. >>>> >>>> The relevant backend is implemented as a user-space application [3] >>>> and uses accompanying helper library [4]. >>>> >>>> Both frontend driver and backend were tested on real HW running Xen hypervisor >>>> (Renesas R-Car ARM based H3/M3 boards, x86) to make sure the proposed >>>> solution does work. >>>> >>>> Rationale >>>> ========= >>>> >>>> During the first attempt to upstream the Linux front driver [5] number >>>> of comments and concerns were raised, one of the biggest flaws in the >>>> design were questioned by both Clemens Ladisch [6] and >>>> Takashi Sakamoto [7]: the absence of synchronization between frontend >>>> and backend during capture/playback. Two options were discussed: >>>> >>>> “In design of ALSA PCM core, drivers are expected to synchronize to >>>> actual hardwares for semi-realtime data transmission. The >>>> synchronization is done by two points: >>>> 1) Interrupts to respond events from actual hardwares. >>>> 2) Positions of actual data transmission in any serial sound interfaces >>>> of actual hardwares. >>>> “ >>>> >>>> and finally a change to the existing protocol was suggested: >>>> >>>> “In 'include/xen/interface/io/sndif.h', there's no functionalities I >>>> described the above: >>>> 1. notifications from DomU to Dom0 about the size of period for >>>> interrupts from actual hardwares. Or no way from Dom0 to DomU about >>>> the configured size of the period. >>>> 2. notifications of the interrupts from actual hardwares to DomU.” >>>> >>>> This is implemented as a change to the sndif protocol and allows removing >>>> period emulation: >>>> 1. Introduced a new event channel from back to front >>>> 2. New event with number of bytes played/captured (XENSND_EVT_CUR_POS, >>>> to be used for sending snd_pcm_period_elapsed at frontend (in Linux >>>> implementation). Sent in bytes, not frames to make the protocol >>>> generic and consistent) >>>> 3. New request for playback/capture control (XENSND_OP_TRIGGER) with >>>> start/pause/stop/resume sub-ops >>>> 4. Playback/capture buffer size is set on the backend side via >>>> XENSND_FIELD_BUFFER_SIZE XenStore entry >>> So the new addition looks serving well for the point that was >>> suggested in the previous thread. As I see no frontend driver >>> implementation, it's hard to tell about the details, but through a >>> quick glance, the protocol should be OK. >> Thank you, the driver is at [1] >>> Now, going back to a big picture: I took a look at the previous >>> patchset, and wonder what about the hw_params setup. Basically the >>> (frontend) application may request any size of buffer and periods >>> unless the driver sets up the hw constraints at open callback. That >>> is, app may request even the 16 bytes of buffer size, or 1GB of >>> buffer. The periods aren't always integer, so it can be 1024 bytes of >>> buffer with 400 bytes of periods. >>> >>> And, if such parameters are set up freely in the frontend side, how >>> the backend is supposed to behave? From the frontend POV, it expects >>> receiving the wakeup/notification at each period processing (e.g. 400 >>> bytes in the case above). But, the backend is another application, so >>> how would it work for such requirements? Am I missing something here? >> Well, the frontend is not that free to decide as it might look like, >> e.g. please see [2]. Basically part of hw_params configuration is written >> to XenStore [3] as a part of domain configuration which depends on >> system/backend >> capabilities. E.g., we usually set buffer sizes to match real HW at >> backend side >> if we use ALSA and we have more freedom if we use PulseAudio there. >> Finally, if backend decides that the requested buffer/period sizes are >> not acceptable it will reject such a configuration. > OK, that restricts minimally. So at least there is the restriction / > communication about the buffer size. But it merely means the > *maximum* buffer size is set. Application may request still any > shorter value than that. > > And, there are no restriction about period sizes (except for the > periods_max, which is calculated from buffer_bytes_max). > That is, application may request any size between them; and it expects > the wake up by this value. > > I think that's a still missing stone in the design. Well, so what would a real HW driver do in that case? My understanding is that in this case SW can still request something that HW can't do and driver will reject such configurations. In my case, the role of that HW driver code which judges on if configuration is acceptable just runs on the backend side, e.g. frontend driver is just a proxy which talks to the backend to check if the backend can do what requested. And it is up to backend to decide.
Does that sound reasonable or you have something else on your mind?
Usually the hardware driver knows already the restrictions and sets up the rules via hw constraints at open callback. There are lots of snd_pcm_hw_constraint_*() helpers (and the relevant ones) to give more additional rules for the parameter restrictions. For example, if the periods must be aligned with the buffer size (i.e. buffer_size % period_size == 0) as on many devices, you can call like: snd_pcm_hw_constraint_integer(substream->runtime, SNDRV_PCM_HW_PARAM_PERIODS); in the open callback.
You are right, I saw those in other drivers
And, now an open question for XEN comes: what kind of restriction should be applied to the frontend. Obviously it depends on the backend, so there must be some communication, and the restriction must be propagated at open, i.e. *before* actually hw_params is performed.
Could you please give me a hint of what those restrictions could look like? E.g. map of supported buffer/period sizes, what else?
Heh, that very much depends on the hardware -- and in this case, on the implementation of the backend.
That is correct, but we try to be backend agnostic, though
Practically seen, the buffer and the period size setups are mandatory, yes. Here is the question whether you want to limit them by list (e.g. read via some XENSND_* protocol), or negotiate the size at each hw_params setup (e.g. getting only min/max at open, and at each hw_params call, negotiate with the backend for period and buffer size changes).
The problem I see here is that at .open real HW driver already knows its constraints and can properly setup. So, in our case at open we should already have all the constraints available to the frontend as well. That will lead to lots of text in domain configuration file if propagated via XenStore (e.g. you have to put all possible combinations of buffers/periods depending on number of channels, sample rates etc., you cannot use logic here as you can in a real HW driver, only values). So, such configuration doesn't seem to be an option here.
It depends. If we do limit the configuration intentionally to only some subsets that should suffice for most use cases, then the list would be relatively short.
Ok, if we go with a limited set of supported buffer/period sizes (and number of channels?), what could a constraint entry look like? E.g. [buffer, period, num_channels, xxx] What is that xxx in question? Sample rate, sample format, anything else? Or [buffer, period, num_channels, rate, format] is enough? I am still thinking on having the above sent at run-time with a new protocol command, which I will call on .open, so I can apply the constraints where most of the drivers do. This way backend can also determine its capabilities at run-time and report those to the frontend, as a bonus eliminating the need for huge domain configuration file/XenStore entries.
If we decide to negotiate the parameters, then it can't be done at .open stage as well, as at this moment we don't know stream parameters yet, e.g. we don't know the number of channels, PCM format etc., so we cannot explain to the backend what we want. Thus, it seems that we need to move the negotiation to .hw_params callback where stream properties are known. But this leaves the only option to ask the backend if it can handle the requested buffer/period and other parameters or not... This is what I do now :(
The additional parameter setup can be done via hw_constraints. The hw constraint is basically a function call for each parameter change to narrow down the range of the given parameter.
snd_pcm_hw_constraint_integer() in the above is just an example. The actual function to adjust values can be freely written.
Yes, this is clear, the question here mostly was not *how* to set the constraints, but *where* to get those
Am I missing something here?
The format, the channels and the sample rate are already included in snd_pcm_hardware setup, so this should be OK, unless they have implicit limitations with each other (e.g. some format is available only under some rate).
Thank you, this should be up to the one who sets up the domain configuration. Taking into account embedded nature of our use-cases this is almost always doable, as these are defined at system design time, e.g. we define number of channels and their properties depending on domain functionality and needs.
Maybe the channels need to be revisited, though; usually you can't handle all number of channels between min and max but only even numbers or such.
But if backend can implement some fancy stuff with software mixing etc... This is why I didn't limit on that
But if the backend doesn't support fancy numbers like 3 channels? That's the same situation as buffer / periods. The frontend needs to know exactly what configuration the backend would allow.
Ok, did I understand you correctly that you see it as described above, e.g. backend communicates (limited) set of constraints to the frontend, so frontend sets these constraints at .open? The way these are communicated could be either XenStore/ domain configuration or extension to the protocol, no preference from your side?
Takashi
Thank you very much for helping with this! Oleksandr
On Tue, 06 Mar 2018 15:48:53 +0100, Oleksandr Andrushchenko wrote:
And, now an open question for XEN comes: what kind of restriction should be applied to the frontend. Obviously it depends on the backend, so there must be some communication, and the restriction must be propagated at open, i.e. *before* actually hw_params is performed.
Could you please give me a hint of what those restrictions could look like? E.g. map of supported buffer/period sizes, what else?
Heh, that very much depends on the hardware -- and in this case, on the implementation of the backend.
That is correct, but we try to be backend agnostic, though
Practically seen, the buffer and the period size setups are mandatory, yes. Here is the question whether you want to limit them by list (e.g. read via some XENSND_* protocol), or negotiate the size at each hw_params setup (e.g. getting only min/max at open, and at each hw_params call, negotiate with the backend for period and buffer size changes).
The problem I see here is that at .open real HW driver already knows its constraints and can properly setup. So, in our case at open we should already have all the constraints available to the frontend as well. That will lead to lots of text in domain configuration file if propagated via XenStore (e.g. you have to put all possible combinations of buffers/periods depending on number of channels, sample rates etc., you cannot use logic here as you can in a real HW driver, only values). So, such configuration doesn't seem to be an option here.
It depends. If we do limit the configuration intentionally to only some subsets that should suffice for most use cases, then the list would be relatively short.
Ok, if we go with a limited set of supported buffer/period sizes (and number of channels?), what could a constraint entry look like? E.g. [buffer, period, num_channels, xxx] What is that xxx in question? Sample rate, sample format, anything else? Or [buffer, period, num_channels, rate, format] is enough?
The buffer, period, channels, rate and format are the basic parameters, and that should be enough for 99.9% cases.
I am still thinking on having the above sent at run-time with a new protocol command, which I will call on .open, so I can apply the constraints where most of the drivers do. This way backend can also determine its capabilities at run-time and report those to the frontend, as a bonus eliminating the need for huge domain configuration file/XenStore entries.
You don't have to list up all combinations of the parameters above at open time. For example, declaring min/max of each of them at open would suffice at first. (But this min/max might be even unnecessary if we implement the proper hw constraints. See below)
The rest fine-tuning is done via the hw constraints...
If we decide to negotiate the parameters, then it can't be done at .open stage as well, as at this moment we don't know stream parameters yet, e.g. we don't know the number of channels, PCM format etc., so we cannot explain to the backend what we want. Thus, it seems that we need to move the negotiation to .hw_params callback where stream properties are known. But this leaves the only option to ask the backend if it can handle the requested buffer/period and other parameters or not... This is what I do now :(
The additional parameter setup can be done via hw_constraints. The hw constraint is basically a function call for each parameter change to narrow down the range of the given parameter.
snd_pcm_hw_constraint_integer() in the above is just an example. The actual function to adjust values can be freely written.
Yes, this is clear, the question here mostly was not *how* to set the constraints, but *where* to get those
... and here comes the hw constraint into the play.
For each parameter change, for example, the frontend just passes the inquiry to the backend. The basis of the hw constraint is nothing but to reduce the range of the given parameter. It's either interval (range, used for period/buffer size or sample rate) or the list (for the format). When any parameter is changed, ALSA PCM core invokes the corresponding hw constraint function, and the function reduces the range. It's repeated until all parameters are set and settled down.
So, for your driver, the frontend just passes the hw constraint for each of basic 5 parameters to the backend. For example, at beginning, the hw constraint for the buffer size will pass the range (1,INTMAX). Then the backend returns the range like (1024,65536). This already gives users the min/max buffer size information. The similar procedure will be done for all other parameters.
In addition, you can put the implicit rule like the integer periods, which makes things easier.
Am I missing something here?
The format, the channels and the sample rate are already included in snd_pcm_hardware setup, so this should be OK, unless they have implicit limitations with each other (e.g. some format is available only under some rate).
Thank you, this should be up to the one who sets up the domain configuration. Taking into account embedded nature of our use-cases this is almost always doable, as these are defined at system design time, e.g. we define number of channels and their properties depending on domain functionality and needs.
Maybe the channels need to be revisited, though; usually you can't handle all number of channels between min and max but only even numbers or such.
But if backend can implement some fancy stuff with software mixing etc... This is why I didn't limit on that
But if the backend doesn't support fancy numbers like 3 channels? That's the same situation as buffer / periods. The frontend needs to know exactly what configuration the backend would allow.
Ok, did I understand you correctly that you see it as described above, e.g. backend communicates (limited) set of constraints to the frontend, so frontend sets these constraints at .open?
Well, what set at the open time is only the constraint "rule". And the rule is a function call, not necessarily static. The actual parameters are determined at hw_params call time, and this is called even repeatedly.
The way these are communicated could be either XenStore/ domain configuration or extension to the protocol, no preference from your side?
Again, the parameter setup pretty depends on the hardware, and in this case, the backend (and its communication).
Takashi
On 03/06/2018 05:06 PM, Takashi Iwai wrote:
On Tue, 06 Mar 2018 15:48:53 +0100, Oleksandr Andrushchenko wrote:
> And, now an open question for XEN comes: what kind of restriction > should be applied to the frontend. Obviously it depends on the > backend, so there must be some communication, and the restriction must > be propagated at open, i.e. *before* actually hw_params is performed. Could you please give me a hint of what those restrictions could look like? E.g. map of supported buffer/period sizes, what else?
Heh, that very much depends on the hardware -- and in this case, on the implementation of the backend.
That is correct, but we try to be backend agnostic, though
Practically seen, the buffer and the period size setups are mandatory, yes. Here is the question whether you want to limit them by list (e.g. read via some XENSND_* protocol), or negotiate the size at each hw_params setup (e.g. getting only min/max at open, and at each hw_params call, negotiate with the backend for period and buffer size changes).
The problem I see here is that at .open real HW driver already knows its constraints and can properly setup. So, in our case at open we should already have all the constraints available to the frontend as well. That will lead to lots of text in domain configuration file if propagated via XenStore (e.g. you have to put all possible combinations of buffers/periods depending on number of channels, sample rates etc., you cannot use logic here as you can in a real HW driver, only values). So, such configuration doesn't seem to be an option here.
It depends. If we do limit the configuration intentionally to only some subsets that should suffice for most use cases, then the list would be relatively short.
Ok, if we go with a limited set of supported buffer/period sizes (and number of channels?), what could a constraint entry look like? E.g. [buffer, period, num_channels, xxx] What is that xxx in question? Sample rate, sample format, anything else? Or [buffer, period, num_channels, rate, format] is enough?
The buffer, period, channels, rate and format are the basic parameters, and that should be enough for 99.9% cases.
Excellent, will use this set as the constraint entry. Just to clarify for the upcoming Xen sound protocol change: the values in this constraint are not ALSA specific and could be used in implementation/OS agnostic Xen protocol.
I am still thinking on having the above sent at run-time with a new protocol command, which I will call on .open, so I can apply the constraints where most of the drivers do. This way backend can also determine its capabilities at run-time and report those to the frontend, as a bonus eliminating the need for huge domain configuration file/XenStore entries.
You don't have to list up all combinations of the parameters above at open time. For example, declaring min/max of each of them at open would suffice at first. (But this min/max might be even unnecessary if we implement the proper hw constraints. See below)
The rest fine-tuning is done via the hw constraints...
If we decide to negotiate the parameters, then it can't be done at .open stage as well, as at this moment we don't know stream parameters yet, e.g. we don't know the number of channels, PCM format etc., so we cannot explain to the backend what we want. Thus, it seems that we need to move the negotiation to .hw_params callback where stream properties are known. But this leaves the only option to ask the backend if it can handle the requested buffer/period and other parameters or not... This is what I do now :(
The additional parameter setup can be done via hw_constraints. The hw constraint is basically a function call for each parameter change to narrow down the range of the given parameter.
snd_pcm_hw_constraint_integer() in the above is just an example. The actual function to adjust values can be freely written.
Yes, this is clear, the question here mostly was not *how* to set the constraints, but *where* to get those
... and here comes the hw constraint into the play.
For each parameter change, for example, the frontend just passes the inquiry to the backend. The basis of the hw constraint is nothing but to reduce the range of the given parameter. It's either interval (range, used for period/buffer size or sample rate) or the list (for the format). When any parameter is changed, ALSA PCM core invokes the corresponding hw constraint function, and the function reduces the range. It's repeated until all parameters are set and settled down.
So, for your driver, the frontend just passes the hw constraint for each of basic 5 parameters to the backend. For example, at beginning, the hw constraint for the buffer size will pass the range (1,INTMAX). Then the backend returns the range like (1024,65536). This already gives users the min/max buffer size information. The similar procedure will be done for all other parameters.
In addition, you can put the implicit rule like the integer periods, which makes things easier.
Thank you very much for such a detailed explanation. Could you please give me an example of ALSA driver which code I can read in order to understand how it is supposed to be used, e.g. which meets the expectations we have for Xen PV sound driver?
Am I missing something here?
The format, the channels and the sample rate are already included in snd_pcm_hardware setup, so this should be OK, unless they have implicit limitations with each other (e.g. some format is available only under some rate).
Thank you, this should be up to the one who sets up the domain configuration. Taking into account embedded nature of our use-cases this is almost always doable, as these are defined at system design time, e.g. we define number of channels and their properties depending on domain functionality and needs.
Maybe the channels need to be revisited, though; usually you can't handle all number of channels between min and max but only even numbers or such.
But if backend can implement some fancy stuff with software mixing etc... This is why I didn't limit on that
But if the backend doesn't support fancy numbers like 3 channels? That's the same situation as buffer / periods. The frontend needs to know exactly what configuration the backend would allow.
Ok, did I understand you correctly that you see it as described above, e.g. backend communicates (limited) set of constraints to the frontend, so frontend sets these constraints at .open?
Well, what set at the open time is only the constraint "rule". And the rule is a function call, not necessarily static. The actual parameters are determined at hw_params call time, and this is called even repeatedly.
I need some time to think about all the above ;)
The way these are communicated could be either XenStore/ domain configuration or extension to the protocol, no preference from your side?
Again, the parameter setup pretty depends on the hardware, and in this case, the backend (and its communication).
Takashi
Thank you! Oleksandr
On Tue, 06 Mar 2018 17:04:41 +0100, Oleksandr Andrushchenko wrote:
If we decide to negotiate the parameters, then it can't be done at .open stage as well, as at this moment we don't know stream parameters yet, e.g. we don't know the number of channels, PCM format etc., so we cannot explain to the backend what we want. Thus, it seems that we need to move the negotiation to .hw_params callback where stream properties are known. But this leaves the only option to ask the backend if it can handle the requested buffer/period and other parameters or not... This is what I do now :(
The additional parameter setup can be done via hw_constraints. The hw constraint is basically a function call for each parameter change to narrow down the range of the given parameter.
snd_pcm_hw_constraint_integer() in the above is just an example. The actual function to adjust values can be freely written.
Yes, this is clear, the question here mostly was not *how* to set the constraints, but *where* to get those
... and here comes the hw constraint into the play.
For each parameter change, for example, the frontend just passes the inquiry to the backend. The basis of the hw constraint is nothing but to reduce the range of the given parameter. It's either interval (range, used for period/buffer size or sample rate) or the list (for the format). When any parameter is changed, ALSA PCM core invokes the corresponding hw constraint function, and the function reduces the range. It's repeated until all parameters are set and settled down.
So, for your driver, the frontend just passes the hw constraint for each of basic 5 parameters to the backend. For example, at beginning, the hw constraint for the buffer size will pass the range (1,INTMAX). Then the backend returns the range like (1024,65536). This already gives users the min/max buffer size information. The similar procedure will be done for all other parameters.
In addition, you can put the implicit rule like the integer periods, which makes things easier.
Thank you very much for such a detailed explanation. Could you please give me an example of ALSA driver which code I can read in order to understand how it is supposed to be used, e.g. which meets the expectations we have for Xen PV sound driver?
This is the most difficult part, apparently :) There are lots of codes deploying the own hw constraints, but nothing is similar like your case.
Suppose that we negotiate from the frontend to the backend like
int query_hw_param(int parm, int *min_p, int *max_p);
so that you can call like err = query_hw_param(PARM_RATE, &min_rate, &max_rate);
This assumes that min_rate and max_rate were already filled by the values requested from frontend user-space. In query_hw_parm, the backend receives this range, checks it, and fills again the actually applicable range that satisfies the given range in return.
In that way, user-space will reduce the configuration space repeatedly. And at the last step, the configurator chooses the optimal values that fit in the given configuration space.
As mentioned in the previous post, in your driver at open, you'd need to add the hw constraint for each parameter. That would be like:
err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, hw_rule_rate, NULL, -1);
and hw_rule_rate() would look like:
static int hw_rule_rate(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { struct snd_interval *p = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); int min_rate = p->min; int max_rate = p->max; struct snd_interval t; int err;
err = query_hw_param(PARM_RATE, &min_rate, &max_rate); if (err < 0) return err;
t.min = min_rate; t.max = max_rate; t.openmin = t.openmax = 0; t.integer = 1;
return snd_interval_refine(p, &t); }
The above is simplified not to allow the open min/max and assume only integer, which should be enough for your cases, I suppose.
And the above function can be generalized like
static int hw_rule_interval(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { struct snd_interval *p = hw_param_interval(params, rule->var); int min_val = p->min; int max_val = p->max; struct snd_interval t; int err;
err = query_hw_param(alsa_parm_to_xen_parm(rule->var), &min_val, &max_val); if (err < 0) return err;
t.min = min_val; t.max = max_val; t.openmin = t.openmax = 0; t.integer = 1;
return snd_interval_refine(p, &t); }
and registering this via
err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, hw_rule_interval, NULL, -1);
In the above NULL can be referred in the callback via rule->private, if you need some closure in the function, too.
Takashi
On 03/06/2018 06:30 PM, Takashi Iwai wrote:
On Tue, 06 Mar 2018 17:04:41 +0100, Oleksandr Andrushchenko wrote:
If we decide to negotiate the parameters, then it can't be done at .open stage as well, as at this moment we don't know stream parameters yet, e.g. we don't know the number of channels, PCM format etc., so we cannot explain to the backend what we want. Thus, it seems that we need to move the negotiation to .hw_params callback where stream properties are known. But this leaves the only option to ask the backend if it can handle the requested buffer/period and other parameters or not... This is what I do now :(
The additional parameter setup can be done via hw_constraints. The hw constraint is basically a function call for each parameter change to narrow down the range of the given parameter.
snd_pcm_hw_constraint_integer() in the above is just an example. The actual function to adjust values can be freely written.
Yes, this is clear, the question here mostly was not *how* to set the constraints, but *where* to get those
... and here comes the hw constraint into the play.
For each parameter change, for example, the frontend just passes the inquiry to the backend. The basis of the hw constraint is nothing but to reduce the range of the given parameter. It's either interval (range, used for period/buffer size or sample rate) or the list (for the format). When any parameter is changed, ALSA PCM core invokes the corresponding hw constraint function, and the function reduces the range. It's repeated until all parameters are set and settled down.
So, for your driver, the frontend just passes the hw constraint for each of basic 5 parameters to the backend. For example, at beginning, the hw constraint for the buffer size will pass the range (1,INTMAX). Then the backend returns the range like (1024,65536). This already gives users the min/max buffer size information. The similar procedure will be done for all other parameters.
In addition, you can put the implicit rule like the integer periods, which makes things easier.
Thank you very much for such a detailed explanation. Could you please give me an example of ALSA driver which code I can read in order to understand how it is supposed to be used, e.g. which meets the expectations we have for Xen PV sound driver?
This is the most difficult part, apparently :) There are lots of codes deploying the own hw constraints, but nothing is similar like your case.
Suppose that we negotiate from the frontend to the backend like
int query_hw_param(int parm, int *min_p, int *max_p);
so that you can call like err = query_hw_param(PARM_RATE, &min_rate, &max_rate);
This assumes that min_rate and max_rate were already filled by the values requested from frontend user-space. In query_hw_parm, the backend receives this range, checks it, and fills again the actually applicable range that satisfies the given range in return.
In that way, user-space will reduce the configuration space repeatedly. And at the last step, the configurator chooses the optimal values that fit in the given configuration space.
As mentioned in the previous post, in your driver at open, you'd need to add the hw constraint for each parameter. That would be like:
err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, hw_rule_rate, NULL, -1);
and hw_rule_rate() would look like:
static int hw_rule_rate(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { struct snd_interval *p = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); int min_rate = p->min; int max_rate = p->max; struct snd_interval t; int err;
err = query_hw_param(PARM_RATE, &min_rate, &max_rate); if (err < 0) return err;
t.min = min_rate; t.max = max_rate; t.openmin = t.openmax = 0; t.integer = 1;
return snd_interval_refine(p, &t); }
The above is simplified not to allow the open min/max and assume only integer, which should be enough for your cases, I suppose.
And the above function can be generalized like
static int hw_rule_interval(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { struct snd_interval *p = hw_param_interval(params, rule->var); int min_val = p->min; int max_val = p->max; struct snd_interval t; int err;
err = query_hw_param(alsa_parm_to_xen_parm(rule->var), &min_val, &max_val); if (err < 0) return err;
t.min = min_val; t.max = max_val; t.openmin = t.openmax = 0; t.integer = 1;
return snd_interval_refine(p, &t); }
and registering this via
err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, hw_rule_interval, NULL, -1);
In the above NULL can be referred in the callback via rule->private, if you need some closure in the function, too.
Thank you so much for that detailed explanation and code sample!!! This is really great to see such a comprehensive response. Meanwhile, I did a yet another change to the protocol (please find attached) which will be added to those two found in this patch set already: In order to provide explicit stream parameter negotiation between backend and frontend the following changes are introduced in the protocol: - add XENSND_OP_HW_PARAM_SET request to set one of the stream parameters: frame rate, sample rate, number of channels, buffer and period sizes - add XENSND_OP_HW_PARAM_QUERY request to read a reduced configuration space for the parameter given: in the response to this request return min/max interval for the parameter given - add minimum buffer size to XenStore configuration
With this change: 1. Frontend sends XENSND_OP_HW_PARAM_SET to the backend in response to user space's snd_pcm_hw_params_set_XXX calls, using XenStore entries as initial configuration space (this is what returned on snd_pcm_hw_params_any) 2. Frontend uses snd_pcm_hw_rule_add to set the rules (for sample rate, format, number of channels, buffer and period sizes) as you described above: querying is done with XENSND_OP_HW_PARAM_QUERY request 3. Finally, frontend issues XENSND_OP_OPEN request with all the negotiated configuration values
Questions:
1. For XENSND_OP_HW_PARAM_SET I will need a hook in the frontend driver so I can intercept snd_pcm_hw_params_set_XXX calls - is this available in ALSA?
2. From backend side, if it runs as ALSA client, it is almost 1:1 mapping for XENSND_OP_HW_PARAM_SET/snd_pcm_hw_params_set_XXX, so I can imagine how to do that. But what do I do if I run the backend as PulseAudio client?
3. Period size rules will not allow the check you mentioned before, e.g. require that buffer_size % period_size == 0). Can frontend driver assume that on its own? So, I simply add the rule regardless of what backend can?
4. Do you think the attached change together with the previous one ( which adds sync event) makes the protocol look good? Do we need any other change?
Takashi
Thank you very much for helping with this, Oleksandr
Hi,
sorry for the long latency.
On Wed, 07 Mar 2018 09:49:24 +0100, Oleksandr Andrushchenko wrote:
Suppose that we negotiate from the frontend to the backend like
int query_hw_param(int parm, int *min_p, int *max_p);
so that you can call like err = query_hw_param(PARM_RATE, &min_rate, &max_rate);
This assumes that min_rate and max_rate were already filled by the values requested from frontend user-space. In query_hw_parm, the backend receives this range, checks it, and fills again the actually applicable range that satisfies the given range in return.
In that way, user-space will reduce the configuration space repeatedly. And at the last step, the configurator chooses the optimal values that fit in the given configuration space.
As mentioned in the previous post, in your driver at open, you'd need to add the hw constraint for each parameter. That would be like:
err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, hw_rule_rate, NULL, -1);
and hw_rule_rate() would look like:
static int hw_rule_rate(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { struct snd_interval *p = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); int min_rate = p->min; int max_rate = p->max; struct snd_interval t; int err;
err = query_hw_param(PARM_RATE, &min_rate, &max_rate); if (err < 0) return err;
t.min = min_rate; t.max = max_rate; t.openmin = t.openmax = 0; t.integer = 1;
return snd_interval_refine(p, &t); }
The above is simplified not to allow the open min/max and assume only integer, which should be enough for your cases, I suppose.
And the above function can be generalized like
static int hw_rule_interval(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { struct snd_interval *p = hw_param_interval(params, rule->var); int min_val = p->min; int max_val = p->max; struct snd_interval t; int err;
err = query_hw_param(alsa_parm_to_xen_parm(rule->var), &min_val, &max_val); if (err < 0) return err;
t.min = min_val; t.max = max_val; t.openmin = t.openmax = 0; t.integer = 1;
return snd_interval_refine(p, &t); }
and registering this via
err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, hw_rule_interval, NULL, -1);
In the above NULL can be referred in the callback via rule->private, if you need some closure in the function, too.
Thank you so much for that detailed explanation and code sample!!! This is really great to see such a comprehensive response. Meanwhile, I did a yet another change to the protocol (please find attached) which will be added to those two found in this patch set already: In order to provide explicit stream parameter negotiation between backend and frontend the following changes are introduced in the protocol: - add XENSND_OP_HW_PARAM_SET request to set one of the stream parameters: frame rate, sample rate, number of channels, buffer and period sizes - add XENSND_OP_HW_PARAM_QUERY request to read a reduced configuration space for the parameter given: in the response to this request return min/max interval for the parameter given - add minimum buffer size to XenStore configuration
With this change:
- Frontend sends XENSND_OP_HW_PARAM_SET to the backend in response
to user space's snd_pcm_hw_params_set_XXX calls, using XenStore entries as initial configuration space (this is what returned on snd_pcm_hw_params_any) 2. Frontend uses snd_pcm_hw_rule_add to set the rules (for sample rate, format, number of channels, buffer and period sizes) as you described above: querying is done with XENSND_OP_HW_PARAM_QUERY request 3. Finally, frontend issues XENSND_OP_OPEN request with all the negotiated configuration values
Questions:
- For XENSND_OP_HW_PARAM_SET I will need a hook in the frontend driver
so I can intercept snd_pcm_hw_params_set_XXX calls - is this available in ALSA?
This is exactly the purpose of hw constraint rule you'd need to add. The callback function gets called at each time the corresponding parameter is changed (or the change is asked) by applications.
The final parameter setup is done in hw_params PCM callback, but each fine-tuning / adjustment beforehand is done via hw constraints.
- From backend side, if it runs as ALSA client, it is almost 1:1
mapping for XENSND_OP_HW_PARAM_SET/snd_pcm_hw_params_set_XXX, so I can imagine how to do that. But what do I do if I run the backend as PulseAudio client?
This pretty depends on your implementation :) I can imagine that the backend assumes a limited configuration depending on the backend application, e.g. PA can't handle the too short period.
- Period size rules will not allow the check you mentioned before, e.g.
require that buffer_size % period_size == 0). Can frontend driver assume that on its own? So, I simply add the rule regardless of what backend can?
Again it's up to your implementation of the backend side. If the backend can support such configuration (periods not aligned with buffer size), it's fine, of course.
I'd say it's safer to add this always, though. It makes often things easier.
- Do you think the attached change together with the previous one (
which adds sync event) makes the protocol look good? Do we need any other change?
I guess that'd be enough, but at best, give a rough version of your frontend driver code for checking. It's very hard to judge without the actual code.
thanks,
Takashi
On 03/11/2018 10:15 AM, Takashi Iwai wrote:
Hi,
sorry for the long latency.
Hi, no problem, thank you
On Wed, 07 Mar 2018 09:49:24 +0100, Oleksandr Andrushchenko wrote:
Suppose that we negotiate from the frontend to the backend like
int query_hw_param(int parm, int *min_p, int *max_p);
so that you can call like err = query_hw_param(PARM_RATE, &min_rate, &max_rate);
This assumes that min_rate and max_rate were already filled by the values requested from frontend user-space. In query_hw_parm, the backend receives this range, checks it, and fills again the actually applicable range that satisfies the given range in return.
In that way, user-space will reduce the configuration space repeatedly. And at the last step, the configurator chooses the optimal values that fit in the given configuration space.
As mentioned in the previous post, in your driver at open, you'd need to add the hw constraint for each parameter. That would be like:
err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, hw_rule_rate, NULL, -1);
and hw_rule_rate() would look like:
static int hw_rule_rate(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { struct snd_interval *p = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); int min_rate = p->min; int max_rate = p->max; struct snd_interval t; int err;
err = query_hw_param(PARM_RATE, &min_rate, &max_rate); if (err < 0) return err;
t.min = min_rate; t.max = max_rate; t.openmin = t.openmax = 0; t.integer = 1;
return snd_interval_refine(p, &t); }
The above is simplified not to allow the open min/max and assume only integer, which should be enough for your cases, I suppose.
And the above function can be generalized like
static int hw_rule_interval(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { struct snd_interval *p = hw_param_interval(params, rule->var); int min_val = p->min; int max_val = p->max; struct snd_interval t; int err;
err = query_hw_param(alsa_parm_to_xen_parm(rule->var), &min_val, &max_val); if (err < 0) return err;
t.min = min_val; t.max = max_val; t.openmin = t.openmax = 0; t.integer = 1;
return snd_interval_refine(p, &t); }
and registering this via
err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, hw_rule_interval, NULL, -1);
In the above NULL can be referred in the callback via rule->private, if you need some closure in the function, too.
Thank you so much for that detailed explanation and code sample!!! This is really great to see such a comprehensive response. Meanwhile, I did a yet another change to the protocol (please find attached) which will be added to those two found in this patch set already: In order to provide explicit stream parameter negotiation between backend and frontend the following changes are introduced in the protocol: - add XENSND_OP_HW_PARAM_SET request to set one of the stream parameters: frame rate, sample rate, number of channels, buffer and period sizes - add XENSND_OP_HW_PARAM_QUERY request to read a reduced configuration space for the parameter given: in the response to this request return min/max interval for the parameter given - add minimum buffer size to XenStore configuration
With this change:
- Frontend sends XENSND_OP_HW_PARAM_SET to the backend in response
to user space's snd_pcm_hw_params_set_XXX calls, using XenStore entries as initial configuration space (this is what returned on snd_pcm_hw_params_any) 2. Frontend uses snd_pcm_hw_rule_add to set the rules (for sample rate, format, number of channels, buffer and period sizes) as you described above: querying is done with XENSND_OP_HW_PARAM_QUERY request 3. Finally, frontend issues XENSND_OP_OPEN request with all the negotiated configuration values
Questions:
- For XENSND_OP_HW_PARAM_SET I will need a hook in the frontend driver
so I can intercept snd_pcm_hw_params_set_XXX calls - is this available in ALSA?
This is exactly the purpose of hw constraint rule you'd need to add. The callback function gets called at each time the corresponding parameter is changed (or the change is asked) by applications.
The final parameter setup is done in hw_params PCM callback, but each fine-tuning / adjustment beforehand is done via hw constraints.
Excellent
- From backend side, if it runs as ALSA client, it is almost 1:1
mapping for XENSND_OP_HW_PARAM_SET/snd_pcm_hw_params_set_XXX, so I can imagine how to do that. But what do I do if I run the backend as PulseAudio client?
This pretty depends on your implementation :) I can imagine that the backend assumes a limited configuration depending on the backend application, e.g. PA can't handle the too short period.
Ok, makes sense
- Period size rules will not allow the check you mentioned before, e.g.
require that buffer_size % period_size == 0). Can frontend driver assume that on its own? So, I simply add the rule regardless of what backend can?
Again it's up to your implementation of the backend side. If the backend can support such configuration (periods not aligned with buffer size), it's fine, of course.
I'd say it's safer to add this always, though. It makes often things easier.
Yes, probably I will put it by default
- Do you think the attached change together with the previous one (
which adds sync event) makes the protocol look good? Do we need any other change?
I guess that'd be enough, but at best, give a rough version of your frontend driver code for checking. It's very hard to judge without the actual code.
Great, I will try to model these (hopefully late this week) and come back: maybe I won't need some of the protocol operations at all. I will update ASAP
thanks,
Takashi
Thank you, Oleksandr
Hi,
On 03/12/2018 08:26 AM, Oleksandr Andrushchenko wrote:
On 03/11/2018 10:15 AM, Takashi Iwai wrote:
Hi,
sorry for the long latency.
Hi, no problem, thank you
On Wed, 07 Mar 2018 09:49:24 +0100, Oleksandr Andrushchenko wrote:
Suppose that we negotiate from the frontend to the backend like
int query_hw_param(int parm, int *min_p, int *max_p);
so that you can call like err = query_hw_param(PARM_RATE, &min_rate, &max_rate);
This assumes that min_rate and max_rate were already filled by the values requested from frontend user-space. In query_hw_parm, the backend receives this range, checks it, and fills again the actually applicable range that satisfies the given range in return.
In that way, user-space will reduce the configuration space repeatedly. And at the last step, the configurator chooses the optimal values that fit in the given configuration space.
As mentioned in the previous post, in your driver at open, you'd need to add the hw constraint for each parameter. That would be like:
err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, hw_rule_rate, NULL, -1);
and hw_rule_rate() would look like:
static int hw_rule_rate(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { struct snd_interval *p = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); int min_rate = p->min; int max_rate = p->max; struct snd_interval t; int err;
err = query_hw_param(PARM_RATE, &min_rate, &max_rate); if (err < 0) return err;
t.min = min_rate; t.max = max_rate; t.openmin = t.openmax = 0; t.integer = 1;
return snd_interval_refine(p, &t); }
The above is simplified not to allow the open min/max and assume only integer, which should be enough for your cases, I suppose.
And the above function can be generalized like
static int hw_rule_interval(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { struct snd_interval *p = hw_param_interval(params, rule->var); int min_val = p->min; int max_val = p->max; struct snd_interval t; int err;
err = query_hw_param(alsa_parm_to_xen_parm(rule->var), &min_val, &max_val); if (err < 0) return err;
t.min = min_val; t.max = max_val; t.openmin = t.openmax = 0; t.integer = 1;
return snd_interval_refine(p, &t); }
and registering this via
err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, hw_rule_interval, NULL, -1);
In the above NULL can be referred in the callback via rule->private, if you need some closure in the function, too.
Thank you so much for that detailed explanation and code sample!!! This is really great to see such a comprehensive response. Meanwhile, I did a yet another change to the protocol (please find attached) which will be added to those two found in this patch set already: In order to provide explicit stream parameter negotiation between backend and frontend the following changes are introduced in the protocol: - add XENSND_OP_HW_PARAM_SET request to set one of the stream parameters: frame rate, sample rate, number of channels, buffer and period sizes - add XENSND_OP_HW_PARAM_QUERY request to read a reduced configuration space for the parameter given: in the response to this request return min/max interval for the parameter given - add minimum buffer size to XenStore configuration
With this change:
- Frontend sends XENSND_OP_HW_PARAM_SET to the backend in response
to user space's snd_pcm_hw_params_set_XXX calls, using XenStore entries as initial configuration space (this is what returned on snd_pcm_hw_params_any) 2. Frontend uses snd_pcm_hw_rule_add to set the rules (for sample rate, format, number of channels, buffer and period sizes) as you described above: querying is done with XENSND_OP_HW_PARAM_QUERY request 3. Finally, frontend issues XENSND_OP_OPEN request with all the negotiated configuration values
Questions:
- For XENSND_OP_HW_PARAM_SET I will need a hook in the frontend driver
so I can intercept snd_pcm_hw_params_set_XXX calls - is this available in ALSA?
This is exactly the purpose of hw constraint rule you'd need to add. The callback function gets called at each time the corresponding parameter is changed (or the change is asked) by applications.
The final parameter setup is done in hw_params PCM callback, but each fine-tuning / adjustment beforehand is done via hw constraints.
Excellent
- From backend side, if it runs as ALSA client, it is almost 1:1
mapping for XENSND_OP_HW_PARAM_SET/snd_pcm_hw_params_set_XXX, so I can imagine how to do that. But what do I do if I run the backend as PulseAudio client?
This pretty depends on your implementation :) I can imagine that the backend assumes a limited configuration depending on the backend application, e.g. PA can't handle the too short period.
Ok, makes sense
- Period size rules will not allow the check you mentioned before,
e.g. require that buffer_size % period_size == 0). Can frontend driver assume that on its own? So, I simply add the rule regardless of what backend can?
Again it's up to your implementation of the backend side. If the backend can support such configuration (periods not aligned with buffer size), it's fine, of course.
I'd say it's safer to add this always, though. It makes often things easier.
Yes, probably I will put it by default
- Do you think the attached change together with the previous one (
which adds sync event) makes the protocol look good? Do we need any other change?
I guess that'd be enough, but at best, give a rough version of your frontend driver code for checking. It's very hard to judge without the actual code.
Great, I will try to model these (hopefully late this week) and come back: maybe I won't need some of the protocol operations at all. I will update ASAP
So, I tried to make a POC to stress the protocol changes and see what implementation of the HW parameter negotiation would look like.
Please find protocol changes at [1]: - add XENSND_OP_HW_PARAM_QUERY request to read/update configuration space for the parameter given: request passes desired parameter interval and the response to this request returns min/max interval for the parameter to be used. Parameters supported by this request: - frame rate - sample rate - number of channels - buffer size - period size - add minimum buffer size to XenStore configuration
From the previous changes to the protocol which I posted earlier I see that XENSND_OP_HW_PARAM_SET is not really needed - removed.
The implementation in the PV frontend driver is at [2].
Takashi, could you please take a look at the above if it meets your expectations so I can move forward?
thanks,
Takashi
Thank you, Oleksandr
Thank you very much, Oleksandr
[1] https://github.com/andr2000/linux/commit/2098a572f452d5247e538462dd1584369d3... [2] https://github.com/andr2000/linux/commit/022163b2c39bf3c8cca099f5b34f599b824...
On Tue, 13 Mar 2018 12:49:00 +0100, Oleksandr Andrushchenko wrote:
So, I tried to make a POC to stress the protocol changes and see what implementation of the HW parameter negotiation would look like.
Please find protocol changes at [1]:
- add XENSND_OP_HW_PARAM_QUERY request to read/update
configuration space for the parameter given: request passes desired parameter interval and the response to this request returns min/max interval for the parameter to be used. Parameters supported by this request: - frame rate - sample rate - number of channels - buffer size - period size - add minimum buffer size to XenStore configuration
From the previous changes to the protocol which I posted earlier I see that XENSND_OP_HW_PARAM_SET is not really needed - removed.
The implementation in the PV frontend driver is at [2].
Takashi, could you please take a look at the above if it meets your expectations so I can move forward?
This looks almost good through a quick glance. But the mixture of SNDRV_PCM_HW_PARAM_PERIOD_SIZE and SNDRV_PCM_HW_PARAM_BUFFER_BYTES are likely confusing. The *_SIZE means in frames unit while *_BYTES means in bytes. You should align both PERIOD_ and BUFFER_ to the same units, i.e. either use SNDRV_PCM_HW_PARAM_PERIOD_BYTES and *_BUFFER_BYTES, or SNDRV_PCM_HW_PARAM_PERIOD_SIZE and *_BUFFER_SIZE.
Also, a slightly remaining concern is the use-case where hw_params is called multiple times. An application may call hw_free and hw_params freely, or even hw_params calls multiple times, in order to change the parameter.
If the backend needs to resolve some dependency between parameters (e.g. the available period size depends on the sample rate), the backend has to remember the previously passed parameters.
So, instead of passing a single parameter, you may extend the protocol always to pass the full (five) parameters, too.
OTOH, this can be considered to be a minor case, and the backend (e.g. PA) can likely support every possible combinations, so maybe a simpler code may be a better solution in the end.
thanks,
Takashi
On 03/13/2018 06:31 PM, Takashi Iwai wrote:
On Tue, 13 Mar 2018 12:49:00 +0100, Oleksandr Andrushchenko wrote:
So, I tried to make a POC to stress the protocol changes and see what implementation of the HW parameter negotiation would look like.
Please find protocol changes at [1]:
- add XENSND_OP_HW_PARAM_QUERY request to read/update
configuration space for the parameter given: request passes desired parameter interval and the response to this request returns min/max interval for the parameter to be used. Parameters supported by this request: - frame rate - sample rate - number of channels - buffer size - period size - add minimum buffer size to XenStore configuration
From the previous changes to the protocol which I posted earlier I see that XENSND_OP_HW_PARAM_SET is not really needed - removed.
The implementation in the PV frontend driver is at [2].
Takashi, could you please take a look at the above if it meets your expectations so I can move forward?
This looks almost good through a quick glance. But the mixture of SNDRV_PCM_HW_PARAM_PERIOD_SIZE and SNDRV_PCM_HW_PARAM_BUFFER_BYTES are likely confusing. The *_SIZE means in frames unit while *_BYTES means in bytes. You should align both PERIOD_ and BUFFER_ to the same units, i.e. either use SNDRV_PCM_HW_PARAM_PERIOD_BYTES and *_BUFFER_BYTES, or SNDRV_PCM_HW_PARAM_PERIOD_SIZE and *_BUFFER_SIZE.
You are correct, fixed this at [1]
Also, a slightly remaining concern is the use-case where hw_params is called multiple times. An application may call hw_free and hw_params freely, or even hw_params calls multiple times, in order to change the parameter.
If the backend needs to resolve some dependency between parameters (e.g. the available period size depends on the sample rate), the backend has to remember the previously passed parameters.
So, instead of passing a single parameter, you may extend the protocol always to pass the full (five) parameters, too.
OTOH, this can be considered to be a minor case, and the backend (e.g. PA) can likely support every possible combinations, so maybe a simpler code may be a better solution in the end.
Yes, let's have it step by step. If you are ok with what we have at the moment then, after I implement both backend and frontend changes and confirm that protocol works, I will send v3 of the series (protocol changes).
Still there some questions: 1. Do we really need min buffer value as configuration [2]? I see no way it can be used, for instance at [3], we only have snd_pcm_hardware.buffer_bytes_max, but not min. So, I feel I can drop that
2. Can I assume that min buffer size == period size and add such a constraint in the frontend driver?
3. On backend side (ALSA), with current changes in the protocol I will call something like int snd_pcm_hw_params_set_channels_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *min, unsigned int *max)
instead of
int snd_pcm_hw_params_set_channels(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val)
while servicing XENSND_OP_HW_PARAM_QUERY.XENSND_OP_HW_PARAM_CHANNELS. Does this make sense?
thanks,
Takashi
Thank you, Oleksandr [1] https://github.com/andr2000/linux/commit/03e74fb23cf5baa2e252cd1e62fa9506dec... [2] https://github.com/andr2000/linux/blob/tiwai_sound_for_next_pv_snd_upstream_... [3] https://elixir.bootlin.com/linux/latest/source/include/sound/pcm.h#L53
On Tue, 13 Mar 2018 18:31:55 +0100, Oleksandr Andrushchenko wrote:
On 03/13/2018 06:31 PM, Takashi Iwai wrote:
On Tue, 13 Mar 2018 12:49:00 +0100, Oleksandr Andrushchenko wrote:
So, I tried to make a POC to stress the protocol changes and see what implementation of the HW parameter negotiation would look like.
Please find protocol changes at [1]:
- add XENSND_OP_HW_PARAM_QUERY request to read/update
configuration space for the parameter given: request passes desired parameter interval and the response to this request returns min/max interval for the parameter to be used. Parameters supported by this request: - frame rate - sample rate - number of channels - buffer size - period size - add minimum buffer size to XenStore configuration
From the previous changes to the protocol which I posted earlier I see that XENSND_OP_HW_PARAM_SET is not really needed - removed.
The implementation in the PV frontend driver is at [2].
Takashi, could you please take a look at the above if it meets your expectations so I can move forward?
This looks almost good through a quick glance. But the mixture of SNDRV_PCM_HW_PARAM_PERIOD_SIZE and SNDRV_PCM_HW_PARAM_BUFFER_BYTES are likely confusing. The *_SIZE means in frames unit while *_BYTES means in bytes. You should align both PERIOD_ and BUFFER_ to the same units, i.e. either use SNDRV_PCM_HW_PARAM_PERIOD_BYTES and *_BUFFER_BYTES, or SNDRV_PCM_HW_PARAM_PERIOD_SIZE and *_BUFFER_SIZE.
You are correct, fixed this at [1]
Also, a slightly remaining concern is the use-case where hw_params is called multiple times. An application may call hw_free and hw_params freely, or even hw_params calls multiple times, in order to change the parameter.
If the backend needs to resolve some dependency between parameters (e.g. the available period size depends on the sample rate), the backend has to remember the previously passed parameters.
So, instead of passing a single parameter, you may extend the protocol always to pass the full (five) parameters, too.
OTOH, this can be considered to be a minor case, and the backend (e.g. PA) can likely support every possible combinations, so maybe a simpler code may be a better solution in the end.
Yes, let's have it step by step. If you are ok with what we have at the moment then, after I implement both backend and frontend changes and confirm that protocol works, I will send v3 of the series (protocol changes).
Still there some questions:
- Do we really need min buffer value as configuration [2]? I see no
way it can be used, for instance at [3], we only have snd_pcm_hardware.buffer_bytes_max, but not min. So, I feel I can drop that
Actually with the hw_param query mechanism, this setup is moot. You can pass a fixed value that should be enough large for all cases there.
- Can I assume that min buffer size == period size and add such a
constraint in the frontend driver?
The buffer sie == period size is a special case, i.e. periods=1, and this won't work most likely. It's used only for a case like PA deployment without the period interrupt. And it needs a special hw_params flag your driver doesn't deal with.
So for the sane setup, you can safely assume min_periods=2.
- On backend side (ALSA), with current changes in the protocol I will
call something like int snd_pcm_hw_params_set_channels_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *min, unsigned int *max)
instead of
int snd_pcm_hw_params_set_channels(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val)
while servicing XENSND_OP_HW_PARAM_QUERY.XENSND_OP_HW_PARAM_CHANNELS. Does this make sense?
Yeah, that's better, I suppose.
Takashi
On 03/13/2018 08:48 PM, Takashi Iwai wrote:
On Tue, 13 Mar 2018 18:31:55 +0100, Oleksandr Andrushchenko wrote:
On 03/13/2018 06:31 PM, Takashi Iwai wrote:
On Tue, 13 Mar 2018 12:49:00 +0100, Oleksandr Andrushchenko wrote:
So, I tried to make a POC to stress the protocol changes and see what implementation of the HW parameter negotiation would look like.
Please find protocol changes at [1]:
add XENSND_OP_HW_PARAM_QUERY request to read/update configuration space for the parameter given: request passes desired parameter interval and the response to this request returns min/max interval for the parameter to be used. Parameters supported by this request: - frame rate - sample rate - number of channels - buffer size - period size - add minimum buffer size to XenStore configuration
From the previous changes to the protocol which I posted earlier I see
that XENSND_OP_HW_PARAM_SET is not really needed - removed.
The implementation in the PV frontend driver is at [2].
Takashi, could you please take a look at the above if it meets your expectations so I can move forward?
This looks almost good through a quick glance. But the mixture of SNDRV_PCM_HW_PARAM_PERIOD_SIZE and SNDRV_PCM_HW_PARAM_BUFFER_BYTES are likely confusing. The *_SIZE means in frames unit while *_BYTES means in bytes. You should align both PERIOD_ and BUFFER_ to the same units, i.e. either use SNDRV_PCM_HW_PARAM_PERIOD_BYTES and *_BUFFER_BYTES, or SNDRV_PCM_HW_PARAM_PERIOD_SIZE and *_BUFFER_SIZE.
You are correct, fixed this at [1]
Also, a slightly remaining concern is the use-case where hw_params is called multiple times. An application may call hw_free and hw_params freely, or even hw_params calls multiple times, in order to change the parameter.
If the backend needs to resolve some dependency between parameters (e.g. the available period size depends on the sample rate), the backend has to remember the previously passed parameters.
So, instead of passing a single parameter, you may extend the protocol always to pass the full (five) parameters, too.
OTOH, this can be considered to be a minor case, and the backend (e.g. PA) can likely support every possible combinations, so maybe a simpler code may be a better solution in the end.
Yes, let's have it step by step. If you are ok with what we have at the moment then, after I implement both backend and frontend changes and confirm that protocol works, I will send v3 of the series (protocol changes).
Still there some questions:
- Do we really need min buffer value as configuration [2]? I see no
way it can be used, for instance at [3], we only have snd_pcm_hardware.buffer_bytes_max, but not min. So, I feel I can drop that
Actually with the hw_param query mechanism, this setup is moot. You can pass a fixed value that should be enough large for all cases there.
ok, so only buffer max as it is already defined
- Can I assume that min buffer size == period size and add such a
constraint in the frontend driver?
The buffer sie == period size is a special case, i.e. periods=1, and this won't work most likely. It's used only for a case like PA deployment without the period interrupt. And it needs a special hw_params flag your driver doesn't deal with.
So for the sane setup, you can safely assume min_periods=2.
Thanks, will limit min to 2 periods then
- On backend side (ALSA), with current changes in the protocol I will
call something like int snd_pcm_hw_params_set_channels_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *min, unsigned int *max)
instead of
int snd_pcm_hw_params_set_channels(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val)
while servicing XENSND_OP_HW_PARAM_QUERY.XENSND_OP_HW_PARAM_CHANNELS. Does this make sense?
Yeah, that's better, I suppose.
Excellent
Takashi
Thank you very much for helping with this!!! Oleksandr Andrushchenko
participants (4)
-
Konrad Rzeszutek Wilk
-
Oleksandr Andrushchenko
-
Oleksandr Andrushchenko
-
Takashi Iwai