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