Exemplo n.º 1
0
        /// <summary>
        /// Erzeugt eine neue Hintergrundaufgabe zum Auslesen von SI Tabellen.
        /// </summary>
        /// <param name="device">Das zu verwendende Gerät.</param>
        /// <param name="stream">Die Datenstromkennung, die überwacht werden soll.</param>
        /// <returns>Die neue Aufgabe.</returns>
        public static CancellableTask <TTableType[]> GetTableAsync <TTableType>(this Hardware device, ushort stream) where TTableType : Table
        {
            // Validate
            if (device == null)
            {
                throw new ArgumentException("no hardware to use", "device");
            }

            // Create the task
            return
                (CancellableTask <TTableType[]> .Run(cancel =>
            {
                // Termination synchronisation
                var sync = new object();
                var done = false;

                // Parsing state
                var tables = default(TTableType[]);
                var expectedVersion = 0;
                var collectedParts = 0;

                // Create parser
                var parser = TableParser.Create(( TTableType table ) =>
                {
                    // Disabled
                    if (done)
                    {
                        return;
                    }

                    // Check version
                    if (tables != null)
                    {
                        if (table.Version != expectedVersion)
                        {
                            tables = null;
                        }
                    }

                    // Discard on count mismatch
                    if (tables != null)
                    {
                        if (tables.Length != (table.LastSection + 1))
                        {
                            tables = null;
                        }
                    }

                    // Discard on overrun
                    if (tables != null)
                    {
                        if (table.CurrentSection >= tables.Length)
                        {
                            tables = null;
                        }
                    }

                    // Discard on duplicates
                    if (tables != null)
                    {
                        if (tables[table.CurrentSection] != null)
                        {
                            tables = null;
                        }
                    }

                    // Create once
                    if (tables == null)
                    {
                        // Create in full size
                        tables = new TTableType[table.LastSection + 1];
                        expectedVersion = table.Version;
                        collectedParts = 0;
                    }

                    // Add it
                    tables[table.CurrentSection] = table;

                    // Mark as done
                    if (++collectedParts >= tables.Length)
                    {
                        lock (sync)
                        {
                            done = true;

                            // Our wake up call
                            Monitor.Pulse(sync);
                        }
                    }
                });

                // Register with cleanup
                var tableType = Table.GetIsExtendedTable <TTableType>() ? StreamTypes.ExtendedTable : StreamTypes.StandardTable;
                var registration = device.AddConsumer(stream, tableType, parser.AddPayload);
                try
                {
                    // Start receiving data
                    device.SetConsumerState(registration, true);

                    // Wait for end and fully process the cancellation token
                    using (cancel.Register(() => { lock (sync) Monitor.Pulse(sync); }))
                        lock (sync)
                            while (!done)
                            {
                                if (cancel.IsCancellationRequested)
                                {
                                    return null;
                                }
                                else
                                {
                                    Monitor.Wait(sync);
                                }
                            }
                }
                finally
                {
                    // Cleanup
                    device.SetConsumerState(registration, null);
                }

                // Report
                return tables;
            }));
        }
        /// <summary>
        /// Erzeugt eine neue Verwaltung.
        /// </summary>
        /// <param name="hardware">Das Gerät, auf dem die zugehörige Quellgruppe gerade aktiv ist.</param>
        /// <param name="profile">Optional das Geräteprofil mit der zugehörigen Senderliste.</param>
        /// <param name="source">Die Quelle, die zu betrachten ist.</param>
        /// <param name="selection">Die zu betrachtenden Datenströme.</param>
        /// <exception cref="ArgumentNullException">Ein Parameter wurde nicht angegeben.</exception>
        public SourceStreamsManager( Hardware hardware, Profile profile, SourceIdentifier source, StreamSelection selection )
        {
            // Validate
            if (null == hardware)
                throw new ArgumentNullException( "hardware" );
            if (null == source)
                throw new ArgumentNullException( "source" );
            if (null == selection)
                throw new ArgumentNullException( "selection" );

            // Remember all
            StreamSelection = selection;
            Hardware = hardware;
            Profile = profile;
            Source = source;
        }
        /// <summary>
        /// Beginnt die Aufzeichnung in einen <i>Transport Stream</i> - optional als
        /// Datei.
        /// </summary>
        /// <param name="nextPID">Die erste Datenstromkennung (PID), die in der Aufzeichnungsdatei verwendet werden darf.</param>
        /// <param name="recreate">Gesetzt, wenn ein Neustart aufgrund veränderter Nutzdatenströme erforderlich wurde.</param>
        /// <exception cref="ArgumentException">Eine Aufzeichnung der angegebenen Quelle ist nicht möglich.</exception>
        private void CreateStream(short nextPID, bool recreate)
        {
            // Try to get the full name
            var filePath = m_OriginalPath;

            if (filePath != null)
            {
                if (m_FileCount > 0)
                {
                    // Split off the parts
                    var name = Path.GetFileNameWithoutExtension(filePath);
                    var dir  = Path.GetDirectoryName(filePath);
                    var ext  = Path.GetExtension(filePath);

                    // Construct new name
                    filePath = Path.Combine(dir, $"{name} - {m_FileCount}{ext}");
                }
            }

            // Try to decrypt
            if (m_Decrypting = m_OriginalSettings.IsEncrypted)
            {
                try
                {
                    // Process
                    Hardware.Decrypt(Source);
                }
                catch
                {
                    // Ignore any error
                    m_Decrypting = false;
                }
            }

            // Type of the video
            EPG.StreamTypes?videoType;

            // Video first
            if (m_OriginalSettings.VideoStream == 0)
            {
                videoType = null;
            }
            else
            {
                videoType = (m_OriginalSettings.VideoType == VideoTypes.H264) ? EPG.StreamTypes.H264 : EPG.StreamTypes.Video13818;
            }

            // Get the buffer size
            var bufferSize = (FileBufferSizeChooser == null) ? null : FileBufferSizeChooser(videoType);

            // Create the new stream
            m_TransportStream = new Manager(filePath, nextPID, bufferSize.GetValueOrDefault(Manager.DefaultBufferSize));

            // Attach PCR sink
            m_TransportStream.OnWritingPCR = m_WritePCRSink;

            // Report of the actually selected streams
            StreamSelection result = new StreamSelection();

            // Cleanup on any error
            try
            {
                // Video first
                if (videoType.HasValue)
                {
                    AddConsumer(m_OriginalSettings.VideoStream, StreamTypes.Video, m_TransportStream.AddVideo((byte)videoType.Value));
                }

                // Select audio
                ProcessAudioSelection(AudioTypes.MP2, result.MP2Tracks, StreamSelection.MP2Tracks);
                ProcessAudioSelection(AudioTypes.AC3, result.AC3Tracks, StreamSelection.AC3Tracks);

                // Videotext
                if (StreamSelection.Videotext)
                {
                    if (0 != m_OriginalSettings.TextStream)
                    {
                        // Register
                        AddConsumer(m_OriginalSettings.TextStream, StreamTypes.VideoText, m_TransportStream.AddTeleText());

                        // Remember
                        result.Videotext = true;
                    }
                }

                // Subtitle streams
                var subtitles = new Dictionary <ushort, List <EPG.SubtitleInfo> >();

                // Preset mode
                result.SubTitles.LanguageMode = LanguageModes.All;

                // All audio
                // Subtitles
                foreach (var subtitle in m_OriginalSettings.Subtitles)
                {
                    // Check for primary
                    if (StreamSelection.SubTitles.LanguageMode == LanguageModes.Primary)
                    {
                        // Attach to the list
                        AddSubtitleInformation(subtitle, subtitles);

                        // Copy over
                        result.SubTitles.LanguageMode = LanguageModes.Primary;

                        // Remember
                        result.SubTitles.Languages.Add(subtitle.Language);

                        // Done
                        break;
                    }

                    // Standard selection
                    if (StreamSelection.SubTitles.Contains(subtitle.Language))
                    {
                        // Attach to the list
                        AddSubtitleInformation(subtitle, subtitles);

                        // Remember
                        result.SubTitles.Languages.Add(subtitle.Language);
                    }
                    else
                    {
                        // At least one is excluded
                        result.SubTitles.LanguageMode = LanguageModes.Selection;
                    }
                }

                // Clear flag if no audio is used
                if (LanguageModes.All == result.SubTitles.LanguageMode)
                {
                    if (result.SubTitles.Languages.Count < 1)
                    {
                        result.SubTitles.LanguageMode = LanguageModes.Selection;
                    }
                }

                // Process all subtitles
                foreach (var current in subtitles)
                {
                    AddConsumer(current.Key, StreamTypes.SubTitle, m_TransportStream.AddSubtitles(current.Value.ToArray()));
                }

                // See if program guide is requested
                bool epg = StreamSelection.ProgramGuide;

                // May want to disable
                if (epg)
                {
                    if ((Hardware.Profile != null) && Hardware.Profile.DisableProgramGuide)
                    {
                        epg = false;
                    }
                    else if (Profile != null)
                    {
                        if (Profile.GetFilter(Source).DisableProgramGuide)
                        {
                            epg = false;
                        }
                    }
                }

                // EPG
                if (epg)
                {
                    // Activate dispatch
                    m_TransportStream.SetEPGMapping(Source.Network, Source.TransportStream, Source.Service);

                    // Start it
                    Hardware.AddProgramGuideConsumer(DispatchEPG);

                    // Remember
                    result.ProgramGuide = true;
                }

                // Counter
                int started = 0;
                try
                {
                    // Start all
                    foreach (var consumer in m_Consumers)
                    {
                        try
                        {
                            // Forward
                            Hardware.SetConsumerState(consumer, true);

                            // Count it
                            ++started;
                        }
                        catch (OutOfConsumersException)
                        {
                            // Translate
                            throw new OutOfConsumersException(m_Consumers.Count, started)
                                  {
                                      RequestedSelection = result
                                  };
                        }
                    }
                }
                catch
                {
                    // Detach EPG
                    Hardware.RemoveProgramGuideConsumer(DispatchEPG);

                    // Cleanup on all errors
                    foreach (var consumer in m_Consumers)
                    {
                        try
                        {
                            // Remove
                            Hardware.SetConsumerState(consumer, null);
                        }
                        catch
                        {
                            // Ignore any error
                        }
                    }

                    // Forward
                    throw;
                }

                // Remember path
                if (filePath != null)
                {
                    m_AllFiles.Add(new FileStreamInformation {
                        FilePath = filePath, VideoType = m_OriginalSettings.VideoType
                    });
                }

                // Remember the time
                LastActivationTime = DateTime.UtcNow;
            }
            catch
            {
                // Simply forget
                m_TransportStream.Dispose();
                m_TransportStream = null;

                // Forward
                throw;
            }

            // Get the next free PID
            NextStreamIdentifier = m_TransportStream.NextPID;

            // Remember the streams we use
            ActiveSelection = result;

            // Attach to clients
            var createNotify = OnCreatedStream;

            // Report
            if (createNotify != null)
            {
                createNotify(this);
            }
        }
