Gentoo Websites Logo
Go to: Gentoo Home Documentation Forums Lists Bugs Planet Store Wiki Get Gentoo!
View | Details | Raw Unified | Return to bug 383987 | Differences between
and this patch

Collapse All | Expand All

(-)channels/chan_sip.c (-7 / +11 lines)
Lines 4316-4321 Link Here
4316
			case T38_ENABLED:
4316
			case T38_ENABLED:
4317
				state = T38_STATE_NEGOTIATED;
4317
				state = T38_STATE_NEGOTIATED;
4318
				break;
4318
				break;
4319
			case T38_REJECTED:
4320
				state = T38_STATE_REJECTED;
4321
				break;
4319
			default:
4322
			default:
4320
				state = T38_STATE_UNKNOWN;
4323
				state = T38_STATE_UNKNOWN;
4321
			}
4324
			}
Lines 4980-4985 Link Here
4980
		parameters.request_response = AST_T38_NEGOTIATED;
4983
		parameters.request_response = AST_T38_NEGOTIATED;
4981
		ast_udptl_set_tag(p->udptl, "SIP/%s", p->username);
4984
		ast_udptl_set_tag(p->udptl, "SIP/%s", p->username);
4982
		break;
4985
		break;
4986
	case T38_REJECTED:
4983
	case T38_DISABLED:
4987
	case T38_DISABLED:
4984
		if (old == T38_ENABLED) {
4988
		if (old == T38_ENABLED) {
4985
			parameters.request_response = AST_T38_TERMINATED;
4989
			parameters.request_response = AST_T38_TERMINATED;
Lines 6558-6568 Link Here
6558
	case AST_T38_REQUEST_NEGOTIATE:         /* Request T38 */
6562
	case AST_T38_REQUEST_NEGOTIATE:         /* Request T38 */
6559
		/* Negotiation can not take place without a valid max_ifp value. */
6563
		/* Negotiation can not take place without a valid max_ifp value. */
6560
		if (!parameters->max_ifp) {
6564
		if (!parameters->max_ifp) {
6561
			change_t38_state(p, T38_DISABLED);
6562
			if (p->t38.state == T38_PEER_REINVITE) {
6565
			if (p->t38.state == T38_PEER_REINVITE) {
6563
				AST_SCHED_DEL_UNREF(sched, p->t38id, dialog_unref(p, "when you delete the t38id sched, you should dec the refcount for the stored dialog ptr"));
6566
				AST_SCHED_DEL_UNREF(sched, p->t38id, dialog_unref(p, "when you delete the t38id sched, you should dec the refcount for the stored dialog ptr"));
6564
				transmit_response_reliable(p, "488 Not acceptable here", &p->initreq);
6567
				transmit_response_reliable(p, "488 Not acceptable here", &p->initreq);
6565
			}
6568
			}
6569
			change_t38_state(p, T38_REJECTED);
6566
			break;
6570
			break;
6567
		} else if (p->t38.state == T38_PEER_REINVITE) {
6571
		} else if (p->t38.state == T38_PEER_REINVITE) {
6568
			AST_SCHED_DEL_UNREF(sched, p->t38id, dialog_unref(p, "when you delete the t38id sched, you should dec the refcount for the stored dialog ptr"));
6572
			AST_SCHED_DEL_UNREF(sched, p->t38id, dialog_unref(p, "when you delete the t38id sched, you should dec the refcount for the stored dialog ptr"));
Lines 6600-6606 Link Here
6600
	case AST_T38_REQUEST_TERMINATE:         /* Shutdown T38 */
6604
	case AST_T38_REQUEST_TERMINATE:         /* Shutdown T38 */
6601
		if (p->t38.state == T38_PEER_REINVITE) {
6605
		if (p->t38.state == T38_PEER_REINVITE) {
6602
			AST_SCHED_DEL_UNREF(sched, p->t38id, dialog_unref(p, "when you delete the t38id sched, you should dec the refcount for the stored dialog ptr"));
6606
			AST_SCHED_DEL_UNREF(sched, p->t38id, dialog_unref(p, "when you delete the t38id sched, you should dec the refcount for the stored dialog ptr"));
6603
			change_t38_state(p, T38_DISABLED);
6607
			change_t38_state(p, T38_REJECTED);
6604
			transmit_response_reliable(p, "488 Not acceptable here", &p->initreq);
6608
			transmit_response_reliable(p, "488 Not acceptable here", &p->initreq);
6605
		} else if (p->t38.state == T38_ENABLED)
6609
		} else if (p->t38.state == T38_ENABLED)
6606
			transmit_reinvite_with_sdp(p, FALSE, FALSE);
6610
			transmit_reinvite_with_sdp(p, FALSE, FALSE);
Lines 9051-9057 Link Here
9051
		}
9055
		}
9052
	}
9056
	}
9053
9057
9054
	if ((portno == -1) && (p->t38.state != T38_DISABLED)) {
9058
	if ((portno == -1) && (p->t38.state != T38_DISABLED) && (p->t38.state != T38_REJECTED)) {
9055
		ast_debug(3, "Have T.38 but no audio, accepting offer anyway\n");
9059
		ast_debug(3, "Have T.38 but no audio, accepting offer anyway\n");
9056
		return 0;
9060
		return 0;
9057
        }
9061
        }
