This source file includes following definitions.
- interrupt_requested
- schedule_timer
- run_timers
- release_timers
- send_hangup
- send_answer
- send_progress
- FIO_SIGNAL_CB_FUNCTION
- place_call
- media_thread
- main
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42 #ifndef __linux__
43 #define _CRT_SECURE_NO_WARNINGS 1
44 #endif
45
46 #include <signal.h>
47
48 #include <stdlib.h>
49 #include <string.h>
50 #include <errno.h>
51
52 #include "freetdm.h"
53
54
55
56 #define MAX_CALLS 255
57
58
59 #define PROGRESS_TIMER 1
60 #define ANSWER_TIMER 5
61 #define HANGUP_TIMER 15
62
63
64 static int app_running = 0;
65
66 typedef void (*expired_function_t)(ftdm_channel_t *channel);
67 typedef struct dummy_timer_s {
68 int time;
69 ftdm_channel_t *channel;
70 expired_function_t expired;
71 } dummy_timer_t;
72
73
74 static dummy_timer_t g_timers[MAX_CALLS];
75
76
77 static ftdm_mutex_t *g_schedule_mutex;
78
79
80 static ftdm_mutex_t *g_channel_mutex;
81
82
83 static ftdm_channel_t *g_outgoing_channel = NULL;
84
85 static void interrupt_requested(int signal)
86 {
87 app_running = 0;
88 }
89
90 static void schedule_timer(ftdm_channel_t *channel, int sec, expired_function_t expired)
91 {
92 int i;
93 ftdm_mutex_lock(g_schedule_mutex);
94 for (i = 0; i < sizeof(g_timers)/sizeof(g_timers[0]); i++) {
95
96 if (!g_timers[i].time) {
97 g_timers[i].time = sec;
98 g_timers[i].channel = channel;
99 g_timers[i].expired = expired;
100 ftdm_mutex_unlock(g_schedule_mutex);
101 return;
102 }
103 }
104 ftdm_log(FTDM_LOG_ERROR, "Failed to schedule timer\n");
105 ftdm_mutex_unlock(g_schedule_mutex);
106 }
107
108 static void run_timers(void)
109 {
110 int i;
111 void *channel;
112 expired_function_t expired_func = NULL;
113 ftdm_mutex_lock(g_schedule_mutex);
114 for (i = 0; i < sizeof(g_timers)/sizeof(g_timers[0]); i++) {
115
116 if (g_timers[i].time) {
117 g_timers[i].time--;
118 }
119
120
121 if (!g_timers[i].time && g_timers[i].expired) {
122 expired_func = g_timers[i].expired;
123 channel = g_timers[i].channel;
124 memset(&g_timers[i], 0, sizeof(g_timers[i]));
125 expired_func(channel);
126 }
127 }
128 ftdm_mutex_unlock(g_schedule_mutex);
129 }
130
131 static void release_timers(ftdm_channel_t *channel)
132 {
133 int i;
134 ftdm_mutex_lock(g_schedule_mutex);
135 for (i = 0; i < sizeof(g_timers)/sizeof(g_timers[0]); i++) {
136
137 if (g_timers[i].channel == channel) {
138 memset(&g_timers[i], 0, sizeof(g_timers[i]));
139 }
140 }
141 ftdm_mutex_unlock(g_schedule_mutex);
142 }
143
144
145 static void send_hangup(ftdm_channel_t *channel)
146 {
147 char dtmfbuff[100];
148 int rc;
149 int spanid = ftdm_channel_get_span_id(channel);
150 int chanid = ftdm_channel_get_id(channel);
151 rc = ftdm_channel_dequeue_dtmf(channel, dtmfbuff, sizeof(dtmfbuff));
152 if (rc) {
153 ftdm_log(FTDM_LOG_NOTICE, "Not hanging up channel %d:%d because has DTMF: %s\n", spanid, chanid, dtmfbuff);
154 schedule_timer(channel, HANGUP_TIMER, send_hangup);
155 return;
156 }
157 ftdm_log(FTDM_LOG_NOTICE, "-- Requesting hangup in channel %d:%d\n", spanid, chanid);
158 ftdm_channel_call_hangup(channel);
159 }
160
161
162 static void send_answer(ftdm_channel_t *channel)
163 {
164
165 int spanid = ftdm_channel_get_span_id(channel);
166 int chanid = ftdm_channel_get_id(channel);
167 ftdm_log(FTDM_LOG_NOTICE, "-- Requesting answer in channel %d:%d\n", spanid, chanid);
168 ftdm_channel_call_answer(channel);
169 schedule_timer(channel, HANGUP_TIMER, send_hangup);
170 }
171
172
173 static void send_progress(ftdm_channel_t *channel)
174 {
175
176 int spanid = ftdm_channel_get_span_id(channel);
177 int chanid = ftdm_channel_get_id(channel);
178 ftdm_log(FTDM_LOG_NOTICE, "-- Requesting progress\n", spanid, chanid);
179 ftdm_channel_call_indicate(channel, FTDM_CHANNEL_INDICATE_PROGRESS);
180 schedule_timer(channel, ANSWER_TIMER, send_answer);
181 }
182
183
184
185
186
187
188
189
190
191 static FIO_SIGNAL_CB_FUNCTION(on_signaling_event)
192 {
193 switch (sigmsg->event_id) {
194
195 case FTDM_SIGEVENT_START:
196 ftdm_log(FTDM_LOG_NOTICE, "Incoming call received in channel %d:%d\n", sigmsg->span_id, sigmsg->chan_id);
197 schedule_timer(sigmsg->channel, PROGRESS_TIMER, send_progress);
198 break;
199
200 case FTDM_SIGEVENT_PROGRESS_MEDIA:
201 ftdm_log(FTDM_LOG_NOTICE, "Progress message received in channel %d:%d\n", sigmsg->span_id, sigmsg->chan_id);
202 break;
203
204 case FTDM_SIGEVENT_UP:
205 ftdm_log(FTDM_LOG_NOTICE, "Answer received in channel %d:%d\n", sigmsg->span_id, sigmsg->chan_id);
206 ftdm_channel_command(sigmsg->channel, FTDM_COMMAND_ENABLE_DTMF_DETECT, NULL);
207
208
209
210
211 break;
212
213 case FTDM_SIGEVENT_STOP:
214 ftdm_log(FTDM_LOG_NOTICE, "Hangup received in channel %d:%d\n", sigmsg->span_id, sigmsg->chan_id);
215 ftdm_mutex_lock(g_channel_mutex);
216 if (g_outgoing_channel == sigmsg->channel) {
217 g_outgoing_channel = NULL;
218 }
219 ftdm_mutex_unlock(g_channel_mutex);
220
221 release_timers(sigmsg->channel);
222
223 ftdm_channel_call_hangup(sigmsg->channel);
224 break;
225 default:
226 ftdm_log(FTDM_LOG_WARNING, "Unhandled event %s in channel %d:%d\n", ftdm_signal_event2str(sigmsg->event_id),
227 sigmsg->span_id, sigmsg->chan_id);
228 break;
229 }
230 return FTDM_SUCCESS;
231 }
232
233 static void place_call(const ftdm_span_t *span, const char *number)
234 {
235 ftdm_channel_t *ftdmchan = NULL;
236 ftdm_caller_data_t caller_data = {{ 0 }};
237 ftdm_status_t status = FTDM_FAIL;
238
239
240 ftdm_set_string(caller_data.dnis.digits, number);
241
242
243 ftdm_set_string(caller_data.cid_name, "testsangomaboost");
244 ftdm_set_string(caller_data.cid_num.digits, "1234");
245
246
247
248
249
250 status = ftdm_channel_open_by_span(ftdm_span_get_id(span), FTDM_TOP_DOWN, &caller_data, &ftdmchan);
251 if (status != FTDM_SUCCESS) {
252 ftdm_log(FTDM_LOG_ERROR, "Failed to originate call\n");
253 return;
254 }
255
256 ftdm_mutex_lock(g_channel_mutex);
257 g_outgoing_channel = ftdmchan;
258 ftdm_mutex_unlock(g_channel_mutex);
259
260
261 ftdm_channel_set_caller_data(ftdmchan, &caller_data);
262
263 status = ftdm_channel_call_place(ftdmchan);
264 if (status != FTDM_SUCCESS) {
265 ftdm_log(FTDM_LOG_ERROR, "Failed to originate call\n");
266 return;
267 }
268
269
270 ftdm_channel_init(ftdmchan);
271 }
272
273 static void *media_thread(ftdm_thread_t *th, void *data)
274 {
275
276 ftdm_wait_flag_t flags = FTDM_NO_FLAGS;
277 ftdm_status_t status;
278 ftdm_channel_t *chan;
279 char iobuff[160];
280 char dnis_str[] = "1234";
281 int tx_dtmf = 0;
282 ftdm_size_t datalen = 0;
283 memset(iobuff, 0, sizeof(iobuff));
284 while(ftdm_running() && app_running) {
285 ftdm_mutex_lock(g_channel_mutex);
286 chan = g_outgoing_channel;
287 ftdm_mutex_unlock(g_channel_mutex);
288 if (chan && tx_dtmf) {
289 flags = FTDM_WRITE | FTDM_READ;
290 ftdm_channel_wait(chan, &flags, 100);
291 if (flags & FTDM_WRITE) {
292 datalen = sizeof(iobuff);
293 status = ftdm_channel_write(chan, iobuff, datalen, &datalen);
294 if (status != FTDM_SUCCESS) {
295 ftdm_log(FTDM_LOG_ERROR, "writing to channel failed\n");
296 }
297 }
298 if (flags & FTDM_READ) {
299 datalen = sizeof(iobuff);
300 status = ftdm_channel_read(chan, iobuff, &datalen);
301 if (status != FTDM_SUCCESS) {
302 ftdm_log(FTDM_LOG_ERROR, "reading from channel failed\n");
303 }
304 }
305 } else if (chan && ftdm_channel_call_check_answered(chan)) {
306 ftdm_log(FTDM_LOG_NOTICE, "Transmitting DNIS %s\n", dnis_str);
307 ftdm_channel_command(g_outgoing_channel, FTDM_COMMAND_SEND_DTMF, dnis_str);
308 tx_dtmf = 1;
309 } else {
310 tx_dtmf = 0;
311 ftdm_sleep(100);
312 }
313 }
314 printf("Shutting down media thread ...\n");
315 return NULL;
316 }
317
318 int main(int argc, char *argv[])
319 {
320 ftdm_conf_parameter_t parameters[20];
321 ftdm_span_t *span;
322 char *todial = NULL;
323 const char *sigtype = NULL;
324 int32_t ticks = 0;
325
326 if (argc < 3) {
327 fprintf(stderr, "Usage: %s <span name> <cpe|net> [number to dial if any]\n", argv[0]);
328 exit(-1);
329 }
330
331
332 #ifdef _WIN64
333
334 if (signal(SIGINT, interrupt_requested) < 0) {
335 #else
336 if (signal(SIGINT, interrupt_requested) == SIG_ERR) {
337 #endif
338 fprintf(stderr, "Could not set the SIGINT signal handler: %s\n", strerror(errno));
339 exit(-1);
340 }
341
342 if (!strcmp(argv[2], "cpe")) {
343 sigtype = "pri_cpe";
344 } else if (!strcmp(argv[2], "net")) {
345 sigtype = "pri_net";
346 } else {
347 fprintf(stderr, "Valid signaling types are cpe and net only\n");
348 exit(-1);
349 }
350 printf("Using signalling %s\n", sigtype);
351
352 if (argc >= 4) {
353 todial = argv[3];
354 if (!strlen(todial)) {
355 todial = NULL;
356 }
357 }
358
359
360 memset(&g_timers, 0, sizeof(g_timers));
361
362
363 ftdm_global_set_default_logger(FTDM_LOG_LEVEL_DEBUG);
364
365
366 if (ftdm_global_init() != FTDM_SUCCESS) {
367 fprintf(stderr, "Error loading FreeTDM\n");
368 exit(-1);
369 }
370
371
372 ftdm_mutex_create(&g_schedule_mutex);
373 ftdm_mutex_create(&g_channel_mutex);
374
375
376 if (ftdm_global_configuration() != FTDM_SUCCESS) {
377 fprintf(stderr, "Error configuring FreeTDM\n");
378 exit(-1);
379 }
380
381
382
383 printf("FreeTDM loaded ...\n");
384
385
386 if (ftdm_span_find_by_name(argv[1], &span) != FTDM_SUCCESS) {
387 fprintf(stderr, "Error finding FreeTDM span %s\n", argv[1]);
388 goto done;
389 }
390
391
392
393
394
395
396 parameters[0].var = "sigmod";
397 parameters[0].val = "sangoma_prid";
398
399
400 parameters[1].var = "switchtype";
401 parameters[1].val = "national";
402
403 parameters[2].var = "signalling";
404 parameters[2].val = sigtype;
405
406
407
408
409
410
411
412
413
414
415
416
417
418 parameters[3].var = NULL;
419
420
421 if (ftdm_configure_span_signaling(span, "sangoma_boost", on_signaling_event, parameters) != FTDM_SUCCESS) {
422 fprintf(stderr, "Error configuring sangoma_boost signaling abstraction in span %s\n", ftdm_span_get_name(span));
423 goto done;
424 }
425
426
427
428
429
430
431
432 ftdm_span_start(span);
433
434 if (ftdm_thread_create_detached(media_thread, NULL) != FTDM_SUCCESS){
435 fprintf(stderr, "Error launching media thread\n");
436 goto done;
437 }
438
439 app_running = 1;
440
441
442 while(ftdm_running() && app_running) {
443 ftdm_sleep(1000);
444 run_timers();
445 ticks++;
446 if (!(ticks % 10) && todial && !g_outgoing_channel) {
447 ftdm_log(FTDM_LOG_NOTICE, "Originating call to number %s\n", todial);
448 place_call(span, todial);
449 }
450 }
451 printf("Shutting down FreeTDM ...\n");
452 done:
453
454 ftdm_mutex_destroy(&g_schedule_mutex);
455 ftdm_mutex_destroy(&g_channel_mutex);
456
457
458 ftdm_global_destroy();
459
460 return 0;
461 }
462
463
464
465
466
467
468
469
470
471
472