More T.38 fax support changes for mod_opal. Not quite there yet.

This commit is contained in:
Robert Jongbloed 2012-09-06 12:43:17 +10:00
parent a580c31122
commit 468739da29
3 changed files with 90 additions and 52 deletions

View File

@ -1109,21 +1109,21 @@ static t38_mode_t request_t38(pvt_t *pvt)
if (!(t38_options = switch_channel_get_private(channel, "_preconfigured_t38_options"))) {
t38_options = switch_core_session_alloc(session, sizeof(*t38_options));
switch_channel_set_private(channel, "_preconfigured_t38_options", NULL);
t38_options->T38MaxBitRate = (pvt->disable_v17) ? 9600 : 14400;
t38_options->T38FaxVersion = 0;
t38_options->T38FaxFillBitRemoval = 1;
t38_options->T38FaxTranscodingMMR = 0;
t38_options->T38FaxTranscodingJBIG = 0;
t38_options->T38FaxRateManagement = "transferredTCF";
t38_options->T38FaxMaxBuffer = 2000;
t38_options->T38FaxMaxDatagram = LOCAL_FAX_MAX_DATAGRAM;
t38_options->T38FaxUdpEC = "t38UDPRedundancy";
t38_options->T38VendorInfo = "0 0 0";
}
t38_options->T38MaxBitRate = (pvt->disable_v17) ? 9600 : 14400;
t38_options->T38FaxVersion = 0;
t38_options->T38FaxFillBitRemoval = 1;
t38_options->T38FaxTranscodingMMR = 0;
t38_options->T38FaxTranscodingJBIG = 0;
t38_options->T38FaxRateManagement = "transferredTCF";
t38_options->T38FaxMaxBuffer = 2000;
t38_options->T38FaxMaxDatagram = LOCAL_FAX_MAX_DATAGRAM;
t38_options->T38FaxUdpEC = "t38UDPRedundancy";
t38_options->T38VendorInfo = "0 0 0";
switch_channel_set_private(channel, "t38_options", t38_options);
switch_channel_set_private(channel, "_preconfigured_t38_options", NULL);
switch_channel_set_private(channel, "t38_options", t38_options);
pvt->t38_mode = T38_MODE_REQUESTED;
switch_channel_set_app_flag_key("T38", channel, CF_APP_T38_REQ);

View File

