Exemplo n.º 1
0
        private void ContinueAfterPlay(RTSPClient rtspClient, int resultCode, string resultString)
        {
            do {
                var scs = ((OurRtspClient)rtspClient).scs; // alias

                if (resultCode != 0) {
                    Console.Error.WriteLine (rtspClient + "Failed to start playing session: " + resultString);
                    break;
                }

                if (scs.duration > 0) {
                    const uint delaySlop = 2;
                    // number of seconds extra to delay, after the stream's expected duration.  (This is optional.)
                    scs.duration += delaySlop;
                    var uSecsToDelay = (long)(scs.duration * 1000000);
                    scs.streamTimerTask = env.TaskScheduler.ScheduleDelayedTask (uSecsToDelay, streamTimerHandler, rtspClient.Native.Native);
                }

                Console.Error.Write (rtspClient + "Started playing session");
                if (scs.duration > 0) {
                    Console.Error.Write (" (for up to " + scs.duration + " seconds)");
                }
                Console.Error.WriteLine ("...");

                return;
            } while (false);

            // An unrecoverable error occurred with this stream.
            ShutdownStream (rtspClient);
        }
Exemplo n.º 2
0
        private void ContinueAfterPlay(RTSPClient rtspClient, int resultCode, string resultString)
        {
            do
            {
                var scs = ((OurRtspClient)rtspClient).scs; // alias

                if (resultCode != 0)
                {
                    Console.Error.WriteLine(rtspClient + "Failed to start playing session: " + resultString);
                    break;
                }

                if (scs.duration > 0)
                {
                    const uint delaySlop = 2;
                    // number of seconds extra to delay, after the stream's expected duration.  (This is optional.)
                    scs.duration += delaySlop;
                    var uSecsToDelay = (long)(scs.duration * 1000000);
                    scs.streamTimerTask = env.TaskScheduler.ScheduleDelayedTask(uSecsToDelay, streamTimerHandler, rtspClient.Native.Native);
                }

                Console.Error.Write(rtspClient + "Started playing session");
                if (scs.duration > 0)
                {
                    Console.Error.Write(" (for up to " + scs.duration + " seconds)");
                }
                Console.Error.WriteLine("...");

                return;
            } while (false);


            // An unrecoverable error occurred with this stream.
            ShutdownStream(rtspClient);
        }
Exemplo n.º 3
0
        private void ContinueAfterDescribe(RTSPClient rtspClient, int resultCode, string resultString)
        {
            while (true) {
                var scs = ((OurRtspClient)rtspClient).scs;

                if (resultCode != 0) {
                    Console.Error.WriteLine ("Failed to get a SDP description: " + resultString);
                    break;
                }

                var description = resultString;

                Console.Error.WriteLine ("Got a SDP description:");
                Console.Error.Write (description);

                scs.session = MediaSession.CreateNew (env, description);

                if (scs.session == null) {
                    Console.Error.WriteLine ("Failed to create a MediaSession object from the SDP description: " + env.GetResultMsg);
                    break;
                }

                if (scs.session.HasSubsessions == 0) {
                    Console.Error.WriteLine ("This session has no media subsessions (i.e., no \"m=\" lines)");
                    break;
                }

                scs.iter = new MediaSubsessionIterator (scs.session);
                SetupNextSubsession (rtspClient);
                return;
            }

            ShutdownStream (rtspClient);
        }
