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,9 +1109,6 @@ static t38_mode_t request_t38(pvt_t *pvt)
if (!(t38_options = switch_channel_get_private(channel, "_preconfigured_t38_options"))) { if (!(t38_options = switch_channel_get_private(channel, "_preconfigured_t38_options"))) {
t38_options = switch_core_session_alloc(session, sizeof(*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->T38MaxBitRate = (pvt->disable_v17) ? 9600 : 14400;
t38_options->T38FaxVersion = 0; t38_options->T38FaxVersion = 0;
t38_options->T38FaxFillBitRemoval = 1; t38_options->T38FaxFillBitRemoval = 1;
@ -1122,8 +1119,11 @@ static t38_mode_t request_t38(pvt_t *pvt)
t38_options->T38FaxMaxDatagram = LOCAL_FAX_MAX_DATAGRAM; t38_options->T38FaxMaxDatagram = LOCAL_FAX_MAX_DATAGRAM;
t38_options->T38FaxUdpEC = "t38UDPRedundancy"; t38_options->T38FaxUdpEC = "t38UDPRedundancy";
t38_options->T38VendorInfo = "0 0 0"; t38_options->T38VendorInfo = "0 0 0";
}
switch_channel_set_private(channel, "t38_options", t38_options); switch_channel_set_private(channel, "t38_options", t38_options);
switch_channel_set_private(channel, "_preconfigured_t38_options", NULL);
pvt->t38_mode = T38_MODE_REQUESTED; pvt->t38_mode = T38_MODE_REQUESTED;
switch_channel_set_app_flag_key("T38", channel, CF_APP_T38_REQ); 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. */ 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"); switch_t38_options_t *t38_options = (switch_t38_options_t *)switch_channel_get_private(m_fsChannel, "t38_options");
if (t38_options == NULL) if (t38_options == NULL)
SetT38OptionsFromMediaFormat(t38); SetT38OptionsFromMediaFormat(t38, "_preconfigured_t38_options");
else { else {
t38.SetOptionInteger("T38FaxVersion", t38_options->T38FaxVersion); t38.SetOptionInteger("T38FaxVersion", t38_options->T38FaxVersion);
t38.SetOptionInteger("T38MaxBitRate", t38_options->T38MaxBitRate); t38.SetOptionInteger("T38MaxBitRate", t38_options->T38MaxBitRate);
@ -978,17 +978,22 @@ switch_status_t FSConnection::receive_message(switch_core_session_message_t *msg
#if HAVE_T38 #if HAVE_T38
case SWITCH_MESSAGE_INDICATE_REQUEST_IMAGE_MEDIA: case SWITCH_MESSAGE_INDICATE_REQUEST_IMAGE_MEDIA:
{ {
PTRACE(2, "mod_opal\tRequesting switch to T.38");
PSafePtr<OpalConnection> other = GetOtherPartyConnection(); 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"); PTRACE(1, "mod_opal\tMode change request to T.38 failed");
} }
break; break;
} }
case SWITCH_MESSAGE_INDICATE_T38_DESCRIPTION: case SWITCH_MESSAGE_INDICATE_T38_DESCRIPTION:
PTRACE(2, "mod_opal\tSWITCH_MESSAGE_INDICATE_T38_DESCRIPTION");
break; break;
case SWITCH_MESSAGE_INDICATE_UDPTL_MODE: case SWITCH_MESSAGE_INDICATE_UDPTL_MODE:
PTRACE(2, "mod_opal\tSWITCH_MESSAGE_INDICATE_UDPTL_MODE");
break; break;
#endif // HAVE_T38 #endif // HAVE_T38
@ -1018,9 +1023,9 @@ bool FSConnection::WaitForMedia()
#if HAVE_T38 #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) if (t38_options == NULL)
t38_options = (switch_t38_options_t *)switch_core_session_alloc(m_fsSession, sizeof(switch_t38_options_t)); 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_ip = switch_core_session_strdup(session, mediaFormat.something);
//t38_options->remote_port = 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) void FSConnection::OnSwitchedT38(bool toT38, bool success)
{ {
PTRACE(3, "mod_opal\tMode change request to fax succeeded"); if (!toT38 || !success || !IndicateSwitchedT38())
OnSwitchingT38(toT38 && success); AbortT38();
} }
void FSConnection::OnSwitchingT38(bool toT38) void FSConnection::OnSwitchingT38(bool toT38)
{ {
if (!toT38) { 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_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);
switch_channel_clear_app_flag_key("T38", m_fsChannel, CF_APP_T38_REQ); 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); switch_channel_set_app_flag_key("T38", m_fsChannel, CF_APP_T38_FAIL);
return; }
}
bool FSConnection::IndicateSwitchedT38()
{
PSafePtr<OpalConnection> other = GetOtherPartyConnection(); PSafePtr<OpalConnection> other = GetOtherPartyConnection();
if (other == NULL) if (other == NULL)
return; return false;
OpalMediaFormatList otherFormats = other->GetMediaFormats(); OpalMediaFormatList otherFormats = other->GetMediaFormats();
OpalMediaFormatList::const_iterator t38 = otherFormats.FindFormat(OpalT38); OpalMediaFormatList::const_iterator t38 = otherFormats.FindFormat(OpalT38);
if (t38 == otherFormats.end()) 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_variable(m_fsChannel, "has_t38", "true");
switch_channel_set_app_flag_key("T38", m_fsChannel, CF_APP_T38); switch_channel_set_app_flag_key("T38", m_fsChannel, CF_APP_T38);
switch_channel_execute_on(m_fsChannel, "opal_execute_on_image"); switch_channel_execute_on(m_fsChannel, "opal_execute_on_t38");
switch_channel_api_on(m_fsChannel, "opal_api_on_image"); switch_channel_api_on(m_fsChannel, "opal_api_on_t38");
PTRACE(3, "mod_opal\tMode change request to T.38 succeeded");
return; return true;
} }
#endif // HAVE_T38 #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) 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) 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) 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)); 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) 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)); 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 int FSMediaStream::StartReadWrite(PatchPtr & mediaPatch) const
{ {
if (!IsOpen()) { if (!IsOpen()) {
PTRACE(2, "mod_opal\tNot open!"); PTRACE(1, "mod_opal\tNot open!");
return -1; return -1;
} }
if (!m_switchCodec) { if (!m_switchCodec) {
PTRACE(2, "mod_opal\tNo codec!"); PTRACE(1, "mod_opal\tNo codec!");
return -1; return -1;
} }
if (!m_connection.IsChannelReady()) { if (!m_connection.IsChannelReady()) {
PTRACE(2, "mod_opal\tChannel not ready!"); PTRACE(1, "mod_opal\tChannel not ready!");
return -1; return -1;
} }
@ -1285,7 +1316,7 @@ int FSMediaStream::StartReadWrite(PatchPtr & mediaPatch) const
if (mediaPatch == NULL) { if (mediaPatch == NULL) {
/*There is a race here... sometimes we make it here and m_mediaPatch is 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. */ 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; 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); m_readRTP.SetTimestamp(m_readFrame.timestamp + m_switchCodec->implementation->samples_per_packet);
if (!mediaPatch->GetSource().ReadPacket(m_readRTP)) { if (!mediaPatch->GetSource().ReadPacket(m_readRTP)) {
PTRACE(1, "mod_opal\tread_frame: no source data!");
return SWITCH_STATUS_FALSE; 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 (m_switchCodec != NULL) {
if (!switch_core_codec_ready(m_switchCodec)) { 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; 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; timestamp += m_switchCodec->implementation->samples_per_packet;
rtp.SetTimestamp(timestamp); 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(); void SetCodecs();
bool WaitForMedia(); bool WaitForMedia();
#if HAVE_T38 #if HAVE_T38
void SetT38OptionsFromMediaFormat(const OpalMediaFormat & mediaFormat); void SetT38OptionsFromMediaFormat(const OpalMediaFormat & mediaFormat, const char * varname);
bool IndicateSwitchedT38();
void AbortT38();
#endif #endif
switch_status_t read_frame(const OpalMediaType & mediaType, switch_frame_t **frame, switch_io_flag_t flags); switch_status_t read_frame(const OpalMediaType & mediaType, switch_frame_t **frame, switch_io_flag_t flags);