Hi,

If you have a USB audio device which uses the feedback endpoint, where the sample rate is not locked to the USB, you may want to try the attached patch. I will test it a bit more and then it will hit the tree next week.

The basic of the change is to reduce the number of sample rate adjustments. Some devices only update the sample rate very slowly, and the current USB audio driver is polling very fast, so the algorithm simply becomes unreliable with some kinds of USB audio devices.

--HPS
Index: sys/dev/sound/usb/uaudio.c
===================================================================
--- sys/dev/sound/usb/uaudio.c	(revision 278206)
+++ sys/dev/sound/usb/uaudio.c	(working copy)
@@ -111,6 +111,7 @@
     &uaudio_default_channels, 0, "uaudio default sample channels");
 #endif
 
+#define	UAUDIO_IRQS	(8000 / UAUDIO_NFRAMES)	/* interrupts per second */
 #define	UAUDIO_NFRAMES		64	/* must be factor of 8 due HS-USB */
 #define	UAUDIO_NCHANBUFS	2	/* number of outstanding request */
 #define	UAUDIO_RECURSE_LIMIT	255	/* rounds */
@@ -189,7 +190,6 @@
 	uint8_t	iface_index;
 	uint8_t	iface_alt_index;
 	uint8_t channels;
-	uint8_t enable_sync;
 };
 
 struct uaudio_chan {
@@ -226,11 +226,10 @@
 #define	CHAN_OP_STOP 2
 #define	CHAN_OP_DRAIN 3
 
-	uint8_t last_sync_time;
-	uint8_t last_sync_state;
-#define	UAUDIO_SYNC_NONE 0
-#define	UAUDIO_SYNC_MORE 1
-#define	UAUDIO_SYNC_LESS 2
+	/* USB audio feedback endpoint state */
+	int16_t last_sync_time;
+	int16_t last_sync_constant;	/* sample rate adjustment in Hz */
+	int16_t last_sync_remainder;
 };
 
 #define	UMIDI_EMB_JACK_MAX   16		/* units */
@@ -1799,14 +1798,6 @@
 		chan_alt->iface_index = curidx;
 		chan_alt->iface_alt_index = alt_index;
 
-		if (UEP_HAS_SYNCADDR(ed1) && ed1->bSynchAddress != 0) {
-			DPRINTF("Sync endpoint will be used, if present\n");
-			chan_alt->enable_sync = 1;
-		} else {
-			DPRINTF("Sync endpoint will not be used\n");
-			chan_alt->enable_sync = 0;
-		}
-
 		usbd_set_parent_iface(sc->sc_udev, curidx,
 		    sc->sc_mixer_iface_index);
 
@@ -2028,17 +2019,21 @@
 		while (temp > (sample_rate + (sample_rate / 2)))
 			temp /= 2;
 
-		/* compare */
-
 		DPRINTF("Comparing %d < %d\n",
 		    (int)temp, (int)sample_rate);
 
-		if (temp == sample_rate)
-			ch->last_sync_state = UAUDIO_SYNC_NONE;
-		else if (temp > sample_rate)
-			ch->last_sync_state = UAUDIO_SYNC_MORE;
-		else
-			ch->last_sync_state = UAUDIO_SYNC_LESS;
+		/* Update sync constant */
+		ch->last_sync_constant += (temp - sample_rate);
+
+		/*
+		 * Range check sync constant. We cannot change the
+		 * number of samples per second by more than the value
+		 * defined by "UAUDIO_IRQS":
+		 */
+		if (ch->last_sync_constant > UAUDIO_IRQS)
+			ch->last_sync_constant = UAUDIO_IRQS;
+		else if (ch->last_sync_constant < -UAUDIO_IRQS)
+			ch->last_sync_constant = -UAUDIO_IRQS;
 		break;
 
 	case USB_ST_SETUP:
@@ -2082,10 +2077,10 @@
 		}
 		chn_intr(ch->pcm_ch);
 
-		/* start SYNC transfer, if any */
-		if (ch->usb_alt[ch->cur_alt].enable_sync != 0) {
-			if ((ch->last_sync_time++ & 7) == 0)
-				usbd_transfer_start(ch->xfer[UAUDIO_NCHANBUFS]);
+		/* start the SYNC transfer one time per second, if any */
+		if (++(ch->last_sync_time) >= UAUDIO_IRQS) {
+			ch->last_sync_time = 0;
+			usbd_transfer_start(ch->xfer[UAUDIO_NCHANBUFS]);
 		}
 
 	case USB_ST_SETUP:
@@ -2120,21 +2115,22 @@
 			}
 
 			if (n == (blockcount - 1)) {
-				switch (ch->last_sync_state) {
-				case UAUDIO_SYNC_MORE:
+				/*
+				 * Update sync remainder and check if
+				 * we should transmit more or less
+				 * data:
+				 */
+				ch->last_sync_remainder += ch->last_sync_constant;
+				if (ch->last_sync_remainder >= UAUDIO_IRQS) {
+					ch->last_sync_remainder -= UAUDIO_IRQS;
 					DPRINTFN(6, "sending one sample more\n");
 					if ((frame_len + sample_size) <= mfl)
 						frame_len += sample_size;
-					ch->last_sync_state = UAUDIO_SYNC_NONE;
-					break;
-				case UAUDIO_SYNC_LESS:
+				} else if (ch->last_sync_remainder <= -UAUDIO_IRQS) {
+					ch->last_sync_remainder += UAUDIO_IRQS;
 					DPRINTFN(6, "sending one sample less\n");
 					if (frame_len >= sample_size)
 						frame_len -= sample_size;
-					ch->last_sync_state = UAUDIO_SYNC_NONE;
-					break;
-				default:
-					break;
 				}
 			}
 
_______________________________________________
freebsd-usb@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-usb
To unsubscribe, send any mail to "freebsd-usb-unsubscr...@freebsd.org"

Reply via email to