Exemplo n.º 4
0
        private void SetupNextSubsession(RTSPClient rtspClient)
        {
            var scs = ((OurRtspClient)rtspClient).scs; // alias

            scs.subsession = scs.iter.Next();
            if (scs.subsession != null)
            {
                if (scs.subsession.Initiate(0) == 0)
                {
                    Console.Error.WriteLine("Failed to initiate the \"" + scs.subsession + "\" subsession: " + env.GetResultMsg);
                    SetupNextSubsession(rtspClient);  // give up on this subsession; go to the next one
                }
                else
                {
                    Console.Error.WriteLine("Initiated the \"" + scs.subsession +
                                            "\" subsession (client ports " + scs.subsession.ClientPortNum + "-" + (scs.subsession.ClientPortNum + 1) + ")");

                    // Continue setting up this subsession, by sending a RTSP "SETUP" command:
                    rtspClient.SendSetupCommand(scs.subsession, ContinueAfterSetup, 0, 0, 0, null);
                }
                return;
            }

            // We've finished setting up all of the subsessions.  Now, send a RTSP "PLAY" command to start the streaming:
            scs.duration = scs.session.PlayEndTime() - scs.session.PlayStartTime();
            rtspClient.SendPlayCommand(scs.session, ContinueAfterPlay, 0, 0, 0, null);
        }
Exemplo n.º 5
0
        private void ShutdownStream(RTSPClient rtspClient, int exitCode = 1)
        {
            var scs = ((OurRtspClient)rtspClient).scs; // alias

            if (scs.session != null)
            {
                var             someSubsessionsWereActive = false;
                var             iter = new MediaSubsessionIterator(scs.session);
                MediaSubsession subsession;

                while ((subsession = iter.Next()) != null)
                {
                    if (subsession.sink != null)
                    {
                        Medium.Close(subsession.sink);
                        subsession.sink = null;

                        if (subsession.RtcpInstance() != null)
                        {
                            subsession.RtcpInstance().SetByeHandler(null, IntPtr.Zero, 1);
                            // in case the server sends a RTCP "BYE" while handling "TEARDOWN"
                        }

                        someSubsessionsWereActive = true;
                    }
                }

                if (someSubsessionsWereActive)
                {
                    // Send a RTSP "TEARDOWN" command, to tell the server to shutdown the stream.
                    // Don't bother handling the response to the "TEARDOWN".
                    rtspClient.SendTeardownCommand(scs.session, null, null);
                }
            }

            Console.Error.WriteLine(rtspClient + "Closing the stream.");
            Medium.Close(rtspClient);
            // Note that this will also cause this stream's "StreamClientState" structure to get reclaimed.

            if (--rtspClientCount == 0)
            {
                // The final stream has ended, so exit the application now.
                // (Of course, if you're embedding this code into your own application, you might want to comment this out.)
                Environment.Exit(exitCode);

                // If you choose *not* to "exit()" the application (i.e., if you comment out the call to "exit()" above),
                // and you don't intend to do anything more with this "TaskScheduler" and "UsageEnvironment",
                // then you can also reclaim the (small) memory used by these objects by doing the following.
                // (However, you must not do this until after you have left the event loop.)

                /*
                 * TaskScheduler* scheduler = &(env.taskScheduler());
                 * env.reclaim();
                 * delete scheduler;
                 */
            }
        }
Exemplo n.º 6
0
        private void subsessionByeHandler(IntPtr clientData)
        {
            var subsession = new MediaSubsession(clientData);
            var rtspClient = new RTSPClient(subsession.miscPtr);

            Console.Error.WriteLine(rtspClient + "Received RTCP \"BYE\" on \"" + subsession + "\" subsession");

            // Now act as if the subsession had closed:
            SubsessionAfterPlaying(subsession.Native.Native);
        }
