\r
m_switchMediaFormats += switchFormat;\r
}\r
+\r
+#if HAVE_T38\r
+ OpalMediaFormat t38 = OpalT38;\r
+\r
+ /* We need to have a T.38 options for TCS, but may be before the\r
+ spandsp_mod has set it us. So, if not, we actually give to spandsp_mod. */\r
+ switch_t38_options_t *t38_options = (switch_t38_options_t *)switch_channel_get_private(m_fsChannel, "t38_options");\r
+ if (t38_options == NULL)\r
+ SetT38OptionsFromMediaFormat(t38);\r
+ else {\r
+ t38.SetOptionInteger("T38FaxVersion", t38_options->T38FaxVersion);\r
+ t38.SetOptionInteger("T38MaxBitRate", t38_options->T38MaxBitRate);\r
+ t38.SetOptionBoolean("T38FaxFillBitRemoval", t38_options->T38FaxFillBitRemoval);\r
+ t38.SetOptionBoolean("T38FaxTranscodingMMR", t38_options->T38FaxTranscodingMMR);\r
+ t38.SetOptionBoolean("T38FaxTranscodingJBIG", t38_options->T38FaxTranscodingJBIG);\r
+ t38.SetOptionValue("T38FaxRateManagement", t38_options->T38FaxRateManagement);\r
+ t38.SetOptionInteger("T38Version", t38_options->T38FaxMaxBuffer);\r
+ t38.SetOptionInteger("T38Version", t38_options->T38FaxMaxDatagram);\r
+ t38.SetOptionValue("T38FaxUdpEC", t38_options->T38FaxUdpEC);\r
+ }\r
+\r
+ m_switchMediaFormats += t38;\r
+#endif // HAVE_T38\r
}\r
\r
\r
ownerCall.Transfer(msg->string_arg, GetOtherPartyConnection());\r
break;\r
\r
+#if HAVE_T38\r
+ case SWITCH_MESSAGE_INDICATE_REQUEST_IMAGE_MEDIA:\r
+ {\r
+ PSafePtr<OpalConnection> other = GetOtherPartyConnection();\r
+ if (other == NULL || !other->SwitchT38(true)) {\r
+ PTRACE(1, "mod_opal\tMode change request to T.38 failed");\r
+ }\r
+ break;\r
+ }\r
+\r
+ case SWITCH_MESSAGE_INDICATE_T38_DESCRIPTION:\r
+ break;\r
+\r
+ case SWITCH_MESSAGE_INDICATE_UDPTL_MODE:\r
+ break;\r
+#endif // HAVE_T38\r
+\r
default:\r
PTRACE(3, "mod_opal\tReceived unhandled message " << msg->message_id << " on connection " << *this);\r
}\r
}\r
\r
\r
+#if HAVE_T38\r
+void FSConnection::SetT38OptionsFromMediaFormat(const OpalMediaFormat & mediaFormat)\r
+{\r
+ switch_t38_options_t *t38_options = (switch_t38_options_t *)switch_channel_get_private(m_fsChannel, "t38_options");\r
+ if (t38_options == NULL)\r
+ t38_options = (switch_t38_options_t *)switch_core_session_alloc(m_fsSession, sizeof(switch_t38_options_t));\r
+\r
+ PString value;\r
+ mediaFormat.GetOptionValue("T38FaxRateManagement", value);\r
+ t38_options->T38FaxRateManagement = switch_core_session_strdup(m_fsSession, value);\r
+\r
+ mediaFormat.GetOptionValue("T38FaxUdpEC", value);\r
+ t38_options->T38FaxUdpEC = switch_core_session_strdup(m_fsSession, value);\r
+\r
+ t38_options->T38MaxBitRate = mediaFormat.GetOptionInteger("T38MaxBitRate", 9600);\r
+ t38_options->T38FaxMaxBuffer = mediaFormat.GetOptionInteger("T38FaxMaxBuffer", 2000);\r
+ t38_options->T38FaxMaxDatagram = mediaFormat.GetOptionInteger("T38FaxMaxDatagram", 528);\r
+\r
+ t38_options->T38FaxFillBitRemoval = mediaFormat.GetOptionBoolean("T38FaxFillBitRemoval") ? SWITCH_TRUE : SWITCH_FALSE;\r
+ t38_options->T38FaxTranscodingMMR = mediaFormat.GetOptionBoolean("T38FaxTranscodingMMR") ? SWITCH_TRUE : SWITCH_FALSE;\r
+ t38_options->T38FaxTranscodingJBIG = mediaFormat.GetOptionBoolean("T38FaxTranscodingJBIG") ? SWITCH_TRUE : SWITCH_FALSE;\r
+\r
+ t38_options->T38VendorInfo = switch_core_session_strdup(m_fsSession, mediaFormat.GetOptionString("T38VendorInfo"));\r
+\r
+ //t38_options->remote_ip = switch_core_session_strdup(session, mediaFormat.something);\r
+ //t38_options->remote_port = mediaFormat.something;\r
+\r
+ switch_channel_set_private(m_fsChannel, "t38_options", t38_options);\r
+}\r
+\r
+\r
+void FSConnection::OnSwitchedT38(bool toT38, bool success)\r
+{\r
+ PTRACE(3, "mod_opal\tMode change request to fax succeeded");\r
+ OnSwitchingT38(toT38 && success);\r
+}\r
+\r
+\r
+void FSConnection::OnSwitchingT38(bool toT38)\r
+{\r
+ if (!toT38) {\r
+ switch_channel_set_private(m_fsChannel, "t38_options", NULL);\r
+ switch_channel_clear_app_flag_key("T38", m_fsChannel, CF_APP_T38);\r
+ switch_channel_clear_app_flag_key("T38", m_fsChannel, CF_APP_T38_REQ);\r
+ switch_channel_set_app_flag_key("T38", m_fsChannel, CF_APP_T38_FAIL);\r
+ return;\r
+ }\r
+\r
+ PSafePtr<OpalConnection> other = GetOtherPartyConnection();\r
+ if (other == NULL)\r
+ return;\r
+\r
+ OpalMediaFormatList otherFormats = other->GetMediaFormats();\r
+ OpalMediaFormatList::const_iterator t38 = otherFormats.FindFormat(OpalT38);\r
+ if (t38 == otherFormats.end())\r
+ return;\r
+\r
+ SetT38OptionsFromMediaFormat(*t38);\r
+\r
+ switch_channel_set_variable(m_fsChannel, "has_t38", "true");\r
+ switch_channel_set_app_flag_key("T38", m_fsChannel, CF_APP_T38);\r
+\r
+ switch_channel_execute_on(m_fsChannel, "opal_execute_on_image");\r
+ switch_channel_api_on(m_fsChannel, "opal_api_on_image");\r
+\r
+ return;\r
+}\r
+#endif // HAVE_T38\r
+\r
+\r
switch_status_t FSConnection::receive_event(switch_event_t *event)\r
{\r
PTRACE(4, "mod_opal\tReceived event " << event->event_id << " on connection " << *this);\r
return false;\r
\r
bool isAudio;\r
- if (mediaFormat.GetMediaType() == OpalMediaType::Audio()) {\r
+ OpalMediaType mediaType = mediaFormat.GetMediaType();\r
+ if (mediaType == OpalMediaType::Audio())\r
isAudio = true;\r
- } else if (mediaFormat.GetMediaType() == OpalMediaType::Video()) {\r
+ else if (mediaType == OpalMediaType::Video())\r
isAudio = false;\r
- } else {\r
+#if HAVE_T38\r
+ else if (mediaType == OpalMediaType::Fax()) {\r
+ m_readFrame.flags = SFF_UDPTL_PACKET;\r
+ return true;\r
+ }\r
+#endif\r
+ else {\r
+ PTRACE(1, "mod_opal\tUnsupported media type: " << mediaType);\r
return false;\r
}\r
\r
switch_core_session_get_pool(fsSession)) != SWITCH_STATUS_SUCCESS) {\r
PTRACE(1, "mod_opal\t" << switch_channel_get_name(fsChannel)\r
<< " cannot initialise " << (IsSink()? "read" : "write") << ' '\r
- << mediaFormat.GetMediaType() << " codec " << mediaFormat << " for connection " << *this);\r
+ << mediaType << " codec " << mediaFormat << " for connection " << *this);\r
switch_channel_hangup(fsChannel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION);\r
return false;\r
}\r
PTRACE(2, "mod_opal\t" << switch_channel_get_name(fsChannel)\r
<< " unsupported ptime of " << ptime << " on " << (IsSink()? "read" : "write") << ' '\r
- << mediaFormat.GetMediaType() << " codec " << mediaFormat << " for connection " << *this);\r
+ << mediaType << " codec " << mediaFormat << " for connection " << *this);\r
}\r
\r
if (IsSink()) {\r
switch_core_session_get_pool(fsSession)) != SWITCH_STATUS_SUCCESS) {\r
PTRACE(1, "mod_opal\t" << switch_channel_get_name(fsChannel)\r
<< " timer init failed on " << (IsSink()? "read" : "write") << ' '\r
- << mediaFormat.GetMediaType() << " codec " << mediaFormat << " for connection " << *this);\r
+ << mediaType << " codec " << mediaFormat << " for connection " << *this);\r
switch_core_codec_destroy(m_switchCodec);\r
m_switchCodec = NULL;\r
return false;\r
\r
PTRACE(3, "mod_opal\t" << switch_channel_get_name(fsChannel)\r
<< " initialised " << (IsSink()? "read" : "write") << ' '\r
- << mediaFormat.GetMediaType() << " codec " << mediaFormat << " for connection " << *this);\r
+ << mediaType << " codec " << mediaFormat << " for connection " << *this);\r
\r
return OpalMediaStream::Open();\r
}\r
}\r
}\r
\r
+ *frame = &m_readFrame;\r
+\r
m_readFrame.packet = m_readRTP.GetPointer();\r
m_readFrame.packetlen = m_readRTP.GetHeaderSize() + m_readFrame.datalen;\r
\r
+ if ((m_readFrame.flags & (SFF_UDPTL_PACKET|SFF_RAW_RTP)) != 0)\r
+ return SWITCH_STATUS_SUCCESS;\r
+\r
#if IMPLEMENT_MULTI_FAME_AUDIO\r
// Repackage frames in incoming packet to agree with what FS expects.\r
// Not implmented yet!!!!!!!!!\r
m_readFrame.payload == RTP_DataFrame::CN ||\r
m_readFrame.payload == RTP_DataFrame::Cisco_CN ? SFF_CNG : 0;\r
\r
- *frame = &m_readFrame;\r
-\r
return SWITCH_STATUS_SUCCESS;\r
}\r
\r
return SWITCH_STATUS_SUCCESS;\r
}\r
\r
- if ((frame->flags & SFF_RAW_RTP) != 0) {\r
+ if ((frame->flags & (SFF_UDPTL_PACKET|SFF_RAW_RTP)) != 0) {\r
RTP_DataFrame rtp((const BYTE *)frame->packet, frame->packetlen, false);\r
return mediaPatch->PushFrame(rtp) ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE;\r
}\r
/* Not sure what FS is going to give us!\r
Suspect it depends on the mod on the other side sending it. */\r
if (frame->timestamp != 0)\r
- timestamp = frame->timestamp;\r
+ timestamp = frame->timestamp;\r
else if (frame->samples != 0)\r
- timestamp += frame->samples;\r
+ timestamp += frame->samples;\r
else\r
- timestamp += m_switchCodec->implementation->samples_per_packet;\r
+ timestamp += m_switchCodec->implementation->samples_per_packet;\r
rtp.SetTimestamp(timestamp);\r
\r
return mediaPatch->PushFrame(rtp) ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE;\r