Some code to make it easier to diagnose echo cancellation issues.
authorjm <jm@0101bb08-14d6-0310-b084-bc0e0c8e3800>
Fri, 16 Mar 2007 14:18:43 +0000 (14:18 +0000)
committerjm <jm@0101bb08-14d6-0310-b084-bc0e0c8e3800>
Fri, 16 Mar 2007 14:18:43 +0000 (14:18 +0000)
git-svn-id: http://svn.xiph.org/trunk/speex@12767 0101bb08-14d6-0310-b084-bc0e0c8e3800

libspeex/echo_diagnostic.m [new file with mode: 0644]
libspeex/mdf.c

diff --git a/libspeex/echo_diagnostic.m b/libspeex/echo_diagnostic.m
new file mode 100644 (file)
index 0000000..94375b3
--- /dev/null
@@ -0,0 +1,61 @@
+% Attempts to diagnose AEC problems from recorded samples
+%
+% out = echo_diagnostic(rec, play, tail_length)
+%
+% Computes the full matrix inversion to cancel echo from the 
+% recording 'rec' using the far end signal 'play' using a filter
+% length of 'tail_length'
+function out = echo_diagnostic(rec, play, tail_length)
+
+rec = [rec; zeros(1024,1)];
+play = [play; zeros(1024,1)];
+
+N = length(rec);
+corr = real(ifft(fft(rec).*conj(fft(play))));
+acorr = real(ifft(fft(play).*conj(fft(play))));
+
+[a,b] = max(corr);
+
+if b > N/2
+      b = b-N;
+end
+printf ("Far end to near end delay is %d samples\n", b);
+if (b > .3*tail_length)
+      printf ('This is too much delay, try delaying the far-end signal a bit\n');
+else if (b < 0)
+      printf ('You have a negative delay, the echo canceller has no chance to cancel anything!\n');
+   else
+      printf ('Delay looks OK.\n');
+      end
+   end
+end
+N2 = round(N/2);
+corr1 = real(ifft(fft(rec(1:N2)).*conj(fft(play(1:N2)))));
+corr2 = real(ifft(fft(rec(N2+1:end)).*conj(fft(play(N2+1:end)))));
+
+[a,b1] = max(corr1);
+if b1 > N/2
+      b1 = b1-N;
+end
+[a,b2] = max(corr2);
+if b2 > N/2
+      b2 = b2-N;
+end
+drift = (b1-b2)/N2;
+printf ('Drift estimate is %f%% (%d samples)\n', 100*drift, b1-b2);
+if abs(b1-b2) < 10
+   printf ('A drift of a few (+-10) samples is normal.\n');
+else
+   if abs(b1-b2) < 30
+      printf ('There may be (not sure) excessive clock drift. Is the capture and playback done on the same soundcard?\n');
+   else
+      printf ('Your clock is drifting! No way the AEC will be able to do anything with that. Most likely, you''re doing capture and playback from two different cards.\n');
+      end
+   end
+end
+acorr(1) = .001+1.00001*acorr(1);
+AtA = toeplitz(acorr(1:tail_length));
+bb = corr(1:tail_length);
+h = AtA\bb;
+
+out = (rec - filter(h, 1, play));
index 498dd39..bc68f91 100644 (file)
@@ -360,12 +360,36 @@ static inline void mdf_adjust_prop(const spx_word32_t *W, int N, int M, spx_word
    /*printf ("\n");*/
 }
 
+#ifdef DUMP_ECHO_CANCEL_DATA
+#include <stdio.h>
+static FILE *rFile=NULL, *pFile=NULL, *oFile=NULL;
+
+static void dump_audio(const spx_int16_t *rec, const spx_int16_t *play, const spx_int16_t *out, int len)
+{
+   if (!(rFile && pFile && oFile))
+   {
+      speex_error("Dump files not open");
+   }
+   fwrite(rec, sizeof(spx_int16_t), len, rFile);
+   fwrite(play, sizeof(spx_int16_t), len, pFile);
+   fwrite(out, sizeof(spx_int16_t), len, oFile);
+}
+#endif
+
 /** Creates a new echo canceller state */
 SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length)
 {
    int i,N,M;
    SpeexEchoState *st = (SpeexEchoState *)speex_alloc(sizeof(SpeexEchoState));
 
+#ifdef DUMP_ECHO_CANCEL_DATA
+   if (rFile || pFile || oFile)
+      speex_error("Opening dump files twice");
+   rFile = fopen("aec_rec.sw", "w");
+   pFile = fopen("aec_play.sw", "w");
+   oFile = fopen("aec_out.sw", "w");
+#endif
+   
    st->frame_size = frame_size;
    st->window_size = 2*frame_size;
    N = st->window_size;
@@ -553,6 +577,13 @@ void speex_echo_state_destroy(SpeexEchoState *st)
 #endif
    speex_free(st->play_buf);
    speex_free(st);
+   
+#ifdef DUMP_ECHO_CANCEL_DATA
+   fclose(rFile);
+   fclose(pFile);
+   fclose(oFile);
+   rFile = pFile = oFile = NULL;
+#endif
 }
 
 void speex_echo_capture(SpeexEchoState *st, const spx_int16_t *rec, spx_int16_t *out)
@@ -861,7 +892,11 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp
       out[i] = (spx_int16_t)tmp_out;
       st->memE = tmp_out;
    }
-
+   
+#ifdef DUMP_ECHO_CANCEL_DATA
+   dump_audio(in, far_end, out, st->frame_size);
+#endif
+   
    /* Compute error signal (filter update version) */ 
    for (i=0;i<st->frame_size;i++)
    {