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 |
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 --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); }