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