2 * Lightweight Autonomic Network Architecture
3 * Copyright 2011 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,
4 * Swiss federal institute of technology (ETH Zurich)
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
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.
45 #include <sys/types.h>
46 #include <sys/socket.h>
47 #include <netinet/in.h>
48 #include <arpa/inet.h>
51 #include <sys/types.h>
56 #include <celt/celt.h>
57 #include <speex/speex_jitter.h>
58 #include <speex/speex_echo.h>
60 #include <sys/ioctl.h>
71 #define SAMPLING_RATE 48000
72 #define FRAME_SIZE 256
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
)
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
)]);
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
;
110 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
114 memset(&ifr
, 0, sizeof(ifr
));
115 strncpy(ifr
.ifr_name
, ifname
, strlen(ifname
));
117 ret
= ioctl(sock
, SIOCGIFINDEX
, &ifr
);
119 index
= ifr
.ifr_ifindex
;
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
;
148 int send_timestamp
= 0;
149 int recv_started
= 0;
151 struct alsa_dev
*dev
;
152 CELTEncoder
*enc_state
;
153 CELTDecoder
*dec_state
;
155 struct sched_param param
;
156 JitterBuffer
*jitter
;
157 SpeexEchoState
*echo_state
;
158 char mac_own
[6], mac_remote
[6];
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");
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);
179 panic("%s: cannot open socket \n", argv
[0]);
181 rc
= bind(sd
, &sa
, sizeof(sa
));
183 panic("bind fucked up!\n");
185 printf("If ready hit key!\n"); //user must do binding
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
, ¶m
))
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
);
205 pfds
[nfds
].events
= POLLIN
;
207 /* Setup jitter buffer using decoder */
208 jitter
= jitter_buffer_init(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
);
215 speex_echo_ctl(echo_state
, SPEEX_ECHO_SET_SAMPLING_RATE
, &tmp
);
217 register_signal_f(SIGALRM
, timer_elapsed
, SA_SIGINFO
);
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
);
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);
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
;
247 /* Put content of the packet into the jitter buffer,
248 except for the pseudo-header */
249 jitter_buffer_put(jitter
, &packet
);
253 /* Ready to play a frame (playback) */
254 if (alsa_play_ready(dev
, pfds
, nfds
)) {
255 short pcm
[FRAME_SIZE
* CHANNELS
] = {0};
257 JitterBufferPacket packet
;
258 /* Get audio from the jitter buffer */
260 packet
.len
= MAX_MSG
;
261 jitter_buffer_tick(jitter
);
262 jitter_buffer_get(jitter
, &packet
, FRAME_SIZE
,
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)
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,
306 panic("cannot send to socket");
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
);