doc update
[speexdsp.git] / speexclient / speexclient.c
1 /***************************************************************************
2    Copyright (C) 2004-2006 by Jean-Marc Valin
3    Copyright (C) 2006 Commonwealth Scientific and Industrial Research
4                       Organisation (CSIRO) Australia
5
6    Redistribution and use in source and binary forms, with or without
7    modification, are permitted provided that the following conditions
8    are met:
9    
10    - Redistributions of source code must retain the above copyright
11    notice, this list of conditions and the following disclaimer.
12    
13    - Redistributions in binary form must reproduce the above copyright
14    notice, this list of conditions and the following disclaimer in the
15    documentation and/or other materials provided with the distribution.
16    
17    - Neither the name of the Xiph.org Foundation nor the names of its
18    contributors may be used to endorse or promote products derived from
19    this software without specific prior written permission.
20    
21    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22    ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24    A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
25    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32    
33 ****************************************************************************/
34  
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
38
39 #include <stdlib.h>
40 #include <sys/types.h>
41 #include <sys/socket.h>
42 #include <netinet/in.h>
43 #include <arpa/inet.h>
44 #include <netdb.h>
45 #include <stdio.h>
46 #include <unistd.h> /* close() */
47 #include <string.h> /* memset() */
48
49 #include "alsa_device.h"
50 #include <speex/speex.h>
51 #include <speex/speex_jitter.h>
52 #include <speex/speex_preprocess.h>
53 #include <speex/speex_echo.h>
54
55 #include <sched.h>
56
57 #define MAX_MSG 1500
58
59 #define SAMPLING_RATE 16000
60 #define FRAME_SIZE 320
61
62 int main(int argc, char *argv[])
63 {
64    
65    int sd, rc, n;
66    int i;
67    struct sockaddr_in cliAddr, remoteAddr;
68    char msg[MAX_MSG];
69    struct hostent *h;
70    int local_port, remote_port;
71    int nfds;
72    struct pollfd *pfds;
73    SpeexPreprocessState *preprocess;
74    AlsaDevice *audio_dev;
75    int tmp;
76
77    if (argc != 5)
78    {
79       fprintf(stderr, "wrong options\n");
80       exit(1);
81    }
82   
83    h = gethostbyname(argv[2]);
84    if(h==NULL) {
85       fprintf(stderr, "%s: unknown host '%s' \n", argv[0], argv[1]);
86       exit(1);
87    }
88
89    local_port = atoi(argv[3]);
90    remote_port = atoi(argv[4]);
91    
92    printf("%s: sending data to '%s' (IP : %s) \n", argv[0], h->h_name,
93           inet_ntoa(*(struct in_addr *)h->h_addr_list[0]));
94
95    {
96       remoteAddr.sin_family = h->h_addrtype;
97       memcpy((char *) &remoteAddr.sin_addr.s_addr,
98             h->h_addr_list[0], h->h_length);
99       remoteAddr.sin_port = htons(remote_port);
100    }
101    /* socket creation */
102    sd=socket(AF_INET, SOCK_DGRAM, 0);
103    if(sd<0) {
104       printf("%s: cannot open socket \n",argv[0]);
105       exit(1);
106    }
107
108    /* bind any port */
109    cliAddr.sin_family = AF_INET;
110    cliAddr.sin_addr.s_addr = htonl(INADDR_ANY);
111    cliAddr.sin_port = htons(local_port);
112
113    rc = bind(sd, (struct sockaddr *) &cliAddr, sizeof(cliAddr));
114    if(rc<0) {
115       printf("%s: cannot bind port\n", argv[0]);
116       exit(1);
117    }
118
119    /* Setup audio device */
120    audio_dev = alsa_device_open(argv[1], SAMPLING_RATE, 1, FRAME_SIZE);
121    
122    /* Setup the encoder and decoder in wideband */
123    void *enc_state, *dec_state;
124    enc_state = speex_encoder_init(&speex_wb_mode);
125    tmp = 8;
126    speex_encoder_ctl(enc_state, SPEEX_SET_QUALITY, &tmp);
127    tmp = 2;
128    speex_encoder_ctl(enc_state, SPEEX_SET_COMPLEXITY, &tmp);
129    dec_state = speex_decoder_init(&speex_wb_mode);
130    tmp = 1;
131    speex_decoder_ctl(dec_state, SPEEX_SET_ENH, &tmp);
132    SpeexBits enc_bits, dec_bits;
133    speex_bits_init(&enc_bits);
134    speex_bits_init(&dec_bits);
135    
136    
137    struct sched_param param;
138    /*param.sched_priority = 40; */
139    param.sched_priority = sched_get_priority_min(SCHED_FIFO);
140    if (sched_setscheduler(0,SCHED_FIFO,&param))
141       perror("sched_setscheduler");
142
143    int send_timestamp = 0;
144    int recv_started=0;
145    
146    /* Setup all file descriptors for poll()ing */
147    nfds = alsa_device_nfds(audio_dev);
148    pfds = malloc(sizeof(*pfds)*(nfds+1));
149    alsa_device_getfds(audio_dev, pfds, nfds);
150    pfds[nfds].fd = sd;
151    pfds[nfds].events = POLLIN;
152
153    /* Setup jitter buffer using decoder */
154    SpeexJitter jitter;
155    speex_jitter_init(&jitter, dec_state, SAMPLING_RATE);
156    
157    /* Echo canceller with 200 ms tail length */
158    SpeexEchoState *echo_state = speex_echo_state_init(FRAME_SIZE, 10*FRAME_SIZE);
159    tmp = SAMPLING_RATE;
160    speex_echo_ctl(echo_state, SPEEX_ECHO_SET_SAMPLING_RATE, &tmp);
161
162    /* Setup preprocessor and associate with echo canceller for residual echo suppression */
163    preprocess = speex_preprocess_state_init(FRAME_SIZE, SAMPLING_RATE);
164    speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_SET_ECHO_STATE, echo_state);
165    
166    alsa_device_start(audio_dev);
167    
168    /* Infinite loop on capture, playback and receiving packets */
169    while (1)
170    {
171       /* Wait for either 1) capture 2) playback 3) socket data */
172       poll(pfds, nfds+1, -1);
173       /* Received packets */
174       if (pfds[nfds].revents & POLLIN)
175       {
176          /*fprintf (stderr, "x");*/
177          n = recv(sd, msg, MAX_MSG, 0);
178          int recv_timestamp = ((int*)msg)[1];
179          int payload = ((int*)msg)[0];
180    
181          if ((payload & 0x80000000) == 0) 
182          {
183             /* Put content of the packet into the jitter buffer, except for the pseudo-header */
184             speex_jitter_put(&jitter, msg+8, n-8, recv_timestamp);
185             recv_started = 1;
186          }
187
188       }
189       /* Ready to play a frame (playback) */
190       if (alsa_device_playback_ready(audio_dev, pfds, nfds))
191       {
192          short pcm[FRAME_SIZE];
193          if (recv_started)
194          {
195             /* Get audio from the jitter buffer */
196             speex_jitter_get(&jitter, pcm, NULL);
197          } else {
198             for (i=0;i<FRAME_SIZE;i++)
199                pcm[i] = 0;
200          }
201          /* Playback the audio and reset the echo canceller if we got an underrun */
202          if (alsa_device_write(audio_dev, pcm, FRAME_SIZE))
203             speex_echo_state_reset(echo_state);
204          /* Put frame into playback buffer */
205          speex_echo_playback(echo_state, pcm);
206       }
207       /* Audio available from the soundcard (capture) */
208       if (alsa_device_capture_ready(audio_dev, pfds, nfds))
209       {
210          short pcm[FRAME_SIZE], pcm2[FRAME_SIZE];
211          char outpacket[MAX_MSG];
212          /* Get audio from the soundcard */
213          alsa_device_read(audio_dev, pcm, FRAME_SIZE);
214          
215          /* Perform echo cancellation */
216          speex_echo_capture(echo_state, pcm, pcm2);
217          for (i=0;i<FRAME_SIZE;i++)
218             pcm[i] = pcm2[i];
219          
220          speex_bits_reset(&enc_bits);
221          
222          /* Apply noise/echo suppression */
223          speex_preprocess_run(preprocess, pcm);
224          
225          /* Encode */
226          speex_encode_int(enc_state, pcm, &enc_bits);
227          int packetSize = speex_bits_write(&enc_bits, outpacket+8, MAX_MSG);
228          
229          /* Pseudo header: four null bytes and a 32-bit timestamp */
230          ((int*)outpacket)[0] = htonl(0);
231          ((int*)outpacket)[1] = send_timestamp;
232          send_timestamp += FRAME_SIZE;
233          rc = sendto(sd, outpacket, packetSize+8, 0,
234                 (struct sockaddr *) &remoteAddr,
235                 sizeof(remoteAddr));
236          
237          if(rc<0) {
238             printf("cannot send audio data\n");
239             close(sd);
240             exit(1);
241          }
242       }
243       
244
245    }
246
247
248    return 0;
249 }