Exemplo n.º 4
0
 /// <summary>
 /// Startet das Auslesen einer SI-Tabelle.
 /// </summary>
 /// <typeparam name="TTableType">Die Art der Tabelle.</typeparam>
 /// <param name="device">Das zu verwendende, bereits aktivierte Gerät.</param>
 /// <returns>Die Steuerung des Auslesevorgangs.</returns>
 public static CancellableTask <TTableType[]> GetTableAsync <TTableType>(this Hardware device) where TTableType : WellKnownTable
 {
     return(device.GetTableAsync <TTableType>(WellKnownTable.GetWellKnownStream <TTableType>()));
 }
 /// <summary>
 /// Meldet einen Datenstrom zum Datenempfang an.
 /// </summary>
 /// <param name="pid">Die gewünschte Datestromkennung (PID).</param>
 /// <param name="type">Die Art der Nutzdaten im Datenstrom.</param>
 /// <param name="stream">Der Empfänger der Daten.</param>
 private void AddConsumer(ushort pid, StreamTypes type, StreamBase stream) => m_Consumers.Add(Hardware.AddConsumer(pid, type, stream.AddPayload));
 /// <summary>
 /// Startet das Auslesen der aktuellen Daten zur aktiven Quelle im Hintergrund.
 /// </summary>
 /// <returns>Eine Steuerinstanz zum asynchronen Zugriff auf die aktuellen Daten.</returns>
 public CancellableTask <SourceInformation> GetCurrentInformationAsync() => Hardware.GetSourceInformationAsync(Source, Profile);
