A few days ago Win32 under the Speex AEC (http://blog.csdn.net/sunkwei/archive/2011/05/18/6429096.aspx), very complex, today to try to make alsa under, found very simple AH!!! First of all, put on the Audacity effect chart:
The code is simple, and the effect seems to be better than Win32.
Because the code is simple, just stick it in here.
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <alloca.h> #include < math.h> #include <alsa/asoundlib.h> #include <sys/socket.h> #include <sys/types.h> #include < netinet/in.h> #include <arpa/inet.h> #include <pthread.h> #include <assert.h> #include <speex/ speex_echo.h> #include <speex/speex_preprocess.h> #include "util_cirbuf.h" #define SAVEFILE 1 #define Listen_ PORT 7777 #define PERIOD_NUM 3 #define FRAMESIZE 160 static snd_pcm_uframes_t _period_size = 160; static unsigned int _period_bytes = 320; sock static int _sock_listen =-1, _sock_sender =-1; static struct sockaddr_in _target; static char *_target_ip; ARGV[1]//Speex obj static speexechostate *_speex_aec = 0; static Speexpreprocessstate *_speex_preprocess = 0; snd obj static snd_pcm_t *_snd_capture = 0, *_snd_playback = 0; FIFO, receive buffer, recording buffer, playback buffer static struct tea_cirbuf_t *_cbuf_recv = 0, *_cbuf_capture = 0, *_CBUF_playback = 0; recv thread static void *_thread_recv (void *p) {/** recv UDP data. And save into _CBUF_RECV/assert (_sock_listen!= -1); ASSERT (_CBUF_RECV); while (1) {char buf[4096];//each PCM packet cannot exceed struct sockaddr_in from; socklen_t fromlen = sizeof (from); int rc = Recvfrom (_s Ock_listen, buf, sizeof (BUF), 0, (struct sockaddr*), &from); if (RC < 0) {fprintf (stderr, "%s:recvfrom err/n", __func__); exit ( -1);}//Chk _cbuf_recv if (util_cbuf_space RECV) < RC) {//Todo:overflow, ERR, can actually empty the processing fprintf (stderr,%S:RECV overflow!!!!!! /n ", __func__); Exit (-1); } util_cbuf_save (_cbuf_recv, buf, RC); fprintf (stderr, "."); return 0; The static int Start_listener () {_sock_listen = socket (af_inet, SOCK_DGRAM, 0); if (_sock_listen = = 1) {fprintf (stderr, " %s:open Listen sock err/n ", __func__); Exit (-1); return-1; } struct sockaddr_in sin; sin.sin_family = af_inet; Sin.sin_port = htons (Listen_port); SIN.SIN_ADDR.S_ADDR = Inaddr_any; if (Bind (_sock_listen, (struct sockaddr*) &sin, sizeof (SIN)) < 0) {fprintf (stderr, "%s:bind Listen port%d err/n", __func__, Listen_port ); Exit (-1); return-1; }//start recv thread pthread_t th; if (pthread_create (&th, 0, _THREAD_RECV, 0)) {fprintf (stderr, "%s:create recv thread err/n", __func__); exit ( -1); re turn-1; return 1; static int Start_sender () {_sock_sender = socket (af_inet, SOCK_DGRAM, 0); if (_sock_sender = = 1) {fprintf (stderr, "% S:create Sender sock err/n ", __func__); Exit (-1); return-1; } _target.sin_family = Af_inet; _target.sin_port = htons (Listen_port); _TARGET.SIN_ADDR.S_ADDR = inet_addr (_TARGET_IP); return 1; static int sendpcm (void *pcm, size_t len) {return sendto (_sock_sender, PCM, Len, 0, (struct sockaddr*) &_target, siz EOF (_target)); } static void Pop_data (struct tea_cirbuf_t *cbuf, char *buf, size_t bufsize) {assert (Util_cbuf_data (cbuf) >= bufsize) ; Char *p; size_t cs = util_cbuf_get_cdata (cbuf, &p); if (CS >= bufsize) {memcpy (buf, p, Bufsize); Util_cbuf_consume (Cbuf, bufsize); else {memcpy (buf, p, CS); Util_cbuf_consume (Cbuf, cs); buf = cs; bufsize-= CS; Util_cbuf_get_cdata (CBUF, &p); mem CPY (BUF, p, bufsize); Util_cbuf_consume (Cbuf, bufsize); } static double Now () {struct timeval TV; Gettimeofday (&TV, 0); return tv.tv_sec + 0.000001*tv.tv_usec;} #define PI 3.1415927/** makes 1khz sine wave for 8k mono, each sample changes to PI/4 */static void Make_sine (short *sample_buf, int samples) {Double RA Dian = 0; for (int i = 0; i < samples; i++) {Sample_buf[i] = 65535 * 0.7 * sin (radian); Radian + = Pi/4;}} /** worker thread, use blocking mode, write (), read () .... */static void *_thread_run (void *p) {assert (_snd_capture && _snd_playbac k); unsigned char *silence = (unsigned char *) malloc (_period_bytes); memset (Silence, 0, _period_bytes); Make_sine (Silence, _period_size); unsigned char *playback_data = (unsigned char *) malloc (_period_bytes); unsigned char *capture_data = (unsigned char *) malloc (_period_bytes); unsigned char *outbuf= (unsigned char*) malloc (_period_bytes); AEC output BUF//Start if (Snd_pcm_start (_snd_capture) < 0) {fprintf (stderr, "%s:snd_pcm_start for capture err/n" , __func__); Exit (-1); } if (Snd_pcm_start (_snd_playback) < 0) {fprintf (stderr, "%s:snd_pcm_start for playback err/n", __func__); exit (-1); } snd_pcm_prepare (_snd_playback); Snd_pcm_prepare (_snd_capture); Double Curr = Now (); while (1) {//p unsigned char *p = silence for data that needs to be written to the sound card (Util_cbuf_data (_CBUF_RECV) >= _period_bytes) {pop_data (_CB UF_RECV, Playback_data, _period_bytes); p = playback_data; else {fprintf (stderr, "S");} int rc = Snd_pcm_writei (_snd_playback, p, _period_size); if (rc = = _period_size) {} else if (rc = =-epipe) {fprintf (stderr,%s:snd_pcm_writei xrun!/n, __func__); exit (-1);} else {fprintf (stderr, "%s:snd_pcm_writei ret%d/n", __func__, RC); exit ( -1);}/read from capture rc = Snd_pcm_readi ( _snd_capture, Capture_data, _period_size); if (rc = = _period_size) {} else if (rc =-epipe{fprintf (stderr, "%s:snd_pcm_readi xrun/n", __func__); exit ( -1);} else {fprintf (stderr, "%s:snd_pcm_readi ERR, code =%d/n ", __func__, RC); Exit (-1); }//AEC speex_echo_cancellation (_SPEEX_AEC, (short*) Capture_data, (short*) Playback_data, (short*) outbuf); Speex_preprocess_run (_speex_preprocess, outbuf); Send to target SENDPCM (Outbuf, _period_size); #if savefile FILE *fp_c = fopen ("CAPTURE.PCM", "AB"); FILE *fp_p = fopen ("PLAYBACK.PCM", "AB"); FILE *fp_o = fopen ("AECD.PCM", "AB"); Fwrite (Capture_data, 1, _period_bytes, Fp_c); Fwrite (Playback_data, 1, _period_bytes, fp_p); Fwrite (Outbuf, 1, _period_bytes, fp_o); Fclose (Fp_c); Fclose (fp_p); Fclose (Fp_o); #endif//Save File}}/** set parameters, Mono, 16bits, 8k */static int set_params (snd_pcm_t *snd) {int err; snd_pcm_hw_params_ T *hwparams; Snd_pcm_hw_params_alloca (&hwparams); if (Snd_pcm_hw_params_any (SND, Hwparams) < 0) {fprintf (stderr,%s:snd_pcm_hw_params_any err/n, __func__); exit (-1) ; return-1; } if (Snd_pcm_hw_paraMs_set_access (snd, Hwparams, snd_pcm_access_rw_interleaved) < 0) {fprintf (stderr, "%s:set_access err/n", __func__); Exit (-1); } if (Snd_pcm_hw_params_set_channels (SND, Hwparams, 1)) {fprintf (stderr,%s:set_channels err/n, __func__); exit (-1);} if (Snd_pcm_hw_params_set_format (snd, Hwparams, Snd_pcm_format_s16_le)) {fprintf (stderr, "%s:set_format err/n", __ FUNC__); Exit (-1); } if (Snd_pcm_hw_params_set_rate (SND, Hwparams, 8000, 1)) {fprintf (stderr, "%s:set_rate err/n", __func__); exit (-1);}/ /Set period size int dir; if (Snd_pcm_hw_params_set_period_size_near (snd, Hwparams, &_period_size, &dir) < 0) {fprintf (stderr, "%s: Snd_pcm_hw_params_set_period_size_near err/n ", __func__); Exit (-1); } fprintf (stderr, "set Period size=%u/n", _period_size); _period_bytes = _period_size*2; Set buffer size if (snd_pcm_hw_params_set_buffer_size (snd, Hwparams, period_num*_period_bytes) < 0) {fprintf (Stder R, "%s:snd_pcm_hw_params_set_buffer_size err/n", __func__); Exit-1); } if (Snd_pcm_hw_params (SND, Hwparams) < 0) {fprintf (stderr,%s:snd_pcm_hw_params err/n, __func__); exit (-1);}// Set software params snd_pcm_sw_params_t *swparams; Snd_pcm_sw_params_alloca (&swparams); return 1; /** Open Alsa plughw:0,0 for capture */static int open_snd_capture () {int err = Snd_pcm_open (&_snd_capture, "Defau LT ", snd_pcm_stream_capture, 0); if (Err < 0) {fprintf (stderr, "%s:snd_pcm_open err/n", __func__); exit ( -1); return-1;} set_params (_snd_capture); return 1; }//Open plughw:0,0 for playback static int open_snd_playback () {int err = Snd_pcm_open (&_snd_playback, "Default", Snd_pcm_stream_playback, 0); if (Err < 0) {fprintf (stderr, "%s:snd_pcm_open err/n", __func__); exit ( -1); return-1;} set_params (_snd_playback); return 1; int main (int argc, char **argv) {if (argc!= 2) {fprintf (stderr, "Usage:%s <target ip>/n", argv[0]); return-1 ; } _target_ip = StrDup (argv[1]); Speex state int sample_rate = 8000; _speex_aec = Speex_echo_state_init (framesize, 2500); _speex_preprocess = Speex_preprocess_state_init (framesize, 8000); Speex_echo_ctl (_SPEEX_AEC, Speex_echo_set_sampling_rate, &sample_rate); Speex_preprocess_ctl (_speex_preprocess, Speex_preprocess_set_echo_state, _SPEEX_AEC); int DN = 1; Speex_preprocess_ctl (_speex_preprocess, Speex_preprocess_set_denoise, &DN); Prepare Cbufs _cbuf_recv = util_cbuf_create (64*1024); _cbuf_capture = Util_cbuf_create (4*1024); _cbuf_playback = Util_cbuf_create (4*1024); Start local listener start_listener (); Start Sender sock start_sender (); Open playback open_snd_playback (); Open_snd_capture (); Work thread pthread_t th; Pthread_create (&th, 0, _thread_run, 0); while (1) {if (GetChar () = = ' Q ') {break;}} return 0; }
Also need that UTIL_CIRBUF.C util_cirbuf.h, here download http://download.csdn.net/source/3290182