[PATCH v2 3/4] usb: gadget: f_uac2: send reasonably sized packets

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The UAC2 function driver currently responds to all packets at all times
with wMaxPacketSize packets. That results in way too fast audio
playback as the function driver (which is in fact supposed to define
the audio stream pace) delivers as fast as it can.

Fix this by pre-calculating the size of each packet to meet the
requested sample rate and format. This won't be 100% accurate, but
that's acceptable. Audio applications have to adopt to the stream's
rate anyway. The important thing here is to make f_uac2 operate at
least rougly in the range of speed that is expected by the host.

Signed-off-by: Daniel Mack <zonque@xxxxxxxxx>
---
 drivers/usb/gadget/function/f_uac2.c | 27 ++++++++++++++++++++++++++-
 1 file changed, 26 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c
index efe8add..610a2f1 100644
--- a/drivers/usb/gadget/function/f_uac2.c
+++ b/drivers/usb/gadget/function/f_uac2.c
@@ -92,6 +92,8 @@ struct snd_uac2_chip {
 
 	struct snd_card *card;
 	struct snd_pcm *pcm;
+
+	unsigned int c_pktsize;
 };
 
 #define BUFF_SIZE_MAX	(PAGE_SIZE * 16)
@@ -187,7 +189,7 @@ agdev_iso_complete(struct usb_ep *ep, struct usb_request *req)
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		src = prm->dma_area + prm->hw_ptr;
-		req->actual = req->length;
+		req->length = req->actual = uac2->c_pktsize;
 		dst = req->buf;
 	} else {
 		dst = prm->dma_area + prm->hw_ptr;
@@ -1046,6 +1048,28 @@ err:
 	return -EINVAL;
 }
 
+static void
+afunc_set_c_pktsize(struct usb_gadget *gadget, struct audio_dev *agdev)
+{
+	struct usb_endpoint_descriptor *ep_desc;
+	unsigned int rate, factor, interval;
+	struct f_uac2_opts *opts =
+		container_of(agdev->func.fi, struct f_uac2_opts, func_inst);
+
+	if (gadget->speed == USB_SPEED_FULL) {
+		ep_desc = &fs_epin_desc;
+		factor = 1000;
+	} else {
+		ep_desc = &hs_epin_desc;
+		factor = 125;
+	}
+
+	interval = (1 << (ep_desc->bInterval - 1)) * factor;
+	rate = opts->c_srate * opts->c_ssize * num_channels(opts->c_chmask);
+	agdev->uac2.c_pktsize =
+		min_t(unsigned int, rate / interval, ep_desc->wMaxPacketSize);
+}
+
 static int
 afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt)
 {
@@ -1084,6 +1108,7 @@ afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt)
 		prm = &uac2->p_prm;
 		config_ep_by_speed(gadget, fn, ep);
 		agdev->as_in_alt = alt;
+		afunc_set_c_pktsize(gadget, agdev);
 	} else {
 		dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
 		return -EINVAL;
-- 
2.1.0

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux