res_fax_spandsp.c 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 2009-2010, Digium, Inc.
  5. *
  6. * Matthew Nicholson <mnicholson@digium.com>
  7. *
  8. * Initial T.38-gateway code
  9. * 2008, Daniel Ferenci <daniel.ferenci@nethemba.com>
  10. * Created by Nethemba s.r.o. http://www.nethemba.com
  11. * Sponsored by IPEX a.s. http://www.ipex.cz
  12. *
  13. * T.38-gateway integration into asterisk app_fax and rework
  14. * 2008, Gregory Hinton Nietsky <gregory@dnstelecom.co.za>
  15. * dns Telecom http://www.dnstelecom.co.za
  16. *
  17. * Modified to make T.38-gateway compatible with Asterisk 1.6.2
  18. * 2010, Anton Verevkin <mymail@verevkin.it>
  19. * ViaNetTV http://www.vianettv.com
  20. *
  21. * Modified to make T.38-gateway work
  22. * 2010, Klaus Darilion, IPCom GmbH, www.ipcom.at
  23. *
  24. * See http://www.asterisk.org for more information about
  25. * the Asterisk project. Please do not directly contact
  26. * any of the maintainers of this project for assistance;
  27. * the project provides a web site, mailing lists and IRC
  28. * channels for your use.
  29. *
  30. * This program is free software, distributed under the terms of
  31. * the GNU General Public License Version 2. See the LICENSE file
  32. * at the top of the source tree.
  33. */
  34. /*! \file
  35. *
  36. * \brief Spandsp T.38 and G.711 FAX Resource
  37. *
  38. * \author Matthew Nicholson <mnicholson@digium.com>
  39. * \author Gregory H. Nietsky <gregory@distrotech.co.za>
  40. *
  41. * This module registers the Spandsp FAX technology with the res_fax module.
  42. */
  43. /*** MODULEINFO
  44. <depend>spandsp</depend>
  45. <depend>res_fax</depend>
  46. <support_level>extended</support_level>
  47. ***/
  48. #include "asterisk.h"
  49. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  50. #define SPANDSP_EXPOSE_INTERNAL_STRUCTURES
  51. #include <spandsp.h>
  52. #include <spandsp/version.h>
  53. #include "asterisk/logger.h"
  54. #include "asterisk/module.h"
  55. #include "asterisk/strings.h"
  56. #include "asterisk/cli.h"
  57. #include "asterisk/utils.h"
  58. #include "asterisk/timing.h"
  59. #include "asterisk/astobj2.h"
  60. #include "asterisk/res_fax.h"
  61. #include "asterisk/channel.h"
  62. #define SPANDSP_FAX_SAMPLES 160
  63. #define SPANDSP_FAX_TIMER_RATE 8000 / SPANDSP_FAX_SAMPLES /* 50 ticks per second, 20ms, 160 samples per second */
  64. #define SPANDSP_ENGAGE_UDPTL_NAT_RETRY 3
  65. static void *spandsp_fax_new(struct ast_fax_session *s, struct ast_fax_tech_token *token);
  66. static void spandsp_fax_destroy(struct ast_fax_session *s);
  67. static struct ast_frame *spandsp_fax_read(struct ast_fax_session *s);
  68. static int spandsp_fax_write(struct ast_fax_session *s, const struct ast_frame *f);
  69. static int spandsp_fax_start(struct ast_fax_session *s);
  70. static int spandsp_fax_cancel(struct ast_fax_session *s);
  71. static int spandsp_fax_switch_to_t38(struct ast_fax_session *s);
  72. static int spandsp_fax_gateway_start(struct ast_fax_session *s);
  73. static int spandsp_fax_gateway_process(struct ast_fax_session *s, const struct ast_frame *f);
  74. static void spandsp_fax_gateway_cleanup(struct ast_fax_session *s);
  75. static int spandsp_v21_detect(struct ast_fax_session *s, const struct ast_frame *f);
  76. static void spandsp_v21_cleanup(struct ast_fax_session *s);
  77. static void spandsp_v21_tone(void *data, int code, int level, int delay);
  78. static char *spandsp_fax_cli_show_capabilities(int fd);
  79. static char *spandsp_fax_cli_show_session(struct ast_fax_session *s, int fd);
  80. static char *spandsp_fax_cli_show_stats(int fd);
  81. static char *spandsp_fax_cli_show_settings(int fd);
  82. static struct ast_fax_tech spandsp_fax_tech = {
  83. .type = "Spandsp",
  84. .description = "Spandsp FAX Driver",
  85. #if SPANDSP_RELEASE_DATE >= 20090220
  86. /* spandsp 0.0.6 */
  87. .version = SPANDSP_RELEASE_DATETIME_STRING,
  88. #else
  89. /* spandsp 0.0.5
  90. * TODO: maybe we should determine the version better way
  91. */
  92. .version = "pre-20090220",
  93. #endif
  94. .caps = AST_FAX_TECH_AUDIO | AST_FAX_TECH_T38 | AST_FAX_TECH_SEND
  95. | AST_FAX_TECH_RECEIVE | AST_FAX_TECH_GATEWAY
  96. | AST_FAX_TECH_V21_DETECT,
  97. .new_session = spandsp_fax_new,
  98. .destroy_session = spandsp_fax_destroy,
  99. .read = spandsp_fax_read,
  100. .write = spandsp_fax_write,
  101. .start_session = spandsp_fax_start,
  102. .cancel_session = spandsp_fax_cancel,
  103. .switch_to_t38 = spandsp_fax_switch_to_t38,
  104. .cli_show_capabilities = spandsp_fax_cli_show_capabilities,
  105. .cli_show_session = spandsp_fax_cli_show_session,
  106. .cli_show_stats = spandsp_fax_cli_show_stats,
  107. .cli_show_settings = spandsp_fax_cli_show_settings,
  108. };
  109. struct spandsp_fax_stats {
  110. int success;
  111. int nofax;
  112. int neg_failed;
  113. int failed_to_train;
  114. int rx_protocol_error;
  115. int tx_protocol_error;
  116. int protocol_error;
  117. int retries_exceeded;
  118. int file_error;
  119. int mem_error;
  120. int call_dropped;
  121. int unknown_error;
  122. int switched;
  123. };
  124. static struct {
  125. ast_mutex_t lock;
  126. struct spandsp_fax_stats g711;
  127. struct spandsp_fax_stats t38;
  128. } spandsp_global_stats;
  129. struct spandsp_pvt {
  130. unsigned int ist38:1;
  131. unsigned int isdone:1;
  132. enum ast_t38_state ast_t38_state;
  133. fax_state_t fax_state;
  134. t38_terminal_state_t t38_state;
  135. t30_state_t *t30_state;
  136. t38_core_state_t *t38_core_state;
  137. struct spandsp_fax_stats *stats;
  138. struct spandsp_fax_gw_stats *t38stats;
  139. t38_gateway_state_t t38_gw_state;
  140. struct ast_timer *timer;
  141. AST_LIST_HEAD(frame_queue, ast_frame) read_frames;
  142. int v21_detected;
  143. modem_connect_tones_rx_state_t *tone_state;
  144. };
  145. static int spandsp_v21_new(struct spandsp_pvt *p);
  146. static void session_destroy(struct spandsp_pvt *p);
  147. static int t38_tx_packet_handler(t38_core_state_t *t38_core_state, void *data, const uint8_t *buf, int len, int count);
  148. static void t30_phase_e_handler(t30_state_t *t30_state, void *data, int completion_code);
  149. static void spandsp_log(int level, const char *msg);
  150. static int update_stats(struct spandsp_pvt *p, int completion_code);
  151. static int spandsp_modems(struct ast_fax_session_details *details);
  152. static void set_logging(logging_state_t *state, struct ast_fax_session_details *details);
  153. static void set_local_info(t30_state_t *t30_state, struct ast_fax_session_details *details);
  154. static void set_file(t30_state_t *t30_state, struct ast_fax_session_details *details);
  155. static void set_ecm(t30_state_t *t30_state, struct ast_fax_session_details *details);
  156. static void session_destroy(struct spandsp_pvt *p)
  157. {
  158. struct ast_frame *f;
  159. t30_terminate(p->t30_state);
  160. p->isdone = 1;
  161. ast_timer_close(p->timer);
  162. p->timer = NULL;
  163. fax_release(&p->fax_state);
  164. t38_terminal_release(&p->t38_state);
  165. while ((f = AST_LIST_REMOVE_HEAD(&p->read_frames, frame_list))) {
  166. ast_frfree(f);
  167. }
  168. }
  169. /*! \brief
  170. *
  171. */
  172. static int t38_tx_packet_handler(t38_core_state_t *t38_core_state, void *data, const uint8_t *buf, int len, int count)
  173. {
  174. int res = -1;
  175. struct ast_fax_session *s = data;
  176. struct spandsp_pvt *p = s->tech_pvt;
  177. struct ast_frame fax_frame = {
  178. .frametype = AST_FRAME_MODEM,
  179. .subclass.integer = AST_MODEM_T38,
  180. .src = "res_fax_spandsp_t38",
  181. };
  182. struct ast_frame *f = &fax_frame;
  183. /* TODO: Asterisk does not provide means of resending the same packet multiple
  184. times so count is ignored at the moment */
  185. AST_FRAME_SET_BUFFER(f, buf, 0, len);
  186. if (!(f = ast_frisolate(f))) {
  187. return res;
  188. }
  189. if (s->details->caps & AST_FAX_TECH_GATEWAY) {
  190. ast_set_flag(f, AST_FAX_FRFLAG_GATEWAY);
  191. if (p->ast_t38_state == T38_STATE_NEGOTIATED) {
  192. res = ast_write(s->chan, f);
  193. } else {
  194. res = ast_queue_frame(s->chan, f);
  195. }
  196. ast_frfree(f);
  197. } else {
  198. /* no need to lock, this all runs in the same thread */
  199. AST_LIST_INSERT_TAIL(&p->read_frames, f, frame_list);
  200. }
  201. return res;
  202. }
  203. static int update_stats(struct spandsp_pvt *p, int completion_code)
  204. {
  205. switch (completion_code) {
  206. case T30_ERR_OK:
  207. ast_atomic_fetchadd_int(&p->stats->success, 1);
  208. break;
  209. /* Link problems */
  210. case T30_ERR_CEDTONE: /*! The CED tone exceeded 5s */
  211. case T30_ERR_T0_EXPIRED: /*! Timed out waiting for initial communication */
  212. case T30_ERR_T1_EXPIRED: /*! Timed out waiting for the first message */
  213. case T30_ERR_T3_EXPIRED: /*! Timed out waiting for procedural interrupt */
  214. case T30_ERR_HDLC_CARRIER: /*! The HDLC carrier did not stop in a timely manner */
  215. case T30_ERR_CANNOT_TRAIN: /*! Failed to train with any of the compatible modems */
  216. ast_atomic_fetchadd_int(&p->stats->failed_to_train, 1);
  217. break;
  218. case T30_ERR_OPER_INT_FAIL: /*! Operator intervention failed */
  219. case T30_ERR_INCOMPATIBLE: /*! Far end is not compatible */
  220. case T30_ERR_RX_INCAPABLE: /*! Far end is not able to receive */
  221. case T30_ERR_TX_INCAPABLE: /*! Far end is not able to transmit */
  222. case T30_ERR_NORESSUPPORT: /*! Far end cannot receive at the resolution of the image */
  223. case T30_ERR_NOSIZESUPPORT: /*! Far end cannot receive at the size of image */
  224. ast_atomic_fetchadd_int(&p->stats->neg_failed, 1);
  225. break;
  226. case T30_ERR_UNEXPECTED: /*! Unexpected message received */
  227. ast_atomic_fetchadd_int(&p->stats->protocol_error, 1);
  228. break;
  229. /* Phase E status values returned to a transmitter */
  230. case T30_ERR_TX_BADDCS: /*! Received bad response to DCS or training */
  231. case T30_ERR_TX_BADPG: /*! Received a DCN from remote after sending a page */
  232. case T30_ERR_TX_ECMPHD: /*! Invalid ECM response received from receiver */
  233. case T30_ERR_TX_GOTDCN: /*! Received a DCN while waiting for a DIS */
  234. case T30_ERR_TX_INVALRSP: /*! Invalid response after sending a page */
  235. case T30_ERR_TX_NODIS: /*! Received other than DIS while waiting for DIS */
  236. case T30_ERR_TX_PHBDEAD: /*! Received no response to DCS, training or TCF */
  237. case T30_ERR_TX_PHDDEAD: /*! No response after sending a page */
  238. case T30_ERR_TX_T5EXP: /*! Timed out waiting for receiver ready (ECM mode) */
  239. ast_atomic_fetchadd_int(&p->stats->tx_protocol_error, 1);
  240. break;
  241. /* Phase E status values returned to a receiver */
  242. case T30_ERR_RX_ECMPHD: /*! Invalid ECM response received from transmitter */
  243. case T30_ERR_RX_GOTDCS: /*! DCS received while waiting for DTC */
  244. case T30_ERR_RX_INVALCMD: /*! Unexpected command after page received */
  245. case T30_ERR_RX_NOCARRIER: /*! Carrier lost during fax receive */
  246. case T30_ERR_RX_NOEOL: /*! Timed out while waiting for EOL (end Of line) */
  247. ast_atomic_fetchadd_int(&p->stats->rx_protocol_error, 1);
  248. break;
  249. case T30_ERR_RX_NOFAX: /*! Timed out while waiting for first line */
  250. ast_atomic_fetchadd_int(&p->stats->nofax, 1);
  251. break;
  252. case T30_ERR_RX_T2EXPDCN: /*! Timer T2 expired while waiting for DCN */
  253. case T30_ERR_RX_T2EXPD: /*! Timer T2 expired while waiting for phase D */
  254. case T30_ERR_RX_T2EXPFAX: /*! Timer T2 expired while waiting for fax page */
  255. case T30_ERR_RX_T2EXPMPS: /*! Timer T2 expired while waiting for next fax page */
  256. case T30_ERR_RX_T2EXPRR: /*! Timer T2 expired while waiting for RR command */
  257. case T30_ERR_RX_T2EXP: /*! Timer T2 expired while waiting for NSS, DCS or MCF */
  258. case T30_ERR_RX_DCNWHY: /*! Unexpected DCN while waiting for DCS or DIS */
  259. case T30_ERR_RX_DCNDATA: /*! Unexpected DCN while waiting for image data */
  260. case T30_ERR_RX_DCNFAX: /*! Unexpected DCN while waiting for EOM, EOP or MPS */
  261. case T30_ERR_RX_DCNPHD: /*! Unexpected DCN after EOM or MPS sequence */
  262. case T30_ERR_RX_DCNRRD: /*! Unexpected DCN after RR/RNR sequence */
  263. case T30_ERR_RX_DCNNORTN: /*! Unexpected DCN after requested retransmission */
  264. ast_atomic_fetchadd_int(&p->stats->rx_protocol_error, 1);
  265. break;
  266. /* TIFF file problems */
  267. case T30_ERR_FILEERROR: /*! TIFF/F file cannot be opened */
  268. case T30_ERR_NOPAGE: /*! TIFF/F page not found */
  269. case T30_ERR_BADTIFF: /*! TIFF/F format is not compatible */
  270. case T30_ERR_BADPAGE: /*! TIFF/F page number tag missing */
  271. case T30_ERR_BADTAG: /*! Incorrect values for TIFF/F tags */
  272. case T30_ERR_BADTIFFHDR: /*! Bad TIFF/F header - incorrect values in fields */
  273. ast_atomic_fetchadd_int(&p->stats->file_error, 1);
  274. break;
  275. case T30_ERR_NOMEM: /*! Cannot allocate memory for more pages */
  276. ast_atomic_fetchadd_int(&p->stats->mem_error, 1);
  277. break;
  278. /* General problems */
  279. case T30_ERR_RETRYDCN: /*! Disconnected after permitted retries */
  280. ast_atomic_fetchadd_int(&p->stats->retries_exceeded, 1);
  281. break;
  282. case T30_ERR_CALLDROPPED: /*! The call dropped prematurely */
  283. ast_atomic_fetchadd_int(&p->stats->call_dropped, 1);
  284. break;
  285. /* Feature negotiation issues */
  286. case T30_ERR_NOPOLL: /*! Poll not accepted */
  287. case T30_ERR_IDENT_UNACCEPTABLE: /*! Far end's ident is not acceptable */
  288. case T30_ERR_SUB_UNACCEPTABLE: /*! Far end's sub-address is not acceptable */
  289. case T30_ERR_SEP_UNACCEPTABLE: /*! Far end's selective polling address is not acceptable */
  290. case T30_ERR_PSA_UNACCEPTABLE: /*! Far end's polled sub-address is not acceptable */
  291. case T30_ERR_SID_UNACCEPTABLE: /*! Far end's sender identification is not acceptable */
  292. case T30_ERR_PWD_UNACCEPTABLE: /*! Far end's password is not acceptable */
  293. case T30_ERR_TSA_UNACCEPTABLE: /*! Far end's transmitting subscriber internet address is not acceptable */
  294. case T30_ERR_IRA_UNACCEPTABLE: /*! Far end's internet routing address is not acceptable */
  295. case T30_ERR_CIA_UNACCEPTABLE: /*! Far end's calling subscriber internet address is not acceptable */
  296. case T30_ERR_ISP_UNACCEPTABLE: /*! Far end's internet selective polling address is not acceptable */
  297. case T30_ERR_CSA_UNACCEPTABLE: /*! Far end's called subscriber internet address is not acceptable */
  298. ast_atomic_fetchadd_int(&p->stats->neg_failed, 1);
  299. break;
  300. default:
  301. ast_atomic_fetchadd_int(&p->stats->unknown_error, 1);
  302. ast_log(LOG_WARNING, "unknown FAX session result '%d' (%s)\n", completion_code, t30_completion_code_to_str(completion_code));
  303. return -1;
  304. }
  305. return 0;
  306. }
  307. /*! \brief Phase E handler callback.
  308. * \param t30_state the span t30 state
  309. * \param data this will be the ast_fax_session
  310. * \param completion_code the result of the fax session
  311. *
  312. * This function pulls stats from the spandsp stack and stores them for res_fax
  313. * to use later.
  314. */
  315. static void t30_phase_e_handler(t30_state_t *t30_state, void *data, int completion_code)
  316. {
  317. struct ast_fax_session *s = data;
  318. struct spandsp_pvt *p = s->tech_pvt;
  319. char headerinfo[T30_MAX_PAGE_HEADER_INFO + 1];
  320. const char *c;
  321. t30_stats_t stats;
  322. ast_debug(5, "FAX session '%d' entering phase E\n", s->id);
  323. p->isdone = 1;
  324. update_stats(p, completion_code);
  325. t30_get_transfer_statistics(t30_state, &stats);
  326. if (completion_code == T30_ERR_OK) {
  327. ast_string_field_set(s->details, result, "SUCCESS");
  328. } else {
  329. ast_string_field_set(s->details, result, "FAILED");
  330. ast_string_field_set(s->details, error, t30_completion_code_to_str(completion_code));
  331. }
  332. ast_string_field_set(s->details, resultstr, t30_completion_code_to_str(completion_code));
  333. ast_debug(5, "FAX session '%d' completed with result: %s (%s)\n", s->id, s->details->result, s->details->resultstr);
  334. if ((c = t30_get_tx_ident(t30_state))) {
  335. ast_string_field_set(s->details, localstationid, c);
  336. }
  337. if ((c = t30_get_rx_ident(t30_state))) {
  338. ast_string_field_set(s->details, remotestationid, c);
  339. }
  340. #if SPANDSP_RELEASE_DATE >= 20090220
  341. s->details->pages_transferred = (s->details->caps & AST_FAX_TECH_RECEIVE) ? stats.pages_rx : stats.pages_tx;
  342. #else
  343. s->details->pages_transferred = stats.pages_transferred;
  344. #endif
  345. ast_string_field_build(s->details, transfer_rate, "%d", stats.bit_rate);
  346. ast_string_field_build(s->details, resolution, "%dx%d", stats.x_resolution, stats.y_resolution);
  347. t30_get_tx_page_header_info(t30_state, headerinfo);
  348. ast_string_field_set(s->details, headerinfo, headerinfo);
  349. }
  350. /*! \brief Send spandsp log messages to asterisk.
  351. * \param level the spandsp logging level
  352. * \param msg the log message
  353. *
  354. * \note This function is a callback function called by spandsp.
  355. */
  356. static void spandsp_log(int level, const char *msg)
  357. {
  358. if (level == SPAN_LOG_ERROR) {
  359. ast_log(LOG_ERROR, "%s", msg);
  360. } else if (level == SPAN_LOG_WARNING) {
  361. ast_log(LOG_WARNING, "%s", msg);
  362. } else {
  363. ast_fax_log(LOG_DEBUG, msg);
  364. }
  365. }
  366. static void set_logging(logging_state_t *state, struct ast_fax_session_details *details)
  367. {
  368. int level = SPAN_LOG_WARNING;
  369. if (details->option.debug) {
  370. level = SPAN_LOG_DEBUG_3;
  371. }
  372. span_log_set_message_handler(state, spandsp_log);
  373. span_log_set_level(state, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | level);
  374. }
  375. static void set_local_info(t30_state_t *t30_state, struct ast_fax_session_details *details)
  376. {
  377. if (!ast_strlen_zero(details->localstationid)) {
  378. t30_set_tx_ident(t30_state, details->localstationid);
  379. }
  380. if (!ast_strlen_zero(details->headerinfo)) {
  381. t30_set_tx_page_header_info(t30_state, details->headerinfo);
  382. }
  383. }
  384. static void set_file(t30_state_t *t30_state, struct ast_fax_session_details *details)
  385. {
  386. if (details->caps & AST_FAX_TECH_RECEIVE) {
  387. t30_set_rx_file(t30_state, AST_LIST_FIRST(&details->documents)->filename, -1);
  388. } else {
  389. /* if not AST_FAX_TECH_RECEIVE, assume AST_FAX_TECH_SEND, this
  390. * should be safe because we ensure either RECEIVE or SEND is
  391. * indicated in spandsp_fax_new() */
  392. t30_set_tx_file(t30_state, AST_LIST_FIRST(&details->documents)->filename, -1, -1);
  393. }
  394. }
  395. static void set_ecm(t30_state_t *t30_state, struct ast_fax_session_details *details)
  396. {
  397. t30_set_ecm_capability(t30_state, details->option.ecm);
  398. t30_set_supported_compressions(t30_state, T30_SUPPORT_T4_1D_COMPRESSION | T30_SUPPORT_T4_2D_COMPRESSION | T30_SUPPORT_T6_COMPRESSION);
  399. }
  400. static int spandsp_v21_new(struct spandsp_pvt *p)
  401. {
  402. /* XXX Here we use MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE even though
  403. * we don't care about CED tones. Using MODEM_CONNECT_TONES_PREAMBLE
  404. * doesn't seem to work right all the time.
  405. */
  406. p->tone_state = modem_connect_tones_rx_init(NULL, MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE, spandsp_v21_tone, p);
  407. if (!p->tone_state) {
  408. return -1;
  409. }
  410. return 0;
  411. }
  412. static int spandsp_modems(struct ast_fax_session_details *details)
  413. {
  414. int modems = 0;
  415. if (AST_FAX_MODEM_V17 & details->modems) {
  416. modems |= T30_SUPPORT_V17;
  417. }
  418. if (AST_FAX_MODEM_V27 & details->modems) {
  419. modems |= T30_SUPPORT_V27TER;
  420. }
  421. if (AST_FAX_MODEM_V29 & details->modems) {
  422. modems |= T30_SUPPORT_V29;
  423. }
  424. if (AST_FAX_MODEM_V34 & details->modems) {
  425. #if defined(T30_SUPPORT_V34)
  426. modems |= T30_SUPPORT_V34;
  427. #elif defined(T30_SUPPORT_V34HDX)
  428. modems |= T30_SUPPORT_V34HDX;
  429. #else
  430. ast_log(LOG_WARNING, "v34 not supported in this version of spandsp\n");
  431. #endif
  432. }
  433. return modems;
  434. }
  435. /*! \brief create an instance of the spandsp tech_pvt for a fax session */
  436. static void *spandsp_fax_new(struct ast_fax_session *s, struct ast_fax_tech_token *token)
  437. {
  438. struct spandsp_pvt *p;
  439. int caller_mode;
  440. if ((!(p = ast_calloc(1, sizeof(*p))))) {
  441. ast_log(LOG_ERROR, "Cannot initialize the spandsp private FAX technology structure.\n");
  442. goto e_return;
  443. }
  444. if (s->details->caps & AST_FAX_TECH_V21_DETECT) {
  445. if (spandsp_v21_new(p)) {
  446. ast_log(LOG_ERROR, "Cannot initialize the spandsp private v21 technology structure.\n");
  447. goto e_return;
  448. }
  449. s->state = AST_FAX_STATE_ACTIVE;
  450. return p;
  451. }
  452. if (s->details->caps & AST_FAX_TECH_GATEWAY) {
  453. s->state = AST_FAX_STATE_INITIALIZED;
  454. return p;
  455. }
  456. AST_LIST_HEAD_INIT(&p->read_frames);
  457. if (s->details->caps & AST_FAX_TECH_RECEIVE) {
  458. caller_mode = 0;
  459. } else if (s->details->caps & AST_FAX_TECH_SEND) {
  460. caller_mode = 1;
  461. } else {
  462. ast_log(LOG_ERROR, "Are we sending or receiving? The FAX requirements (capabilities: 0x%X) were not properly set.\n", s->details->caps);
  463. goto e_free;
  464. }
  465. if (!(p->timer = ast_timer_open())) {
  466. ast_log(LOG_ERROR, "Channel '%s' FAX session '%d' failed to create timing source.\n", s->channame, s->id);
  467. goto e_free;
  468. }
  469. s->fd = ast_timer_fd(p->timer);
  470. p->stats = &spandsp_global_stats.g711;
  471. if (s->details->caps & AST_FAX_TECH_T38) {
  472. if ((s->details->caps & AST_FAX_TECH_AUDIO) == 0) {
  473. /* audio mode was not requested, start in T.38 mode */
  474. p->ist38 = 1;
  475. p->stats = &spandsp_global_stats.t38;
  476. }
  477. /* init t38 stuff */
  478. t38_terminal_init(&p->t38_state, caller_mode, t38_tx_packet_handler, s);
  479. set_logging(&p->t38_state.logging, s->details);
  480. }
  481. if (s->details->caps & AST_FAX_TECH_AUDIO) {
  482. /* init audio stuff */
  483. fax_init(&p->fax_state, caller_mode);
  484. set_logging(&p->fax_state.logging, s->details);
  485. }
  486. s->state = AST_FAX_STATE_INITIALIZED;
  487. return p;
  488. e_free:
  489. ast_free(p);
  490. e_return:
  491. return NULL;
  492. }
  493. static void spandsp_v21_cleanup(struct ast_fax_session *s) {
  494. struct spandsp_pvt *p = s->tech_pvt;
  495. modem_connect_tones_rx_free(p->tone_state);
  496. }
  497. /*! \brief Destroy a spandsp fax session.
  498. */
  499. static void spandsp_fax_destroy(struct ast_fax_session *s)
  500. {
  501. struct spandsp_pvt *p = s->tech_pvt;
  502. if (s->details->caps & AST_FAX_TECH_GATEWAY) {
  503. spandsp_fax_gateway_cleanup(s);
  504. } else if (s->details->caps & AST_FAX_TECH_V21_DETECT) {
  505. spandsp_v21_cleanup(s);
  506. } else {
  507. session_destroy(p);
  508. }
  509. ast_free(p);
  510. s->tech_pvt = NULL;
  511. s->fd = -1;
  512. }
  513. /*! \brief Read a frame from the spandsp fax stack.
  514. */
  515. static struct ast_frame *spandsp_fax_read(struct ast_fax_session *s)
  516. {
  517. struct spandsp_pvt *p = s->tech_pvt;
  518. uint8_t buffer[AST_FRIENDLY_OFFSET + SPANDSP_FAX_SAMPLES * sizeof(uint16_t)];
  519. int16_t *buf = (int16_t *) (buffer + AST_FRIENDLY_OFFSET);
  520. int samples;
  521. struct ast_frame fax_frame = {
  522. .frametype = AST_FRAME_VOICE,
  523. .src = "res_fax_spandsp_g711",
  524. };
  525. struct ast_frame *f = &fax_frame;
  526. ast_format_set(&fax_frame.subclass.format, AST_FORMAT_SLINEAR, 0);
  527. if (ast_timer_ack(p->timer, 1) < 0) {
  528. ast_log(LOG_ERROR, "Failed to acknowledge timer for FAX session '%d'\n", s->id);
  529. return NULL;
  530. }
  531. /* XXX do we need to lock here? */
  532. if (p->isdone) {
  533. s->state = AST_FAX_STATE_COMPLETE;
  534. ast_debug(5, "FAX session '%d' is complete.\n", s->id);
  535. return NULL;
  536. }
  537. if (p->ist38) {
  538. t38_terminal_send_timeout(&p->t38_state, SPANDSP_FAX_SAMPLES);
  539. if ((f = AST_LIST_REMOVE_HEAD(&p->read_frames, frame_list))) {
  540. return f;
  541. }
  542. } else {
  543. if ((samples = fax_tx(&p->fax_state, buf, SPANDSP_FAX_SAMPLES)) > 0) {
  544. f->samples = samples;
  545. AST_FRAME_SET_BUFFER(f, buffer, AST_FRIENDLY_OFFSET, samples * sizeof(int16_t));
  546. return ast_frisolate(f);
  547. }
  548. }
  549. return &ast_null_frame;
  550. }
  551. static void spandsp_v21_tone(void *data, int code, int level, int delay)
  552. {
  553. struct spandsp_pvt *p = data;
  554. if (code == MODEM_CONNECT_TONES_FAX_PREAMBLE) {
  555. p->v21_detected = 1;
  556. }
  557. }
  558. static int spandsp_v21_detect(struct ast_fax_session *s, const struct ast_frame *f) {
  559. struct spandsp_pvt *p = s->tech_pvt;
  560. if (p->v21_detected) {
  561. return 0;
  562. }
  563. /*invalid frame*/
  564. if (!f->data.ptr || !f->datalen) {
  565. return -1;
  566. }
  567. modem_connect_tones_rx(p->tone_state, f->data.ptr, f->samples);
  568. if (p->v21_detected) {
  569. s->details->option.v21_detected = 1;
  570. }
  571. return 0;
  572. }
  573. /*! \brief Write a frame to the spandsp fax stack.
  574. * \param s a fax session
  575. * \param f the frame to write
  576. *
  577. * \note res_fax does not currently use the return value of this function.
  578. * Also the fax_rx() function never fails.
  579. *
  580. * \retval 0 success
  581. * \retval -1 failure
  582. */
  583. static int spandsp_fax_write(struct ast_fax_session *s, const struct ast_frame *f)
  584. {
  585. struct spandsp_pvt *p = s->tech_pvt;
  586. if (s->details->caps & AST_FAX_TECH_V21_DETECT) {
  587. return spandsp_v21_detect(s, f);
  588. }
  589. if (s->details->caps & AST_FAX_TECH_GATEWAY) {
  590. return spandsp_fax_gateway_process(s, f);
  591. }
  592. /* XXX do we need to lock here? */
  593. if (s->state == AST_FAX_STATE_COMPLETE) {
  594. ast_log(LOG_WARNING, "FAX session '%d' is in the '%s' state.\n", s->id, ast_fax_state_to_str(s->state));
  595. return -1;
  596. }
  597. if (p->ist38) {
  598. return t38_core_rx_ifp_packet(p->t38_core_state, f->data.ptr, f->datalen, f->seqno);
  599. } else {
  600. return fax_rx(&p->fax_state, f->data.ptr, f->samples);
  601. }
  602. }
  603. /*! \brief generate T.30 packets sent to the T.30 leg of gateway
  604. * \param chan T.30 channel
  605. * \param data fax session structure
  606. * \param len not used
  607. * \param samples no of samples generated
  608. * \return -1 on failure or 0 on sucess*/
  609. static int spandsp_fax_gw_t30_gen(struct ast_channel *chan, void *data, int len, int samples)
  610. {
  611. int res = -1;
  612. struct ast_fax_session *s = data;
  613. struct spandsp_pvt *p = s->tech_pvt;
  614. uint8_t buffer[AST_FRIENDLY_OFFSET + samples * sizeof(uint16_t)];
  615. struct ast_frame *f;
  616. struct ast_frame t30_frame = {
  617. .frametype = AST_FRAME_VOICE,
  618. .src = "res_fax_spandsp_g711",
  619. .samples = samples,
  620. .flags = AST_FAX_FRFLAG_GATEWAY,
  621. };
  622. AST_FRAME_SET_BUFFER(&t30_frame, buffer, AST_FRIENDLY_OFFSET, t30_frame.samples * sizeof(int16_t));
  623. ast_format_set(&t30_frame.subclass.format, AST_FORMAT_SLINEAR, 0);
  624. if (!(f = ast_frisolate(&t30_frame))) {
  625. return p->isdone ? -1 : res;
  626. }
  627. /* generate a T.30 packet */
  628. if ((f->samples = t38_gateway_tx(&p->t38_gw_state, f->data.ptr, f->samples))) {
  629. f->datalen = f->samples * sizeof(int16_t);
  630. res = ast_write(chan, f);
  631. }
  632. ast_frfree(f);
  633. return p->isdone ? -1 : res;
  634. }
  635. /*! \brief simple routine to allocate data to generator
  636. * \param chan channel
  637. * \param params generator data
  638. * \return data to use in generator call*/
  639. static void *spandsp_fax_gw_gen_alloc(struct ast_channel *chan, void *params) {
  640. ao2_ref(params, +1);
  641. return params;
  642. }
  643. static void spandsp_fax_gw_gen_release(struct ast_channel *chan, void *data) {
  644. ao2_ref(data, -1);
  645. }
  646. /*! \brief activate a spandsp gateway based on the information in the given fax session
  647. * \param s fax session
  648. * \return -1 on error 0 on sucess*/
  649. static int spandsp_fax_gateway_start(struct ast_fax_session *s) {
  650. struct spandsp_pvt *p = s->tech_pvt;
  651. struct ast_fax_t38_parameters *t38_param;
  652. int i;
  653. struct ast_channel *peer;
  654. static struct ast_generator t30_gen = {
  655. .alloc = spandsp_fax_gw_gen_alloc,
  656. .release = spandsp_fax_gw_gen_release,
  657. .generate = spandsp_fax_gw_t30_gen,
  658. };
  659. #if SPANDSP_RELEASE_DATE >= 20081012
  660. /* for spandsp shaphots 0.0.6 and higher */
  661. p->t38_core_state=&p->t38_gw_state.t38x.t38;
  662. #else
  663. /* for spandsp release 0.0.5 */
  664. p->t38_core_state=&p->t38_gw_state.t38;
  665. #endif
  666. if (!t38_gateway_init(&p->t38_gw_state, t38_tx_packet_handler, s)) {
  667. return -1;
  668. }
  669. p->ist38 = 1;
  670. p->ast_t38_state = ast_channel_get_t38_state(s->chan);
  671. if (!(peer = ast_bridged_channel(s->chan))) {
  672. ast_channel_unlock(s->chan);
  673. return -1;
  674. }
  675. /* we can be in T38_STATE_NEGOTIATING or T38_STATE_NEGOTIATED when the
  676. * gateway is started. We treat both states the same. */
  677. if (p->ast_t38_state == T38_STATE_NEGOTIATING) {
  678. p->ast_t38_state = T38_STATE_NEGOTIATED;
  679. }
  680. ast_activate_generator(p->ast_t38_state == T38_STATE_NEGOTIATED ? peer : s->chan, &t30_gen , s);
  681. set_logging(&p->t38_gw_state.logging, s->details);
  682. set_logging(&p->t38_core_state->logging, s->details);
  683. t38_param = (p->ast_t38_state == T38_STATE_NEGOTIATED) ? &s->details->our_t38_parameters : &s->details->their_t38_parameters;
  684. t38_set_t38_version(p->t38_core_state, t38_param->version);
  685. t38_gateway_set_ecm_capability(&p->t38_gw_state, s->details->option.ecm);
  686. t38_set_max_datagram_size(p->t38_core_state, t38_param->max_ifp);
  687. t38_set_fill_bit_removal(p->t38_core_state, t38_param->fill_bit_removal);
  688. t38_set_mmr_transcoding(p->t38_core_state, t38_param->transcoding_mmr);
  689. t38_set_jbig_transcoding(p->t38_core_state, t38_param->transcoding_jbig);
  690. t38_set_data_rate_management_method(p->t38_core_state,
  691. (t38_param->rate_management == AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF)? 1 : 2);
  692. t38_gateway_set_transmit_on_idle(&p->t38_gw_state, TRUE);
  693. t38_set_sequence_number_handling(p->t38_core_state, TRUE);
  694. t38_gateway_set_supported_modems(&p->t38_gw_state, spandsp_modems(s->details));
  695. /* engage udptl nat on other side of T38 line
  696. * (Asterisk changes media ports thus we send a few packets to reinitialize
  697. * pinholes in NATs and FWs
  698. */
  699. for (i=0; i < SPANDSP_ENGAGE_UDPTL_NAT_RETRY; i++) {
  700. #if SPANDSP_RELEASE_DATE >= 20091228
  701. t38_core_send_indicator(&p->t38_gw_state.t38x.t38, T38_IND_NO_SIGNAL);
  702. #elif SPANDSP_RELEASE_DATE >= 20081012
  703. t38_core_send_indicator(&p->t38_gw_state.t38x.t38, T38_IND_NO_SIGNAL, p->t38_gw_state.t38x.t38.indicator_tx_count);
  704. #else
  705. t38_core_send_indicator(&p->t38_gw_state.t38, T38_IND_NO_SIGNAL, p->t38_gw_state.t38.indicator_tx_count);
  706. #endif
  707. }
  708. s->state = AST_FAX_STATE_ACTIVE;
  709. return 0;
  710. }
  711. /*! \brief process a frame from the bridge
  712. * \param s fax session
  713. * \param f frame to process
  714. * \return 1 on sucess 0 on incorect packet*/
  715. static int spandsp_fax_gateway_process(struct ast_fax_session *s, const struct ast_frame *f)
  716. {
  717. struct spandsp_pvt *p = s->tech_pvt;
  718. /*invalid frame*/
  719. if (!f->data.ptr || !f->datalen) {
  720. return -1;
  721. }
  722. /* Process a IFP packet */
  723. if ((f->frametype == AST_FRAME_MODEM) && (f->subclass.integer == AST_MODEM_T38)) {
  724. return t38_core_rx_ifp_packet(p->t38_core_state, f->data.ptr, f->datalen, f->seqno);
  725. } else if ((f->frametype == AST_FRAME_VOICE) && (f->subclass.format.id == AST_FORMAT_SLINEAR)) {
  726. return t38_gateway_rx(&p->t38_gw_state, f->data.ptr, f->samples);
  727. }
  728. return -1;
  729. }
  730. /*! \brief gather data and clean up after gateway ends
  731. * \param s fax session*/
  732. static void spandsp_fax_gateway_cleanup(struct ast_fax_session *s)
  733. {
  734. struct spandsp_pvt *p = s->tech_pvt;
  735. t38_stats_t t38_stats;
  736. t38_gateway_get_transfer_statistics(&p->t38_gw_state, &t38_stats);
  737. s->details->option.ecm = t38_stats.error_correcting_mode ? AST_FAX_OPTFLAG_TRUE : AST_FAX_OPTFLAG_FALSE;
  738. s->details->pages_transferred = t38_stats.pages_transferred;
  739. ast_string_field_build(s->details, transfer_rate, "%d", t38_stats.bit_rate);
  740. }
  741. /*! \brief */
  742. static int spandsp_fax_start(struct ast_fax_session *s)
  743. {
  744. struct spandsp_pvt *p = s->tech_pvt;
  745. s->state = AST_FAX_STATE_OPEN;
  746. if (s->details->caps & AST_FAX_TECH_GATEWAY) {
  747. return spandsp_fax_gateway_start(s);
  748. }
  749. if (p->ist38) {
  750. #if SPANDSP_RELEASE_DATE >= 20080725
  751. /* for spandsp shaphots 0.0.6 and higher */
  752. p->t30_state = &p->t38_state.t30;
  753. p->t38_core_state = &p->t38_state.t38_fe.t38;
  754. #else
  755. /* for spandsp releases 0.0.5 */
  756. p->t30_state = &p->t38_state.t30_state;
  757. p->t38_core_state = &p->t38_state.t38;
  758. #endif
  759. } else {
  760. #if SPANDSP_RELEASE_DATE >= 20080725
  761. /* for spandsp shaphots 0.0.6 and higher */
  762. p->t30_state = &p->fax_state.t30;
  763. #else
  764. /* for spandsp release 0.0.5 */
  765. p->t30_state = &p->fax_state.t30_state;
  766. #endif
  767. }
  768. set_logging(&p->t30_state->logging, s->details);
  769. /* set some parameters */
  770. set_local_info(p->t30_state, s->details);
  771. set_file(p->t30_state, s->details);
  772. set_ecm(p->t30_state, s->details);
  773. t30_set_supported_modems(p->t30_state, spandsp_modems(s->details));
  774. /* perhaps set_transmit_on_idle() should be called */
  775. t30_set_phase_e_handler(p->t30_state, t30_phase_e_handler, s);
  776. /* set T.38 parameters */
  777. if (p->ist38) {
  778. set_logging(&p->t38_core_state->logging, s->details);
  779. t38_set_max_datagram_size(p->t38_core_state, s->details->their_t38_parameters.max_ifp);
  780. if (s->details->their_t38_parameters.fill_bit_removal) {
  781. t38_set_fill_bit_removal(p->t38_core_state, TRUE);
  782. }
  783. if (s->details->their_t38_parameters.transcoding_mmr) {
  784. t38_set_mmr_transcoding(p->t38_core_state, TRUE);
  785. }
  786. if (s->details->their_t38_parameters.transcoding_jbig) {
  787. t38_set_jbig_transcoding(p->t38_core_state, TRUE);
  788. }
  789. } else {
  790. /* have the fax stack generate silence if it has no data to send */
  791. fax_set_transmit_on_idle(&p->fax_state, 1);
  792. }
  793. /* start the timer */
  794. if (ast_timer_set_rate(p->timer, SPANDSP_FAX_TIMER_RATE)) {
  795. ast_log(LOG_ERROR, "FAX session '%d' error setting rate on timing source.\n", s->id);
  796. return -1;
  797. }
  798. s->state = AST_FAX_STATE_ACTIVE;
  799. return 0;
  800. }
  801. /*! \brief */
  802. static int spandsp_fax_cancel(struct ast_fax_session *s)
  803. {
  804. struct spandsp_pvt *p = s->tech_pvt;
  805. if (s->details->caps & AST_FAX_TECH_GATEWAY) {
  806. p->isdone = 1;
  807. return 0;
  808. }
  809. t30_terminate(p->t30_state);
  810. p->isdone = 1;
  811. return 0;
  812. }
  813. /*! \brief */
  814. static int spandsp_fax_switch_to_t38(struct ast_fax_session *s)
  815. {
  816. struct spandsp_pvt *p = s->tech_pvt;
  817. /* prevent the phase E handler from running, this is not a real termination */
  818. t30_set_phase_e_handler(p->t30_state, NULL, NULL);
  819. t30_terminate(p->t30_state);
  820. s->details->option.switch_to_t38 = 1;
  821. ast_atomic_fetchadd_int(&p->stats->switched, 1);
  822. p->ist38 = 1;
  823. p->stats = &spandsp_global_stats.t38;
  824. spandsp_fax_start(s);
  825. return 0;
  826. }
  827. /*! \brief */
  828. static char *spandsp_fax_cli_show_capabilities(int fd)
  829. {
  830. ast_cli(fd, "SEND RECEIVE T.38 G.711 GATEWAY\n\n");
  831. return CLI_SUCCESS;
  832. }
  833. /*! \brief */
  834. static char *spandsp_fax_cli_show_session(struct ast_fax_session *s, int fd)
  835. {
  836. ao2_lock(s);
  837. if (s->details->caps & AST_FAX_TECH_GATEWAY) {
  838. struct spandsp_pvt *p = s->tech_pvt;
  839. ast_cli(fd, "%-22s : %d\n", "session", s->id);
  840. ast_cli(fd, "%-22s : %s\n", "operation", "Gateway");
  841. ast_cli(fd, "%-22s : %s\n", "state", ast_fax_state_to_str(s->state));
  842. if (s->state != AST_FAX_STATE_UNINITIALIZED) {
  843. t38_stats_t stats;
  844. t38_gateway_get_transfer_statistics(&p->t38_gw_state, &stats);
  845. ast_cli(fd, "%-22s : %s\n", "ECM Mode", stats.error_correcting_mode ? "Yes" : "No");
  846. ast_cli(fd, "%-22s : %d\n", "Data Rate", stats.bit_rate);
  847. ast_cli(fd, "%-22s : %d\n", "Page Number", stats.pages_transferred + 1);
  848. }
  849. } else if (s->details->caps & AST_FAX_TECH_V21_DETECT) {
  850. ast_cli(fd, "%-22s : %d\n", "session", s->id);
  851. ast_cli(fd, "%-22s : %s\n", "operation", "V.21 Detect");
  852. ast_cli(fd, "%-22s : %s\n", "state", ast_fax_state_to_str(s->state));
  853. } else {
  854. struct spandsp_pvt *p = s->tech_pvt;
  855. ast_cli(fd, "%-22s : %d\n", "session", s->id);
  856. ast_cli(fd, "%-22s : %s\n", "operation", (s->details->caps & AST_FAX_TECH_RECEIVE) ? "Receive" : "Transmit");
  857. ast_cli(fd, "%-22s : %s\n", "state", ast_fax_state_to_str(s->state));
  858. if (s->state != AST_FAX_STATE_UNINITIALIZED) {
  859. t30_stats_t stats;
  860. t30_get_transfer_statistics(p->t30_state, &stats);
  861. ast_cli(fd, "%-22s : %s\n", "Last Status", t30_completion_code_to_str(stats.current_status));
  862. ast_cli(fd, "%-22s : %s\n", "ECM Mode", stats.error_correcting_mode ? "Yes" : "No");
  863. ast_cli(fd, "%-22s : %d\n", "Data Rate", stats.bit_rate);
  864. ast_cli(fd, "%-22s : %dx%d\n", "Image Resolution", stats.x_resolution, stats.y_resolution);
  865. #if SPANDSP_RELEASE_DATE >= 20090220
  866. ast_cli(fd, "%-22s : %d\n", "Page Number", ((s->details->caps & AST_FAX_TECH_RECEIVE) ? stats.pages_rx : stats.pages_tx) + 1);
  867. #else
  868. ast_cli(fd, "%-22s : %d\n", "Page Number", stats.pages_transferred + 1);
  869. #endif
  870. 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);
  871. ast_cli(fd, "\nData Statistics:\n");
  872. #if SPANDSP_RELEASE_DATE >= 20090220
  873. ast_cli(fd, "%-22s : %d\n", "Tx Pages", stats.pages_tx);
  874. ast_cli(fd, "%-22s : %d\n", "Rx Pages", stats.pages_rx);
  875. #else
  876. ast_cli(fd, "%-22s : %d\n", "Tx Pages", (s->details->caps & AST_FAX_TECH_SEND) ? stats.pages_transferred : 0);
  877. ast_cli(fd, "%-22s : %d\n", "Rx Pages", (s->details->caps & AST_FAX_TECH_RECEIVE) ? stats.pages_transferred : 0);
  878. #endif
  879. ast_cli(fd, "%-22s : %d\n", "Longest Bad Line Run", stats.longest_bad_row_run);
  880. ast_cli(fd, "%-22s : %d\n", "Total Bad Lines", stats.bad_rows);
  881. }
  882. }
  883. ao2_unlock(s);
  884. ast_cli(fd, "\n\n");
  885. return CLI_SUCCESS;
  886. }
  887. /*! \brief */
  888. static char *spandsp_fax_cli_show_stats(int fd)
  889. {
  890. ast_mutex_lock(&spandsp_global_stats.lock);
  891. ast_cli(fd, "\n%-20.20s\n", "Spandsp G.711");
  892. ast_cli(fd, "%-20.20s : %d\n", "Success", spandsp_global_stats.g711.success);
  893. ast_cli(fd, "%-20.20s : %d\n", "Switched to T.38", spandsp_global_stats.g711.switched);
  894. ast_cli(fd, "%-20.20s : %d\n", "Call Dropped", spandsp_global_stats.g711.call_dropped);
  895. ast_cli(fd, "%-20.20s : %d\n", "No FAX", spandsp_global_stats.g711.nofax);
  896. ast_cli(fd, "%-20.20s : %d\n", "Negotiation Failed", spandsp_global_stats.g711.neg_failed);
  897. ast_cli(fd, "%-20.20s : %d\n", "Train Failure", spandsp_global_stats.g711.failed_to_train);
  898. ast_cli(fd, "%-20.20s : %d\n", "Retries Exceeded", spandsp_global_stats.g711.retries_exceeded);
  899. ast_cli(fd, "%-20.20s : %d\n", "Protocol Error", spandsp_global_stats.g711.protocol_error);
  900. ast_cli(fd, "%-20.20s : %d\n", "TX Protocol Error", spandsp_global_stats.g711.tx_protocol_error);
  901. ast_cli(fd, "%-20.20s : %d\n", "RX Protocol Error", spandsp_global_stats.g711.rx_protocol_error);
  902. ast_cli(fd, "%-20.20s : %d\n", "File Error", spandsp_global_stats.g711.file_error);
  903. ast_cli(fd, "%-20.20s : %d\n", "Memory Error", spandsp_global_stats.g711.mem_error);
  904. ast_cli(fd, "%-20.20s : %d\n", "Unknown Error", spandsp_global_stats.g711.unknown_error);
  905. ast_cli(fd, "\n%-20.20s\n", "Spandsp T.38");
  906. ast_cli(fd, "%-20.20s : %d\n", "Success", spandsp_global_stats.t38.success);
  907. ast_cli(fd, "%-20.20s : %d\n", "Call Dropped", spandsp_global_stats.t38.call_dropped);
  908. ast_cli(fd, "%-20.20s : %d\n", "No FAX", spandsp_global_stats.t38.nofax);
  909. ast_cli(fd, "%-20.20s : %d\n", "Negotiation Failed", spandsp_global_stats.t38.neg_failed);
  910. ast_cli(fd, "%-20.20s : %d\n", "Train Failure", spandsp_global_stats.t38.failed_to_train);
  911. ast_cli(fd, "%-20.20s : %d\n", "Retries Exceeded", spandsp_global_stats.t38.retries_exceeded);
  912. ast_cli(fd, "%-20.20s : %d\n", "Protocol Error", spandsp_global_stats.t38.protocol_error);
  913. ast_cli(fd, "%-20.20s : %d\n", "TX Protocol Error", spandsp_global_stats.t38.tx_protocol_error);
  914. ast_cli(fd, "%-20.20s : %d\n", "RX Protocol Error", spandsp_global_stats.t38.rx_protocol_error);
  915. ast_cli(fd, "%-20.20s : %d\n", "File Error", spandsp_global_stats.t38.file_error);
  916. ast_cli(fd, "%-20.20s : %d\n", "Memory Error", spandsp_global_stats.t38.mem_error);
  917. ast_cli(fd, "%-20.20s : %d\n", "Unknown Error", spandsp_global_stats.t38.unknown_error);
  918. ast_mutex_unlock(&spandsp_global_stats.lock);
  919. return CLI_SUCCESS;
  920. }
  921. /*! \brief Show res_fax_spandsp settings */
  922. static char *spandsp_fax_cli_show_settings(int fd)
  923. {
  924. /* no settings at the moment */
  925. return CLI_SUCCESS;
  926. }
  927. /*! \brief unload res_fax_spandsp */
  928. static int unload_module(void)
  929. {
  930. ast_fax_tech_unregister(&spandsp_fax_tech);
  931. ast_mutex_destroy(&spandsp_global_stats.lock);
  932. return AST_MODULE_LOAD_SUCCESS;
  933. }
  934. /*! \brief load res_fax_spandsp */
  935. static int load_module(void)
  936. {
  937. ast_mutex_init(&spandsp_global_stats.lock);
  938. spandsp_fax_tech.module = ast_module_info->self;
  939. if (ast_fax_tech_register(&spandsp_fax_tech) < 0) {
  940. ast_log(LOG_ERROR, "failed to register FAX technology\n");
  941. return AST_MODULE_LOAD_DECLINE;
  942. }
  943. /* prevent logging to stderr */
  944. span_set_message_handler(NULL);
  945. return AST_MODULE_LOAD_SUCCESS;
  946. }
  947. AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Spandsp G.711 and T.38 FAX Technologies",
  948. .load = load_module,
  949. .unload = unload_module,
  950. );