Exemplo n.º 7
0
        private void ContinueAfterSetup(RTSPClient rtspClient, int resultCode, string resultString)
        {
            do
            {
                var scs = ((OurRtspClient)rtspClient).scs; // alias

                if (resultCode != 0)
                {
                    Console.Error.WriteLine(rtspClient + "Failed to set up the \"" + scs.subsession + "\" subsession: " +
                                            env.GetResultMsg);
                    break;
                }

                Console.Error.WriteLine(rtspClient + "Set up the \"" + scs.subsession
                                        + "\" subsession (client ports " + scs.subsession.ClientPortNum + "-" +
                                        (scs.subsession.ClientPortNum + 1) + ")");

                // Having successfully setup the subsession, create a data sink for it, and call "startPlaying()" on it.
                // (This will prepare the data sink to receive data; the actual flow of data from the client won't start happening until later,
                // after we've sent a RTSP "PLAY" command.)

                scs.subsession.sink = DummySink.CreateNew(env, scs.subsession, rtspClient.Url);
                // perhaps use your own custom "MediaSink" subclass instead
                if (scs.subsession.sink == null)
                {
                    Console.Error.WriteLine(rtspClient + "Failed to create a data sink for the \"" + scs.subsession
                                            + "\" subsession: " + env.GetResultMsg);
                    break;
                }

                Console.Error.WriteLine(rtspClient + "Created a data sink for the \"" + scs.subsession + "\" subsession");
                scs.subsession.miscPtr = rtspClient.Native.Native;
                // a hack to let subsession handle functions get the "RTSPClient" from the subsession
                scs.subsession.sink.StartPlaying(scs.subsession.ReadSource(), SubsessionAfterPlaying,
                                                 scs.subsession.Native.Native);
                // Also set a handler to be called if a RTCP "BYE" arrives for this subsession:
                if (scs.subsession.RtcpInstance() != null)
                {
                    scs.subsession.RtcpInstance().SetByeHandler(subsessionByeHandler, scs.subsession.Native.Native, 1);
                }
            } while (false);

            // Set up the next subsession, if any:
            SetupNextSubsession(rtspClient);
        }
Exemplo n.º 8
0
        public void Start(string commandData)
        {
            try
            {
                m_rtspAppStruct = new RTSPAppStruct(commandData, false);

                RTSPClient rtspClient = new RTSPClient();
                string     sdp        = rtspClient.GetStreamDescription(m_rtspAppStruct.URL);

                SIPResponse sipResponse = GetOkResponse(m_clientTransaction.TransactionRequest, sdp);

                m_clientTransaction.SendFinalResponse(sipResponse);

                //rtspClient.Start(m_rtspAppStruct.URL, m_clientTransaction.RemoteEndPoint.Address, m_rtpPort);
            }
            catch (Exception excp)
            {
                logger.Error("Exception RTSPCall StartCall. " + excp.Message);
            }
        }
Exemplo n.º 9
0
        private void ContinueAfterDescribe(RTSPClient rtspClient, int resultCode, string resultString)
        {
            while (true)
            {
                var scs = ((OurRtspClient)rtspClient).scs;

                if (resultCode != 0)
                {
                    Console.Error.WriteLine("Failed to get a SDP description: " + resultString);
                    break;
                }

                var description = resultString;

                Console.Error.WriteLine("Got a SDP description:");
                Console.Error.Write(description);

                scs.session = MediaSession.CreateNew(env, description);

                if (scs.session == null)
                {
                    Console.Error.WriteLine("Failed to create a MediaSession object from the SDP description: " + env.GetResultMsg);
                    break;
                }

                if (scs.session.HasSubsessions == 0)
                {
                    Console.Error.WriteLine("This session has no media subsessions (i.e., no \"m=\" lines)");
                    break;
                }

                scs.iter = new MediaSubsessionIterator(scs.session);
                SetupNextSubsession(rtspClient);
                return;
            }

            ShutdownStream(rtspClient);
        }
Exemplo n.º 10
0
        private void SubsessionAfterPlaying(IntPtr clientData)
        {
            var subsession = new MediaSubsession(clientData);
            var rtspClient = new RTSPClient(subsession.miscPtr);

            // Begin by closing this subsession's stream:
            Medium.Close(subsession.sink);
            subsession.sink = null;

            // Next, check whether *all* subsessions' streams have now been closed:
            var session = subsession.ParentSession();
            var iter    = new MediaSubsessionIterator(session);

            while ((subsession = iter.Next()) != null)
            {
                if (subsession.sink != null)
                {
                    return;                          // this subsession is still active
                }
            }

            // All subsessions' streams have now been closed, so shutdown the client:
            ShutdownStream(rtspClient);
        }
