Jump to content

SAT>IP


Schimi

Recommended Posts

eddiepropane

Hi all,

 

Didn't want to start a new thread as it discussed quite heavily in here.

 

Lifetime supporter which is all I can really do apart from test unfortunately as I have no coding skills - Spent the last Cpl of hours looking at emby and VLC's GitHub to see if I can see why it works on VLC and not emby (I think I know it is ffdshow related but was trying to see how it parsed the m3u) and realised I know far less than I thought!! :(

 

Has there been any updates/movement on the Dvbviewer RS Sat-Ip support?

 

I can see that the server parses the m3u file a bit better since I last checked a few months ago but still does not get playback.

 

The live TV plugins are good and well developed but each have their strengths and weaknesses and to be able to use sat-ip and schedules direct on the server without and additional software would be awesome!!

 

Thanks, B.

Link to comment
Share on other sites

There hasn't been any movement lately for built-in sat-ip support. It's still a possibility for the future.

  • Like 1
Link to comment
Share on other sites

pir8radio

What is needed for the developers to make this happen?   Other than time...    A device for testing?

Link to comment
Share on other sites

pir8radio

I can probably stand one up online for testing....   so you don't have to deal with antenna aiming and what not.  If that helps..  Give you an IP and DMZ it...  If that's something you would be interested in.

Edited by pir8radio
Link to comment
Share on other sites

Guest Diefenthal

 one please

 

dont only Support the m3u way

 

if emby really want Support the sat>ip protocol  then should it both ways Support

that was since my Suggestion with

ssdp for device discovery (is done in the sample)

rtsp for start, keepalive, stop the mediastream(is done in the sample)

rtp for receiving the mediastream(is done in the sample)

rtcp for mediastream informations ( Recieption Details Signal Level Quality , Lost packets ....)(is done in the sample)

 

 

parsing of Mpeg2TS (PAT, PMT, SDT, NIT, EIT) for Channel / Service Scan (not finshed  far away from stable)

 

 

Edited by Diefenthal
  • Like 2
Link to comment
Share on other sites

@@Luke had here 2 questions

 

for what stands the integer TunerHostInfo.Tuners?

 

if i build emby with vs 2015  on Windows 10 wich is the commonstartup Project for testing ?

 

https://github.com/MediaBrowser/Emby/pull/2116

 

Total number of tuners. The startup project for windows is mediabrowser.ServerApplication

 

Thanks!

Link to comment
Share on other sites

Guest Diefenthal

ok _tunerCountDVBS integer is working

 

so should it work with  _tunerCountDVBT and _tunerCountDVBC too

 

but i am must now look why only one of two Satip Servers are listed in the UI 

Link to comment
Share on other sites

Thanks! I have merged all current changes into the dev branch as well as posted a dev build for Windows users. So any of you with Sat/IP can help test it out. For those who run beta, it will be in tomorrow's beta. Thanks.

  • Like 1
Link to comment
Share on other sites

@@Luke

 

had set an Breakpoint  in method GetChannelsInternal()  from SatipHost.cs  but this is never triggert

 

Did you try running the refresh guide scheduled task?

Link to comment
Share on other sites

Guest Diefenthal

in futuere should it splittet  or controlled with one more Parameter

the channel scan is much faster without reading guide data (DVB EIT)

 

 

 

