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