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: 375893 $")
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 p->timer = NULL;
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 if (ast_timer_ack(p->timer, 1) < 0) {
00529 ast_log(LOG_ERROR, "Failed to acknowledge timer for FAX session '%d'\n", s->id);
00530 return NULL;
00531 }
00532
00533
00534 if (p->isdone) {
00535 s->state = AST_FAX_STATE_COMPLETE;
00536 ast_debug(5, "FAX session '%d' is complete.\n", s->id);
00537 return NULL;
00538 }
00539
00540 if (p->ist38) {
00541 t38_terminal_send_timeout(&p->t38_state, SPANDSP_FAX_SAMPLES);
00542 if ((f = AST_LIST_REMOVE_HEAD(&p->read_frames, frame_list))) {
00543 return f;
00544 }
00545 } else {
00546 if ((samples = fax_tx(&p->fax_state, buf, SPANDSP_FAX_SAMPLES)) > 0) {
00547 f->samples = samples;
00548 AST_FRAME_SET_BUFFER(f, buffer, AST_FRIENDLY_OFFSET, samples * sizeof(int16_t));
00549 return ast_frisolate(f);
00550 }
00551 }
00552
00553 return &ast_null_frame;
00554 }
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566 static int spandsp_fax_write(struct ast_fax_session *s, const struct ast_frame *f)
00567 {
00568 struct spandsp_pvt *p = s->tech_pvt;
00569
00570
00571 if (s->state == AST_FAX_STATE_COMPLETE) {
00572 ast_log(LOG_WARNING, "FAX session '%d' is in the '%s' state.\n", s->id, ast_fax_state_to_str(s->state));
00573 return -1;
00574 }
00575
00576 if (p->ist38) {
00577 return t38_core_rx_ifp_packet(p->t38_core_state, f->data.ptr, f->datalen, f->seqno);
00578 } else {
00579 return fax_rx(&p->fax_state, f->data.ptr, f->samples);
00580 }
00581 }
00582
00583
00584 static int spandsp_fax_start(struct ast_fax_session *s)
00585 {
00586 struct spandsp_pvt *p = s->tech_pvt;
00587
00588 s->state = AST_FAX_STATE_OPEN;
00589
00590 if (p->ist38) {
00591 #if SPANDSP_RELEASE_DATE >= 20080725
00592
00593 p->t30_state = &p->t38_state.t30;
00594 p->t38_core_state = &p->t38_state.t38_fe.t38;
00595 #else
00596
00597 p->t30_state = &p->t38_state.t30_state;
00598 p->t38_core_state = &p->t38_state.t38;
00599 #endif
00600 } else {
00601 #if SPANDSP_RELEASE_DATE >= 20080725
00602
00603 p->t30_state = &p->fax_state.t30;
00604 #else
00605
00606 p->t30_state = &p->fax_state.t30_state;
00607 #endif
00608 }
00609
00610 set_logging(&p->t30_state->logging, s->details);
00611
00612
00613 set_local_info(p->t30_state, s->details);
00614 set_file(p->t30_state, s->details);
00615 set_ecm(p->t30_state, s->details);
00616 t30_set_supported_modems(p->t30_state, spandsp_modems(s->details));
00617
00618
00619
00620 t30_set_phase_e_handler(p->t30_state, t30_phase_e_handler, s);
00621
00622
00623 if (p->ist38) {
00624 set_logging(&p->t38_core_state->logging, s->details);
00625
00626 t38_set_max_datagram_size(p->t38_core_state, s->details->their_t38_parameters.max_ifp);
00627
00628 if (s->details->their_t38_parameters.fill_bit_removal) {
00629 t38_set_fill_bit_removal(p->t38_core_state, TRUE);
00630 }
00631
00632 if (s->details->their_t38_parameters.transcoding_mmr) {
00633 t38_set_mmr_transcoding(p->t38_core_state, TRUE);
00634 }
00635
00636 if (s->details->their_t38_parameters.transcoding_jbig) {
00637 t38_set_jbig_transcoding(p->t38_core_state, TRUE);
00638 }
00639 } else {
00640
00641 fax_set_transmit_on_idle(&p->fax_state, 1);
00642 }
00643
00644
00645
00646 if (ast_timer_set_rate(p->timer, SPANDSP_FAX_TIMER_RATE)) {
00647 ast_log(LOG_ERROR, "FAX session '%d' error setting rate on timing source.\n", s->id);
00648 return -1;
00649 }
00650
00651 s->state = AST_FAX_STATE_ACTIVE;
00652
00653 return 0;
00654 }
00655
00656
00657 static int spandsp_fax_cancel(struct ast_fax_session *s)
00658 {
00659 struct spandsp_pvt *p = s->tech_pvt;
00660 t30_terminate(p->t30_state);
00661 p->isdone = 1;
00662 return 0;
00663 }
00664
00665
00666 static int spandsp_fax_switch_to_t38(struct ast_fax_session *s)
00667 {
00668 struct spandsp_pvt *p = s->tech_pvt;
00669
00670
00671 t30_set_phase_e_handler(p->t30_state, NULL, NULL);
00672
00673 t30_terminate(p->t30_state);
00674
00675 s->details->option.switch_to_t38 = 1;
00676 ast_atomic_fetchadd_int(&p->stats->switched, 1);
00677
00678 p->ist38 = 1;
00679 p->stats = &spandsp_global_stats.t38;
00680 spandsp_fax_start(s);
00681
00682 return 0;
00683 }
00684
00685
00686 static char *spandsp_fax_cli_show_capabilities(int fd)
00687 {
00688 ast_cli(fd, "SEND RECEIVE T.38 G.711\n\n");
00689 return CLI_SUCCESS;
00690 }
00691
00692
00693 static char *spandsp_fax_cli_show_session(struct ast_fax_session *s, int fd)
00694 {
00695 struct spandsp_pvt *p = s->tech_pvt;
00696 t30_stats_t stats;
00697
00698 ao2_lock(s);
00699 ast_cli(fd, "%-22s : %d\n", "session", s->id);
00700 ast_cli(fd, "%-22s : %s\n", "operation", (s->details->caps & AST_FAX_TECH_RECEIVE) ? "Receive" : "Transmit");
00701 ast_cli(fd, "%-22s : %s\n", "state", ast_fax_state_to_str(s->state));
00702 if (s->state != AST_FAX_STATE_UNINITIALIZED) {
00703 t30_get_transfer_statistics(p->t30_state, &stats);
00704 ast_cli(fd, "%-22s : %s\n", "Last Status", t30_completion_code_to_str(stats.current_status));
00705 ast_cli(fd, "%-22s : %s\n", "ECM Mode", stats.error_correcting_mode ? "Yes" : "No");
00706 ast_cli(fd, "%-22s : %d\n", "Data Rate", stats.bit_rate);
00707 ast_cli(fd, "%-22s : %dx%d\n", "Image Resolution", stats.x_resolution, stats.y_resolution);
00708 #if SPANDSP_RELEASE_DATE >= 20090220
00709 ast_cli(fd, "%-22s : %d\n", "Page Number", ((s->details->caps & AST_FAX_TECH_RECEIVE) ? stats.pages_rx : stats.pages_tx) + 1);
00710 #else
00711 ast_cli(fd, "%-22s : %d\n", "Page Number", stats.pages_transferred + 1);
00712 #endif
00713 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);
00714
00715 ast_cli(fd, "\nData Statistics:\n");
00716 #if SPANDSP_RELEASE_DATE >= 20090220
00717 ast_cli(fd, "%-22s : %d\n", "Tx Pages", stats.pages_tx);
00718 ast_cli(fd, "%-22s : %d\n", "Rx Pages", stats.pages_rx);
00719 #else
00720 ast_cli(fd, "%-22s : %d\n", "Tx Pages", (s->details->caps & AST_FAX_TECH_SEND) ? stats.pages_transferred : 0);
00721 ast_cli(fd, "%-22s : %d\n", "Rx Pages", (s->details->caps & AST_FAX_TECH_RECEIVE) ? stats.pages_transferred : 0);
00722 #endif
00723 ast_cli(fd, "%-22s : %d\n", "Longest Bad Line Run", stats.longest_bad_row_run);
00724 ast_cli(fd, "%-22s : %d\n", "Total Bad Lines", stats.bad_rows);
00725 }
00726 ao2_unlock(s);
00727 ast_cli(fd, "\n\n");
00728 return CLI_SUCCESS;
00729 }
00730
00731
00732 static char *spandsp_fax_cli_show_stats(int fd)
00733 {
00734 ast_mutex_lock(&spandsp_global_stats.lock);
00735 ast_cli(fd, "\n%-20.20s\n", "Spandsp G.711");
00736 ast_cli(fd, "%-20.20s : %d\n", "Success", spandsp_global_stats.g711.success);
00737 ast_cli(fd, "%-20.20s : %d\n", "Switched to T.38", spandsp_global_stats.g711.switched);
00738 ast_cli(fd, "%-20.20s : %d\n", "Call Dropped", spandsp_global_stats.g711.call_dropped);
00739 ast_cli(fd, "%-20.20s : %d\n", "No FAX", spandsp_global_stats.g711.nofax);
00740 ast_cli(fd, "%-20.20s : %d\n", "Negotiation Failed", spandsp_global_stats.g711.neg_failed);
00741 ast_cli(fd, "%-20.20s : %d\n", "Train Failure", spandsp_global_stats.g711.failed_to_train);
00742 ast_cli(fd, "%-20.20s : %d\n", "Retries Exceeded", spandsp_global_stats.g711.retries_exceeded);
00743 ast_cli(fd, "%-20.20s : %d\n", "Protocol Error", spandsp_global_stats.g711.protocol_error);
00744 ast_cli(fd, "%-20.20s : %d\n", "TX Protocol Error", spandsp_global_stats.g711.tx_protocol_error);
00745 ast_cli(fd, "%-20.20s : %d\n", "RX Protocol Error", spandsp_global_stats.g711.rx_protocol_error);
00746 ast_cli(fd, "%-20.20s : %d\n", "File Error", spandsp_global_stats.g711.file_error);
00747 ast_cli(fd, "%-20.20s : %d\n", "Memory Error", spandsp_global_stats.g711.mem_error);
00748 ast_cli(fd, "%-20.20s : %d\n", "Unknown Error", spandsp_global_stats.g711.unknown_error);
00749
00750 ast_cli(fd, "\n%-20.20s\n", "Spandsp T.38");
00751 ast_cli(fd, "%-20.20s : %d\n", "Success", spandsp_global_stats.t38.success);
00752 ast_cli(fd, "%-20.20s : %d\n", "Call Dropped", spandsp_global_stats.t38.call_dropped);
00753 ast_cli(fd, "%-20.20s : %d\n", "No FAX", spandsp_global_stats.t38.nofax);
00754 ast_cli(fd, "%-20.20s : %d\n", "Negotiation Failed", spandsp_global_stats.t38.neg_failed);
00755 ast_cli(fd, "%-20.20s : %d\n", "Train Failure", spandsp_global_stats.t38.failed_to_train);
00756 ast_cli(fd, "%-20.20s : %d\n", "Retries Exceeded", spandsp_global_stats.t38.retries_exceeded);
00757 ast_cli(fd, "%-20.20s : %d\n", "Protocol Error", spandsp_global_stats.t38.protocol_error);
00758 ast_cli(fd, "%-20.20s : %d\n", "TX Protocol Error", spandsp_global_stats.t38.tx_protocol_error);
00759 ast_cli(fd, "%-20.20s : %d\n", "RX Protocol Error", spandsp_global_stats.t38.rx_protocol_error);
00760 ast_cli(fd, "%-20.20s : %d\n", "File Error", spandsp_global_stats.t38.file_error);
00761 ast_cli(fd, "%-20.20s : %d\n", "Memory Error", spandsp_global_stats.t38.mem_error);
00762 ast_cli(fd, "%-20.20s : %d\n", "Unknown Error", spandsp_global_stats.t38.unknown_error);
00763 ast_mutex_unlock(&spandsp_global_stats.lock);
00764
00765 return CLI_SUCCESS;
00766 }
00767
00768
00769 static char *spandsp_fax_cli_show_settings(int fd)
00770 {
00771
00772 return CLI_SUCCESS;
00773 }
00774
00775
00776 static int unload_module(void)
00777 {
00778 ast_fax_tech_unregister(&spandsp_fax_tech);
00779 ast_mutex_destroy(&spandsp_global_stats.lock);
00780 return AST_MODULE_LOAD_SUCCESS;
00781 }
00782
00783
00784 static int load_module(void)
00785 {
00786 ast_mutex_init(&spandsp_global_stats.lock);
00787 spandsp_fax_tech.module = ast_module_info->self;
00788 if (ast_fax_tech_register(&spandsp_fax_tech) < 0) {
00789 ast_log(LOG_ERROR, "failed to register FAX technology\n");
00790 return AST_MODULE_LOAD_DECLINE;
00791 }
00792
00793
00794 span_set_message_handler(NULL);
00795
00796 return AST_MODULE_LOAD_SUCCESS;
00797 }
00798
00799
00800 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Spandsp G.711 and T.38 FAX Technologies",
00801 .load = load_module,
00802 .unload = unload_module,
00803 );