Linux USB
 help / color / mirror / Atom feed
From: Pavel Hofman <pavel.hofman@ivitera.com>
To: "linux-usb@vger.kernel.org" <linux-usb@vger.kernel.org>,
	"alsa-devel@alsa-project.org" <alsa-devel@alsa-project.org>
Cc: Ruslan Bilovol <ruslan.bilovol@gmail.com>,
	Jerome Brunet <jbrunet@baylibre.com>,
	Julian Scheel <julian@jusst.de>, Takashi Iwai <tiwai@suse.de>
Subject: Re: RFC: usb: gadget: u_audio: Notifying gadget that host started playback/capture?
Date: Fri, 1 Oct 2021 14:38:45 +0200	[thread overview]
Message-ID: <35766f0f-784d-d37a-6d07-665f9ee88331@ivitera.com> (raw)
In-Reply-To: <6ebc2456-a46b-bc47-da76-7a341414c1fb@ivitera.com>

[-- Attachment #1: Type: text/plain, Size: 2097 bytes --]

Hi,

Dne 08. 09. 21 v 10:21 Pavel Hofman napsal(a):
> Hi,
> 
> The current audio gadget has no way to inform the gadget side that the 
> host side has started playback/capture and that gadget-side alsa 
> processes should be started.
> 
> Playback/capture processes on the host side do not get stuck without the 
> gadget side consuming/producing data (OUT requests are ignored in 
> u_audio_iso_complete, IN ones send initial zeros in their req->buf).
> 
> However, playback/capture processes on the gadget side get stuck without 
> the host side sending playback OUT packets or capture IN requests and 
> time out with error. If there was a way to inform the gadget side that 
> playback/capture has started on the host side, the gadget clients could 
> react accordingly.
> 

I drafted a simple patch for u_audio.c which defines read-only boolean 
ctl elems "Capture Requested" and "Playback Requested". Their values are 
set/reset in methods u_audio_start_capture/playback and 
u_audio_stop_capture/playback, i.e. at changes of respective altsettings 
from 0 to 1 and back. Every ctl elem value change sends notification via 
snd_ctl_notify. The principle works OK for capture/playback start/stop 
on the host, as monitored by alsactl:

pi@raspberrypi:~ $ alsactl monitor hw:UAC2Gadget
node hw:UAC2Gadget, #4 (3,0,0,Capture Requested,0) VALUE
node hw:UAC2Gadget, #4 (3,0,0,Capture Requested,0) VALUE
node hw:UAC2Gadget, #3 (3,0,0,Playback Requested,0) VALUE
node hw:UAC2Gadget, #3 (3,0,0,Playback Requested,0) VALUE

However at enumeration the USB host switches both playback and capture 
altsettings repeatedly, generating "fake" events from the gadget side 
POW. The host even sends regular-sized EP-OUT packets filled with zeros 
during enumeration (tested on linux only for now).

Please is there any way to "detect" the enumeration stage to mask out 
the "fake" playback/capture start/stop events?

The attached patch does not apply cleanly to mainline u_audio.c because 
it's rebased on other patches not submitted yet but it's only a 
discussion inducer for now.

Thanks a lot,

Pavel.

[-- Attachment #2: patch.diff --]
[-- Type: text/x-patch, Size: 5116 bytes --]

diff --git a/drivers/usb/gadget/function/u_audio.c b/drivers/usb/gadget/function/u_audio.c
index e395be32275c..69aef4e3677d 100644
--- a/drivers/usb/gadget/function/u_audio.c
+++ b/drivers/usb/gadget/function/u_audio.c
@@ -34,6 +34,8 @@ enum {
 	UAC_VOLUME_CTRL,
 	UAC_CAPTURE_RATE_CTRL,
 	UAC_PLAYBACK_RATE_CTRL,
+	UAC_CAPTURE_REQ_CTRL,
+	UAC_PLAYBACK_REQ_CTRL,
 };
 
 /* Runtime data params for one stream */
@@ -63,6 +65,9 @@ struct uac_rtd_params {
   s16 volume_min, volume_max, volume_res;
   s16 volume;
   int mute;
+  /* playback/capture_is_requested and their state */
+  struct snd_kcontrol *snd_kctl_is_req;
+  int is_requested;
 
   spinlock_t lock; /* lock for control transfers */
 
@@ -542,6 +547,8 @@ int u_audio_set_playback_srate(struct g_audio *audio_dev, int srate)
 }
 EXPORT_SYMBOL_GPL(u_audio_set_playback_srate);
 
+static void update_is_requested(struct uac_rtd_params *prm, unsigned int val);
+
 int u_audio_start_capture(struct g_audio *audio_dev)
 {
 	struct snd_uac_chip *uac = audio_dev->uac;
@@ -553,6 +560,7 @@ int u_audio_start_capture(struct g_audio *audio_dev)
 	struct uac_params *params = &audio_dev->params;
 	int req_len, i;
 
+	update_is_requested(&uac->c_prm, 1);
 	ep = audio_dev->out_ep;
 	prm = &uac->c_prm;
 	config_ep_by_speed(gadget, &audio_dev->func, ep);
@@ -625,6 +633,7 @@ void u_audio_stop_capture(struct g_audio *audio_dev)
 {
 	struct snd_uac_chip *uac = audio_dev->uac;
 
+	update_is_requested(&uac->c_prm, 0);
 	if (audio_dev->in_ep_fback)
 		free_ep_fback(&uac->c_prm, audio_dev->in_ep_fback);
 	free_ep(&uac->c_prm, audio_dev->out_ep);
@@ -645,6 +654,7 @@ int u_audio_start_playback(struct g_audio *audio_dev)
 	int req_len, i;
 	unsigned int p_interval, p_pktsize, p_pktsize_residue;
 
+	update_is_requested(&uac->p_prm, 1);
 	dev_dbg(dev, "start playback with rate %d\n", params->p_srate_active);
 	ep = audio_dev->in_ep;
 	prm = &uac->p_prm;
@@ -711,6 +721,7 @@ void u_audio_stop_playback(struct g_audio *audio_dev)
 {
 	struct snd_uac_chip *uac = audio_dev->uac;
 
+	update_is_requested(&uac->p_prm, 0);
 	free_ep(&uac->p_prm, audio_dev->in_ep);
 }
 EXPORT_SYMBOL_GPL(u_audio_stop_playback);
@@ -1027,6 +1038,27 @@ static int uac_pcm_rate_get(struct snd_kcontrol *kcontrol,
 	return 0;
 }
 
+static int u_audio_stream_requested_info(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	uinfo->value.integer.step = 1;
+
+	return 0;
+}
+
+static int u_audio_stream_requested_get(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct uac_rtd_params *prm = snd_kcontrol_chip(kcontrol);
+	ucontrol->value.integer.value[0] = prm->is_requested;
+	return 0;
+}
+
+
 static struct snd_kcontrol_new u_audio_controls[]  = {
   [UAC_FBACK_CTRL] {
     .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
@@ -1072,8 +1104,35 @@ static struct snd_kcontrol_new u_audio_controls[]  = {
 		.get = uac_pcm_rate_get,
 		.private_value = SNDRV_PCM_STREAM_PLAYBACK,
 		},
+  [UAC_CAPTURE_REQ_CTRL] {
+    .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
+    .name =         "Capture Requested",
+    .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+    .info =         u_audio_stream_requested_info,
+    .get =          u_audio_stream_requested_get,
+    .private_value = SNDRV_PCM_STREAM_CAPTURE,
+  },
+  [UAC_PLAYBACK_REQ_CTRL] {
+    .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
+    .name =         "Playback Requested",
+    .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+    .info =         u_audio_stream_requested_info,
+    .get =          u_audio_stream_requested_get,
+    .private_value = SNDRV_PCM_STREAM_PLAYBACK,
+  },
 };
 
+static void update_is_requested(struct uac_rtd_params *prm, unsigned int val) {
+	struct snd_kcontrol *kctl = prm->snd_kctl_is_req;
+
+	if (prm->is_requested != val) {
+		prm->is_requested = val;
+		snd_ctl_notify(prm->uac->card, SNDRV_CTL_EVENT_MASK_VALUE,
+				&kctl->id);
+		pr_debug("Setting '%s' to %d", kctl->id.name, val);
+	}
+}
+
 int g_audio_setup(struct g_audio *g_audio, const char *pcm_name,
 					const char *card_name)
 {
@@ -1209,6 +1268,38 @@ int g_audio_setup(struct g_audio *g_audio, const char *pcm_name,
 		err = snd_ctl_add(card, kctl);
 		if (err < 0)
 			goto snd_fail;
+
+		kctl = snd_ctl_new1(&u_audio_controls[UAC_PLAYBACK_REQ_CTRL],
+						&uac->p_prm);
+		if (!kctl) {
+			err = -ENOMEM;
+			goto snd_fail;
+		}
+
+		kctl->id.device = pcm->device;
+		kctl->id.subdevice = 0;
+
+		err = snd_ctl_add(card, kctl);
+		if (err < 0)
+			goto snd_fail;
+		(&uac->p_prm)->snd_kctl_is_req = kctl;
+	}
+
+	if (c_chmask) {
+		kctl = snd_ctl_new1(&u_audio_controls[UAC_CAPTURE_REQ_CTRL],
+					&uac->c_prm);
+		if (!kctl) {
+			err = -ENOMEM;
+			goto snd_fail;
+		}
+
+		kctl->id.device = pcm->device;
+		kctl->id.subdevice = 0;
+
+		err = snd_ctl_add(card, kctl);
+		if (err < 0)
+			goto snd_fail;
+		(&uac->c_prm)->snd_kctl_is_req = kctl;
 	}
 
 	for (i = 0; i <= SNDRV_PCM_STREAM_LAST; i++) {

  reply	other threads:[~2021-10-01 12:38 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-09-08  8:21 RFC: usb: gadget: u_audio: Notifying gadget that host started playback/capture? Pavel Hofman
2021-10-01 12:38 ` Pavel Hofman [this message]
2023-09-21  1:30   ` Arun Raghavan
2023-09-22  7:09     ` Pavel Hofman
2023-10-04 23:15       ` Arun Raghavan
2023-10-05 14:30         ` Pavel Hofman
2023-10-25 16:33           ` Arun Raghavan
2023-10-30 16:19             ` Arun Raghavan

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=35766f0f-784d-d37a-6d07-665f9ee88331@ivitera.com \
    --to=pavel.hofman@ivitera.com \
    --cc=alsa-devel@alsa-project.org \
    --cc=jbrunet@baylibre.com \
    --cc=julian@jusst.de \
    --cc=linux-usb@vger.kernel.org \
    --cc=ruslan.bilovol@gmail.com \
    --cc=tiwai@suse.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox