diff mbox series

usb: u_audio: Notifying gadget audio device about starting/stopping capture/playback on the host

Message ID da466290-249c-d3d9-7b81-bed6a964a361@ivitera.com
State New
Headers show
Series usb: u_audio: Notifying gadget audio device about starting/stopping capture/playback on the host | expand

Commit Message

Pavel Hofman May 12, 2021, 8:47 a.m. UTC
Hi,

I am trying to notify the user-space code running on USB audio gadget
that the USB host has started/stopped capture/playback.

For stopping action, I am enclosing a patch snippet. I used snd_pcm_stop
code when alsa SPDIF receivers detect a change in the stream
https://github.com/torvalds/linux/blob/master/sound/i2c/other/ak4117.c#L505
When testing the code, aplay/arecord ends, sox just reports alsa device
warning and does not stop. IMO that is the desired outcome - the
snd_pcm_read/write methods returned errors when capture/playback on the
host side stopped.

For starting the capture/playback on the host, perhaps some
snd_ctl_notify on some dedicated alsa control could be used, notifying
the user space application that it can open the gadget audio device?

The patch below does not compile on upstream kernel as it uses changes
not included in upstream yet (explicit feedback EP, samplerate
switching), but I am just discussing principles and options now.

Thank you very much for your opinion and recommendations.

With regards,

Pavel.

Comments

Pavel Hofman May 24, 2021, 11:44 a.m. UTC | #1
Dne 12. 05. 21 v 10:47 Pavel Hofman napsal(a):
> Hi,

> 

> I am trying to notify the user-space code running on USB audio gadget

> that the USB host has started/stopped capture/playback.

> 

> For stopping action, I am enclosing a patch snippet. I used snd_pcm_stop

> code when alsa SPDIF receivers detect a change in the stream

> https://github.com/torvalds/linux/blob/master/sound/i2c/other/ak4117.c#L505

> When testing the code, aplay/arecord ends, sox just reports alsa device

> warning and does not stop. IMO that is the desired outcome - the

> snd_pcm_read/write methods returned errors when capture/playback on the

> host side stopped.

> 

> For starting the capture/playback on the host, perhaps some

> snd_ctl_notify on some dedicated alsa control could be used, notifying

> the user space application that it can open the gadget audio device?

> 

> The patch below does not compile on upstream kernel as it uses changes

> not included in upstream yet (explicit feedback EP, samplerate

> switching), but I am just discussing principles and options now.

> 

> Thank you very much for your opinion and recommendations.

> 


Hi, please may I ask for some feedback? The gadget has a great potential
but it's still missing features important for a smooth usage. I want to
add more patches but have not gotten any feedback in the last months. I
am "hoarding" audio gadget-related patches (not proper commit
descriptions in commits authored by me yet) in my repo
https://github.com/pavhofman/linux-rpi/commits/rpi-5.12.y for now. When
Ruslan's/Jerome's async feedback EP patches finally make it upstream I
will rebase accordingly.

Thank you,

Pavel.


> 

> 

> 

> 

> diff --git a/drivers/usb/gadget/function/u_audio.c

> b/drivers/usb/gadget/function/u_audio.c

> index 45367d650c5a..c6cdb844fec1 100644

> --- a/drivers/usb/gadget/function/u_audio.c

> +++ b/drivers/usb/gadget/function/u_audio.c

> @@ -565,6 +565,7 @@ int u_audio_start_capture(struct g_audio *audio_dev)

>  	struct uac_params *params = &audio_dev->params;

>  	int req_len, i;

> 

> +  dev_dbg(dev, "starting capture with rate %d\n", params->c_srate_active);

>  	ep = audio_dev->out_ep;

>  	prm = &uac->c_prm;

>  	config_ep_by_speed(gadget, &audio_dev->func, ep);

> @@ -635,6 +636,23 @@ EXPORT_SYMBOL_GPL(u_audio_start_capture);

>  void u_audio_stop_capture(struct g_audio *audio_dev)

