]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
Fixed numerous issues with T.38 support on mod_opal, now WORKS!
authorRobert Jongbloed <robertj@voxlucida.com.au>
Thu, 13 Sep 2012 04:55:04 +0000 (14:55 +1000)
committerRobert Jongbloed <robertj@voxlucida.com.au>
Wed, 19 Sep 2012 02:33:06 +0000 (12:33 +1000)
Added tracing for error conditions in mod_spandsp

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 f48bed8ad52bd6eae1de01a55f0349e3c0c1fc3a..7e07a4e7db70e8a7cee33d1dbe8c93923eca7c74 100644 (file)
@@ -1590,21 +1590,29 @@ static switch_status_t t38_gateway_on_soft_execute(switch_core_session_t *sessio
        while (switch_channel_ready(channel) && switch_channel_up(other_channel) && !switch_channel_test_app_flag_key("T38", channel, CF_APP_T38)) {
                status = switch_core_session_read_frame(session, &read_frame, SWITCH_IO_FLAG_NONE, 0);
 
-               if (!SWITCH_READ_ACCEPTABLE(status) || pvt->done) {
+               if (pvt->done) {
+                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "%s Premature exit while negotiating\n", switch_channel_get_name(channel));
                        /* Our duty is over */
                        goto end_unlock;
                }
 
+               if (!SWITCH_READ_ACCEPTABLE(status)) {
+                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "%s Read failed, status=%u\n", switch_channel_get_name(channel), status);
+                       goto end_unlock;
+               }
+
                if (switch_test_flag(read_frame, SFF_CNG)) {
                        continue;
                }
 
                if (switch_core_session_write_frame(other_session, read_frame, SWITCH_IO_FLAG_NONE, 0) != SWITCH_STATUS_SUCCESS) {
+                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "%s Write failed\n", switch_channel_get_name(channel));
                        goto end_unlock;
                }
        }
 
        if (!(switch_channel_ready(channel) && switch_channel_up(other_channel))) {
+               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "%s Channel not ready\n", switch_channel_get_name(channel));
                goto end_unlock;
        }
 
@@ -1645,6 +1653,7 @@ static switch_status_t t38_gateway_on_soft_execute(switch_core_session_t *sessio
                status = switch_core_session_read_frame(session, &read_frame, SWITCH_IO_FLAG_NONE, 0);
 
                if (!SWITCH_READ_ACCEPTABLE(status) || pvt->done) {
+                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "%s Premature exit while negotiating\n", switch_channel_get_name(channel), status);
                        /* Our duty is over */
                        goto end_unlock;
                }
@@ -1654,7 +1663,9 @@ static switch_status_t t38_gateway_on_soft_execute(switch_core_session_t *sessio
                }
 
                if (switch_test_flag(read_frame, SFF_UDPTL_PACKET)) {
-                       udptl_rx_packet(pvt->udptl_state, read_frame->packet, read_frame->packetlen);
+                       if (udptl_rx_packet(pvt->udptl_state, read_frame->packet, read_frame->packetlen) < 0) {
+                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s Error decoding UDPTL (%u bytes)\n", switch_channel_get_name(channel), read_frame->packetlen);
+                        }
                }
        }
 
index 1becc0dcc2d586005fe7bb979c1c903f95a9723b..fa7b64229d3ff5fceb0994a84d53cfcdc6b353c6 100644 (file)
@@ -26,6 +26,9 @@
 #include "mod_opal.h"\r
 #include <opal/patch.h>\r
 #include <rtp/rtp.h>\r
+#if PTLIB_CHECK_VERSION(2,11,1)\r
+#include <rtp/rtp_session.h>\r
+#endif\r
 #include <h323/h323pdu.h>\r
 #include <h323/gkclient.h>\r
 \r
@@ -57,6 +60,7 @@ static FSProcess *opal_process = NULL;
 \r
 static PConstString const ModuleName("opal");\r
 static char const ConfigFile[] = "opal.conf";\r
+#define FS_PREFIX "fs"\r
 \r
 \r
 static switch_io_routines_t opalfs_io_routines = {\r
@@ -287,9 +291,9 @@ bool FSManager::Initialise(switch_loadable_module_interface_t *iface)
         }\r
     }\r
 \r