Exemplo n.º 11
0
    public void Connect()
    {
        byte [] rbs = new byte[4 + 8 + 16];
        RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();

        rng.GetBytes(rbs);

        string sid = String.Format("{0:D10}",
                                   BitConverter.ToUInt32(rbs, 0));
        string sci = String.Format("{0:X16}",
                                   BitConverter.ToUInt64(rbs, 4));
        string sac = Convert.ToBase64String(rbs, 12, 16);

        string url = String.Format("rtsp://{0}/{1}", local, sid);

        rc           = new RTSPClient(host, 5000, url);
        rc.UserAgent = "iTunes/4.6 (Macintosh; U; PPC Mac OS X 10.3)";
        rc.AddHeaders.Set("Client-Instance", sci);
        rc.Connect();

        string key = Convert.ToBase64String(RSAEncrypt(alg.Key));
        string iv  = Convert.ToBase64String(alg.IV);

        string sdp = String.Format(
            "v=0\r\n" +
            "o=iTunes {0} 0 IN IP4 {1}\r\n" +
            "s=iTunes\r\n" +
            "c=IN IP4 {2}\r\n" +
            "t=0 0\r\n" +
            "m=audio 0 RTP/AVP 96\r\n" +
            "a=rtpmap:96 AppleLossless\r\n" +
            "a=fmtp:96 4096 0 16 40 10 14 2 255 0 0 44100\r\n" +
            "a=rsaaeskey:{3}\r\n" +
            "a=aesiv:{4}\r\n",
            sid, local, host,
            key.Replace("=", ""),
            iv.Replace("=", ""));

        rc.AddHeaders.Set("Apple-Challenge", sac.Replace("=", ""));
        rc.AnnounceSDP(sdp);
        rc.AddHeaders.Remove("Apple-Challenge");

        Hashtable ht = rc.Setup();
        string    aj = (string)ht["Audio-Jack-Status"];

        if (aj == null)
        {
            throw new Exception("Audio-Jack-Status is missing");
        }

        string [] ptokens = aj.Split(new char[] { ';' });
        for (int i = 0; i < ptokens.Length; i++)
        {
            string [] ctokens = ptokens[i].Split(new char[] { '=' });
            for (int j = 0; j < ctokens.Length; j++)
            {
                if (ctokens.Length == 1 &&
                    ctokens[0].Trim().Equals("connected"))
                {
                    ajstatus = JACK_STATUS_CONNECTED;
                }
                else if (ctokens.Length == 2 &&
                         ctokens[0].Trim().Equals("type"))
                {
                    if (ctokens[1].Trim().Equals("digital"))
                    {
                        ajtype = JACK_TYPE_DIGITAL;
                    }
                }
            }
        }

        rc.Record();

        UpdateVolume();

        tcdata = new TcpClient();
        tcdata.Connect(host, rc.ServerPort);
        nsdata = tcdata.GetStream();
    }
Exemplo n.º 12
0
        private void subsessionByeHandler(IntPtr clientData)
        {
            var subsession = new MediaSubsession (clientData);
            var rtspClient = new RTSPClient (subsession.miscPtr);

            Console.Error.WriteLine (rtspClient + "Received RTCP \"BYE\" on \"" + subsession + "\" subsession");

            // Now act as if the subsession had closed:
            SubsessionAfterPlaying (subsession.Native.Native);
        }
Exemplo n.º 13
0
        private void SubsessionAfterPlaying(IntPtr clientData)
        {
            var subsession = new MediaSubsession (clientData);
            var rtspClient = new RTSPClient (subsession.miscPtr);

            // Begin by closing this subsession's stream:
            Medium.Close (subsession.sink);
            subsession.sink = null;

            // Next, check whether *all* subsessions' streams have now been closed:
            var session = subsession.ParentSession ();
            var iter = new MediaSubsessionIterator (session);
            while ((subsession = iter.Next ()) != null) {
                if (subsession.sink != null) return; // this subsession is still active
            }

            // All subsessions' streams have now been closed, so shutdown the client:
            ShutdownStream (rtspClient);
        }
