]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
More T.38 fax support changes for mod_opal. Not quite there yet.
authorRobert Jongbloed <robertj@voxlucida.com.au>
Thu, 6 Sep 2012 02:43:17 +0000 (12:43 +1000)
committerRobert Jongbloed <robertj@voxlucida.com.au>
Wed, 19 Sep 2012 02:32:22 +0000 (12:32 +1000)
src/mod/applications/mod_spandsp/mod_spandsp_fax.c
src/mod/endpoints/mod_opal/mod_opal.cpp
src/mod/endpoints/mod_opal/mod_opal.h

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