2 * Lightweight Autonomic Network Architecture
3 * Copyright 2011 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,
4 * Swiss federal institute of technology (ETH Zurich)
8 /* NOTE: make sure you also have the alsa userspace tools compiled with
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
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.
43 #include <sys/types.h>
44 #include <sys/socket.h>
45 #include <netinet/in.h>
46 #include <arpa/inet.h>
49 #include <sys/types.h>
54 #include <celt/celt.h>
55 #include <speex/speex_jitter.h>
56 #include <speex/speex_echo.h>
58 #include <sys/ioctl.h>
69 #define SAMPLING_RATE 48000
70 #define FRAME_SIZE 256
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
)
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
)]);
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
;
108 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
112 memset(&ifr
, 0, sizeof(ifr
));
113 strncpy(ifr
.ifr_name
, ifname
, strlen(ifname
));
115 ret
= ioctl(sock
, SIOCGIFINDEX
, &ifr
);
117 index
= ifr
.ifr_ifindex
;
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
;
146 int send_timestamp
= 0;
147 int recv_started
= 0;
149 struct alsa_dev
*dev
;
150 CELTEncoder
*enc_state
;
151 CELTDecoder
*dec_state
;
153 struct sched_param param
;
154 JitterBuffer
*jitter
;
155 SpeexEchoState
*echo_state
;
156 char mac_own
[6], mac_remote
[6];
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");
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);
177 panic("%s: cannot open socket \n", argv
[0]);
179 rc
= bind(sd
, &sa
, sizeof(sa
));
181 panic("bind fucked up!\n");
183 printf("If ready hit key!\n"); //user must do binding
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
, ¶m
))
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
);
203 pfds
[nfds
].events
= POLLIN
;
205 /* Setup jitter buffer using decoder */
206 jitter
= jitter_buffer_init(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
);
213 speex_echo_ctl(echo_state
, SPEEX_ECHO_SET_SAMPLING_RATE
, &tmp
);
215 register_signal_f(SIGALRM
, timer_elapsed
, SA_SIGINFO
);
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
);
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);
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);
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
;
251 /* Put content of the packet into the jitter buffer,
252 except for the pseudo-header */
253 jitter_buffer_put(jitter
, &packet
);
257 /* Ready to play a frame (playback) */
258 if (alsa_play_ready(dev
, pfds
, nfds
)) {
259 short pcm
[FRAME_SIZE
* CHANNELS
];
261 JitterBufferPacket packet
;
262 /* Get audio from the jitter buffer */
264 packet
.len
= MAX_MSG
;
265 jitter_buffer_tick(jitter
);
266 jitter_buffer_get(jitter
, &packet
, FRAME_SIZE
,
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)
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,
310 panic("cannot send to socket");
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
);