Added header comment for needed packets on Debian/Ubuntu
[ana-net.git] / app / voe.c
blob04a51543c5136895c6d1b55e4cdd03149db3b01b
1 /*
2 * Lightweight Autonomic Network Architecture
3 * Copyright 2011 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,
4 * Swiss federal institute of technology (ETH Zurich)
5 * Subject to the GPL.
6 */
8 /* apt-get install libcelt0-0 libcelt-dev libspeexdsp1 libspeexdsp-dev libasound2-dev libasound2 */
10 /* NOTE: make sure you also have the alsa userspace tools compiled with
11 * the same version! */
14 * Copyright (C) 2011 Daniel Borkmann (major cleanups, improvements, fixed bugs,
15 * new API, used PF_LANA instead of IPv4/UDP)
16 * Copyright (C) 2004-2006 Jean-Marc Valin
17 * Copyright (C) 2006 Commonwealth Scientific and Industrial Research
18 * Organisation (CSIRO) Australia
20 * Redistribution and use in source and binary forms, with or without
21 * modification, are permitted provided that the following conditions are
22 * met:
24 * 1. Redistributions of source code must retain the above copyright notice,
25 * this list of conditions and the following disclaimer.
27 * 2. Redistributions in binary form must reproduce the above copyright
28 * notice, this list of conditions and the following disclaimer in the
29 * documentation and/or other materials provided with the distribution.
31 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
32 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
33 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
34 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
35 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
36 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
37 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
40 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGE.
44 #include <stdlib.h>
45 #include <sys/types.h>
46 #include <sys/socket.h>
47 #include <netinet/in.h>
48 #include <arpa/inet.h>
49 #include <time.h>
50 #include <sys/time.h>
51 #include <sys/types.h>
52 #include <netdb.h>
53 #include <stdio.h>
54 #include <unistd.h>
55 #include <string.h>
56 #include <celt/celt.h>
57 #include <speex/speex_jitter.h>
58 #include <speex/speex_echo.h>
59 #include <sched.h>
60 #include <sys/ioctl.h>
61 #include <net/if.h>
63 #include "alsa.h"
64 #include "signals.h"
65 #include "die.h"
66 #include "xmalloc.h"
68 #define AF_LANA 27
70 #define MAX_MSG 1500
71 #define SAMPLING_RATE 48000
72 #define FRAME_SIZE 256
73 #define PACKETSIZE 43
74 #define CHANNELS 1
76 static sig_atomic_t sigint = 0;
77 static sig_atomic_t pkts_in = 0, pkts_out = 0;
78 static struct itimerval itimer;
79 static unsigned long interval = 100;
81 void sighandler(int nr)
83 if (nr == SIGINT)
84 sigint = 1;
87 static char blubber[] = {'-', '\\', '|', '/'};
89 static void timer_elapsed(int number)
91 unsigned int in = pkts_in, out = pkts_out;
93 itimer.it_interval.tv_sec = 0;
94 itimer.it_interval.tv_usec = interval;
95 itimer.it_value.tv_sec = 0;
96 itimer.it_value.tv_usec = interval;
98 printf("\rnet: in %c, out %c\t",
99 blubber[in % sizeof(blubber)], blubber[out % sizeof(blubber)]);
100 fflush(stdout);
101 setitimer(ITIMER_REAL, &itimer, NULL);
104 /* TODO: add support for SIOCGIFINDEX into AF_LANA */
105 static int device_ifindex(const char *ifname)
107 int ret, sock, index;
108 struct ifreq ifr;
110 sock = socket(AF_INET, SOCK_DGRAM, 0);
111 if (sock < 0)
112 return sock;
114 memset(&ifr, 0, sizeof(ifr));
115 strncpy(ifr.ifr_name, ifname, strlen(ifname));
117 ret = ioctl(sock, SIOCGIFINDEX, &ifr);
118 if (!ret)
119 index = ifr.ifr_ifindex;
120 else
121 index = -1;
123 close(sock);
124 return index;
127 void hack_mac(char *dst, char *src, size_t len)
129 unsigned int dst1[6];
130 /* Fucked up crap. */
131 sscanf(src, "%x:%x:%x:%x:%x:%x",
132 &dst1[0], &dst1[1], &dst1[2],
133 &dst1[3], &dst1[4], &dst1[5]);
134 dst[0] = (uint8_t) dst1[0];
135 dst[1] = (uint8_t) dst1[1];
136 dst[2] = (uint8_t) dst1[2];
137 dst[3] = (uint8_t) dst1[3];
138 dst[4] = (uint8_t) dst1[4];
139 dst[5] = (uint8_t) dst1[5];
142 int main(int argc, char **argv)
144 int /*i,*/ sd, rc, n, tmp, idx;
145 struct sockaddr sa;
146 char msg[MAX_MSG];
147 int nfds;
148 int send_timestamp = 0;
149 int recv_started = 0;
150 struct pollfd *pfds;
151 struct alsa_dev *dev;
152 CELTEncoder *enc_state;
153 CELTDecoder *dec_state;
154 CELTMode *mode;
155 struct sched_param param;
156 JitterBuffer *jitter;
157 SpeexEchoState *echo_state;
158 char mac_own[6], mac_remote[6];
160 if (argc != 4)
161 panic("Usage %s plughw:0,0 <lmac in xx:xx:xx:xx:xx:xx> <rmac>\n", argv[0]);
163 register_signal(SIGINT, sighandler);
165 hack_mac(mac_own, argv[2], strlen(argv[2]));
166 hack_mac(mac_remote, argv[3], strlen(argv[3]));
168 /* XXX: #include <net/if.h> -> if_nametoindex(3) */
169 idx = device_ifindex("eth0");
170 if (idx < 0)
171 panic("device_ifindex fucked up!\n");
173 memset(&sa, 0, sizeof(sa));
174 sa.sa_family = AF_LANA;
175 sa.sa_data[0] = (uint8_t) idx;
177 sd = socket(AF_LANA, SOCK_RAW, 0);
178 if (sd < 0)
179 panic("%s: cannot open socket \n", argv[0]);
181 rc = bind(sd, &sa, sizeof(sa));
182 if (rc < 0)
183 panic("bind fucked up!\n");
185 printf("If ready hit key!\n"); //user must do binding
186 getchar();
188 dev = alsa_open(argv[1], SAMPLING_RATE, CHANNELS, FRAME_SIZE);
190 mode = celt_mode_create(SAMPLING_RATE, FRAME_SIZE, NULL);
191 enc_state = celt_encoder_create(mode, CHANNELS, NULL);
192 dec_state = celt_decoder_create(mode, CHANNELS, NULL);
194 param.sched_priority = sched_get_priority_min(SCHED_FIFO);
195 if (sched_setscheduler(0, SCHED_FIFO, &param))
196 whine("sched_setscheduler error!\n");
198 /* Setup all file descriptors for poll()ing */
199 nfds = alsa_nfds(dev);
200 pfds = xmalloc(sizeof(*pfds) * (nfds + 1));
202 alsa_getfds(dev, pfds, nfds);
204 pfds[nfds].fd = sd;
205 pfds[nfds].events = POLLIN;
207 /* Setup jitter buffer using decoder */
208 jitter = jitter_buffer_init(FRAME_SIZE);
209 tmp = FRAME_SIZE;
210 jitter_buffer_ctl(jitter, JITTER_BUFFER_SET_MARGIN, &tmp);
212 /* Echo canceller with 200 ms tail length */
213 echo_state = speex_echo_state_init(FRAME_SIZE, 10 * FRAME_SIZE);
214 tmp = SAMPLING_RATE;
215 speex_echo_ctl(echo_state, SPEEX_ECHO_SET_SAMPLING_RATE, &tmp);
217 register_signal_f(SIGALRM, timer_elapsed, SA_SIGINFO);
219 alsa_start(dev);
220 printf("ALSA started!\n");
222 itimer.it_interval.tv_sec = 0;
223 itimer.it_interval.tv_usec = interval;
224 itimer.it_value.tv_sec = 0;
225 itimer.it_value.tv_usec = interval;
226 setitimer(ITIMER_REAL, &itimer, NULL);
228 while (!sigint) {
229 poll(pfds, nfds + 1, -1);
231 /* Received packets */
232 if (pfds[nfds].revents & POLLIN) {
233 memset(msg, 0, MAX_MSG);
234 n = recv(sd, msg, MAX_MSG, 0);
235 if (n <= 0)
236 goto do_alsa;
237 pkts_in++;
238 int recv_timestamp;
239 memcpy(&recv_timestamp, msg, sizeof(recv_timestamp));
240 JitterBufferPacket packet;
241 packet.data = msg+4/*+6+6+2*/;
242 packet.len = n-4/*-6-6-2*/;
243 packet.timestamp = recv_timestamp;
244 packet.span = FRAME_SIZE;
245 packet.sequence = 0;
247 /* Put content of the packet into the jitter buffer,
248 except for the pseudo-header */
249 jitter_buffer_put(jitter, &packet);
250 recv_started = 1;
252 do_alsa:
253 /* Ready to play a frame (playback) */
254 if (alsa_play_ready(dev, pfds, nfds)) {
255 short pcm[FRAME_SIZE * CHANNELS] = {0};
256 if (recv_started) {
257 JitterBufferPacket packet;
258 /* Get audio from the jitter buffer */
259 packet.data = msg;
260 packet.len = MAX_MSG;
261 jitter_buffer_tick(jitter);
262 jitter_buffer_get(jitter, &packet, FRAME_SIZE,
263 NULL);
264 if (packet.len == 0)
265 packet.data=NULL;
266 celt_decode(dec_state, (const unsigned char *)
267 packet.data, packet.len, pcm);
269 /* Playback the audio and reset the echo canceller
270 if we got an underrun */
272 alsa_write(dev, pcm, FRAME_SIZE);
273 // if (alsa_write(dev, pcm, FRAME_SIZE))
274 // speex_echo_state_reset(echo_state);
275 /* Put frame into playback buffer */
276 // speex_echo_playback(echo_state, pcm);
279 /* Audio available from the soundcard (capture) */
280 if (alsa_cap_ready(dev, pfds, nfds)) {
281 short pcm[FRAME_SIZE * CHANNELS];
282 //pcm2[FRAME_SIZE * CHANNELS];
283 char outpacket[MAX_MSG];
285 alsa_read(dev, pcm, FRAME_SIZE);
286 /* Perform echo cancellation */
287 // speex_echo_capture(echo_state, pcm, pcm2);
288 // for (i = 0; i < FRAME_SIZE * CHANNELS; ++i)
289 // pcm[i] = pcm2[i];
291 celt_encode(enc_state, pcm, NULL, (unsigned char *)
292 (outpacket+4+6+6+2), PACKETSIZE);
294 /* Pseudo header: four null bytes and a 32-bit
295 timestamp; XXX hack */
296 memcpy(outpacket,mac_remote,6);
297 memcpy(outpacket+6,mac_own,6);
298 outpacket[6+6] = (uint8_t) 0xac;
299 outpacket[6+6+1] = (uint8_t) 0xdc;
300 memcpy(outpacket+6+6+2, &send_timestamp, sizeof(send_timestamp));
301 send_timestamp += FRAME_SIZE;
303 rc = sendto(sd, outpacket, PACKETSIZE+4+6+6+2, 0,
304 &sa, sizeof(sa));
305 if (rc < 0)
306 panic("cannot send to socket");
307 pkts_out++;
311 itimer.it_interval.tv_sec = 0;
312 itimer.it_interval.tv_usec = 0;
313 itimer.it_value.tv_sec = 0;
314 itimer.it_value.tv_usec = 0;
315 setitimer(ITIMER_REAL, &itimer, NULL);
317 close(sd);
318 return 0;