Put the channel count outside of the energy calculation. Increased the allowed
[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    enc_state = celt_encoder_new(celt_mono);   
125    dec_state = celt_decoder_new(celt_mono);   
126    struct sched_param param;
127    /*param.sched_priority = 40; */
128    param.sched_priority = sched_get_priority_min(SCHED_FIFO);
129    if (sched_setscheduler(0,SCHED_FIFO,&param))
130       perror("sched_setscheduler");
131
132    int send_timestamp = 0;
133    int recv_started=0;
134    
135    /* Setup all file descriptors for poll()ing */
136    nfds = alsa_device_nfds(audio_dev);
137    pfds = malloc(sizeof(*pfds)*(nfds+1));
138    alsa_device_getfds(audio_dev, pfds, nfds);
139    pfds[nfds].fd = sd;
140    pfds[nfds].events = POLLIN;
141
142    /* Setup jitter buffer using decoder */
143    JitterBuffer *jitter;
144    jitter = jitter_buffer_init(FRAME_SIZE);
145    
146    /* Echo canceller with 200 ms tail length */
147    SpeexEchoState *echo_state = speex_echo_state_init(FRAME_SIZE, 10*FRAME_SIZE);
148    tmp = SAMPLING_RATE;
149    speex_echo_ctl(echo_state, SPEEX_ECHO_SET_SAMPLING_RATE, &tmp);
150    
151    alsa_device_start(audio_dev);
152    
153    /* Infinite loop on capture, playback and receiving packets */
154    while (1)
155    {
156       /* Wait for either 1) capture 2) playback 3) socket data */
157       poll(pfds, nfds+1, -1);
158       /* Received packets */
159       if (pfds[nfds].revents & POLLIN)
160       {
161          /*fprintf (stderr, "x");*/
162          n = recv(sd, msg, MAX_MSG, 0);
163          int recv_timestamp = ((int*)msg)[0];
164    
165          JitterBufferPacket packet;
166          packet.data = msg+4;
167          packet.len = n-4;
168          packet.timestamp = recv_timestamp;
169          packet.span = FRAME_SIZE;
170          packet.sequence = 0;
171          /* Put content of the packet into the jitter buffer, except for the pseudo-header */
172          jitter_buffer_put(jitter, &packet);
173          recv_started = 1;
174
175       }
176       /* Ready to play a frame (playback) */
177       if (alsa_device_playback_ready(audio_dev, pfds, nfds))
178       {
179          short pcm[FRAME_SIZE];
180          if (recv_started)
181          {
182             JitterBufferPacket packet;
183             /* Get audio from the jitter buffer */
184             jitter_buffer_get(jitter, &packet, FRAME_SIZE, NULL);
185             celt_decode(dec_state, packet.data, packet.len, pcm);
186          } else {
187             for (i=0;i<FRAME_SIZE;i++)
188                pcm[i] = 0;
189          }
190          /* Playback the audio and reset the echo canceller if we got an underrun */
191          if (alsa_device_write(audio_dev, pcm, FRAME_SIZE))
192             speex_echo_state_reset(echo_state);
193          /* Put frame into playback buffer */
194          speex_echo_playback(echo_state, pcm);
195       }
196       /* Audio available from the soundcard (capture) */
197       if (alsa_device_capture_ready(audio_dev, pfds, nfds))
198       {
199          short pcm[FRAME_SIZE], pcm2[FRAME_SIZE];
200          char outpacket[MAX_MSG];
201          /* Get audio from the soundcard */
202          alsa_device_read(audio_dev, pcm, FRAME_SIZE);
203          
204          /* Perform echo cancellation */
205          speex_echo_capture(echo_state, pcm, pcm2);
206          for (i=0;i<FRAME_SIZE;i++)
207             pcm[i] = pcm2[i];
208          
209          /* Encode */
210          celt_encode(enc_state, pcm, outpacket+4, packetSize);
211          
212          /* Pseudo header: four null bytes and a 32-bit timestamp */
213          ((int*)outpacket)[0] = send_timestamp;
214          send_timestamp += FRAME_SIZE;
215          rc = sendto(sd, outpacket, packetSize+4, 0,
216                 (struct sockaddr *) &remoteAddr,
217                 sizeof(remoteAddr));
218          
219          if(rc<0) {
220             printf("cannot send audio data\n");
221             close(sd);
222             exit(1);
223          }
224       }
225       
226
227    }
228
229
230    return 0;
231 }