added suffix to real fft. The celtclient can now be built with an unmodified
[opus.git] / tools / celtclient.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 <celt.h>
51 #include <speex/speex_echo.h>
52 #include <speex/speex_jitter.h>
53
54 #include <sched.h>
55
56 #define MAX_MSG 1500
57
58 #define SAMPLING_RATE 48000
59 #define FRAME_SIZE 256
60
61 int main(int argc, char *argv[])
62 {
63    
64    int sd, rc, n;
65    int i;
66    struct sockaddr_in cliAddr, remoteAddr;
67    char msg[MAX_MSG];
68    struct hostent *h;
69    int local_port, remote_port;
70    int nfds;
71    struct pollfd *pfds;
72    AlsaDevice *audio_dev;
73    int tmp;
74    int packetSize = 32;
75
76    if (argc != 5)
77    {
78       fprintf(stderr, "wrong options\n");
79       exit(1);
80    }
81   
82    h = gethostbyname(argv[2]);
83    if(h==NULL) {
84       fprintf(stderr, "%s: unknown host '%s' \n", argv[0], argv[1]);
85       exit(1);
86    }
87
88    local_port = atoi(argv[3]);
89    remote_port = atoi(argv[4]);
90    
91    printf("%s: sending data to '%s' (IP : %s) \n", argv[0], h->h_name,
92           inet_ntoa(*(struct in_addr *)h->h_addr_list[0]));
93
94    {
95       remoteAddr.sin_family = h->h_addrtype;
96       memcpy((char *) &remoteAddr.sin_addr.s_addr,
97             h->h_addr_list[0], h->h_length);
98       remoteAddr.sin_port = htons(remote_port);
99    }
100    /* socket creation */
101    sd=socket(AF_INET, SOCK_DGRAM, 0);
102    if(sd<0) {
103       printf("%s: cannot open socket \n",argv[0]);
104       exit(1);
105    }
106
107    /* bind any port */
108    cliAddr.sin_family = AF_INET;
109    cliAddr.sin_addr.s_addr = htonl(INADDR_ANY);
110    cliAddr.sin_port = htons(local_port);
111
112    rc = bind(sd, (struct sockaddr *) &cliAddr, sizeof(cliAddr));
113    if(rc<0) {
114       printf("%s: cannot bind port\n", argv[0]);
115       exit(1);
116    }
117
118    /* Setup audio device */
119    audio_dev = alsa_device_open(argv[1], SAMPLING_RATE, 1, FRAME_SIZE);
120    
121    /* Setup the encoder and decoder in wideband */
122    CELTEncoder *enc_state;
123    CELTDecoder *dec_state;
124    CELTMode *mode = celt_mode_create(48000, 2, 256, 128, NULL);
125    enc_state = celt_encoder_create(mode);   
126    dec_state = celt_decoder_create(mode);   
127    struct sched_param param;
128    /*param.sched_priority = 40; */
129    param.sched_priority = sched_get_priority_min(SCHED_FIFO);
130    if (sched_setscheduler(0,SCHED_FIFO,&param))
131       perror("sched_setscheduler");
132
133    int send_timestamp = 0;
134    int recv_started=0;
135    
136    /* Setup all file descriptors for poll()ing */
137    nfds = alsa_device_nfds(audio_dev);
138    pfds = malloc(sizeof(*pfds)*(nfds+1));
139    alsa_device_getfds(audio_dev, pfds, nfds);
140    pfds[nfds].fd = sd;
141    pfds[nfds].events = POLLIN;
142
143    /* Setup jitter buffer using decoder */
144    JitterBuffer *jitter;
145    jitter = jitter_buffer_init(FRAME_SIZE);
146    tmp = FRAME_SIZE;
147    jitter_buffer_ctl(jitter, JITTER_BUFFER_SET_MARGIN, &tmp);
148    /* Echo canceller with 200 ms tail length */
149    SpeexEchoState *echo_state = speex_echo_state_init(FRAME_SIZE, 10*FRAME_SIZE);
150    tmp = SAMPLING_RATE;
151    speex_echo_ctl(echo_state, SPEEX_ECHO_SET_SAMPLING_RATE, &tmp);
152    
153    alsa_device_start(audio_dev);
154    
155    /* Infinite loop on capture, playback and receiving packets */
156    while (1)
157    {
158       /* Wait for either 1) capture 2) playback 3) socket data */
159       poll(pfds, nfds+1, -1);
160       /* Received packets */
161       if (pfds[nfds].revents & POLLIN)
162       {
163          /*fprintf (stderr, "x");*/
164          n = recv(sd, msg, MAX_MSG, 0);
165          int recv_timestamp = ((int*)msg)[0];
166    
167          JitterBufferPacket packet;
168          packet.data = msg+4;
169          packet.len = n-4;
170          packet.timestamp = recv_timestamp;
171          packet.span = FRAME_SIZE;
172          packet.sequence = 0;
173          /* Put content of the packet into the jitter buffer, except for the pseudo-header */
174          jitter_buffer_put(jitter, &packet);
175          recv_started = 1;
176
177       }
178       /* Ready to play a frame (playback) */
179       if (alsa_device_playback_ready(audio_dev, pfds, nfds))
180       {
181          short pcm[FRAME_SIZE];
182          if (recv_started)
183          {
184             JitterBufferPacket packet;
185             /* Get audio from the jitter buffer */
186             jitter_buffer_get(jitter, &packet, FRAME_SIZE, NULL);
187             celt_decode(dec_state, packet.data, packet.len, pcm);
188          } else {
189             for (i=0;i<FRAME_SIZE;i++)
190                pcm[i] = 0;
191          }
192          /* Playback the audio and reset the echo canceller if we got an underrun */
193          if (alsa_device_write(audio_dev, pcm, FRAME_SIZE))
194             speex_echo_state_reset(echo_state);
195          /* Put frame into playback buffer */
196          speex_echo_playback(echo_state, pcm);
197       }
198       /* Audio available from the soundcard (capture) */
199       if (alsa_device_capture_ready(audio_dev, pfds, nfds))
200       {
201          short pcm[FRAME_SIZE], pcm2[FRAME_SIZE];
202          char outpacket[MAX_MSG];
203          /* Get audio from the soundcard */
204          alsa_device_read(audio_dev, pcm, FRAME_SIZE);
205          
206          /* Perform echo cancellation */
207          speex_echo_capture(echo_state, pcm, pcm2);
208          for (i=0;i<FRAME_SIZE;i++)
209             pcm[i] = pcm2[i];
210          
211          /* Encode */
212          celt_encode(enc_state, pcm, outpacket+4, packetSize);
213          
214          /* Pseudo header: four null bytes and a 32-bit timestamp */
215          ((int*)outpacket)[0] = send_timestamp;
216          send_timestamp += FRAME_SIZE;
217          rc = sendto(sd, outpacket, packetSize+4, 0,
218                 (struct sockaddr *) &remoteAddr,
219                 sizeof(remoteAddr));
220          
221          if(rc<0) {
222             printf("cannot send audio data\n");
223             close(sd);
224             exit(1);
225          }
226       }
227       
228
229    }
230
231
232    return 0;
233 }