File 0022-alsaloop-added-resampling-for-unsupported-soundcard-.patch of Package alsa-utils

From 058357f04239e1c61d60c29f40409f91d6a6e413 Mon Sep 17 00:00:00 2001
From: Jaroslav Kysela <perex@perex.cz>
Date: Thu, 7 Oct 2010 20:38:36 +0200
Subject: [PATCH 22/38] alsaloop: added resampling for unsupported soundcard rates

- improve also xrun synchronization

Signed-off-by: Jaroslav Kysela <perex@perex.cz>
---
 alsaloop/alsaloop.c |    6 +-
 alsaloop/alsaloop.h |    7 +-
 alsaloop/pcmjob.c   |  279 +++++++++++++++++++++++++++++++++++++--------------
 alsaloop/test.sh    |   12 ++-
 4 files changed, 223 insertions(+), 81 deletions(-)

diff --git a/alsaloop/alsaloop.c b/alsaloop/alsaloop.c
index 6fb9c2a..bbf570e 100644
--- a/alsaloop/alsaloop.c
+++ b/alsaloop/alsaloop.c
@@ -79,7 +79,7 @@ static int create_loopback_handle(struct loopback_handle **_handle,
 	handle->id = strdup(idbuf);
 	handle->access = SND_PCM_ACCESS_RW_INTERLEAVED;
 	handle->format = SND_PCM_FORMAT_S16_LE;
-	handle->rate = 48000;
+	handle->rate = handle->rate_req = 48000;
 	handle->channels = 2;
 	handle->resample = 0;
 	*_handle = handle;
@@ -311,7 +311,7 @@ static int parse_config(int argc, char *argv[], snd_output_t *output)
 	int arg_nblock = 0;
 	int arg_effect = 0;
 	int arg_resample = 0;
-	int arg_samplerate = 0;
+	int arg_samplerate = SRC_SINC_FASTEST + 1;
 	int arg_sync = SYNC_TYPE_AUTO;
 	int arg_slave = SLAVE_TYPE_AUTO;
 	int arg_thread = 0;
@@ -474,7 +474,7 @@ static int parse_config(int argc, char *argv[], snd_output_t *output)
 			exit(EXIT_FAILURE);
 		}
 		play->format = capt->format = arg_format;
-		play->rate = capt->rate = arg_rate;
+		play->rate = play->rate_req = capt->rate = capt->rate_req = arg_rate;
 		play->channels = capt->channels = arg_channels;
 		play->buffer_size_req = capt->buffer_size_req = arg_buffer_size;
 		play->period_size_req = capt->period_size_req = arg_period_size;
