| 
					
				 | 
			
			
				@@ -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 ] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 |