Lines 18980-18986 Link Here
18980
	} else  if (!strcasecmp(data, "peername")) {
18984
	} else  if (!strcasecmp(data, "peername")) {
18981
		ast_copy_string(buf, p->peername, len);
18985
		ast_copy_string(buf, p->peername, len);
18982
	} else if (!strcasecmp(data, "t38passthrough")) {
18986
	} else if (!strcasecmp(data, "t38passthrough")) {
18983
		if (p->t38.state == T38_DISABLED) {
18987
		if ((p->t38.state == T38_DISABLED) || (p->t38.state == T38_REJECTED)) {
18984
			ast_copy_string(buf, "0", len);
18988
			ast_copy_string(buf, "0", len);
18985
		} else { /* T38 is offered or enabled in this call */
18989
		} else { /* T38 is offered or enabled in this call */
18986
			ast_copy_string(buf, "1", len);
18990
			ast_copy_string(buf, "1", len);
Lines 19746-19752 Link Here
19746
	case 606: /* Not Acceptable */
19750
	case 606: /* Not Acceptable */
19747
		xmitres = transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, FALSE);
19751
		xmitres = transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, FALSE);
19748
		if (p->udptl && p->t38.state == T38_LOCAL_REINVITE) {
19752
		if (p->udptl && p->t38.state == T38_LOCAL_REINVITE) {
19749
			change_t38_state(p, T38_DISABLED);
19753
			change_t38_state(p, T38_REJECTED);
19750
			/* Try to reset RTP timers */
19754
			/* Try to reset RTP timers */
19751
			//ast_rtp_set_rtptimers_onhold(p->rtp);
19755
			//ast_rtp_set_rtptimers_onhold(p->rtp);
19752
19756
Lines 21554-21560 Link Here
21554
	 * want to abort the negotiation process
21558
	 * want to abort the negotiation process
21555
	 */
21559
	 */
21556
	if (p->t38id != -1) {
21560
	if (p->t38id != -1) {
21557
		change_t38_state(p, T38_DISABLED);
21561
		change_t38_state(p, T38_REJECTED);
21558
		transmit_response_reliable(p, "488 Not acceptable here", &p->initreq);
21562
		transmit_response_reliable(p, "488 Not acceptable here", &p->initreq);
21559
		p->t38id = -1;
21563
		p->t38id = -1;
21560
		dialog_unref(p, "unref the dialog ptr from sip_t38_abort, because it held a dialog ptr");
21564
		dialog_unref(p, "unref the dialog ptr from sip_t38_abort, because it held a dialog ptr");
Lines 22429-22435 Link Here
22429
			} else if (p->t38.state == T38_ENABLED) {
22433
			} else if (p->t38.state == T38_ENABLED) {
22430
				ast_set_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED);
22434
				ast_set_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED);
22431
				transmit_response_with_t38_sdp(p, "200 OK", req, (reinvite ? XMIT_RELIABLE : (req->ignore ?  XMIT_UNRELIABLE : XMIT_CRITICAL)));
22435
				transmit_response_with_t38_sdp(p, "200 OK", req, (reinvite ? XMIT_RELIABLE : (req->ignore ?  XMIT_UNRELIABLE : XMIT_CRITICAL)));
22432
			} else if (p->t38.state == T38_DISABLED) {
22436
			} else if ((p->t38.state == T38_DISABLED) || (p->t38.state == T38_REJECTED)) {
22433
				/* If this is not a re-invite or something to ignore - it's critical */
22437
				/* If this is not a re-invite or something to ignore - it's critical */
22434
				if (p->srtp && !ast_test_flag(p->srtp, SRTP_CRYPTO_OFFER_OK)) {
22438
				if (p->srtp && !ast_test_flag(p->srtp, SRTP_CRYPTO_OFFER_OK)) {
22435
					ast_log(LOG_WARNING, "Target does not support required crypto\n");
22439
					ast_log(LOG_WARNING, "Target does not support required crypto\n");
(-)channels/sip/include/sip.h (-1 / +2 lines)
Lines 597-603 Link Here
597
	T38_DISABLED = 0,     /*!< Not enabled */
597
	T38_DISABLED = 0,     /*!< Not enabled */
598
	T38_LOCAL_REINVITE,   /*!< Offered from local - REINVITE */
598
	T38_LOCAL_REINVITE,   /*!< Offered from local - REINVITE */
599
	T38_PEER_REINVITE,    /*!< Offered from peer - REINVITE */
599
	T38_PEER_REINVITE,    /*!< Offered from peer - REINVITE */
600
	T38_ENABLED           /*!< Negotiated (enabled) */
600
	T38_ENABLED,          /*!< Negotiated (enabled) */
601
	T38_REJECTED          /*!< Refused */
601
};
602
};
602
603
603
/*! \brief Parameters to know status of transfer */
604
/*! \brief Parameters to know status of transfer */
(-)addons/chan_ooh323.c (-219 / +554 lines)
Lines 25-30 Link Here
25
#include "chan_ooh323.h"
25
#include "chan_ooh323.h"
26
#include <math.h>
26
#include <math.h>
27
27
28
/*** DOCUMENTATION
29
	<function name="OOH323" language="en_US">
30
		<synopsis>
31
			Allow Setting / Reading OOH323 Settings
32
		</synopsis>
33
		<syntax>
34
			<parameter name="name" required="true">
35
				<enumlist>
36
					<enum name="faxdetect">
37
						<para>Fax Detect [R/W]</para>
38
						<para>Returns 0 or 1</para>
39
						<para>Write yes or no</para>
40
					</enum>
41
				</enumlist>
42
				<enumlist>
43
					<enum name="t38support">
44
						<para>t38support [R/W]</para>
45
						<para>Returns 0 or 1</para>
46
						<para>Write yes or no</para>
47
					</enum>
48
				</enumlist>
49
				<enumlist>
50
					<enum name="h323id">
51
						<para>Returns h323id [R]</para>
52
					</enum>
53
				</enumlist>
54
			</parameter>
55
		</syntax>
56
		<description>
57
			<para>Read and set channel parameters in the dialplan.
58
			<replaceable>name</replaceable> is one of the above only those with a [W] can be writen to.
59
			</para>
60
		</description>
61
	</function>
62
***/
63
28
#define FORMAT_STRING_SIZE	512
64
#define FORMAT_STRING_SIZE	512
29
65
30
/* Defaults */
66
/* Defaults */
Lines 50-55 Link Here
50
#define T38_ENABLED 1
86
#define T38_ENABLED 1
51
#define T38_FAXGW 1
87
#define T38_FAXGW 1
52
88
89
#define FAXDETECT_CNG	1
90
#define FAXDETECT_T38	2
91
53
/* Channel description */
92
/* Channel description */
54
static const char type[] = "OOH323";
93
static const char type[] = "OOH323";
55
static const char tdesc[] = "Objective Systems H323 Channel Driver";
94
static const char tdesc[] = "Objective Systems H323 Channel Driver";
Lines 140-145 Link Here
140
	struct ast_rtp_instance *vrtp; /* Placeholder for now */
179
	struct ast_rtp_instance *vrtp; /* Placeholder for now */
141
180
142
	int t38support;			/* T.38 mode - disable, transparent, faxgw */
181
	int t38support;			/* T.38 mode - disable, transparent, faxgw */
182
	int faxdetect;
183
	int faxdetected;
143
	int rtptimeout;
184
	int rtptimeout;
144
	struct ast_udptl *udptl;
185
	struct ast_udptl *udptl;
145
	int faxmode;
186
	int faxmode;
Lines 201-225 Link Here
201
/* Profile of H.323 user registered with PBX*/
242
/* Profile of H.323 user registered with PBX*/
202
struct ooh323_user{
243
struct ooh323_user{
203
	ast_mutex_t lock;
244
	ast_mutex_t lock;
204
	char        name[256];
245
	char		name[256];
205
	char        context[AST_MAX_EXTENSION];
246
	char		context[AST_MAX_EXTENSION];
206
	int         incominglimit;
247
	int		incominglimit;
207
	unsigned    inUse;
248
	unsigned	inUse;
208
	char        accountcode[20];
249
	char		accountcode[20];
209
	int         amaflags;
250
	int		amaflags;
210
	format_t    capability;
251
	format_t	capability;
211
	struct ast_codec_pref prefs;
252
	struct ast_codec_pref prefs;
212
	int         dtmfmode;
253
	int		dtmfmode;
213
	int	    dtmfcodec;
254
	int		dtmfcodec;
214
	int	    t38support;
255
	int		faxdetect;
215
	int         rtptimeout;
256
	int		t38support;
216
	int         mUseIP;        /* Use IP address or H323-ID to search user */
257
	int		rtptimeout;
217
	char        mIP[20];
258
	int		mUseIP;        /* Use IP address or H323-ID to search user */
218
	struct OOH323Regex	    *rtpmask;
259
	char		mIP[20];
219
	char	    rtpmaskstr[120];
260
	struct OOH323Regex *rtpmask;
220
	int	    rtdrcount, rtdrinterval;
261
	char		rtpmaskstr[120];
221
	int	    faststart, h245tunneling;
262
	int		rtdrcount, rtdrinterval;
222
	int	    g729onlyA;
263
	int		faststart, h245tunneling;
264
	int		g729onlyA;
223
	struct ooh323_user *next;
265
	struct ooh323_user *next;
224
};
266
};
225
267
Lines 235-240 Link Here
235
	int         amaflags;
277
	int         amaflags;
236
	int         dtmfmode;
278
	int         dtmfmode;
237
	int	    dtmfcodec;
279
	int	    dtmfcodec;
280
	int	    faxdetect;
238
	int	    t38support;
281
	int	    t38support;
239
	int         mFriend;    /* indicates defined as friend */
282
	int         mFriend;    /* indicates defined as friend */
240
	char        ip[20];
283
	char        ip[20];
Lines 295-300 Link Here
295
static struct ast_codec_pref gPrefs;
338
static struct ast_codec_pref gPrefs;
296
static int  gDTMFMode = H323_DTMF_RFC2833;
339
static int  gDTMFMode = H323_DTMF_RFC2833;
297
static int  gDTMFCodec = 101;
340
static int  gDTMFCodec = 101;
341
static int  gFAXdetect = FAXDETECT_CNG;
298
static int  gT38Support = T38_FAXGW;
342
static int  gT38Support = T38_FAXGW;
299
static char gGatekeeper[100];
343
static char gGatekeeper[100];
300
static enum RasGatekeeperMode gRasGkMode = RasNoGatekeeper;
344
static enum RasGatekeeperMode gRasGkMode = RasNoGatekeeper;
Lines 343-352 Link Here
343
387
344
388
345
static struct ast_channel *ooh323_new(struct ooh323_pvt *i, int state,
389
static struct ast_channel *ooh323_new(struct ooh323_pvt *i, int state,
346
                                             const char *host, int capability, const char *linkedid) 
390
                                             const char *host, int capability, const char *linkedid)
347
{
391
{
348
	struct ast_channel *ch = NULL;
392
	struct ast_channel *ch = NULL;
349
	int fmt = 0;
393
	int fmt = 0;
394
	int features = 0;
395
350
	if (gH323Debug)
396
	if (gH323Debug)
351
		ast_verbose("---   ooh323_new - %s, %d\n", host, capability);
397
		ast_verbose("---   ooh323_new - %s, %d\n", host, capability);
352
398
Lines 390-407 Link Here
390
		ast_module_ref(myself);
436
		ast_module_ref(myself);
391
437
392
		/* Allocate dsp for in-band DTMF support */
438
		/* Allocate dsp for in-band DTMF support */
393
		if (i->dtmfmode & H323_DTMF_INBAND) {
439
		if ((i->dtmfmode & H323_DTMF_INBAND) || (i->faxdetect & FAXDETECT_CNG)) {
394
			i->vad = ast_dsp_new();
440
			i->vad = ast_dsp_new();
395
			ast_dsp_set_features(i->vad, DSP_FEATURE_DIGIT_DETECT);
441
		}
396
       			ast_dsp_set_features(i->vad,
397
						DSP_FEATURE_DIGIT_DETECT | DSP_FEATURE_FAX_DETECT);
398
        		ast_dsp_set_faxmode(i->vad,
399
						DSP_FAXMODE_DETECT_CNG | DSP_FAXMODE_DETECT_CED);
400
442
401
			if (i->dtmfmode & H323_DTMF_INBANDRELAX)
443
		/* inband DTMF*/
444
		if (i->dtmfmode & H323_DTMF_INBAND) {
445
			features |= DSP_FEATURE_DIGIT_DETECT;
446
			if (i->dtmfmode & H323_DTMF_INBANDRELAX) {
402
				ast_dsp_set_digitmode(i->vad, DSP_DIGITMODE_DTMF | DSP_DIGITMODE_RELAXDTMF);
447
				ast_dsp_set_digitmode(i->vad, DSP_DIGITMODE_DTMF | DSP_DIGITMODE_RELAXDTMF);
448
			}
403
		}
449
		}
404
450
451
		/* fax detection*/
452
		if (i->faxdetect & FAXDETECT_CNG) {
453
			features |= DSP_FEATURE_FAX_DETECT;
454
			ast_dsp_set_faxmode(i->vad,
455
					DSP_FAXMODE_DETECT_CNG | DSP_FAXMODE_DETECT_CED);
456
		}
457
458
		if (features) {
459
			ast_dsp_set_features(i->vad, features);
460
		}
461
405
		ast_mutex_lock(&usecnt_lock);
462
		ast_mutex_lock(&usecnt_lock);
406
		usecnt++;
463
		usecnt++;
407
		ast_mutex_unlock(&usecnt_lock);
464
		ast_mutex_unlock(&usecnt_lock);
Lines 517-522 Link Here
517
	ast_udptl_set_error_correction_scheme(pvt->udptl, UDPTL_ERROR_CORRECTION_NONE);
574
	ast_udptl_set_error_correction_scheme(pvt->udptl, UDPTL_ERROR_CORRECTION_NONE);
518
	ast_udptl_set_far_max_datagram(pvt->udptl, 144);
575
	ast_udptl_set_far_max_datagram(pvt->udptl, 144);
519
	pvt->faxmode = 0;
576
	pvt->faxmode = 0;
577
	pvt->chmodepend = 0;
578
	pvt->faxdetected = 0;
579
	pvt->faxdetect = gFAXdetect;
520
	pvt->t38support = gT38Support;
580
	pvt->t38support = gT38Support;
521
	pvt->rtptimeout = gRTPTimeout;
581
	pvt->rtptimeout = gRTPTimeout;
522
	pvt->rtdrinterval = gRTDRInterval;
582
	pvt->rtdrinterval = gRTDRInterval;
Lines 646-651 Link Here
646
		p->g729onlyA = peer->g729onlyA;
706
		p->g729onlyA = peer->g729onlyA;
647
		p->dtmfmode |= peer->dtmfmode;
707
		p->dtmfmode |= peer->dtmfmode;
648
		p->dtmfcodec  = peer->dtmfcodec;
708
		p->dtmfcodec  = peer->dtmfcodec;
709
		p->faxdetect = peer->faxdetect;
649
		p->t38support = peer->t38support;
710
		p->t38support = peer->t38support;
650
		p->rtptimeout = peer->rtptimeout;
711
		p->rtptimeout = peer->rtptimeout;
651
		p->faststart = peer->faststart;
712
		p->faststart = peer->faststart;
Lines 675-680 Link Here
675
		p->g729onlyA = g729onlyA;
736
		p->g729onlyA = g729onlyA;
676
		p->dtmfmode = gDTMFMode;
737
		p->dtmfmode = gDTMFMode;
677
		p->dtmfcodec = gDTMFCodec;
738
		p->dtmfcodec = gDTMFCodec;
739
		p->faxdetect = gFAXdetect;
678
		p->t38support = gT38Support;
740
		p->t38support = gT38Support;
679
		p->rtptimeout = gRTPTimeout;
741
		p->rtptimeout = gRTPTimeout;
680
		p->capability = gCapability;
742
		p->capability = gCapability;
Lines 864-880 Link Here
864
	}
926
	}
865
	ast_mutex_lock(&p->lock);
927
	ast_mutex_lock(&p->lock);
866
928
867
929
	if (p->rtp && ((p->dtmfmode & H323_DTMF_RFC2833) || (p->dtmfmode & H323_DTMF_CISCO))) {
868
	if (digit == 'e' && !p->faxmode && p->t38support != T38_DISABLED)  {
869
		if (!p->chmodepend) {
870
			if (gH323Debug)
871
				ast_verbose("request to change %s to t.38 because fax cng\n",
872
						p->callToken);
873
			p->chmodepend = 1;
874
			ooRequestChangeMode(p->callToken, 1);
875
		}
876
877
	} else if (p->rtp && ((p->dtmfmode & H323_DTMF_RFC2833) || (p->dtmfmode & H323_DTMF_CISCO))) {
878
		ast_rtp_instance_dtmf_begin(p->rtp, digit);
930
		ast_rtp_instance_dtmf_begin(p->rtp, digit);
879
	} else if (((p->dtmfmode & H323_DTMF_Q931) ||
931
	} else if (((p->dtmfmode & H323_DTMF_Q931) ||
880
						 (p->dtmfmode & H323_DTMF_H245ALPHANUMERIC) ||
932
						 (p->dtmfmode & H323_DTMF_H245ALPHANUMERIC) ||
Lines 1309-1335 Link Here
1309
				(int)sizeof(enum ast_control_t38), (int)datalen);
1361
				(int)sizeof(enum ast_control_t38), (int)datalen);
1310
		} else {
1362
		} else {
1311
			const struct ast_control_t38_parameters *parameters = data;
1363
			const struct ast_control_t38_parameters *parameters = data;
1364
			struct ast_control_t38_parameters our_parameters;
1312
			enum ast_control_t38 message = parameters->request_response;
1365
			enum ast_control_t38 message = parameters->request_response;
1313
			switch (message) {
1366
			switch (message) {
1314
1367
1368
			case AST_T38_NEGOTIATED:
1369
				if (p->faxmode) {
1370
					res = 0;
1371
					break;
1372
				}
1315
			case AST_T38_REQUEST_NEGOTIATE:
1373
			case AST_T38_REQUEST_NEGOTIATE:
1316
1374
1317
				if (!p->chmodepend && !p->faxmode) {
1375
				if (p->faxmode) {
1376
					/* T.38 already negotiated */
1377
					our_parameters.request_response = AST_T38_NEGOTIATED;
1378
					our_parameters.max_ifp = ast_udptl_get_far_max_ifp(p->udptl);
1379
					our_parameters.rate = AST_T38_RATE_14400;
1380
					ast_queue_control_data(p->owner, AST_CONTROL_T38_PARAMETERS, &our_parameters, sizeof(our_parameters));
1381
				} else if (!p->chmodepend) {
1382
					p->chmodepend = 1;
1318
					ooRequestChangeMode(p->callToken, 1);
1383
					ooRequestChangeMode(p->callToken, 1);
1319
					p->chmodepend = 1;
1320
					res = 0;
1384
					res = 0;
1321
				}
1385
				}
1322
				break;
1386
				break;
1323
1387
1324
			case AST_T38_REQUEST_TERMINATE:
1388
			case AST_T38_REQUEST_TERMINATE:
1325
1389
1326
				if (!p->chmodepend && p->faxmode) {
1390
				if (!p->faxmode) {
1391
					/* T.38 already terminated */
1392
					our_parameters.request_response = AST_T38_TERMINATED;
1393
					ast_queue_control_data(p->owner, AST_CONTROL_T38_PARAMETERS, &our_parameters, sizeof(our_parameters));
1394
				} else if (!p->chmodepend) {
1395
					p->chmodepend = 1;
1327
					ooRequestChangeMode(p->callToken, 0);
1396
					ooRequestChangeMode(p->callToken, 0);
1328
					p->chmodepend = 1;
1329
					res = 0;
1397
					res = 0;
1330
				}
1398
				}
1331
				break;
1399
				break;
1332
1400
1401
			case AST_T38_REQUEST_PARMS:
1402
				our_parameters.request_response = AST_T38_REQUEST_PARMS;
1403
				our_parameters.max_ifp = ast_udptl_get_far_max_ifp(p->udptl);
1404
				our_parameters.rate = AST_T38_RATE_14400;
1405
				ast_queue_control_data(p->owner, AST_CONTROL_T38_PARAMETERS, &our_parameters, sizeof(our_parameters));
1406
				res = AST_T38_REQUEST_PARMS;
1407
				break;
1333
1408
1334
			default:
1409
			default:
1335
				;
1410
				;
Lines 1375-1391 Link Here
1375
		case AST_OPTION_T38_STATE:
1450
		case AST_OPTION_T38_STATE:
1376
1451
1377
			if (*datalen != sizeof(enum ast_t38_state)) {
1452
			if (*datalen != sizeof(enum ast_t38_state)) {
1378
                        	ast_log(LOG_ERROR, "Invalid datalen for AST_OPTION_T38_STATE option."
1453
				ast_log(LOG_ERROR, "Invalid datalen for AST_OPTION_T38_STATE option."
1379
				" Expected %d, got %d\n", (int)sizeof(enum ast_t38_state), *datalen);
1454
				" Expected %d, got %d\n", (int)sizeof(enum ast_t38_state), *datalen);
1380
				break;
1455
				break;
1381
			}
1456
			}
1382
			if (p->t38support != T38_DISABLED)
1383
				state = T38_STATE_UNKNOWN;
1384
			if (p->faxmode)
1385
				state = (p->chmodepend) ? T38_STATE_UNKNOWN : T38_STATE_NEGOTIATED;
1386
			else if (p->chmodepend)
1387
				state = T38_STATE_NEGOTIATING;
1388
1457
1458
			if (p->t38support != T38_DISABLED) {
1459
				if (p->faxmode) {
1460
					state = (p->chmodepend) ? T38_STATE_NEGOTIATING : T38_STATE_NEGOTIATED;
1461
				} else {
1462
					state = T38_STATE_UNKNOWN;
1463
				}
1464
			}
1389
1465
1390
			*((enum ast_t38_state *) data) = state;
1466
			*((enum ast_t38_state *) data) = state;
1391
			res = 0;
1467
			res = 0;
Lines 1803-1808 Link Here
1803
		memcpy(&p->prefs, &user->prefs, sizeof(struct ast_codec_pref));
1879
		memcpy(&p->prefs, &user->prefs, sizeof(struct ast_codec_pref));
1804
		p->dtmfmode |= user->dtmfmode;
1880
		p->dtmfmode |= user->dtmfmode;
1805
		p->dtmfcodec = user->dtmfcodec;
1881
		p->dtmfcodec = user->dtmfcodec;
1882
		p->faxdetect = user->faxdetect;
1806
		p->t38support = user->t38support;
1883
		p->t38support = user->t38support;
1807
		p->rtptimeout = user->rtptimeout;
1884
		p->rtptimeout = user->rtptimeout;
1808
		p->h245tunneling = user->h245tunneling;
1885
		p->h245tunneling = user->h245tunneling;
Lines 2225-2230 Link Here
2225
		user->rtptimeout = gRTPTimeout;
2302
		user->rtptimeout = gRTPTimeout;
2226
		user->dtmfmode = gDTMFMode;
2303
		user->dtmfmode = gDTMFMode;
2227
		user->dtmfcodec = gDTMFCodec;
2304
		user->dtmfcodec = gDTMFCodec;
2305
		user->faxdetect = gFAXdetect;
2228
		user->t38support = gT38Support;
2306
		user->t38support = gT38Support;
2229
		user->faststart = gFastStart;
2307
		user->faststart = gFastStart;
2230
		user->h245tunneling = gTunneling;
2308
		user->h245tunneling = gTunneling;
Lines 2300-2306 Link Here
2300
				user->dtmfmode |= ast_true(v->value) ? H323_DTMF_INBANDRELAX : 0;
2378
				user->dtmfmode |= ast_true(v->value) ? H323_DTMF_INBANDRELAX : 0;
2301
			} else if (!strcasecmp(v->name, "dtmfcodec") && atoi(v->value)) {
2379
			} else if (!strcasecmp(v->name, "dtmfcodec") && atoi(v->value)) {
2302
				user->dtmfcodec = atoi(v->value);
2380
				user->dtmfcodec = atoi(v->value);
2303
	 		} else if (!strcasecmp(v->name, "t38support")) {
2381
			} else if (!strcasecmp(v->name, "faxdetect")) {
2382
				if (ast_true(v->value)) {
2383
					user->faxdetect = FAXDETECT_CNG | FAXDETECT_T38;
2384
				} else if (ast_false(v->value)) {
2385
					user->faxdetect = 0;
2386
				} else {
2387
					char *buf = ast_strdupa(v->value);
2388
					char *word, *next = buf;
2389
					user->faxdetect = 0;
2390
					while ((word = strsep(&next, ","))) {
2391
						if (!strcasecmp(word, "cng")) {
2392
							user->faxdetect |= FAXDETECT_CNG;
2393
						} else if (!strcasecmp(word, "t38")) {
2394
							user->faxdetect |= FAXDETECT_T38;
2395
						} else {
2396
							ast_log(LOG_WARNING, "Unknown faxdetect mode '%s' on line %d.\n", word, v->lineno);
2397
						}
2398
					}
2399
2400
				}
2401
			} else if (!strcasecmp(v->name, "t38support")) {
2304
				if (!strcasecmp(v->value, "disabled"))
2402
				if (!strcasecmp(v->value, "disabled"))
2305
					user->t38support = T38_DISABLED;
2403
					user->t38support = T38_DISABLED;
2306
				if (!strcasecmp(v->value, "no"))
2404
				if (!strcasecmp(v->value, "no"))
Lines 2339-2349 Link Here
2339
		peer->amaflags = gAMAFLAGS;
2437
		peer->amaflags = gAMAFLAGS;
2340
		peer->dtmfmode = gDTMFMode;
2438
		peer->dtmfmode = gDTMFMode;
2341
		peer->dtmfcodec = gDTMFCodec;
2439
		peer->dtmfcodec = gDTMFCodec;
2440
		peer->faxdetect = gFAXdetect;
2342
		peer->t38support = gT38Support;
2441
		peer->t38support = gT38Support;
2343
		peer->faststart = gFastStart;
2442
		peer->faststart = gFastStart;
2344
		peer->h245tunneling = gTunneling;
2443
		peer->h245tunneling = gTunneling;
2345
		peer->g729onlyA = g729onlyA;
2444
		peer->g729onlyA = g729onlyA;
2346
      		peer->port = 1720;
2445
		peer->port = 1720;
2347
		if (0 == friend_type) {
2446
		if (0 == friend_type) {
2348
			peer->mFriend = 1;
2447
			peer->mFriend = 1;
2349
		}
2448
		}
Lines 2439-2445 Link Here
2439
				peer->dtmfmode |= ast_true(v->value) ? H323_DTMF_INBANDRELAX : 0;
2538
				peer->dtmfmode |= ast_true(v->value) ? H323_DTMF_INBANDRELAX : 0;
2440
			} else if (!strcasecmp(v->name, "dtmfcodec") && atoi(v->value)) {
2539
			} else if (!strcasecmp(v->name, "dtmfcodec") && atoi(v->value)) {
2441
				peer->dtmfcodec = atoi(v->value);
2540
				peer->dtmfcodec = atoi(v->value);
2442
	 		} else if (!strcasecmp(v->name, "t38support")) {
2541
			} else if (!strcasecmp(v->name, "faxdetect")) {
2542
				if (ast_true(v->value)) {
2543
					peer->faxdetect = FAXDETECT_CNG | FAXDETECT_T38;
2544
				} else if (ast_false(v->value)) {
2545
					peer->faxdetect = 0;
2546
				} else {
2547
					char *buf = ast_strdupa(v->value);
2548
					char *word, *next = buf;
2549
					peer->faxdetect = 0;
2550
					while ((word = strsep(&next, ","))) {
2551
						if (!strcasecmp(word, "cng")) {
2552
							peer->faxdetect |= FAXDETECT_CNG;
2553
						} else if (!strcasecmp(word, "t38")) {
2554
							peer->faxdetect |= FAXDETECT_T38;
2555
						} else {
2556
							ast_log(LOG_WARNING, "Unknown faxdetect mode '%s' on line %d.\n", word, v->lineno);
2557
						}
2558
					}
2559
2560
				}
2561
			} else if (!strcasecmp(v->name, "t38support")) {
2443
				if (!strcasecmp(v->value, "disabled"))
2562
				if (!strcasecmp(v->value, "disabled"))
2444
					peer->t38support = T38_DISABLED;
2563
					peer->t38support = T38_DISABLED;
2445
				if (!strcasecmp(v->value, "no"))
2564
				if (!strcasecmp(v->value, "no"))
Lines 2560-2565 Link Here
2560
	memset(&gPrefs, 0, sizeof(struct ast_codec_pref));
2679
	memset(&gPrefs, 0, sizeof(struct ast_codec_pref));
2561
	gDTMFMode = H323_DTMF_RFC2833;
2680
	gDTMFMode = H323_DTMF_RFC2833;
2562
	gDTMFCodec = 101;
2681
	gDTMFCodec = 101;
2682
	gFAXdetect = FAXDETECT_CNG;
2563
	gT38Support = T38_FAXGW;
2683
	gT38Support = T38_FAXGW;
2564
	gTRCLVL = OOTRCLVLERR;
2684
	gTRCLVL = OOTRCLVLERR;
2565
	gRasGkMode = RasNoGatekeeper;
2685
	gRasGkMode = RasNoGatekeeper;
Lines 2756-2762 Link Here
2756
			gDTMFMode |= ast_true(v->value) ? H323_DTMF_INBANDRELAX : 0;
2876
			gDTMFMode |= ast_true(v->value) ? H323_DTMF_INBANDRELAX : 0;
2757
		} else if (!strcasecmp(v->name, "dtmfcodec") && atoi(v->value)) {
2877
		} else if (!strcasecmp(v->name, "dtmfcodec") && atoi(v->value)) {
2758
			gDTMFCodec = atoi(v->value);
2878
			gDTMFCodec = atoi(v->value);
2759
	 	} else if (!strcasecmp(v->name, "t38support")) {
2879
		} else if (!strcasecmp(v->name, "faxdetect")) {
2880
			if (ast_true(v->value)) {
2881
				gFAXdetect = FAXDETECT_CNG | FAXDETECT_T38;
2882
			} else if (ast_false(v->value)) {
2883
				gFAXdetect = 0;
2884
			} else {
2885
				char *buf = ast_strdupa(v->value);
2886
				char *word, *next = buf;
2887
				gFAXdetect = 0;
2888
				while ((word = strsep(&next, ","))) {
2889
					if (!strcasecmp(word, "cng")) {
2890
						gFAXdetect |= FAXDETECT_CNG;
2891
					} else if (!strcasecmp(word, "t38")) {
2892
						gFAXdetect |= FAXDETECT_T38;
2893
					} else {
2894
						ast_log(LOG_WARNING, "Unknown faxdetect mode '%s' on line %d.\n", word, v->lineno);
2895
					}
2896
				}
2897
2898
			}
2899
		} else if (!strcasecmp(v->name, "t38support")) {
2760
			if (!strcasecmp(v->value, "disabled"))
2900
			if (!strcasecmp(v->value, "disabled"))
2761
				gT38Support = T38_DISABLED;
2901
				gT38Support = T38_DISABLED;
2762
			if (!strcasecmp(v->value, "no"))
2902
			if (!strcasecmp(v->value, "no"))
Lines 2843-2856 Link Here
2843
	if (a->argc != 4)
2983
	if (a->argc != 4)
2844
		return CLI_SHOWUSAGE;
2984
		return CLI_SHOWUSAGE;
2845
2985
2846
 
2847
	ast_mutex_lock(&peerl.lock);
2986
	ast_mutex_lock(&peerl.lock);
2848
	peer = peerl.peers;
2987
	peer = peerl.peers;
2849
	while (peer) {
2988
	while (peer) {
2850
		ast_mutex_lock(&peer->lock);
2989
		ast_mutex_lock(&peer->lock);
2851
      		if(!strcmp(peer->name, a->argv[3]))
2990
		if (!strcmp(peer->name, a->argv[3])) {
2852
			break;
2991
			break;
2853
		else {
2992
		} else {
2854
			prev = peer;
2993
			prev = peer;
2855
			peer = peer->next;
2994
			peer = peer->next;
2856
			ast_mutex_unlock(&prev->lock);
2995
			ast_mutex_unlock(&prev->lock);
Lines 2858-2910 Link Here
2858
	}
2997
	}
2859
2998
2860
	if (peer) {
2999
	if (peer) {
2861
      sprintf(ip_port, "%s:%d", peer->ip, peer->port);
3000
		sprintf(ip_port, "%s:%d", peer->ip, peer->port);
2862
      ast_cli(a->fd, "%-15.15s%s\n", "Name: ", peer->name);
3001
		ast_cli(a->fd, "%-15.15s%s\n", "Name: ", peer->name);
2863
      ast_cli(a->fd, "%s:%s,%s\n", "FastStart/H.245 Tunneling", peer->faststart?"yes":"no",
3002
		ast_cli(a->fd, "%s:%s,%s\n", "FastStart/H.245 Tunneling", peer->faststart?"yes":"no",
2864
					peer->h245tunneling?"yes":"no");
3003
					peer->h245tunneling?"yes":"no");
2865
      ast_cli(a->fd, "%-15.15s%s", "Format Prefs: ", "(");
3004
		ast_cli(a->fd, "%-15.15s%s", "Format Prefs: ", "(");
2866
      print_codec_to_cli(a->fd, &peer->prefs);
3005
		print_codec_to_cli(a->fd, &peer->prefs);
2867
      ast_cli(a->fd, ")\n");
3006
		ast_cli(a->fd, ")\n");
2868
      ast_cli(a->fd, "%-15.15s", "DTMF Mode: ");
3007
		ast_cli(a->fd, "%-15.15s", "DTMF Mode: ");
2869
		if (peer->dtmfmode & H323_DTMF_CISCO) {
3008
		if (peer->dtmfmode & H323_DTMF_CISCO) {
2870
         ast_cli(a->fd, "%s\n", "cisco");
3009
			ast_cli(a->fd, "%s\n", "cisco");
2871
	 ast_cli(a->fd, "%-15.15s%d\n", "DTMF Codec: ", peer->dtmfcodec);
3010
			ast_cli(a->fd, "%-15.15s%d\n", "DTMF Codec: ", peer->dtmfcodec);
2872
		} else if (peer->dtmfmode & H323_DTMF_RFC2833) {
3011
		} else if (peer->dtmfmode & H323_DTMF_RFC2833) {
2873
         ast_cli(a->fd, "%s\n", "rfc2833");
3012
			ast_cli(a->fd, "%s\n", "rfc2833");
2874
	 ast_cli(a->fd, "%-15.15s%d\n", "DTMF Codec: ", peer->dtmfcodec);
3013
			ast_cli(a->fd, "%-15.15s%d\n", "DTMF Codec: ", peer->dtmfcodec);
2875
		} else if (peer->dtmfmode & H323_DTMF_Q931)
3014
		} else if (peer->dtmfmode & H323_DTMF_Q931) {
2876
         ast_cli(a->fd, "%s\n", "q931keypad");
3015
			ast_cli(a->fd, "%s\n", "q931keypad");
2877
		else if (peer->dtmfmode & H323_DTMF_H245ALPHANUMERIC)
3016
		} else if (peer->dtmfmode & H323_DTMF_H245ALPHANUMERIC) {
2878
         ast_cli(a->fd, "%s\n", "h245alphanumeric");
3017
			ast_cli(a->fd, "%s\n", "h245alphanumeric");
2879
		else if (peer->dtmfmode & H323_DTMF_H245SIGNAL)
3018
		} else if (peer->dtmfmode & H323_DTMF_H245SIGNAL) {
2880
         ast_cli(a->fd, "%s\n", "h245signal");
3019
			ast_cli(a->fd, "%s\n", "h245signal");
2881
		else if (peer->dtmfmode & H323_DTMF_INBAND && peer->dtmfmode & H323_DTMF_INBANDRELAX)
3020
		} else if (peer->dtmfmode & H323_DTMF_INBAND && peer->dtmfmode & H323_DTMF_INBANDRELAX) {
2882
         ast_cli(a->fd, "%s\n", "inband-relaxed");
3021
			ast_cli(a->fd, "%s\n", "inband-relaxed");
2883
		else if (peer->dtmfmode & H323_DTMF_INBAND)
3022
		} else if (peer->dtmfmode & H323_DTMF_INBAND) {
2884
         ast_cli(a->fd, "%s\n", "inband");
3023
			ast_cli(a->fd, "%s\n", "inband");
2885
		else
3024
		} else {
2886
         ast_cli(a->fd, "%s\n", "unknown");
3025
			ast_cli(a->fd, "%s\n", "unknown");
3026
		}
3027
		ast_cli(a->fd,"%-15s", "T.38 Mode: ");
3028
		if (peer->t38support == T38_DISABLED) {
3029
			ast_cli(a->fd, "%s\n", "disabled");
3030
		} else if (peer->t38support == T38_FAXGW) {
3031
			ast_cli(a->fd, "%s\n", "faxgw/chan_sip compatible");
3032
		}
3033
		if (peer->faxdetect == (FAXDETECT_CNG | FAXDETECT_T38)) {
3034
			ast_cli(a->fd,"%-20s%s\n", "FAX Detect:", "Yes");
3035
		} else if (peer->faxdetect & FAXDETECT_CNG) {
3036
			ast_cli(a->fd,"%-20s%s\n", "FAX Detect:", "Cng");
3037
		} else if (peer->faxdetect & FAXDETECT_T38) {
3038
			ast_cli(a->fd,"%-20s%s\n", "FAX Detect:", "T.38");
3039
		} else {
3040
			ast_cli(a->fd,"%-20s%s\n", "FAX Detect:", "No");
3041
		}
2887
3042
2888
	ast_cli(a->fd,"%-15s", "T.38 Mode: ");
3043
		ast_cli(a->fd, "%-15.15s%s\n", "AccountCode: ", peer->accountcode);
2889
	if (peer->t38support == T38_DISABLED)
3044
		ast_cli(a->fd, "%-15.15s%s\n", "AMA flags: ", ast_cdr_flags2str(peer->amaflags));
2890
		ast_cli(a->fd, "%s\n", "disabled");
3045
		ast_cli(a->fd, "%-15.15s%s\n", "IP:Port: ", ip_port);
2891
	else if (peer->t38support == T38_FAXGW)
3046
		ast_cli(a->fd, "%-15.15s%d\n", "OutgoingLimit: ", peer->outgoinglimit);
2892
		ast_cli(a->fd, "%s\n", "faxgw/chan_sip compatible");
3047
		ast_cli(a->fd, "%-15.15s%d\n", "rtptimeout: ", peer->rtptimeout);
2893
3048
		if (peer->rtpmaskstr[0]) {
2894
	ast_cli(a->fd, "%-15.15s%s\n", "AccountCode: ", peer->accountcode);
3049
			ast_cli(a->fd, "%-15.15s%s\n", "rtpmask: ", peer->rtpmaskstr);
2895
	ast_cli(a->fd, "%-15.15s%s\n", "AMA flags: ", 
3050
		}
2896
		ast_cdr_flags2str(peer->amaflags));
3051
		if (peer->rtdrcount && peer->rtdrinterval) {
2897
	ast_cli(a->fd, "%-15.15s%s\n", "IP:Port: ", ip_port);
3052
			ast_cli(a->fd, "%-15.15s%d,%d\n", "RoundTrip: ", peer->rtdrcount, peer->rtdrinterval);
2898
	ast_cli(a->fd, "%-15.15s%d\n", "OutgoingLimit: ", peer->outgoinglimit);
3053
		}
2899
	ast_cli(a->fd, "%-15.15s%d\n", "rtptimeout: ", peer->rtptimeout);
3054
		ast_mutex_unlock(&peer->lock);
2900
	if (peer->rtpmaskstr[0])
2901
		ast_cli(a->fd, "%-15.15s%s\n", "rtpmask: ", peer->rtpmaskstr);
2902
	if (peer->rtdrcount && peer->rtdrinterval) 
2903
		ast_cli(a->fd, "%-15.15s%d,%d\n", "RoundTrip: ", peer->rtdrcount, peer->rtdrinterval);
2904
	ast_mutex_unlock(&peer->lock);
2905
	} else {
3055
	} else {
2906
	ast_cli(a->fd, "Peer %s not found\n", a->argv[3]);
3056
		ast_cli(a->fd, "Peer %s not found\n", a->argv[3]);
2907
	ast_cli(a->fd, "\n");
3057
		ast_cli(a->fd, "\n");
2908
	}
3058
	}
2909
	ast_mutex_unlock(&peerl.lock);
3059
	ast_mutex_unlock(&peerl.lock);
2910
3060
Lines 2994-3002 Link Here
2994
	user = userl.users;
3144
	user = userl.users;
2995
	while (user) {
3145
	while (user) {
2996
		ast_mutex_lock(&user->lock);
3146
		ast_mutex_lock(&user->lock);
2997
      if(!strcmp(user->name, a->argv[3])) {
3147
		if (!strcmp(user->name, a->argv[3])) {
2998
			break;
3148
			break;
2999
      } else {
3149
		} else {
3000
			prev = user;
3150
			prev = user;
3001
			user = user->next;
3151
			user = user->next;
3002
			ast_mutex_unlock(&prev->lock);
3152
			ast_mutex_unlock(&prev->lock);
Lines 3004-3056 Link Here
3004
	}
3154
	}
3005
3155
3006
	if (user) {
3156
	if (user) {
3007
      ast_cli(a->fd, "%-15.15s%s\n", "Name: ", user->name);
3157
		ast_cli(a->fd, "%-15.15s%s\n", "Name: ", user->name);
3008
      ast_cli(a->fd, "%s:%s,%s\n", "FastStart/H.245 Tunneling", user->faststart?"yes":"no",
3158
		ast_cli(a->fd, "%s:%s,%s\n", "FastStart/H.245 Tunneling", user->faststart?"yes":"no",
3009
					user->h245tunneling?"yes":"no");
3159
					user->h245tunneling?"yes":"no");
3010
      ast_cli(a->fd, "%-15.15s%s", "Format Prefs: ", "(");
3160
		ast_cli(a->fd, "%-15.15s%s", "Format Prefs: ", "(");
3011
      print_codec_to_cli(a->fd, &user->prefs);
3161
		print_codec_to_cli(a->fd, &user->prefs);
3012
      ast_cli(a->fd, ")\n");
3162
		ast_cli(a->fd, ")\n");
3013
      ast_cli(a->fd, "%-15.15s", "DTMF Mode: ");
3163
		ast_cli(a->fd, "%-15.15s", "DTMF Mode: ");
3014
		if (user->dtmfmode & H323_DTMF_CISCO) {
3164
		if (user->dtmfmode & H323_DTMF_CISCO) {
3015
         ast_cli(a->fd, "%s\n", "cisco");
3165
			ast_cli(a->fd, "%s\n", "cisco");
3016
	 ast_cli(a->fd, "%-15.15s%d\n", "DTMF Codec: ", user->dtmfcodec);
3166
			ast_cli(a->fd, "%-15.15s%d\n", "DTMF Codec: ", user->dtmfcodec);
3017
		} else if (user->dtmfmode & H323_DTMF_RFC2833) {
3167
		} else if (user->dtmfmode & H323_DTMF_RFC2833) {
3018
         ast_cli(a->fd, "%s\n", "rfc2833");
3168
			ast_cli(a->fd, "%s\n", "rfc2833");
3019
	 ast_cli(a->fd, "%-15.15s%d\n", "DTMF Codec: ", user->dtmfcodec);
3169
			ast_cli(a->fd, "%-15.15s%d\n", "DTMF Codec: ", user->dtmfcodec);
3020
		} else if (user->dtmfmode & H323_DTMF_Q931)
3170
		} else if (user->dtmfmode & H323_DTMF_Q931) {
3021
         ast_cli(a->fd, "%s\n", "q931keypad");
3171
			ast_cli(a->fd, "%s\n", "q931keypad");
3022
		else if (user->dtmfmode & H323_DTMF_H245ALPHANUMERIC)
3172
		} else if (user->dtmfmode & H323_DTMF_H245ALPHANUMERIC) {
3023
         ast_cli(a->fd, "%s\n", "h245alphanumeric");
3173
			ast_cli(a->fd, "%s\n", "h245alphanumeric");
3024
		else if (user->dtmfmode & H323_DTMF_H245SIGNAL)
3174
		} else if (user->dtmfmode & H323_DTMF_H245SIGNAL) {
3025
         ast_cli(a->fd, "%s\n", "h245signal");
3175
			ast_cli(a->fd, "%s\n", "h245signal");
3026
		else if (user->dtmfmode & H323_DTMF_INBAND && user->dtmfmode & H323_DTMF_INBANDRELAX)
3176
		} else if (user->dtmfmode & H323_DTMF_INBAND && user->dtmfmode & H323_DTMF_INBANDRELAX) {
3027
         ast_cli(a->fd, "%s\n", "inband-relaxed");
3177
			ast_cli(a->fd, "%s\n", "inband-relaxed");
3028
		else if (user->dtmfmode & H323_DTMF_INBAND)
3178
		} else if (user->dtmfmode & H323_DTMF_INBAND) {
3029
         ast_cli(a->fd, "%s\n", "inband");
3179
			ast_cli(a->fd, "%s\n", "inband");
3030
		else
3180
		} else {
3031
         ast_cli(a->fd, "%s\n", "unknown");
3181
			ast_cli(a->fd, "%s\n", "unknown");
3182
		}
3183
		ast_cli(a->fd,"%-15s", "T.38 Mode: ");
3184
		if (user->t38support == T38_DISABLED) {
3185
			ast_cli(a->fd, "%s\n", "disabled");
3186
		} else if (user->t38support == T38_FAXGW) {
3187
			ast_cli(a->fd, "%s\n", "faxgw/chan_sip compatible");
3188
		}
3189
		if (user->faxdetect == (FAXDETECT_CNG | FAXDETECT_T38)) {
3190
			ast_cli(a->fd,"%-20s%s\n", "FAX Detect:", "Yes");
3191
		} else if (user->faxdetect & FAXDETECT_CNG) {
3192
			ast_cli(a->fd,"%-20s%s\n", "FAX Detect:", "Cng");
3193
		} else if (user->faxdetect & FAXDETECT_T38) {
3194
			ast_cli(a->fd,"%-20s%s\n", "FAX Detect:", "T.38");
3195
		} else {
3196
			ast_cli(a->fd,"%-20s%s\n", "FAX Detect:", "No");
3197
		}
3032
3198
3033
   	ast_cli(a->fd,"%-15s", "T.38 Mode: ");
3199
		ast_cli(a->fd, "%-15.15s%s\n", "AccountCode: ", user->accountcode);
3034
	if (user->t38support == T38_DISABLED)
3200
		ast_cli(a->fd, "%-15.15s%s\n", "AMA flags: ", ast_cdr_flags2str(user->amaflags));
3035
		ast_cli(a->fd, "%s\n", "disabled");
3201
		ast_cli(a->fd, "%-15.15s%s\n", "Context: ", user->context);
3036
	else if (user->t38support == T38_FAXGW)
3202
		ast_cli(a->fd, "%-15.15s%d\n", "IncomingLimit: ", user->incominglimit);
3037
		ast_cli(a->fd, "%s\n", "faxgw/chan_sip compatible");
3203
		ast_cli(a->fd, "%-15.15s%d\n", "InUse: ", user->inUse);
3038
3204
		ast_cli(a->fd, "%-15.15s%d\n", "rtptimeout: ", user->rtptimeout);
3039
      ast_cli(a->fd, "%-15.15s%s\n", "AccountCode: ", user->accountcode);
3205
		if (user->rtpmaskstr[0]) {
3040
      ast_cli(a->fd, "%-15.15s%s\n", "AMA flags: ", 
3206
			ast_cli(a->fd, "%-15.15s%s\n", "rtpmask: ", user->rtpmaskstr);
3041
                                            ast_cdr_flags2str(user->amaflags));
3207
		}
3042
      ast_cli(a->fd, "%-15.15s%s\n", "Context: ", user->context);
3043
      ast_cli(a->fd, "%-15.15s%d\n", "IncomingLimit: ", user->incominglimit);
3044
      ast_cli(a->fd, "%-15.15s%d\n", "InUse: ", user->inUse);
3045
      ast_cli(a->fd, "%-15.15s%d\n", "rtptimeout: ", user->rtptimeout);
3046
	if (user->rtpmaskstr[0])
3047
		ast_cli(a->fd, "%-15.15s%s\n", "rtpmask: ", user->rtpmaskstr);
3048
		ast_mutex_unlock(&user->lock);
3208
		ast_mutex_unlock(&user->lock);
3049
	if (user->rtdrcount && user->rtdrinterval) 
3209
		if (user->rtdrcount && user->rtdrinterval) {
3050
		ast_cli(a->fd, "%-15.15s%d,%d\n", "RoundTrip: ", user->rtdrcount, user->rtdrinterval);
3210
			ast_cli(a->fd, "%-15.15s%d,%d\n", "RoundTrip: ", user->rtdrcount, user->rtdrinterval);
3211
		}
3051
	} else {
3212
	} else {
3052
     ast_cli(a->fd, "User %s not found\n", a->argv[3]);
3213
		ast_cli(a->fd, "User %s not found\n", a->argv[3]);
3053
     ast_cli(a->fd, "\n");
3214
		ast_cli(a->fd, "\n");
3054
	}
3215
	}
3055
	ast_mutex_unlock(&userl.lock);
3216
	ast_mutex_unlock(&userl.lock);
3056
3217
Lines 3149-3239 Link Here
3149
	if (a->argc != 3)
3310
	if (a->argc != 3)
3150
		return CLI_SHOWUSAGE;
3311
		return CLI_SHOWUSAGE;
3151
3312
3152
3313
	ast_cli(a->fd, "\nObjective Open H.323 Channel Driver's Config:\n");
3153
3154
   ast_cli(a->fd, "\nObjective Open H.323 Channel Driver's Config:\n");
3155
	snprintf(value, sizeof(value), "%s:%d", gIP, gPort);
3314
	snprintf(value, sizeof(value), "%s:%d", gIP, gPort);
3156
   ast_cli(a->fd, "%-20s%s\n", "IP:Port: ", value);
3315
	ast_cli(a->fd, "%-20s%s\n", "IP:Port: ", value);
3157
   ast_cli(a->fd, "%-20s%d-%d\n", "H.225 port range: ", 
3316
	ast_cli(a->fd, "%-20s%d-%d\n", "H.225 port range: ", ooconfig.mTCPPortStart, ooconfig.mTCPPortEnd);
3158
      ooconfig.mTCPPortStart, ooconfig.mTCPPortEnd);
3317
	ast_cli(a->fd, "%-20s%s\n", "FastStart", gFastStart?"yes":"no");
3159
   ast_cli(a->fd, "%-20s%s\n", "FastStart", gFastStart?"yes":"no");
3318
	ast_cli(a->fd, "%-20s%s\n", "Tunneling", gTunneling?"yes":"no");
3160
   ast_cli(a->fd, "%-20s%s\n", "Tunneling", gTunneling?"yes":"no");
3319
	ast_cli(a->fd, "%-20s%s\n", "CallerId", gCallerID);
3161
   ast_cli(a->fd, "%-20s%s\n", "CallerId", gCallerID);
3320
	ast_cli(a->fd, "%-20s%s\n", "MediaWaitForConnect", gMediaWaitForConnect?"yes":"no");
3162
   ast_cli(a->fd, "%-20s%s\n", "MediaWaitForConnect", 
3163
      gMediaWaitForConnect?"yes":"no");
3164
3321
3165
#if (0)
3322
#if (0)
3166
		extern OOH323EndPoint gH323ep;
3323
		extern OOH323EndPoint gH323ep;
3167
   ast_cli(a->fd, "%-20s%s\n", "FASTSTART", 
3324
	ast_cli(a->fd, "%-20s%s\n", "FASTSTART",
3168
			(OO_TESTFLAG(gH323ep.flags, OO_M_FASTSTART) != 0) ? "yes" : "no");
3325
		(OO_TESTFLAG(gH323ep.flags, OO_M_FASTSTART) != 0) ? "yes" : "no");
3169
   ast_cli(a->fd, "%-20s%s\n", "TUNNELING", 
3326
	ast_cli(a->fd, "%-20s%s\n", "TUNNELING",
3170
			(OO_TESTFLAG(gH323ep.flags, OO_M_TUNNELING) != 0) ? "yes" : "no");
3327
		(OO_TESTFLAG(gH323ep.flags, OO_M_TUNNELING) != 0) ? "yes" : "no");
3171
   ast_cli(a->fd, "%-20s%s\n", "MEDIAWAITFORCONN",
3328
	ast_cli(a->fd, "%-20s%s\n", "MEDIAWAITFORCONN",
3172
			(OO_TESTFLAG(gH323ep.flags, OO_M_MEDIAWAITFORCONN) != 0) ? "yes" : "no");
3329
		(OO_TESTFLAG(gH323ep.flags, OO_M_MEDIAWAITFORCONN) != 0) ? "yes" : "no");
3173
#endif
3330
#endif
3174
3331
3175
	if (gRasGkMode == RasNoGatekeeper)
3332
	if (gRasGkMode == RasNoGatekeeper) {
3176
		snprintf(value, sizeof(value), "%s", "No Gatekeeper");
3333
		snprintf(value, sizeof(value), "%s", "No Gatekeeper");
3177
	else if (gRasGkMode == RasDiscoverGatekeeper)
3334
	} else if (gRasGkMode == RasDiscoverGatekeeper) {
3178
		snprintf(value, sizeof(value), "%s", "Discover");
3335
		snprintf(value, sizeof(value), "%s", "Discover");
3179
	else
3336
	} else {
3180
		snprintf(value, sizeof(value), "%s", gGatekeeper);
3337
		snprintf(value, sizeof(value), "%s", gGatekeeper);
3181
3338
	}
3182
   ast_cli(a->fd,  "%-20s%s\n", "Gatekeeper:", value);
3339
	ast_cli(a->fd,  "%-20s%s\n", "Gatekeeper:", value);
3183
3340
	ast_cli(a->fd,  "%-20s%s\n", "H.323 LogFile:", gLogFile);
3184
   ast_cli(a->fd,  "%-20s%s\n", "H.323 LogFile:", gLogFile);   
3341
	ast_cli(a->fd,  "%-20s%s\n", "Context:", gContext);
3185
3342
	ast_cli(a->fd,  "%-20s%s\n", "Capability:",
3186
   ast_cli(a->fd,  "%-20s%s\n", "Context:", gContext);
3343
		ast_getformatname_multiple(value,FORMAT_STRING_SIZE,gCapability));
3187
   
3344
	ast_cli(a->fd, "%-20s", "DTMF Mode: ");
3188
   ast_cli(a->fd,  "%-20s%s\n", "Capability:", 
3189
           ast_getformatname_multiple(value,FORMAT_STRING_SIZE,gCapability));
3190
3191
   ast_cli(a->fd, "%-20s", "DTMF Mode: ");
3192
	if (gDTMFMode & H323_DTMF_CISCO) {
3345
	if (gDTMFMode & H323_DTMF_CISCO) {
3193
      ast_cli(a->fd, "%s\n", "cisco");
3346
		ast_cli(a->fd, "%s\n", "cisco");
3194
      ast_cli(a->fd, "%-15.15s%d\n", "DTMF Codec: ", gDTMFCodec);
3347
		ast_cli(a->fd, "%-20.15s%d\n", "DTMF Codec: ", gDTMFCodec);
3195
	} else if (gDTMFMode & H323_DTMF_RFC2833) {
3348
	} else if (gDTMFMode & H323_DTMF_RFC2833) {
3196
      ast_cli(a->fd, "%s\n", "rfc2833");
3349
		ast_cli(a->fd, "%s\n", "rfc2833");
3197
      ast_cli(a->fd, "%-15.15s%d\n", "DTMF Codec: ", gDTMFCodec);
3350
		ast_cli(a->fd, "%-20.15s%d\n", "DTMF Codec: ", gDTMFCodec);
3198
	} else if (gDTMFMode & H323_DTMF_Q931)
3351
	} else if (gDTMFMode & H323_DTMF_Q931) {
3199
      ast_cli(a->fd, "%s\n", "q931keypad");
3352
		ast_cli(a->fd, "%s\n", "q931keypad");
3200
	else if (gDTMFMode & H323_DTMF_H245ALPHANUMERIC)
3353
	} else if (gDTMFMode & H323_DTMF_H245ALPHANUMERIC) {
3201
      ast_cli(a->fd, "%s\n", "h245alphanumeric");
3354
		ast_cli(a->fd, "%s\n", "h245alphanumeric");
3202
	else if (gDTMFMode & H323_DTMF_H245SIGNAL)
3355
	} else if (gDTMFMode & H323_DTMF_H245SIGNAL) {
3203
      ast_cli(a->fd, "%s\n", "h245signal");
3356
		ast_cli(a->fd, "%s\n", "h245signal");
3204
		else if (gDTMFMode & H323_DTMF_INBAND && gDTMFMode & H323_DTMF_INBANDRELAX)
3357
	} else if (gDTMFMode & H323_DTMF_INBAND && gDTMFMode & H323_DTMF_INBANDRELAX) {
3205
         ast_cli(a->fd, "%s\n", "inband-relaxed");
3358
		ast_cli(a->fd, "%s\n", "inband-relaxed");
3206
		else if (gDTMFMode & H323_DTMF_INBAND)
3359
	} else if (gDTMFMode & H323_DTMF_INBAND) {
3207
         ast_cli(a->fd, "%s\n", "inband");
3360
		ast_cli(a->fd, "%s\n", "inband");
3208
	else
3361
	} else {
3209
		ast_cli(a->fd, "%s\n", "unknown");
3362
		ast_cli(a->fd, "%s\n", "unknown");
3363
	}
3210
3364
3211
   	ast_cli(a->fd,"%-20s", "T.38 Mode: ");
3365
	ast_cli(a->fd,"%-20s", "T.38 Mode: ");
3212
	if (gT38Support == T38_DISABLED)
3366
	if (gT38Support == T38_DISABLED) {
3213
		ast_cli(a->fd, "%s\n", "disabled");
3367
		ast_cli(a->fd, "%s\n", "disabled");
3214
	else if (gT38Support == T38_FAXGW)
3368
	} else if (gT38Support == T38_FAXGW) {
3215
		ast_cli(a->fd, "%s\n", "faxgw/chan_sip compatible");
3369
		ast_cli(a->fd, "%s\n", "faxgw/chan_sip compatible");
3370
	}
3371
	if (gFAXdetect == (FAXDETECT_CNG | FAXDETECT_T38)) {
3372
		ast_cli(a->fd,"%-20s%s\n", "FAX Detect:", "Yes");
3373
	} else if (gFAXdetect & FAXDETECT_CNG) {
3374
		ast_cli(a->fd,"%-20s%s\n", "FAX Detect:", "Cng");
3375
	} else if (gFAXdetect & FAXDETECT_T38) {
3376
		ast_cli(a->fd,"%-20s%s\n", "FAX Detect:", "T.38");
3377
	} else {
3378
		ast_cli(a->fd,"%-20s%s\n", "FAX Detect:", "No");
3379
	}
3216
3380
3217
	if (gRTDRCount && gRTDRInterval)
3381
	if (gRTDRCount && gRTDRInterval) {
3218
		ast_cli(a->fd, "%-15.15s%d,%d\n", "RoundTrip: ", gRTDRCount, gRTDRInterval);
3382
		ast_cli(a->fd, "%-20.15s%d,%d\n", "RoundTrip: ", gRTDRCount, gRTDRInterval);
3383
	}
3219
3384
3220
   ast_cli(a->fd, "%-20s%ld\n", "Call counter: ", callnumber);
3385
	ast_cli(a->fd, "%-20s%ld\n", "Call counter: ", callnumber);
3221
   ast_cli(a->fd, "%-20s%s\n", "AccountCode: ", gAccountcode);
3386
	ast_cli(a->fd, "%-20s%s\n", "AccountCode: ", gAccountcode);
3387
	ast_cli(a->fd, "%-20s%s\n", "AMA flags: ", ast_cdr_flags2str(gAMAFLAGS));
3222
3388
3223
   ast_cli(a->fd, "%-20s%s\n", "AMA flags: ", ast_cdr_flags2str(gAMAFLAGS));
3224
3225
	pAlias = gAliasList;
3389
	pAlias = gAliasList;
3226
   if(pAlias) {
3390
	if(pAlias) {
3227
     ast_cli(a->fd, "%-20s\n", "Aliases: ");
3391
		ast_cli(a->fd, "%-20s\n", "Aliases: ");
3228
   }
3392
	}
3229
	while (pAlias) {
3393
	while (pAlias) {
3230
		pAliasNext = pAlias->next;
3394
		pAliasNext = pAlias->next;
3231
		if (pAliasNext) {
3395
		if (pAliasNext) {
3232
         ast_cli(a->fd,"\t%-30s\t%-30s\n",pAlias->value, pAliasNext->value);
3396
			ast_cli(a->fd,"\t%-30s\t%-30s\n",pAlias->value, pAliasNext->value);
3233
			pAlias = pAliasNext->next;
3397
			pAlias = pAliasNext->next;
3234
      }
3398
		} else {
3235
      else{
3399
			ast_cli(a->fd,"\t%-30s\n",pAlias->value);
3236
         ast_cli(a->fd,"\t%-30s\n",pAlias->value);
3237
			pAlias = pAlias->next;
3400
			pAlias = pAlias->next;
3238
		}
3401
		}
3239
	}
3402
	}
Lines 3250-3256 Link Here
3250
        AST_CLI_DEFINE(handle_cli_ooh323_reload, "reload ooh323 config")
3413
        AST_CLI_DEFINE(handle_cli_ooh323_reload, "reload ooh323 config")
3251
};
3414
};
3252
3415
3416
/*! \brief OOH323 Dialplan function - reads ooh323 settings */
3417
static int function_ooh323_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
3418
{
3419
	struct ooh323_pvt *p = chan->tech_pvt;
3253
3420
3421
	ast_channel_lock(chan);
3422
	if (!p) {
3423
		ast_channel_unlock(chan);
3424
		return -1;
3425
	}
3426
3427
	if (strcmp(chan->tech->type, "OOH323")) {
3428
		ast_log(LOG_ERROR, "This function is only supported on OOH323 channels, Channel is %s\n", chan->tech->type);
3429
		ast_channel_unlock(chan);
3430
		return -1;
3431
	}
3432
3433
	ast_mutex_lock(&p->lock);
3434
	if (!strcasecmp(data, "faxdetect")) {
3435
		ast_copy_string(buf, p->faxdetect ? "1" : "0", len);
3436
	} else if (!strcasecmp(data, "t38support")) {
3437
		ast_copy_string(buf, p->t38support ? "1" : "0", len);
3438
	} else if (!strcasecmp(data, "caller_h323id")) {
3439
		ast_copy_string(buf, p->caller_h323id, len);
3440
	} else if (!strcasecmp(data, "caller_dialeddigits")) {
3441
		ast_copy_string(buf, p->caller_dialedDigits, len);
3442
	} else if (!strcasecmp(data, "caller_email")) {
3443
		ast_copy_string(buf, p->caller_email, len);
3444
	} else if (!strcasecmp(data, "h323id_url")) {
3445
		ast_copy_string(buf, p->caller_url, len);
3446
	} else if (!strcasecmp(data, "callee_h323id")) {
3447
		ast_copy_string(buf, p->callee_h323id, len);
3448
	} else if (!strcasecmp(data, "callee_dialeddigits")) {
3449
		ast_copy_string(buf, p->callee_dialedDigits, len);
3450
	} else if (!strcasecmp(data, "callee_email")) {
3451
		ast_copy_string(buf, p->callee_email, len);
3452
	} else if (!strcasecmp(data, "callee_url")) {
3453
		ast_copy_string(buf, p->callee_url, len);
3454
	}
3455
	ast_mutex_unlock(&p->lock);
3456
3457
	ast_channel_unlock(chan);
3458
	return 0;
3459
}
3460
3461
/*! \brief OOH323 Dialplan function - writes ooh323 settings */
3462
static int function_ooh323_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
3463
{
3464
	struct ooh323_pvt *p = chan->tech_pvt;
3465
	int res = -1;
3466
3467
	ast_channel_lock(chan);
3468
	if (!p) {
3469
		ast_channel_unlock(chan);
3470
		return -1;
3471
	}
3472
3473
	if (strcmp(chan->tech->type, "OOH323")) {
3474
		ast_log(LOG_ERROR, "This function is only supported on OOH323 channels, Channel is %s\n", chan->tech->type);
3475
		ast_channel_unlock(chan);
3476
		return -1;
3477
	}
3478
3479
	ast_mutex_lock(&p->lock);
3480
	if (!strcasecmp(data, "faxdetect")) {
3481
		if (ast_true(value)) {
3482
			p->faxdetect = 1;
3483
			res = 0;
3484
		} else if (ast_false(value)) {
3485
			p->faxdetect = 0;
3486
			res = 0;
3487
		} else {
3488
			char *buf = ast_strdupa(value);
3489
			char *word, *next = buf;
3490
			p->faxdetect = 0;
3491
			res = 0;
3492
			while ((word = strsep(&next, ","))) {
3493
				if (!strcasecmp(word, "cng")) {
3494
					p->faxdetect |= FAXDETECT_CNG;
3495
				} else if (!strcasecmp(word, "t38")) {
3496
					p->faxdetect |= FAXDETECT_T38;
3497
				} else {
3498
					ast_log(LOG_WARNING, "Unknown faxdetect mode '%s'.\n", word);
3499
					res = -1;
3500
				}
3501
			}
3502
3503
		}
3504
	} else if (!strcasecmp(data, "t38support")) {
3505
		if (ast_true(value)) {
3506
			p->t38support = 1;
3507
			res = 0;
3508
		} else {
3509
			p->t38support = 0;
3510
			res = 0;
3511
		}
3512
	}
3513
	ast_mutex_unlock(&p->lock);
3514
	ast_channel_unlock(chan);
3515
3516
	return res;
3517
}
3518
3519
/*! \brief Structure to declare a dialplan function: OOH323 */
3520
static struct ast_custom_function ooh323_function = {
3521
        .name = "OOH323",
3522
        .read = function_ooh323_read,
3523
        .write = function_ooh323_write,
3524
};
3525
3254
static int load_module(void)
3526
static int load_module(void)
3255
{
3527
{
3256
	int res;
3528
	int res;
Lines 3407-3412 Link Here
3407
		restart_monitor();
3679
		restart_monitor();
3408
	}
3680
	}
3409
3681
3682
	/* Register dialplan functions */
3683
	ast_custom_function_register(&ooh323_function);
3684
3410
	return 0;
3685
	return 0;
3411
}
3686
}
3412
3687
Lines 3681-3687 Link Here
3681
	ast_mutex_unlock(&userl.lock);
3956
	ast_mutex_unlock(&userl.lock);
3682
	return 0;
3957
	return 0;
3683
}
3958
}
3684
  
3959
3685
static int unload_module(void)
3960
static int unload_module(void)
3686
{
3961
{
3687
	struct ooh323_pvt *p;
3962
	struct ooh323_pvt *p;
Lines 3796-3803 Link Here
3796
	}
4071
	}
3797
	ooH323EpDestroy();
4072
	ooH323EpDestroy();
3798
4073
4074
	/* Unregister dial plan functions */
4075
	ast_custom_function_unregister(&ooh323_function);
4076
3799
	if (gH323Debug) {
4077
	if (gH323Debug) {
3800
		ast_verbose("+++ ooh323  unload_module \n");	
4078
		ast_verbose("+++ ooh323  unload_module \n");
3801
	}
4079
	}
3802
4080
3803
	return 0;
4081
	return 0;
Lines 4262-4267 Link Here
4262
{
4540
{
4263
	/* Retrieve audio/etc from channel.  Assumes p->lock is already held. */
4541
	/* Retrieve audio/etc from channel.  Assumes p->lock is already held. */
4264
	struct ast_frame *f;
4542
	struct ast_frame *f;
4543
	struct ast_frame *dfr = NULL;
4265
	static struct ast_frame null_frame = { AST_FRAME_NULL, };
4544
	static struct ast_frame null_frame = { AST_FRAME_NULL, };
4266
	switch (ast->fdno) {
4545
	switch (ast->fdno) {
4267
	case 0:
4546
	case 0:
Lines 4286-4310 Link Here
4286
		f = &null_frame;
4565
		f = &null_frame;
4287
	}
4566
	}
4288
4567
4289
	if (p->owner) {
4568
	if (p->owner && !p->faxmode && (f->frametype == AST_FRAME_VOICE)) {
4290
		/* We already hold the channel lock */
4569
		/* We already hold the channel lock */
4291
		if (f->frametype == AST_FRAME_VOICE && !p->faxmode) {
4570
		if (f->subclass.codec != p->owner->nativeformats) {
4292
			if (f->subclass.codec != p->owner->nativeformats) {
4571
			ast_debug(1, "Oooh, voice format changed to %s\n", ast_getformatname(f->subclass.codec));
4293
            			ast_debug(1, "Oooh, voice format changed to %s\n", ast_getformatname(f->subclass.codec));
4572
			p->owner->nativeformats = f->subclass.codec;
4294
				p->owner->nativeformats = f->subclass.codec;
4573
			ast_set_read_format(p->owner, p->owner->readformat);
4295
				ast_set_read_format(p->owner, p->owner->readformat);
4574
			ast_set_write_format(p->owner, p->owner->writeformat);
4296
				ast_set_write_format(p->owner, p->owner->writeformat);
4575
		}
4297
			}
4576
		if (((p->dtmfmode & H323_DTMF_INBAND) || (p->faxdetect && FAXDETECT_CNG)) && p->vad &&
4577
		    (f->subclass.codec == AST_FORMAT_SLINEAR || f->subclass.codec == AST_FORMAT_ALAW ||
4578
		     f->subclass.codec == AST_FORMAT_ULAW)) {
4579
			dfr = ast_frdup(f);
4580
			dfr = ast_dsp_process(p->owner, p->vad, dfr);
4581
		}
4582
	} else {
4583
		return f;
4584
	}
4298
4585
4299
			if ((p->dtmfmode & H323_DTMF_INBAND) && p->vad &&
4586
	/* process INBAND DTMF*/
4300
				(f->subclass.codec == AST_FORMAT_SLINEAR || f->subclass.codec == AST_FORMAT_ALAW ||
4587
	if (dfr && (dfr->frametype == AST_FRAME_DTMF) && ((dfr->subclass.integer == 'f') || (dfr->subclass.integer == 'e'))) {
4301
					f->subclass.codec == AST_FORMAT_ULAW)) {
4588
		ast_debug(1, "* Detected FAX Tone %s\n", (dfr->subclass.integer == 'e') ? "CED" : "CNG");
4302
				f = ast_dsp_process(p->owner, p->vad, f);
4589
		/* Switch to T.38 ON CED*/
4303
            			if (f && (f->frametype == AST_FRAME_DTMF)) 
4590
		if (!p->faxmode && !p->chmodepend && (dfr->subclass.integer == 'e') && (p->t38support != T38_DISABLED)) {
4304
               				ast_debug(1, "* Detected inband DTMF '%c'\n", f->subclass.integer);
4591
			if (gH323Debug)
4592
				ast_verbose("request to change %s to t.38 because fax ced\n", p->callToken);
4593
			p->chmodepend = 1;
4594
			p->faxdetected = 1;
4595
			ooRequestChangeMode(p->callToken, 1);
4596
		} else if ((dfr->subclass.integer == 'f') && !p->faxdetected) {
4597
			const char *target_context = S_OR(p->owner->macrocontext, p->owner->context);
4598
			if ((strcmp(p->owner->exten, "fax")) &&
4599
			    (ast_exists_extension(p->owner, target_context, "fax", 1,
4600
		            S_COR(p->owner->caller.id.number.valid, p->owner->caller.id.number.str, NULL)))) {
4601
				ast_verb(2, "Redirecting '%s' to fax extension due to CNG detection\n", p->owner->name);
4602
				pbx_builtin_setvar_helper(p->owner, "FAXEXTEN", p->owner->exten);
4603
				if (ast_async_goto(p->owner, target_context, "fax", 1)) {
4604
					ast_log(LOG_NOTICE, "Failed to async goto '%s' into fax of '%s'\n", p->owner->name,target_context);
4605
				}
4606
				p->faxdetected = 1;
4607
				if (dfr) {
4608
					ast_frfree(dfr);
4609
				}
4610
				return &ast_null_frame;
4305
			}
4611
			}
4306
		}
4612
		}
4613
	} else if (dfr && dfr->frametype == AST_FRAME_DTMF) {
4614
		ast_debug(1, "* Detected inband DTMF '%c'\n", f->subclass.integer);
4615
		ast_frfree(f);
4616
		return dfr;
4307
	}
4617
	}
4618
4619
	if (dfr) {
4620
		ast_frfree(dfr);
4621
	}
4308
	return f;
4622
	return f;
4309
}
4623
}
4310
4624
Lines 4326-4331 Link Here
4326
		if (gH323Debug)
4640
		if (gH323Debug)
4327
			ast_debug(1, "mode for %s is already %d\n", call->callToken,
4641
			ast_debug(1, "mode for %s is already %d\n", call->callToken,
4328
					t38mode);
4642
					t38mode);
4643
		p->chmodepend = 0;
4329
		ast_mutex_unlock(&p->lock);
4644
		ast_mutex_unlock(&p->lock);
4330
		return;
4645
		return;
4331
	}
4646
	}
Lines 4336-4346 Link Here
4336
			DEADLOCK_AVOIDANCE(&p->lock);
4651
			DEADLOCK_AVOIDANCE(&p->lock);
4337
		}
4652
		}
4338
		if (!p->owner) {
4653
		if (!p->owner) {
4654
			p->chmodepend = 0;
4339
			ast_mutex_unlock(&p->lock);
4655
			ast_mutex_unlock(&p->lock);
4340
			ast_log(LOG_ERROR, "Channel has no owner\n");
4656
			ast_log(LOG_ERROR, "Channel has no owner\n");
4341
			return;
4657
			return;
4342
		}
4658
		}
4343
	} else {
4659
	} else {
4660
		p->chmodepend = 0;
4344
		ast_mutex_unlock(&p->lock);
4661
		ast_mutex_unlock(&p->lock);
4345
		ast_log(LOG_ERROR, "Channel has no owner\n");
4662
		ast_log(LOG_ERROR, "Channel has no owner\n");
4346
		return;
4663
		return;
Lines 4350-4359 Link Here
4350
4667
4351
4668
4352
		if (p->t38support == T38_ENABLED) {
4669
		if (p->t38support == T38_ENABLED) {
4670
			struct ast_control_t38_parameters parameters = { .request_response = 0 };
4353
4671
4672
			if ((p->faxdetect & FAXDETECT_T38) && !p->faxdetected) {
4673
                       		const char *target_context;
4674
				ast_debug(1, "* Detected T.38 Request\n");
4675
				target_context = S_OR(p->owner->macrocontext, p->owner->context);
4676
                        	if ((strcmp(p->owner->exten, "fax")) &&
4677
                            		(ast_exists_extension(p->owner, target_context, "fax", 1,
4678
                            		S_COR(p->owner->caller.id.number.valid, p->owner->caller.id.number.str, NULL)))) {
4679
                                	ast_verb(2, "Redirecting '%s' to fax extension due to CNG detection\n", p->owner->name);
4680
                                	pbx_builtin_setvar_helper(p->owner, "FAXEXTEN", p->owner->exten);
4681
                                	if (ast_async_goto(p->owner, target_context, "fax", 1)) {
4682
                                        	ast_log(LOG_NOTICE, "Failed to async goto '%s' into fax of '%s'\n", p->owner->name,target_context);
4683
					}
4684
                                }
4685
                                p->faxdetected = 1;
4686
			}
4687
4354
/* AST_T38_CONTROL mode */
4688
/* AST_T38_CONTROL mode */
4355
4689
4356
			struct ast_control_t38_parameters parameters = { .request_response = 0 };
4357
			parameters.request_response = AST_T38_REQUEST_NEGOTIATE;
4690
			parameters.request_response = AST_T38_REQUEST_NEGOTIATE;
4358
			if (call->T38FarMaxDatagram) {
4691
			if (call->T38FarMaxDatagram) {
4359
				ast_udptl_set_far_max_datagram(p->udptl, call->T38FarMaxDatagram);
4692
				ast_udptl_set_far_max_datagram(p->udptl, call->T38FarMaxDatagram);
Lines 4369-4374 Link Here
4369
							&parameters, sizeof(parameters));
4702
							&parameters, sizeof(parameters));
4370
			p->faxmode = 1;
4703
			p->faxmode = 1;
4371
4704
4705
4372
		}
4706
		}
4373
	} else {
4707
	} else {
4374
		if (p->t38support == T38_ENABLED) {
4708
		if (p->t38support == T38_ENABLED) {
Lines 4380-4385 Link Here
4380
							&parameters, sizeof(parameters));
4714
							&parameters, sizeof(parameters));
4381
		}