diff --git a/alsaloop/alsaloop.h b/alsaloop/alsaloop.h
index 4b357de..9753c41 100644
--- a/alsaloop/alsaloop.h
+++ b/alsaloop/alsaloop.h
@@ -79,6 +79,7 @@ struct loopback_handle {
 	snd_pcm_access_t access;
 	snd_pcm_format_t format;
 	unsigned int rate;
+	unsigned int rate_req;
 	unsigned int channels;
 	unsigned int buffer_size;
 	unsigned int period_size;
@@ -100,6 +101,8 @@ struct loopback_handle {
 	unsigned long long counter;
 	unsigned long sync_point;	/* in samples */
 	snd_pcm_sframes_t last_delay;
+	double pitch;
+	snd_pcm_uframes_t total_queued;
 	/* control */
 	snd_ctl_t *ctl;
 	unsigned int ctl_pollfd_count;
@@ -135,15 +138,15 @@ struct loopback {
 	snd_pcm_sframes_t pitch_diff;
 	snd_pcm_sframes_t pitch_diff_min;
 	snd_pcm_sframes_t pitch_diff_max;
-	snd_pcm_uframes_t total_queued;
 	unsigned int total_queued_count;
 	snd_timestamp_t tstamp_start;
 	snd_timestamp_t tstamp_end;
 	/* control mixer */
 	struct loopback_mixer *controls;
 	/* sample rate */
+	unsigned int use_samplerate:1;
 #ifdef USE_SAMPLERATE
-	unsigned int src_enable: 1;
+	unsigned int src_enable:1;
 	int src_converter_type;
 	SRC_STATE *src_state;
 	SRC_DATA src_data;
diff --git a/alsaloop/pcmjob.c b/alsaloop/pcmjob.c
index 4ad752d..86917ef 100644
--- a/alsaloop/pcmjob.c
+++ b/alsaloop/pcmjob.c
@@ -99,18 +99,20 @@ static int setparams_stream(struct loopback_handle *lhandle,
 		logit(LOG_CRIT, "Channels count (%i) not available for %s: %s\n", lhandle->channels, lhandle->id, snd_strerror(err));
 		return err;
 	}
-	rrate = lhandle->rate;
+	rrate = lhandle->rate_req;
 	err = snd_pcm_hw_params_set_rate_near(handle, params, &rrate, 0);
 	if (err < 0) {
-		logit(LOG_CRIT, "Rate %iHz not available for %s: %s\n", lhandle->rate, lhandle->id, snd_strerror(err));
+		logit(LOG_CRIT, "Rate %iHz not available for %s: %s\n", lhandle->rate_req, lhandle->id, snd_strerror(err));
 		return err;
 	}
 	rrate = 0;
 	snd_pcm_hw_params_get_rate(params, &rrate, 0);
-	if ((int)rrate != lhandle->rate) {
+	lhandle->rate = rrate;
+	if (!lhandle->loopback->src_enable && (int)rrate != lhandle->rate) {
 		logit(LOG_CRIT, "Rate does not match (requested %iHz, got %iHz, resample %i)\n", lhandle->rate, rrate, lhandle->resample);
 		return -EINVAL;
 	}
+	lhandle->pitch = (double)lhandle->rate_req / (double)lhandle->rate;
 	return 0;
 }
 
@@ -245,11 +247,11 @@ static int setparams(struct loopback *loop, snd_pcm_uframes_t bufsize)
 		return err;
 	}
 
-	if ((err = setparams_bufsize(loop->play, p_params, pt_params, bufsize)) < 0) {
+	if ((err = setparams_bufsize(loop->play, p_params, pt_params, bufsize / loop->play->pitch)) < 0) {
 		logit(LOG_CRIT, "Unable to set buffer parameters for %s stream: %s\n", loop->play->id, snd_strerror(err));
 		return err;
 	}
-	if ((err = setparams_bufsize(loop->capt, c_params, ct_params, bufsize)) < 0) {
+	if ((err = setparams_bufsize(loop->capt, c_params, ct_params, bufsize / loop->capt->pitch)) < 0) {
 		logit(LOG_CRIT, "Unable to set buffer parameters for %s stream: %s\n", loop->capt->id, snd_strerror(err));
 		return err;
 	}
@@ -618,6 +620,7 @@ static snd_pcm_sframes_t remove_samples(struct loopback *loop,
 	} else {
 		if (count > play->buf_count)
 			count = play->buf_count;
+		play->buf_count -= count;
 	}
 	return count;
 }
@@ -627,7 +630,7 @@ static int xrun_sync(struct loopback *loop)
 	struct loopback_handle *play = loop->play;
 	struct loopback_handle *capt = loop->capt;
 	snd_pcm_uframes_t fill = get_whole_latency(loop);
-	snd_pcm_sframes_t delay, delayi, pdelay, cdelay, diff;
+	snd_pcm_sframes_t pdelay, cdelay, delay1, pdelay1, cdelay1, diff;
 	int err;
 
       __again:
@@ -681,45 +684,82 @@ static int xrun_sync(struct loopback *loop)
 	}
 	capt->counter = cdelay;
 	play->counter = pdelay;
-	loop->total_queued = 0;
-	loop->total_queued_count = 0;
-	loop->pitch_diff = loop->pitch_diff_min = loop->pitch_diff_max = 0;
-	delay = delayi = pdelay + cdelay;
 	if (play->buf != capt->buf)
-		delay += capt->buf_count;
-	delay += play->buf_count;
+		cdelay += capt->buf_count;
+	pdelay += play->buf_count;
 #ifdef USE_SAMPLERATE
-	delay += loop->src_out_frames;
-	delayi += loop->src_out_frames;
+	pdelay += loop->src_out_frames;
 #endif
-#if 0
-	printf("s: cdelay = %li, pdelay = %li, delay = %li, delayi = %li, fill = %li, src_out = %li\n",
-		(long)cdelay, (long)pdelay, (long)delay,
-		(long)delayi, (long)fill, (long)loop->src_out_frames);
-	printf("s: cbufcount = %li, pbufcount = %li\n", (long)capt->buf_count, (long)play->buf_count);
-#endif
-	if (delayi > fill) {
+	cdelay1 = cdelay * capt->pitch;
+	pdelay1 = pdelay * play->pitch;
+	delay1 = cdelay1 + pdelay1;
+	capt->total_queued = 0;
+	play->total_queued = 0;
+	loop->total_queued_count = 0;
+	loop->pitch_diff = loop->pitch_diff_min = loop->pitch_diff_max = 0;
+	if (verbose > 6) {
+		snd_output_printf(loop->output,
+			"sync: cdelay=%li(%li), pdelay=%li(%li), fill=%li (delay=%li), src_out=%li\n",
+			(long)cdelay, (long)cdelay1, (long)pdelay, (long)pdelay1,
+			(long)fill, (long)delay1, (long)loop->src_out_frames);
+		snd_output_printf(loop->output,
+			"sync: cbufcount=%li, pbufcount=%li\n",
+			(long)capt->buf_count, (long)play->buf_count);
+	}
+	if (delay1 > fill && capt->counter > 0) {
 		if ((err = snd_pcm_drop(capt->handle)) < 0)
 			return err;
 		if ((err = snd_pcm_prepare(capt->handle)) < 0)
 			return err;
 		if ((err = snd_pcm_start(capt->handle)) < 0)
 			return err;
-		remove_samples(loop, 1, delayi - fill);
+		diff = remove_samples(loop, 1, (delay1 - fill) / capt->pitch);
+		if (verbose > 6)
+			snd_output_printf(loop->output,
+				"sync: capt stop removed %li samples\n", (long)diff);
 		goto __again;
 	}
-	if (delay > fill) {
-		diff = fill > delayi ? play->buf_count - (fill - delayi) : 0;
-		delay -= remove_samples(loop, 0, diff);
+	if (delay1 > fill) {
+		diff = (delay1 - fill) / play->pitch;
+		if (diff > play->buf_count)
+			diff = play->buf_count;
+		if (verbose > 6)
+			snd_output_printf(loop->output,
+				"sync: removing %li playback samples, delay1=%li\n", (long)diff, (long)delay1);
+		diff = remove_samples(loop, 0, diff);
+		pdelay -= diff;
+		pdelay1 = pdelay * play->pitch;
+		delay1 = cdelay1 + pdelay1;
+		if (verbose > 6)
+			snd_output_printf(loop->output,
+				"sync: removed %li playback samples, delay1=%li\n", (long)diff, (long)delay1);
 	}
-	if (delay > fill) {
-		diff = fill > delayi ? capt->buf_count - (fill - delayi) : 0;
-		delay -= remove_samples(loop, 1, diff);
+	if (delay1 > fill) {
+		diff = (delay1 - fill) / capt->pitch;
+		if (diff > capt->buf_count)
+			diff = capt->buf_count;
+		if (verbose > 6)
+			snd_output_printf(loop->output,
+				"sync: removing %li captured samples, delay1=%li\n", (long)diff, (long)delay1);
+		diff -= remove_samples(loop, 1, diff);
+		cdelay -= diff;
+		cdelay1 = cdelay * capt->pitch;
+		delay1 = cdelay1 + pdelay1;		
+		if (verbose > 6)
+			snd_output_printf(loop->output,
+				"sync: removed %li captured samples, delay1=%li\n", (long)diff, (long)delay1);
 	}
 	if (play->xrun_pending) {
 		play->xrun_pending = 0;
-		if (fill > delay && play->buf_count < fill - delay) {
-			diff = fill - delay - play->buf_count;
+		diff = (fill - delay1) / play->pitch;
+		if (verbose > 6)
+			snd_output_printf(loop->output,
+				"sync: xrun_pending, silence filling %li / buf_count=%li\n", (long)diff, play->buf_count);
+		if (fill > delay1 && play->buf_count < diff) {
+			diff = diff - play->buf_count;
+			if (verbose > 6)
+				snd_output_printf(loop->output,
+					"sync: playback silence added %li samples\n", (long)diff);
 			play->buf_pos -= diff;
 			play->buf_pos %= play->buf_size;
 			if ((err = snd_pcm_format_set_silence(play->format, play->buf + play->buf_pos * play->channels, diff)) < 0)
@@ -728,18 +768,43 @@ static int xrun_sync(struct loopback *loop)
 		}
 		if ((err = snd_pcm_prepare(play->handle)) < 0) {
 			logit(LOG_CRIT, "%s prepare failed: %s\n", play->id, snd_strerror(err));
+
 			return err;
 		}
-		delayi = writeit(play);
-		if (delayi > diff)
-			buf_remove(loop, delayi - diff);
+		delay1 = writeit(play);
+		if (verbose > 6)
+			snd_output_printf(loop->output,
+				"sync: playback wrote %li samples\n", (long)delay1);
+		if (delay1 > diff) {
+			buf_remove(loop, delay1 - diff);
+			if (verbose > 6)
+				snd_output_printf(loop->output,
+					"sync: playback buf_remove %li samples\n", (long)(delay1 - diff));
+		}
 		if ((err = snd_pcm_start(play->handle)) < 0) {
 			logit(LOG_CRIT, "%s start failed: %s\n", play->id, snd_strerror(err));
 			return err;
 		}
 	}
-	if (verbose > 5)
+	if (verbose > 5) {
 		snd_output_printf(loop->output, "%s: xrun sync ok\n", loop->id);
+		if (verbose > 6) {
+			if (snd_pcm_delay(capt->handle, &cdelay) < 0)
+				cdelay = -1;
+			if (snd_pcm_delay(play->handle, &pdelay) < 0)
+				pdelay = -1;
+			if (play->buf != capt->buf)
+				cdelay += capt->buf_count;
+			pdelay += play->buf_count;
+#ifdef USE_SAMPLERATE
+			pdelay += loop->src_out_frames;
+#endif
+			cdelay1 = cdelay * capt->pitch;
+			pdelay1 = pdelay * play->pitch;
+			delay1 = cdelay1 + pdelay1;
+			snd_output_printf(loop->output, "%s: sync verify: %li\n", loop->id, delay1);
+		}
+	}
 	return 0;
 }
 
@@ -778,6 +843,46 @@ static int set_rate_shift(struct loopback_handle *lhandle, double pitch)
 	return 0;
 }
 
+void update_pitch(struct loopback *loop)
+{
+	double pitch = loop->pitch;
+
+#ifdef USE_SAMPLERATE
+	if (loop->sync == SYNC_TYPE_SAMPLERATE) {
+		loop->src_data.src_ratio = (double)1.0 / (pitch *
+				loop->play->pitch * loop->capt->pitch);
+		if (verbose > 2)
+			snd_output_printf(loop->output, "%s: Samplerate src_ratio update1: %.8f\n", loop->id, loop->src_data.src_ratio);
+	} else
+#endif
+	if (loop->sync == SYNC_TYPE_CAPTRATESHIFT) {
+		set_rate_shift(loop->capt, pitch);
+#ifdef USE_SAMPLERATE
+		if (loop->use_samplerate) {
+			loop->src_data.src_ratio = 
+				(double)1.0 /
+					(loop->play->pitch * loop->capt->pitch);
+			if (verbose > 2)
+				snd_output_printf(loop->output, "%s: Samplerate src_ratio update2: %.8f\n", loop->id, loop->src_data.src_ratio);
+		}
+#endif
+	}
+	else if (loop->sync == SYNC_TYPE_PLAYRATESHIFT) {
+		set_rate_shift(loop->play, pitch);
+#ifdef USE_SAMPLERATE
+		if (loop->use_samplerate) {
+			loop->src_data.src_ratio = 
+				(double)1.0 /
+					(loop->play->pitch * loop->capt->pitch);
+			if (verbose > 2)
+				snd_output_printf(loop->output, "%s: Samplerate src_ratio update3: %.8f\n", loop->id, loop->src_data.src_ratio);
+		}
+#endif
+	}
+	if (verbose)
+		snd_output_printf(loop->output, "New pitch for %s: %.8f (min/max samples = %li/%li)\n", loop->id, pitch, loop->pitch_diff_min, loop->pitch_diff_max);
+}
+
 static int get_active(struct loopback_handle *lhandle)
 {
 	int err;
@@ -1002,6 +1107,8 @@ int pcmjob_init(struct loopback *loop)
 #ifdef USE_SAMPLERATE
 	if (loop->sync == SYNC_TYPE_AUTO && loop->src_enable)
 		loop->sync = SYNC_TYPE_SAMPLERATE;
+#else
+	loop->src_enable = 0;
 #endif
 	if (loop->sync == SYNC_TYPE_AUTO)
 		loop->sync = SYNC_TYPE_SIMPLE;
@@ -1035,8 +1142,9 @@ int pcmjob_init(struct loopback *loop)
 static void freeloop(struct loopback *loop)
 {
 #ifdef USE_SAMPLERATE
-	if (loop->src_enable) {
-		src_delete(loop->src_state);
+	if (loop->use_samplerate) {
+		if (loop->src_state)
+			src_delete(loop->src_state);
 		loop->src_state = NULL;
 		free(loop->src_data.data_in);
 		loop->src_data.data_in = NULL;
@@ -1078,6 +1186,7 @@ static void lhandle_start(struct loopback_handle *lhandle)
 	lhandle->buf_pos = 0;
 	lhandle->buf_count = 0;
 	lhandle->counter = 0;
+	lhandle->total_queued = 0;
 }
 
 int pcmjob_start(struct loopback *loop)
@@ -1098,7 +1207,7 @@ int pcmjob_start(struct loopback *loop)
 		err = get_rate(loop->capt);
 		if (err < 0)
 			goto __error;
-		loop->play->rate = loop->capt->rate = err;
+		loop->play->rate_req = loop->capt->rate_req = err;
 		err = get_channels(loop->capt);
 		if (err < 0)
 			goto __error;
@@ -1107,6 +1216,7 @@ int pcmjob_start(struct loopback *loop)
 	loop->pollfd_count = loop->play->ctl_pollfd_count +
 			     loop->capt->ctl_pollfd_count;
 	loop->reinit = 0;
+	loop->use_samplerate = 0;
 	loop->latency = loop->latency_req;
 	if (loop->latency == 0)
 		loop->latency = time_to_frames(loop->play,
@@ -1114,7 +1224,7 @@ int pcmjob_start(struct loopback *loop)
 	if ((err = setparams(loop, loop->latency/2)) < 0)
 		goto __error;
 	if (verbose)
-		showlatency(loop, loop->latency, loop->play->rate);
+		showlatency(loop, loop->latency, loop->play->rate_req);
 	if (loop->play->access == loop->capt->access &&
 	    loop->play->format == loop->capt->format &&
 	    loop->play->rate == loop->capt->rate &&
@@ -1142,6 +1252,10 @@ int pcmjob_start(struct loopback *loop)
 			goto __error;
 		if ((err = init_handle(loop->capt, 1)) < 0)
 			goto __error;
+		if (loop->play->rate_req != loop->play->rate)
+			loop->use_samplerate = 1;
+		if (loop->capt->rate_req != loop->capt->rate)
+			loop->use_samplerate = 1;
 	}
 	if ((err = snd_pcm_poll_descriptors_count(loop->play->handle)) < 0)
 		goto __error;
@@ -1152,7 +1266,22 @@ int pcmjob_start(struct loopback *loop)
 	loop->capt->pollfd_count = err;
 	loop->pollfd_count += err;
 #ifdef USE_SAMPLERATE
-	if (loop->sync == SYNC_TYPE_SAMPLERATE) {
+	if (loop->sync == SYNC_TYPE_SAMPLERATE)
+		loop->use_samplerate = 1;
+	if (loop->use_samplerate && !loop->src_enable) {
+		logit(LOG_CRIT, "samplerate conversion required but disabled\n");
+		loop->use_samplerate = 0;
+		err = -EIO;
+		goto __error;		
+	}
+	if (loop->use_samplerate) {
+		if (loop->capt->format != SND_PCM_FORMAT_S16 ||
+		    loop->play->format != SND_PCM_FORMAT_S16) {
+			logit(LOG_CRIT, "samplerate conversion supports only S16_LE format (%i, %i)\n", loop->play->format, loop->capt->format);
+			loop->use_samplerate = 0;
+			err = -EIO;
+			goto __error;		
+		}
 		loop->src_state = src_new(loop->src_converter_type,
 					  loop->play->channels, &err);
 		loop->src_data.data_in = calloc(1, sizeof(float)*loop->capt->channels*loop->capt->buf_size);
@@ -1173,7 +1302,7 @@ int pcmjob_start(struct loopback *loop)
 		loop->src_state = NULL;
 	}
 #else
-	if (loop->sync == SYNC_TYPE_SAMPLERATE) {
+	if (loop->sync == SYNC_TYPE_SAMPLERATE || loop->use_samplerate) {
 		logit(LOG_CRIT, "alsaloop is compiled without libsamplerate support\n");
 		err = -EIO;
 		goto __error;
@@ -1195,12 +1324,12 @@ int pcmjob_start(struct loopback *loop)
 		logit(LOG_CRIT, "%s: silence error\n", loop->id);
 		goto __error;
 	}
-	loop->pitch = 1;
+	loop->pitch = 1.0;
+	update_pitch(loop);
 	loop->pitch_delta = 1.0 / ((double)loop->capt->rate * 4);
-	loop->total_queued = 0;
 	loop->total_queued_count = 0;
 	loop->pitch_diff = 0;
-	count = get_whole_latency(loop);
+	count = get_whole_latency(loop) / loop->play->pitch;
 	loop->play->buf_count = count;
 	if (loop->play->buf == loop->capt->buf)
 		loop->capt->buf_pos = count;
@@ -1277,19 +1406,14 @@ int pcmjob_pollfds_init(struct loopback *loop, struct pollfd *fds)
 	return idx;
 }
 
-static snd_pcm_sframes_t get_queued_samples(struct loopback *loop)
+static snd_pcm_sframes_t get_queued_playback_samples(struct loopback *loop)
 {
-	snd_pcm_sframes_t pdelay, cdelay, delay;
+	snd_pcm_sframes_t delay;
 	int err;
 
-	if ((err = snd_pcm_delay(loop->play->handle, &pdelay)) < 0)
-		return 0;
-	if ((err = snd_pcm_delay(loop->capt->handle, &cdelay)) < 0)
+	if ((err = snd_pcm_delay(loop->play->handle, &delay)) < 0)
 		return 0;
-	loop->play->last_delay = pdelay;
-	loop->capt->last_delay = cdelay;
-	delay = pdelay + cdelay;
-	delay += loop->capt->buf_count;
+	loop->play->last_delay = delay;
 	delay += loop->play->buf_count;
 #ifdef USE_SAMPLERATE
 	delay += loop->src_out_frames;
@@ -1297,6 +1421,18 @@ static snd_pcm_sframes_t get_queued_samples(struct loopback *loop)
 	return delay;
 }
 
+static snd_pcm_sframes_t get_queued_capture_samples(struct loopback *loop)
+{
+	snd_pcm_sframes_t delay;
+	int err;
+
+	if ((err = snd_pcm_delay(loop->capt->handle, &delay)) < 0)
+		return 0;
+	loop->capt->last_delay = delay;
+	delay += loop->capt->buf_count;
+	return delay;
+}
+
 static int ctl_event_check(snd_ctl_elem_value_t *val, snd_ctl_event_t *ev)
 {
 	snd_ctl_elem_id_t *id1, *id2;
@@ -1363,7 +1499,6 @@ int pcmjob_pollfds_handle(struct loopback *loop, struct pollfd *fds)
 	struct loopback_handle *capt = loop->capt;
 	unsigned short prevents, crevents, events;
 	snd_pcm_uframes_t ccount, pcount;
-	snd_pcm_sframes_t queued;
 	int err, loopcount = 10, idx;
 
 	if (verbose > 11)
@@ -1463,8 +1598,8 @@ int pcmjob_pollfds_handle(struct loopback *loop, struct pollfd *fds)
 	    play->counter >= play->sync_point &&
 	    capt->counter >= play->sync_point) {
 		snd_pcm_sframes_t diff, lat = get_whole_latency(loop);
-		double pitch;
-		diff = ((double)loop->total_queued /
+		diff = ((double)(((double)play->total_queued * play->pitch) +
+				 ((double)capt->total_queued * capt->pitch)) /
 			(double)loop->total_queued_count) - lat;
 		/* FIXME: this algorithm may be slightly better */
 		if (verbose > 3)
@@ -1472,12 +1607,12 @@ int pcmjob_pollfds_handle(struct loopback *loop, struct pollfd *fds)
 		if (diff > 0) {
 			if (diff == loop->pitch_diff)
 				loop->pitch += loop->pitch_delta;
-			if (diff > loop->pitch_diff)
+			else if (diff > loop->pitch_diff)
 				loop->pitch += loop->pitch_delta*2;
 		} else if (diff < 0) {
 			if (diff == loop->pitch_diff)
 				loop->pitch -= loop->pitch_delta;
-			if (diff < loop->pitch_diff)
+			else if (diff < loop->pitch_diff)
 				loop->pitch -= loop->pitch_delta*2;
 		}
 		loop->pitch_diff = diff;
@@ -1485,31 +1620,25 @@ int pcmjob_pollfds_handle(struct loopback *loop, struct pollfd *fds)
 			loop->pitch_diff_min = diff;
 		if (loop->pitch_diff_max < diff)
 			loop->pitch_diff_max = diff;
-		pitch = loop->pitch;
-#ifdef USE_SAMPLERATE
-		if (loop->sync == SYNC_TYPE_SAMPLERATE)
-			loop->src_data.src_ratio = (double)1.0 / pitch;
-		else
-#endif
-		if (loop->sync == SYNC_TYPE_CAPTRATESHIFT)
-			set_rate_shift(capt, pitch);
-		if (loop->sync == SYNC_TYPE_PLAYRATESHIFT)
-			set_rate_shift(play, pitch);
-		if (verbose)
-			snd_output_printf(loop->output, "New pitch for %s: %.8f (min/max samples = %li/%li)\n", loop->id, pitch, loop->pitch_diff_min, loop->pitch_diff_max);
+		update_pitch(loop);
 		play->counter -= play->sync_point;
 		capt->counter -= play->sync_point;
-		loop->total_queued = 0;
+		play->total_queued = 0;
+		capt->total_queued = 0;
 		loop->total_queued_count = 0;
 	}
 	if (loop->sync != SYNC_TYPE_NONE) {
-		queued = get_queued_samples(loop);
+		snd_pcm_sframes_t pqueued, cqueued;
+		pqueued = get_queued_playback_samples(loop);
+		cqueued = get_queued_capture_samples(loop);
 		if (verbose > 4)
-			snd_output_printf(loop->output, "%s: queued %li samples\n", loop->id, queued);
-		if (queued > 0) {
-			loop->total_queued += queued;
+			snd_output_printf(loop->output, "%s: queued %li/%li samples\n", loop->id, pqueued, cqueued);
+		if (pqueued > 0)
+			loop->play->total_queued += pqueued;
+		if (cqueued > 0)
+			loop->capt->total_queued += cqueued;
+		if (pqueued > 0 || cqueued > 0)
 			loop->total_queued_count += 1;
-		}
 	}
 	if (verbose > 12) {
 		snd_pcm_sframes_t pdelay, cdelay;
diff --git a/alsaloop/test.sh b/alsaloop/test.sh
index a1d4dbe..fbd40c0 100755
--- a/alsaloop/test.sh
+++ b/alsaloop/test.sh
@@ -6,7 +6,7 @@ CFGFILE="/tmp/alsaloop.test.cfg"
 
 test1() {
   echo "TEST1"
-  $DBG ./alsaloop -C hw:1,0 -P hw:0,0 \
+  $DBG ./alsaloop -C hw:1,0 -P plughw:0,0 \
     --tlatency 50000 \
     --mixer "name='Master Playback Volume'@name='Master Playback Volume'" \
     --mixer "name='Master Playback Switch'@name='Master Playback Switch'" \
@@ -45,9 +45,19 @@ EOF
   $DBG ./alsaloop --config $CFGFILE
 }
 
+test4() {
+  echo "TEST4"
+  $DBG ./alsaloop -C hw:1,0 -P plughw:0,0 -a off -r 11025 \
+    --tlatency 50000 \
+    --mixer "name='Master Playback Volume'@name='Master Playback Volume'" \
+    --mixer "name='Master Playback Switch'@name='Master Playback Switch'" \
+    --mixer "name='PCM Playback Volume'"
+}
+
 case "$1" in
 test1) test1 ;;
 test2) test2 ;;
 test3) test3 ;;
+test4) test4 ;;
 *) test1 ;;
 esac
-- 
1.7.3.1

openSUSE Build Service is sponsored by