|
@@ -0,0 +1,240 @@
|
|
|
|
+### ALSA virtual device which combines recording and playback loopback for AEC processing
|
|
|
|
+# https://github.com/sanebow/alsa-aec
|
|
|
|
+# sanebow@gmail.com
|
|
|
|
+# Version: 0.3 (20210506)
|
|
|
|
+
|
|
|
|
+defaults.pcm.aec.playback_hw.card defaults.pcm.card # playback hw card
|
|
|
|
+defaults.pcm.aec.playback_hw.rate 48000 # sample rate supported by the playback card
|
|
|
|
+defaults.pcm.aec.capture_hw.card defaults.pcm.card # capture hw card
|
|
|
|
+defaults.pcm.aec.capture_hw.rate 16000 # sample rate supported by the capture card
|
|
|
|
+## you may also directly set some PCM device as playback and capture device
|
|
|
|
+defaults.pcm.aec.playback_pcm "playback_hw"
|
|
|
|
+defaults.pcm.aec.capture_pcm "capture_hw"
|
|
|
|
+defaults.pcm.aec.pre_loopidx 4 # loopback subdevice index for stream before aec processing
|
|
|
|
+defaults.pcm.aec.post_loopidx 5 # loopback subdevice index for stream after aec processing
|
|
|
|
+
|
|
|
|
+pcm.playback_hw {
|
|
|
|
+ @args [ CARD RATE ]
|
|
|
|
+ @args.CARD {
|
|
|
|
+ type string
|
|
|
|
+ default {
|
|
|
|
+ @func refer
|
|
|
|
+ name defaults.pcm.aec.playback_hw.card
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ @args.RATE {
|
|
|
|
+ type integer
|
|
|
|
+ default {
|
|
|
|
+ @func refer
|
|
|
|
+ name defaults.pcm.aec.playback_hw.rate
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ type plug
|
|
|
|
+ slave.rate "unchanged"
|
|
|
|
+ slave.pcm {
|
|
|
|
+ type rate
|
|
|
|
+ slave.rate $RATE
|
|
|
|
+ slave.pcm {
|
|
|
|
+ type dmix
|
|
|
|
+ ipc_key 10009
|
|
|
|
+ ipc_key_add_uid yes
|
|
|
|
+ slave {
|
|
|
|
+ pcm {@func concat strings [ "hw:" $CARD ] }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+pcm.capture_hw {
|
|
|
|
+ @args [ CARD RATE ]
|
|
|
|
+ @args.CARD {
|
|
|
|
+ type string
|
|
|
|
+ default {
|
|
|
|
+ @func refer
|
|
|
|
+ name defaults.pcm.aec.capture_hw.card
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ @args.RATE {
|
|
|
|
+ type integer
|
|
|
|
+ default {
|
|
|
|
+ @func refer
|
|
|
|
+ name defaults.pcm.aec.capture_hw.rate
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ type rate
|
|
|
|
+ slave.rate $RATE
|
|
|
|
+ slave.pcm {
|
|
|
|
+ type dsnoop
|
|
|
|
+ ipc_key 20009
|
|
|
|
+ ipc_key_add_uid yes
|
|
|
|
+ slave {
|
|
|
|
+ pcm {@func concat strings [ "hw:" $CARD ] }
|
|
|
|
+ rate $RATE
|
|
|
|
+ }
|
|
|
|
+ bindings.0 0
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+pcm.loopback_out {
|
|
|
|
+ @args [ SUBDEVICE ]
|
|
|
|
+ @args.SUBDEVICE { type integer }
|
|
|
|
+ type empty
|
|
|
|
+ slave.pcm {
|
|
|
|
+ type hw
|
|
|
|
+ card "Loopback"
|
|
|
|
+ device 0
|
|
|
|
+ subdevice $SUBDEVICE
|
|
|
|
+ channels 1
|
|
|
|
+ rate 16000
|
|
|
|
+ format S16_LE
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+pcm.loopback_in {
|
|
|
|
+ @args [ SUBDEVICE ]
|
|
|
|
+ @args.SUBDEVICE { type integer }
|
|
|
|
+ type empty
|
|
|
|
+ slave.pcm {
|
|
|
|
+ type hw
|
|
|
|
+ card "Loopback"
|
|
|
|
+ device 1
|
|
|
|
+ subdevice $SUBDEVICE
|
|
|
|
+ channels 1
|
|
|
|
+ rate 16000
|
|
|
|
+ format S16_LE
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+# audio play to this device will be duplicated to hw (stereo) and loopback (mono)
|
|
|
|
+pcm.mloopplay {
|
|
|
|
+ @args [ PCM LOOPIDX ]
|
|
|
|
+ @args.PCM {
|
|
|
|
+ type string
|
|
|
|
+ default {
|
|
|
|
+ @func refer
|
|
|
|
+ name defaults.pcm.aec.playback_pcm
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ @args.LOOPIDX {
|
|
|
|
+ type integer
|
|
|
|
+ default 4
|
|
|
|
+ }
|
|
|
|
+ type route
|
|
|
|
+ slave.pcm {
|
|
|
|
+ type multi
|
|
|
|
+ slaves.a.pcm $PCM
|
|
|
|
+ slaves.a.channels 2
|
|
|
|
+ slaves.b.pcm { # loopback null sink
|
|
|
|
+ @func concat
|
|
|
|
+ strings [ "plug:loopback_out:" $LOOPIDX ]
|
|
|
|
+ }
|
|
|
|
+ slaves.b.channels 1
|
|
|
|
+ bindings.0 { slave a channel 0 }
|
|
|
|
+ bindings.1 { slave a channel 1 }
|
|
|
|
+ bindings.2 { slave b channel 0 }
|
|
|
|
+ }
|
|
|
|
+ slave.channels 3
|
|
|
|
+ ttable.0.0 1
|
|
|
|
+ ttable.1.1 1
|
|
|
|
+ ttable.0.2 0.5
|
|
|
|
+ ttable.1.2 0.5
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+# combine mic (ch 0) and loopback (ch 1) to single recording
|
|
|
|
+pcm.mlooprec {
|
|
|
|
+ @args [ PCM LOOPIDX ]
|
|
|
|
+ @args.PCM {
|
|
|
|
+ type string
|
|
|
|
+ default {
|
|
|
|
+ @func refer
|
|
|
|
+ name defaults.pcm.aec.capture_pcm
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ @args.LOOPIDX {
|
|
|
|
+ type integer
|
|
|
|
+ default 4
|
|
|
|
+ }
|
|
|
|
+ type multi
|
|
|
|
+ slaves.a.pcm $PCM
|
|
|
|
+ slaves.a.channels 1
|
|
|
|
+ slaves.b.pcm { # loopback capturing interface
|
|
|
|
+ type dsnoop # to align with capture_hw, avoid PortAudio error
|
|
|
|
+ ipc_key 10099
|
|
|
|
+ slave.pcm {
|
|
|
|
+ @func concat
|
|
|
|
+ strings [ "loopback_in:" $LOOPIDX ]
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ slaves.b.channels 1
|
|
|
|
+ bindings.0 { slave a channel 0 }
|
|
|
|
+ bindings.1 { slave b channel 0 }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+pcm.aec_internal {
|
|
|
|
+ @args [ CAPPCM PRELOOPIDX POSTLOOPIDX ]
|
|
|
|
+ @args.CAPPCM {
|
|
|
|
+ type string
|
|
|
|
+ default {
|
|
|
|
+ @func refer
|
|
|
|
+ name defaults.pcm.aec.capture_pcm
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ @args.PRELOOPIDX {
|
|
|
|
+ type integer
|
|
|
|
+ default {
|
|
|
|
+ @func refer
|
|
|
|
+ name defaults.pcm.aec.pre_loopidx
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ @args.POSTLOOPIDX {
|
|
|
|
+ type integer
|
|
|
|
+ default {
|
|
|
|
+ @func refer
|
|
|
|
+ name defaults.pcm.aec.post_loopidx
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ type asym
|
|
|
|
+ capture.pcm { # -i for aec script
|
|
|
|
+ @func concat
|
|
|
|
+ strings [ "mlooprec:" $CAPPCM "," $PRELOOPIDX ]
|
|
|
|
+ }
|
|
|
|
+ playback.pcm { # -o for aec script
|
|
|
|
+ @func concat
|
|
|
|
+ strings [ "loopback_out:" $POSTLOOPIDX ]
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+pcm.aec {
|
|
|
|
+ @args [ PLYPCM PRELOOPIDX POSTLOOPIDX ]
|
|
|
|
+ @args.PLYPCM {
|
|
|
|
+ type string
|
|
|
|
+ default {
|
|
|
|
+ @func refer
|
|
|
|
+ name defaults.pcm.aec.playback_pcm
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ @args.PRELOOPIDX {
|
|
|
|
+ type integer
|
|
|
|
+ default {
|
|
|
|
+ @func refer
|
|
|
|
+ name defaults.pcm.aec.pre_loopidx
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ @args.POSTLOOPIDX {
|
|
|
|
+ type integer
|
|
|
|
+ default {
|
|
|
|
+ @func refer
|
|
|
|
+ name defaults.pcm.aec.post_loopidx
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ type asym
|
|
|
|
+ playback.pcm {
|
|
|
|
+ @func concat
|
|
|
|
+ strings [ "mloopplay:" $PLYPCM "," $PRELOOPIDX ]
|
|
|
|
+ }
|
|
|
|
+ capture.pcm {
|
|
|
|
+ @func concat
|
|
|
|
+ strings [ "loopback_in:" $POSTLOOPIDX ]
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|