Exemplo n.º 14
0
        private void SetupNextSubsession(RTSPClient rtspClient)
        {
            var scs = ((OurRtspClient)rtspClient).scs; // alias

            scs.subsession = scs.iter.Next ();
            if (scs.subsession != null) {
                if (scs.subsession.Initiate (0) == 0) {
                    Console.Error.WriteLine ("Failed to initiate the \"" + scs.subsession + "\" subsession: " + env.GetResultMsg);
                    SetupNextSubsession (rtspClient); // give up on this subsession; go to the next one
                } else {
                    Console.Error.WriteLine ("Initiated the \"" + scs.subsession +
                        "\" subsession (client ports " + scs.subsession.ClientPortNum + "-" + (scs.subsession.ClientPortNum + 1) + ")");

                    // Continue setting up this subsession, by sending a RTSP "SETUP" command:
                    rtspClient.SendSetupCommand (scs.subsession, ContinueAfterSetup, 0, 0, 0, null);
                }
                return;
            }

            // We've finished setting up all of the subsessions.  Now, send a RTSP "PLAY" command to start the streaming:
            scs.duration = scs.session.PlayEndTime () - scs.session.PlayStartTime ();
            rtspClient.SendPlayCommand (scs.session, ContinueAfterPlay, 0, 0, 0, null);
        }
Exemplo n.º 15
0
        private void ContinueAfterSetup(RTSPClient rtspClient, int resultCode, string resultString)
        {
            do {
                var scs = ((OurRtspClient)rtspClient).scs; // alias

                if (resultCode != 0) {
                    Console.Error.WriteLine (rtspClient + "Failed to set up the \"" + scs.subsession + "\" subsession: " +
                                            env.GetResultMsg);
                    break;
                }

                Console.Error.WriteLine (rtspClient + "Set up the \"" + scs.subsession
                                        + "\" subsession (client ports " + scs.subsession.ClientPortNum + "-" +
                                        (scs.subsession.ClientPortNum + 1) + ")");

                // Having successfully setup the subsession, create a data sink for it, and call "startPlaying()" on it.
                // (This will prepare the data sink to receive data; the actual flow of data from the client won't start happening until later,
                // after we've sent a RTSP "PLAY" command.)

                scs.subsession.sink = DummySink.CreateNew (env, scs.subsession, rtspClient.Url);
                // perhaps use your own custom "MediaSink" subclass instead
                if (scs.subsession.sink == null) {
                    Console.Error.WriteLine (rtspClient + "Failed to create a data sink for the \"" + scs.subsession
                                            + "\" subsession: " + env.GetResultMsg);
                    break;
                }

                Console.Error.WriteLine (rtspClient + "Created a data sink for the \"" + scs.subsession + "\" subsession");
                scs.subsession.miscPtr = rtspClient.Native.Native;
                // a hack to let subsession handle functions get the "RTSPClient" from the subsession
                scs.subsession.sink.StartPlaying (scs.subsession.ReadSource (), SubsessionAfterPlaying,
                                                 scs.subsession.Native.Native);
                // Also set a handler to be called if a RTCP "BYE" arrives for this subsession:
                if (scs.subsession.RtcpInstance () != null) {
                    scs.subsession.RtcpInstance ().SetByeHandler (subsessionByeHandler, scs.subsession.Native.Native, 1);
                }
            } while (false);

            // Set up the next subsession, if any:
            SetupNextSubsession (rtspClient);
        }
