00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #include "asterisk.h"
00035
00036 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 352144 $")
00037
00038 #define SPANDSP_EXPOSE_INTERNAL_STRUCTURES
00039 #include <spandsp.h>
00040 #include <spandsp/version.h>
00041
00042 #include "asterisk/logger.h"
00043 #include "asterisk/module.h"
00044 #include "asterisk/strings.h"
00045 #include "asterisk/cli.h"
00046 #include "asterisk/utils.h"
00047 #include "asterisk/timing.h"
00048 #include "asterisk/astobj2.h"
00049 #include "asterisk/res_fax.h"
00050
00051 #define SPANDSP_FAX_SAMPLES 160
00052 #define SPANDSP_FAX_TIMER_RATE 8000 / SPANDSP_FAX_SAMPLES
00053
00054 static void *spandsp_fax_new(struct ast_fax_session *s, struct ast_fax_tech_token *token);
00055 static void spandsp_fax_destroy(struct ast_fax_session *s);
00056 static struct ast_frame *spandsp_fax_read(struct ast_fax_session *s);
00057 static int spandsp_fax_write(struct ast_fax_session *s, const struct ast_frame *f);
00058 static int spandsp_fax_start(struct ast_fax_session *s);
00059 static int spandsp_fax_cancel(struct ast_fax_session *s);
00060 static int spandsp_fax_switch_to_t38(struct ast_fax_session *s);
00061
00062 static char *spandsp_fax_cli_show_capabilities(int fd);
00063 static char *spandsp_fax_cli_show_session(struct ast_fax_session *s, int fd);
00064 static char *spandsp_fax_cli_show_stats(int fd);
00065 static char *spandsp_fax_cli_show_settings(int fd);
00066
00067 static struct ast_fax_tech spandsp_fax_tech = {
00068 .type = "Spandsp",
00069 .description = "Spandsp FAX Driver",
00070 #if SPANDSP_RELEASE_DATE >= 20090220
00071
00072 .version = SPANDSP_RELEASE_DATETIME_STRING,
00073 #else
00074
00075
00076
00077 .version = "pre-20090220",
00078 #endif
00079 .caps = AST_FAX_TECH_AUDIO | AST_FAX_TECH_T38 | AST_FAX_TECH_SEND | AST_FAX_TECH_RECEIVE,
00080 .new_session = spandsp_fax_new,
00081 .destroy_session = spandsp_fax_destroy,
00082 .read = spandsp_fax_read,
00083 .write = spandsp_fax_write,
00084 .start_session = spandsp_fax_start,
00085 .cancel_session = spandsp_fax_cancel,
00086 .switch_to_t38 = spandsp_fax_switch_to_t38,
00087 .cli_show_capabilities = spandsp_fax_cli_show_capabilities,
00088 .cli_show_session = spandsp_fax_cli_show_session,
00089 .cli_show_stats = spandsp_fax_cli_show_stats,
00090 .cli_show_settings = spandsp_fax_cli_show_settings,
00091 };
00092
00093 struct spandsp_fax_stats {
00094 int success;
00095 int nofax;
00096 int neg_failed;
00097 int failed_to_train;
00098 int rx_protocol_error;
00099 int tx_protocol_error;
00100 int protocol_error;
00101 int retries_exceeded;
00102 int file_error;
00103 int mem_error;
00104 int call_dropped;
00105 int unknown_error;
00106 int switched;
00107 };
00108
00109 static struct {
00110 ast_mutex_t lock;
00111 struct spandsp_fax_stats g711;
00112 struct spandsp_fax_stats t38;
00113 } spandsp_global_stats;
00114
00115 struct spandsp_pvt {
00116 unsigned int ist38:1;
00117 unsigned int isdone:1;
00118 fax_state_t fax_state;
00119 t38_terminal_state_t t38_state;
00120 t30_state_t *t30_state;
00121 t38_core_state_t *t38_core_state;
00122
00123 struct spandsp_fax_stats *stats;
00124
00125 struct ast_timer *timer;
00126 AST_LIST_HEAD(frame_queue, ast_frame) read_frames;
00127 };
00128
00129 static void session_destroy(struct spandsp_pvt *p);
00130 static int t38_tx_packet_handler(t38_core_state_t *t38_core_state, void *data, const uint8_t *buf, int len, int count);
00131 static void t30_phase_e_handler(t30_state_t *t30_state, void *data, int completion_code);
00132 static void spandsp_log(int level, const char *msg);
00133 static int update_stats(struct spandsp_pvt *p, int completion_code);
00134 static int spandsp_modems(struct ast_fax_session_details *details);
00135
00136 static void set_logging(logging_state_t *state, struct ast_fax_session_details *details);
00137 static void set_local_info(t30_state_t *t30_state, struct ast_fax_session_details *details);
00138 static void set_file(t30_state_t *t30_state, struct ast_fax_session_details *details);
00139 static void set_ecm(t30_state_t *t30_state, struct ast_fax_session_details *details);
00140
00141 static void session_destroy(struct spandsp_pvt *p)
00142 {
00143 struct ast_frame *f;
00144
00145 t30_terminate(p->t30_state);
00146 p->isdone = 1;
00147
00148 ast_timer_close(p->timer);
00149
00150 fax_release(&p->fax_state);
00151 t38_terminal_release(&p->t38_state);
00152
00153 while ((f = AST_LIST_REMOVE_HEAD(&p->read_frames, frame_list))) {
00154 ast_frfree(f);
00155 }
00156 }
00157
00158
00159
00160
00161 static int t38_tx_packet_handler(t38_core_state_t *t38_core_state, void *data, const uint8_t *buf, int len, int count)
00162 {
00163 struct spandsp_pvt *p = data;
00164 struct ast_frame fax_frame = {
00165 .frametype = AST_FRAME_MODEM,
00166 .subclass.integer = AST_MODEM_T38,
00167 .src = "res_fax_spandsp_t38",
00168 };
00169
00170 struct ast_frame *f = &fax_frame;
00171
00172
00173
00174
00175
00176 AST_FRAME_SET_BUFFER(f, buf, 0, len);
00177
00178 if (!(f = ast_frisolate(f))) {
00179 return -1;
00180 }
00181
00182
00183 AST_LIST_INSERT_TAIL(&p->read_frames, f, frame_list);
00184
00185 return 0;
00186 }
00187
00188 static int update_stats(struct spandsp_pvt *p, int completion_code)
00189 {
00190 switch (completion_code) {
00191 case T30_ERR_OK:
00192 ast_atomic_fetchadd_int(&p->stats->success, 1);
00193 break;
00194
00195
00196 case T30_ERR_CEDTONE:
00197 case T30_ERR_T0_EXPIRED:
00198 case T30_ERR_T1_EXPIRED:
00199 case T30_ERR_T3_EXPIRED:
00200 case T30_ERR_HDLC_CARRIER:
00201 case T30_ERR_CANNOT_TRAIN:
00202 ast_atomic_fetchadd_int(&p->stats->failed_to_train, 1);
00203 break;
00204
00205 case T30_ERR_OPER_INT_FAIL:
00206 case T30_ERR_INCOMPATIBLE:
00207 case T30_ERR_RX_INCAPABLE:
00208 case T30_ERR_TX_INCAPABLE:
00209 case T30_ERR_NORESSUPPORT:
00210 case T30_ERR_NOSIZESUPPORT:
00211 ast_atomic_fetchadd_int(&p->stats->neg_failed, 1);
00212 break;
00213
00214 case T30_ERR_UNEXPECTED:
00215 ast_atomic_fetchadd_int(&p->stats->protocol_error, 1);
00216 break;
00217
00218
00219 case T30_ERR_TX_BADDCS:
00220 case T30_ERR_TX_BADPG:
00221 case T30_ERR_TX_ECMPHD:
00222 case T30_ERR_TX_GOTDCN:
00223 case T30_ERR_TX_INVALRSP:
00224 case T30_ERR_TX_NODIS:
00225 case T30_ERR_TX_PHBDEAD:
00226 case T30_ERR_TX_PHDDEAD:
00227 case T30_ERR_TX_T5EXP:
00228 ast_atomic_fetchadd_int(&p->stats->tx_protocol_error, 1);
00229 break;
00230
00231
00232 case T30_ERR_RX_ECMPHD:
00233 case T30_ERR_RX_GOTDCS:
00234 case T30_ERR_RX_INVALCMD:
00235 case T30_ERR_RX_NOCARRIER:
00236 case T30_ERR_RX_NOEOL:
00237 ast_atomic_fetchadd_int(&p->stats->rx_protocol_error, 1);
00238 break;
00239 case T30_ERR_RX_NOFAX:
00240 ast_atomic_fetchadd_int(&p->stats->nofax, 1);
00241 break;
00242 case T30_ERR_RX_T2EXPDCN:
00243 case T30_ERR_RX_T2EXPD:
00244 case T30_ERR_RX_T2EXPFAX:
00245 case T30_ERR_RX_T2EXPMPS:
00246 case T30_ERR_RX_T2EXPRR:
00247 case T30_ERR_RX_T2EXP:
00248 case T30_ERR_RX_DCNWHY:
00249 case T30_ERR_RX_DCNDATA:
00250 case T30_ERR_RX_DCNFAX:
00251 case T30_ERR_RX_DCNPHD:
00252 case T30_ERR_RX_DCNRRD:
00253 case T30_ERR_RX_DCNNORTN:
00254 ast_atomic_fetchadd_int(&p->stats->rx_protocol_error, 1);
00255 break;
00256
00257
00258 case T30_ERR_FILEERROR:
00259 case T30_ERR_NOPAGE:
00260 case T30_ERR_BADTIFF:
00261 case T30_ERR_BADPAGE:
00262 case T30_ERR_BADTAG:
00263 case T30_ERR_BADTIFFHDR:
00264 ast_atomic_fetchadd_int(&p->stats->file_error, 1);
00265 break;
00266 case T30_ERR_NOMEM:
00267 ast_atomic_fetchadd_int(&p->stats->mem_error, 1);
00268 break;
00269
00270
00271 case T30_ERR_RETRYDCN:
00272 ast_atomic_fetchadd_int(&p->stats->retries_exceeded, 1);
00273 break;
00274 case T30_ERR_CALLDROPPED:
00275 ast_atomic_fetchadd_int(&p->stats->call_dropped, 1);
00276 break;
00277
00278
00279 case T30_ERR_NOPOLL:
00280 case T30_ERR_IDENT_UNACCEPTABLE:
00281 case T30_ERR_SUB_UNACCEPTABLE:
00282 case T30_ERR_SEP_UNACCEPTABLE:
00283 case T30_ERR_PSA_UNACCEPTABLE:
00284 case T30_ERR_SID_UNACCEPTABLE:
00285 case T30_ERR_PWD_UNACCEPTABLE:
00286 case T30_ERR_TSA_UNACCEPTABLE:
00287 case T30_ERR_IRA_UNACCEPTABLE:
00288 case T30_ERR_CIA_UNACCEPTABLE:
00289 case T30_ERR_ISP_UNACCEPTABLE:
00290 case T30_ERR_CSA_UNACCEPTABLE:
00291 ast_atomic_fetchadd_int(&p->stats->neg_failed, 1);
00292 break;
00293 default:
00294 ast_atomic_fetchadd_int(&p->stats->unknown_error, 1);
00295 ast_log(LOG_WARNING, "unknown FAX session result '%d' (%s)\n", completion_code, t30_completion_code_to_str(completion_code));
00296 return -1;
00297 }
00298 return 0;
00299 }
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309 static void t30_phase_e_handler(t30_state_t *t30_state, void *data, int completion_code)
00310 {
00311 struct ast_fax_session *s = data;
00312 struct spandsp_pvt *p = s->tech_pvt;
00313 char headerinfo[T30_MAX_PAGE_HEADER_INFO + 1];
00314 const char *c;
00315 t30_stats_t stats;
00316
00317 ast_debug(5, "FAX session '%d' entering phase E\n", s->id);
00318
00319 p->isdone = 1;
00320
00321 update_stats(p, completion_code);
00322
00323 t30_get_transfer_statistics(t30_state, &stats);
00324
00325 if (completion_code == T30_ERR_OK) {
00326 ast_string_field_set(s->details, result, "SUCCESS");
00327 } else {
00328 ast_string_field_set(s->details, result, "FAILED");
00329 ast_string_field_set(s->details, error, t30_completion_code_to_str(completion_code));
00330 }
00331
00332 ast_string_field_set(s->details, resultstr, t30_completion_code_to_str(completion_code));
00333
00334 ast_debug(5, "FAX session '%d' completed with result: %s (%s)\n", s->id, s->details->result, s->details->resultstr);
00335
00336 if ((c = t30_get_tx_ident(t30_state))) {
00337 ast_string_field_set(s->details, localstationid, c);
00338 }
00339
00340 if ((c = t30_get_rx_ident(t30_state))) {
00341 ast_string_field_set(s->details, remotestationid, c);
00342 }
00343
00344 #if SPANDSP_RELEASE_DATE >= 20090220
00345 s->details->pages_transferred = (s->details->caps & AST_FAX_TECH_RECEIVE) ? stats.pages_rx : stats.pages_tx;
00346 #else
00347 s->details->pages_transferred = stats.pages_transferred;
00348 #endif
00349
00350 ast_string_field_build(s->details, transfer_rate, "%d", stats.bit_rate);
00351
00352 ast_string_field_build(s->details, resolution, "%dx%d", stats.x_resolution, stats.y_resolution);
00353
00354 t30_get_tx_page_header_info(t30_state, headerinfo);
00355 ast_string_field_set(s->details, headerinfo, headerinfo);
00356 }
00357
00358
00359
00360
00361
00362
00363
00364 static void spandsp_log(int level, const char *msg)
00365 {
00366 if (level == SPAN_LOG_ERROR) {
00367 ast_log(LOG_ERROR, "%s", msg);
00368 } else if (level == SPAN_LOG_WARNING) {
00369 ast_log(LOG_WARNING, "%s", msg);
00370 } else {
00371 ast_fax_log(LOG_DEBUG, msg);
00372 }
00373 }
00374
00375 static void set_logging(logging_state_t *state, struct ast_fax_session_details *details)
00376 {
00377 int level = SPAN_LOG_WARNING;
00378
00379 if (details->option.debug) {
00380 level = SPAN_LOG_DEBUG_3;
00381 }
00382
00383 span_log_set_message_handler(state, spandsp_log);
00384 span_log_set_level(state, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | level);
00385 }
00386
00387 static void set_local_info(t30_state_t *t30_state, struct ast_fax_session_details *details)
00388 {
00389 if (!ast_strlen_zero(details->localstationid)) {
00390 t30_set_tx_ident(t30_state, details->localstationid);
00391 }
00392
00393 if (!ast_strlen_zero(details->headerinfo)) {
00394 t30_set_tx_page_header_info(t30_state, details->headerinfo);
00395 }
00396 }
00397
00398 static void set_file(t30_state_t *t30_state, struct ast_fax_session_details *details)
00399 {
00400 if (details->caps & AST_FAX_TECH_RECEIVE) {
00401 t30_set_rx_file(t30_state, AST_LIST_FIRST(&details->documents)->filename, -1);
00402 } else {
00403
00404
00405
00406 t30_set_tx_file(t30_state, AST_LIST_FIRST(&details->documents)->filename, -1, -1);
00407 }
00408 }
00409
00410 static void set_ecm(t30_state_t *t30_state, struct ast_fax_session_details *details)
00411 {
00412 t30_set_ecm_capability(t30_state, details->option.ecm);
00413 t30_set_supported_compressions(t30_state, T30_SUPPORT_T4_1D_COMPRESSION | T30_SUPPORT_T4_2D_COMPRESSION | T30_SUPPORT_T6_COMPRESSION);
00414 }
00415
00416 static int spandsp_modems(struct ast_fax_session_details *details)
00417 {
00418 int modems = 0;
00419 if (AST_FAX_MODEM_V17 & details->modems) {
00420 modems |= T30_SUPPORT_V17;
00421 }
00422 if (AST_FAX_MODEM_V27 & details->modems) {
00423 modems |= T30_SUPPORT_V27TER;
00424 }
00425 if (AST_FAX_MODEM_V29 & details->modems) {
00426 modems |= T30_SUPPORT_V29;
00427 }
00428 if (AST_FAX_MODEM_V34 & details->modems) {
00429 #if defined(T30_SUPPORT_V34)
00430 modems |= T30_SUPPORT_V34;
00431 #elif defined(T30_SUPPORT_V34HDX)
00432 modems |= T30_SUPPORT_V34HDX;
00433 #else
00434 ast_log(LOG_WARNING, "v34 not supported in this version of spandsp\n");
00435 #endif
00436 }
00437
00438 return modems;
00439 }
00440
00441
00442 static void *spandsp_fax_new(struct ast_fax_session *s, struct ast_fax_tech_token *token)
00443 {
00444 struct spandsp_pvt *p;
00445 int caller_mode;
00446
00447 if ((!(p = ast_calloc(1, sizeof(*p))))) {
00448 ast_log(LOG_ERROR, "Cannot initialize the spandsp private FAX technology structure.\n");
00449 goto e_return;
00450 }
00451
00452 AST_LIST_HEAD_INIT(&p->read_frames);
00453
00454 if (s->details->caps & AST_FAX_TECH_RECEIVE) {
00455 caller_mode = 0;
00456 } else if (s->details->caps & AST_FAX_TECH_SEND) {
00457 caller_mode = 1;
00458 } else {
00459 ast_log(LOG_ERROR, "Are we sending or receiving? The FAX requirements (capabilities: 0x%X) were not properly set.\n", s->details->caps);
00460 goto e_free;
00461 }
00462
00463 if (!(p->timer = ast_timer_open())) {
00464 ast_log(LOG_ERROR, "Channel '%s' FAX session '%d' failed to create timing source.\n", s->channame, s->id);
00465 goto e_free;
00466 }
00467
00468 s->fd = ast_timer_fd(p->timer);
00469
00470 p->stats = &spandsp_global_stats.g711;
00471
00472 if (s->details->caps & AST_FAX_TECH_T38) {
00473 if ((s->details->caps & AST_FAX_TECH_AUDIO) == 0) {
00474
00475 p->ist38 = 1;
00476 p->stats = &spandsp_global_stats.t38;
00477 }
00478
00479
00480 t38_terminal_init(&p->t38_state, caller_mode, t38_tx_packet_handler, p);
00481 set_logging(&p->t38_state.logging, s->details);
00482 }
00483
00484 if (s->details->caps & AST_FAX_TECH_AUDIO) {
00485
00486 fax_init(&p->fax_state, caller_mode);
00487 set_logging(&p->fax_state.logging, s->details);
00488 }
00489
00490 s->state = AST_FAX_STATE_INITIALIZED;
00491 return p;
00492
00493 e_free:
00494 ast_free(p);
00495 e_return:
00496 return NULL;
00497 }
00498
00499
00500
00501 static void spandsp_fax_destroy(struct ast_fax_session *s)
00502 {
00503 struct spandsp_pvt *p = s->tech_pvt;
00504
00505 session_destroy(p);
00506 ast_free(p);
00507 s->tech_pvt = NULL;
00508 s->fd = -1;
00509 }
00510
00511
00512
00513 static struct ast_frame *spandsp_fax_read(struct ast_fax_session *s)
00514 {
00515 struct spandsp_pvt *p = s->tech_pvt;
00516 uint8_t buffer[AST_FRIENDLY_OFFSET + SPANDSP_FAX_SAMPLES * sizeof(uint16_t)];
00517 int16_t *buf = (int16_t *) (buffer + AST_FRIENDLY_OFFSET);
00518 int samples;
00519
00520 struct ast_frame fax_frame = {
00521 .frametype = AST_FRAME_VOICE,
00522 .subclass.codec = AST_FORMAT_SLINEAR,
00523 .src = "res_fax_spandsp_g711",
00524 };
00525
00526 struct ast_frame *f = &fax_frame;
00527
00528 ast_timer_ack(p->timer, 1);
00529
00530
00531 if (p->isdone) {
00532 s->state = AST_FAX_STATE_COMPLETE;
00533 ast_debug(5, "FAX session '%d' is complete.\n", s->id);
00534 return NULL;
00535 }
00536
00537 if (p->ist38) {
00538 t38_terminal_send_timeout(&p->t38_state, SPANDSP_FAX_SAMPLES);
00539 if ((f = AST_LIST_REMOVE_HEAD(&p->read_frames, frame_list))) {
00540 return f;
00541 }
00542 } else {
00543 if ((samples = fax_tx(&p->fax_state, buf, SPANDSP_FAX_SAMPLES)) > 0) {
00544 f->samples = samples;
00545 AST_FRAME_SET_BUFFER(f, buffer, AST_FRIENDLY_OFFSET, samples * sizeof(int16_t));
00546 return ast_frisolate(f);
00547 }
00548 }
00549
00550 return &ast_null_frame;
00551 }
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563 static int spandsp_fax_write(struct ast_fax_session *s, const struct ast_frame *f)
00564 {
00565 struct spandsp_pvt *p = s->tech_pvt;
00566
00567
00568 if (s->state == AST_FAX_STATE_COMPLETE) {
00569 ast_log(LOG_WARNING, "FAX session '%d' is in the '%s' state.\n", s->id, ast_fax_state_to_str(s->state));
00570 return -1;
00571 }
00572
00573 if (p->ist38) {
00574 return t38_core_rx_ifp_packet(p->t38_core_state, f->data.ptr, f->datalen, f->seqno);
00575 } else {
00576 return fax_rx(&p->fax_state, f->data.ptr, f->samples);
00577 }
00578 }
00579
00580
00581 static int spandsp_fax_start(struct ast_fax_session *s)
00582 {
00583 struct spandsp_pvt *p = s->tech_pvt;
00584
00585 s->state = AST_FAX_STATE_OPEN;
00586
00587 if (p->ist38) {
00588 #if SPANDSP_RELEASE_DATE >= 20080725
00589
00590 p->t30_state = &p->t38_state.t30;
00591 p->t38_core_state = &p->t38_state.t38_fe.t38;
00592 #else
00593
00594 p->t30_state = &p->t38_state.t30_state;
00595 p->t38_core_state = &p->t38_state.t38;
00596 #endif
00597 } else {
00598 #if SPANDSP_RELEASE_DATE >= 20080725
00599
00600 p->t30_state = &p->fax_state.t30;
00601 #else
00602
00603 p->t30_state = &p->fax_state.t30_state;
00604 #endif
00605 }
00606
00607 set_logging(&p->t30_state->logging, s->details);
00608
00609
00610 set_local_info(p->t30_state, s->details);
00611 set_file(p->t30_state, s->details);
00612 set_ecm(p->t30_state, s->details);
00613 t30_set_supported_modems(p->t30_state, spandsp_modems(s->details));
00614
00615
00616
00617 t30_set_phase_e_handler(p->t30_state, t30_phase_e_handler, s);
00618
00619
00620 if (p->ist38) {
00621 set_logging(&p->t38_core_state->logging, s->details);
00622
00623 t38_set_max_datagram_size(p->t38_core_state, s->details->their_t38_parameters.max_ifp);
00624
00625 if (s->details->their_t38_parameters.fill_bit_removal) {
00626 t38_set_fill_bit_removal(p->t38_core_state, TRUE);
00627 }
00628
00629 if (s->details->their_t38_parameters.transcoding_mmr) {
00630 t38_set_mmr_transcoding(p->t38_core_state, TRUE);
00631 }
00632
00633 if (s->details->their_t38_parameters.transcoding_jbig) {
00634 t38_set_jbig_transcoding(p->t38_core_state, TRUE);
00635 }
00636 } else {
00637
00638 fax_set_transmit_on_idle(&p->fax_state, 1);
00639 }
00640
00641
00642
00643 if (ast_timer_set_rate(p->timer, SPANDSP_FAX_TIMER_RATE)) {
00644 ast_log(LOG_ERROR, "FAX session '%d' error setting rate on timing source.\n", s->id);
00645 return -1;
00646 }
00647
00648 s->state = AST_FAX_STATE_ACTIVE;
00649
00650 return 0;
00651 }
00652
00653
00654 static int spandsp_fax_cancel(struct ast_fax_session *s)
00655 {
00656 struct spandsp_pvt *p = s->tech_pvt;
00657 t30_terminate(p->t30_state);
00658 p->isdone = 1;
00659 return 0;
00660 }
00661
00662
00663 static int spandsp_fax_switch_to_t38(struct ast_fax_session *s)
00664 {
00665 struct spandsp_pvt *p = s->tech_pvt;
00666
00667
00668 t30_set_phase_e_handler(p->t30_state, NULL, NULL);
00669
00670 t30_terminate(p->t30_state);
00671
00672 s->details->option.switch_to_t38 = 1;
00673 ast_atomic_fetchadd_int(&p->stats->switched, 1);
00674
00675 p->ist38 = 1;
00676 p->stats = &spandsp_global_stats.t38;
00677 spandsp_fax_start(s);
00678
00679 return 0;
00680 }
00681
00682
00683 static char *spandsp_fax_cli_show_capabilities(int fd)
00684 {
00685 ast_cli(fd, "SEND RECEIVE T.38 G.711\n\n");
00686 return CLI_SUCCESS;
00687 }
00688
00689
00690 static char *spandsp_fax_cli_show_session(struct ast_fax_session *s, int fd)
00691 {
00692 struct spandsp_pvt *p = s->tech_pvt;
00693 t30_stats_t stats;
00694
00695 ao2_lock(s);
00696 ast_cli(fd, "%-22s : %d\n", "session", s->id);
00697 ast_cli(fd, "%-22s : %s\n", "operation", (s->details->caps & AST_FAX_TECH_RECEIVE) ? "Receive" : "Transmit");
00698 ast_cli(fd, "%-22s : %s\n", "state", ast_fax_state_to_str(s->state));
00699 if (s->state != AST_FAX_STATE_UNINITIALIZED) {
00700 t30_get_transfer_statistics(p->t30_state, &stats);
00701 ast_cli(fd, "%-22s : %s\n", "Last Status", t30_completion_code_to_str(stats.current_status));
00702 ast_cli(fd, "%-22s : %s\n", "ECM Mode", stats.error_correcting_mode ? "Yes" : "No");
00703 ast_cli(fd, "%-22s : %d\n", "Data Rate", stats.bit_rate);
00704 ast_cli(fd, "%-22s : %dx%d\n", "Image Resolution", stats.x_resolution, stats.y_resolution);
00705 #if SPANDSP_RELEASE_DATE >= 20090220
00706 ast_cli(fd, "%-22s : %d\n", "Page Number", ((s->details->caps & AST_FAX_TECH_RECEIVE) ? stats.pages_rx : stats.pages_tx) + 1);
00707 #else
00708 ast_cli(fd, "%-22s : %d\n", "Page Number", stats.pages_transferred + 1);
00709 #endif
00710 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);
00711
00712 ast_cli(fd, "\nData Statistics:\n");
00713 #if SPANDSP_RELEASE_DATE >= 20090220
00714 ast_cli(fd, "%-22s : %d\n", "Tx Pages", stats.pages_tx);
00715 ast_cli(fd, "%-22s : %d\n", "Rx Pages", stats.pages_rx);
00716 #else
00717 ast_cli(fd, "%-22s : %d\n", "Tx Pages", (s->details->caps & AST_FAX_TECH_SEND) ? stats.pages_transferred : 0);
00718 ast_cli(fd, "%-22s : %d\n", "Rx Pages", (s->details->caps & AST_FAX_TECH_RECEIVE) ? stats.pages_transferred : 0);
00719 #endif
00720 ast_cli(fd, "%-22s : %d\n", "Longest Bad Line Run", stats.longest_bad_row_run);
00721 ast_cli(fd, "%-22s : %d\n", "Total Bad Lines", stats.bad_rows);
00722 }
00723 ao2_unlock(s);
00724 ast_cli(fd, "\n\n");
00725 return CLI_SUCCESS;
00726 }
00727
00728
00729 static char *spandsp_fax_cli_show_stats(int fd)
00730 {
00731 ast_mutex_lock(&spandsp_global_stats.lock);
00732 ast_cli(fd, "\n%-20.20s\n", "Spandsp G.711");
00733 ast_cli(fd, "%-20.20s : %d\n", "Success", spandsp_global_stats.g711.success);
00734 ast_cli(fd, "%-20.20s : %d\n", "Switched to T.38", spandsp_global_stats.g711.switched);
00735 ast_cli(fd, "%-20.20s : %d\n", "Call Dropped", spandsp_global_stats.g711.call_dropped);
00736 ast_cli(fd, "%-20.20s : %d\n", "No FAX", spandsp_global_stats.g711.nofax);
00737 ast_cli(fd, "%-20.20s : %d\n", "Negotiation Failed", spandsp_global_stats.g711.neg_failed);
00738 ast_cli(fd, "%-20.20s : %d\n", "Train Failure", spandsp_global_stats.g711.failed_to_train);
00739 ast_cli(fd, "%-20.20s : %d\n", "Retries Exceeded", spandsp_global_stats.g711.retries_exceeded);
00740 ast_cli(fd, "%-20.20s : %d\n", "Protocol Error", spandsp_global_stats.g711.protocol_error);
00741 ast_cli(fd, "%-20.20s : %d\n", "TX Protocol Error", spandsp_global_stats.g711.tx_protocol_error);
00742 ast_cli(fd, "%-20.20s : %d\n", "RX Protocol Error", spandsp_global_stats.g711.rx_protocol_error);
00743 ast_cli(fd, "%-20.20s : %d\n", "File Error", spandsp_global_stats.g711.file_error);
00744 ast_cli(fd, "%-20.20s : %d\n", "Memory Error", spandsp_global_stats.g711.mem_error);
00745 ast_cli(fd, "%-20.20s : %d\n", "Unknown Error", spandsp_global_stats.g711.unknown_error);
00746
00747 ast_cli(fd, "\n%-20.20s\n", "Spandsp T.38");
00748 ast_cli(fd, "%-20.20s : %d\n", "Success", spandsp_global_stats.t38.success);
00749 ast_cli(fd, "%-20.20s : %d\n", "Call Dropped", spandsp_global_stats.t38.call_dropped);
00750 ast_cli(fd, "%-20.20s : %d\n", "No FAX", spandsp_global_stats.t38.nofax);
00751 ast_cli(fd, "%-20.20s : %d\n", "Negotiation Failed", spandsp_global_stats.t38.neg_failed);
00752 ast_cli(fd, "%-20.20s : %d\n", "Train Failure", spandsp_global_stats.t38.failed_to_train);
00753 ast_cli(fd, "%-20.20s : %d\n", "Retries Exceeded", spandsp_global_stats.t38.retries_exceeded);
00754 ast_cli(fd, "%-20.20s : %d\n", "Protocol Error", spandsp_global_stats.t38.protocol_error);
00755 ast_cli(fd, "%-20.20s : %d\n", "TX Protocol Error", spandsp_global_stats.t38.tx_protocol_error);
00756 ast_cli(fd, "%-20.20s : %d\n", "RX Protocol Error", spandsp_global_stats.t38.rx_protocol_error);
00757 ast_cli(fd, "%-20.20s : %d\n", "File Error", spandsp_global_stats.t38.file_error);
00758 ast_cli(fd, "%-20.20s : %d\n", "Memory Error", spandsp_global_stats.t38.mem_error);
00759 ast_cli(fd, "%-20.20s : %d\n", "Unknown Error", spandsp_global_stats.t38.unknown_error);
00760 ast_mutex_unlock(&spandsp_global_stats.lock);
00761
00762 return CLI_SUCCESS;
00763 }
00764
00765
00766 static char *spandsp_fax_cli_show_settings(int fd)
00767 {
00768
00769 return CLI_SUCCESS;
00770 }
00771
00772
00773 static int unload_module(void)
00774 {
00775 ast_fax_tech_unregister(&spandsp_fax_tech);
00776 ast_mutex_destroy(&spandsp_global_stats.lock);
00777 return AST_MODULE_LOAD_SUCCESS;
00778 }
00779
00780
00781 static int load_module(void)
00782 {
00783 ast_mutex_init(&spandsp_global_stats.lock);
00784 spandsp_fax_tech.module = ast_module_info->self;
00785 if (ast_fax_tech_register(&spandsp_fax_tech) < 0) {
00786 ast_log(LOG_ERROR, "failed to register FAX technology\n");
00787 return AST_MODULE_LOAD_DECLINE;
00788 }
00789
00790
00791 span_set_message_handler(NULL);
00792
00793 return AST_MODULE_LOAD_SUCCESS;
00794 }
00795
00796
00797 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Spandsp G.711 and T.38 FAX Technologies",
00798 .load = load_module,
00799 .unload = unload_module,
00800 );