@ -751,7 +751,7 @@ void FSConnection::SetCodecs()
spandsp_mod has set it us. So, if not, we actually give to spandsp_mod. */
switch_t38_options_t *t38_options = (switch_t38_options_t *)switch_channel_get_private(m_fsChannel, "t38_options");
if (t38_options == NULL)
SetT38OptionsFromMediaFormat(t38);
SetT38OptionsFromMediaFormat(t38, "_preconfigured_t38_options");
else {
t38.SetOptionInteger("T38FaxVersion", t38_options->T38FaxVersion);
t38.SetOptionInteger("T38MaxBitRate", t38_options->T38MaxBitRate);
@ -786,18 +786,18 @@ void FSConnection::OnPatchMediaStream(PBoolean isSource, OpalMediaPatch & patch)
return;
if (switch_channel_direction(m_fsChannel) == SWITCH_CALL_DIRECTION_INBOUND) {
if (isSource)
m_rxAudioOpened.Signal();
else
m_txAudioOpened.Signal();
if (isSource)
m_rxAudioOpened.Signal();
else
m_txAudioOpened.Signal();
}
else if (GetMediaStream(OpalMediaType::Audio(), !isSource) != NULL) {
// Have open media in both directions.
// Have open media in both directions.
if (IsEstablished())
switch_channel_mark_answered(m_fsChannel);
switch_channel_mark_answered(m_fsChannel);
else if (!IsReleased())
switch_channel_mark_pre_answered(m_fsChannel);
}
switch_channel_mark_pre_answered(m_fsChannel);
}
}
@ -978,17 +978,22 @@ switch_status_t FSConnection::receive_message(switch_core_session_message_t *msg
#if HAVE_T38
case SWITCH_MESSAGE_INDICATE_REQUEST_IMAGE_MEDIA:
{
PTRACE(2, "mod_opal\tRequesting switch to T.38");
PSafePtr<OpalConnection> other = GetOtherPartyConnection();
if (other == NULL || !other->SwitchT38(true)) {
if (other != NULL && other->SwitchT38(true))
switch_channel_set_flag(m_fsChannel, CF_REQ_MEDIA);
else {
PTRACE(1, "mod_opal\tMode change request to T.38 failed");
}
break;
}
case SWITCH_MESSAGE_INDICATE_T38_DESCRIPTION:
PTRACE(2, "mod_opal\tSWITCH_MESSAGE_INDICATE_T38_DESCRIPTION");
break;
case SWITCH_MESSAGE_INDICATE_UDPTL_MODE:
PTRACE(2, "mod_opal\tSWITCH_MESSAGE_INDICATE_UDPTL_MODE");
break;
#endif // HAVE_T38
@ -1018,9 +1023,9 @@ bool FSConnection::WaitForMedia()
#if HAVE_T38
void FSConnection::SetT38OptionsFromMediaFormat(const OpalMediaFormat & mediaFormat)
void FSConnection::SetT38OptionsFromMediaFormat(const OpalMediaFormat & mediaFormat, const char * varname)
{
switch_t38_options_t *t38_options = (switch_t38_options_t *)switch_channel_get_private(m_fsChannel, "t38_options");
switch_t38_options_t *t38_options = (switch_t38_options_t *)switch_channel_get_private(m_fsChannel, varname);
if (t38_options == NULL)
t38_options = (switch_t38_options_t *)switch_core_session_alloc(m_fsSession, sizeof(switch_t38_options_t));
@ -1044,45 +1049,55 @@ void FSConnection::SetT38OptionsFromMediaFormat(const OpalMediaFormat & mediaFor
//t38_options->remote_ip = switch_core_session_strdup(session, mediaFormat.something);
//t38_options->remote_port = mediaFormat.something;
switch_channel_set_private(m_fsChannel, "t38_options", t38_options);
switch_channel_set_private(m_fsChannel, varname, t38_options);
PTRACE(3, "mod_opal\tSet " << varname);
}
void FSConnection::OnSwitchedT38(bool toT38, bool success)
{
PTRACE(3, "mod_opal\tMode change request to fax succeeded");
OnSwitchingT38(toT38 && success);
if (!toT38 || !success || !IndicateSwitchedT38())
AbortT38();
}
void FSConnection::OnSwitchingT38(bool toT38)
{
if (!toT38) {
switch_channel_set_private(m_fsChannel, "t38_options", NULL);
switch_channel_clear_app_flag_key("T38", m_fsChannel, CF_APP_T38);
switch_channel_clear_app_flag_key("T38", m_fsChannel, CF_APP_T38_REQ);
switch_channel_set_app_flag_key("T38", m_fsChannel, CF_APP_T38_FAIL);
return;
}
if (!toT38 || !IndicateSwitchedT38())
AbortT38();
}
void FSConnection::AbortT38()
{
PTRACE(3, "mod_opal\tMode change request to T.38 failed");
switch_channel_set_private(m_fsChannel, "t38_options", NULL);
switch_channel_clear_app_flag_key("T38", m_fsChannel, CF_APP_T38);
switch_channel_clear_app_flag_key("T38", m_fsChannel, CF_APP_T38_REQ);
switch_channel_set_app_flag_key("T38", m_fsChannel, CF_APP_T38_FAIL);
}
bool FSConnection::IndicateSwitchedT38()
{
PSafePtr<OpalConnection> other = GetOtherPartyConnection();
if (other == NULL)
return;
return false;
OpalMediaFormatList otherFormats = other->GetMediaFormats();
OpalMediaFormatList::const_iterator t38 = otherFormats.FindFormat(OpalT38);
if (t38 == otherFormats.end())
return;
return false;
SetT38OptionsFromMediaFormat(*t38);
SetT38OptionsFromMediaFormat(*t38, "t38_options");
switch_channel_set_variable(m_fsChannel, "has_t38", "true");
switch_channel_set_app_flag_key("T38", m_fsChannel, CF_APP_T38);
switch_channel_execute_on(m_fsChannel, "opal_execute_on_image");
switch_channel_api_on(m_fsChannel, "opal_api_on_image");
return;
switch_channel_execute_on(m_fsChannel, "opal_execute_on_t38");
switch_channel_api_on(m_fsChannel, "opal_api_on_t38");
PTRACE(3, "mod_opal\tMode change request to T.38 succeeded");
return true;
}
#endif // HAVE_T38
@ -1103,13 +1118,21 @@ switch_status_t FSConnection::state_change()
switch_status_t FSConnection::read_audio_frame(switch_frame_t **frame, switch_io_flag_t flags, int stream_id)
{
return read_frame(OpalMediaType::Audio(), frame, flags);
// Avoid all the channel closing and re-opening upsetting FS
if (ownerCall.IsSwitchingT38())
return SWITCH_STATUS_SUCCESS;
return read_frame((flags&SFF_UDPTL_PACKET) ? OpalMediaType::Fax() : OpalMediaType::Audio(), frame, flags);
}
switch_status_t FSConnection::write_audio_frame(switch_frame_t *frame, switch_io_flag_t flags, int stream_id)
{
return write_frame(OpalMediaType::Audio(), frame, flags);
// Avoid all the channel closing and re-opening upsetting FS
if (ownerCall.IsSwitchingT38())
return SWITCH_STATUS_SUCCESS;
return write_frame((flags&SFF_UDPTL_PACKET) ? OpalMediaType::Fax() : OpalMediaType::Audio(), frame, flags);
}
@ -1128,14 +1151,22 @@ switch_status_t FSConnection::write_video_frame(switch_frame_t *frame, switch_io
switch_status_t FSConnection::read_frame(const OpalMediaType & mediaType, switch_frame_t **frame, switch_io_flag_t flags)
{
PSafePtr <FSMediaStream> stream = PSafePtrCast <OpalMediaStream, FSMediaStream>(GetMediaStream(mediaType, false));
return stream != NULL ? stream->read_frame(frame, flags) : SWITCH_STATUS_FALSE;
if (stream != NULL)
return stream->read_frame(frame, flags);
PTRACE(2, "mod_opal\tNo stream for read of " << mediaType);
return SWITCH_STATUS_SUCCESS;
}
switch_status_t FSConnection::write_frame(const OpalMediaType & mediaType, const switch_frame_t *frame, switch_io_flag_t flags)
{
PSafePtr <FSMediaStream> stream = PSafePtrCast<OpalMediaStream, FSMediaStream>(GetMediaStream(mediaType, true));
return stream != NULL ? stream->write_frame(frame, flags) : SWITCH_STATUS_FALSE;
if (stream != NULL)
return stream->write_frame(frame, flags);
PTRACE(2, "mod_opal\tNo stream for write of " << mediaType);
return SWITCH_STATUS_SUCCESS;
}
@ -1266,17 +1297,17 @@ PBoolean FSMediaStream::RequiresPatchThread(OpalMediaStream *) const
int FSMediaStream::StartReadWrite(PatchPtr & mediaPatch) const
{
if (!IsOpen()) {
PTRACE(2, "mod_opal\tNot open!");
PTRACE(1, "mod_opal\tNot open!");
return -1;
}
if (!m_switchCodec) {
PTRACE(2, "mod_opal\tNo codec!");
PTRACE(1, "mod_opal\tNo codec!");
return -1;
}
if (!m_connection.IsChannelReady()) {
PTRACE(2, "mod_opal\tChannel not ready!");
PTRACE(1, "mod_opal\tChannel not ready!");
return -1;
}
@ -1285,7 +1316,7 @@ int FSMediaStream::StartReadWrite(PatchPtr & mediaPatch) const
if (mediaPatch == NULL) {
/*There is a race here... sometimes we make it here and m_mediaPatch is NULL
if we wait it shows up in 1ms, maybe there is a better way to wait. */
PTRACE(3, "mod_opal\tPatch not ready!");
PTRACE(2, "mod_opal\tPatch not ready!");
return 1;
}
@ -1310,6 +1341,7 @@ switch_status_t FSMediaStream::read_frame(switch_frame_t **frame, switch_io_flag
m_readRTP.SetTimestamp(m_readFrame.timestamp + m_switchCodec->implementation->samples_per_packet);
if (!mediaPatch->GetSource().ReadPacket(m_readRTP)) {
PTRACE(1, "mod_opal\tread_frame: no source data!");
return SWITCH_STATUS_FALSE;
}
}
@ -1320,7 +1352,7 @@ switch_status_t FSMediaStream::read_frame(switch_frame_t **frame, switch_io_flag
if (m_switchCodec != NULL) {
if (!switch_core_codec_ready(m_switchCodec)) {
PTRACE(2, "mod_opal\tread_frame: codec not ready!");
PTRACE(1, "mod_opal\tread_frame: codec not ready!");
return SWITCH_STATUS_FALSE;
}
}
@ -1385,7 +1417,11 @@ switch_status_t FSMediaStream::write_frame(const switch_frame_t *frame, switch_i
timestamp += m_switchCodec->implementation->samples_per_packet;
rtp.SetTimestamp(timestamp);
return mediaPatch->PushFrame(rtp) ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE;
if (mediaPatch->PushFrame(rtp))
return SWITCH_STATUS_SUCCESS;
PTRACE(1, "mod_opal\tread_frame: push failed!");
return SWITCH_STATUS_FALSE;
}

View File

@ -305,7 +305,9 @@ class FSConnection : public OpalLocalConnection
void SetCodecs();
bool WaitForMedia();
#if HAVE_T38
void SetT38OptionsFromMediaFormat(const OpalMediaFormat & mediaFormat);
void SetT38OptionsFromMediaFormat(const OpalMediaFormat & mediaFormat, const char * varname);
bool IndicateSwitchedT38();
void AbortT38();
#endif
switch_status_t read_frame(const OpalMediaType & mediaType, switch_frame_t **frame, switch_io_flag_t flags);