Date: Sat, 07 Feb 2015 16:21:01 +0100 From: Hans Petter Selasky <hps@selasky.org> To: freebsd-usb@freebsd.org, freebsd-multimedia@FreeBSD.org Subject: USB audio patch Message-ID: <54D62D5D.2000201@selasky.org>
next in thread | raw e-mail | index | archive | help
This is a multi-part message in MIME format. --------------080502000008090701010708 Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 7bit 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 --------------080502000008090701010708 Content-Type: text/x-patch; name="uaudio.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="uaudio.patch" 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; } } --------------080502000008090701010708--
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?54D62D5D.2000201>