Update on pf_lana and others
[ana-net.git] / app / voe.c
blobd652d76df874b84f2ee32921be3e1732984b8ad2
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 /*
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
17 * met:
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.
39 #include <stdlib.h>
40 #include <sys/types.h>
41 #include <sys/socket.h>
42 #include <netinet/in.h>
43 #include <arpa/inet.h>
44 #include <netdb.h>
45 #include <stdio.h>
46 #include <unistd.h>
47 #include <string.h>
48 #include <celt/celt.h>
49 #include <speex/speex_jitter.h>
50 #include <speex/speex_echo.h>
51 #include <sched.h>
52 #include <sys/ioctl.h>
53 #include <net/if.h>
55 #include "alsa.h"
56 #include "die.h"
57 #include "xmalloc.h"
59 #define AF_LANA 27
61 #define MAX_MSG 1500
62 #define SAMPLING_RATE 48000
63 #define FRAME_SIZE 256
64 #define PACKETSIZE 43
65 #define CHANNELS 1
67 /* TODO: add support for SIOCGIFINDEX into AF_LANA */
68 static int device_ifindex(const char *ifname)
70 int ret, sock, index;
71 struct ifreq ifr;
73 sock = socket(AF_INET, SOCK_DGRAM, 0);
74 if (sock < 0)
75 return sock;
77 memset(&ifr, 0, sizeof(ifr));
78 strncpy(ifr.ifr_name, ifname, strlen(ifname));
80 ret = ioctl(sock, SIOCGIFINDEX, &ifr);
81 if (!ret)
82 index = ifr.ifr_ifindex;
83 else
84 index = -1;
86 close(sock);
87 return index;
90 void hack_mac(char *dst, char *src, size_t len)
92 unsigned int dst1[6];
93 /* Fucked up crap. */
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;
108 struct sockaddr sa;
109 char msg[MAX_MSG];
110 int nfds;
111 int send_timestamp = 0;
112 int recv_started = 0;
113 struct pollfd *pfds;
114 struct alsa_dev *dev;
115 CELTEncoder *enc_state;
116 CELTDecoder *dec_state;
117 CELTMode *mode;
118 struct sched_param param;
119 JitterBuffer *jitter;
120 SpeexEchoState *echo_state;
121 char mac_own[6], mac_remote[6];
123 if (argc != 4)
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");
131 if (idx < 0)
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);
139 if (sd < 0)
140 panic("%s: cannot open socket \n", argv[0]);
142 rc = bind(sd, &sa, sizeof(sa));
143 if (rc < 0)
144 panic("bind fucked up!\n");
146 printf("If ready hit key!\n"); //user must do binding
147 getchar();
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, &param))
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);
165 pfds[nfds].fd = sd;
166 pfds[nfds].events = POLLIN;
168 /* Setup jitter buffer using decoder */
169 jitter = jitter_buffer_init(FRAME_SIZE);
170 tmp = 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);
175 tmp = SAMPLING_RATE;
176 speex_echo_ctl(echo_state, SPEEX_ECHO_SET_SAMPLING_RATE, &tmp);
178 alsa_start(dev);
179 while (1) {
180 poll(pfds, nfds + 1, -1);
182 /* Received packets */
183 if (pfds[nfds].revents & POLLIN) {
184 n = recv(sd, msg, MAX_MSG, 0);
185 if (n <= 0)
186 continue;
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;
194 packet.sequence = 0;
196 /* Put content of the packet into the jitter buffer,
197 except for the pseudo-header */
198 jitter_buffer_put(jitter, &packet);
199 recv_started = 1;
202 /* Ready to play a frame (playback) */
203 if (alsa_play_ready(dev, pfds, nfds)) {
204 short pcm[FRAME_SIZE * CHANNELS];
205 if (recv_started) {
206 JitterBufferPacket packet;
207 /* Get audio from the jitter buffer */
208 packet.data = msg;
209 packet.len = MAX_MSG;
210 jitter_buffer_tick(jitter);
211 jitter_buffer_get(jitter, &packet, FRAME_SIZE,
212 NULL);
213 if (packet.len == 0)
214 packet.data=NULL;
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)
238 pcm[i] = pcm2[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,
253 &sa, sizeof(sa));
254 if (rc < 0)
255 panic("cannot send to socket");
256 printf("frame sent!\n");
260 close(sd);
261 return 0;