Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 13 Apr 2016 05:28:27 +0000 (UTC)
From:      Oleksandr Tymoshenko <gonzo@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r297911 - head/sys/arm/broadcom/bcm2835
Message-ID:  <201604130528.u3D5SRqU002222@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: gonzo
Date: Wed Apr 13 05:28:27 2016
New Revision: 297911
URL: https://svnweb.freebsd.org/changeset/base/297911

Log:
  Multiple fixes in VCHI audio driver:
  
  - Pre-buffer audio data to VideoCore so there are no audible glitches when
      driver is too late to provide samples
  - Start actual playback when there is some prebuffered audio,
      it fixes audible noisy click in the beginning of playback
  - Use #defines instead of hardcoded values where appropriate
  - Fix copy-pasted comment
  
  PR:		208678

Modified:
  head/sys/arm/broadcom/bcm2835/bcm2835_audio.c

Modified: head/sys/arm/broadcom/bcm2835/bcm2835_audio.c
==============================================================================
--- head/sys/arm/broadcom/bcm2835/bcm2835_audio.c	Wed Apr 13 05:19:16 2016	(r297910)
+++ head/sys/arm/broadcom/bcm2835/bcm2835_audio.c	Wed Apr 13 05:28:27 2016	(r297911)
@@ -46,6 +46,7 @@ SND_DECLARE_FILE("$FreeBSD$");
 
 #define	VCHIQ_AUDIO_PACKET_SIZE	4000
 #define	VCHIQ_AUDIO_BUFFER_SIZE	128000
+#define	VCHIQ_AUDIO_PREBUFFER	10 /* Number of pre-buffered audio messages */
 
 #define	VCHIQ_AUDIO_MAX_VOLUME	
 /* volume in terms of 0.01dB */
@@ -91,6 +92,7 @@ struct bcm2835_audio_chinfo {
 	uint32_t free_buffer;
 	uint32_t buffered_ptr;
 	int playback_state;
+	int prebuffered;
 };
 
 struct bcm2835_audio_info {
@@ -170,11 +172,10 @@ bcm2835_audio_callback(void *param, cons
 
 		ch->complete_pos = (ch->complete_pos + count) % sndbuf_getsize(ch->buffer);
 		ch->free_buffer += count;
+		chn_intr(sc->pch.channel);
 
-		if (perr || ch->free_buffer >= VCHIQ_AUDIO_PACKET_SIZE) {
-			chn_intr(ch->channel);
+		if (perr || ch->free_buffer >= VCHIQ_AUDIO_PACKET_SIZE)
 			cv_signal(&sc->data_cv);
-		}
 	} else
 		printf("%s: unknown m.type: %d\n", __func__, m.type);
 }
@@ -244,6 +245,7 @@ bcm2835_audio_reset_channel(struct bcm28
 	ch->playback_state = 0;
 	ch->buffered_ptr = 0;
 	ch->complete_pos = 0;
+	ch->prebuffered = 0;
 
 	sndbuf_reset(ch->buffer);
 }
@@ -478,21 +480,29 @@ bcm2835_audio_worker(void *data)
 		if (sc->unloading)
 			break;
 
-		if ((ch->playback_state == PLAYBACK_PLAYING) &&
-		    (vchiq_unbuffered_bytes(ch) >= VCHIQ_AUDIO_PACKET_SIZE)
-		    && (ch->free_buffer >= VCHIQ_AUDIO_PACKET_SIZE)) {
-			bcm2835_audio_write_samples(ch);
-		} else {
-			if (ch->playback_state == PLAYBACK_STOPPING) {
-				bcm2835_audio_reset_channel(&sc->pch);
-				ch->playback_state = PLAYBACK_IDLE;
-			}
-
+		if (ch->playback_state == PLAYBACK_IDLE) {
 			cv_wait_sig(&sc->data_cv, &sc->data_lock);
+			continue;
+		}
+
+		if (ch->playback_state == PLAYBACK_STOPPING) {
+			bcm2835_audio_reset_channel(&sc->pch);
+			ch->playback_state = PLAYBACK_IDLE;
+			continue;
+		}
+
+		if (ch->free_buffer < vchiq_unbuffered_bytes(ch)) {
+			cv_timedwait_sig(&sc->data_cv, &sc->data_lock, 10);
+			continue;
+		}
+
+
+		bcm2835_audio_write_samples(ch);
 
-			if (ch->playback_state == PLAYBACK_STARTING) {
-				/* Give it initial kick */
-				chn_intr(sc->pch.channel);
+		if (ch->playback_state == PLAYBACK_STARTING) {
+			ch->prebuffered++;
+			if (ch->prebuffered == VCHIQ_AUDIO_PREBUFFER) {
+				bcm2835_audio_start(ch);
 				ch->playback_state = PLAYBACK_PLAYING;
 			}
 		}
@@ -514,7 +524,7 @@ bcm2835_audio_create_worker(struct bcm28
 }
 
 /* -------------------------------------------------------------------- */
-/* channel interface for ESS18xx */
+/* channel interface for VCHI audio */
 static void *
 bcmchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
 {
@@ -612,7 +622,6 @@ bcmchan_trigger(kobj_t obj, void *data, 
 
 	switch (go) {
 	case PCMTRIG_START:
-		bcm2835_audio_start(ch);
 		ch->playback_state = PLAYBACK_STARTING;
 		/* wakeup worker thread */
 		cv_signal(&sc->data_cv);
@@ -620,7 +629,7 @@ bcmchan_trigger(kobj_t obj, void *data, 
 
 	case PCMTRIG_STOP:
 	case PCMTRIG_ABORT:
-		ch->playback_state = 1;
+		ch->playback_state = PLAYBACK_STOPPING;
 		bcm2835_audio_stop(ch);
 		break;
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201604130528.u3D5SRqU002222>