4715
		}
4382
		p->faxmode = 0;
4716
		p->faxmode = 0;
4717
		p->faxdetected = 0;
4383
		p->t38_init = 0;
4718
		p->t38_init = 0;
4384
	}
4719
	}
4385
4720
(-)include/asterisk/res_fax.h (+9 lines)
Lines 42-47 Link Here
42
	AST_FAX_TECH_T38       = (1 << 3),
42
	AST_FAX_TECH_T38       = (1 << 3),
43
	/*! sending mulitple documents supported */
43
	/*! sending mulitple documents supported */
44
	AST_FAX_TECH_MULTI_DOC = (1 << 4),
44
	AST_FAX_TECH_MULTI_DOC = (1 << 4),
45
	/*! T.38 - T.30 Gateway */
46
	AST_FAX_TECH_GATEWAY = (1 << 5),
45
};
47
};
46
48
47
/*! \brief fax modem capabilities */
49
/*! \brief fax modem capabilities */
Lines 168-173 Link Here
168
	struct ast_fax_t38_parameters our_t38_parameters;
170
	struct ast_fax_t38_parameters our_t38_parameters;
169
	/*! the other endpoint's T.38 session parameters, if any */
171
	/*! the other endpoint's T.38 session parameters, if any */
170
	struct ast_fax_t38_parameters their_t38_parameters;
