/// <summary>
        /// Beginnt mit dem Auslesen der Quelldaten.
        /// </summary>
        /// <param name="source">Die gewünschte Quelle.</param>
        /// <param name="device">Das zu verwendende Gerät.</param>
        /// <param name="profile">Optional das zu berücksichtigende Geräteprofil.</param>
        /// <returns>Die Hintergrundaufgabe zum Auslesen der Quelledaten.</returns>
        public static CancellableTask <SourceInformation> GetSourceInformationAsync(this Hardware device, SourceIdentifier source, Profile profile = null)
        {
            // Validate
            if (device == null)
            {
                throw new ArgumentNullException("no hardware to use", "device");
            }
            if (source == null)
            {
                throw new ArgumentException("no source to get information for", "source");
            }

            // Attach to tasks
            var patReader   = device.AssociationTableReader;
            var groupReader = device.GroupReader;

            // Start
            return
                (CancellableTask <SourceInformation> .Run(cancel =>
            {
                // Check tasks
                if (groupReader == null)
                {
                    return null;
                }
                if (patReader == null)
                {
                    return null;
                }

                // Wait on tasks
                if (!groupReader.CancellableWait(cancel))
                {
                    return null;
                }
                if (!patReader.CancellableWait(cancel))
                {
                    return null;
                }

                // Get the current group information
                var groupInfo = groupReader.Result;
                if (groupInfo == null)
                {
                    return null;
                }

                // See if group exists
                if (!groupInfo.Sources.Any(source.Equals))
                {
                    return null;
                }

                // Find the stream identifier for the service
                var pmtIdentifier = patReader.Result.FindService(source.Service);
                if (!pmtIdentifier.HasValue)
                {
                    return null;
                }

                // Wait for mapping table
                var pmtReader = device.GetTableAsync <PMT>(pmtIdentifier.Value);
                if (!pmtReader.CancellableWait(cancel))
                {
                    return null;
                }

                // Request table
                var pmts = pmtReader.Result;
                if (pmts == null)
                {
                    return null;
                }

                // Create dummy
                var currentSettings = new SourceInformation {
                    Source = source, VideoType = VideoTypes.NoVideo
                };

                // Process all PMT - actually should be only one
                foreach (var pmt in pmts)
                {
                    // Overwrite encryption if CA descriptor is present
                    if (pmt.Table.Descriptors != null)
                    {
                        currentSettings.IsEncrypted = pmt.Table.Descriptors.Any(descriptor => EPG.DescriptorTags.CA == descriptor.Tag);
                    }

                    // Process the program entries
                    foreach (var program in pmt.Table.ProgramEntries)
                    {
                        currentSettings.Update(program);
                    }
                }

                // Find the related station information
                var station = groupInfo.Sources.FirstOrDefault(source.Equals) as Station;
                if (station != null)
                {
                    // Take data from there
                    currentSettings.Provider = station.Provider;
                    currentSettings.Name = station.Name;

                    // See if this is a service
                    currentSettings.IsService = station.IsService;

                    // Overwrite encryption if regular service entry exists
                    if (!currentSettings.IsService)
                    {
                        currentSettings.IsEncrypted = station.IsEncrypted;
                    }
                }

                // See if profile is attached
                if (profile != null)
                {
                    // Apply the modifier
                    var modifier = profile.GetFilter(currentSettings.Source);
                    if (modifier != null)
                    {
                        modifier.ApplyTo(currentSettings);
                    }
                }

                // Report
                return currentSettings;
            }));
        }
Ejemplo n.º 2
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;
            }));
        }