Re: Audio I/O parameters

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

 



On Fri, 26 Jul 2013, Clemens Ladisch wrote:

> Alan Stern wrote:
> > On Thu, 25 Jul 2013, James Stone wrote:
> >> The only slight difference I can see is that maybe the 3.10 uses
> >> slightly higher CPU load than 3.5 at the ridiculously low latency of
> >> 64 frames/period duplex.
> >
> > With the new patch, what you actually get is 44.1 frames/period (on
> > average).
> 
> In ALSA, the number of frames per period is a constant integer, and Jack
> requires it to be a power of two.  (Where "frame" is an audio frame, and
> "period" is the interval between interrupts reported to user space.)
> 
> With a sample rate of 44100 Hz and a packet rate of 8000 Hz, there
> should be about 5.5 samples per packet.  With a period size of 64 audio
> frames, this results in about 11.6 packets per period.
> 
> The driver does not completely fill URBs to ensure that interrupts
> happen at period boundaries.

Oho!  I missed all that period_elapsed stuff in prepare_playback_urb()!
But you don't do the same thing for recording URBs -- presumably
because you can't tell in advance how many samples the device will
send.

This makes the calculation of the number of URBs more complicated.  
Revised patch below.

James, can you try this out and send me the usbmon trace?  At 64
frames/period this should end up using 4 URBs, which is the minimum
requirement if there are no more than 8 packets per URB and an
incompletely filled URB can contain as few as 1 packets.  With this
patch, there should be no difficulty going down to 32 or maybe even 16
frames/period.

One more thing: I don't understand the calculations involving delay,
est_delay, last_delay, and so on in pcm.c.  Regardless, they appear not
to be as good as they could be, because they don't use
urb->start_frame.

> > Another problem, not necessarily a bad one: The feedback data from the
> > sound device indicates that its internal clock is actually running at
> > 45168 Hz, even though it claims to be running at 44100.
> 
> The feedback data is not measured in "real Hz" (wall clock time) but
> relatively to the 8 kHz bus clock.  Furthermore, it does not show the
> device's internal clock but the rate at which the device wants to
> receive frames; this can be higher at the beginning of a stream if the
> device has an empty FIFO and wants to fill it up.

Sorry, this was a miscalculation on my part.  I divided the value from 
the device by 8000 instead of 8192.  The correct calculation shows the 
internal clock is running at 44109 Hz.  Close enough.

Alan Stern