rtsp session is feed with an wrong Url Format  there is only the address needed no Schema(Http://) no port(:x) from the description

 

possible fix can be use two fields 

one called Device Description Url

the other Device Url

 

for an channel Change must the session not terminated (Teardown) an simple Play request with updated Tuning string, addpids or delpids to the Server is enough see it in the wireshark capture wich is inside attached zip

 

 

 

 

 

 

Edited by Diefenthal
Link to comment
Share on other sites

Guest Diefenthal

what think you over this

 

each tuner inside an Sat>ip device  had an own

rtsp rtp rtcp session

 

sure this code snippet  isnt complete  but it sould only illustrade what for other ways it give

public abstract class Tuner:IDisposable
    {
        private static readonly Regex REGEX_DESCRIBE_RESPONSE_SIGNAL_INFO = new Regex(@";tuner=\d+,(\d+),(\d+),(\d+),", RegexOptions.Singleline | RegexOptions.IgnoreCase);
        private static readonly Regex REGEX_RTSP_SESSION_HEADER = new Regex(@"\s*([^\s;]+)(;timeout=(\d+))?");
        private static readonly TimeSpan DEFAULT_RTSP_SESSION_TIMEOUT = new TimeSpan(0, 0, 60);
        private static readonly TimeSpan RTCP_REPORT_WAIT_TIMEOUT = new TimeSpan(0, 0, 0, 0, 400);

        #region Private Fields
        /// <summary>
        /// An RTSP client, used to communicate with the SAT>IP server.
        /// </summary>
        private RtspClient _rtspClient = null;
        /// <summary>
        /// The time after which the SAT>IP server will stop streaming if it does
        /// not receive some kind of interaction.
        /// </summary>
        private TimeSpan _rtspSessionTimeout = TimeSpan.Zero;
        /// <summary>
        /// The current RTSP session ID. Used in the header of all RTSP messages
        /// sent to the server.
        /// </summary>
        private string _rtspSessionId = string.Empty;
        /// <summary>
        /// A thread, used to periodically send RTSP OPTIONS to tell the SAT>IP
        /// server not to stop streaming.
        /// </summary>
        private Thread _keepAliveThread = null;
        /// <summary>
        /// An event, used to stop the streaming keep-alive thread.
        /// </summary>
        private AutoResetEvent _keepAliveThreadStopEvent = null;
        /// <summary>
        /// A thread, used to listen for RTP Packets containing the Transportstream
        /// </summary>
        private Thread _rtpListenerThread = null;
        /// <summary>
        /// An event, used to stop the RTP listener thread.
        /// </summary>
        private AutoResetEvent _rtpListenerThreadStopEvent = null;
        /// <summary>
        /// A thread, used to listen for RTCP reports containing signal status
        /// updates.
        /// </summary>
        private Thread _rtcpListenerThread = null;
        /// <summary>
        /// An event, used to stop the RTCP listener thread.
        /// </summary>
        private AutoResetEvent _rtcpListenerThreadStopEvent = null;
        /// <summary>
        /// 
        /// </summary>
        private TransmissionMode _transmissionMode = TransmissionMode.Unicast;
        /// <summary>
        /// The Address on which the RTP RTCP listener thread listens.
        /// </summary>
        private string _destination;
        /// <summary>
        /// The Address that the RTP RTCP listener thread listens to.
        /// </summary>
        private string _source;
        /// <summary>
        /// The port on which the RTP listener thread listens.
        /// </summary>
        private int _rtpClientPort;
        /// <summary>
        /// The port that the RTP listener thread listens to.
        /// </summary>
        private int _rtpServerPort;
        /// <summary>
        /// The port on which the RTCP listener thread listens.
        /// </summary>
        private int _rtcpClientPort;
        /// <summary>
        /// The port that the RTCP listener thread listens to.
        /// </summary>
        private int _rtcpServerPort;
        /// <summary>
        /// 
        /// </summary>
        private bool _signalLocked = false;
        /// <summary>
        /// 
        /// </summary>
        private int _signalLevel = -1;
        /// <summary>
        /// 
        /// </summary>
        private int _signalQuality = -1;        
        #endregion
        #region Properties
        /// <summary>
        /// The Address on which the RTP RTCP listener thread listens.
        /// </summary>
        public string Destination
        {
            get { return _destination; }
            set { _destination = value; }
        }
        /// <summary>
        /// The Address that the RTP RTCP listener thread listens to.
        /// </summary>
        public string Source
        {
            get { return _source; }
            set { _source = value; }
        }
        /// <summary>
        /// The port on which the RTP listener thread listens.
        /// </summary>
        public int RtpClientPort
        {
            get { return _rtpClientPort; }
            set { _rtpClientPort = value; }
        }
        /// <summary>
        /// The port that the RTP listener thread listens to.
        /// </summary>
        public int RtpServerPort
        {
            get { return _rtpServerPort; }
            set { _rtpServerPort = value; }
        } 
        /// <summary>
        /// The port on which the RTCP listener thread listens.
        /// </summary>
        public int RtcpClientPort
        {
            get { return _rtcpClientPort; }
            set { _rtcpClientPort = value; }
        }
        /// <summary>
        /// The port that the RTCP listener thread listens to.
        /// </summary>
        public int RtcpServerPort
        {
            get { return _rtcpServerPort; }
            set { _rtcpServerPort = value; }
        }
        /// <summary>
        /// 
        /// </summary>
        public bool SignalLocked
        {
            get { return _signalLocked; }
            set { _signalLocked = value; }
        }
        /// <summary>
        /// 
        /// </summary>
        public int SignalLevel
        {
            get { return _signalLevel; }
            set { _signalLevel = value; }
        }
        /// <summary>
        /// 
        /// </summary>
        public int SignalQuality
        {
            get { return _signalQuality; }
            set { _signalQuality = value; }
        }


        #endregion
        #region KeepAlive Thread
        private void StartKeepAliveThread()
        {
            // Kill the existing thread if it is in "zombie" state.
            if (_keepAliveThread != null && !_keepAliveThread.IsAlive)
            {
                StopKeepAliveThread();
            }
 
            if (_keepAliveThread == null)
            {
                Logger.Info("SAT>IP : starting new keep-alive thread");
                _keepAliveThreadStopEvent = new AutoResetEvent(false);
                _keepAliveThread = new Thread(new ThreadStart(KeepAlive));
                _keepAliveThread.Name = string.Format("SAT>IP tuner  keep-alive");
                _keepAliveThread.IsBackground = true;
                _keepAliveThread.Priority = ThreadPriority.Lowest;
                _keepAliveThread.Start();
            }
        } 
        private void StopKeepAliveThread()
        {
            if (_keepAliveThread != null)
            {
                if (!_keepAliveThread.IsAlive)
                {
                    Logger.Critical("SAT>IP : aborting old keep-alive thread");
                    _keepAliveThread.Abort();
                }
                else
                {
                    _keepAliveThreadStopEvent.Set();
                    if (!_keepAliveThread.Join((int)_rtspSessionTimeout.TotalMilliseconds * 2))
                    {
                        Logger.Critical("SAT>IP : failed to join keep-alive thread, aborting thread");
                        _keepAliveThread.Abort();
                    }
                }
                _keepAliveThread = null;
                if (_keepAliveThreadStopEvent != null)
                {
                    _keepAliveThreadStopEvent.Close();
                    _keepAliveThreadStopEvent = null;
                }
            }
        }     
        private void KeepAlive()
        {
            try
            {
                while (!_keepAliveThreadStopEvent.WaitOne((int)(_rtspSessionTimeout - new TimeSpan(0, 0, 5)).TotalMilliseconds * 1000))    // -5 seconds to avoid timeout
                {
                    RtspRequest request = new RtspRequest(RtspMethod.Options, string.Format("rtsp://{0}/", Source),1,0);
                    request.Headers.Add("Session", _rtspSessionId);
                    RtspResponse response;
                    if (_rtspClient.SendRequest(request, out response) != RtspStatusCode.Ok)
                    {
                        Logger.Critical("SAT>IP : keep-alive request/response failed, non-OK RTSP OPTIONS status code {0} {1}", response.StatusCode, response.ReasonPhrase);
                    }
                }
            }
            catch (ThreadAbortException)
            {
            }
            catch (Exception ex)
            {
                Logger.Error(ex.ToString(), "SAT>IP : keep-alive thread exception");
                return;
            }
            Logger.Info("SAT>IP : keep-alive thread stopping");
        }   
        #endregion
        #region RTP listener Thread
        public void StartRtpListenerThread()
        {
            // Kill the existing thread if it is in "zombie" state.
            if (_rtpListenerThread != null && !_rtpListenerThread.IsAlive)
            {
                StopRtpListenerThread();
            }

            if (_rtpListenerThread == null)
            {
                Logger.Info("SAT>IP : starting new RTP listener thread");
                _rtpListenerThreadStopEvent = new AutoResetEvent(false);
                _rtpListenerThread = new Thread(new ThreadStart(RtpListenerThread));
                _rtpListenerThread.Name = string.Format("SAT>IP tuner  RTP listener");
                _rtpListenerThread.IsBackground = true;
                _rtpListenerThread.Priority = ThreadPriority.Lowest;
                _rtpListenerThread.Start();
            }
        }
        public void StopRtpListenerThread()
        {
            if (_rtpListenerThread != null)
            {
                if (!_rtpListenerThread.IsAlive)
                {
                    Logger.Warn("SAT>IP : aborting old RTP listener thread");
                    _rtpListenerThread.Abort();
                }
                else
                {
                    _rtpListenerThreadStopEvent.Set();
                    if (!_rtpListenerThread.Join(400 * 2))
                    {
                        Logger.Warn("SAT>IP : failed to join RTP listener thread, aborting thread");
                        _rtpListenerThread.Abort();
                    }
                }
                _rtpListenerThread = null;
                if (_rtpListenerThreadStopEvent != null)
                {
                    _rtpListenerThreadStopEvent.Close();
                    _rtpListenerThreadStopEvent = null;
                }
            }
        }

        private void RtpListenerThread()
        {
            UdpClient rtpClient = null;
            IPEndPoint serverEndPoint = null;
            IPEndPoint multicastEndPoint = null;
            try
            {
                switch (_transmissionMode)
                {
                    case TransmissionMode.Unicast:
                        rtpClient = new UdpClient(new IPEndPoint(IPAddress.Parse(Destination), RtpClientPort));
                        serverEndPoint = new IPEndPoint(IPAddress.Any, 0);
                        break;
                    case TransmissionMode.Multicast:
                        multicastEndPoint = new IPEndPoint(IPAddress.Parse(Destination), RtpClientPort);
                        serverEndPoint = null;
                        rtpClient = new UdpClient();
                        rtpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, 1);
                        rtpClient.ExclusiveAddressUse = false;
                        rtpClient.Client.Bind(new IPEndPoint(IPAddress.Any, multicastEndPoint.Port));
                        rtpClient.JoinMulticastGroup(multicastEndPoint.Address);
                        break;
                }  
                try
                {

                    while (!receivedGoodBye && !_rtpListenerThreadStopEvent.WaitOne(1))
                    {
                        byte[] receivedbytes = rtpClient.Receive(ref serverEndPoint);
                        RtpPacket packet = RtpPacket.Decode(receivedbytes);
                        //OnPacketReceived(new RtpPacketReceivedArgs(packet));
                    }
                }
                finally
                {
                    switch (_transmissionMode)
                    {
                        case TransmissionMode.Multicast:
                            rtpClient.DropMulticastGroup(multicastEndPoint.Address);
                            rtpClient.Close();
                            break;
                        case TransmissionMode.Unicast:
                            rtpClient.Close();
                            break;
                    }
                }
            }
            catch (ThreadAbortException)
            {
            }
            catch (Exception ex)
            {
                Logger.Error(string.Format("SAT>IP : RTP listener thread exception"), ex);
                return;
            }
            Logger.Warn("SAT>IP : RTP listener thread stopping");
        }

        #endregion
        #region RTCP listener Thread
        private void StartRtcpListenerThread()
        {
            // Kill the existing thread if it is in "zombie" state.
            if (_rtcpListenerThread != null && !_rtcpListenerThread.IsAlive)
            {
                StopRtcpListenerThread();
            }

            if (_rtcpListenerThread == null)
            {
                Logger.Info("SAT>IP base: starting new RTCP listener thread");
                _rtcpListenerThreadStopEvent = new AutoResetEvent(false);
                _rtcpListenerThread = new Thread(new ThreadStart(RtcpListener));
                _rtcpListenerThread.Name = string.Format("SAT>IP tuner RTCP listener");
                _rtcpListenerThread.IsBackground = true;
                _rtcpListenerThread.Priority = ThreadPriority.Lowest;
                _rtcpListenerThread.Start();
            }
        }
        private void StopRtcpListenerThread()
        {
            if (_rtcpListenerThread != null)
            {
                if (!_rtcpListenerThread.IsAlive)
                {
                    Logger.Critical("SAT>IP base: aborting old RTCP listener thread");
                    _rtcpListenerThread.Abort();
                }
                else
                {
                    _rtcpListenerThreadStopEvent.Set();
                    if (!_rtcpListenerThread.Join((int)RTCP_REPORT_WAIT_TIMEOUT.TotalMilliseconds * 2))
                    {
                        Logger.Critical("SAT>IP base: failed to join RTCP listener thread, aborting thread");
                        _rtcpListenerThread.Abort();
                    }
                }
                _rtcpListenerThread = null;
                if (_rtcpListenerThreadStopEvent != null)
                {

                    _rtcpListenerThreadStopEvent.Close();
                    _rtcpListenerThreadStopEvent = null;
                }
            }
        }
        private void RtcpListener()
        {
            UdpClient rtcpClient = null;
            IPEndPoint serverEndPoint = null;
            IPEndPoint multicastEndPoint = null;
            try
            {
                switch (_transmissionMode)
                {
                    case TransmissionMode.Unicast:
                        rtcpClient = new UdpClient(new IPEndPoint(IPAddress.Parse(Destination), RtcpClientPort));
                        rtcpClient.Client.ReceiveTimeout = 5000;
                        serverEndPoint = new IPEndPoint(IPAddress.Any, 0);
                        break;
                    case TransmissionMode.Multicast:
                        multicastEndPoint = new IPEndPoint(IPAddress.Parse(Destination), RtcpClientPort);
                        serverEndPoint = new IPEndPoint(IPAddress.Any, 0);
                        rtcpClient = new UdpClient();
                        rtcpClient.Client.ReceiveTimeout = 5000;
                        rtcpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, 1);
                        rtcpClient.ExclusiveAddressUse = false;
                        rtcpClient.Client.Bind(new IPEndPoint(IPAddress.Any, RtcpClientPort));
                        rtcpClient.JoinMulticastGroup(multicastEndPoint.Address);
                        break;
                }
                bool receivedGoodBye = false;
               
                try
                {                    
                    while (!receivedGoodBye && !_rtcpListenerThreadStopEvent.WaitOne(1))
                    {
                        byte[] packets = null;
                        try
                        {
                            packets = rtcpClient.Receive(ref serverEndPoint);
                        }
                        catch (Exception ex)
                        {
                            Logger.Critical(ex.ToString(), "SAT>IP base: failed to receive RTCP packets");
                        }
                        if (packets == null)
                        {
                            continue;
                        }
                        int offset = 0;                        
                        while (offset < packets.Length)
                        {
                            switch (packets[offset + 1])
                            {
                                case 200: //sr
                                    var sr = new RtcpSenderReportPacket();
                                    sr.Parse(packets, offset);
                                    offset += sr.Length;
                                    break;
                                case 201: //rr
                                    var rr = new RtcpReceiverReportPacket();
                                    rr.Parse(packets, offset);
                                    offset += rr.Length;
                                    break;
                                case 202: //sd
                                    var sd = new RtcpSourceDescriptionPacket();
                                    sd.Parse(packets, offset);
                                    offset += sd.Length;
                                    break;
                                case 203: // bye
                                    var bye = new RtcpByePacket();
                                    bye.Parse(packets, offset);
                                    receivedGoodBye = true;                                    
                                    offset += bye.Length;
                                    break;
                                case 204: // app
                                    var app = new RtcpAppPacket();
                                    app.Parse(packets, offset);
                                    var m = REGEX_DESCRIBE_RESPONSE_SIGNAL_INFO.Match(app.Data);
                                    if (m.Success)
                                    {
                                        _signalLocked = m.Groups[2].Captures[0].Value.Equals("1");
                                        _signalLevel = int.Parse(m.Groups[1].Captures[0].Value) * 100 / 255;    // level: 0..255 => 0..100
                                        _signalQuality = int.Parse(m.Groups[3].Captures[0].Value) * 100 / 15;   // quality: 0..15 => 0..100                
                                    }
                                    
                                    offset += app.Length;
                                    break;
                            }
                        }
                    }
                }

                finally
                {
                    switch (_transmissionMode)
                    {
                        case TransmissionMode.Multicast:
                            rtcpClient.DropMulticastGroup(multicastEndPoint.Address);
                            rtcpClient.Close();
                            break;
                        case TransmissionMode.Unicast:
                            rtcpClient.Close();
                            break;
                    }   
                }
            }
            catch (ThreadAbortException)
            {
            }
            catch (Exception ex)
            {
                Logger.Error(ex.ToString(), "SAT>IP base: RTCP listener thread exception");
                return;
            }
            Logger.Info("SAT>IP base: RTCP listener thread stopping");
        }
        #endregion       


        #region IDisposable Members
        /// <summary>
        /// Release and dispose all resources.
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        /// <summary>
        /// Release and dispose all resources.
        /// </summary>
        /// <param name="isDisposing"><c>True</c> if the instance is being disposed.</param>
        private void Dispose(bool isDisposing)
        {
            if (isDisposing)
            {
                if (_rtspClient != null)
                {
                    _rtspClient.Dispose();
                    _rtspClient = null;
                }                
            }
        }
        #endregion
    }
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...