This fixes the frame_size check on the encoder and decoder and removes some unused...
[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    Copyright (C) 2008-2009 Gregory Maxwell
6    Copyright (c) 2007-2009 Xiph.Org Foundation
7
8    Redistribution and use in source and binary forms, with or without
9    modification, are permitted provided that the following conditions
10    are met:
11    
12    - Redistributions of source code must retain the above copyright
13    notice, this list of conditions and the following disclaimer.
14    
15    - Redistributions in binary form must reproduce the above copyright
16    notice, this list of conditions and the following disclaimer in the
17    documentation and/or other materials provided with the distribution.
18    
19    - Neither the name of the Xiph.org Foundation nor the names of its
20    contributors may be used to endorse or promote products derived from
21    this software without specific prior written permission.
22    
23    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24    ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26    A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
27    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34    
35 ****************************************************************************/
36  
37 #ifdef HAVE_CONFIG_H
38 #include <config.h>
39 #endif
40
41 #include <stdlib.h>
42 #include <sys/types.h>
43 #include <sys/socket.h>
44 #include <netinet/in.h>
45 #include <arpa/inet.h>
46 #include <netdb.h>
47 #include <stdio.h>
48 #include <unistd.h> /* close() */
49 #include <string.h> /* memset() */
50
51 #include "alsa_device.h"
52 #include <celt.h>
53 #include <speex/speex_jitter.h>
54
55 #include <sched.h>
56
57 #define MAX_MSG 1500
58 #define SAMPLING_RATE 48000
59 #define FRAME_SIZE 256
60 #define PACKETSIZE 43
61 #define CHANNELS 1
62 #define HAS_SPEEX_AEC 
63
64 #if CHANNELS == 2
65 /* FIXME: The Speex AEC has multichannel support; but that API isn't being
66    used here yet. */
67 #undef HAS_SPEEX_AEC   
68 #endif
69
70 #ifdef HAS_SPEEX_AEC 
71 #include <speex/speex_echo.h>
72 #endif
73
74 int main(int argc, char *argv[])
75 {
76    
77    int sd, rc, n;
78    int i;
79    struct sockaddr_in cliAddr, remoteAddr;
80    char msg[MAX_MSG];
81    struct hostent *h;
82    int local_port, remote_port;
83    int nfds;
84    struct pollfd *pfds;
85    AlsaDevice *audio_dev;
86    int tmp;
87
88    if (argc != 5)
89    {
90       fprintf(stderr, "Usage %s plughw:0,0 remote_host local_udp_port remote_udp_port\n",argv[0]);
91       exit(1);
92    }
93   
94    h = gethostbyname(argv[2]);
95    if(h==NULL) {
96       fprintf(stderr, "%s: unknown host '%s' \n", argv[0], argv[2]);
97       exit(1);
98    }
99
100    local_port = atoi(argv[3]);
101    remote_port = atoi(argv[4]);
102    
103    printf("%s: sending data to '%s' (IP : %s) \n", argv[0], h->h_name,
104           inet_ntoa(*(struct in_addr *)h->h_addr_list[0]));
105
106    {
107       remoteAddr.sin_family = h->h_addrtype;
108       memcpy((char *) &remoteAddr.sin_addr.s_addr,
109             h->h_addr_list[0], h->h_length);
110       remoteAddr.sin_port = htons(remote_port);
111    }
112    /* socket creation */
113    sd=socket(AF_INET, SOCK_DGRAM, 0);
114    if(sd<0) {
115       printf("%s: cannot open socket \n",argv[0]);
116       exit(1);
117    }
118
119    /* bind any port */
120    cliAddr.sin_family = AF_INET;
121    cliAddr.sin_addr.s_addr = htonl(INADDR_ANY);
122    cliAddr.sin_port = htons(local_port);
123
124    rc = bind(sd, (struct sockaddr *) &cliAddr, sizeof(cliAddr));
125    if(rc<0) {
126       printf("%s: cannot bind port\n", argv[0]);
127       exit(1);
128    }
129
130    /* Setup audio device */
131    audio_dev = alsa_device_open(argv[1], SAMPLING_RATE, CHANNELS, FRAME_SIZE);
132    
133    /* Setup the encoder and decoder in wideband */
134    CELTEncoder *enc_state;
135    CELTDecoder *dec_state;
136    CELTMode *mode = celt_mode_create(SAMPLING_RATE, FRAME_SIZE, NULL);
137    enc_state = celt_encoder_create(mode, CHANNELS, NULL);
138    dec_state = celt_decoder_create(mode, CHANNELS, NULL);
139    struct sched_param param;
140    /*param.sched_priority = 40; */
141    param.sched_priority = sched_get_priority_min(SCHED_FIFO);
142    if (sched_setscheduler(0,SCHED_FIFO,&param))
143       perror("sched_setscheduler");
144
145    int send_timestamp = 0;
146    int recv_started=0;
147    
148    /* Setup all file descriptors for poll()ing */
149    nfds = alsa_device_nfds(audio_dev);
150    pfds = malloc(sizeof(*pfds)*(nfds+1));
151    alsa_device_getfds(audio_dev, pfds, nfds);
152    pfds[nfds].fd = sd;
153    pfds[nfds].events = POLLIN;
154
155    /* Setup jitter buffer using decoder */
156    JitterBuffer *jitter;
157    jitter = jitter_buffer_init(FRAME_SIZE);
158    tmp = FRAME_SIZE;
159    jitter_buffer_ctl(jitter, JITTER_BUFFER_SET_MARGIN, &tmp);
160 #ifdef HAS_SPEEX_AEC
161    /* Echo canceller with 200 ms tail length */
162    SpeexEchoState *echo_state = speex_echo_state_init(FRAME_SIZE, 10*FRAME_SIZE);
163    tmp = SAMPLING_RATE;
164    speex_echo_ctl(echo_state, SPEEX_ECHO_SET_SAMPLING_RATE, &tmp);
165 #endif   
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          n = recv(sd, msg, MAX_MSG, 0);
177          int recv_timestamp = ((int*)msg)[0];
178    
179          JitterBufferPacket packet;
180          packet.data = msg+4;
181          packet.len = n-4;
182          packet.timestamp = recv_timestamp;
183          packet.span = FRAME_SIZE;
184          packet.sequence = 0;
185          /* Put content of the packet into the jitter buffer, except for the pseudo-header */
186          jitter_buffer_put(jitter, &packet);
187          recv_started = 1;
188
189       }
190       /* Ready to play a frame (playback) */
191       if (alsa_device_playback_ready(audio_dev, pfds, nfds))
192       {
193          short pcm[FRAME_SIZE*CHANNELS];
194          if (recv_started)
195          {
196             JitterBufferPacket packet;
197             /* Get audio from the jitter buffer */
198             packet.data = msg;
199             packet.len  = MAX_MSG;
200             jitter_buffer_tick(jitter);
201             jitter_buffer_get(jitter, &packet, FRAME_SIZE, NULL);
202             if (packet.len==0)
203               packet.data=NULL;
204             celt_decode(dec_state, packet.data, packet.len, pcm);
205          } else {
206             for (i=0;i<FRAME_SIZE*CHANNELS;i++)
207                pcm[i] = 0;
208          }
209          /* Playback the audio and reset the echo canceller if we got an underrun */
210
211 #ifdef HAS_SPEEX_AEC
212          if (alsa_device_write(audio_dev, pcm, FRAME_SIZE)) 
213             speex_echo_state_reset(echo_state);
214          /* Put frame into playback buffer */
215          speex_echo_playback(echo_state, pcm);
216 #else
217          alsa_device_write(audio_dev, pcm, FRAME_SIZE);
218 #endif
219       }
220       /* Audio available from the soundcard (capture) */
221       if (alsa_device_capture_ready(audio_dev, pfds, nfds))
222       {
223          short pcm[FRAME_SIZE*CHANNELS], pcm2[FRAME_SIZE*CHANNELS];
224          char outpacket[MAX_MSG];
225          /* Get audio from the soundcard */
226          alsa_device_read(audio_dev, pcm, FRAME_SIZE);
227          
228 #ifdef HAS_SPEEX_AEC
229          /* Perform echo cancellation */
230          speex_echo_capture(echo_state, pcm, pcm2);
231          for (i=0;i<FRAME_SIZE*CHANNELS;i++)
232             pcm[i] = pcm2[i];
233 #endif   
234          /* Encode */
235          celt_encode(enc_state, pcm, NULL, outpacket+4, PACKETSIZE);
236          
237          /* Pseudo header: four null bytes and a 32-bit timestamp */
238          ((int*)outpacket)[0] = send_timestamp;
239          send_timestamp += FRAME_SIZE;
240          rc = sendto(sd, outpacket, PACKETSIZE+4, 0,
241                 (struct sockaddr *) &remoteAddr,
242                 sizeof(remoteAddr));
243          
244          if(rc<0) {
245             perror("cannot send to socket");
246             close(sd);
247             exit(1);
248          }
249       }
250       
251
252    }
253
254
255    return 0;
256 }