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>
51 #include <celt/celt.h>
52 #include <speex/speex_jitter.h>
53 #include <speex/speex_echo.h>
55 #include <sys/ioctl.h>
66 #define SAMPLING_RATE 48000
67 #define FRAME_SIZE 256
71 sig_atomic_t sigint
= 0;
73 void sighandler(int nr
)
79 /* TODO: add support for SIOCGIFINDEX into AF_LANA */
80 static int device_ifindex(const char *ifname
)
85 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
89 memset(&ifr
, 0, sizeof(ifr
));
90 strncpy(ifr
.ifr_name
, ifname
, strlen(ifname
));
92 ret
= ioctl(sock
, SIOCGIFINDEX
, &ifr
);
94 index
= ifr
.ifr_ifindex
;
102 void hack_mac(char *dst
, char *src
, size_t len
)
104 unsigned int dst1
[6];
105 /* Fucked up crap. */
106 sscanf(src
, "%x:%x:%x:%x:%x:%x",
107 &dst1
[0], &dst1
[1], &dst1
[2],
108 &dst1
[3], &dst1
[4], &dst1
[5]);
109 dst
[0] = (uint8_t) dst1
[0];
110 dst
[1] = (uint8_t) dst1
[1];
111 dst
[2] = (uint8_t) dst1
[2];
112 dst
[3] = (uint8_t) dst1
[3];
113 dst
[4] = (uint8_t) dst1
[4];
114 dst
[5] = (uint8_t) dst1
[5];
117 int main(int argc
, char **argv
)
119 int i
, sd
, rc
, n
, tmp
, idx
;
123 int send_timestamp
= 0;
124 int recv_started
= 0;
126 struct alsa_dev
*dev
;
127 CELTEncoder
*enc_state
;
128 CELTDecoder
*dec_state
;
130 struct sched_param param
;
131 JitterBuffer
*jitter
;
132 SpeexEchoState
*echo_state
;
133 char mac_own
[6], mac_remote
[6];
136 panic("Usage %s plughw:0,0 <lmac in xx:xx:xx:xx:xx:xx> <rmac>\n", argv
[0]);
138 register_signal(SIGINT
, sighandler
);
140 hack_mac(mac_own
, argv
[2], strlen(argv
[2]));
141 hack_mac(mac_remote
, argv
[3], strlen(argv
[3]));
143 /* XXX: #include <net/if.h> -> if_nametoindex(3) */
144 idx
= device_ifindex("eth0");
146 panic("device_ifindex fucked up!\n");
148 memset(&sa
, 0, sizeof(sa
));
149 sa
.sa_family
= AF_LANA
;
150 sa
.sa_data
[0] = (uint8_t) idx
;
152 sd
= socket(AF_LANA
, SOCK_RAW
, 0);
154 panic("%s: cannot open socket \n", argv
[0]);
156 rc
= bind(sd
, &sa
, sizeof(sa
));
158 panic("bind fucked up!\n");
160 printf("If ready hit key!\n"); //user must do binding
163 dev
= alsa_open(argv
[1], SAMPLING_RATE
, CHANNELS
, FRAME_SIZE
);
165 mode
= celt_mode_create(SAMPLING_RATE
, FRAME_SIZE
, NULL
);
166 enc_state
= celt_encoder_create(mode
, CHANNELS
, NULL
);
167 dec_state
= celt_decoder_create(mode
, CHANNELS
, NULL
);
169 param
.sched_priority
= sched_get_priority_min(SCHED_FIFO
);
170 if (sched_setscheduler(0, SCHED_FIFO
, ¶m
))
171 whine("sched_setscheduler error!\n");
173 /* Setup all file descriptors for poll()ing */
174 nfds
= alsa_nfds(dev
);
175 pfds
= xmalloc(sizeof(*pfds
) * (nfds
+ 1));
177 alsa_getfds(dev
, pfds
, nfds
);
180 pfds
[nfds
].events
= POLLIN
;
182 /* Setup jitter buffer using decoder */
183 jitter
= jitter_buffer_init(FRAME_SIZE
);
185 jitter_buffer_ctl(jitter
, JITTER_BUFFER_SET_MARGIN
, &tmp
);
187 /* Echo canceller with 200 ms tail length */
188 echo_state
= speex_echo_state_init(FRAME_SIZE
, 10 * FRAME_SIZE
);
190 speex_echo_ctl(echo_state
, SPEEX_ECHO_SET_SAMPLING_RATE
, &tmp
);
194 poll(pfds
, nfds
+ 1, -1);
196 /* Received packets */
197 if (pfds
[nfds
].revents
& POLLIN
) {
198 n
= recv(sd
, msg
, MAX_MSG
, 0);
201 if (msg
[6+6] != 0xac && msg
[6+6+1] != 0xdc)
203 int recv_timestamp
= ((int*) msg
)[6+6+2];
205 JitterBufferPacket packet
;
206 packet
.data
= msg
+4+6+6+2;
207 packet
.len
= n
-4-6-6-2;
208 packet
.timestamp
= recv_timestamp
;
209 packet
.span
= FRAME_SIZE
;
212 /* Put content of the packet into the jitter buffer,
213 except for the pseudo-header */
214 jitter_buffer_put(jitter
, &packet
);
218 /* Ready to play a frame (playback) */
219 if (alsa_play_ready(dev
, pfds
, nfds
)) {
220 short pcm
[FRAME_SIZE
* CHANNELS
];
222 JitterBufferPacket packet
;
223 /* Get audio from the jitter buffer */
225 packet
.len
= MAX_MSG
;
226 jitter_buffer_tick(jitter
);
227 jitter_buffer_get(jitter
, &packet
, FRAME_SIZE
,
231 celt_decode(dec_state
, (const unsigned char *)
232 packet
.data
, packet
.len
, pcm
);
234 /* Playback the audio and reset the echo canceller
235 if we got an underrun */
237 if (alsa_write(dev
, pcm
, FRAME_SIZE
))
238 speex_echo_state_reset(echo_state
);
239 /* Put frame into playback buffer */
240 speex_echo_playback(echo_state
, pcm
);
244 /* Audio available from the soundcard (capture) */
245 if (alsa_cap_ready(dev
, pfds
, nfds
)) {
246 short pcm
[FRAME_SIZE
* CHANNELS
],
247 pcm2
[FRAME_SIZE
* CHANNELS
];
248 char outpacket
[MAX_MSG
];
250 alsa_read(dev
, pcm
, FRAME_SIZE
);
251 /* Perform echo cancellation */
252 speex_echo_capture(echo_state
, pcm
, pcm2
);
253 for (i
= 0; i
< FRAME_SIZE
* CHANNELS
; ++i
)
256 celt_encode(enc_state
, pcm
, NULL
, (unsigned char *)
257 (outpacket
+4+6+6+2), PACKETSIZE
);
259 /* Pseudo header: four null bytes and a 32-bit
260 timestamp; XXX hack */
261 memcpy(outpacket
,mac_remote
,6);
262 memcpy(outpacket
+6,mac_own
,6);
263 outpacket
[6+6] = (uint8_t) 0xac;
264 outpacket
[6+6+1] = (uint8_t) 0xdc;
265 ((int*) outpacket
)[6+6+2] = send_timestamp
;
266 send_timestamp
+= FRAME_SIZE
;
268 rc
= sendto(sd
, outpacket
, PACKETSIZE
+4+6+6+2, 0,
271 panic("cannot send to socket");