Exemplo n.º 7
0
 /// <summary>
 /// Meldet eine Analyseinstanz auf einem Datenstrom von SI Tabellen an.
 /// </summary>
 /// <param name="provider">Die zu aktuelle Hardware Abstraktion.</param>
 /// <param name="stream">Die eindeutige Nummer (PID) des Datenstroms in der aktuellen <see cref="SourceGroup"/>.</param>
 /// <param name="parser">Die zu verwendene Analyseeinheit.</param>
 /// <returns>Die eindeutige Kennung des neu angemeldeten Verbrauchers.</returns>
 /// <exception cref="ArgumentNullException">Die Hardware Abstraktion und / oder die Analyseinstanz
 /// sind nicht gesetzt.</exception>
 public static Guid AddConsumer(this Hardware provider, ushort stream, TableParser parser)
 {
     // Forward
     return(provider.AddConsumer(stream, parser, StreamTypes.StandardTable));
 }
Exemplo n.º 8
0
 /// <summary>
 /// Wandelt einen zusammengehörigen Block von SI NIT Tabellen in Informationen über einen
 /// Ursprung um.
 /// </summary>
 /// <param name="tables">Die Rohinformationen als SI NIT Tabellen.</param>
 /// <param name="provider">Das zugehörige DVB.NET Gerät, das noch auf den Ursprung eingestellt ist.</param>
 /// <returns>Die gewünschten Informationen.</returns>
 public static TerrestrialLocationInformation ToLocationInformation(this NIT[] tables, Hardware <TerrestrialProfile, TerrestrialLocation, TerrestrialGroup> provider)
 {
     // Forward
     return(CreateLocationInformation <TerrestrialGroup, TerrestrialLocationInformation>(new TerrestrialLocation(), tables));
 }
