static struct ast_frame *fax_gateway_framehook(struct ast_channel *chan, struct ast_frame *f, enum ast_framehook_event event, void *data)
{
struct fax_gateway *gateway = data;
- struct ast_channel *peer, *active;
- struct ast_fax_session_details *details;
+ struct ast_channel *active;
+ RAII_VAR(struct ast_fax_session_details *, details, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_channel *, peer, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_channel *, chan_ref, chan, ao2_cleanup);
+
+ /* Ref bump channel for when we have to unlock it */
+ ao2_ref(chan_ref, 1);
if (gateway->s) {
details = gateway->s->details;
if (gateway->bridged) {
ast_set_read_format(chan, &gateway->chan_read_format);
- ast_set_read_format(chan, &gateway->chan_write_format);
+ ast_set_write_format(chan, &gateway->chan_write_format);
- if ((peer = ast_bridged_channel(chan))) {
+ peer = ast_bridged_channel(chan);
+ if (peer) {
+ ao2_ref(peer, +1);
+ ast_channel_unlock(chan);
ast_set_read_format(peer, &gateway->peer_read_format);
- ast_set_read_format(peer, &gateway->peer_write_format);
+ ast_set_write_format(peer, &gateway->peer_write_format);
ast_channel_make_compatible(chan, peer);
+ ast_channel_lock(chan);
}
}
-
- ao2_ref(details, -1);
return NULL;
}
if (!f || (event == AST_FRAMEHOOK_EVENT_ATTACHED)) {
- ao2_ref(details, -1);
return NULL;
};
/* this frame was generated by the fax gateway, pass it on */
if (ast_test_flag(f, AST_FAX_FRFLAG_GATEWAY)) {
- ao2_ref(details, -1);
return f;
}
- if (!(peer = ast_bridged_channel(chan))) {
- /* not bridged, don't do anything */
- ao2_ref(details, -1);
+ /* If we aren't bridged or we don't have a peer, don't do anything */
+ peer = ast_bridged_channel(chan);
+ if (!peer) {
return f;
}
+ ao2_ref(peer, +1);
- if (!gateway->bridged && peer) {
+ if (!gateway->bridged) {
/* don't start a gateway if neither channel can handle T.38 */
if (ast_channel_get_t38_state(chan) == T38_STATE_UNAVAILABLE && ast_channel_get_t38_state(peer) == T38_STATE_UNAVAILABLE) {
ast_debug(1, "not starting gateway for %s and %s; neither channel supports T.38\n", ast_channel_name(chan), ast_channel_name(peer));
ast_string_field_set(details, resultstr, "neither channel supports T.38");
ast_string_field_set(details, error, "T38_NEG_ERROR");
set_channel_variables(chan, details);
- ao2_ref(details, -1);
return f;
}
gateway->timeout_start = ast_tvnow();
}
+ ast_channel_unlock(chan);
+ ast_channel_lock_both(chan, peer);
+
/* we are bridged, change r/w formats to SLIN for v21 preamble
* detection and T.30 */
ast_format_copy(&gateway->chan_read_format, ast_channel_readformat(chan));
- ast_format_copy(&gateway->chan_write_format, ast_channel_readformat(chan));
+ ast_format_copy(&gateway->chan_write_format, ast_channel_writeformat(chan));
ast_format_copy(&gateway->peer_read_format, ast_channel_readformat(peer));
- ast_format_copy(&gateway->peer_write_format, ast_channel_readformat(peer));
+ ast_format_copy(&gateway->peer_write_format, ast_channel_writeformat(peer));
ast_set_read_format_by_id(chan, AST_FORMAT_SLINEAR);
ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR);
ast_set_read_format_by_id(peer, AST_FORMAT_SLINEAR);
ast_set_write_format_by_id(peer, AST_FORMAT_SLINEAR);
- ast_channel_make_compatible(chan, peer);
+ ast_channel_unlock(peer);
+
gateway->bridged = 1;
if (!(gateway->peer_v21_session = fax_v21_session_new(peer))) {
ast_log(LOG_ERROR, "Can't create V21 session on chan %s for T.38 gateway session\n", ast_channel_name(peer));
ast_string_field_build(details, resultstr, "no fax activity after %d ms", details->gateway_timeout);
ast_string_field_set(details, error, "TIMEOUT");
set_channel_variables(chan, details);
- ao2_ref(details, -1);
return f;
}
}
case AST_FORMAT_ULAW:
break;
default:
- ao2_ref(details, -1);
return f;
}
break;
if (f->subclass.integer == AST_MODEM_T38) {
break;
}
- ao2_ref(details, -1);
return f;
case AST_FRAME_CONTROL:
if (f->subclass.integer == AST_CONTROL_T38_PARAMETERS) {
break;
}
- ao2_ref(details, -1);
return f;
default:
- ao2_ref(details, -1);
return f;
}
break;
default:
ast_log(LOG_WARNING, "unhandled framehook event %u\n", event);
- ao2_ref(details, -1);
return f;
}
/* handle control frames */
if (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_T38_PARAMETERS) {
- ao2_ref(details, -1);
return fax_gateway_detect_t38(gateway, chan, peer, active, f);
}
if (!gateway->detected_v21 && gateway->t38_state == T38_STATE_UNAVAILABLE && f->frametype == AST_FRAME_VOICE) {
/* not in gateway mode and have not detected v21 yet, listen
* for v21 */
- ao2_ref(details, -1);
return fax_gateway_detect_v21(gateway, chan, peer, active, f);
}
&& (readtrans = ast_channel_readtrans(active))) {
if ((f = ast_translate(readtrans, f, 1)) == NULL) {
f = &ast_null_frame;
- ao2_ref(details, -1);
return f;
}
/* XXX we ignore the return value here, perhaps we should
}
f = &ast_null_frame;
- ao2_ref(details, -1);
return f;
}
};
ast_format_set(&silence_frame.subclass.format, AST_FORMAT_SLINEAR, 0);
memset(silence_buf, 0, sizeof(silence_buf));
-
- ao2_ref(details, -1);
return ast_frisolate(&silence_frame);
} else {
- ao2_ref(details, -1);
return &ast_null_frame;
}
}
- ao2_ref(details, -1);
return f;
}