172
	struct ast_fax_t38_parameters their_t38_parameters;
173
	/*! the id of the t.38 gateway framehook for this channel */
174
	int gateway_id;
175
	/*! the timeout for this gateway in seconds */
176
	int gateway_timeout;
171
};
177
};
172
178
173
struct ast_fax_tech;
179
struct ast_fax_tech;
Lines 204-209 Link Here
204
	struct ast_smoother *smoother;
210
	struct ast_smoother *smoother;
205
};
211
};
206
212
213
/* if this overlaps with any AST_FRFLAG_* values, problems will occur */
214
#define AST_FAX_FRFLAG_GATEWAY (1 << 13)
215
207
/*! \brief used to register a FAX technology module with res_fax */
216
/*! \brief used to register a FAX technology module with res_fax */
208
struct ast_fax_tech {
217
struct ast_fax_tech {
209
	/*! the type of fax session supported with this ast_fax_tech structure */
218
	/*! the type of fax session supported with this ast_fax_tech structure */
(-)include/asterisk/dsp.h (-3 / +5 lines)
Lines 43-51 Link Here
43
#define DSP_FEATURE_CALL_PROGRESS	(DSP_PROGRESS_TALK | DSP_PROGRESS_RINGING | DSP_PROGRESS_BUSY | DSP_PROGRESS_CONGESTION)
43
#define DSP_FEATURE_CALL_PROGRESS	(DSP_PROGRESS_TALK | DSP_PROGRESS_RINGING | DSP_PROGRESS_BUSY | DSP_PROGRESS_CONGESTION)
44
#define DSP_FEATURE_WAITDIALTONE	(1 << 20)		/*!< Enable dial tone detection */
44
#define DSP_FEATURE_WAITDIALTONE	(1 << 20)		/*!< Enable dial tone detection */
45
45
46
#define DSP_FAXMODE_DETECT_CNG	(1 << 0)
46
#define DSP_FAXMODE_DETECT_CNG		(1 << 0)
47
#define DSP_FAXMODE_DETECT_CED	(1 << 1)
47
#define DSP_FAXMODE_DETECT_CED		(1 << 1)
48
#define DSP_FAXMODE_DETECT_ALL	(DSP_FAXMODE_DETECT_CNG | DSP_FAXMODE_DETECT_CED)
48
#define DSP_FAXMODE_DETECT_SQUELCH	(1 << 2)
49
#define DSP_FAXMODE_DETECT_V21		(1 << 3)
50
#define DSP_FAXMODE_DETECT_ALL	(DSP_FAXMODE_DETECT_CNG | DSP_FAXMODE_DETECT_CED | DSP_FAXMODE_DETECT_V21)
49
51
50
#define DSP_TONE_STATE_SILENCE  0
52
#define DSP_TONE_STATE_SILENCE  0
51
#define DSP_TONE_STATE_RINGING  1
53
#define DSP_TONE_STATE_RINGING  1
(-)main/dsp.c (-1 / +152 lines)
Lines 254-259 Link Here
254
254
255
typedef struct
255
typedef struct
256
{
256
{
257
	int block_size;
258
	goertzel_state_t tone;
259
	float energy;		/* Accumulated energy of the current block */
260
	int samples_pending;	/* Samples remain to complete the current block */
261
262
	float threshold;	/* Energy of the tone relative to energy from all other signals to consider a hit */
263
264
	int hit_count;
265
	int miss_count;
266
267
} v21_detect_state_t;
268
269
typedef struct
270
{
257
	goertzel_state_t row_out[4];
271
	goertzel_state_t row_out[4];
258
	goertzel_state_t col_out[4];
272
	goertzel_state_t col_out[4];
259
	int hits_to_begin;		/* How many successive hits needed to consider begin of a digit */
273
	int hits_to_begin;		/* How many successive hits needed to consider begin of a digit */
Lines 399-404 Link Here
399
	digit_detect_state_t digit_state;
413
	digit_detect_state_t digit_state;
400
	tone_detect_state_t cng_tone_state;
414
	tone_detect_state_t cng_tone_state;
401
	tone_detect_state_t ced_tone_state;
415
	tone_detect_state_t ced_tone_state;
416
	v21_detect_state_t v21_state;
402
};
417
};
403
418
404
static void mute_fragment(struct ast_dsp *dsp, fragment_t *fragment)
419
static void mute_fragment(struct ast_dsp *dsp, fragment_t *fragment)
Lines 471-480 Link Here
471
	ast_debug(1, "Setup tone %d Hz, %d ms, block_size=%d, hits_required=%d\n", freq, duration, s->block_size, s->hits_required);
486
	ast_debug(1, "Setup tone %d Hz, %d ms, block_size=%d, hits_required=%d\n", freq, duration, s->block_size, s->hits_required);
472
}
487
}
473
488
489
static void ast_v21_detect_init(v21_detect_state_t *s)
490
{
491
	float x;
492
	int periods_in_block;
493
494
	/* If we want to remove tone, it is important to have block size not
495
	   to exceed frame size. Otherwise by the moment tone is detected it is too late
496
	   to squelch it from previous frames. Block size is 20ms at the given sample rate.*/
497
	s->block_size = SAMPLES_IN_FRAME;
498
499
	periods_in_block = s->block_size * 1850 / SAMPLE_RATE;
500
501
	/* Make sure we will have at least 5 periods at target frequency for analisys.
502
	   This may make block larger than expected packet and will make squelching impossible
503
	   but at least we will be detecting the tone */
504
	if (periods_in_block < 5)
505
		periods_in_block = 5;
506
507
	/* Now calculate final block size. It will contain integer number of periods */
508
	s->block_size = periods_in_block * SAMPLE_RATE / 1850;
509
510
	goertzel_init(&s->tone, 1850.0, s->block_size);
511
512
	s->samples_pending = s->block_size;
513
	s->hit_count = 0;
514
	s->miss_count = 0;
515
	s->energy = 0.0;
516
517
	/* We want tone energy to be amp decibels above the rest of the signal (the noise).
518
	   According to Parseval's theorem the energy computed in time domain equals to energy
519
	   computed in frequency domain. So subtracting energy in the frequency domain (Goertzel result)
520
	   from the energy in the time domain we will get energy of the remaining signal (without the tone
521
	   we are detecting). We will be checking that
522
		10*log(Ew / (Et - Ew)) > amp
523
	   Calculate threshold so that we will be actually checking
524
		Ew > Et * threshold
525
	*/
526
527
	x = pow(10.0, 16 / 10.0);
528
	s->threshold = x / (x + 1);
529
530
	ast_debug(1, "Setup v21 detector, block_size=%d\n", s->block_size);
531
}
532
474
static void ast_fax_detect_init(struct ast_dsp *s)
533
static void ast_fax_detect_init(struct ast_dsp *s)
475
{
534
{
476
	ast_tone_detect_init(&s->cng_tone_state, FAX_TONE_CNG_FREQ, FAX_TONE_CNG_DURATION, FAX_TONE_CNG_DB);
535
	ast_tone_detect_init(&s->cng_tone_state, FAX_TONE_CNG_FREQ, FAX_TONE_CNG_DURATION, FAX_TONE_CNG_DB);
477
	ast_tone_detect_init(&s->ced_tone_state, FAX_TONE_CED_FREQ, FAX_TONE_CED_DURATION, FAX_TONE_CED_DB);
536
	ast_tone_detect_init(&s->ced_tone_state, FAX_TONE_CED_FREQ, FAX_TONE_CED_DURATION, FAX_TONE_CED_DB);
537
	ast_v21_detect_init(&s->v21_state);
538
	if (s->faxmode & DSP_FAXMODE_DETECT_SQUELCH) {
539
		s->cng_tone_state.squelch = 1;
540
		s->ced_tone_state.squelch = 1;
541
	}
478
}
542
}
479
543
480
static void ast_dtmf_detect_init (dtmf_detect_state_t *s)
544
static void ast_dtmf_detect_init (dtmf_detect_state_t *s)
Lines 521-526 Link Here
521
	}
585
	}
522
}
586
}
523
587
588
/*! \brief Detect a v21 preamble.
589
 * This code is derived from the tone_detect code and detects a pattern of 1850
590
 * Hz tone found in a v21 preamble.
591
 */
592
static int v21_detect(struct ast_dsp *dsp, v21_detect_state_t *s, int16_t *amp, int samples)
593
{
594
	float tone_energy;
595
	int i;
596
	int hit = 0;
597
	int limit;
598
	int res = 0;
599
	int16_t *ptr;
600
	int start, end;
601
602
	for (start = 0;  start < samples;  start = end) {
603
		/* Process in blocks. */
604
		limit = samples - start;
605
		if (limit > s->samples_pending) {
606
			limit = s->samples_pending;
607
		}
608
		end = start + limit;
609
610
		for (i = limit, ptr = amp ; i > 0; i--, ptr++) {
611
			/* signed 32 bit int should be enough to suqare any possible signed 16 bit value */
612
			s->energy += (int32_t) *ptr * (int32_t) *ptr;
613
614
			goertzel_sample(&s->tone, *ptr);
615
		}
616
617
		s->samples_pending -= limit;
618
619
		if (s->samples_pending) {
620
			/* Finished incomplete (last) block */
621
			break;
622
		}
623
624
		tone_energy = goertzel_result(&s->tone);
625
626
		/* Scale to make comparable */
627
		tone_energy *= 2.0;
628
		s->energy *= s->block_size;
629
630
		ast_debug(10, "v21 1850 Ew=%.2E, Et=%.2E, s/n=%10.2f\n", tone_energy, s->energy, tone_energy / (s->energy - tone_energy));
631
632
		hit = 0;
633
		if (tone_energy > s->energy * s->threshold) {
634
			ast_debug(10, "Hit! count=%d; miss_count=%d\n", s->hit_count, s->miss_count);
635
			hit = 1;
636
		}
637
638
		if (hit) {
639
			if (s->hit_count == 0 || s->miss_count == 3) {
640
				s->hit_count++;
641
			} else {
642
				s->hit_count = 0;
643
			}
644
645
			s->miss_count = 0;
646
		} else {
647
			s->miss_count++;
648
			if (s->miss_count > 3) {
649
				s->hit_count = 0;
650
			}
651
		}
652
653
		if (s->hit_count == 4) {
654
			ast_debug(1, "v21 preamble detected\n");
655
			res = 1;
656
		}
657
658
		/* Reinitialise the detector for the next block */
659
		goertzel_reset(&s->tone);
660
661
		/* Advance to the next block */
662
		s->energy = 0.0;
663
		s->samples_pending = s->block_size;
664
665
		amp += limit;
666
	}
667
668
	return res;
669
}
670
524
static int tone_detect(struct ast_dsp *dsp, tone_detect_state_t *s, int16_t *amp, int samples)
671
static int tone_detect(struct ast_dsp *dsp, tone_detect_state_t *s, int16_t *amp, int samples)
525
{
672
{
526
	float tone_energy;
673
	float tone_energy;
Lines 1385-1390 Link Here
1385
		if ((dsp->faxmode & DSP_FAXMODE_DETECT_CED) && tone_detect(dsp, &dsp->ced_tone_state, shortdata, len)) {
1532
		if ((dsp->faxmode & DSP_FAXMODE_DETECT_CED) && tone_detect(dsp, &dsp->ced_tone_state, shortdata, len)) {
1386
			fax_digit = 'e';
1533
			fax_digit = 'e';
1387
		}
1534
		}
1535
1536
		if ((dsp->faxmode & DSP_FAXMODE_DETECT_V21) && v21_detect(dsp, &dsp->v21_state, shortdata, len)) {
1537
			fax_digit = 'g';
1538
		}
1388
	}
1539
	}
1389
1540
1390
	if (dsp->features & (DSP_FEATURE_DIGIT_DETECT | DSP_FEATURE_BUSY_DETECT)) {
1541
	if (dsp->features & (DSP_FEATURE_DIGIT_DETECT | DSP_FEATURE_BUSY_DETECT)) {
Lines 1640-1648 Link Here
1640
int ast_dsp_set_faxmode(struct ast_dsp *dsp, int faxmode)
1791
int ast_dsp_set_faxmode(struct ast_dsp *dsp, int faxmode)
1641
{
1792
{
1642
	if (dsp->faxmode != faxmode) {
1793
	if (dsp->faxmode != faxmode) {
1794
		dsp->faxmode = faxmode;
1643
		ast_fax_detect_init(dsp);
1795
		ast_fax_detect_init(dsp);
1644
	}
1796
	}
1645
	dsp->faxmode = faxmode;
1646
	return 0;
1797
	return 0;
1647
}
1798
}
1648
1799
(-)main/frame.c (-2 / +2 lines)
Lines 413-419 Link Here
413
		out->samples = fr->samples;
413
		out->samples = fr->samples;
414
		out->offset = fr->offset;
414
		out->offset = fr->offset;
415
		/* Copy the timing data */
415
		/* Copy the timing data */
416
		ast_copy_flags(out, fr, AST_FRFLAG_HAS_TIMING_INFO);
416
		ast_copy_flags(out, fr, AST_FLAGS_ALL);
417
		if (ast_test_flag(fr, AST_FRFLAG_HAS_TIMING_INFO)) {
417
		if (ast_test_flag(fr, AST_FRFLAG_HAS_TIMING_INFO)) {
418
			out->ts = fr->ts;
418
			out->ts = fr->ts;
419
			out->len = fr->len;
419
			out->len = fr->len;
Lines 537-543 Link Here
537
		/* Must have space since we allocated for it */
537
		/* Must have space since we allocated for it */
538
		strcpy(src, f->src);
538
		strcpy(src, f->src);
539
	}
539
	}
540
	ast_copy_flags(out, f, AST_FRFLAG_HAS_TIMING_INFO);
540
	ast_copy_flags(out, f, AST_FLAGS_ALL);
541
	out->ts = f->ts;
541
	out->ts = f->ts;
542
	out->len = f->len;
542
	out->len = f->len;
543
	out->seqno = f->seqno;
543
	out->seqno = f->seqno;
(-)configs/chan_ooh323.conf.sample (+12 lines)
Lines 122-127 Link Here
122
;
122
;
123
;roundtrip=x,y
123
;roundtrip=x,y
124
124
125
;
126
; FAX detection will cause the OOH323 channel to jump to the 'fax' extension (if it exists)
127
; based one or more events being detected. The events that can be detected are an incoming
128
; CNG tone or an incoming T.38 RequestMode packet
129
;
130
; yes - enable both detection (CNG & T.38)
131
; no - disable both 
132
; cng - enable CNG detection (default)
133
; t38 - enable T.38 request detection
134
;
135
faxdetect = cng
136
125
; User/peer/friend definitions:
137
; User/peer/friend definitions:
126
; User config options                    Peer config options
138
; User config options                    Peer config options
127
; ------------------                     -------------------
139
; ------------------                     -------------------
(-)res/res_fax.c (-55 / +1161 lines)
Lines 5-11 Link Here
5
 *
5
 *
6
 * Dwayne M. Hubbard <dhubbard@digium.com>
6
 * Dwayne M. Hubbard <dhubbard@digium.com>
7
 * Kevin P. Fleming <kpfleming@digium.com>
7
 * Kevin P. Fleming <kpfleming@digium.com>
8
 * Matthew Nicholson <mnicholson@digium.com>
8
 *
9
 *
10
 * Initial T.38-gateway code
11
 * 2008, Daniel Ferenci <daniel.ferenci@nethemba.com>
12
 * Created by Nethemba s.r.o. http://www.nethemba.com
13
 * Sponsored by IPEX a.s. http://www.ipex.cz
14
 *
15
 * T.38-gateway integration into asterisk app_fax and rework
16
 * 2008-2011, Gregory Hinton Nietsky <gregory@distrotech.co.za>
17
 * dns Telecom http://www.dnstelecom.co.za
18
 *
19
 * Modified to make T.38-gateway compatible with Asterisk 1.6.2
20
 * 2010, Anton Verevkin <mymail@verevkin.it>
21
 * ViaNetTV http://www.vianettv.com
22
 *
23
 * Modified to make T.38-gateway work
24
 * 2010, Klaus Darilion, IPCom GmbH, www.ipcom.at
25
 *
9
 * See http://www.asterisk.org for more information about
26
 * See http://www.asterisk.org for more information about
10
 * the Asterisk project. Please do not directly contact
27
 * the Asterisk project. Please do not directly contact
11
 * any of the maintainers of this project for assistance;
28
 * any of the maintainers of this project for assistance;
Lines 27-32 Link Here
27
 *
44
 *
28
 * \author Dwayne M. Hubbard <dhubbard@digium.com>
45
 * \author Dwayne M. Hubbard <dhubbard@digium.com>
29
 * \author Kevin P. Fleming <kpfleming@digium.com>
46
 * \author Kevin P. Fleming <kpfleming@digium.com>
47
 * \author Matthew Nicholson <mnicholson@digium.com>
48
 * \author Gregory H. Nietsky  <gregory@distrotech.co.za>
30
 * 
49
 * 
31
 * A generic FAX resource module that provides SendFAX and ReceiveFAX applications.
50
 * A generic FAX resource module that provides SendFAX and ReceiveFAX applications.
32
 * This module requires FAX technology modules, like res_fax_spandsp, to register with it
51
 * This module requires FAX technology modules, like res_fax_spandsp, to register with it
Lines 62-67 Link Here
62
#include "asterisk/dsp.h"
81
#include "asterisk/dsp.h"
63
#include "asterisk/indications.h"
82
#include "asterisk/indications.h"
64
#include "asterisk/ast_version.h"
83
#include "asterisk/ast_version.h"
84
#include "asterisk/translate.h"
65
85
66
/*** DOCUMENTATION
86
/*** DOCUMENTATION
67
	<application name="ReceiveFax" language="en_US">
87
	<application name="ReceiveFax" language="en_US">
Lines 163-168 Link Here
163
					<enum name="modem">
183
					<enum name="modem">
164
						<para>R/W Modem type (v17/v27/v29).</para>
184
						<para>R/W Modem type (v17/v27/v29).</para>
165
					</enum>
185
					</enum>
186
					<enum name="gateway">
187
						<para>R/W T38 Gateway Enabled With optional fax activity timeout in seconds (yes[,gwtimeout]/no)</para>
188
					</enum>
166
					<enum name="pages">
189
					<enum name="pages">
167
						<para>R/O Number of pages transferred.</para>
190
						<para>R/O Number of pages transferred.</para>
168
					</enum>
191
					</enum>
Lines 196-205 Link Here
196
			<ref type="application">SendFax</ref>
219
			<ref type="application">SendFax</ref>
197
		</see-also>
220
		</see-also>
198
	</function>
221
	</function>
222
	<application name="WaitFAX" language="en_US">
223
		<synopsis>
224
			Generic Fax Detect CNG/T.38 (Wait For Fax)
225
		</synopsis>
226
		<syntax>
227
			<parameter name="timeout" required="true">
228
				<para>Specifies the number of seconds we attempt to detect a fax tone on the channel</para>
229
			</parameter>
230
			<parameter name="tone" required="false">
231
				<para>Either the tone name defined in the "indications.conf" configuration file,
232
				or a directly specified list of frequencies and durations.</para>
233
				<para>If not specified silence is generated.</para>
234
			</parameter>
235
			<parameter name="noise" required="false">
236
				<para>Number of ms noise detected before proceeding with the dialplan.</para>
237
			</parameter>
238
		</syntax>
239
		<description>
240
			<para>This application sets FAXOPT(status) To SUCCESS | FAILURE | ERROR</para>
241
			<para>FAXOPT(statusstr) will be set to CNG | T38 on SUCCESS or reason on FAILURE | ERROR</para>
242
		</description>
243
	</application>
199
***/
244
***/
200
245
201
static const char app_receivefax[] = "ReceiveFAX";
246
static const char app_receivefax[] = "ReceiveFAX";
202
static const char app_sendfax[] = "SendFAX";
247
static const char app_sendfax[] = "SendFAX";
248
static const char app_waitfax[] = "WaitFAX";
203
249
204
struct debug_info_history {
250
struct debug_info_history {
205
	unsigned int consec_frames;
251
	unsigned int consec_frames;
Lines 213-224 Link Here
213
	struct ast_dsp *dsp;
259
	struct ast_dsp *dsp;
214
};
260
};
215
261
262
/*! \brief used for gateway framehook */
263
struct fax_gateway {
264
	/*! \brief FAX Session */
265
	struct ast_fax_session *s;
266
	/*! \brief reserved fax session token */
267
	struct ast_fax_tech_token *token;
268
	/*! \brief the start of our timeout counter */
269
	struct timeval timeout_start;
270
	/*! \brief DSP Processor */
271
	struct ast_dsp *chan_dsp;
272
	struct ast_dsp *peer_dsp;
273
	/*! \brief framehook used in gateway mode */
274
	int framehook;
275
	/*! \brief bridged */
276
	int bridged:1;
277
	/*! \brief 1 if a v21 preamble has been detected */
278
	int detected_v21:1;
279
	/*! \brief a flag to track the state of our negotiation */
280
	enum ast_t38_state t38_state;
281
	/*! \brief Original audio formats */
282
	unsigned int chan_read_format;
283
	unsigned int chan_write_format;
284
	unsigned int peer_read_format;
285
	unsigned int peer_write_format;
286
};
287
216
static int fax_logger_level = -1;
288
static int fax_logger_level = -1;
217
289
218
/*! \brief maximum buckets for res_fax ao2 containers */
290
/*! \brief maximum buckets for res_fax ao2 containers */
219
#define FAX_MAXBUCKETS 10
291
#define FAX_MAXBUCKETS 10
220
292
221
#define RES_FAX_TIMEOUT 10000
293
#define RES_FAX_TIMEOUT 10000
294
#define FAX_GATEWAY_TIMEOUT RES_FAX_TIMEOUT
222
295
223
/*! \brief The faxregistry is used to manage information and statistics for all FAX sessions. */
296
/*! \brief The faxregistry is used to manage information and statistics for all FAX sessions. */
224
static struct {
297
static struct {
Lines 393-402 Link Here
393
	d->modems = general_options.modems;
466
	d->modems = general_options.modems;
394
	d->minrate = general_options.minrate;
467
	d->minrate = general_options.minrate;
395
	d->maxrate = general_options.maxrate;
468
	d->maxrate = general_options.maxrate;
469
	d->gateway_id = -1;
396
470
397
	return d;
471
	return d;
398
}
472
}
399
473
474
static struct ast_control_t38_parameters our_t38_parameters = {
475
	.version = 0,
476
	.max_ifp = 400,
477
	.rate = AST_T38_RATE_14400,
478
	.rate_management = AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF,
479
};
480
481
static void t38_parameters_ast_to_fax(struct ast_fax_t38_parameters *dst, const struct ast_control_t38_parameters *src)
482
{
483
	dst->version = src->version;
484
	dst->max_ifp = src->max_ifp;
485
	dst->rate = src->rate;
486
	dst->rate_management = src->rate_management;
487
	dst->fill_bit_removal = src->fill_bit_removal;
488
	dst->transcoding_mmr = src->transcoding_mmr;
489
	dst->transcoding_jbig = src->transcoding_jbig;
490
}
491
492
static void t38_parameters_fax_to_ast(struct ast_control_t38_parameters *dst, const struct ast_fax_t38_parameters *src)
493
{
494
	dst->version = src->version;
495
	dst->max_ifp = src->max_ifp;
496
	dst->rate = src->rate;
497
	dst->rate_management = src->rate_management;
498
	dst->fill_bit_removal = src->fill_bit_removal;
499
	dst->transcoding_mmr = src->transcoding_mmr;
500
	dst->transcoding_jbig = src->transcoding_jbig;
501
}
502
400
/*! \brief returns a reference counted details structure from the channel's fax datastore.  If the datastore
503
/*! \brief returns a reference counted details structure from the channel's fax datastore.  If the datastore
401
 * does not exist it will be created */	
504
 * does not exist it will be created */	
402
static struct ast_fax_session_details *find_or_create_details(struct ast_channel *chan)
505
static struct ast_fax_session_details *find_or_create_details(struct ast_channel *chan)
Lines 419-424 Link Here
419
	}
522
	}
