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