Software EC with voice-engine / ec

Tinkering section again
Suggest doing an update of speexdsp & speex with libasound2-plugins as in

But not essential.

Install is pretty easy, but you need to make sure the sink and source come from the same clock source as clock drift will likely render it useless.
I have tried the pulseaudio webrtc EC several times which is supposed to cope with clock drift but on Arm it doesn’t seem to work at all.
Also strangely the echo of the alsaplugin of speex doesn’t seem to work but in the following this repo will use the speexdsp libs and it will work extremely well? Dunno…
But your soundcard make sure it plays and records such as a usb soundcard or some of the mic hats with a soundcard chip (gets a bit confusing as some hats have seperate on board clocks for dac and adc).
So cheap USB soundcard or something like the respeaker 2mic.

We are going to run from where we install this will just install in %HOME install where you wish

git clone https://github.com/voice-engine/ec.git
cd ec
make
./ec -h

should give you the help info of ec and show its installed.

Ec uses a fifo file in /tmp for audio rather than a source so again just install.

This utility will install rather than just in the repo directory.

cd ..
git clone https://github.com/voice-engine/alsa_plugin_fifo.git
cd alsa_plugin_fifo
make && sudo make install

https://raw.githubusercontent.com/voice-engine/ec/master/asound.conf copy to /etc/asound.conf

pcm.!default {
    type asym
    playback.pcm "eci"
    capture.pcm "eco"
}


pcm.eci {
    type plug
    slave {
        format S16_LE
        rate 16000
        channels 1
        pcm {
            type file
            slave.pcm null
            file "/tmp/ec.input"
            format "raw"
        }
    }
}

pcm.eco {
    type plug
    slave.pcm {
        type fifo
        infile "/tmp/ec.output"
        rate 16000
        format S16_LE
        channels 2
    }
}

So this sets to fifo files ec-in and ec-out as your playback and capture defaults.
Go back to ec

cd ..
cd ec
./ec -i plughw:2 -o plughw:2 -d 20

The -d 20 is to try and compensate for your latency which really should of mentioned earlier as you can use alsabat with –roundtriplatency to measure latency from output to mic capture.
The repo states its 200 msec but to be honest it seems to be much less but alsa the redirection of ec may also add to this but seems impossible to measure with EC running so test your hardware first.

You need to open another terminal and aplay a wav.

wget https://file-examples-com.github.io/uploads/2017/11/file_example_WAV_10MG.wav
aplay file_example_WAV_10MG.wav

EC will start on playing media and at end of file stop.
So aplay an example wav to the default playback device and Enable AEC will show.
When it ends you will get something like

playback filled 256 bytes zero
No playback, bypass AEC

So what is happening is EC is listening on the mic and trying to subtract the playing wav from that fifo file eci and places the result in eco which we need to record from.

So just to test we will open up another terminal and start a recording before we play.
arecord -r16000 -fS16_LE -c1 ec-rec.wav
EC is already running so go back to the aplay console and play the example wav again.
Then ctrl+c to stop the recording in the arecord terminal.

Now you prob have found the one quirk that EC has that on the end of recording EC ends with
-bash: playback: command not found

So we need to fix that with a alsa loopback device which we need to modprobe.
So this gets the alsa index it will on boot each we enable we are going to add it to the modules to load on boot.

sudo nano /etc/modules and add snd-aloop to that file save and reboot.
you should see something like

pi@raspberrypi:~ $ aplay -l
**** List of PLAYBACK Hardware Devices ****
card 0: Loopback [Loopback], device 0: Loopback PCM [Loopback PCM]
  Subdevices: 8/8
  Subdevice #0: subdevice #0
  Subdevice #1: subdevice #1
  Subdevice #2: subdevice #2
  Subdevice #3: subdevice #3
  Subdevice #4: subdevice #4
  Subdevice #5: subdevice #5
  Subdevice #6: subdevice #6
  Subdevice #7: subdevice #7
card 0: Loopback [Loopback], device 1: Loopback PCM [Loopback PCM]
  Subdevices: 8/8
  Subdevice #0: subdevice #0
  Subdevice #1: subdevice #1
  Subdevice #2: subdevice #2
  Subdevice #3: subdevice #3
  Subdevice #4: subdevice #4
  Subdevice #5: subdevice #5
  Subdevice #6: subdevice #6
  Subdevice #7: subdevice #7
card 1: b1 [bcm2835 HDMI 1], device 0: bcm2835 HDMI 1 [bcm2835 HDMI 1]
  Subdevices: 4/4
  Subdevice #0: subdevice #0
  Subdevice #1: subdevice #1
  Subdevice #2: subdevice #2
  Subdevice #3: subdevice #3
card 2: Headphones [bcm2835 Headphones], device 0: bcm2835 Headphones [bcm2835 H                      eadphones]
  Subdevices: 4/4
  Subdevice #0: subdevice #0
  Subdevice #1: subdevice #1
  Subdevice #2: subdevice #2
  Subdevice #3: subdevice #3