420
	/* add the datastore to the channel and increment the refcount */
523
	/* add the datastore to the channel and increment the refcount */
421
	datastore->data = details;
524
	datastore->data = details;
525
526
	/* initialize default T.38 parameters */
527
	t38_parameters_ast_to_fax(&details->our_t38_parameters, &our_t38_parameters);
528
	t38_parameters_ast_to_fax(&details->their_t38_parameters, &our_t38_parameters);
529
422
	ao2_ref(details, 1);
530
	ao2_ref(details, 1);
423
	ast_channel_lock(chan);
531
	ast_channel_lock(chan);
424
	ast_channel_datastore_add(chan, datastore);
532
	ast_channel_datastore_add(chan, datastore);
Lines 511-516 Link Here
511
		ast_build_string(&buf, &size, "MULTI_DOC");
619
		ast_build_string(&buf, &size, "MULTI_DOC");
512
		first = 0;
620
		first = 0;
513
	}
621
	}
622
	if (caps & AST_FAX_TECH_GATEWAY) {
623
		if (!first) {
624
			ast_build_string(&buf, &size, ",");
625
		}
626
		ast_build_string(&buf, &size, "T38_GATEWAY");
627
		first = 0;
628
	}
514
629
515
	return out;
630
	return out;
516
}
631
}
Lines 686-691 Link Here
686
	}
801
	}
687
}
802
}
688
803
804
/*! \brief Release a session token.
805
 * \param s a session returned from fax_session_reserve()
806
 * \param token a token generated from fax_session_reserve()
807
 *
808
 * This function releases the given token and marks the given session as no
809
 * longer reserved. It is safe to call on a session that is not actually
810
 * reserved and with a NULL token. This is so that sessions returned by
811
 * technologies that do not support reserved sessions don't require extra logic
812
 * to handle.
813
 *
814
 * \note This function DOES NOT release the given fax session, only the given
815
 * token.
816
 */
