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"