API: Change celt_encode and celt_encode_float so that they take an optional synthesis...
[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, 2, 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, 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             packet.data = msg;
187             jitter_buffer_get(jitter, &packet, FRAME_SIZE, NULL);
188             celt_decode(dec_state, packet.data, packet.len, pcm);
189          } else {
190             for (i=0;i<FRAME_SIZE;i++)
191                pcm[i] = 0;
192          }
193          /* Playback the audio and reset the echo canceller if we got an underrun */
194          if (alsa_device_write(audio_dev, pcm, FRAME_SIZE))
195             speex_echo_state_reset(echo_state);
196          /* Put frame into playback buffer */
197          speex_echo_playback(echo_state, pcm);
198       }
199       /* Audio available from the soundcard (capture) */
200       if (alsa_device_capture_ready(audio_dev, pfds, nfds))
201       {
202          short pcm[FRAME_SIZE], pcm2[FRAME_SIZE];
203          char outpacket[MAX_MSG];
204          /* Get audio from the soundcard */
205          alsa_device_read(audio_dev, pcm, FRAME_SIZE);
206          
207          /* Perform echo cancellation */
208          speex_echo_capture(echo_state, pcm, pcm2);
209          for (i=0;i<FRAME_SIZE;i++)
210             pcm[i] = pcm2[i];
211          
212          /* Encode */
213          celt_encode(enc_state, pcm, NULL, outpacket+4, packetSize);
214          
215          /* Pseudo header: four null bytes and a 32-bit timestamp */
216          ((int*)outpacket)[0] = send_timestamp;
217          send_timestamp += FRAME_SIZE;
218          rc = sendto(sd, outpacket, packetSize+4, 0,
219                 (struct sockaddr *) &remoteAddr,
220                 sizeof(remoteAddr));
221          
222          if(rc<0) {
223             perror("cannot send to socket");
224             close(sd);
225             exit(1);
226          }
227       }
228       
229
230    }
231
232
233    return 0;
234 }