Exemplo n.º 16
0
    public void Connect()
    {
        byte [] rbs = new byte[ 4 + 8 + 16 ];
        RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
        rng.GetBytes( rbs );

        string sid = String.Format( "{0:D10}",
            BitConverter.ToUInt32( rbs, 0 ) );
        string sci = String.Format( "{0:X16}",
            BitConverter.ToUInt64( rbs, 4 ) );
        string sac = Convert.ToBase64String( rbs, 12, 16 );

        string url = String.Format( "rtsp://{0}/{1}", local, sid );
        rc = new RTSPClient( host, 5000, url );
        rc.UserAgent = "iTunes/4.6 (Macintosh; U; PPC Mac OS X 10.3)";
        rc.AddHeaders.Set( "Client-Instance", sci );
        rc.Connect();

        string key = Convert.ToBase64String( RSAEncrypt( alg.Key ) );
        string iv = Convert.ToBase64String( alg.IV );

        string sdp = String.Format(
            "v=0\r\n" +
            "o=iTunes {0} 0 IN IP4 {1}\r\n" +
            "s=iTunes\r\n" +
            "c=IN IP4 {2}\r\n" +
            "t=0 0\r\n" +
            "m=audio 0 RTP/AVP 96\r\n" +
            "a=rtpmap:96 AppleLossless\r\n" +
            "a=fmtp:96 4096 0 16 40 10 14 2 255 0 0 44100\r\n" +
            "a=rsaaeskey:{3}\r\n" +
            "a=aesiv:{4}\r\n",
            sid, local, host,
            key.Replace( "=", "" ),
            iv.Replace( "=", "" ) );

        rc.AddHeaders.Set( "Apple-Challenge", sac.Replace( "=", "" ) );
        rc.AnnounceSDP( sdp );
        rc.AddHeaders.Remove( "Apple-Challenge" );

        Hashtable ht = rc.Setup();
        string aj = (string)ht[ "Audio-Jack-Status" ];
        if( aj == null )
            throw new Exception( "Audio-Jack-Status is missing" );

        string [] ptokens = aj.Split( new char[] { ';' } );
        for( int i = 0; i < ptokens.Length; i++ )
        {
            string [] ctokens = ptokens[ i ].Split( new char[] { '=' } );
            for( int j = 0; j < ctokens.Length; j++ )
            {
                if( ctokens.Length == 1 &&
                    ctokens[ 0 ].Trim().Equals( "connected" ) )
                {
                    ajstatus = JACK_STATUS_CONNECTED;
                }
                else if( ctokens.Length == 2 &&
                         ctokens[ 0 ].Trim().Equals( "type" ) )
                {
                    if( ctokens[ 1 ].Trim().Equals( "digital" ) )
                        ajtype = JACK_TYPE_DIGITAL;
                }
            }
        }

        rc.Record();

        UpdateVolume();

        tcdata = new TcpClient();
        tcdata.Connect( host, rc.ServerPort );
        nsdata = tcdata.GetStream();
    }
        public async void rtspClientStart()
        {
            rtspCancel = new CancellationTokenSource();

            var url = "rtsp://192.168.0.10:8554/H264Video";

            String       now    = DateTime.Now.ToString("yyyyMMdd_HHmmss");
            MemoryStream fs_vps = null; // used to write the video
            MemoryStream fs_v   = null; // used to write the video
            MemoryStream fs_a   = null; // used to write the audio

            h264 = false;
            h265 = false;
            bool spsdone = false;

            RTSPClient c = new RTSPClient();

            // The SPS/PPS comes from the SDP data
            // or it is the first SPS/PPS from the H264 video stream
            c.Received_SPS_PPS += (byte[] sps, byte[] pps) => {
                h264 = true;
                if (fs_vps == null)
                {
                    String filename = "rtsp_capture_" + now + ".264";
                    fs_vps = new MemoryStream();
                }

                if (fs_vps != null)
                {
                    fs_vps.SetLength(0);
                    fs_vps.Write(new byte[] { 0x00, 0x00, 0x00, 0x01 }, 0, 4);  // Write Start Code
                    fs_vps.Write(sps, 0, sps.Length);
                    fs_vps.Write(new byte[] { 0x00, 0x00, 0x00, 0x01 }, 0, 4);  // Write Start Code
                    fs_vps.Write(pps, 0, pps.Length);
                }
            };

            c.Received_VPS_SPS_PPS += (byte[] vps, byte[] sps, byte[] pps) => {
                h265 = true;
                if (fs_vps == null)
                {
                    String filename = "rtsp_capture_" + now + ".265";
                    fs_vps = new MemoryStream();
                }

                if (fs_vps != null)
                {
                    fs_vps.SetLength(0);
                    fs_vps.Write(new byte[] { 0x00, 0x00, 0x00, 0x01 }, 0, 4); // Write Start Code
                    fs_vps.Write(vps, 0, vps.Length);                          // Video parameter set
                    fs_vps.Write(new byte[] { 0x00, 0x00, 0x00, 0x01 }, 0, 4); // Write Start Code
                    fs_vps.Write(sps, 0, sps.Length);                          // Sequence Parameter Set
                    fs_vps.Write(new byte[] { 0x00, 0x00, 0x00, 0x01 }, 0, 4); // Write Start Code
                    fs_vps.Write(pps, 0, pps.Length);                          // Picture Parameter Set
                }
            };

            // Video NALs. May also include the SPS and PPS in-band for H264
            c.Received_NALs += (List <byte[]> nal_units) =>
            {
                foreach (byte[] nal_unit in nal_units)
                {
                    // Output some H264 stream information
                    if (h264 && nal_unit.Length > 0)
                    {
                        int    nal_ref_idc   = (nal_unit[0] >> 5) & 0x03;
                        int    nal_unit_type = nal_unit[0] & 0x1F;
                        String description   = "";
                        if (nal_unit_type == 1)
                        {
                            description = "NON IDR NAL";
                        }
                        else if (nal_unit_type == 5)
                        {
                            description = "IDR NAL";
                        }
                        else if (nal_unit_type == 6)
                        {
                            description = "SEI NAL";
                        }
                        else if (nal_unit_type == 7)
                        {
                            description = "SPS NAL";
                        }
                        else if (nal_unit_type == 8)
                        {
                            description = "PPS NAL";
                        }
                        else if (nal_unit_type == 9)
                        {
                            description = "ACCESS UNIT DELIMITER NAL";
                        }
                        else
                        {
                            description = "OTHER NAL";
                        }
                        //Console.WriteLine("NAL Ref = " + nal_ref_idc + " NAL Type = " + nal_unit_type + " " + description);
                    }

                    // Output some H265 stream information
                    if (h265 && nal_unit.Length > 0)
                    {
                        int    nal_unit_type = (nal_unit[0] >> 1) & 0x3F;
                        String description   = "";
                        if (nal_unit_type == 1)
                        {
                            description = "NON IDR NAL";
                        }
                        else if (nal_unit_type == 19)
                        {
                            description = "IDR NAL";
                        }
                        else if (nal_unit_type == 32)
                        {
                            description = "VPS NAL";
                        }
                        else if (nal_unit_type == 33)
                        {
                            description = "SPS NAL";
                        }
                        else if (nal_unit_type == 34)
                        {
                            description = "PPS NAL";
                        }
                        else if (nal_unit_type == 39)
                        {
                            description = "SEI NAL";
                        }
                        else
                        {
                            description = "OTHER NAL";
                        }
                        //Console.WriteLine("NAL Type = " + nal_unit_type + " " + description);
                    }

                    // we need sps... first
                    if (!h264 && !h265)
                    {
                        return;
                    }

                    if (!spsdone)
                    {
                        if (callbacks == null || callbacks.buffers.Count == 0)
                        {
                            return;
                        }
                        var index  = callbacks.buffers.Pop();
                        var buffer = codec.GetInputBuffer(index);
                        buffer.Clear();
                        buffer.Put(fs_vps.ToArray());
                        codec.QueueInputBuffer(index, 0, (int)fs_vps.Length, 0, MediaCodecBufferFlags.CodecConfig);
                        spsdone = true;

                        fs_v = new MemoryStream();
                    }

                    if (fs_v != null)
                    {
                        fs_v.Write(new byte[] { 0x00, 0x00, 0x00, 0x01 }, 0, 4); // Write Start Code
                        fs_v.Write(nal_unit, 0, nal_unit.Length);                // Write NAL
                    }

                    if (callbacks == null || fs_v == null || callbacks.buffers.Count == 0)
                    {
                        return;
                    }
                    try
                    {
                        var index  = callbacks.buffers.Pop();
                        var buffer = codec.GetInputBuffer(index);
                        buffer.Clear();
                        buffer.Put(fs_v.ToArray());
                        codec.QueueInputBuffer(index, 0, (int)fs_v.Length, 0, MediaCodecBufferFlags.None);
                        fs_v.SetLength(0);
                    }
                    catch
                    {
                    }
                }
            };

            // seperate and stay running
            Task.Run(() =>
            {
                while (rtspCancel != null && true)
                {
                    try
                    {
                        if (rtspCancel.Token.IsCancellationRequested)
                        {
                            return;
                        }

                        c.Connect(url, RTSPClient.RTP_TRANSPORT.UDP);
                        var lastrtp = 0;
                        int cnt     = 0;
                        while (!c.StreamingFinished())
                        {
                            rtsprunning = true;
                            Thread.Sleep(500);
                            // existing
                            if (rtspCancel.Token.IsCancellationRequested)
                            {
                                c.Stop();
                                return;
                            }

                            // no rtp in .5 sec
                            if (lastrtp == c.rtp_count && cnt++ > 5)
                            {
                                c.Stop();
                                rtspCancel = null;
                                return;
                            }

                            lastrtp = c.rtp_count;
                        }

                        rtsprunning = false;
                    }
                    catch
                    {
                    }
                }
            });
        }
