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