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