From owner-svn-src-stable-9@FreeBSD.ORG Fri Feb 13 07:52:13 2015 Return-Path: Delivered-To: svn-src-stable-9@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 1707EDF0; Fri, 13 Feb 2015 07:52:13 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id EC2FE913; Fri, 13 Feb 2015 07:52:12 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id t1D7qC0a013429; Fri, 13 Feb 2015 07:52:12 GMT (envelope-from hselasky@FreeBSD.org) Received: (from hselasky@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id t1D7qCfm013428; Fri, 13 Feb 2015 07:52:12 GMT (envelope-from hselasky@FreeBSD.org) Message-Id: <201502130752.t1D7qCfm013428@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: hselasky set sender to hselasky@FreeBSD.org using -f From: Hans Petter Selasky Date: Fri, 13 Feb 2015 07:52:12 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-9@freebsd.org Subject: svn commit: r278665 - stable/9/sys/dev/sound/usb X-SVN-Group: stable-9 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-stable-9@freebsd.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: SVN commit messages for only the 9-stable src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 13 Feb 2015 07:52:13 -0000 Author: hselasky Date: Fri Feb 13 07:52:12 2015 New Revision: 278665 URL: https://svnweb.freebsd.org/changeset/base/278665 Log: MFC r278503: Revert r274918 and make a better solution. Poll the synchronisation endpoint less frequently to make the sample rate adjustment more accurate. This should resolve problems with the DN32-USB module for Midas audio systems and possibly other similar products from Klark Teknik. Modified: stable/9/sys/dev/sound/usb/uaudio.c Directory Properties: stable/9/sys/ (props changed) stable/9/sys/dev/ (props changed) Modified: stable/9/sys/dev/sound/usb/uaudio.c ============================================================================== --- stable/9/sys/dev/sound/usb/uaudio.c Fri Feb 13 07:51:26 2015 (r278664) +++ stable/9/sys/dev/sound/usb/uaudio.c Fri Feb 13 07:52:12 2015 (r278665) @@ -117,6 +117,7 @@ SYSCTL_INT(_hw_usb_uaudio, OID_AUTO, def &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 */ @@ -195,7 +196,6 @@ struct uaudio_chan_alt { uint8_t iface_index; uint8_t iface_alt_index; uint8_t channels; - uint8_t enable_sync; }; struct uaudio_chan { @@ -232,11 +232,12 @@ struct uaudio_chan { #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 */ + struct { + uint16_t time; /* I/O interrupt count */ + int16_t constant; /* sample rate adjustment in Hz */ + int16_t remainder; /* current remainder */ + } feedback; }; #define UMIDI_EMB_JACK_MAX 16 /* units */ @@ -1805,14 +1806,6 @@ uaudio_chan_fill_info_sub(struct uaudio_ 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); @@ -2022,29 +2015,44 @@ uaudio_chan_play_sync_callback(struct us if (temp == 0) break; - /* correctly scale value */ - - temp = (temp * 125ULL) - 64; + temp *= 125ULL; /* auto adjust */ - while (temp < (sample_rate - (sample_rate / 4))) temp *= 2; - + while (temp > (sample_rate + (sample_rate / 2))) temp /= 2; - /* compare */ + /* + * Some USB audio devices only report a sample rate + * different from the nominal one when they want one + * more or less sample. Make sure we catch this case + * by pulling the sample rate offset slowly towards + * zero if the reported value is equal to the sample + * rate. + */ + if (temp > sample_rate) + ch->feedback.constant += 1; + else if (temp < sample_rate) + ch->feedback.constant -= 1; + else if (ch->feedback.constant > 0) + ch->feedback.constant--; + else if (ch->feedback.constant < 0) + ch->feedback.constant++; - DPRINTF("Comparing %d < %d\n", - (int)temp, (int)sample_rate); + DPRINTF("Comparing %d Hz :: %d Hz :: %d samples drift\n", + (int)temp, (int)sample_rate, (int)ch->feedback.constant); - 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; + /* + * Range check sync constant. We cannot change the + * number of samples per second by more than the value + * defined by "UAUDIO_IRQS": + */ + if (ch->feedback.constant > UAUDIO_IRQS) + ch->feedback.constant = UAUDIO_IRQS; + else if (ch->feedback.constant < -UAUDIO_IRQS) + ch->feedback.constant = -UAUDIO_IRQS; break; case USB_ST_SETUP: @@ -2088,10 +2096,10 @@ tr_transferred: } 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->feedback.time) >= UAUDIO_IRQS) { + ch->feedback.time = 0; + usbd_transfer_start(ch->xfer[UAUDIO_NCHANBUFS]); } case USB_ST_SETUP: @@ -2126,21 +2134,22 @@ tr_transferred: } 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->feedback.remainder += ch->feedback.constant; + if (ch->feedback.remainder >= UAUDIO_IRQS) { + ch->feedback.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->feedback.remainder <= -UAUDIO_IRQS) { + ch->feedback.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; } } @@ -2458,6 +2467,9 @@ uaudio_chan_start(struct uaudio_chan *ch } usb_proc_explore_unlock(sc->sc_udev); + /* reset feedback endpoint state */ + memset(&ch->feedback, 0, sizeof(ch->feedback)); + if (do_start) { usbd_transfer_start(ch->xfer[0]); usbd_transfer_start(ch->xfer[1]);