2 * Lightweight Autonomic Network Architecture
3 * Copyright 2011 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,
4 * Swiss federal institute of technology (ETH Zurich)
9 * Copyright (C) 2011 Daniel Borkmann (major cleanups, improvements, fixed bugs,
10 * new API, used PF_LANA instead of IPv4/UDP)
11 * Copyright (C) 2004-2006 Jean-Marc Valin
12 * Copyright (C) 2006 Commonwealth Scientific and Industrial Research
13 * Organisation (CSIRO) Australia
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions are
19 * 1. Redistributions of source code must retain the above copyright notice,
20 * this list of conditions and the following disclaimer.
22 * 2. Redistributions in binary form must reproduce the above copyright
23 * notice, this list of conditions and the following disclaimer in the
24 * documentation and/or other materials provided with the distribution.
26 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
27 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
28 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
29 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
30 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
31 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
32 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
34 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
35 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
40 #include <sys/types.h>
41 #include <sys/socket.h>
42 #include <netinet/in.h>
43 #include <arpa/inet.h>
48 #include <celt/celt.h>
49 #include <speex/speex_jitter.h>
50 #include <speex/speex_echo.h>
52 #include <sys/ioctl.h>
62 #define SAMPLING_RATE 48000
63 #define FRAME_SIZE 256
67 /* TODO: add support for SIOCGIFINDEX into AF_LANA */
68 static int device_ifindex(const char *ifname
)
73 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
77 memset(&ifr
, 0, sizeof(ifr
));
78 strncpy(ifr
.ifr_name
, ifname
, strlen(ifname
));
80 ret
= ioctl(sock
, SIOCGIFINDEX
, &ifr
);
82 index
= ifr
.ifr_ifindex
;
90 void hack_mac(char *dst
, char *src
, size_t len
)
94 sscanf(src
, "%x:%x:%x:%x:%x:%x",
95 &dst1
[0], &dst1
[1], &dst1
[2],
96 &dst1
[3], &dst1
[4], &dst1
[5]);
97 dst
[0] = (uint8_t) dst1
[0];
98 dst
[1] = (uint8_t) dst1
[1];
99 dst
[2] = (uint8_t) dst1
[2];
100 dst
[3] = (uint8_t) dst1
[3];
101 dst
[4] = (uint8_t) dst1
[4];
102 dst
[5] = (uint8_t) dst1
[5];
105 int main(int argc
, char **argv
)
107 int i
, sd
, rc
, n
, tmp
, idx
;
111 int send_timestamp
= 0;
112 int recv_started
= 0;
114 struct alsa_dev
*dev
;
115 CELTEncoder
*enc_state
;
116 CELTDecoder
*dec_state
;
118 struct sched_param param
;
119 JitterBuffer
*jitter
;
120 SpeexEchoState
*echo_state
;
121 char mac_own
[6], mac_remote
[6];
124 panic("Usage %s plughw:0,0 <lmac in xx:xx:xx:xx:xx:xx> <rmac>\n", argv
[0]);
126 hack_mac(mac_own
, argv
[2], strlen(argv
[2]));
127 hack_mac(mac_remote
, argv
[3], strlen(argv
[3]));
129 /* XXX: #include <net/if.h> -> if_nametoindex(3) */
130 idx
= device_ifindex("eth0");
132 panic("device_ifindex fucked up!\n");
134 memset(&sa
, 0, sizeof(sa
));
135 sa
.sa_family
= AF_LANA
;
136 sa
.sa_data
[0] = (uint8_t) idx
;
138 sd
= socket(AF_LANA
, SOCK_RAW
, 0);
140 panic("%s: cannot open socket \n", argv
[0]);
142 rc
= bind(sd
, &sa
, sizeof(sa
));
144 panic("bind fucked up!\n");
146 printf("If ready hit key!\n"); //user must do binding
149 dev
= alsa_open(argv
[1], SAMPLING_RATE
, CHANNELS
, FRAME_SIZE
);
151 mode
= celt_mode_create(SAMPLING_RATE
, FRAME_SIZE
, NULL
);
152 enc_state
= celt_encoder_create(mode
, CHANNELS
, NULL
);
153 dec_state
= celt_decoder_create(mode
, CHANNELS
, NULL
);
155 param
.sched_priority
= sched_get_priority_min(SCHED_FIFO
);
156 if (sched_setscheduler(0, SCHED_FIFO
, ¶m
))
157 whine("sched_setscheduler error!\n");
159 /* Setup all file descriptors for poll()ing */
160 nfds
= alsa_nfds(dev
);
161 pfds
= xmalloc(sizeof(*pfds
) * (nfds
+ 1));
163 alsa_getfds(dev
, pfds
, nfds
);
166 pfds
[nfds
].events
= POLLIN
;
168 /* Setup jitter buffer using decoder */
169 jitter
= jitter_buffer_init(FRAME_SIZE
);
171 jitter_buffer_ctl(jitter
, JITTER_BUFFER_SET_MARGIN
, &tmp
);
173 /* Echo canceller with 200 ms tail length */
174 echo_state
= speex_echo_state_init(FRAME_SIZE
, 10 * FRAME_SIZE
);
176 speex_echo_ctl(echo_state
, SPEEX_ECHO_SET_SAMPLING_RATE
, &tmp
);
180 poll(pfds
, nfds
+ 1, -1);
182 /* Received packets */
183 if (pfds
[nfds
].revents
& POLLIN
) {
184 n
= recv(sd
, msg
, MAX_MSG
, 0);
187 int recv_timestamp
= ((int*) msg
)[0];
189 JitterBufferPacket packet
;
190 packet
.data
= msg
+4+6+6+2;
191 packet
.len
= n
-4-6-6-2;
192 packet
.timestamp
= recv_timestamp
;
193 packet
.span
= FRAME_SIZE
;
196 /* Put content of the packet into the jitter buffer,
197 except for the pseudo-header */
198 jitter_buffer_put(jitter
, &packet
);
202 /* Ready to play a frame (playback) */
203 if (alsa_play_ready(dev
, pfds
, nfds
)) {
204 short pcm
[FRAME_SIZE
* CHANNELS
];
206 JitterBufferPacket packet
;
207 /* Get audio from the jitter buffer */
209 packet
.len
= MAX_MSG
;
210 jitter_buffer_tick(jitter
);
211 jitter_buffer_get(jitter
, &packet
, FRAME_SIZE
,
215 celt_decode(dec_state
, (const unsigned char *)
216 packet
.data
, packet
.len
, pcm
);
218 /* Playback the audio and reset the echo canceller
219 if we got an underrun */
221 if (alsa_write(dev
, pcm
, FRAME_SIZE
))
222 speex_echo_state_reset(echo_state
);
223 /* Put frame into playback buffer */
224 speex_echo_playback(echo_state
, pcm
);
228 /* Audio available from the soundcard (capture) */
229 if (alsa_cap_ready(dev
, pfds
, nfds
)) {
230 short pcm
[FRAME_SIZE
* CHANNELS
],
231 pcm2
[FRAME_SIZE
* CHANNELS
];
232 char outpacket
[MAX_MSG
];
234 alsa_read(dev
, pcm
, FRAME_SIZE
);
235 /* Perform echo cancellation */
236 speex_echo_capture(echo_state
, pcm
, pcm2
);
237 for (i
= 0; i
< FRAME_SIZE
* CHANNELS
; ++i
)
240 celt_encode(enc_state
, pcm
, NULL
, (unsigned char *)
241 (outpacket
+4+6+6+2), PACKETSIZE
);
243 /* Pseudo header: four null bytes and a 32-bit
244 timestamp; XXX hack */
245 memcpy(outpacket
,mac_remote
,6);
246 memcpy(outpacket
+6,mac_own
,6);
247 outpacket
[6+6] = (uint8_t) 0xac;
248 outpacket
[6+6+1] = (uint8_t) 0xdc;
249 ((int*) outpacket
)[6+6+2] = send_timestamp
;
250 send_timestamp
+= FRAME_SIZE
;
252 rc
= sendto(sd
, outpacket
, PACKETSIZE
+4+6+6+2, 0,
255 panic("cannot send to socket");
256 printf("frame sent!\n");