summaryrefslogtreecommitdiff
path: root/res
diff options
context:
space:
mode:
authorKevin P. Fleming <kpfleming@digium.com>2011-12-28 18:59:16 +0000
committerKevin P. Fleming <kpfleming@digium.com>2011-12-28 18:59:16 +0000
commitfdda4947767a5c0ee2424532ff5f01250797175d (patch)
tree1f46d156caa5b18f979c2cccb8d222659009236e /res
parentd9651f2be9e5f19d5a5408eb818df7202af3bf1d (diff)
Improve T.38 gateway V.21 preamble detection.
This commit removes the V.21 preamble detection code previously added to the generic DSP implementation in Asterisk, and instead enhances the res_fax module to be able to utilize V.21 preamble detection functionality made available by FAX technology modules. This commit also adds such support to res_fax_spandsp, which uses the Spandsp modem tone detection code to do the V.21 preamble detection. There should be no functional change here, other than much more reliable V.21 preamble detection (and thus T.38 gateway initiation). ........ Merged revisions 349248 from http://svn.asterisk.org/svn/asterisk/branches/10 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@349249 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'res')
-rw-r--r--res/res_fax.c193
-rw-r--r--res/res_fax_spandsp.c85
2 files changed, 201 insertions, 77 deletions
diff --git a/res/res_fax.c b/res/res_fax.c
index ec2c98b82..7ee4cceff 100644
--- a/res/res_fax.c
+++ b/res/res_fax.c
@@ -249,13 +249,12 @@ struct ast_fax_debug_info {
struct fax_gateway {
/*! \brief FAX Session */
struct ast_fax_session *s;
+ struct ast_fax_session *peer_v21_session;
+ struct ast_fax_session *chan_v21_session;
/*! \brief reserved fax session token */
struct ast_fax_tech_token *token;
/*! \brief the start of our timeout counter */
struct timeval timeout_start;
- /*! \brief DSP Processor */
- struct ast_dsp *chan_dsp;
- struct ast_dsp *peer_dsp;
/*! \brief framehook used in gateway mode */
int framehook;
/*! \brief bridged */
@@ -336,7 +335,7 @@ static struct {
enum ast_fax_modems modems;
uint32_t statusevents:1;
uint32_t ecm:1;
- unsigned int minrate;
+ unsigned int minrate;
unsigned int maxrate;
} general_options;
@@ -371,7 +370,7 @@ struct manager_event_info {
};
static void debug_check_frame_for_silence(struct ast_fax_session *s, unsigned int c2s, struct ast_frame *frame)
-{
+{
struct debug_info_history *history = c2s ? &s->debug_info->c2s : &s->debug_info->s2c;
int dspsilence;
unsigned int last_consec_frames, last_consec_ms;
@@ -403,7 +402,7 @@ static void debug_check_frame_for_silence(struct ast_fax_session *s, unsigned in
history->consec_ms += (frame->samples / 8);
}
-static void destroy_callback(void *data)
+static void destroy_callback(void *data)
{
if (data) {
ao2_ref(data, -1);
@@ -421,9 +420,9 @@ static struct ast_fax_session_details *find_details(struct ast_channel *chan)
struct ast_fax_session_details *details;
struct ast_datastore *datastore;
- ast_channel_lock(chan);
+ ast_channel_lock(chan);
if (!(datastore = ast_channel_datastore_find(chan, &fax_datastore, NULL))) {
- ast_channel_unlock(chan);
+ ast_channel_unlock(chan);
return NULL;
}
if (!(details = datastore->data)) {
@@ -431,8 +430,8 @@ static struct ast_fax_session_details *find_details(struct ast_channel *chan)
ast_channel_unlock(chan);
return NULL;
}
- ao2_ref(details, 1);
- ast_channel_unlock(chan);
+ ao2_ref(details, 1);
+ ast_channel_unlock(chan);
return details;
}
@@ -442,11 +441,11 @@ static void destroy_session_details(void *details)
{
struct ast_fax_session_details *d = details;
struct ast_fax_document *doc;
-
+
while ((doc = AST_LIST_REMOVE_HEAD(&d->documents, next))) {
ast_free(doc);
}
- ast_string_field_free_memory(d);
+ ast_string_field_free_memory(d);
}
/*! \brief create a FAX session details structure */
@@ -457,7 +456,7 @@ static struct ast_fax_session_details *session_details_new(void)
if (!(d = ao2_alloc(sizeof(*d), destroy_session_details))) {
return NULL;
}
-
+
if (ast_string_field_init(d, 512)) {
ao2_ref(d, -1);
return NULL;
@@ -512,7 +511,7 @@ static void t38_parameters_fax_to_ast(struct ast_control_t38_parameters *dst, co
}
/*! \brief returns a reference counted details structure from the channel's fax datastore. If the datastore
- * does not exist it will be created */
+ * does not exist it will be created */
static struct ast_fax_session_details *find_or_create_details(struct ast_channel *chan)
{
struct ast_fax_session_details *details;
@@ -556,7 +555,7 @@ unsigned int ast_fax_minrate(void)
}
static int update_modem_bits(enum ast_fax_modems *bits, const char *value)
-{
+{
char *m[5], *tok, *v = (char *)value;
int i = 0, j;
@@ -636,7 +635,13 @@ static char *ast_fax_caps_to_str(enum ast_fax_capabilities caps, char *buf, size
ast_build_string(&buf, &size, "GATEWAY");
first = 0;
}
-
+ if (caps & AST_FAX_TECH_V21_DETECT) {
+ if (!first) {
+ ast_build_string(&buf, &size, ",");
+ }
+ ast_build_string(&buf, &size, "V21");
+ first = 0;
+ }
return out;
}
@@ -748,7 +753,7 @@ void ast_fax_tech_unregister(struct ast_fax_tech *tech)
ast_module_unref(ast_module_info->self);
ast_free(fax);
ast_verb(4, "Unregistered FAX module type '%s'\n", tech->type);
- break;
+ break;
}
AST_RWLIST_TRAVERSE_SAFE_END;
AST_RWLIST_UNLOCK(&faxmodules);
@@ -856,7 +861,7 @@ static void destroy_session(void *session)
}
ao2_ref(s->details, -1);
}
-
+
if (s->debug_info) {
ast_dsp_free(s->debug_info->dsp);
ast_free(s->debug_info);
@@ -996,7 +1001,7 @@ static struct ast_fax_session *fax_session_new(struct ast_fax_session_details *d
return NULL;
}
ast_dsp_set_threshold(s->debug_info->dsp, 128);
- }
+ }
if (!(s->channame = ast_strdup(chan->name))) {
fax_session_release(s, token);
@@ -1311,7 +1316,7 @@ static int generic_fax_exec(struct ast_channel *chan, struct ast_fax_session_det
}
ast_channel_lock(chan);
- /* update session details */
+ /* update session details */
if (ast_strlen_zero(details->headerinfo) && (tempvar = pbx_builtin_getvar_helper(chan, "LOCALHEADERINFO"))) {
ast_string_field_set(details, headerinfo, tempvar);
}
@@ -1409,7 +1414,7 @@ static int generic_fax_exec(struct ast_channel *chan, struct ast_fax_session_det
(frame->datalen == sizeof(t38_parameters))) {
unsigned int was_t38 = t38negotiated;
struct ast_control_t38_parameters *parameters = frame->data.ptr;
-
+
switch (parameters->request_response) {
case AST_T38_REQUEST_NEGOTIATE:
/* the other end has requested a switch to T.38, so reply that we are willing, if we can
@@ -1435,15 +1440,15 @@ static int generic_fax_exec(struct ast_channel *chan, struct ast_fax_session_det
ast_smoother_free(fax->smoother);
fax->smoother = NULL;
}
-
+
report_fax_status(chan, details, "T.38 Negotiated");
-
+
ast_verb(3, "Channel '%s' switched to T.38 FAX session '%d'.\n", chan->name, fax->id);
}
} else if ((frame->frametype == expected_frametype) &&
(!memcmp(&frame->subclass, &expected_framesubclass, sizeof(frame->subclass)))) {
struct ast_frame *f;
-
+
if (fax->smoother) {
/* push the frame into a smoother */
if (ast_smoother_feed(fax->smoother, frame) < 0) {
@@ -1805,7 +1810,7 @@ static int receivefax_exec(struct ast_channel *chan, const char *data)
ao2_ref(details, -1);
return -1;
}
-
+
ast_atomic_fetchadd_int(&faxregistry.fax_rx_attempts, 1);
pbx_builtin_setvar_helper(chan, "FAXERROR", "Channel Problems");
@@ -1909,7 +1914,7 @@ static int receivefax_exec(struct ast_channel *chan, const char *data)
get_manager_event_info(chan, &info);
manager_event(EVENT_FLAG_CALL,
- "ReceiveFAX",
+ "ReceiveFAX",
"Channel: %s\r\n"
"Context: %s\r\n"
"Exten: %s\r\n"
@@ -2265,7 +2270,7 @@ static int sendfax_exec(struct ast_channel *chan, const char *data)
ao2_ref(details, -1);
return -1;
}
-
+
/* check for unsupported FAX application options */
if (ast_test_flag(&opts, OPT_CALLERMODE) || ast_test_flag(&opts, OPT_CALLEDMODE)) {
ast_string_field_set(details, error, "INVALID_ARGUMENTS");
@@ -2407,7 +2412,7 @@ static int sendfax_exec(struct ast_channel *chan, const char *data)
ast_channel_lock(chan);
get_manager_event_info(chan, &info);
manager_event(EVENT_FLAG_CALL,
- "SendFAX",
+ "SendFAX",
"Channel: %s\r\n"
"Context: %s\r\n"
"Exten: %s\r\n"
@@ -2439,20 +2444,34 @@ static int sendfax_exec(struct ast_channel *chan, const char *data)
return (!channel_alive) ? -1 : 0;
}
-/*! \brief destroy a FAX gateway session structure */
-static void destroy_gateway(void *data)
+/*! \brief destroy the v21 detection parts of a fax gateway session */
+static void destroy_v21_sessions(struct fax_gateway *gateway)
{
- struct fax_gateway *gateway = data;
+ if (gateway->chan_v21_session) {
+ ao2_lock(faxregistry.container);
+ ao2_unlink(faxregistry.container, gateway->chan_v21_session);
+ ao2_unlock(faxregistry.container);
- if (gateway->chan_dsp) {
- ast_dsp_free(gateway->chan_dsp);
- gateway->chan_dsp = NULL;
+ ao2_ref(gateway->chan_v21_session, -1);
+ gateway->chan_v21_session = NULL;
}
- if (gateway->peer_dsp) {
- ast_dsp_free(gateway->peer_dsp);
- gateway->peer_dsp = NULL;
+ if (gateway->peer_v21_session) {
+ ao2_lock(faxregistry.container);
+ ao2_unlink(faxregistry.container, gateway->peer_v21_session);
+ ao2_unlock(faxregistry.container);
+
+ ao2_ref(gateway->peer_v21_session, -1);
+ gateway->peer_v21_session = NULL;
}
+}
+
+/*! \brief destroy a FAX gateway session structure */
+static void destroy_gateway(void *data)
+{
+ struct fax_gateway *gateway = data;
+
+ destroy_v21_sessions(gateway);
if (gateway->s) {
fax_session_release(gateway->s, gateway->token);
@@ -2468,35 +2487,38 @@ static void destroy_gateway(void *data)
}
/*! \brief Create a new fax gateway object.
+ * \param chan the channel the gateway object will be attached to
* \param details the fax session details
* \return NULL or a fax gateway object
*/
-static struct fax_gateway *fax_gateway_new(struct ast_fax_session_details *details)
+static struct fax_gateway *fax_gateway_new(struct ast_channel *chan, struct ast_fax_session_details *details)
{
struct fax_gateway *gateway = ao2_alloc(sizeof(*gateway), destroy_gateway);
+ struct ast_fax_session_details *v21_details;
if (!gateway) {
return NULL;
}
- gateway->chan_dsp = ast_dsp_new();
- if (!gateway->chan_dsp) {
+ if (!(v21_details = session_details_new())) {
ao2_ref(gateway, -1);
return NULL;
}
- gateway->peer_dsp = ast_dsp_new();
- if (!gateway->peer_dsp) {
+ v21_details->caps = AST_FAX_TECH_V21_DETECT;
+ if (!(gateway->chan_v21_session = fax_session_new(v21_details, chan, NULL, NULL))) {
+ ao2_ref(v21_details, -1);
ao2_ref(gateway, -1);
return NULL;
}
- gateway->framehook = -1;
-
- ast_dsp_set_features(gateway->chan_dsp, DSP_FEATURE_FAX_DETECT);
- ast_dsp_set_faxmode(gateway->chan_dsp, DSP_FAXMODE_DETECT_V21);
+ if (!(gateway->peer_v21_session = fax_session_new(v21_details, chan, NULL, NULL))) {
+ ao2_ref(v21_details, -1);
+ ao2_ref(gateway, -1);
+ return NULL;
+ }
+ ao2_ref(v21_details, -1);
- ast_dsp_set_features(gateway->peer_dsp, DSP_FEATURE_FAX_DETECT);
- ast_dsp_set_faxmode(gateway->peer_dsp, DSP_FAXMODE_DETECT_V21);
+ gateway->framehook = -1;
details->caps = AST_FAX_TECH_GATEWAY;
if (details->gateway_timeout && !(gateway->s = fax_session_reserve(details, &gateway->token))) {
@@ -2591,24 +2613,20 @@ static struct ast_frame *fax_gateway_request_t38(struct fax_gateway *gateway, st
static struct ast_frame *fax_gateway_detect_v21(struct fax_gateway *gateway, struct ast_channel *chan, struct ast_channel *peer, struct ast_channel *active, struct ast_frame *f)
{
- struct ast_frame *dfr = ast_frdup(f);
- struct ast_dsp *active_dsp = (active == chan) ? gateway->chan_dsp : gateway->peer_dsp;
struct ast_channel *other = (active == chan) ? peer : chan;
+ struct ast_fax_session *active_v21_session = (active == chan) ? gateway->chan_v21_session : gateway->peer_v21_session;
- if (gateway->detected_v21) {
+ if (!active_v21_session || gateway->detected_v21) {
return f;
}
- if (!dfr) {
- return f;
- }
-
- if (!(dfr = ast_dsp_process(active, active_dsp, dfr))) {
- return f;
+ if (active_v21_session->tech->write(active_v21_session, f) == 0 &&
+ active_v21_session->details->option.v21_detected) {
+ gateway->detected_v21 = 1;
}
- if (dfr->frametype == AST_FRAME_DTMF && dfr->subclass.integer == 'g') {
- gateway->detected_v21 = 1;
+ if (gateway->detected_v21) {
+ destroy_v21_sessions(gateway);
if (ast_channel_get_t38_state(other) == T38_STATE_UNKNOWN) {
ast_debug(1, "detected v21 preamble from %s\n", active->name);
return fax_gateway_request_t38(gateway, chan, f);
@@ -2617,7 +2635,6 @@ static struct ast_frame *fax_gateway_detect_v21(struct fax_gateway *gateway, str
}
}
- ast_frfree(dfr);
return f;
}
@@ -3120,7 +3137,7 @@ static int fax_gateway_attach(struct ast_channel *chan, struct ast_fax_session_d
set_channel_variables(chan, details);
/* set up the frame hook*/
- gateway = fax_gateway_new(details);
+ gateway = fax_gateway_new(chan, details);
if (!gateway) {
ast_string_field_set(details, result, "FAILED");
ast_string_field_set(details, resultstr, "error initializing gateway session");
@@ -3468,7 +3485,7 @@ static char *cli_fax_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_
switch (cmd) {
case CLI_INIT:
e->command = "fax set debug {on|off}";
- e->usage =
+ e->usage =
"Usage: fax set debug { on | off }\n"
" Enable/Disable FAX debugging on new FAX sessions. The basic FAX debugging will result in\n"
" additional events sent to manager sessions with 'call' class permissions. When\n"
@@ -3499,11 +3516,11 @@ static char *cli_fax_show_capabilities(struct ast_cli_entry *e, int cmd, struct
{
struct fax_module *fax;
unsigned int num_modules = 0;
-
+
switch (cmd) {
case CLI_INIT:
e->command = "fax show capabilities";
- e->usage =
+ e->usage =
"Usage: fax show capabilities\n"
" Shows the capabilities of the registered FAX technology modules\n";
return NULL;
@@ -3594,12 +3611,12 @@ static char *cli_fax_show_session(struct ast_cli_entry *e, int cmd, struct ast_c
return CLI_SUCCESS;
}
-
+
/*! \brief display fax stats */
static char *cli_fax_show_stats(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
struct fax_module *fax;
-
+
switch (cmd) {
case CLI_INIT:
e->command = "fax show stats";
@@ -3628,6 +3645,36 @@ static char *cli_fax_show_stats(struct ast_cli_entry *e, int cmd, struct ast_cli
return CLI_SUCCESS;
}
+static const char *cli_session_type(struct ast_fax_session *s)
+{
+ if (s->details->caps & AST_FAX_TECH_AUDIO) {
+ return "G.711";
+ }
+ if (s->details->caps & AST_FAX_TECH_T38) {
+ return "T.38";
+ }
+
+ return "none";
+}
+
+static const char *cli_session_operation(struct ast_fax_session *s)
+{
+ if (s->details->caps & AST_FAX_TECH_GATEWAY) {
+ return "gateway";
+ }
+ if (s->details->caps & AST_FAX_TECH_SEND) {
+ return "send";
+ }
+ if (s->details->caps & AST_FAX_TECH_RECEIVE) {
+ return "receive";
+ }
+ if (s->details->caps & AST_FAX_TECH_V21_DETECT) {
+ return "V.21";
+ }
+
+ return "none";
+}
+
/*! \brief display fax sessions */
static char *cli_fax_show_sessions(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
@@ -3658,10 +3705,8 @@ static char *cli_fax_show_sessions(struct ast_cli_entry *e, int cmd, struct ast_
ast_cli(a->fd, "%-20.20s %-10.10s %-10d %-5.5s %-10.10s %-15.15s %-30s\n",
s->channame, s->tech->type, s->id,
- (s->details->caps & AST_FAX_TECH_AUDIO) ? "G.711" : "T.38",
- (s->details->caps & AST_FAX_TECH_GATEWAY)
- ? "gateway"
- : (s->details->caps & AST_FAX_TECH_SEND) ? "send" : "receive",
+ cli_session_type(s),
+ cli_session_operation(s),
ast_fax_state_to_str(s->state), S_OR(filenames, ""));
ast_free(filenames);
@@ -3693,9 +3738,9 @@ static int set_config(const char *config_file)
struct ast_flags config_flags = { 0 };
char modems[128] = "";
- /* set defaults */
+ /* set defaults */
general_options.minrate = RES_FAX_MINRATE;
- general_options.maxrate = RES_FAX_MAXRATE;
+ general_options.maxrate = RES_FAX_MAXRATE;
general_options.statusevents = RES_FAX_STATUSEVENTS;
general_options.modems = RES_FAX_MODEM;
general_options.ecm = AST_FAX_OPTFLAG_TRUE;
@@ -3979,7 +4024,7 @@ struct ast_custom_function acf_faxopt = {
static int unload_module(void)
{
ast_cli_unregister_multiple(fax_cli, ARRAY_LEN(fax_cli));
-
+
if (ast_custom_function_unregister(&acf_faxopt) < 0) {
ast_log(LOG_WARNING, "failed to unregister function '%s'\n", acf_faxopt.name);
}
@@ -4012,7 +4057,7 @@ static int load_module(void)
if (!(faxregistry.container = ao2_container_alloc(FAX_MAXBUCKETS, session_hash_cb, session_cmp_cb))) {
return AST_MODULE_LOAD_DECLINE;
}
-
+
if (set_config(config) < 0) {
ast_log(LOG_ERROR, "failed to load configuration file '%s'\n", config);
ao2_ref(faxregistry.container, -1);
diff --git a/res/res_fax_spandsp.c b/res/res_fax_spandsp.c
index 81711bb40..7f4fbfc67 100644
--- a/res/res_fax_spandsp.c
+++ b/res/res_fax_spandsp.c
@@ -80,6 +80,9 @@ static int spandsp_fax_switch_to_t38(struct ast_fax_session *s);
static int spandsp_fax_gateway_start(struct ast_fax_session *s);
static int spandsp_fax_gateway_process(struct ast_fax_session *s, const struct ast_frame *f);
static void spandsp_fax_gateway_cleanup(struct ast_fax_session *s);
+static int spandsp_v21_detect(struct ast_fax_session *s, const struct ast_frame *f);
+static void spandsp_v21_cleanup(struct ast_fax_session *s);
+static void spandsp_v21_tone(void *data, int code, int level, int delay);
static char *spandsp_fax_cli_show_capabilities(int fd);
static char *spandsp_fax_cli_show_session(struct ast_fax_session *s, int fd);
@@ -98,7 +101,9 @@ static struct ast_fax_tech spandsp_fax_tech = {
*/
.version = "pre-20090220",
#endif
- .caps = AST_FAX_TECH_AUDIO | AST_FAX_TECH_T38 | AST_FAX_TECH_SEND | AST_FAX_TECH_RECEIVE | AST_FAX_TECH_GATEWAY,
+ .caps = AST_FAX_TECH_AUDIO | AST_FAX_TECH_T38 | AST_FAX_TECH_SEND
+ | AST_FAX_TECH_RECEIVE | AST_FAX_TECH_GATEWAY
+ | AST_FAX_TECH_V21_DETECT,
.new_session = spandsp_fax_new,
.destroy_session = spandsp_fax_destroy,
.read = spandsp_fax_read,
@@ -150,8 +155,12 @@ struct spandsp_pvt {
struct ast_timer *timer;
AST_LIST_HEAD(frame_queue, ast_frame) read_frames;
+
+ int v21_detected;
+ modem_connect_tones_rx_state_t *tone_state;
};
+static int spandsp_v21_new(struct spandsp_pvt *p);
static void session_destroy(struct spandsp_pvt *p);
static int t38_tx_packet_handler(t38_core_state_t *t38_core_state, void *data, const uint8_t *buf, int len, int count);
static void t30_phase_e_handler(t30_state_t *t30_state, void *data, int completion_code);
@@ -450,6 +459,20 @@ static void set_ecm(t30_state_t *t30_state, struct ast_fax_session_details *deta
t30_set_supported_compressions(t30_state, T30_SUPPORT_T4_1D_COMPRESSION | T30_SUPPORT_T4_2D_COMPRESSION | T30_SUPPORT_T6_COMPRESSION);
}
+static int spandsp_v21_new(struct spandsp_pvt *p)
+{
+ /* XXX Here we use MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE even though
+ * we don't care about CED tones. Using MODEM_CONNECT_TONES_PREAMBLE
+ * doesn't seem to work right all the time.
+ */
+ p->tone_state = modem_connect_tones_rx_init(NULL, MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE, spandsp_v21_tone, p);
+ if (!p->tone_state) {
+ return -1;
+ }
+
+ return 0;
+}
+
/*! \brief create an instance of the spandsp tech_pvt for a fax session */
static void *spandsp_fax_new(struct ast_fax_session *s, struct ast_fax_tech_token *token)
{
@@ -461,6 +484,15 @@ static void *spandsp_fax_new(struct ast_fax_session *s, struct ast_fax_tech_toke
goto e_return;
}
+ if (s->details->caps & AST_FAX_TECH_V21_DETECT) {
+ if (spandsp_v21_new(p)) {
+ ast_log(LOG_ERROR, "Cannot initialize the spandsp private v21 technology structure.\n");
+ goto e_return;
+ }
+ s->state = AST_FAX_STATE_ACTIVE;
+ return p;
+ }
+
if (s->details->caps & AST_FAX_TECH_GATEWAY) {
s->state = AST_FAX_STATE_INITIALIZED;
return p;
@@ -513,6 +545,11 @@ e_return:
return NULL;
}
+static void spandsp_v21_cleanup(struct ast_fax_session *s) {
+ struct spandsp_pvt *p = s->tech_pvt;
+ modem_connect_tones_rx_free(p->tone_state);
+}
+
/*! \brief Destroy a spandsp fax session.
*/
static void spandsp_fax_destroy(struct ast_fax_session *s)
@@ -521,6 +558,8 @@ static void spandsp_fax_destroy(struct ast_fax_session *s)
if (s->details->caps & AST_FAX_TECH_GATEWAY) {
spandsp_fax_gateway_cleanup(s);
+ } else if (s->details->caps & AST_FAX_TECH_V21_DETECT) {
+ spandsp_v21_cleanup(s);
} else {
session_destroy(p);
}
@@ -571,6 +610,36 @@ static struct ast_frame *spandsp_fax_read(struct ast_fax_session *s)
return &ast_null_frame;
}
+static void spandsp_v21_tone(void *data, int code, int level, int delay)
+{
+ struct spandsp_pvt *p = data;
+
+ if (code == MODEM_CONNECT_TONES_FAX_PREAMBLE) {
+ p->v21_detected = 1;
+ }
+}
+
+static int spandsp_v21_detect(struct ast_fax_session *s, const struct ast_frame *f) {
+ struct spandsp_pvt *p = s->tech_pvt;
+
+ if (p->v21_detected) {
+ return 0;
+ }
+
+ /*invalid frame*/
+ if (!f->data.ptr || !f->datalen) {
+ return -1;
+ }
+
+ modem_connect_tones_rx(p->tone_state, f->data.ptr, f->samples);
+
+ if (p->v21_detected) {
+ s->details->option.v21_detected = 1;
+ }
+
+ return 0;
+}
+
/*! \brief Write a frame to the spandsp fax stack.
* \param s a fax session
* \param f the frame to write
@@ -585,6 +654,10 @@ static int spandsp_fax_write(struct ast_fax_session *s, const struct ast_frame *
{
struct spandsp_pvt *p = s->tech_pvt;
+ if (s->details->caps & AST_FAX_TECH_V21_DETECT) {
+ return spandsp_v21_detect(s, f);
+ }
+
if (s->details->caps & AST_FAX_TECH_GATEWAY) {
return spandsp_fax_gateway_process(s, f);
}
@@ -906,10 +979,10 @@ static char *spandsp_fax_cli_show_capabilities(int fd)
/*! \brief */
static char *spandsp_fax_cli_show_session(struct ast_fax_session *s, int fd)
{
- struct spandsp_pvt *p = s->tech_pvt;
-
ao2_lock(s);
if (s->details->caps & AST_FAX_TECH_GATEWAY) {
+ struct spandsp_pvt *p = s->tech_pvt;
+
ast_cli(fd, "%-22s : %d\n", "session", s->id);
ast_cli(fd, "%-22s : %s\n", "operation", "Gateway");
ast_cli(fd, "%-22s : %s\n", "state", ast_fax_state_to_str(s->state));
@@ -920,7 +993,13 @@ static char *spandsp_fax_cli_show_session(struct ast_fax_session *s, int fd)
ast_cli(fd, "%-22s : %d\n", "Data Rate", stats.bit_rate);
ast_cli(fd, "%-22s : %d\n", "Page Number", stats.pages_transferred + 1);
}
+ } else if (s->details->caps & AST_FAX_TECH_V21_DETECT) {
+ ast_cli(fd, "%-22s : %d\n", "session", s->id);
+ ast_cli(fd, "%-22s : %s\n", "operation", "V.21 Detect");
+ ast_cli(fd, "%-22s : %s\n", "state", ast_fax_state_to_str(s->state));
} else {
+ struct spandsp_pvt *p = s->tech_pvt;
+
ast_cli(fd, "%-22s : %d\n", "session", s->id);
ast_cli(fd, "%-22s : %s\n", "operation", (s->details->caps & AST_FAX_TECH_RECEIVE) ? "Receive" : "Transmit");
ast_cli(fd, "%-22s : %s\n", "state", ast_fax_state_to_str(s->state));