card 3: Dongle [VIA USB Dongle], device 0: USB Audio [USB Audio]
  Subdevices: 1/1
  Subdevice #0: subdevice #0

So what we will do is pipe the arecord into one side of the loopback a sink and the other side will be our source.

So in a terminal run ec again you may find the card index has changed ./ec -i plughw:3 -o plughw:3 -d 20
Pipe arecord into the loopback arecord -Deco -r16000 -fS16_LE -c1 | aplay -Dplughw:0,0,0 so its constantly recording.
But we will now use the other side as a source to record from arecord -Dplughw:0,1,0 -r16000 -fS16_LE ec-rec.wav

Now you prob want to edit the /etc/asound.conf and make the loopback on -Dplughw:0,1,0 the default capture device.
Or you may want to use that as a pcm slave for speex AGC but will let you decide on how you edit and channge /etc/asound.conf.
You should now find when Rhasspy plays or records on the default devices EC will continue.
You will have to create a boot script or service and run EC and pipe through the loopback but at least you know how to get EC running.
There is ec_hw in the repo and it would also of been compiled on make never did work it out maybe you can.

It should be called Echo Attenuation but you should find its more than capable of allowing barge in that was extremely problematic before.

2 Likes

An addition as actually worked out to get the delay.

Record with EC ./ec -i plughw:2 -o plughw:2 -s
Do the usual record in one cli and playback an example in the other but remain quiet so its just the example we get.

cd util

python raw2wav.py
You should now see in this dir some extra wav files
You may have to sudo apt-get install python-numpy
python get_delay.py recording.wav playback.wav
That should get you something like this

pi@raspberrypi:~/ec/util $ python get_delay.py recording.wav  playback.wav
get_delay.py:35: RuntimeWarning: invalid value encountered in divide
  cc = np.fft.irfft(R / np.abs(R), n=(interp * n))
[-8000.0, -8000.0]
[-8000.0, -8000.0]
[-8000.0, -8000.0]
[-8000.0, -8000.0]
[-8000.0, -8000.0]
[-8000.0, -8000.0]
[-8000.0, -8000.0]
[-8000.0, -8000.0]
[-8000.0, -8000.0]
[-8000.0, -8000.0]
[746.0, 745.0]
[746.0, 746.0]
[746.0, 745.0]
[747.0, 745.0]
[746.0, 745.0]
[746.0, 745.0]
[747.0, 745.0]
[746.0, 745.0]
[746.0, 745.0]
[747.0, 745.0]
[747.0, 745.0]
[746.0, 745.0]
[747.0, 745.0]
[747.0, 745.0]
[746.0, 745.0]
[747.0, 745.0]
[747.0, 745.0]
[746.0, 745.0]
[746.0, 745.0]
[747.0, 745.0]
[747.0, 745.0]
[746.0, 745.0]
[747.0, 745.0]
[747.0, 745.0]
[750.0, 745.0]
[747.0, 745.0]
[747.0, 745.0]
[746.0, 745.0]
[746.0, 745.0]
[747.0, 745.0]
[747.0, 745.0]
[746.0, 745.0]
[747.0, 745.0]
[747.0, 745.0]
[746.0, 745.0]
[747.0, 745.0]
[747.0, 745.0]
[746.0, 745.0]
[746.0, 745.0]
[747.0, 745.0]
[747.0, 745.0]
[750.0, 745.0]
[747.0, 745.0]
[747.0, 745.0]
[747.0, 745.0]
[747.0, 745.0]
[747.0, 745.0]
[746.0, 745.0]
[747.0, 745.0]
[747.0, 745.0]
[750.0, 745.0]
[750.0, 745.0]
[747.0, 745.0]
[747.0, 745.0]
[750.0, 745.0]
[747.0, 745.0]
[747.0, 745.0]
[746.0, 745.0]
[749.0, 0.0]
[-265.0, 1689.0]
[-8000.0, -8000.0]
[-8000.0, -8000.0]
[-8000.0, -8000.0]

Now as far as I can make out that is the delay in samples of your channels and above with the 2 mic left/right
So 746 samples to turn into Hz = 746/16000 as that is our sample rate.

So 0.0466 Hz or approx 46 msec which the -d of ec is from what I can read of the code even though it says frames.

So for me I would try ./ec -i plughw:2 -o plughw:2 -d 46 and that should of taken the guess work out of the speaker2mic delay, also not sure if it should be centered in the frame which guess would be +5.

1 Like

PS last thing and prob just total OCD

in /src/ec.c

    /* int frame_size = config.rate * 10 / 1000; // 10 ms */
    int frame_size = 256; 

We are always recording @ 16K and the above gives a frame size of 160 but I did read in the SpeexDsp blurb that really the frame size for effcient FFT should be a power of 2^
Very hard to tell as from listening very little difference but does seem to give a better Audacity plot.

make clean
make and it will compile the above change.