-    AddRouteEntry("h323:.* = local:<da>");  // config option for direct routing\r
-    AddRouteEntry("iax2:.* = local:<da>");  // config option for direct routing\r
-    AddRouteEntry("local:.* = h323:<da>");  // config option for direct routing\r
+    AddRouteEntry("h323:.* = "FS_PREFIX":<da>");  // config option for direct routing\r
+    AddRouteEntry("iax2:.* = "FS_PREFIX":<da>");  // config option for direct routing\r
+    AddRouteEntry(FS_PREFIX":.* = h323:<da>");  // config option for direct routing\r
 \r
     // Make sure all known codecs are instantiated,\r
     // these are ones we know how to translate into H.323 capabilities\r
@@ -320,6 +324,10 @@ bool FSManager::Initialise(switch_loadable_module_interface_t *iface)
     }\r
 #endif // IMPLEMENT_MULTI_FAME_AUDIO\r
 \r
+    OpalMediaFormat t38 = OpalT38;\r
+    t38.SetOptionBoolean("UDPTL-Raw-Mode", true);\r
+    OpalMediaFormat::SetRegisteredMediaFormat(t38);\r
+\r
     if (!m_gkAddress.IsEmpty()) {\r
       if (m_h323ep->UseGatekeeper(m_gkAddress, m_gkIdentifer, m_gkInterface))\r
         switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Started gatekeeper: %s\n",\r
@@ -453,7 +461,7 @@ static switch_call_cause_t create_outgoing_channel(switch_core_session_t   *sess
     params.cancel_cause     = cancel_cause;\r
     params.fail_cause       = SWITCH_CAUSE_INVALID_NUMBER_FORMAT;\r
 \r
-    if (opal_process->GetManager().SetUpCall("local:", outbound_profile->destination_number, &params) != NULL)\r
+    if (opal_process->GetManager().SetUpCall(FS_PREFIX":", outbound_profile->destination_number, &params) != NULL)\r
         return SWITCH_CAUSE_SUCCESS;\r
 \r
     if (*new_session != NULL)\r
@@ -465,7 +473,7 @@ static switch_call_cause_t create_outgoing_channel(switch_core_session_t   *sess
 ///////////////////////////////////////////////////////////////////////\r
 \r
 FSEndPoint::FSEndPoint(FSManager & manager)\r
-  : OpalLocalEndPoint(manager)\r
+  : OpalLocalEndPoint(manager, FS_PREFIX)\r
   , m_manager(manager)\r
 {\r
     PTRACE(4, "mod_opal\tFSEndPoint created.");\r
@@ -490,6 +498,7 @@ FSConnection::FSConnection(OpalCall & call,
   , m_fsSession(NULL)\r
   , m_fsChannel(NULL)\r
   , m_flushAudio(false)\r
+  , m_udptl(false)\r
 {\r
     memset(&m_read_timer, 0, sizeof(m_read_timer));\r
     memset(&m_read_codec, 0, sizeof(m_read_codec));\r
@@ -497,6 +506,8 @@ FSConnection::FSConnection(OpalCall & call,
     memset(&m_vid_read_timer, 0, sizeof(m_vid_read_timer));\r
     memset(&m_vid_read_codec, 0, sizeof(m_vid_read_codec));\r
     memset(&m_vid_write_codec, 0, sizeof(m_vid_write_codec));\r
+    memset(&m_dummy_frame, 0, sizeof(m_dummy_frame));\r
+    m_dummy_frame.flags = SFF_CNG;\r
 \r
     if (params != NULL) {\r
         // If we fail, this is the cause\r
@@ -871,7 +882,7 @@ switch_status_t FSConnection::on_destroy()
 {\r
     PTRACE(3, "mod_opal\tFS on_destroy for connection " << *this);\r
 \r
-    m_fsChannel = NULL; // Will be destoyed by FS, so don't use it any more.\r
+    m_fsChannel = NULL; // Will be destroyed by FS, so don't use it any more.\r
 \r
     switch_core_codec_destroy(&m_read_codec);\r
     switch_core_codec_destroy(&m_write_codec);\r
@@ -909,7 +920,7 @@ switch_status_t FSConnection::on_exchange_media()
 \r
 switch_status_t FSConnection::on_soft_execute()\r
 {\r
-    PTRACE(4, "mod_opal\tTransmit on connection " << *this);\r
+    PTRACE(4, "mod_opal\tSoft execute on connection " << *this);\r
     return SWITCH_STATUS_SUCCESS;\r
 }\r
 \r
@@ -920,12 +931,15 @@ switch_status_t FSConnection::kill_channel(int sig)
     case SWITCH_SIG_KILL:\r
         m_rxAudioOpened.Signal();\r
         m_txAudioOpened.Signal();\r
-        PTRACE(4, "mod_opal\tSignal channel KILL on connection " << *this);\r
+        PTRACE(4, "mod_opal\tSignal KILL received on connection " << *this);\r
         break;\r
-    case SWITCH_SIG_XFER:\r
+\r
     case SWITCH_SIG_BREAK:\r
+        PTRACE(4, "mod_opal\tSignal BREAK received on connection " << *this);\r
+        break;\r
+\r
     default:\r
-        PTRACE(4, "mod_opal\tSignal channel " << sig << " on connection " << *this);\r
+        PTRACE(4, "mod_opal\tSignal " << sig << " received on connection " << *this);\r
         break;\r
     }\r
 \r
@@ -1030,6 +1044,7 @@ switch_status_t FSConnection::receive_message(switch_core_session_message_t *msg
 \r
     case SWITCH_MESSAGE_INDICATE_UDPTL_MODE:\r
         PTRACE(2, "mod_opal\tSWITCH_MESSAGE_INDICATE_UDPTL_MODE");\r
+        m_udptl = true;\r
         break;\r
 #endif // HAVE_T38\r
 \r
@@ -1092,15 +1107,23 @@ void FSConnection::SetT38OptionsFromMediaFormat(const OpalMediaFormat & mediaFor
 \r
 void FSConnection::OnSwitchedT38(bool toT38, bool success)\r
 {\r
-    if (!toT38 || !success || !IndicateSwitchedT38())\r
-      AbortT38();\r
+    if (toT38 && success && IndicateSwitchedT38()) {\r
+        PTRACE(3, "mod_opal\tMode change request to T.38 succeeded");\r
+    }\r
+    else {\r
+        AbortT38();\r
+    }\r
 }\r
 \r
 \r
 void FSConnection::OnSwitchingT38(bool toT38)\r
 {\r
-    if (!toT38 || !IndicateSwitchedT38())\r
+    if (toT38 && IndicateSwitchedT38()) {\r
+        PTRACE(3, "mod_opal\tMode change request to T.38 started");\r
+    }\r
+    else {\r
       AbortT38();\r
+    }\r
 }\r
 \r
 \r
@@ -1117,13 +1140,17 @@ void FSConnection::AbortT38()
 bool FSConnection::IndicateSwitchedT38()\r
 {\r
     PSafePtr<OpalConnection> other = GetOtherPartyConnection();\r
-    if (other == NULL)\r
+    if (other == NULL) {\r
+        PTRACE(3, "mod_opal\tCan't change to T.38, no other connection");\r
         return false;\r
+    }\r
 \r
     OpalMediaFormatList otherFormats = other->GetMediaFormats();\r
     OpalMediaFormatList::const_iterator t38 = otherFormats.FindFormat(OpalT38);\r
-    if (t38 == otherFormats.end())\r
+    if (t38 == otherFormats.end()) {\r
+        PTRACE(3, "mod_opal\tCan't change to T.38, no remote capability");\r
         return false;\r
+    }\r
 \r
     SetT38OptionsFromMediaFormat(*t38, "t38_options");\r
 \r
@@ -1132,7 +1159,6 @@ bool FSConnection::IndicateSwitchedT38()
 \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
@@ -1154,21 +1180,13 @@ 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
-    // 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
+    return read_frame(m_udptl ? 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
-    // 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
+    return write_frame(m_udptl ? OpalMediaType::Fax() : OpalMediaType::Audio(), frame, flags);\r
 }\r
 \r
 \r
@@ -1186,17 +1204,26 @@ switch_status_t FSConnection::write_video_frame(switch_frame_t *frame, switch_io
 \r
 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
-    if (stream != NULL)\r
-      return stream->read_frame(frame, flags);\r
+    if (!ownerCall.IsSwitchingT38()) {\r
+        PSafePtr <FSMediaStream> stream = PSafePtrCast <OpalMediaStream, FSMediaStream>(GetMediaStream(mediaType, 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
+    }\r
 \r
-    PTRACE(2, "mod_opal\tNo stream for read of " << mediaType);\r
+    // Avoid all the channel closing and re-opening, especially with faxa switching, upsetting FS\r
+    *frame = &m_dummy_frame;\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
+    // Avoid all the channel closing and re-opening, especially with faxa switching, upsetting FS\r
+    if (ownerCall.IsSwitchingT38())\r
+      return SWITCH_STATUS_SUCCESS;\r
+\r
     PSafePtr <FSMediaStream> stream = PSafePtrCast<OpalMediaStream, FSMediaStream>(GetMediaStream(mediaType, true));\r
     if (stream != NULL)\r
       return stream->write_frame(frame, flags);\r
@@ -1211,6 +1238,8 @@ switch_status_t FSConnection::write_frame(const OpalMediaType & mediaType, const
 FSMediaStream::FSMediaStream(FSConnection & conn, const OpalMediaFormat & mediaFormat, unsigned sessionID, bool isSource)\r
     : OpalMediaStream(conn, mediaFormat, sessionID, isSource)\r
     , m_connection(conn)\r
+    , m_switchTimer(NULL)\r
+    , m_switchCodec(NULL)\r
     , m_readRTP(0, SWITCH_RECOMMENDED_BUFFER_SIZE)\r
 {\r
     memset(&m_readFrame, 0, sizeof(m_readFrame));\r
@@ -1236,8 +1265,8 @@ PBoolean FSMediaStream::Open()
         isAudio = false;\r
 #if HAVE_T38\r
     else if (mediaType == OpalMediaType::Fax()) {\r
-        m_readFrame.flags = SFF_UDPTL_PACKET;\r
-        return true;\r
+        m_readFrame.flags = SFF_UDPTL_PACKET|SFF_PROXY_PACKET;\r
+        return OpalMediaStream::Open();\r
     }\r
 #endif\r
     else {\r
@@ -1337,11 +1366,6 @@ int FSMediaStream::StartReadWrite(PatchPtr & mediaPatch) const
         return -1;\r
     }\r
 \r
-    if (!m_switchCodec) {\r
-        PTRACE(1, "mod_opal\tNo codec!");\r
-        return -1;\r
-    }\r
-\r
     if (!m_connection.IsChannelReady()) {\r
         PTRACE(1, "mod_opal\tChannel not ready!");\r
         return -1;\r
@@ -1362,6 +1386,9 @@ int FSMediaStream::StartReadWrite(PatchPtr & mediaPatch) const
 \r
 switch_status_t FSMediaStream::read_frame(switch_frame_t **frame, switch_io_flag_t flags)\r
 {\r
+    *frame = &m_readFrame;\r
+    m_readFrame.flags |= SFF_CNG;\r
+\r
     PatchPtr mediaPatch;\r
     switch (StartReadWrite(mediaPatch)) {\r
       case -1 :\r
@@ -1374,7 +1401,9 @@ switch_status_t FSMediaStream::read_frame(switch_frame_t **frame, switch_io_flag
         mediaPatch->GetSource().EnableJitterBuffer(); // This flushes data and resets jitter buffer\r
         m_readRTP.SetPayloadSize(0);\r
     } else {\r
-        m_readRTP.SetTimestamp(m_readFrame.timestamp + m_switchCodec->implementation->samples_per_packet);\r
+        if (m_switchCodec != NULL) {\r
+            m_readRTP.SetTimestamp(m_readFrame.timestamp + m_switchCodec->implementation->samples_per_packet);\r
+        }\r
 \r
         if (!mediaPatch->GetSource().ReadPacket(m_readRTP)) {\r
             PTRACE(1, "mod_opal\tread_frame: no source data!");\r
@@ -1393,13 +1422,19 @@ switch_status_t FSMediaStream::read_frame(switch_frame_t **frame, switch_io_flag
         }\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
+    if (switch_test_flag(&m_readFrame, SFF_UDPTL_PACKET)) {\r
+        m_readFrame.flags    &= ~SFF_CNG;\r
+        m_readFrame.packet    = m_readRTP.GetPayloadPtr();\r
+        m_readFrame.packetlen = m_readRTP.GetPayloadSize();\r
+        return SWITCH_STATUS_SUCCESS;\r
+    }\r
 \r
-    if ((m_readFrame.flags & (SFF_UDPTL_PACKET|SFF_RAW_RTP)) != 0)\r
+    if (switch_test_flag(&m_readFrame, SFF_RAW_RTP)) {\r
+        m_readFrame.flags    &= ~SFF_CNG;\r
+        m_readFrame.packet    = m_readRTP.GetPointer();\r
+        m_readFrame.packetlen = m_readRTP.GetHeaderSize() + m_readRTP.GetPayloadSize();\r
         return SWITCH_STATUS_SUCCESS;\r
+    }\r
 \r
 #if IMPLEMENT_MULTI_FAME_AUDIO\r
     // Repackage frames in incoming packet to agree with what FS expects.\r
@@ -1415,9 +1450,12 @@ switch_status_t FSMediaStream::read_frame(switch_frame_t **frame, switch_io_flag
     m_readFrame.ssrc      = m_readRTP.GetSyncSource();\r
     m_readFrame.m         = m_readRTP.GetMarker() ? SWITCH_TRUE : SWITCH_FALSE;\r
     m_readFrame.payload   = (switch_payload_t)m_readRTP.GetPayloadType();\r
-    m_readFrame.flags     = m_readFrame.datalen == 0 ||\r
-                            m_readFrame.payload == RTP_DataFrame::CN ||\r
-                            m_readFrame.payload == RTP_DataFrame::Cisco_CN ? SFF_CNG : 0;\r
+\r
+    if (m_readFrame.datalen > 0 &&\r
+        m_readFrame.payload != RTP_DataFrame::CN &&\r
+        m_readFrame.payload != RTP_DataFrame::Cisco_CN) {\r
+        m_readFrame.flags &= ~SFF_CNG;\r
+    }\r
 \r
     return SWITCH_STATUS_SUCCESS;\r
 }\r
@@ -1433,25 +1471,30 @@ switch_status_t FSMediaStream::write_frame(const switch_frame_t *frame, switch_i
         return SWITCH_STATUS_SUCCESS;\r
     }\r
 \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
+    RTP_DataFrame rtp;\r
+    if (switch_test_flag(frame, SFF_RAW_RTP)) {\r
+        rtp = RTP_DataFrame((const BYTE *)frame->packet, frame->packetlen, false);\r
+    }\r
+    else if (switch_test_flag(frame, SFF_UDPTL_PACKET)) {\r
+        rtp.SetPayloadSize(frame->packetlen);\r
+        memcpy(rtp.GetPayloadPtr(), frame->packet, frame->packetlen);\r
+    }\r
+    else {\r
+        rtp.SetPayloadSize(frame->datalen);\r
+        memcpy(rtp.GetPayloadPtr(), frame->data, frame->datalen);\r
+\r
+        rtp.SetPayloadType(mediaFormat.GetPayloadType());\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
+        else if (frame->samples != 0)\r
+            timestamp += frame->samples;\r
+        else if (m_switchCodec != NULL)\r
+            timestamp += m_switchCodec->implementation->samples_per_packet;\r
+        rtp.SetTimestamp(timestamp);\r
     }\r
-\r
-    RTP_DataFrame rtp(frame->datalen);\r
-    memcpy(rtp.GetPayloadPtr(), frame->data, frame->datalen);\r
-\r
-    rtp.SetPayloadType(mediaFormat.GetPayloadType());\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
-    else if (frame->samples != 0)\r
-        timestamp += frame->samples;\r
-    else\r
-        timestamp += m_switchCodec->implementation->samples_per_packet;\r
-    rtp.SetTimestamp(timestamp);\r
 \r
     if (mediaPatch->PushFrame(rtp))\r
       return SWITCH_STATUS_SUCCESS;\r
index db66c323814025d5559a7ea2169b3d64993987c9..da2ea1fa5b1a0a831e54c26652aca240ca2de4e1 100644 (file)
@@ -331,7 +331,10 @@ class FSConnection : public OpalLocalConnection
     switch_codec_t m_vid_read_codec;\r
     switch_codec_t m_vid_write_codec;\r
 \r
+    switch_frame_t m_dummy_frame;\r
+\r
     bool m_flushAudio;\r
+    bool m_udptl;\r
 \r
     friend PBoolean FSMediaStream::Open();\r
 };\r