Exemplo n.º 9
0
 /// <summary>
 /// Wandelt einen zusammengehörigen Block von SI NIT Tabellen in Informationen über einen
 /// Ursprung um.
 /// </summary>
 /// <param name="tables">Die Rohinformationen als SI NIT Tabellen.</param>
 /// <param name="provider">Das zugehörige DVB.NET Gerät, das noch auf den Ursprung eingestellt ist.</param>
 /// <returns>Die gewünschten Informationen.</returns>
 public static CableLocationInformation ToLocationInformation(this NIT[] tables, Hardware <CableProfile, CableLocation, CableGroup> provider)
 {
     // Forward
     return(CreateLocationInformation <CableGroup, CableLocationInformation>(new CableLocation(), tables));
 }
Exemplo n.º 10
0
 /// <summary>
 /// Wandelt einen zusammengehörigen Block von SI NIT Tabellen in Informationen über einen
 /// Ursprung um.
 /// </summary>
 /// <param name="tables">Die Rohinformationen als SI NIT Tabellen.</param>
 /// <param name="provider">Das zugehörige DVB.NET Gerät, das noch auf den Ursprung eingestellt ist.</param>
 /// <returns>Die gewünschten Informationen.</returns>
 public static SatelliteLocationInformation ToLocationInformation(this NIT[] tables, Hardware <SatelliteProfile, SatelliteLocation, SatelliteGroup> provider)
 {
     // Forward
     if (null == provider)
     {
         return(CreateLocationInformation <SatelliteGroup, SatelliteLocationInformation>(new SatelliteLocation(), tables));
     }
     else
     {
         return(CreateLocationInformation <SatelliteGroup, SatelliteLocationInformation>(SatelliteLocation.Parse(provider.CurrentLocation.ToString()), tables));
     }
 }
 /// <summary>
 /// Erzeugt einen Aufzeichnungskontext für eine Quelle.
 /// </summary>
 /// <param name="source">Die Informationen zur Quelle.</param>
 /// <param name="hardware">Das zu verwendende Gerät.</param>
 /// <param name="profile">Opetional ein Geräteprofil mit der zugehörigen Senderliste.</param>
 /// <param name="streams">Die gewünschten Aufzeichnungsparameter.</param>
 /// <returns>Eine Kontrollinstanz für die Aufzeichnung. Diese muss mittels <see cref="IDisposable.Dispose"/>
 /// freigegeben werden.</returns>
 public static SourceStreamsManager Open(this SourceIdentifier source, Hardware hardware, Profile profile, StreamSelection streams)
 {
     // Forward
     return(new SourceStreamsManager(hardware, profile, source, streams));
 }