Mercurial > hg > audiostuff
comparison spandsp-0.0.3/spandsp-0.0.3/src/t38_core.c @ 5:f762bf195c4b
import spandsp-0.0.3
author | Peter Meerwald <pmeerw@cosy.sbg.ac.at> |
---|---|
date | Fri, 25 Jun 2010 16:00:21 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
4:26cd8f1ef0b1 | 5:f762bf195c4b |
---|---|
1 /* | |
2 * SpanDSP - a series of DSP components for telephony | |
3 * | |
4 * t38_core.c - Encode and decode the ASN.1 of a T.38 IFP message | |
5 * | |
6 * Written by Steve Underwood <steveu@coppice.org> | |
7 * | |
8 * Copyright (C) 2005, 2006 Steve Underwood | |
9 * | |
10 * All rights reserved. | |
11 * | |
12 * This program is free software; you can redistribute it and/or modify | |
13 * it under the terms of the GNU General Public License version 2, as | |
14 * published by the Free Software Foundation. | |
15 * | |
16 * This program is distributed in the hope that it will be useful, | |
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
19 * GNU General Public License for more details. | |
20 * | |
21 * You should have received a copy of the GNU General Public License | |
22 * along with this program; if not, write to the Free Software | |
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
24 * | |
25 * $Id: t38_core.c,v 1.24 2006/12/09 04:50:12 steveu Exp $ | |
26 */ | |
27 | |
28 /*! \file */ | |
29 | |
30 #ifdef HAVE_CONFIG_H | |
31 #include "config.h" | |
32 #endif | |
33 | |
34 #include <inttypes.h> | |
35 #include <stdlib.h> | |
36 #include <stdio.h> | |
37 #include <fcntl.h> | |
38 #include <time.h> | |
39 #include <string.h> | |
40 #if defined(HAVE_TGMATH_H) | |
41 #include <tgmath.h> | |
42 #endif | |
43 #if defined(HAVE_MATH_H) | |
44 #include <math.h> | |
45 #endif | |
46 #include <assert.h> | |
47 #include <memory.h> | |
48 #include <tiffio.h> | |
49 | |
50 #include "spandsp/telephony.h" | |
51 #include "spandsp/logging.h" | |
52 #include "spandsp/bit_operations.h" | |
53 #include "spandsp/queue.h" | |
54 #include "spandsp/power_meter.h" | |
55 #include "spandsp/complex.h" | |
56 #include "spandsp/tone_generate.h" | |
57 #include "spandsp/async.h" | |
58 #include "spandsp/hdlc.h" | |
59 #include "spandsp/fsk.h" | |
60 #include "spandsp/v29rx.h" | |
61 #include "spandsp/v29tx.h" | |
62 #include "spandsp/v27ter_rx.h" | |
63 #include "spandsp/v27ter_tx.h" | |
64 #if defined(ENABLE_V17) | |
65 #include "spandsp/v17rx.h" | |
66 #include "spandsp/v17tx.h" | |
67 #endif | |
68 #include "spandsp/t4.h" | |
69 | |
70 #include "spandsp/t30_fcf.h" | |
71 #include "spandsp/t35.h" | |
72 #include "spandsp/t30.h" | |
73 | |
74 #include "spandsp/t38_core.h" | |
75 | |
76 #define ACCEPTABLE_SEQ_NO_OFFSET 2000 | |
77 | |
78 const char *t38_indicator(int indicator) | |
79 { | |
80 const char *type; | |
81 | |
82 switch (indicator) | |
83 { | |
84 case T38_IND_NO_SIGNAL: | |
85 type = "no-signal"; | |
86 break; | |
87 case T38_IND_CNG: | |
88 type = "cng"; | |
89 break; | |
90 case T38_IND_CED: | |
91 type = "ced"; | |
92 break; | |
93 case T38_IND_V21_PREAMBLE: | |
94 type = "v21-preamble"; | |
95 break; | |
96 case T38_IND_V27TER_2400_TRAINING: | |
97 type = "v27-2400-training"; | |
98 break; | |
99 case T38_IND_V27TER_4800_TRAINING: | |
100 type = "v27-4800-training"; | |
101 break; | |
102 case T38_IND_V29_7200_TRAINING: | |
103 type = "v29-7200-training"; | |
104 break; | |
105 case T38_IND_V29_9600_TRAINING: | |
106 type = "v29-9600-training"; | |
107 break; | |
108 case T38_IND_V17_7200_SHORT_TRAINING: | |
109 type = "v17-7200-short-training"; | |
110 break; | |
111 case T38_IND_V17_7200_LONG_TRAINING: | |
112 type = "v17-7200-long-training"; | |
113 break; | |
114 case T38_IND_V17_9600_SHORT_TRAINING: | |
115 type = "v17-9600-short-training"; | |
116 break; | |
117 case T38_IND_V17_9600_LONG_TRAINING: | |
118 type = "v17-9600-long-training"; | |
119 break; | |
120 case T38_IND_V17_12000_SHORT_TRAINING: | |
121 type = "v17-12000-short-training"; | |
122 break; | |
123 case T38_IND_V17_12000_LONG_TRAINING: | |
124 type = "v17-12000-long-training"; | |
125 break; | |
126 case T38_IND_V17_14400_SHORT_TRAINING: | |
127 type = "v17-14400-short-training"; | |
128 break; | |
129 case T38_IND_V17_14400_LONG_TRAINING: | |
130 type = "v17-14400-long-training"; | |
131 break; | |
132 case T38_IND_V8_ANSAM: | |
133 type = "v8-ansam"; | |
134 break; | |
135 case T38_IND_V8_SIGNAL: | |
136 type = "v8-signal"; | |
137 break; | |
138 case T38_IND_V34_CNTL_CHANNEL_1200: | |
139 type = "v34-cntl-channel-1200"; | |
140 break; | |
141 case T38_IND_V34_PRI_CHANNEL: | |
142 type = "v34-pri-channel"; | |
143 break; | |
144 case T38_IND_V34_CC_RETRAIN: | |
145 type = "v34-CC-retrain"; | |
146 break; | |
147 case T38_IND_V33_12000_TRAINING: | |
148 type = "v33-12000-training"; | |
149 break; | |
150 case T38_IND_V33_14400_TRAINING: | |
151 type = "v33-14400-training"; | |
152 break; | |
153 default: | |
154 type = "???"; | |
155 break; | |
156 } | |
157 return type; | |
158 } | |
159 /*- End of function --------------------------------------------------------*/ | |
160 | |
161 const char *t38_data_type(int data_type) | |
162 { | |
163 const char *type; | |
164 | |
165 switch (data_type) | |
166 { | |
167 case T38_DATA_V21: | |
168 type = "v21"; | |
169 break; | |
170 case T38_DATA_V27TER_2400: | |
171 type = "v27-2400"; | |
172 break; | |
173 case T38_DATA_V27TER_4800: | |
174 type = "v27-4800"; | |
175 break; | |
176 case T38_DATA_V29_7200: | |
177 type = "v29-7200"; | |
178 break; | |
179 case T38_DATA_V29_9600: | |
180 type = "v29-9600"; | |
181 break; | |
182 case T38_DATA_V17_7200: | |
183 type = "v17-7200"; | |
184 break; | |
185 case T38_DATA_V17_9600: | |
186 type = "v17-9600"; | |
187 break; | |
188 case T38_DATA_V17_12000: | |
189 type = "v17-12000"; | |
190 break; | |
191 case T38_DATA_V17_14400: | |
192 type = "v17-14400"; | |
193 break; | |
194 case T38_DATA_V8: | |
195 type = "v8"; | |
196 break; | |
197 case T38_DATA_V34_PRI_RATE: | |
198 type = "v34-pri-rate"; | |
199 break; | |
200 case T38_DATA_V34_CC_1200: | |
201 type = "v34-CC-1200"; | |
202 break; | |
203 case T38_DATA_V34_PRI_CH: | |
204 type = "v34-pri-vh"; | |
205 break; | |
206 case T38_DATA_V33_12000: | |
207 type = "v33-12000"; | |
208 break; | |
209 case T38_DATA_V33_14400: | |
210 type = "v33-14400"; | |
211 break; | |
212 default: | |
213 type = "???"; | |
214 break; | |
215 } | |
216 return type; | |
217 } | |
218 /*- End of function --------------------------------------------------------*/ | |
219 | |
220 const char *t38_field_type(int field_type) | |
221 { | |
222 const char *type; | |
223 | |
224 switch (field_type) | |
225 { | |
226 case T38_FIELD_HDLC_DATA: | |
227 type = "hdlc-data"; | |
228 break; | |
229 case T38_FIELD_HDLC_SIG_END: | |
230 type = "hdlc-sig-end"; | |
231 break; | |
232 case T38_FIELD_HDLC_FCS_OK: | |
233 type = "hdlc-fcs-OK"; | |
234 break; | |
235 case T38_FIELD_HDLC_FCS_BAD: | |
236 type = "hdlc-fcs-BAD"; | |
237 break; | |
238 case T38_FIELD_HDLC_FCS_OK_SIG_END: | |
239 type = "hdlc-fcs-OK-sig-end"; | |
240 break; | |
241 case T38_FIELD_HDLC_FCS_BAD_SIG_END: | |
242 type = "hdlc-fcs-BAD-sig-end"; | |
243 break; | |
244 case T38_FIELD_T4_NON_ECM_DATA: | |
245 type = "t4-non-ecm-data"; | |
246 break; | |
247 case T38_FIELD_T4_NON_ECM_SIG_END: | |
248 type = "t4-non-ecm-sig-end"; | |
249 break; | |
250 case T38_FIELD_CM_MESSAGE: | |
251 type = "cm-message"; | |
252 break; | |
253 case T38_FIELD_JM_MESSAGE: | |
254 type = "jm-message"; | |
255 break; | |
256 case T38_FIELD_CI_MESSAGE: | |
257 type = "ci-message"; | |
258 break; | |
259 case T38_FIELD_V34RATE: | |
260 type = "v34rate"; | |
261 break; | |
262 default: | |
263 type = "???"; | |
264 break; | |
265 } | |
266 return type; | |
267 } | |
268 /*- End of function --------------------------------------------------------*/ | |
269 | |
270 static __inline__ int classify_seq_no_offset(int expected, int actual) | |
271 { | |
272 /* Classify the mismatch between expected and actual sequence numbers | |
273 according to whether the actual is a little in the past (late), a | |
274 little in the future (some packets have been lost), or a large jump | |
275 that represents the sequence being lost (possibly when some RTP | |
276 gets dumped to a UDPTL port). */ | |
277 /* This assumes they are not equal */ | |
278 if (expected > actual) | |
279 { | |
280 if (expected > actual + 0x10000 - ACCEPTABLE_SEQ_NO_OFFSET) | |
281 { | |
282 /* In the near future */ | |
283 return 1; | |
284 } | |
285 if (expected < actual + ACCEPTABLE_SEQ_NO_OFFSET) | |
286 { | |
287 /* In the recent past */ | |
288 return -1; | |
289 } | |
290 } | |
291 else | |
292 { | |
293 if (expected + ACCEPTABLE_SEQ_NO_OFFSET > actual) | |
294 { | |
295 /* In the near future */ | |
296 return 1; | |
297 } | |
298 if (expected + 0x10000 - ACCEPTABLE_SEQ_NO_OFFSET < actual) | |
299 { | |
300 /* In the recent past */ | |
301 return -1; | |
302 } | |
303 } | |
304 /* There has been a huge step in the sequence */ | |
305 return 0; | |
306 } | |
307 /*- End of function --------------------------------------------------------*/ | |
308 | |
309 int t38_core_rx_ifp_packet(t38_core_state_t *s, int seq_no, const uint8_t *buf, int len) | |
310 { | |
311 int i; | |
312 int t30_indicator; | |
313 int t30_data; | |
314 int ptr; | |
315 int other_half; | |
316 int numocts; | |
317 const uint8_t *msg; | |
318 uint8_t type; | |
319 unsigned int count; | |
320 unsigned int field_type; | |
321 uint8_t data_field_present; | |
322 uint8_t field_data_present; | |
323 | |
324 if (span_log_test(&s->logging, SPAN_LOG_FLOW)) | |
325 { | |
326 char tag[20]; | |
327 | |
328 sprintf(tag, "Rx %5d:", seq_no); | |
329 span_log_buf(&s->logging, SPAN_LOG_FLOW, tag, buf, len); | |
330 } | |
331 if (len < 1) | |
332 { | |
333 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Bad packet length - %d\n", seq_no, len); | |
334 return -1; | |
335 } | |
336 seq_no &= 0xFFFF; | |
337 if (seq_no != s->rx_expected_seq_no) | |
338 { | |
339 /* An expected value of -1 indicates this is the first received packet, and will accept | |
340 anything for that. We can't assume they will start from zero, even though they should. */ | |
341 if (s->rx_expected_seq_no != -1) | |
342 { | |
343 /* We have a packet with a serial number that is not in sequence. The cause could be: | |
344 - 1. a repeat copy of a recent packet. Many T.38 implementations can preduce quite a lot of these. | |
345 - 2. a late packet, whose point in the sequence we have already passed. | |
346 - 3. the result of a hop in the sequence numbers cause by something weird from the other | |
347 end. Stream switching might cause this | |
348 - 4. missing packets. | |
349 | |
350 In cases 1 and 2 we need to drop this packet. In case 2 it might make sense to try to do | |
351 something with it in the terminal case. Currently we don't. For gateway operation it will be | |
352 too late to do anything useful. | |
353 */ | |
354 if (((seq_no + 1) & 0xFFFF) == s->rx_expected_seq_no) | |
355 { | |
356 /* Assume this is truly a repeat packet, and don't bother checking its contents. */ | |
357 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Repeat packet number\n", seq_no); | |
358 return 0; | |
359 } | |
360 /* Distinguish between a little bit out of sequence, and a huge hop. */ | |
361 switch (classify_seq_no_offset(s->rx_expected_seq_no, seq_no)) | |
362 { | |
363 case -1: | |
364 /* This packet is in the near past, so its late. */ | |
365 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Late packet - expected %d\n", seq_no, s->rx_expected_seq_no); | |
366 return 0; | |
367 case 1: | |
368 /* This packet is in the near future, so some packets have been lost */ | |
369 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Missing from %d\n", seq_no, s->rx_expected_seq_no); | |
370 s->rx_missing_handler(s, s->rx_user_data, s->rx_expected_seq_no, seq_no); | |
371 s->missing_packets += (seq_no - s->rx_expected_seq_no); | |
372 break; | |
373 default: | |
374 /* The sequence has jumped wildly */ | |
375 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Sequence restart\n", seq_no); | |
376 s->rx_missing_handler(s, s->rx_user_data, -1, -1); | |
377 s->missing_packets++; | |
378 break; | |
379 } | |
380 } | |
381 s->rx_expected_seq_no = seq_no; | |
382 } | |
383 s->rx_expected_seq_no = (s->rx_expected_seq_no + 1) & 0xFFFF; | |
384 | |
385 data_field_present = (buf[0] >> 7) & 1; | |
386 type = (buf[0] >> 6) & 1; | |
387 ptr = 0; | |
388 switch (type) | |
389 { | |
390 case T38_TYPE_OF_MSG_T30_INDICATOR: | |
391 /* Indicators should never have a data field */ | |
392 if (data_field_present) | |
393 { | |
394 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Data field with indicator\n", seq_no); | |
395 return -1; | |
396 } | |
397 if ((buf[0] & 0x20)) | |
398 { | |
399 /* Extension */ | |
400 if (len != 2) | |
401 { | |
402 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Invalid length for indicator\n", seq_no); | |
403 return -1; | |
404 } | |
405 t30_indicator = T38_IND_V8_ANSAM + (((buf[0] << 2) & 0x3C) | ((buf[1] >> 6) & 0x3)); | |
406 if (t30_indicator > T38_IND_V33_14400_TRAINING) | |
407 { | |
408 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Unknown indicator - %d\n", seq_no, t30_indicator); | |
409 return -1; | |
410 } | |
411 } | |
412 else | |
413 { | |
414 if (len != 1) | |
415 { | |
416 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Invalid length for indicator\n", seq_no); | |
417 return -1; | |
418 } | |
419 t30_indicator = (buf[0] >> 1) & 0xF; | |
420 } | |
421 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: indicator %s\n", seq_no, t38_indicator(t30_indicator)); | |
422 s->rx_indicator_handler(s, s->rx_user_data, t30_indicator); | |
423 /* This must come after the indicator handler, so the handler routine sees the existing state of the | |
424 indicator. */ | |
425 s->current_rx_indicator = t30_indicator; | |
426 break; | |
427 case T38_TYPE_OF_MSG_T30_DATA: | |
428 if ((buf[0] & 0x20)) | |
429 { | |
430 /* Extension */ | |
431 if (len < 2) | |
432 { | |
433 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Invalid length for data\n", seq_no); | |
434 return -1; | |
435 } | |
436 t30_data = T38_DATA_V8 + (((buf[0] << 2) & 0x3C) | ((buf[1] >> 6) & 0x3)); | |
437 if (t30_data > T38_DATA_V33_14400) | |
438 { | |
439 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Unknown data type - %d\n", seq_no, t30_data); | |
440 return -1; | |
441 } | |
442 ptr = 2; | |
443 } | |
444 else | |
445 { | |
446 t30_data = (buf[0] >> 1) & 0xF; | |
447 if (t30_data > T38_DATA_V17_14400) | |
448 { | |
449 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Unknown data type - %d\n", seq_no, t30_data); | |
450 return -1; | |
451 } | |
452 ptr = 1; | |
453 } | |
454 if (!data_field_present) | |
455 { | |
456 /* This is kinda weird, but I guess if the length checks out we accept it. */ | |
457 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Data type with no data field\n", seq_no); | |
458 if (ptr != len) | |
459 { | |
460 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Bad length\n", seq_no); | |
461 return -1; | |
462 } | |
463 break; | |
464 } | |
465 if (ptr >= len) | |
466 { | |
467 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Bad length\n", seq_no); | |
468 return -1; | |
469 } | |
470 count = buf[ptr++]; | |
471 //printf("Count is %d\n", count); | |
472 other_half = FALSE; | |
473 for (i = 0; i < (int) count; i++) | |
474 { | |
475 if (ptr >= len) | |
476 { | |
477 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Bad length\n", seq_no); | |
478 return -1; | |
479 } | |
480 if (s->t38_version == 0) | |
481 { | |
482 /* The original version of T.38 with a typo in the ASN.1 spec. */ | |
483 if (other_half) | |
484 { | |
485 /* The lack of a data field in the previous message means | |
486 we are currently in the middle of an octet. */ | |
487 field_data_present = (buf[ptr] >> 3) & 1; | |
488 /* Decode field_type */ | |
489 field_type = buf[ptr] & 0x7; | |
490 ptr++; | |
491 other_half = FALSE; | |
492 } | |
493 else | |
494 { | |
495 field_data_present = (buf[ptr] >> 7) & 1; | |
496 /* Decode field_type */ | |
497 field_type = (buf[ptr] >> 4) & 0x7; | |
498 if (field_data_present) | |
499 ptr++; | |
500 else | |
501 other_half = TRUE; | |
502 } | |
503 if (field_type > T38_FIELD_T4_NON_ECM_SIG_END) | |
504 { | |
505 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Unknown field type - %d\n", seq_no, field_type); | |
506 return -1; | |
507 } | |
508 } | |
509 else | |
510 { | |
511 field_data_present = (buf[ptr] >> 7) & 1; | |
512 /* Decode field_type */ | |
513 if ((buf[ptr] & 0x40)) | |
514 { | |
515 if (ptr > len - 2) | |
516 { | |
517 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Bad length\n", seq_no); | |
518 return -1; | |
519 } | |
520 field_type = T38_FIELD_CM_MESSAGE + (((buf[ptr] << 2) & 0x3C) | ((buf[ptr + 1] >> 6) & 0x3)); | |
521 if (field_type > T38_FIELD_V34RATE) | |
522 { | |
523 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Unknown field type - %d\n", seq_no, field_type); | |
524 return -1; | |
525 } | |
526 ptr++; | |
527 } | |
528 else | |
529 { | |
530 field_type = (buf[ptr++] >> 3) & 0x7; | |
531 if (field_type > T38_FIELD_T4_NON_ECM_SIG_END) | |
532 { | |
533 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Unknown field type - %d\n", seq_no, field_type); | |
534 return -1; | |
535 } | |
536 } | |
537 } | |
538 /* Decode field_data */ | |
539 if (field_data_present) | |
540 { | |
541 if (ptr > len - 2) | |
542 { | |
543 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Bad length\n", seq_no); | |
544 return -1; | |
545 } | |
546 numocts = ((buf[ptr] << 8) | buf[ptr + 1]) + 1; | |
547 msg = buf + ptr + 2; | |
548 ptr += numocts + 2; | |
549 } | |
550 else | |
551 { | |
552 numocts = 0; | |
553 msg = NULL; | |
554 } | |
555 if (ptr > len) | |
556 { | |
557 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Bad length\n", seq_no); | |
558 return -1; | |
559 } | |
560 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: data type %s/%s + %d byte(s)\n", seq_no, t38_data_type(t30_data), t38_field_type(field_type), numocts); | |
561 s->rx_data_handler(s, s->rx_user_data, t30_data, field_type, msg, numocts); | |
562 } | |
563 if (ptr != len) | |
564 { | |
565 span_log(&s->logging, SPAN_LOG_FLOW, "Rx %5d: Bad length\n", seq_no); | |
566 return -1; | |
567 } | |
568 break; | |
569 } | |
570 return 0; | |
571 } | |
572 /*- End of function --------------------------------------------------------*/ | |
573 | |
574 static int t38_encode_data(t38_core_state_t *s, uint8_t buf[], int data_type, int field_type, const uint8_t *msg, int msglen) | |
575 { | |
576 int len; | |
577 int i; | |
578 int enclen; | |
579 int multiplier; | |
580 int data_field_no; | |
581 int data_field_count; | |
582 data_field_element_t data_field_seq[10]; | |
583 data_field_element_t *q; | |
584 unsigned int encoded_len; | |
585 unsigned int fragment_len; | |
586 unsigned int value; | |
587 uint8_t data_field_present; | |
588 | |
589 span_log(&s->logging, SPAN_LOG_FLOW, "Tx %5d: data type %s/%s + %d byte(s)\n", s->tx_seq_no, t38_data_type(data_type), t38_field_type(field_type), msglen); | |
590 | |
591 /* Build the IFP packet */ | |
592 data_field_present = TRUE; | |
593 | |
594 data_field_seq[0].field_data_present = (uint8_t) (msglen > 0); | |
595 data_field_seq[0].field_type = field_type; | |
596 data_field_seq[0].field_data.numocts = msglen; | |
597 data_field_seq[0].field_data.data = msg; | |
598 data_field_count = 1; | |
599 | |
600 len = 0; | |
601 /* Data field present */ | |
602 /* Data packet */ | |
603 /* Type of data */ | |
604 if (data_type <= T38_DATA_V17_14400) | |
605 { | |
606 buf[len++] = (uint8_t) ((data_field_present << 7) | 0x40 | (data_type << 1)); | |
607 } | |
608 else if (data_type <= T38_DATA_V33_14400) | |
609 { | |
610 buf[len++] = (uint8_t) ((data_field_present << 7) | 0x60 | (((data_type - T38_DATA_V8) & 0xF) >> 2)); | |
611 buf[len++] = (uint8_t) (((data_type - T38_DATA_V8) << 6) & 0xFF); | |
612 } | |
613 else | |
614 { | |
615 return -1; | |
616 } | |
617 if (data_field_present) | |
618 { | |
619 encoded_len = 0; | |
620 data_field_no = 0; | |
621 do | |
622 { | |
623 value = data_field_count - encoded_len; | |
624 if (value < 0x80) | |
625 { | |
626 /* 1 octet case */ | |
627 buf[len++] = (uint8_t) value; | |
628 enclen = value; | |
629 } | |
630 else if (value < 0x4000) | |
631 { | |
632 /* 2 octet case */ | |
633 buf[len++] = (uint8_t) (0x80 | ((value >> 8) & 0xFF)); | |
634 buf[len++] = (uint8_t) (value & 0xFF); | |
635 enclen = value; | |
636 } | |
637 else | |
638 { | |
639 /* Fragmentation case */ | |
640 multiplier = (value/0x4000 < 4) ? value/0x4000 : 4; | |
641 buf[len++] = (uint8_t) (0xC0 | multiplier); | |
642 enclen = 0x4000*multiplier; | |
643 } | |
644 | |
645 fragment_len = enclen; | |
646 encoded_len += fragment_len; | |
647 /* Encode the elements */ | |
648 for (i = 0; i < (int) encoded_len; i++) | |
649 { | |
650 q = &data_field_seq[data_field_no]; | |
651 /* Encode field_type */ | |
652 if (s->t38_version == 0) | |
653 { | |
654 /* Original version of T.38 with a typo */ | |
655 if (q->field_type > T38_FIELD_T4_NON_ECM_SIG_END) | |
656 return -1; | |
657 buf[len++] = (uint8_t) ((q->field_data_present << 7) | (q->field_type << 4)); | |
658 } | |
659 else | |
660 { | |
661 if (q->field_type <= T38_FIELD_T4_NON_ECM_SIG_END) | |
662 { | |
663 buf[len++] = (uint8_t) ((q->field_data_present << 7) | (q->field_type << 3)); | |
664 } | |
665 else if (q->field_type <= T38_FIELD_V34RATE) | |
666 { | |
667 buf[len++] = (uint8_t) ((q->field_data_present << 7) | 0x40 | (((q->field_type - T38_FIELD_CM_MESSAGE) & 0x1F) >> 1)); | |
668 buf[len++] = (uint8_t) (((q->field_type - T38_FIELD_CM_MESSAGE) << 7) & 0xFF); | |
669 } | |
670 else | |
671 { | |
672 return -1; | |
673 } | |
674 } | |
675 /* Encode field_data */ | |
676 if (q->field_data_present) | |
677 { | |
678 if (q->field_data.numocts < 1 || q->field_data.numocts > 65535) | |
679 return -1; | |
680 buf[len++] = (uint8_t) (((q->field_data.numocts - 1) >> 8) & 0xFF); | |
681 buf[len++] = (uint8_t) ((q->field_data.numocts - 1) & 0xFF); | |
682 memcpy(buf + len, q->field_data.data, q->field_data.numocts); | |
683 len += q->field_data.numocts; | |
684 } | |
685 data_field_no++; | |
686 } | |
687 } | |
688 while (data_field_count != (int) encoded_len || fragment_len >= 16384); | |
689 } | |
690 | |
691 if (span_log_test(&s->logging, SPAN_LOG_FLOW)) | |
692 { | |
693 char tag[20]; | |
694 | |
695 sprintf(tag, "Tx %5d:", s->tx_seq_no); | |
696 span_log_buf(&s->logging, SPAN_LOG_FLOW, tag, buf, len); | |
697 } | |
698 return len; | |
699 } | |
700 /*- End of function --------------------------------------------------------*/ | |
701 | |
702 static int t38_encode_indicator(t38_core_state_t *s, uint8_t buf[], int indicator) | |
703 { | |
704 int len; | |
705 | |
706 span_log(&s->logging, SPAN_LOG_FLOW, "Tx %5d: indicator %s\n", s->tx_seq_no, t38_indicator(indicator)); | |
707 | |
708 /* Build the IFP packet */ | |
709 /* Data field not present */ | |
710 /* Indicator packet */ | |
711 /* Type of indicator */ | |
712 if (indicator <= T38_IND_V17_14400_LONG_TRAINING) | |
713 { | |
714 buf[0] = (uint8_t) (indicator << 1); | |
715 len = 1; | |
716 } | |
717 else if (indicator <= T38_IND_V33_14400_TRAINING) | |
718 { | |
719 buf[0] = (uint8_t) (0x20 | (((indicator - T38_IND_V8_ANSAM) & 0xF) >> 2)); | |
720 buf[1] = (uint8_t) (((indicator - T38_IND_V8_ANSAM) << 6) & 0xFF); | |
721 len = 2; | |
722 } | |
723 else | |
724 { | |
725 len = -1; | |
726 } | |
727 return len; | |
728 } | |
729 /*- End of function --------------------------------------------------------*/ | |
730 | |
731 int t38_core_send_data(t38_core_state_t *s, int data_type, int field_type, const uint8_t *msg, int msglen) | |
732 { | |
733 uint8_t buf[100]; | |
734 int len; | |
735 | |
736 if ((len = t38_encode_data(s, buf, data_type, field_type, msg, msglen)) > 0) | |
737 s->tx_packet_handler(s, s->tx_packet_user_data, buf, len, 1); | |
738 else | |
739 span_log(&s->logging, SPAN_LOG_FLOW, "T.38 data len is %d\n", len); | |
740 s->tx_seq_no = (s->tx_seq_no + 1) & 0xFFFF; | |
741 return 0; | |
742 } | |
743 /*- End of function --------------------------------------------------------*/ | |
744 | |
745 int t38_core_send_indicator(t38_core_state_t *s, int indicator, int count) | |
746 { | |
747 uint8_t buf[100]; | |
748 int len; | |
749 | |
750 if ((len = t38_encode_indicator(s, buf, indicator)) > 0) | |
751 { | |
752 s->tx_packet_handler(s, s->tx_packet_user_data, buf, len, count); | |
753 s->current_tx_indicator = indicator; | |
754 } | |
755 else | |
756 { | |
757 span_log(&s->logging, SPAN_LOG_FLOW, "T.38 indicator len is %d\n", len); | |
758 } | |
759 s->tx_seq_no = (s->tx_seq_no + 1) & 0xFFFF; | |
760 return 0; | |
761 } | |
762 /*- End of function --------------------------------------------------------*/ | |
763 | |
764 void t38_set_data_rate_management_method(t38_core_state_t *s, int method) | |
765 { | |
766 s->data_rate_management_method = method; | |
767 } | |
768 /*- End of function --------------------------------------------------------*/ | |
769 | |
770 void t38_set_data_transport_protocol(t38_core_state_t *s, int data_transport_protocol) | |
771 { | |
772 s->data_transport_protocol = data_transport_protocol; | |
773 } | |
774 /*- End of function --------------------------------------------------------*/ | |
775 | |
776 void t38_set_fill_bit_removal(t38_core_state_t *s, int fill_bit_removal) | |
777 { | |
778 s->fill_bit_removal = fill_bit_removal; | |
779 } | |
780 /*- End of function --------------------------------------------------------*/ | |
781 | |
782 void t38_set_mmr_transcoding(t38_core_state_t *s, int mmr_transcoding) | |
783 { | |
784 s->mmr_transcoding = mmr_transcoding; | |
785 } | |
786 /*- End of function --------------------------------------------------------*/ | |
787 | |
788 void t38_set_jbig_transcoding(t38_core_state_t *s, int jbig_transcoding) | |
789 { | |
790 s->jbig_transcoding = jbig_transcoding; | |
791 } | |
792 /*- End of function --------------------------------------------------------*/ | |
793 | |
794 void t38_set_max_buffer_size(t38_core_state_t *s, int max_buffer_size) | |
795 { | |
796 s->max_buffer_size = max_buffer_size; | |
797 } | |
798 /*- End of function --------------------------------------------------------*/ | |
799 | |
800 void t38_set_max_datagram_size(t38_core_state_t *s, int max_datagram_size) | |
801 { | |
802 s->max_datagram_size = max_datagram_size; | |
803 } | |
804 /*- End of function --------------------------------------------------------*/ | |
805 | |
806 void t38_set_t38_version(t38_core_state_t *s, int t38_version) | |
807 { | |
808 s->t38_version = t38_version; | |
809 } | |
810 /*- End of function --------------------------------------------------------*/ | |
811 | |
812 int t38_get_fastest_image_data_rate(t38_core_state_t *s) | |
813 { | |
814 return s->fastest_image_data_rate; | |
815 } | |
816 /*- End of function --------------------------------------------------------*/ | |
817 | |
818 t38_core_state_t *t38_core_init(t38_core_state_t *s, | |
819 t38_rx_indicator_handler_t *rx_indicator_handler, | |
820 t38_rx_data_handler_t *rx_data_handler, | |
821 t38_rx_missing_handler_t *rx_missing_handler, | |
822 void *rx_user_data) | |
823 { | |
824 memset(s, 0, sizeof(*s)); | |
825 span_log_init(&s->logging, SPAN_LOG_NONE, NULL); | |
826 span_log_set_protocol(&s->logging, "T.38"); | |
827 | |
828 span_log(&s->logging, SPAN_LOG_FLOW, "Start tx document\n"); | |
829 s->data_rate_management_method = 2; | |
830 s->data_transport_protocol = T38_TRANSPORT_UDPTL; | |
831 s->fill_bit_removal = FALSE; | |
832 s->mmr_transcoding = FALSE; | |
833 s->jbig_transcoding = FALSE; | |
834 s->max_buffer_size = 400; | |
835 s->max_datagram_size = 100; | |
836 s->t38_version = 0; | |
837 s->iaf = FALSE; | |
838 s->current_rx_indicator = -1; | |
839 | |
840 s->rx_indicator_handler = rx_indicator_handler; | |
841 s->rx_data_handler = rx_data_handler; | |
842 s->rx_missing_handler = rx_missing_handler; | |
843 s->rx_user_data = rx_user_data; | |
844 | |
845 s->rx_expected_seq_no = -1; | |
846 return s; | |
847 } | |
848 /*- End of function --------------------------------------------------------*/ | |
849 /*- End of file ------------------------------------------------------------*/ |