Index: usb-3.10/sound/usb/endpoint.c
===================================================================
--- usb-3.10.orig/sound/usb/endpoint.c
+++ usb-3.10/sound/usb/endpoint.c
@@ -575,6 +575,7 @@ static int data_ep_set_params(struct snd
 			      struct snd_usb_endpoint *sync_ep)
 {
 	unsigned int maxsize, i, urb_packs, total_packs, packs_per_ms;
+	unsigned int min_queued_packs, max_packs;
 	int is_playback = usb_pipeout(ep->pipe);
 	int frame_bits = snd_pcm_format_physical_width(pcm_format) * channels;
 
@@ -608,11 +609,21 @@ static int data_ep_set_params(struct snd
 	else
 		ep->curpacksize = maxsize;
 
-	if (snd_usb_get_speed(ep->chip->dev) != USB_SPEED_FULL)
+	if (snd_usb_get_speed(ep->chip->dev) != USB_SPEED_FULL) {
 		packs_per_ms = 8 >> ep->datainterval;
-	else
+
+		/* high speed needs 10 USB uframes on the queue at all times */
+		min_queued_packs = DIV_ROUND_UP(10, 8 / packs_per_ms);
+		max_packs = MAX_PACKS_HS;
+	} else {
 		packs_per_ms = 1;
 
+		/* full speed needs one USB frame on the queue at all times */
+		min_queued_packs = 1;
+		max_packs = MAX_PACKS;
+	}
+	max_packs = min(max_packs, MAX_QUEUE * packs_per_ms);
+
 	if (is_playback && !snd_usb_endpoint_implicit_feedback_sink(ep)) {
 		urb_packs = max(ep->chip->nrpacks, 1);
 		urb_packs = min(urb_packs, (unsigned int) MAX_PACKS);
@@ -625,42 +636,46 @@ static int data_ep_set_params(struct snd
 	if (sync_ep && !snd_usb_endpoint_implicit_feedback_sink(ep))
 		urb_packs = min(urb_packs, 1U << sync_ep->syncinterval);
 
-	/* decide how many packets to be used */
-	if (is_playback && !snd_usb_endpoint_implicit_feedback_sink(ep)) {
-		unsigned int minsize, maxpacks;
-		/* determine how small a packet can be */
-		minsize = (ep->freqn >> (16 - ep->datainterval))
-			  * (frame_bits >> 3);
-		/* with sync from device, assume it can be 12% lower */
-		if (sync_ep)
-			minsize -= minsize >> 3;
-		minsize = max(minsize, 1u);
-		total_packs = (period_bytes + minsize - 1) / minsize;
-		/* we need at least two URBs for queueing */
-		if (total_packs < 2) {
-			total_packs = 2;
-		} else {
-			/* and we don't want too long a queue either */
-			maxpacks = max(MAX_QUEUE * packs_per_ms, urb_packs * 2);
-			total_packs = min(total_packs, maxpacks);
+	/* each URB must fit into one period */
+	urb_packs = min(urb_packs, period_bytes / maxsize);
+	urb_packs = max(1u, urb_packs);
+
+	if (is_playback) {
+		unsigned int min_packs_per_period, urbs_per_period;
+		unsigned int queued_periods, leftover_packs;
+
+		/*
+		 * Allocate one more URB than needed to fill the minimum
+		 * USB queue.  The calculation is complicated because URBs
+		 * don't always have the same number of packets.  At the
+		 * end of a period, the number of packets is reduced so
+		 * that the URB just reaches the period's end.
+		 */
+
+		/* how few packets and URBs can fill out a period? */
+		min_packs_per_period = max(1u, period_bytes / maxsize);
+		urbs_per_period = DIV_ROUND_UP(min_packs_per_period, urb_packs);
+
+		/* how many periods in the minimum queue size? */
+		queued_periods = min_queued_packs / min_packs_per_period;
+		leftover_packs = min_queued_packs % min_packs_per_period;
+
+		/* at least one more URB than needed for the minimum queue */
+		ep->nurbs = 1 + queued_periods * urbs_per_period;
+		if (leftover_packs > 0) {
+			/* the queue might begin with a one-packet URB */
+			ep->nurbs += 1 + DIV_ROUND_UP(leftover_packs - 1,
+					urb_packs);
 		}
 	} else {
-		while (urb_packs > 1 && urb_packs * maxsize >= period_bytes)
-			urb_packs >>= 1;
-		total_packs = MAX_URBS * urb_packs;
+		ep->nurbs = 1 + DIV_ROUND_UP(min_queued_packs, urb_packs);
 	}
 
-	ep->nurbs = (total_packs + urb_packs - 1) / urb_packs;
-	if (ep->nurbs > MAX_URBS) {
-		/* too much... */
-		ep->nurbs = MAX_URBS;
-		total_packs = MAX_URBS * urb_packs;
-	} else if (ep->nurbs < 2) {
-		/* too little - we need at least two packets
-		 * to ensure contiguous playback/capture
-		 */
-		ep->nurbs = 2;
+	if (ep->nurbs * urb_packs > max_packs) {
+		/* too much -- URBs have too many packets */
+		urb_packs = max_packs / ep->nurbs;
 	}
+	total_packs = ep->nurbs * urb_packs;
 
 	/* allocate and initialize data urbs */
 	for (i = 0; i < ep->nurbs; i++) {

--
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