689
static void fax_session_release(struct ast_fax_session *s, struct ast_fax_tech_token *token)
817
static void fax_session_release(struct ast_fax_session *s, struct ast_fax_tech_token *token)
690
{
818
{
691
	if (token) {
819
	if (token) {
Lines 732-737 Link Here
732
	ast_free(s->chan_uniqueid);
860
	ast_free(s->chan_uniqueid);
733
}
861
}
734
862
863
/*! \brief Reserve a fax session.
864
 * \param details the fax session details
865
 * \param token a pointer to a place to store a token to be passed to fax_session_new() later
866
 *
867
 * This function reserves a fax session for use later. If the selected fax
868
 * technology does not support reserving sessions a session will still be
869
 * returned but token will not be set.
870
 *
871
 * \note The reference returned by this function does not get consumed by
872
 * fax_session_new() and must always be dereferenced separately.
873
 *
874
 * \return NULL or an uninitialized and possibly reserved session
875
 */
735
static struct ast_fax_session *fax_session_reserve(struct ast_fax_session_details *details, struct ast_fax_tech_token **token)
876
static struct ast_fax_session *fax_session_reserve(struct ast_fax_session_details *details, struct ast_fax_tech_token **token)
736
{
877
{
737
	struct ast_fax_session *s;
878
	struct ast_fax_session *s;
Lines 743-748 Link Here
743
	}
884
	}
744
885
745
	s->state = AST_FAX_STATE_INACTIVE;
886
	s->state = AST_FAX_STATE_INACTIVE;
887
	s->details = details;
888
	ao2_ref(s->details, 1);
746
889
747
	/* locate a FAX technology module that can handle said requirements
890
	/* locate a FAX technology module that can handle said requirements
748
	 * Note: the requirements have not yet been finalized as T.38
891
	 * Note: the requirements have not yet been finalized as T.38
Lines 781-787 Link Here
781
	return s;
924
	return s;
782
}
925
}
783
926
784
/*! \brief create a FAX session */
927
/*! \brief create a FAX session
928
 *
929
 * \param details details for the session
930
 * \param chan the channel the session will run on
931
 * \param reserved a reserved session to base this session on (can be NULL)
932
 * \param token the token for a reserved session (can be NULL)
933
 *
934
 * Create a new fax session based on the given details structure.
935
 *
936
 * \note The given token is always consumed (by tech->new_session() or by
937
 * fax_session_release() in the event of a failure). The given reference to a
938
 * reserved session is never consumed and must be dereferenced separately from
939
 * the reference returned by this function.
940
 *
941
 * \return NULL or a reference to a new fax session
942
 */
785
static struct ast_fax_session *fax_session_new(struct ast_fax_session_details *details, struct ast_channel *chan, struct ast_fax_session *reserved, struct ast_fax_tech_token *token)
943
static struct ast_fax_session *fax_session_new(struct ast_fax_session_details *details, struct ast_channel *chan, struct ast_fax_session *reserved, struct ast_fax_tech_token *token)
786
{
944
{
787
	struct ast_fax_session *s = NULL;
945
	struct ast_fax_session *s = NULL;
Lines 792-797 Link Here
792
		s = reserved;
950
		s = reserved;
793
		ao2_ref(reserved, +1);
951
		ao2_ref(reserved, +1);
794
952
953
		/* NOTE: we don't consume the reference to the reserved
954
		 * session. The session returned from fax_session_new() is a
955
		 * new reference and must be derefed in addition to the
956
		 * reserved session.
957
		 */
958
795
		if (s->state == AST_FAX_STATE_RESERVED) {
959
		if (s->state == AST_FAX_STATE_RESERVED) {
796
			ast_atomic_fetchadd_int(&faxregistry.reserved_sessions, -1);
960
			ast_atomic_fetchadd_int(&faxregistry.reserved_sessions, -1);
797
			s->state = AST_FAX_STATE_UNINITIALIZED;
961
			s->state = AST_FAX_STATE_UNINITIALIZED;
Lines 834-841 Link Here
834
	}
998
	}
835
999
836
	s->chan = chan;
1000
	s->chan = chan;
837
	s->details = details;
1001
	if (!s->details) {
838
	ao2_ref(s->details, 1);
1002
		s->details = details;
1003
		ao2_ref(s->details, 1);
1004
	}
839
1005
840
	details->id = s->id = ast_atomic_fetchadd_int(&faxregistry.nextsessionname, 1);
1006
	details->id = s->id = ast_atomic_fetchadd_int(&faxregistry.nextsessionname, 1);
841
1007
Lines 935-943 Link Here
935
static int report_fax_status(struct ast_channel *chan, struct ast_fax_session_details *details, const char *status)
1101
static int report_fax_status(struct ast_channel *chan, struct ast_fax_session_details *details, const char *status)
936
{
1102
{
937
	char *filenames = generate_filenames_string(details, "FileName: ", "\r\n");
1103
	char *filenames = generate_filenames_string(details, "FileName: ", "\r\n");
938
	if (!filenames) {
939
		return 1;
940
	}
941
1104
942
	ast_channel_lock(chan);
1105
	ast_channel_lock(chan);
943
	if (details->option.statusevents) {
1106
	if (details->option.statusevents) {
Lines 945-969 Link Here
945
1108
946
		get_manager_event_info(chan, &info);
1109
		get_manager_event_info(chan, &info);
947
		manager_event(EVENT_FLAG_CALL,
1110
		manager_event(EVENT_FLAG_CALL,
948
			      (details->caps & AST_FAX_TECH_RECEIVE) ? "ReceiveFAXStatus" : "SendFAXStatus",
1111
			      "FAXStatus",
1112
			      "Operation: %s\r\n"
949
			      "Status: %s\r\n"
1113
			      "Status: %s\r\n"
950
			      "Channel: %s\r\n"
1114
			      "Channel: %s\r\n"
951
			      "Context: %s\r\n"
1115
			      "Context: %s\r\n"
952
			      "Exten: %s\r\n"
1116
			      "Exten: %s\r\n"
953
			      "CallerID: %s\r\n"
1117
			      "CallerID: %s\r\n"
954
			      "LocalStationID: %s\r\n"
1118
			      "LocalStationID: %s\r\n"
955
			      "%s\r\n",
1119
			      "%s%s",
1120
			      (details->caps & AST_FAX_TECH_GATEWAY) ? "gateway" : (details->caps & AST_FAX_TECH_RECEIVE) ? "receive" : "send",
956
			      status,
1121
			      status,
957
			      chan->name,
1122
			      chan->name,
958
			      info.context,
1123
			      info.context,
959
			      info.exten,
1124
			      info.exten,
960
			      info.cid,
1125
			      info.cid,
961
			      details->localstationid,
1126
			      details->localstationid,
962
			      filenames);
1127
			      S_OR(filenames, ""),
1128
			      filenames ? "\r\n" : "");
963
	}
1129
	}
964
	ast_channel_unlock(chan);
1130
	ast_channel_unlock(chan);
965
	ast_free(filenames);
966
1131
1132
	if (filenames) {
1133
		ast_free(filenames);
1134
	}
1135
967
	return 0;
1136
	return 0;
968
}
1137
}
969
1138
Lines 1006-1042 Link Here
1006
		GENERIC_FAX_EXEC_ERROR_QUIET(fax, chan, errorstr, reason); \
1175
		GENERIC_FAX_EXEC_ERROR_QUIET(fax, chan, errorstr, reason); \
1007
	} while (0)
1176
	} while (0)
1008
1177
1009
static void t38_parameters_ast_to_fax(struct ast_fax_t38_parameters *dst, const struct ast_control_t38_parameters *src)
1010
{
1011
	dst->version = src->version;
1012
	dst->max_ifp = src->max_ifp;
1013
	dst->rate = src->rate;
1014
	dst->rate_management = src->rate_management;
1015
	dst->fill_bit_removal = src->fill_bit_removal;
1016
	dst->transcoding_mmr = src->transcoding_mmr;
1017
	dst->transcoding_jbig = src->transcoding_jbig;
1018
}
1019
1020
static void t38_parameters_fax_to_ast(struct ast_control_t38_parameters *dst, const struct ast_fax_t38_parameters *src)
1021
{
1022
	dst->version = src->version;
1023
	dst->max_ifp = src->max_ifp;
1024
	dst->rate = src->rate;
1025
	dst->rate_management = src->rate_management;
1026
	dst->fill_bit_removal = src->fill_bit_removal;
1027
	dst->transcoding_mmr = src->transcoding_mmr;
1028
	dst->transcoding_jbig = src->transcoding_jbig;
1029
}
1030
1031
static int set_fax_t38_caps(struct ast_channel *chan, struct ast_fax_session_details *details)
1178
static int set_fax_t38_caps(struct ast_channel *chan, struct ast_fax_session_details *details)
1032
{
1179
{
1033
	switch (ast_channel_get_t38_state(chan)) {
1180
	switch (ast_channel_get_t38_state(chan)) {
1034
	case T38_STATE_UNKNOWN:
1181
	case T38_STATE_UNKNOWN:
1035
		details->caps |= AST_FAX_TECH_T38;
1182
		details->caps |= AST_FAX_TECH_T38;
1036
		break;
1183
		break;
1184
	case T38_STATE_REJECTED:
1037
	case T38_STATE_UNAVAILABLE:
1185
	case T38_STATE_UNAVAILABLE:
1038
		details->caps |= AST_FAX_TECH_AUDIO;
1186
		details->caps |= AST_FAX_TECH_AUDIO;
1039
		break;
1187
		break;
1188
	case T38_STATE_NEGOTIATED:
1189
		/* already in T.38 mode? This should not happen. */
1040
	case T38_STATE_NEGOTIATING: {
1190
	case T38_STATE_NEGOTIATING: {
1041
		/* the other end already sent us a T.38 reinvite, so we need to prod the channel
1191
		/* the other end already sent us a T.38 reinvite, so we need to prod the channel
1042
		 * driver into resending their parameters to us if it supports doing so... if
1192
		 * driver into resending their parameters to us if it supports doing so... if
Lines 1118-1130 Link Here
1118
	return 0;
1268
	return 0;
1119
}
1269
}
1120
1270
1121
static struct ast_control_t38_parameters our_t38_parameters = {
1122
	.version = 0,
1123
	.max_ifp = 400,
1124
	.rate = AST_T38_RATE_14400,
1125
	.rate_management = AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF,
1126
};
1127
1128
/*! \brief this is the generic FAX session handling function */
1271
/*! \brief this is the generic FAX session handling function */
1129
static int generic_fax_exec(struct ast_channel *chan, struct ast_fax_session_details *details, struct ast_fax_session *reserved, struct ast_fax_tech_token *token)
1272
static int generic_fax_exec(struct ast_channel *chan, struct ast_fax_session_details *details, struct ast_fax_session *reserved, struct ast_fax_tech_token *token)
1130
{
1273
{
Lines 1390-1397 Link Here
1390
	struct ast_frame *frame = NULL;
1533
	struct ast_frame *frame = NULL;
1391
	struct ast_control_t38_parameters t38_parameters;
1534
	struct ast_control_t38_parameters t38_parameters;
1392
1535
1393
	t38_parameters_ast_to_fax(&details->our_t38_parameters, &our_t38_parameters);
1394
1395
	/* don't send any audio if we've already received a T.38 reinvite */
1536
	/* don't send any audio if we've already received a T.38 reinvite */
1396
	if (ast_channel_get_t38_state(chan) != T38_STATE_NEGOTIATING) {
1537
	if (ast_channel_get_t38_state(chan) != T38_STATE_NEGOTIATING) {
1397
		/* generate 3 seconds of CED */
1538
		/* generate 3 seconds of CED */
Lines 1551-1556 Link Here
1551
	);
1692
	);
1552
	struct ast_flags opts = { 0, };
1693
	struct ast_flags opts = { 0, };
1553
	struct manager_event_info info;
1694
	struct manager_event_info info;
1695
	enum ast_t38_state t38state;
1554
1696
1555
	/* initialize output channel variables */
1697
	/* initialize output channel variables */
1556
	pbx_builtin_setvar_helper(chan, "FAXSTATUS", "FAILED");
1698
	pbx_builtin_setvar_helper(chan, "FAXSTATUS", "FAILED");
Lines 1579-1584 Link Here
1579
	ast_string_field_set(details, error, "INIT_ERROR");
1721
	ast_string_field_set(details, error, "INIT_ERROR");
1580
	set_channel_variables(chan, details);
1722
	set_channel_variables(chan, details);
1581
1723
1724
	if (details->caps & AST_FAX_TECH_GATEWAY) {
1725
		ast_string_field_set(details, resultstr, "can't receive a fax on a channel with a T.38 gateway");
1726
		set_channel_variables(chan, details);
1727
		ast_log(LOG_ERROR, "executing ReceiveFAX on a channel with a T.38 Gateway is not supported\n");
1728
		ao2_ref(details, -1);
1729
		return -1;
1730
	}
1731
1582
	if (details->maxrate < details->minrate) {
1732
	if (details->maxrate < details->minrate) {
1583
		ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
1733
		ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
1584
		ast_string_field_set(details, error, "INVALID_ARGUMENTS");
1734
		ast_string_field_set(details, error, "INVALID_ARGUMENTS");
Lines 1683-1689 Link Here
1683
		details->option.statusevents = AST_FAX_OPTFLAG_TRUE;
1833
		details->option.statusevents = AST_FAX_OPTFLAG_TRUE;
1684
	}
1834
	}
1685
1835
1686
	if ((ast_channel_get_t38_state(chan) == T38_STATE_UNAVAILABLE) ||
1836
	t38state = ast_channel_get_t38_state(chan);
1837
	if ((t38state == T38_STATE_UNAVAILABLE) || (t38state == T38_STATE_REJECTED) ||
1687
	    ast_test_flag(&opts, OPT_ALLOWAUDIO)) {
1838
	    ast_test_flag(&opts, OPT_ALLOWAUDIO)) {
1688
		details->option.allow_audio = AST_FAX_OPTFLAG_TRUE;
1839
		details->option.allow_audio = AST_FAX_OPTFLAG_TRUE;
1689
	}
1840
	}
Lines 1789-1796 Link Here
1789
	struct ast_frame *frame = NULL;
1940
	struct ast_frame *frame = NULL;
1790
	struct ast_control_t38_parameters t38_parameters;
1941
	struct ast_control_t38_parameters t38_parameters;
1791
1942
1792
	t38_parameters_ast_to_fax(&details->our_t38_parameters, &our_t38_parameters);
1793
1794
	/* send CNG tone while listening for the receiver to initiate a switch
1943
	/* send CNG tone while listening for the receiver to initiate a switch
1795
	 * to T.38 mode; if they do, stop sending the CNG tone and proceed with
1944
	 * to T.38 mode; if they do, stop sending the CNG tone and proceed with
1796
	 * the switch.
1945
	 * the switch.
Lines 2023-2028 Link Here
2023
	);
2172
	);
2024
	struct ast_flags opts = { 0, };
2173
	struct ast_flags opts = { 0, };
2025
	struct manager_event_info info;
2174
	struct manager_event_info info;
2175
	enum ast_t38_state t38state;
2026
2176
2027
	/* initialize output channel variables */
2177
	/* initialize output channel variables */
2028
	pbx_builtin_setvar_helper(chan, "FAXSTATUS", "FAILED");
2178
	pbx_builtin_setvar_helper(chan, "FAXSTATUS", "FAILED");
Lines 2051-2056 Link Here
2051
	ast_string_field_set(details, error, "INIT_ERROR");
2201
	ast_string_field_set(details, error, "INIT_ERROR");
2052
	set_channel_variables(chan, details);
2202
	set_channel_variables(chan, details);
2053
2203
2204
	if (details->caps & AST_FAX_TECH_GATEWAY) {
2205
		ast_string_field_set(details, resultstr, "can't send a fax on a channel with a T.38 gateway");
2206
		set_channel_variables(chan, details);
2207
		ast_log(LOG_ERROR, "executing SendFAX on a channel with a T.38 Gateway is not supported\n");
2208
		ao2_ref(details, -1);
2209
		return -1;
2210
	}
2211
2054
	if (details->maxrate < details->minrate) {
2212
	if (details->maxrate < details->minrate) {
2055
		ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
2213
		ast_atomic_fetchadd_int(&faxregistry.fax_failures, 1);
2056
		ast_string_field_set(details, error, "INVALID_ARGUMENTS");
2214
		ast_string_field_set(details, error, "INVALID_ARGUMENTS");
Lines 2175-2181 Link Here
2175
		details->option.statusevents = AST_FAX_OPTFLAG_TRUE;
2333
		details->option.statusevents = AST_FAX_OPTFLAG_TRUE;
2176
	}
2334
	}
2177
2335
2178
	if ((ast_channel_get_t38_state(chan) == T38_STATE_UNAVAILABLE) ||
2336
	t38state = ast_channel_get_t38_state(chan);
2337
	if ((t38state == T38_STATE_UNAVAILABLE) || (t38state == T38_STATE_REJECTED) ||
2179
	    ast_test_flag(&opts, OPT_ALLOWAUDIO)) {
2338
	    ast_test_flag(&opts, OPT_ALLOWAUDIO)) {
2180
		details->option.allow_audio = AST_FAX_OPTFLAG_TRUE;
2339
		details->option.allow_audio = AST_FAX_OPTFLAG_TRUE;
2181
	}
2340
	}
Lines 2287-2292 Link Here
2287
	return (!channel_alive) ? -1 : 0;
2446
	return (!channel_alive) ? -1 : 0;
2288
}
2447
}
2289
2448
2449
/*! \brief destroy a FAX gateway session structure */
2450
static void destroy_gateway(void *data)
2451
{
2452
	struct fax_gateway *gateway = data;
2453
2454
	if (gateway->chan_dsp) {
2455
		ast_dsp_free(gateway->chan_dsp);
2456
		gateway->chan_dsp = NULL;
2457
	}
2458
2459
	if (gateway->peer_dsp) {
2460
		ast_dsp_free(gateway->peer_dsp);
2461
		gateway->peer_dsp = NULL;
2462
	}
2463
2464
	if (gateway->s) {
2465
		fax_session_release(gateway->s, gateway->token);
2466
		gateway->token = NULL;
2467
		gateway->s->details->caps |= ~AST_FAX_TECH_GATEWAY;
2468
2469
		ao2_lock(faxregistry.container);
2470
		ao2_unlink(faxregistry.container, gateway->s);
2471
		ao2_unlock(faxregistry.container);
2472
2473
		ao2_ref(gateway->s, -1);
2474
		gateway->s = NULL;
2475
	}
2476
}
2477
2478
/*! \brief Create a new fax gateway object.
2479
 * \param details the fax session details
2480
 * \return NULL or a fax gateway object
2481
 */
2482
static struct fax_gateway *fax_gateway_new(struct ast_fax_session_details *details)
2483
{
2484
	struct fax_gateway *gateway = ao2_alloc(sizeof(*gateway), destroy_gateway);
2485
	if (!gateway) {
2486
		return NULL;
2487
	}
2488
2489
	gateway->chan_dsp = ast_dsp_new();
2490
	if (!gateway->chan_dsp) {
2491
		ao2_ref(gateway, -1);
2492
		return NULL;
2493
	}
2494
2495
	gateway->peer_dsp = ast_dsp_new();
2496
	if (!gateway->peer_dsp) {
2497
		ao2_ref(gateway, -1);
2498
		return NULL;
2499
	}
2500
2501
	gateway->framehook = -1;
2502
2503
	ast_dsp_set_features(gateway->chan_dsp, DSP_FEATURE_FAX_DETECT);
2504
	ast_dsp_set_faxmode(gateway->chan_dsp, DSP_FAXMODE_DETECT_V21 | DSP_FAXMODE_DETECT_CED);
2505
2506
	ast_dsp_set_features(gateway->peer_dsp, DSP_FEATURE_FAX_DETECT);
2507
	ast_dsp_set_faxmode(gateway->peer_dsp, DSP_FAXMODE_DETECT_V21 | DSP_FAXMODE_DETECT_CED);
2508
2509
	details->caps = AST_FAX_TECH_GATEWAY;
2510
	if (details->gateway_timeout && !(gateway->s = fax_session_reserve(details, &gateway->token))) {
2511
		details->caps |= ~AST_FAX_TECH_GATEWAY;
2512
		ast_log(LOG_ERROR, "Can't reserve a FAX session, gateway attempt failed.\n");
2513
		ao2_ref(gateway, -1);
2514
		return NULL;
2515
	}
2516
2517
	return gateway;
2518
}
2519
2520
/*! \brief Create a fax session and start T.30<->T.38 gateway mode
2521
 * \param gateway a fax gateway object
2522
 * \param details fax session details
2523
 * \param chan active channel
2524
 * \return 0 on error 1 on success*/
2525
static int fax_gateway_start(struct fax_gateway *gateway, struct ast_fax_session_details *details, struct ast_channel *chan)
2526
{
2527
	struct ast_fax_session *s;
2528
2529
	/* create the FAX session */
2530
	if (!(s = fax_session_new(details, chan, gateway->s, gateway->token))) {
2531
		gateway->token = NULL;
2532
		ast_string_field_set(details, result, "FAILED");
2533
		ast_string_field_set(details, resultstr, "error starting gateway session");
2534
		ast_string_field_set(details, error, "INIT_ERROR");
2535
		set_channel_variables(chan, details);
2536
		report_fax_status(chan, details, "No Available Resource");
2537
		ast_log(LOG_ERROR, "Can't create a FAX session, gateway attempt failed.\n");
2538
		return -1;
2539
	}
2540
	/* release the reference for the reserved session and replace it with
2541
	 * the real session */
2542
	ao2_ref(gateway->s, -1);
2543
	gateway->s = s;
2544
	gateway->token = NULL;
2545
2546
	if (gateway->s->tech->start_session(gateway->s) < 0) {
2547
		ast_string_field_set(details, result, "FAILED");
2548
		ast_string_field_set(details, resultstr, "error starting gateway session");
2549
		ast_string_field_set(details, error, "INIT_ERROR");
2550
		set_channel_variables(chan, details);
2551
		return -1;
2552
	}
2553
2554
	gateway->timeout_start.tv_sec = 0;
2555
	gateway->timeout_start.tv_usec = 0;
2556
2557
	report_fax_status(chan, details, "FAX Transmission In Progress");
2558
2559
	return 0;
2560
}
2561
2562
static struct ast_frame *fax_gateway_request_t38(struct fax_gateway *gateway, struct ast_channel *chan, struct ast_frame *f)
2563
{
2564
	struct ast_frame *fp;
2565
	struct ast_control_t38_parameters t38_parameters = {
2566
		.request_response = AST_T38_REQUEST_NEGOTIATE,
2567
	};
2568
	struct ast_frame control_frame = {
2569
		.src = "res_fax",
2570
		.frametype = AST_FRAME_CONTROL,
2571
		.datalen = sizeof(t38_parameters),
2572
		.subclass.integer = AST_CONTROL_T38_PARAMETERS,
2573
		.data.ptr = &t38_parameters,
2574
	};
2575
2576
	struct ast_fax_session_details *details = find_details(chan);
2577
2578
	if (!details) {
2579
		ast_log(LOG_ERROR, "no FAX session details found on chan %s for T.38 gateway session, odd\n", chan->name);
2580
		ast_framehook_detach(chan, gateway->framehook);
2581
		return f;
2582
	}
2583
2584
	t38_parameters_fax_to_ast(&t38_parameters, &details->our_t38_parameters);
2585
	ao2_ref(details, -1);
2586
2587
	if (!(fp = ast_frisolate(&control_frame))) {
2588
		ast_log(LOG_ERROR, "error generating T.38 request control frame on chan %s for T.38 gateway session\n", chan->name);
2589
		return f;
2590
	}
2591
2592
	gateway->t38_state = T38_STATE_NEGOTIATING;
2593
	gateway->timeout_start = ast_tvnow();
2594
	details->gateway_timeout = FAX_GATEWAY_TIMEOUT;
2595
2596
	ast_debug(1, "requesting T.38 for gateway session for %s\n", chan->name);
2597
	return fp;
2598
}
2599
2600
static struct ast_frame *fax_gateway_detect_v21(struct fax_gateway *gateway, struct ast_channel *chan, struct ast_channel *peer, struct ast_channel *active, struct ast_frame *f)
2601
{
2602
	struct ast_frame *dfr = ast_frdup(f);
2603
	struct ast_dsp *active_dsp = (active == chan) ? gateway->chan_dsp : gateway->peer_dsp;
2604
	struct ast_channel *other = (active == chan) ? peer : chan;
2605
2606
	if (gateway->detected_v21) {
2607
		return f;
2608
	}
2609
2610
	if (!dfr) {
2611
		return f;
2612
	}
2613
2614
	if (!(dfr = ast_dsp_process(active, active_dsp, dfr))) {
2615
		return f;
2616
	}
2617
2618
	if (dfr->frametype == AST_FRAME_DTMF && ((dfr->subclass.integer == 'e') || (dfr->subclass.integer == 'g'))) {
2619
		gateway->detected_v21 = 1;
2620
		if (ast_channel_get_t38_state(other) == T38_STATE_UNKNOWN) {
2621
			ast_debug(1, "detected v21 preamble from %s\n", active->name);
2622
			return fax_gateway_request_t38(gateway, chan, f);
2623
		} else {
2624
			ast_debug(1, "detected v21 preamble on %s, but %s does not support T.38 for T.38 gateway session\n", active->name, other->name);
2625
		}
2626
	}
2627
2628
	ast_frfree(dfr);
2629
	return f;
2630
}
2631
2632
static int fax_gateway_indicate_t38(struct ast_channel *chan, struct ast_channel *active, struct ast_control_t38_parameters *control_params)
2633
{
2634
	if (active == chan) {
2635
		return ast_indicate_data(chan, AST_CONTROL_T38_PARAMETERS, control_params, sizeof(*control_params));
2636
	} else {
2637
		return ast_queue_control_data(chan, AST_CONTROL_T38_PARAMETERS, control_params, sizeof(*control_params));
2638
	}
2639
}
2640
2641
/*! \brief T38 Gateway Negotiate t38 parameters
2642
 * \param gateway gateway object
2643
 * \param chan channel running the gateway
2644
 * \param peer channel im bridged too
2645
 * \param active channel the frame originated on
2646
 * \param f the control frame to process
2647
 * \return processed control frame or null frame
2648
 */
2649
static struct ast_frame *fax_gateway_detect_t38(struct fax_gateway *gateway, struct ast_channel *chan, struct ast_channel *peer, struct ast_channel *active, struct ast_frame *f)
2650
{
2651
	struct ast_control_t38_parameters *control_params = f->data.ptr;
2652
	struct ast_channel *other = (active == chan) ? peer : chan;
2653
	struct ast_fax_session_details *details;
2654
2655
	if (f->datalen != sizeof(struct ast_control_t38_parameters)) {
2656
		/* invalaid AST_CONTROL_T38_PARAMETERS frame, we can't
2657
		 * do anything with it, pass it on */
2658
		return f;
2659
	}
2660
2661
	/* ignore frames from ourselves */
2662
	if ((gateway->t38_state == T38_STATE_NEGOTIATED && control_params->request_response == AST_T38_NEGOTIATED)
2663
		|| (gateway->t38_state == T38_STATE_REJECTED && control_params->request_response == AST_T38_REFUSED)
2664
		|| (gateway->t38_state == T38_STATE_NEGOTIATING && control_params->request_response == AST_T38_REQUEST_TERMINATE)) {
2665
2666
		return f;
2667
	}
2668
2669
	if (!(details = find_details(chan))) {
2670
		ast_log(LOG_ERROR, "no FAX session details found on chan %s for T.38 gateway session, odd\n", chan->name);
2671
		ast_framehook_detach(chan, gateway->framehook);
2672
		return f;
2673
	}
2674
2675
	if (control_params->request_response == AST_T38_REQUEST_NEGOTIATE) {
2676
		enum ast_t38_state state = ast_channel_get_t38_state(other);
2677
2678
		if (state == T38_STATE_UNKNOWN) {
2679
			/* we detected a request to negotiate T.38 and the
2680
			 * other channel appears to support T.38, we'll pass
2681
			 * the request through and only step in if the other
2682
			 * channel rejects the request */
2683
			ast_debug(1, "%s is attempting to negotiate T.38 with %s, we'll see what happens\n", active->name, other->name);
2684
			t38_parameters_ast_to_fax(&details->their_t38_parameters, control_params);
2685
			gateway->t38_state = T38_STATE_UNKNOWN;
2686
			gateway->timeout_start = ast_tvnow();
2687
			details->gateway_timeout = FAX_GATEWAY_TIMEOUT;
2688
			ao2_ref(details, -1);
2689
			return f;
2690
		} else if (state == T38_STATE_UNAVAILABLE || state == T38_STATE_REJECTED) {
2691
			/* the other channel does not support T.38, we need to
2692
			 * step in here */
2693
			ast_debug(1, "%s is attempting to negotiate T.38 but %s does not support it\n", active->name, other->name);
2694
			ast_debug(1, "starting T.38 gateway for T.38 channel %s and G.711 channel %s\n", active->name, other->name);
2695
2696
			t38_parameters_ast_to_fax(&details->their_t38_parameters, control_params);
2697
			t38_parameters_fax_to_ast(control_params, &details->our_t38_parameters);
2698
2699
			if (fax_gateway_start(gateway, details, chan)) {
2700
				ast_log(LOG_ERROR, "error starting T.38 gateway for T.38 channel %s and G.711 channel %s\n", active->name, other->name);
2701
				gateway->t38_state = T38_STATE_REJECTED;
2702
				control_params->request_response = AST_T38_REFUSED;
2703
2704
				ast_framehook_detach(chan, details->gateway_id);
2705
				details->gateway_id = -1;
2706
			} else {
2707
				gateway->t38_state = T38_STATE_NEGOTIATED;
2708
				control_params->request_response = AST_T38_NEGOTIATED;
2709
				report_fax_status(chan, details, "T.38 Negotiated");
2710
			}
2711
2712
			fax_gateway_indicate_t38(chan, active, control_params);
2713
2714
			ao2_ref(details, -1);
2715
			return &ast_null_frame;
2716
		} else if (gateway->t38_state == T38_STATE_NEGOTIATING) {
2717
			/* we got a request to negotiate T.38 after we already
2718
			 * sent one to the other party based on v21 preamble
2719
			 * detection. We'll just pretend we passed this request
2720
			 * through in the first place. */
2721
2722
			t38_parameters_ast_to_fax(&details->their_t38_parameters, control_params);
2723
			gateway->t38_state = T38_STATE_UNKNOWN;
2724
			gateway->timeout_start = ast_tvnow();
2725
			details->gateway_timeout = FAX_GATEWAY_TIMEOUT;
2726
2727
			ast_debug(1, "%s is attempting to negotiate T.38 after we already sent a negotiation request based on v21 preamble detection\n", active->name);
2728
			ao2_ref(details, -1);
2729
			return &ast_null_frame;
2730
		} else if (gateway->t38_state == T38_STATE_NEGOTIATED) {
2731
			/* we got a request to negotiate T.38 after we already
2732
			 * sent one to the other party based on v21 preamble
2733
			 * detection and received a response. We need to
2734
			 * respond to this and shut down the gateway. */
2735
2736
			t38_parameters_fax_to_ast(control_params, &details->their_t38_parameters);
2737
			ast_framehook_detach(chan, details->gateway_id);
2738
			details->gateway_id = -1;
2739
2740
			control_params->request_response = AST_T38_NEGOTIATED;
2741
2742
			fax_gateway_indicate_t38(chan, active, control_params);
2743
2744
			ast_string_field_set(details, result, "SUCCESS");
2745
			ast_string_field_set(details, resultstr, "no gateway necessary");
2746
			ast_string_field_set(details, error, "NATIVE_T38");
2747
			set_channel_variables(chan, details);
2748
2749
			ast_debug(1, "%s is attempting to negotiate T.38 after we already negotiated T.38 with %s, disabling the gateway\n", active->name, other->name);
2750
			ao2_ref(details, -1);
2751
			return &ast_null_frame;
2752
		} else {
2753
			ast_log(LOG_WARNING, "%s is attempting to negotiate T.38 while %s is in an unsupported state\n", active->name, other->name);
2754
			ao2_ref(details, -1);
2755
			return f;
2756
		}
2757
	} else if (gateway->t38_state == T38_STATE_NEGOTIATING
2758
		&& control_params->request_response == AST_T38_REFUSED) {
2759
2760
		ast_debug(1, "unable to negotiate T.38 on %s for fax gateway\n", active->name);
2761
2762
		/* our request to negotiate T.38 was refused, if the other
2763
		 * channel supports T.38, they might still reinvite and save
2764
		 * the day.  Otherwise disable the gateway. */
2765
		if (ast_channel_get_t38_state(other) == T38_STATE_UNKNOWN) {
2766
			gateway->t38_state = T38_STATE_UNAVAILABLE;
2767
		} else {
2768
			ast_framehook_detach(chan, details->gateway_id);
2769
			details->gateway_id = -1;
2770
2771
			ast_string_field_set(details, result, "FAILED");
2772
			ast_string_field_set(details, resultstr, "unable to negotiate T.38");
2773
			ast_string_field_set(details, error, "T38_NEG_ERROR");
2774
			set_channel_variables(chan, details);
2775
		}
2776
2777
		ao2_ref(details, -1);
2778
		return &ast_null_frame;
2779
	} else if (gateway->t38_state == T38_STATE_NEGOTIATING
2780
		&& control_params->request_response == AST_T38_NEGOTIATED) {
2781
2782
		ast_debug(1, "starting T.38 gateway for T.38 channel %s and G.711 channel %s\n", active->name, other->name);
2783
2784
		t38_parameters_ast_to_fax(&details->their_t38_parameters, control_params);
2785
2786
		if (fax_gateway_start(gateway, details, chan)) {
2787
			ast_log(LOG_ERROR, "error starting T.38 gateway for T.38 channel %s and G.711 channel %s\n", active->name, other->name);
2788
			gateway->t38_state = T38_STATE_NEGOTIATING;
2789
			control_params->request_response = AST_T38_REQUEST_TERMINATE;
2790
2791
			fax_gateway_indicate_t38(chan, active, control_params);
2792
		} else {
2793
			gateway->t38_state = T38_STATE_NEGOTIATED;
2794
			report_fax_status(chan, details, "T.38 Negotiated");
2795
		}
2796
2797
		ao2_ref(details, -1);
2798
		return &ast_null_frame;
2799
	} else if (control_params->request_response == AST_T38_REFUSED) {
2800
		/* the other channel refused the request to negotiate T.38,
2801
		 * we'll step in here and pretend the request was accepted */
2802
2803
		ast_debug(1, "%s attempted to negotiate T.38 but %s refused the request\n", other->name, active->name);
2804
		ast_debug(1, "starting T.38 gateway for T.38 channel %s and G.711 channel %s\n", other->name, active->name);
2805
2806
		t38_parameters_fax_to_ast(control_params, &details->our_t38_parameters);
2807
2808
		if (fax_gateway_start(gateway, details, chan)) {
2809
			ast_log(LOG_ERROR, "error starting T.38 gateway for T.38 channel %s and G.711 channel %s\n", active->name, other->name);
2810
			gateway->t38_state = T38_STATE_REJECTED;
2811
			control_params->request_response = AST_T38_REFUSED;
2812
2813
			ast_framehook_detach(chan, details->gateway_id);
2814
			details->gateway_id = -1;
2815
		} else {
2816
			gateway->t38_state = T38_STATE_NEGOTIATED;
2817
			control_params->request_response = AST_T38_NEGOTIATED;
2818
		}
2819
2820
		ao2_ref(details, -1);
2821
		return f;
2822
	} else if (control_params->request_response == AST_T38_REQUEST_TERMINATE) {
2823
		/* the channel wishes to end our short relationship, we shall
2824
		 * oblige */
2825
2826
		ast_debug(1, "T.38 channel %s is requesting a shutdown of T.38, disabling the gateway\n", active->name);
2827
2828
		ast_framehook_detach(chan, details->gateway_id);
2829
		details->gateway_id = -1;
2830
2831
		gateway->t38_state = T38_STATE_REJECTED;
2832
		control_params->request_response = AST_T38_TERMINATED;
2833
2834
		fax_gateway_indicate_t38(chan, active, control_params);
2835
2836
		ao2_ref(details, -1);
2837
		return &ast_null_frame;
2838
	} else if (control_params->request_response == AST_T38_NEGOTIATED) {
2839
		ast_debug(1, "T.38 successfully negotiated between %s and %s, no gateway necessary\n", active->name, other->name);
2840
2841
		ast_framehook_detach(chan, details->gateway_id);
2842
		details->gateway_id = -1;
2843
2844
		ast_string_field_set(details, result, "SUCCESS");
2845
		ast_string_field_set(details, resultstr, "no gateway necessary");
2846
		ast_string_field_set(details, error, "NATIVE_T38");
2847
		set_channel_variables(chan, details);
2848
2849
		ao2_ref(details, -1);
2850
		return f;
2851
	} else if (control_params->request_response == AST_T38_TERMINATED) {
2852
		ast_debug(1, "T.38 disabled on channel %s\n", active->name);
2853
2854
		ast_framehook_detach(chan, details->gateway_id);
2855
		details->gateway_id = -1;
2856
2857
		ao2_ref(details, -1);
2858
		return &ast_null_frame;
2859
	}
2860
2861
	ao2_ref(details, -1);
2862
	return f;
2863
}
2864
2865
/*! \brief Destroy the gateway data structure when the framehook is detached
2866
 * \param data framehook data (gateway data)*/
2867
static void fax_gateway_framehook_destroy(void *data) {
2868
	struct fax_gateway *gateway = data;
2869
2870
	if (gateway->s) {
2871
		switch (gateway->s->state) {
2872
		case AST_FAX_STATE_INITIALIZED:
2873
		case AST_FAX_STATE_OPEN:
2874
		case AST_FAX_STATE_ACTIVE:
2875
		case AST_FAX_STATE_COMPLETE:
2876
			if (gateway->s->tech->cancel_session) {
2877
				gateway->s->tech->cancel_session(gateway->s);
2878
			}
2879
			/* fall through */
2880
		default:
2881
			break;
2882
		}
2883
	}
2884
2885
	ao2_ref(gateway, -1);
2886
}
2887
2888
/*! \brief T.30<->T.38 gateway framehook.
2889
 *
2890
 * Intercept packets on bridged channels and determine if a T.38 gateway is
2891
 * required. If a gateway is required, start a gateway and handle T.38
2892
 * negotiation if necessary.
2893
 *
2894
 * \param chan channel running the gateway
2895
 * \param f frame to handle may be NULL
2896
 * \param event framehook event
2897
 * \param data framehook data (struct fax_gateway *)
2898
 *
2899
 * \return processed frame or NULL when f is NULL or a null frame
2900
 */
2901
static struct ast_frame *fax_gateway_framehook(struct ast_channel *chan, struct ast_frame *f, enum ast_framehook_event event, void *data) {
2902
	struct fax_gateway *gateway = data;
2903
	struct ast_channel *peer, *active;
2904
	struct ast_fax_session_details *details;
2905
2906
	if (gateway->s) {
2907
		details = gateway->s->details;
2908
		ao2_ref(details, 1);
2909
	} else {
2910
		if (!(details = find_details(chan))) {
2911
			ast_log(LOG_ERROR, "no FAX session details found on chan %s for T.38 gateway session, odd\n", chan->name);
2912
			ast_framehook_detach(chan, gateway->framehook);
2913
			details->gateway_id = -1;
2914
			return f;
2915
		}
2916
	}
2917
2918
	/* restore audio formats when we are detached */
2919
	if (event == AST_FRAMEHOOK_EVENT_DETACHED) {
2920
		set_channel_variables(chan, details);
2921
2922
		if (gateway->bridged) {
2923
			ast_set_read_format(chan, gateway->chan_read_format);
2924
			ast_set_read_format(chan, gateway->chan_write_format);
2925
2926
			if ((peer = ast_bridged_channel(chan))) {
2927
				ast_set_read_format(peer, gateway->peer_read_format);
2928
				ast_set_read_format(peer, gateway->peer_write_format);
2929
				ast_channel_make_compatible(chan, peer);
2930
			}
2931
		}
2932
2933
		ao2_ref(details, -1);
2934
		return NULL;
2935
	}
2936
2937
	if (!f || (event == AST_FRAMEHOOK_EVENT_ATTACHED)) {
2938
		ao2_ref(details, -1);
2939
		return NULL;
2940
	};
2941
2942
	/* this frame was generated by the fax gateway, pass it on */
2943
	if (ast_test_flag(f, AST_FAX_FRFLAG_GATEWAY)) {
2944
		ao2_ref(details, -1);
2945
		return f;
2946
	}
2947
2948
	if (!(peer = ast_bridged_channel(chan))) {
2949
		/* not bridged, don't do anything */
2950
		ao2_ref(details, -1);
2951
		return f;
2952
	}
2953
2954
	if (!gateway->bridged && peer) {
2955
		/* don't start a gateway if neither channel can handle T.38 */
2956
		if (ast_channel_get_t38_state(chan) == T38_STATE_UNAVAILABLE && ast_channel_get_t38_state(peer) == T38_STATE_UNAVAILABLE) {
2957
			ast_debug(1, "not starting gateway for %s and %s; neither channel supports T.38\n", chan->name, peer->name);
2958
			ast_framehook_detach(chan, gateway->framehook);
2959
			details->gateway_id = -1;
2960
2961
			ast_string_field_set(details, result, "FAILED");
2962
			ast_string_field_set(details, resultstr, "neither channel supports T.38");
2963
			ast_string_field_set(details, error, "T38_NEG_ERROR");
2964
			set_channel_variables(chan, details);
2965
			ao2_ref(details, -1);
2966
			return f;
2967
		}
2968
2969
		if (details->gateway_timeout) {
2970
			gateway->timeout_start = ast_tvnow();
2971
		}
2972
2973
		/* we are bridged, change r/w formats to SLIN for v21 preamble
2974
		 * detection and T.30 */
2975
		gateway->chan_read_format = chan->readformat;
2976
		gateway->chan_write_format = chan->readformat;
2977
2978
		gateway->peer_read_format = peer->readformat;
2979
		gateway->peer_write_format = peer->readformat;
2980
2981
		ast_set_read_format(chan, AST_FORMAT_SLINEAR);
2982
		ast_set_write_format(chan, AST_FORMAT_SLINEAR);
2983
2984
		ast_set_read_format(peer, AST_FORMAT_SLINEAR);
2985
		ast_set_write_format(peer, AST_FORMAT_SLINEAR);
2986
2987
		ast_channel_make_compatible(chan, peer);
2988
		gateway->bridged = 1;
2989
	}
2990
2991
	if (gateway->bridged && !ast_tvzero(gateway->timeout_start)) {
2992
		if (ast_tvdiff_ms(ast_tvnow(), gateway->timeout_start) > details->gateway_timeout) {
2993
			ast_debug(1, "no fax activity between %s and %s after %d ms, disabling gateway\n", chan->name, peer->name, details->gateway_timeout);
2994
			ast_framehook_detach(chan, gateway->framehook);
2995
			details->gateway_id = -1;
2996
2997
			ast_string_field_set(details, result, "FAILED");
2998
			ast_string_field_build(details, resultstr, "no fax activity after %d ms", details->gateway_timeout);
2999
			ast_string_field_set(details, error, "TIMEOUT");
3000
			set_channel_variables(chan, details);
3001
			ao2_ref(details, -1);
3002
			return f;
3003
		}
3004
	}
3005
3006
	/* only handle VOICE, MODEM, and CONTROL frames*/
3007
	switch (f->frametype) {
3008
	case AST_FRAME_VOICE:
3009
		switch (f->subclass.codec) {
3010
		case AST_FORMAT_SLINEAR:
3011
		case AST_FORMAT_ALAW:
3012
		case AST_FORMAT_ULAW:
3013
			break;
3014
		default:
3015
			ao2_ref(details, -1);
3016
			return f;
3017
		}
3018
		break;
3019
	case AST_FRAME_MODEM:
3020
		if (f->subclass.integer == AST_MODEM_T38) {
3021
			break;
3022
		}
3023
		ao2_ref(details, -1);
3024
		return f;
3025
	case AST_FRAME_CONTROL:
3026
		if (f->subclass.integer == AST_CONTROL_T38_PARAMETERS) {
3027
			break;
3028
		}
3029
		ao2_ref(details, -1);
3030
		return f;
3031
	default:
3032
		ao2_ref(details, -1);
3033
		return f;
3034
	}
3035
3036
	/* detect the active channel */
3037
	switch (event) {
3038
	case AST_FRAMEHOOK_EVENT_WRITE:
3039
		active = peer;
3040
		break;
3041
	case AST_FRAMEHOOK_EVENT_READ:
3042
		active = chan;
3043
		break;
3044
	default:
3045
		ast_log(LOG_WARNING, "unhandled framehook event %i\n", event);
3046
		ao2_ref(details, -1);
3047
		return f;
3048
	}
3049
3050
	/* handle control frames */
3051
	if (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_T38_PARAMETERS) {
3052
		ao2_ref(details, -1);
3053
		return fax_gateway_detect_t38(gateway, chan, peer, active, f);
3054
	}
3055
3056
	if (!gateway->detected_v21 && gateway->t38_state == T38_STATE_UNAVAILABLE && f->frametype == AST_FRAME_VOICE) {
3057
		/* not in gateway mode and have not detected v21 yet, listen
3058
		 * for v21 */
3059
		ao2_ref(details, -1);
3060
		return fax_gateway_detect_v21(gateway, chan, peer, active, f);
3061
	}
3062
3063
	/* in gateway mode, gateway some packets */
3064
	if (gateway->t38_state == T38_STATE_NEGOTIATED) {
3065
		/* framehooks are called in __ast_read() before frame format
3066
		 * translation is done, so we need to translate here */
3067
		if ((f->frametype == AST_FRAME_VOICE) && (f->subclass.codec != AST_FORMAT_SLINEAR)) {
3068
			if (active->readtrans && (f = ast_translate(active->readtrans, f, 1)) == NULL) {
3069
				f = &ast_null_frame;
3070
				ao2_ref(details, -1);
3071
				return f;
3072
			}
3073
		}
3074
3075
		/* XXX we ignore the return value here, perhaps we should
3076
		 * disable the gateway if a write fails. I am not sure how a
3077
		 * write would fail, or even if a failure would be fatal so for
3078
		 * now we'll just ignore the return value. */
3079
		gateway->s->tech->write(gateway->s, f);
3080
		f = &ast_null_frame;
3081
		ao2_ref(details, -1);
3082
		return f;
3083
	}
3084
3085
	/* force silence on the line if T.38 negotiation might be taking place */
3086
	if (gateway->t38_state != T38_STATE_UNAVAILABLE && gateway->t38_state != T38_STATE_REJECTED) {
3087
		if (f->frametype == AST_FRAME_VOICE && f->subclass.codec == AST_FORMAT_SLINEAR) {
3088
			short silence_buf[f->samples];
3089
			struct ast_frame silence_frame = {
3090
				.frametype = AST_FRAME_VOICE,
3091
				.data.ptr = silence_buf,
3092
				.samples = f->samples,
3093
				.datalen = sizeof(silence_buf),
3094
				.subclass.codec = AST_FORMAT_SLINEAR,
3095
			};
3096
			memset(silence_buf, 0, sizeof(silence_buf));
3097
3098
			ao2_ref(details, -1);
3099
			return ast_frisolate(&silence_frame);
3100
		} else {
3101
			ao2_ref(details, -1);
3102
			return &ast_null_frame;
3103
		}
3104
	}
3105
3106
	ao2_ref(details, -1);
3107
	return f;
3108
}
3109
3110
/*! \brief Attach a gateway framehook object to a channel.
3111
 * \param chan the channel to attach to
3112
 * \param details fax session details
3113
 * \return the framehook id of the attached framehook or -1 on error
3114
 * \retval -1 error
3115
 */
3116
static int fax_gateway_attach(struct ast_channel *chan, struct ast_fax_session_details *details)
3117
{
3118
	struct fax_gateway *gateway;
3119
	struct ast_framehook_interface fr_hook = {
3120
		.version = AST_FRAMEHOOK_INTERFACE_VERSION,
3121
		.event_cb = fax_gateway_framehook,
3122
		.destroy_cb = fax_gateway_framehook_destroy,
3123
	};
3124
3125
	ast_string_field_set(details, result, "SUCCESS");
3126
	ast_string_field_set(details, resultstr, "gateway operation started successfully");
3127
	ast_string_field_set(details, error, "NO_ERROR");
3128
	set_channel_variables(chan, details);
3129
3130
	/* set up the frame hook*/
3131
	gateway = fax_gateway_new(details);
3132
	if (!gateway) {
3133
		ast_string_field_set(details, result, "FAILED");
3134
		ast_string_field_set(details, resultstr, "error initializing gateway session");
3135
		ast_string_field_set(details, error, "INIT_ERROR");
3136
		set_channel_variables(chan, details);
3137
		report_fax_status(chan, details, "No Available Resource");
3138
		return -1;
3139
	}
3140
3141
	fr_hook.data = gateway;
3142
	ast_channel_lock(chan);
3143
	gateway->framehook = ast_framehook_attach(chan, &fr_hook);
3144
	ast_channel_unlock(chan);
3145
3146
	if (gateway->framehook < 0) {
3147
		ao2_ref(gateway, -1);
3148
		ast_string_field_set(details, result, "FAILED");
3149
		ast_string_field_set(details, resultstr, "error attaching gateway to channel");
3150
		ast_string_field_set(details, error, "INIT_ERROR");
3151
		set_channel_variables(chan, details);
3152
		return -1;
3153
	}
3154
3155
	return gateway->framehook;
3156
}
3157
3158
/*! \brief Faxdetect loop used by WaitFAX
3159
 * \details Run DSP faxdetect on the channel for timeout seconds or until fax is detected
3160
 * \param chan channel to run fax detect on
3161
 * \param timeout maximum time to wait for fax detection
3162
 * \return 0 if nothing was detected 1 on CNG detected 2 if T38 negotiation is started -1 on error*/
3163
static int do_waitfax_exec(struct ast_channel *chan, int timeout, int noiselim)
3164
{
3165
	int timeleft = timeout;
3166
	int res = 0;
3167
	int dspnoise = 0;
3168
	struct ast_dsp *dsp = NULL;
3169
	struct ast_frame *f, *dup_f;
3170
	enum ast_t38_state t38state = T38_STATE_UNKNOWN;
3171
	unsigned int orig_read_format;
3172
	AST_LIST_HEAD_NOLOCK(, ast_frame) deferred_frames;
3173
3174
	/* Setup DSP CNG processing */
3175
	orig_read_format = chan->readformat;
3176
	switch (chan->readformat) {
3177
		case AST_FORMAT_SLINEAR:
3178
			break;
3179
		default:
3180
			if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
3181
				return -1;
3182
			}
3183
	}
3184
3185
	if (!(dsp = ast_dsp_new())) {
3186
		return -1;
3187
	}
3188
3189
	ast_dsp_set_features(dsp, DSP_FEATURE_FAX_DETECT);
3190
	ast_dsp_set_faxmode(dsp, DSP_FAXMODE_DETECT_CNG | DSP_FAXMODE_DETECT_SQUELCH);
3191
	ast_dsp_set_threshold(dsp, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE));
3192
3193
	AST_LIST_HEAD_INIT_NOLOCK(&deferred_frames);
3194
3195
	while ((timeleft = ast_waitfor(chan, timeleft))) {
3196
		if (!(f = ast_read(chan))) {
3197
			break;
3198
		}
3199
3200
		if (dsp && (f->frametype == AST_FRAME_VOICE) && ((f->subclass.codec == AST_FORMAT_SLINEAR) ||
3201
		    (f->subclass.codec == AST_FORMAT_ULAW) || (f->subclass.codec == AST_FORMAT_ALAW))) {
3202
			f = ast_dsp_process(chan, dsp, f);
3203
			if ((f->frametype ==  AST_FRAME_DTMF) && (f->subclass.integer == 'f')) {
3204
				res = 1;
3205
			} else if ((f->frametype == AST_FRAME_VOICE) && (noiselim > 0)) {
3206
				ast_dsp_noise(dsp, f, &dspnoise);
3207
				if (dspnoise > noiselim) {
3208
					break;
3209
				}
3210
			}
3211
		}
3212
3213
		if (ast_is_deferrable_frame(f)) {
3214
			AST_LIST_INSERT_HEAD(&deferred_frames, f, frame_list);
3215
		} else {
3216
			ast_frfree(f);
3217
		}
3218
3219
		t38state = ast_channel_get_t38_state(chan);
3220
		if ((t38state == T38_STATE_NEGOTIATING) || (t38state == T38_STATE_NEGOTIATED)) {
3221
			res = 2;
3222
			break;
3223
		} else if (res) {
3224
			break;
3225
		}
3226
	}
3227
3228
	if (orig_read_format != chan->readformat) {
3229
		ast_set_read_format(chan, orig_read_format);
3230
	}
3231
3232
	ast_channel_lock(chan);
3233
	while ((f = AST_LIST_REMOVE_HEAD(&deferred_frames, frame_list))) {
3234
		dup_f = ast_frisolate(f);
3235
		ast_queue_frame_head(chan, dup_f);
3236
		if (dup_f != f) {
3237
			ast_frfree(f);
3238
		}
3239
	}
3240
	ast_channel_unlock(chan);
3241
3242
	if (dsp) {
3243
		ast_dsp_free(dsp);
3244
	}
3245
3246
	return res;
3247
}
3248
3249
/*! \brief Alternate wait app that listens for CNG
3250
 * \details This app answers the channel and waits for CNG tone or T38 negotiation
3251
 * if the channel driver supports faxdetect it will proceed to the fax
3252
 * extension.
3253
 * it will set FAXOPT(status) and FAXOPT(statusstr) allowing dial plan processing where
3254
 * the channel does not have fax detect or the Dialplan needs to handle faxdetection
3255
 *
3256
 * \param chan channel this application is called on
3257
 * \param data the paramaters passed to the application
3258
 * \return this application will always return 0
3259
 */
3260
static int waitfax_exec(struct ast_channel *chan, const char *data)
3261
{
3262
	int res = 0;
3263
	unsigned int timeout;
3264
	unsigned int noiselim;
3265
	int ptres = -1;
3266
	char *parse;
3267
	struct ast_fax_session_details *details;
3268
	struct ast_silence_generator *silgen = NULL;
3269
	struct ast_tone_zone_sound *ts;
3270
3271
	AST_DECLARE_APP_ARGS(args,
3272
		AST_APP_ARG(timeout);
3273
		AST_APP_ARG(tone);
3274
		AST_APP_ARG(noise);
3275
	);
3276
3277
	if (!(details = find_or_create_details(chan))) {
3278
		ast_log(LOG_ERROR, "System cannot provide memory for session requirements.\n");
3279
		return 0;
3280
	}
3281
3282
	parse = ast_strdupa(data);
3283
	AST_STANDARD_APP_ARGS(args, parse);
3284
3285
	if (!ast_strlen_zero(args.timeout) && sscanf(args.timeout, "%u", &timeout) == 1) {
3286
		timeout = timeout * 1000;
3287
	} else {
3288
		timeout = 0;
3289
	}
3290
3291
	if (timeout <= 0) {
3292
		ast_string_field_set(details, result, "ERROR");
3293
		ast_string_field_set(details, resultstr, "Invalid timeout in WaitFAX");
3294
		ast_log(LOG_ERROR, "Application WaitFAX requires a valid timeout\n");
3295
		ao2_ref(details, -1);
3296
		return 0;
3297
	}
3298
3299
	if (ast_strlen_zero(args.noise) || sscanf(args.noise, "%u", &noiselim) != 1) {
3300
		noiselim = 0;
3301
	}
3302
3303
	if (chan->_state != AST_STATE_UP) {
3304
		ast_answer(chan);
3305
	}
3306
3307
	/* If no other generator is present, start tone or silencegen while waiting */
3308
	if (!chan->generatordata && !ast_strlen_zero(args.tone)) {
3309
		if ((ts = ast_get_indication_tone(chan->zone, args.tone))) {
3310
			ptres = ast_playtones_start(chan, 0, ts->data, 0);
3311
			ts = ast_tone_zone_sound_unref(ts);
3312
		} else {
3313
			ptres = ast_playtones_start(chan, 0, args.tone, 0);
3314
		}
3315
		if (!ptres && ast_opt_transmit_silence) {
3316
			silgen = ast_channel_start_silence_generator(chan);
3317
		}
3318
	} else if (ast_opt_transmit_silence && !chan->generatordata) {
3319
		silgen = ast_channel_start_silence_generator(chan);
3320
	}
3321
3322
	res = do_waitfax_exec(chan, timeout, noiselim);
3323
3324
	/* stop silgen or tones if present */
3325
	if (silgen) {
3326
		ast_channel_stop_silence_generator(chan, silgen);
3327
	} else if (!ptres) {
3328
		ast_playtones_stop(chan);
3329
	}
3330
3331
	if (res > 0) {
3332
		ast_string_field_set(details, result, "SUCCESS");
3333
		if (res == 1) {
3334
			ast_string_field_set(details, resultstr, "CNG");
3335
		} else {
3336
			ast_string_field_set(details, resultstr, "T38");
3337
		}
3338
	} else if (res < 0) {
3339
		ast_string_field_set(details, result, "ERROR");
3340
		ast_string_field_set(details, resultstr, "DSP Error WaitFAX Failed");
3341
	} else {
3342
		ast_string_field_set(details, result, "FAILED");
3343
		ast_string_field_set(details, resultstr, "No CNG Tone Or T38 Detected");
3344
	}
3345
3346
	ao2_ref(details, -1);
3347
	return 0;
3348
}
3349
3350
2290
/*! \brief hash callback for ao2 */
3351
/*! \brief hash callback for ao2 */
2291
static int session_hash_cb(const void *obj, const int flags)
3352
static int session_hash_cb(const void *obj, const int flags)
2292
{
3353
{
Lines 2558-2576 Link Here
2558
	while ((s = ao2_iterator_next(&i))) {
3619
	while ((s = ao2_iterator_next(&i))) {
2559
		ao2_lock(s);
3620
		ao2_lock(s);
2560
3621
2561
		if (!(filenames = generate_filenames_string(s->details, "", ", "))) {
3622
		filenames = generate_filenames_string(s->details, "", ", ");
2562
			ast_log(LOG_ERROR, "error printing filenames for 'fax show sessions' command");
2563
			ao2_unlock(s);
2564
			ao2_ref(s, -1);
2565
			ao2_iterator_destroy(&i);
2566
			return CLI_FAILURE;
2567
		}
2568
3623
2569
		ast_cli(a->fd, "%-20.20s %-10.10s %-10d %-5.5s %-10.10s %-15.15s %-30s\n",
3624
		ast_cli(a->fd, "%-20.20s %-10.10s %-10d %-5.5s %-10.10s %-15.15s %-30s\n",
2570
			s->channame, s->tech->type, s->id,
3625
			s->channame, s->tech->type, s->id,
2571
			(s->details->caps & AST_FAX_TECH_AUDIO) ? "G.711" : "T.38",
3626
			(s->details->caps & AST_FAX_TECH_AUDIO) ? "G.711" : "T.38",
2572
			(s->details->caps & AST_FAX_TECH_SEND) ? "send" : "receive",
3627
			(s->details->caps & AST_FAX_TECH_GATEWAY)
2573
			ast_fax_state_to_str(s->state), filenames);
3628
				? "gateway"
3629
				: (s->details->caps & AST_FAX_TECH_SEND) ? "send" : "receive",
3630
			ast_fax_state_to_str(s->state), S_OR(filenames, ""));
2574
3631
2575
		ast_free(filenames);
3632
		ast_free(filenames);
2576
		ao2_unlock(s);
3633
		ao2_unlock(s);
Lines 2689-2694 Link Here
2689
	}
3746
	}
2690
	if (!strcasecmp(data, "ecm")) {
3747
	if (!strcasecmp(data, "ecm")) {
2691
		ast_copy_string(buf, details->option.ecm ? "yes" : "no", len);
3748
		ast_copy_string(buf, details->option.ecm ? "yes" : "no", len);
3749
	} else if (!strcasecmp(data, "t38gateway") || !strcasecmp(data, "gateway") ||
3750
		   !strcasecmp(data, "t38_gateway") || !strcasecmp(data, "faxgateway")) {
3751
		ast_copy_string(buf, details->gateway_id != -1 ? "yes" : "no", len);
2692
	} else if (!strcasecmp(data, "error")) {
3752
	} else if (!strcasecmp(data, "error")) {
2693
		ast_copy_string(buf, details->error, len);
3753
		ast_copy_string(buf, details->error, len);
2694
	} else if (!strcasecmp(data, "filename")) {
3754
	} else if (!strcasecmp(data, "filename")) {
Lines 2763-2768 Link Here
2763
		} else {
3823
		} else {
2764
			ast_log(LOG_WARNING, "Unsupported value '%s' passed to FAXOPT(ecm).\n", value);
3824
			ast_log(LOG_WARNING, "Unsupported value '%s' passed to FAXOPT(ecm).\n", value);
2765
		}
3825
		}
3826
	} else if (!strcasecmp(data, "t38gateway") || !strcasecmp(data, "gateway") ||
3827
		   !strcasecmp(data, "t38_gateway") || !strcasecmp(data, "faxgateway")) {
3828
		const char *val = ast_skip_blanks(value);
3829
		char *timeout = strchr(val, ',');
3830
3831
		if (timeout) {
3832
			*timeout++ = '\0';
3833
		}
3834
3835
		if (ast_true(val)) {
3836
			if (details->gateway_id < 0) {
3837
				details->gateway_timeout = 0;
3838
				if (timeout) {
3839
					unsigned int gwtimeout;
3840
					if (sscanf(timeout, "%u", &gwtimeout) == 1) {
3841
						details->gateway_timeout = gwtimeout * 1000;
3842
					} else {
3843
						ast_log(LOG_WARNING, "Unsupported timeout '%s' passed to FAXOPT(%s).\n", timeout, data);
3844
					}
3845
				}
3846
3847
				details->gateway_id = fax_gateway_attach(chan, details);
3848
				if (details->gateway_id < 0) {
3849
					ast_log(LOG_ERROR, "Error attaching T.38 gateway to channel %s.\n", chan->name);
3850
					res = -1;
3851
				} else {
3852
					ast_debug(1, "Attached T.38 gateway to channel %s.\n", chan->name);
3853
				}
3854
			} else {
3855
				ast_log(LOG_WARNING, "Attempt to attach a T.38 gateway on channel (%s) with gateway already running.\n", chan->name);
3856
			}
3857
		} else if (ast_false(val)) {
3858
			ast_framehook_detach(chan, details->gateway_id);
3859
			details->gateway_id = -1;
3860
		} else {
3861
			ast_log(LOG_WARNING, "Unsupported value '%s' passed to FAXOPT(%s).\n", value, data);
3862
		}
2766
	} else if (!strcasecmp(data, "headerinfo")) {
3863
	} else if (!strcasecmp(data, "headerinfo")) {
2767
		ast_string_field_set(details, headerinfo, value);
3864
		ast_string_field_set(details, headerinfo, value);
2768
	} else if (!strcasecmp(data, "localstationid")) {
3865
	} else if (!strcasecmp(data, "localstationid")) {
Lines 2813-2818 Link Here
2813
		ast_log(LOG_WARNING, "failed to unregister '%s'\n", app_receivefax);
3910
		ast_log(LOG_WARNING, "failed to unregister '%s'\n", app_receivefax);
2814
	}
3911
	}
2815
3912
3913
	if (ast_unregister_application(app_waitfax) < 0) {
3914
		ast_log(LOG_WARNING, "failed to unregister '%s'\n", app_waitfax);
3915
	}
3916
2816
	if (fax_logger_level != -1) {
3917
	if (fax_logger_level != -1) {
2817
		ast_logger_unregister_level("FAX");
3918
		ast_logger_unregister_level("FAX");
2818
	}
3919
	}
Lines 2852-2859 Link Here
2852
		ao2_ref(faxregistry.container, -1);
3953
		ao2_ref(faxregistry.container, -1);
2853
		return AST_MODULE_LOAD_DECLINE;
3954
		return AST_MODULE_LOAD_DECLINE;
2854
	}
3955
	}
3956
3957
	if (ast_register_application_xml(app_waitfax, waitfax_exec) < 0) {
3958
		ast_log(LOG_WARNING, "failed to register '%s'.\n", app_waitfax);
3959
	}
3960
2855
	ast_cli_register_multiple(fax_cli, ARRAY_LEN(fax_cli));
3961
	ast_cli_register_multiple(fax_cli, ARRAY_LEN(fax_cli));
2856
	res = ast_custom_function_register(&acf_faxopt);	
3962
	res = ast_custom_function_register(&acf_faxopt);
2857
	fax_logger_level = ast_logger_register_level("FAX");
3963
	fax_logger_level = ast_logger_register_level("FAX");
2858
3964
2859
	return res;
3965
	return res;
(-)res/res_fax_spandsp.c (-30 / +287 lines)
Lines 5-10 Link Here
5
 *
5
 *
6
 * Matthew Nicholson <mnicholson@digium.com>
6
 * Matthew Nicholson <mnicholson@digium.com>
7
 *
7
 *
8
 * Initial T.38-gateway code
9
 * 2008, Daniel Ferenci <daniel.ferenci@nethemba.com>
10
 * Created by Nethemba s.r.o. http://www.nethemba.com
11
 * Sponsored by IPEX a.s. http://www.ipex.cz
12
 *
13
 * T.38-gateway integration into asterisk app_fax and rework
14
 * 2008, Gregory Hinton Nietsky <gregory@dnstelecom.co.za>
15
 * dns Telecom http://www.dnstelecom.co.za
16
 *
17
 * Modified to make T.38-gateway compatible with Asterisk 1.6.2
18
 * 2010, Anton Verevkin <mymail@verevkin.it>
19
 * ViaNetTV http://www.vianettv.com
20
 *
21
 * Modified to make T.38-gateway work
22
 * 2010, Klaus Darilion, IPCom GmbH, www.ipcom.at
23
 *
8
 * See http://www.asterisk.org for more information about
24
 * See http://www.asterisk.org for more information about
9
 * the Asterisk project. Please do not directly contact
25
 * the Asterisk project. Please do not directly contact
10
 * any of the maintainers of this project for assistance;
26
 * any of the maintainers of this project for assistance;
Lines 21-26 Link Here
21
 * \brief Spandsp T.38 and G.711 FAX Resource
37
 * \brief Spandsp T.38 and G.711 FAX Resource
22
 *
38
 *
23
 * \author Matthew Nicholson <mnicholson@digium.com>
39
 * \author Matthew Nicholson <mnicholson@digium.com>
40
 * \author Gregory H. Nietsky <gregory@distrotech.co.za>
24
 *
41
 *
25
 * This module registers the Spandsp FAX technology with the res_fax module.
42
 * This module registers the Spandsp FAX technology with the res_fax module.
26
 */
43
 */
Lines 47-55 Link Here
47
#include "asterisk/timing.h"
64
#include "asterisk/timing.h"
48
#include "asterisk/astobj2.h"
65
#include "asterisk/astobj2.h"
49
#include "asterisk/res_fax.h"
66
#include "asterisk/res_fax.h"
67
#include "asterisk/channel.h"
50
68
51
#define SPANDSP_FAX_SAMPLES 160
69
#define SPANDSP_FAX_SAMPLES 160
52
#define SPANDSP_FAX_TIMER_RATE 8000 / SPANDSP_FAX_SAMPLES	/* 50 ticks per second, 20ms, 160 samples per second */
70
#define SPANDSP_FAX_TIMER_RATE 8000 / SPANDSP_FAX_SAMPLES	/* 50 ticks per second, 20ms, 160 samples per second */
71
#define SPANDSP_ENGAGE_UDPTL_NAT_RETRY 3
53
72
54
static void *spandsp_fax_new(struct ast_fax_session *s, struct ast_fax_tech_token *token);
73
static void *spandsp_fax_new(struct ast_fax_session *s, struct ast_fax_tech_token *token);
55
static void spandsp_fax_destroy(struct ast_fax_session *s);
74
static void spandsp_fax_destroy(struct ast_fax_session *s);
Lines 58-63 Link Here
58
static int spandsp_fax_start(struct ast_fax_session *s);
77
static int spandsp_fax_start(struct ast_fax_session *s);
59
static int spandsp_fax_cancel(struct ast_fax_session *s);
78
static int spandsp_fax_cancel(struct ast_fax_session *s);
60
static int spandsp_fax_switch_to_t38(struct ast_fax_session *s);
79
static int spandsp_fax_switch_to_t38(struct ast_fax_session *s);
80
static int spandsp_fax_gateway_start(struct ast_fax_session *s);
81
static int spandsp_fax_gateway_process(struct ast_fax_session *s, const struct ast_frame *f);
82
static void spandsp_fax_gateway_cleanup(struct ast_fax_session *s);
61
83
62
static char *spandsp_fax_cli_show_capabilities(int fd);
84
static char *spandsp_fax_cli_show_capabilities(int fd);
63
static char *spandsp_fax_cli_show_session(struct ast_fax_session *s, int fd);
85
static char *spandsp_fax_cli_show_session(struct ast_fax_session *s, int fd);
Lines 76-82 Link Here
76
	 */
98
	 */
77
	.version = "pre-20090220",
99
	.version = "pre-20090220",
78
#endif
100
#endif
79
	.caps = AST_FAX_TECH_AUDIO | AST_FAX_TECH_T38 | AST_FAX_TECH_SEND | AST_FAX_TECH_RECEIVE,
101
	.caps = AST_FAX_TECH_AUDIO | AST_FAX_TECH_T38 | AST_FAX_TECH_SEND | AST_FAX_TECH_RECEIVE | AST_FAX_TECH_GATEWAY,
80
	.new_session = spandsp_fax_new,
102
	.new_session = spandsp_fax_new,
81
	.destroy_session = spandsp_fax_destroy,
103
	.destroy_session = spandsp_fax_destroy,
82
	.read = spandsp_fax_read,
104
	.read = spandsp_fax_read,
Lines 115-120 Link Here
115
struct spandsp_pvt {
137
struct spandsp_pvt {
116
	unsigned int ist38:1;
138
	unsigned int ist38:1;
117
	unsigned int isdone:1;
139
	unsigned int isdone:1;
140
	enum ast_t38_state ast_t38_state;
118
	fax_state_t fax_state;
141
	fax_state_t fax_state;
119
	t38_terminal_state_t t38_state;
142
	t38_terminal_state_t t38_state;
120
	t30_state_t *t30_state;
143
	t30_state_t *t30_state;
Lines 122-127 Link Here
122
145
123
	struct spandsp_fax_stats *stats;
146
	struct spandsp_fax_stats *stats;
124
147
148
	struct spandsp_fax_gw_stats *t38stats;
149
	t38_gateway_state_t t38_gw_state;
150
125
	struct ast_timer *timer;
151
	struct ast_timer *timer;
126
	AST_LIST_HEAD(frame_queue, ast_frame) read_frames;
152
	AST_LIST_HEAD(frame_queue, ast_frame) read_frames;
127
};
153
};
Lines 159-165 Link Here
159
 */
185
 */
160
static int t38_tx_packet_handler(t38_core_state_t *t38_core_state, void *data, const uint8_t *buf, int len, int count)
186
static int t38_tx_packet_handler(t38_core_state_t *t38_core_state, void *data, const uint8_t *buf, int len, int count)
161
{
187
{
162
	struct spandsp_pvt *p = data;
188
	int res = -1;
189
	struct ast_fax_session *s = data;
190
	struct spandsp_pvt *p = s->tech_pvt;
163
	struct ast_frame fax_frame = {
191
	struct ast_frame fax_frame = {
164
		.frametype = AST_FRAME_MODEM,
192
		.frametype = AST_FRAME_MODEM,
165
		.subclass.integer = AST_MODEM_T38,
193
		.subclass.integer = AST_MODEM_T38,
Lines 175-187 Link Here
175
	AST_FRAME_SET_BUFFER(f, buf, 0, len);
203
	AST_FRAME_SET_BUFFER(f, buf, 0, len);
176
204
177
	if (!(f = ast_frisolate(f))) {
205
	if (!(f = ast_frisolate(f))) {
178
		return -1;
206
		return res;
179
	}
207
	}
180
208
181
	/* no need to lock, this all runs in the same thread */
209
	if (s->details->caps & AST_FAX_TECH_GATEWAY) {
182
	AST_LIST_INSERT_TAIL(&p->read_frames, f, frame_list);
210
		ast_set_flag(f, AST_FAX_FRFLAG_GATEWAY);
211
		if (p->ast_t38_state == T38_STATE_NEGOTIATED) {
212
			res = ast_write(s->chan, f);
213
		} else {
214
			res = ast_queue_frame(s->chan, f);
215
		}
216
		ast_frfree(f);
217
	} else {
218
		/* no need to lock, this all runs in the same thread */
219
		AST_LIST_INSERT_TAIL(&p->read_frames, f, frame_list);
220
	}
183
221
184
	return 0;
222
	return res;
185
}
223
}
186
224
187
static int update_stats(struct spandsp_pvt *p, int completion_code)
225
static int update_stats(struct spandsp_pvt *p, int completion_code)
Lines 423-428 Link Here
423
		goto e_return;
461
		goto e_return;
424
	}
462
	}
425
463
464
	if (s->details->caps & AST_FAX_TECH_GATEWAY) {
465
		s->state = AST_FAX_STATE_INITIALIZED;
466
		return p;
467
	}
468
426
	AST_LIST_HEAD_INIT(&p->read_frames);
469
	AST_LIST_HEAD_INIT(&p->read_frames);
427
470
428
	if (s->details->caps & AST_FAX_TECH_RECEIVE) {
471
	if (s->details->caps & AST_FAX_TECH_RECEIVE) {
Lines 451-457 Link Here
451
		}
494
		}
452
495
453
		/* init t38 stuff */
496
		/* init t38 stuff */
454
		t38_terminal_init(&p->t38_state, caller_mode, t38_tx_packet_handler, p);
497
		t38_terminal_init(&p->t38_state, caller_mode, t38_tx_packet_handler, s);
455
		set_logging(&p->t38_state.logging, s->details);
498
		set_logging(&p->t38_state.logging, s->details);
456
	}
499
	}
457
500
Lines 476-482 Link Here
476
{
519
{
477
	struct spandsp_pvt *p = s->tech_pvt;
520
	struct spandsp_pvt *p = s->tech_pvt;
478
521
479
	session_destroy(p);
522
	if (s->details->caps & AST_FAX_TECH_GATEWAY) {
523
		spandsp_fax_gateway_cleanup(s);
524
	} else {
525
		session_destroy(p);
526
	}
527
480
	ast_free(p);
528
	ast_free(p);
481
	s->tech_pvt = NULL;
529
	s->tech_pvt = NULL;
482
	s->fd = -1;
530
	s->fd = -1;
Lines 496-502 Link Here
496
		.subclass.codec = AST_FORMAT_SLINEAR,
544
		.subclass.codec = AST_FORMAT_SLINEAR,
497
		.src = "res_fax_spandsp_g711",
545
		.src = "res_fax_spandsp_g711",
498
	};
546
	};
499
500
	struct ast_frame *f = &fax_frame;
547
	struct ast_frame *f = &fax_frame;
501
548
502
	ast_timer_ack(p->timer, 1);
549
	ast_timer_ack(p->timer, 1);
Lines 538-543 Link Here
538
{
585
{
539
	struct spandsp_pvt *p = s->tech_pvt;
586
	struct spandsp_pvt *p = s->tech_pvt;
540
587
588
	if (s->details->caps & AST_FAX_TECH_GATEWAY) {
589
		return spandsp_fax_gateway_process(s, f);
590
	}
591
541
	/* XXX do we need to lock here? */
592
	/* XXX do we need to lock here? */
542
	if (s->state == AST_FAX_STATE_COMPLETE) {
593
	if (s->state == AST_FAX_STATE_COMPLETE) {
543
		ast_log(LOG_WARNING, "FAX session '%d' is in the '%s' state.\n", s->id, ast_fax_state_to_str(s->state));
594
		ast_log(LOG_WARNING, "FAX session '%d' is in the '%s' state.\n", s->id, ast_fax_state_to_str(s->state));
Lines 551-556 Link Here
551
	}
602
	}
552
}
603
}
553
604
605
/*! \brief generate T.30 packets sent to the T.30 leg of gateway
606
 * \param chan T.30 channel
607
 * \param data fax session structure
608
 * \param len not used
609
 * \param samples no of samples generated
610
 * \return -1 on failure or 0 on sucess*/
611
static int spandsp_fax_gw_t30_gen(struct ast_channel *chan, void *data, int len, int samples)
612
{
613
	int res = -1;
614
	struct ast_fax_session *s = data;
615
	struct spandsp_pvt *p = s->tech_pvt;
616
	uint8_t buffer[AST_FRIENDLY_OFFSET + samples * sizeof(uint16_t)];
617
	struct ast_frame *f;
618
	struct ast_frame t30_frame = {
619
		.frametype = AST_FRAME_VOICE,
620
		.subclass.codec = AST_FORMAT_SLINEAR,
621
		.src = "res_fax_spandsp_g711",
622
		.samples = samples,
623
		.flags = AST_FAX_FRFLAG_GATEWAY,
624
	};
625
626
	AST_FRAME_SET_BUFFER(&t30_frame, buffer, AST_FRIENDLY_OFFSET, t30_frame.samples * sizeof(int16_t));
627
628
	if (!(f = ast_frisolate(&t30_frame))) {
629
		return p->isdone ? -1 : res;
630
	}
631
632
	/* generate a T.30 packet */
633
	if ((f->samples = t38_gateway_tx(&p->t38_gw_state, f->data.ptr, f->samples))) {
634
		f->datalen = f->samples * sizeof(int16_t);
635
		res = ast_write(chan, f);
636
	}
637
	ast_frfree(f);
638
	return p->isdone ? -1 : res;
639
}
640
641
/*! \brief simple routine to allocate data to generator
642
 * \param chan channel
643
 * \param params generator data
644
 * \return data to use in generator call*/
645
static void *spandsp_fax_gw_gen_alloc(struct ast_channel *chan, void *params) {
646
	ao2_ref(params, +1);
647
	return params;
648
}
649
650
static void spandsp_fax_gw_gen_release(struct ast_channel *chan, void *data) {
651
	ao2_ref(data, -1);
652
}
653
654
/*! \brief activate a spandsp gateway based on the information in the given fax session
655
 * \param s fax session
656
 * \return -1 on error 0 on sucess*/
657
static int spandsp_fax_gateway_start(struct ast_fax_session *s) {
658
	struct spandsp_pvt *p = s->tech_pvt;
659
	struct ast_fax_t38_parameters *t38_param;
660
	int i, modems = 0;
661
	struct ast_channel *peer;
662
	static struct ast_generator t30_gen = {
663
		alloc: spandsp_fax_gw_gen_alloc,
664
		release: spandsp_fax_gw_gen_release,
665
		generate: spandsp_fax_gw_t30_gen,
666
	};
667
668
#if SPANDSP_RELEASE_DATE >= 20081012
669
	/* for spandsp shaphots 0.0.6 and higher */
670
	p->t38_core_state=&p->t38_gw_state.t38x.t38;
671
#else
672
	/* for spandsp release 0.0.5 */
673
	p->t38_core_state=&p->t38_gw_state.t38;
674
#endif
675
676
	if (!t38_gateway_init(&p->t38_gw_state, t38_tx_packet_handler, s)) {
677
		return -1;
678
	}
679
680
	p->ist38 = 1;
681
	p->ast_t38_state = ast_channel_get_t38_state(s->chan);
682
	if (!(peer = ast_bridged_channel(s->chan))) {
683
		ast_channel_unlock(s->chan);
684
		return -1;
685
	}
686
687
	/* we can be in T38_STATE_NEGOTIATING or T38_STATE_NEGOTIATED when the
688
	 * gateway is started. We treat both states the same. */
689
	if (p->ast_t38_state == T38_STATE_NEGOTIATING) {
690
		p->ast_t38_state = T38_STATE_NEGOTIATED;
691
	}
692
693
	ast_activate_generator(p->ast_t38_state == T38_STATE_NEGOTIATED ? peer : s->chan, &t30_gen , s);
694
695
	set_logging(&p->t38_gw_state.logging, s->details);
696
	set_logging(&p->t38_core_state->logging, s->details);
697
698
	t38_param = (p->ast_t38_state == T38_STATE_NEGOTIATED) ? &s->details->our_t38_parameters : &s->details->their_t38_parameters;
699
	t38_set_t38_version(p->t38_core_state, t38_param->version);
700
	t38_gateway_set_ecm_capability(&p->t38_gw_state, s->details->option.ecm);
701
	t38_set_max_datagram_size(p->t38_core_state, t38_param->max_ifp);
702
	t38_set_fill_bit_removal(p->t38_core_state, t38_param->fill_bit_removal);
703
	t38_set_mmr_transcoding(p->t38_core_state, t38_param->transcoding_mmr);
704
	t38_set_jbig_transcoding(p->t38_core_state, t38_param->transcoding_jbig);
705
	t38_set_data_rate_management_method(p->t38_core_state, 
706
			(t38_param->rate_management == AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF)? 1 : 2);
707
708
	t38_gateway_set_transmit_on_idle(&p->t38_gw_state, TRUE);
709
	t38_set_sequence_number_handling(p->t38_core_state, TRUE);
710
711
	if (AST_FAX_MODEM_V17 & s->details->modems) {
712
		modems |= T30_SUPPORT_V17;
713
	}
714
	if (AST_FAX_MODEM_V27 & s->details->modems) {
715
		modems |= T30_SUPPORT_V27TER;
716
	}
717
	if (AST_FAX_MODEM_V29 & s->details->modems) {
718
		modems |= T30_SUPPORT_V29;
719
	}
720
	if (AST_FAX_MODEM_V34 & s->details->modems) {
721
#if defined(T30_SUPPORT_V34)
722
		modems |= T30_SUPPORT_V34;
723
#elif defined(T30_SUPPORT_V34HDX)
724
		modems |= T30_SUPPORT_V34HDX;
725
#else
726
		ast_log(LOG_WARNING, "v34 not supported in this version of spandsp\n");
727
#endif
728
	}
729
730
	t38_gateway_set_supported_modems(&p->t38_gw_state, modems);
731
732
	/* engage udptl nat on other side of T38 line 
733
	 * (Asterisk changes media ports thus we send a few packets to reinitialize
734
	 * pinholes in NATs and FWs
735
	 */
736
	for (i=0; i < SPANDSP_ENGAGE_UDPTL_NAT_RETRY; i++) {
737
#if SPANDSP_RELEASE_DATE >= 20091228
738
		t38_core_send_indicator(&p->t38_gw_state.t38x.t38, T38_IND_NO_SIGNAL);
739
#elif SPANDSP_RELEASE_DATE >= 20081012
740
		t38_core_send_indicator(&p->t38_gw_state.t38x.t38, T38_IND_NO_SIGNAL, p->t38_gw_state.t38x.t38.indicator_tx_count);
741
#else
742
		t38_core_send_indicator(&p->t38_gw_state.t38, T38_IND_NO_SIGNAL, p->t38_gw_state.t38.indicator_tx_count);
743
#endif
744
	}
745
746
	s->state = AST_FAX_STATE_ACTIVE;
747
748
	return 0;
749
}
750
751
/*! \brief process a frame from the bridge
752
 * \param s fax session
753
 * \param f frame to process
754
 * \return 1 on sucess 0 on incorect packet*/
755
static int spandsp_fax_gateway_process(struct ast_fax_session *s, const struct ast_frame *f)
756
{
757
	struct spandsp_pvt *p = s->tech_pvt;
758
759
	/*invalid frame*/
760
	if (!f->data.ptr || !f->datalen) {
761
		return -1;
762
	}
763
764
	/* Process a IFP packet */
765
	if ((f->frametype == AST_FRAME_MODEM) && (f->subclass.integer == AST_MODEM_T38)) {
766
		return t38_core_rx_ifp_packet(p->t38_core_state, f->data.ptr, f->datalen, f->seqno);
767
	} else if ((f->frametype == AST_FRAME_VOICE) && (f->subclass.codec == AST_FORMAT_SLINEAR)) {
768
		return t38_gateway_rx(&p->t38_gw_state, f->data.ptr, f->samples);
769
	}
770
771
	return -1;
772
}
773
774
/*! \brief gather data and clean up after gateway ends
775
 * \param s fax session*/
776
static void spandsp_fax_gateway_cleanup(struct ast_fax_session *s)
777
{
778
	struct spandsp_pvt *p = s->tech_pvt;
779
	t38_stats_t t38_stats;
780
781
	t38_gateway_get_transfer_statistics(&p->t38_gw_state, &t38_stats);
782
783
	s->details->option.ecm = t38_stats.error_correcting_mode ? AST_FAX_OPTFLAG_TRUE : AST_FAX_OPTFLAG_FALSE;
784
	s->details->pages_transferred = t38_stats.pages_transferred;
785
	ast_string_field_build(s->details, transfer_rate, "%d", t38_stats.bit_rate);
786
}
787
554
/*! \brief */
788
/*! \brief */
555
static int spandsp_fax_start(struct ast_fax_session *s)
789
static int spandsp_fax_start(struct ast_fax_session *s)
556
{
790
{
Lines 558-563 Link Here
558
792
559
	s->state = AST_FAX_STATE_OPEN;
793
	s->state = AST_FAX_STATE_OPEN;
560
794
795
	if (s->details->caps & AST_FAX_TECH_GATEWAY) {
796
		return spandsp_fax_gateway_start(s);
797
	}
798
561
	if (p->ist38) {
799
	if (p->ist38) {
562
#if SPANDSP_RELEASE_DATE >= 20080725
800
#if SPANDSP_RELEASE_DATE >= 20080725
563
		/* for spandsp shaphots 0.0.6 and higher */
801
		/* for spandsp shaphots 0.0.6 and higher */
Lines 627-632 Link Here
627
static int spandsp_fax_cancel(struct ast_fax_session *s)
865
static int spandsp_fax_cancel(struct ast_fax_session *s)
628
{
866
{
629
	struct spandsp_pvt *p = s->tech_pvt;
867
	struct spandsp_pvt *p = s->tech_pvt;
868
869
	if (s->details->caps & AST_FAX_TECH_GATEWAY) {
870
		p->isdone = 1;
871
		return 0;
872
	}
873
630
	t30_terminate(p->t30_state);
874
	t30_terminate(p->t30_state);
631
	p->isdone = 1;
875
	p->isdone = 1;
632
	return 0;
876
	return 0;
Lines 655-661 Link Here
655
/*! \brief */
899
/*! \brief */
656
static char *spandsp_fax_cli_show_capabilities(int fd)
900
static char *spandsp_fax_cli_show_capabilities(int fd)
657
{
901
{
658
	ast_cli(fd, "SEND RECEIVE T.38 G.711\n\n");
902
	ast_cli(fd, "SEND RECEIVE T.38 G.711 GATEWAY\n\n");
659
	return  CLI_SUCCESS;
903
	return  CLI_SUCCESS;
660
}
904
}
661
905
Lines 663-697 Link Here
663
static char *spandsp_fax_cli_show_session(struct ast_fax_session *s, int fd)
907
static char *spandsp_fax_cli_show_session(struct ast_fax_session *s, int fd)
664
{
908
{
665
	struct spandsp_pvt *p = s->tech_pvt;
909
	struct spandsp_pvt *p = s->tech_pvt;
666
	t30_stats_t stats;
667
910
668
	ao2_lock(s);
911
	ao2_lock(s);
669
	ast_cli(fd, "%-22s : %d\n", "session", s->id);
912
	if (s->details->caps & AST_FAX_TECH_GATEWAY) {
670
	ast_cli(fd, "%-22s : %s\n", "operation", (s->details->caps & AST_FAX_TECH_RECEIVE) ? "Receive" : "Transmit");
913
		ast_cli(fd, "%-22s : %d\n", "session", s->id);
671
	ast_cli(fd, "%-22s : %s\n", "state", ast_fax_state_to_str(s->state));
914
		ast_cli(fd, "%-22s : %s\n", "operation", "Gateway");
672
	if (s->state != AST_FAX_STATE_UNINITIALIZED) {
915
		ast_cli(fd, "%-22s : %s\n", "state", ast_fax_state_to_str(s->state));
673
		t30_get_transfer_statistics(p->t30_state, &stats);
916
		if (s->state != AST_FAX_STATE_UNINITIALIZED) {
674
		ast_cli(fd, "%-22s : %s\n", "Last Status", t30_completion_code_to_str(stats.current_status));
917
			t38_stats_t stats;
675
		ast_cli(fd, "%-22s : %s\n", "ECM Mode", stats.error_correcting_mode ? "Yes" : "No");
918
			t38_gateway_get_transfer_statistics(&p->t38_gw_state, &stats);
676
		ast_cli(fd, "%-22s : %d\n", "Data Rate", stats.bit_rate);
919
			ast_cli(fd, "%-22s : %s\n", "ECM Mode", stats.error_correcting_mode ? "Yes" : "No");
677
		ast_cli(fd, "%-22s : %dx%d\n", "Image Resolution", stats.x_resolution, stats.y_resolution);
920
			ast_cli(fd, "%-22s : %d\n", "Data Rate", stats.bit_rate);
921
			ast_cli(fd, "%-22s : %d\n", "Page Number", stats.pages_transferred + 1);
922
		}
923
	} else {
924
		ast_cli(fd, "%-22s : %d\n", "session", s->id);
925
		ast_cli(fd, "%-22s : %s\n", "operation", (s->details->caps & AST_FAX_TECH_RECEIVE) ? "Receive" : "Transmit");
926
		ast_cli(fd, "%-22s : %s\n", "state", ast_fax_state_to_str(s->state));
927
		if (s->state != AST_FAX_STATE_UNINITIALIZED) {
928
			t30_stats_t stats;
929
			t30_get_transfer_statistics(p->t30_state, &stats);
930
			ast_cli(fd, "%-22s : %s\n", "Last Status", t30_completion_code_to_str(stats.current_status));
931
			ast_cli(fd, "%-22s : %s\n", "ECM Mode", stats.error_correcting_mode ? "Yes" : "No");
932
			ast_cli(fd, "%-22s : %d\n", "Data Rate", stats.bit_rate);
933
			ast_cli(fd, "%-22s : %dx%d\n", "Image Resolution", stats.x_resolution, stats.y_resolution);
678
#if SPANDSP_RELEASE_DATE >= 20090220
934
#if SPANDSP_RELEASE_DATE >= 20090220
679
		ast_cli(fd, "%-22s : %d\n", "Page Number", ((s->details->caps & AST_FAX_TECH_RECEIVE) ? stats.pages_rx : stats.pages_tx) + 1);
935
			ast_cli(fd, "%-22s : %d\n", "Page Number", ((s->details->caps & AST_FAX_TECH_RECEIVE) ? stats.pages_rx : stats.pages_tx) + 1);
680
#else
936
#else
681
		ast_cli(fd, "%-22s : %d\n", "Page Number", stats.pages_transferred + 1);
937
			ast_cli(fd, "%-22s : %d\n", "Page Number", stats.pages_transferred + 1);
682
#endif
938
#endif
683
		ast_cli(fd, "%-22s : %s\n", "File Name", s->details->caps & AST_FAX_TECH_RECEIVE ? p->t30_state->rx_file : p->t30_state->tx_file);
939
			ast_cli(fd, "%-22s : %s\n", "File Name", s->details->caps & AST_FAX_TECH_RECEIVE ? p->t30_state->rx_file : p->t30_state->tx_file);
684
940
685
		ast_cli(fd, "\nData Statistics:\n");
941
			ast_cli(fd, "\nData Statistics:\n");
686
#if SPANDSP_RELEASE_DATE >= 20090220
942
#if SPANDSP_RELEASE_DATE >= 20090220
687
		ast_cli(fd, "%-22s : %d\n", "Tx Pages", stats.pages_tx);
943
			ast_cli(fd, "%-22s : %d\n", "Tx Pages", stats.pages_tx);
688
		ast_cli(fd, "%-22s : %d\n", "Rx Pages", stats.pages_rx);
944
			ast_cli(fd, "%-22s : %d\n", "Rx Pages", stats.pages_rx);
689
#else
945
#else
690
		ast_cli(fd, "%-22s : %d\n", "Tx Pages", (s->details->caps & AST_FAX_TECH_SEND) ? stats.pages_transferred : 0);
946
			ast_cli(fd, "%-22s : %d\n", "Tx Pages", (s->details->caps & AST_FAX_TECH_SEND) ? stats.pages_transferred : 0);
691
		ast_cli(fd, "%-22s : %d\n", "Rx Pages", (s->details->caps & AST_FAX_TECH_RECEIVE) ? stats.pages_transferred : 0);
947
			ast_cli(fd, "%-22s : %d\n", "Rx Pages", (s->details->caps & AST_FAX_TECH_RECEIVE) ? stats.pages_transferred : 0);
692
#endif
948
#endif
693
		ast_cli(fd, "%-22s : %d\n", "Longest Bad Line Run", stats.longest_bad_row_run);
949
			ast_cli(fd, "%-22s : %d\n", "Longest Bad Line Run", stats.longest_bad_row_run);
694
		ast_cli(fd, "%-22s : %d\n", "Total Bad Lines", stats.bad_rows);
950
			ast_cli(fd, "%-22s : %d\n", "Total Bad Lines", stats.bad_rows);
951
		}
695
	}
952
	}
696
	ao2_unlock(s);
953
	ao2_unlock(s);
697
	ast_cli(fd, "\n\n");
954
	ast_cli(fd, "\n\n");
698
  + *
955
  + *
699
  + /branches/1.8:1-336111
956
  + /branches/1.8:1-336111
700
  + gregory@distrotech.co.za
957
  + gregory@distrotech.co.za

Return to bug 383987