Exemplo n.º 18
0
        private void ShutdownStream(RTSPClient rtspClient, int exitCode = 1)
        {
            var scs = ((OurRtspClient)rtspClient).scs; // alias

            if (scs.session != null) {
                var someSubsessionsWereActive = false;
                var iter = new MediaSubsessionIterator (scs.session);
                MediaSubsession subsession;

                while ((subsession = iter.Next ()) != null) {
                    if (subsession.sink != null) {
                        Medium.Close (subsession.sink);
                        subsession.sink = null;

                        if (subsession.RtcpInstance () != null) {
                            subsession.RtcpInstance ().SetByeHandler (null, IntPtr.Zero, 1);
                            // in case the server sends a RTCP "BYE" while handling "TEARDOWN"
                        }

                        someSubsessionsWereActive = true;
                    }
                }

                if (someSubsessionsWereActive) {
                    // Send a RTSP "TEARDOWN" command, to tell the server to shutdown the stream.
                    // Don't bother handling the response to the "TEARDOWN".
                    rtspClient.SendTeardownCommand (scs.session, null, null);
                }
            }

            Console.Error.WriteLine (rtspClient + "Closing the stream.");
            Medium.Close (rtspClient);
            // Note that this will also cause this stream's "StreamClientState" structure to get reclaimed.

            if (--rtspClientCount == 0) {
                // The final stream has ended, so exit the application now.
                // (Of course, if you're embedding this code into your own application, you might want to comment this out.)
                Environment.Exit (exitCode);

                // If you choose *not* to "exit()" the application (i.e., if you comment out the call to "exit()" above),
                // and you don't intend to do anything more with this "TaskScheduler" and "UsageEnvironment",
                // then you can also reclaim the (small) memory used by these objects by doing the following.
                // (However, you must not do this until after you have left the event loop.)
                /*
                  TaskScheduler* scheduler = &(env.taskScheduler());
                  env.reclaim();
                  delete scheduler;
                */
            }
        }