>  {

>  	struct snd_uac_chip *uac = audio_dev->uac;

> +	unsigned long _flags;

> +	struct snd_pcm_substream *substream;

> +	struct uac_rtd_params *prm;

> +

> +  dev_dbg(uac->card->dev, "stopping capture\n");

> +  prm = &uac->c_prm;

> +  if (prm) {

> +    substream = prm->ss;

> +    if (substream) {

> +      dev_dbg(uac->card->dev, "stopping capture substream\n");

> +      snd_pcm_stream_lock_irqsave(substream, _flags);

> +      if (snd_pcm_running(substream)) {

> +        snd_pcm_stop(substream, SNDRV_PCM_STATE_DRAINING);

> +      }

> +      snd_pcm_stream_unlock_irqrestore(substream, _flags);

> +    }

> +  }

> 

>  	if (audio_dev->in_ep_fback)

>  		free_ep_fback(&uac->c_prm, audio_dev->in_ep_fback);

> @@ -655,7 +673,7 @@ int u_audio_start_playback(struct g_audio *audio_dev)

>  	const struct usb_endpoint_descriptor *ep_desc;

>  	int req_len, i;

> 

> -  dev_dbg(dev, "start playback with rate %d\n", params->p_srate_active);

> +  dev_dbg(dev, "starting playback with rate %d\n", params->p_srate_active);

>  	ep = audio_dev->in_ep;

>  	prm = &uac->p_prm;

>  	config_ep_by_speed(gadget, &audio_dev->func, ep);

> @@ -715,6 +733,23 @@ EXPORT_SYMBOL_GPL(u_audio_start_playback);

>  void u_audio_stop_playback(struct g_audio *audio_dev)

>  {

>  	struct snd_uac_chip *uac = audio_dev->uac;

> +  unsigned long _flags;

> +  struct snd_pcm_substream *substream;

> +  struct uac_rtd_params *prm;

> +

> +  dev_dbg(uac->card->dev, "stopping playback\n");

> +  prm = &uac->p_prm;

> +  if (prm) {

> +    substream = prm->ss;

> +    if (substream) {

> +      dev_dbg(uac->card->dev, "stopping playback substream\n");

> +      snd_pcm_stream_lock_irqsave(substream, _flags);

> +      if (snd_pcm_running(substream)) {

> +        snd_pcm_stop(substream, SNDRV_PCM_STATE_DRAINING);

> +      }

> +      snd_pcm_stream_unlock_irqrestore(substream, _flags);

> +    }

> +  }

> 

>  	free_ep(&uac->p_prm, audio_dev->in_ep);

>  }

>
diff mbox series

Patch

diff --git a/drivers/usb/gadget/function/u_audio.c
b/drivers/usb/gadget/function/u_audio.c
index 45367d650c5a..c6cdb844fec1 100644
--- a/drivers/usb/gadget/function/u_audio.c
+++ b/drivers/usb/gadget/function/u_audio.c
@@ -565,6 +565,7 @@  int u_audio_start_capture(struct g_audio *audio_dev)
 	struct uac_params *params = &audio_dev->params;
 	int req_len, i;

+  dev_dbg(dev, "starting capture with rate %d\n", params->c_srate_active);
 	ep = audio_dev->out_ep;
 	prm = &uac->c_prm;
 	config_ep_by_speed(gadget, &audio_dev->func, ep);
@@ -635,6 +636,23 @@  EXPORT_SYMBOL_GPL(u_audio_start_capture);
 void u_audio_stop_capture(struct g_audio *audio_dev)
 {
 	struct snd_uac_chip *uac = audio_dev->uac;
+	unsigned long _flags;
+	struct snd_pcm_substream *substream;
+	struct uac_rtd_params *prm;
+
+  dev_dbg(uac->card->dev, "stopping capture\n");
+  prm = &uac->c_prm;
+  if (prm) {
+    substream = prm->ss;
+    if (substream) {
+      dev_dbg(uac->card->dev, "stopping capture substream\n");
+      snd_pcm_stream_lock_irqsave(substream, _flags);
+      if (snd_pcm_running(substream)) {
+        snd_pcm_stop(substream, SNDRV_PCM_STATE_DRAINING);
+      }
+      snd_pcm_stream_unlock_irqrestore(substream, _flags);
+    }
+  }

 	if (audio_dev->in_ep_fback)
 		free_ep_fback(&uac->c_prm, audio_dev->in_ep_fback);
@@ -655,7 +673,7 @@  int u_audio_start_playback(struct g_audio *audio_dev)
 	const struct usb_endpoint_descriptor *ep_desc;
 	int req_len, i;

-  dev_dbg(dev, "start playback with rate %d\n", params->p_srate_active);
+  dev_dbg(dev, "starting playback with rate %d\n", params->p_srate_active);
 	ep = audio_dev->in_ep;
 	prm = &uac->p_prm;
 	config_ep_by_speed(gadget, &audio_dev->func, ep);
@@ -715,6 +733,23 @@  EXPORT_SYMBOL_GPL(u_audio_start_playback);
 void u_audio_stop_playback(struct g_audio *audio_dev)
 {
 	struct snd_uac_chip *uac = audio_dev->uac;
+  unsigned long _flags;
+  struct snd_pcm_substream *substream;
+  struct uac_rtd_params *prm;
+
+  dev_dbg(uac->card->dev, "stopping playback\n");
+  prm = &uac->p_prm;
+  if (prm) {
+    substream = prm->ss;
+    if (substream) {
+      dev_dbg(uac->card->dev, "stopping playback substream\n");
+      snd_pcm_stream_lock_irqsave(substream, _flags);
+      if (snd_pcm_running(substream)) {
+        snd_pcm_stop(substream, SNDRV_PCM_STATE_DRAINING);
+      }
+      snd_pcm_stream_unlock_irqrestore(substream, _flags);
+    }
+  }

 	free_ep(&uac->p_prm, audio_dev->in_ep);
 }