summaryrefslogtreecommitdiff
path: root/res/res_fax.c
diff options
context:
space:
mode:
Diffstat (limited to 'res/res_fax.c')
-rw-r--r--res/res_fax.c193
1 files changed, 119 insertions, 74 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);