2 * transsip - the telephony network
3 * By Daniel Borkmann <daniel@transsip.org>
4 * Copyright 2011 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,
5 * Swiss federal institute of technology (ETH Zurich)
6 * Subject to the GPL, version 2.
16 #include <sys/types.h>
17 #include <sys/socket.h>
18 #include <netinet/in.h>
19 #include <arpa/inet.h>
21 #include <celt/celt.h>
22 #include <speex/speex_jitter.h>
23 #include <speex/speex_echo.h>
34 #define SAMPLING_RATE 48000
35 #define FRAME_SIZE 256
39 static pthread_t ptid
;
41 static char *port
= "30111";
42 static char *stun_server
= "stunserver.org";
43 static char *alsadev
= "plughw:0,0";
45 extern sig_atomic_t quit
;
46 sig_atomic_t did_stun
= 0;
47 static sig_atomic_t incoming_call
= 0;
49 static struct pollfd
*pfds
= NULL
;
50 static struct alsa_dev
*dev
= NULL
;
51 static CELTEncoder
*encoder
= NULL
;
52 static CELTDecoder
*decoder
= NULL
;
53 static JitterBuffer
*jitter
= NULL
;
54 static SpeexEchoState
*echostate
= NULL
;
56 static void do_call_duplex(void)
59 int ret
, recv_started
= 0;
62 while (likely(!quit
)) {
63 ret
= poll(pfds
, nfds
+ 1, -1);
65 panic("Poll returned with %d!\n", ret
);
67 /* Received packets */
68 if (pfds
[nfds
].revents
& POLLIN
) {
69 n
= recv(sd
, msg
, MAX_MSG
, 0);
70 int recv_timestamp
= ((int*) msg
)[0];
72 JitterBufferPacket packet
;
73 packet
.data
= msg
+ 4;
75 packet
.timestamp
= recv_timestamp
;
76 packet
.span
= FRAME_SIZE
;
79 jitter_buffer_put(jitter
, &packet
);
83 /* Ready to play a frame (playback) */
84 if (alsa_play_ready(dev
, pfds
, nfds
)) {
85 short pcm
[FRAME_SIZE
* CHANNELS
];
87 JitterBufferPacket packet
;
88 /* Get audio from the jitter buffer */
91 jitter_buffer_tick(jitter
);
92 jitter_buffer_get(jitter
, &packet
, FRAME_SIZE
,
96 celt_decode(dec_state
, (const unsigned char *)
97 packet
.data
, packet
.len
, pcm
);
99 for (i
= 0; i
< FRAME_SIZE
* CHANNELS
; ++i
)
103 /* Playback the audio and reset the echo canceller
104 if we got an underrun */
106 if (alsa_write(dev
, pcm
, FRAME_SIZE
))
107 speex_echo_state_reset(echo_state
);
108 /* Put frame into playback buffer */
109 speex_echo_playback(echo_state
, pcm
);
112 /* Audio available from the soundcard (capture) */
113 if (alsa_cap_ready(dev
, pfds
, nfds
)) {
114 short pcm
[FRAME_SIZE
* CHANNELS
],
115 pcm2
[FRAME_SIZE
* CHANNELS
];
116 char outpacket
[MAX_MSG
];
118 alsa_read(dev
, pcm
, FRAME_SIZE
);
120 /* Perform echo cancellation */
121 speex_echo_capture(echo_state
, pcm
, pcm2
);
122 for (i
= 0; i
< FRAME_SIZE
* CHANNELS
; ++i
)
125 celt_encode(enc_state
, pcm
, NULL
, (unsigned char *)
126 (outpacket
+ 4), PACKETSIZE
);
128 /* Pseudo header: four null bytes and a 32-bit
130 ((int*)outpacket
)[0] = send_timestamp
;
131 send_timestamp
+= FRAME_SIZE
;
133 rc
= sendto(sd
, outpacket
, PACKETSIZE
+ 4, 0,
134 (struct sockaddr
*) &remote_addr
,
135 sizeof(remote_addr
));
137 panic("cannot send to socket");
143 void call_out(char *host
, char *port
)
146 /* wait for accept */
149 printf("Trying to call %s:%s ...\n", host
, port
);
153 void call_in(int take
)
155 /* lookup addrbook */
160 if (incoming_call
== 0) {
161 printf("No incoming call right now!\n");
165 printf("Trying to take incoming call ...\n");
169 static void *thread(void *null
)
171 int sock
= -1, ret
, mtu
, nfds
, tmp
;
172 struct addrinfo hints
, *ahead
, *ai
;
175 while (did_stun
== 0)
178 memset(&hints
, 0, sizeof(hints
));
179 hints
.ai_family
= PF_UNSPEC
;
180 hints
.ai_socktype
= SOCK_DGRAM
;
181 hints
.ai_protocol
= IPPROTO_UDP
;
182 hints
.ai_flags
= AI_PASSIVE
;
184 ret
= getaddrinfo(NULL
, port
, &hints
, &ahead
);
186 panic("Cannot get address info!\n");
188 for (ai
= ahead
; ai
!= NULL
&& sock
< 0; ai
= ai
->ai_next
) {
189 sock
= socket(ai
->ai_family
, ai
->ai_socktype
, ai
->ai_protocol
);
192 if (ai
->ai_family
== AF_INET6
) {
195 ret
= setsockopt(sock
, IPPROTO_IPV6
, IPV6_V6ONLY
,
206 #endif /* IPV6_V6ONLY */
208 mtu
= IP_PMTUDISC_DONT
;
209 setsockopt(sock
, SOL_IP
, IP_MTU_DISCOVER
, &mtu
, sizeof(mtu
));
210 ret
= bind(sock
, ai
->ai_addr
, ai
->ai_addrlen
);
219 panic("Cannot open socket!\n");
221 dev
= alsa_open(alsadev
, SAMPLING_RATE
, CHANNELS
, FRAME_SIZE
);
223 panic("Cannot open ALSA device %s!\n", alsadev
);
225 mode
= celt_mode_create(SAMPLING_RATE
, FRAME_SIZE
, NULL
);
226 encoder
= celt_encoder_create(mode
, CHANNELS
, NULL
);
227 decoder
= celt_decoder_create(mode
, CHANNELS
, NULL
);
229 nfds
= alsa_nfds(dev
);
230 pfds
= xmalloc(sizeof(*pfds
) * (nfds
+ 1));
231 alsa_getfds(dev
, pfds
, nfds
);
232 pfds
[nfds
].fd
= sock
;
233 pfds
[nfds
].events
= POLLIN
;
235 jitter
= jitter_buffer_init(FRAME_SIZE
);
237 jitter_buffer_ctl(jitter
, JITTER_BUFFER_SET_MARGIN
, &tmp
);
239 echostate
= speex_echo_state_init(FRAME_SIZE
, 10 * FRAME_SIZE
);
241 speex_echo_ctl(echostate
, SPEEX_ECHO_SET_SAMPLING_RATE
, &tmp
);
243 while (likely(!quit
)) {
244 ret
= poll(&pfds
[nfds
], 1, -1);
246 panic("Poll returned with %d!\n", ret
);
247 if (pfds
[nfds
].revents
& POLLIN
) {
248 /* Check for Auth pkt, if yes, set current caller and notifiy cli */
249 /* cli user must call take, that triggers call_in() */
260 static void start_server(void)
262 int ret
= pthread_create(&ptid
, NULL
, thread
, NULL
);
264 panic("Cannot create server thread!\n");
267 static void stop_server(void)
269 /* pthread_join(ptid, NULL);*/
272 int main(int argc
, char **argv
)
285 char *get_stun_server(void)