/// <summary>
        /// Aktiviert den Empfang einer Quelle.
        /// </summary>
        /// <param name="sources">Informationen zu den zu aktivierenden Quellen.</param>
        protected override void OnAddSources(ReceiveInformation[] sources)
        {
            // Prepare operation
            Start(device =>
            {
                // Check mode
                if (EPGProgress.HasValue)
                {
                    CardServerException.Throw(new EPGActiveFault());
                }
                if (m_ScanProgress >= 0)
                {
                    CardServerException.Throw(new SourceUpdateActiveFault());
                }

                // Force reload of group information to be current
                device.ResetInformationReaders();

                // Create optimizer
                var optimizer = new StreamSelectionOptimizer();

                // Source backmap
                var infos = new Dictionary <SourceIdenfierWithKey, ReceiveInformation>();

                // Pre-Test
                foreach (var info in sources)
                {
                    // It's not allowed to activate a source twice
                    var key = new SourceIdenfierWithKey(info.UniqueIdentifier, info.Selection.Source);
                    if (FindSource(key) != null)
                    {
                        CardServerException.Throw(new SourceInUseFault(info.Selection.Source));
                    }

                    // Remember
                    infos.Add(key, info);

                    // Prepare to optimize
                    optimizer.Add(info.Selection, info.Streams);
                }

                // See how many we are allowed to start
                var allowed = optimizer.Optimize();

                // Streams to activate
                var newStreams = new List <ActiveStream>();
                try
                {
                    // Process all
                    for (int i = 0; i < allowed; ++i)
                    {
                        // Attach to the source
                        var current = sources[i];
                        var source  = current.Selection;
                        var key     = new SourceIdenfierWithKey(current.UniqueIdentifier, source.Source);

                        // Create the stream manager
                        var manager = source.Open(optimizer.GetStreams(i));

                        // Attach file size mapper
                        manager.FileBufferSizeChooser = infos[key].GetFileBufferSize;

                        // Create
                        var stream = new ActiveStream(key.UniqueIdentifier, manager, current.Streams, current.RecordingPath);

                        // Remember
                        newStreams.Add(stream);

                        // See if we have to connect an optimizer for restarts
                        if (device.HasConsumerRestriction)
                        {
                            stream.EnableOptimizer(source);
                        }

                        // Try to start
                        stream.Refresh(m_RetestWatchDogInterval);
                    }

                    // Loaded all
                    newStreams.ForEach(stream => Streams.Add(stream.SourceKey, stream));

                    // Generate response
                    try
                    {
                        // Create all
                        return(newStreams.Select(stream => stream.CreateInformation()).ToArray());
                    }
                    finally
                    {
                        // No need to clean up
                        newStreams.Clear();
                    }
                }
                finally
                {
                    // Cleanup
                    newStreams.ForEach(stream => stream.Dispose());
                }
            });
        }
        /// <summary>
        /// Aktiviert eine einzelne Quelle für den <i>Zapping Modus</i>.
        /// </summary>
        /// <param name="source">Die gewünschte Quelle.</param>
        /// <param name="target">Die Netzwerkadresse, an die alle Daten versendet werden sollen.</param>
        protected override void OnSetZappingSource(SourceSelection source, string target)
        {
            // Prepare operation
            Start(device =>
            {
                // The next stream identifier to use
                short nextStreamIdentifier = 0;
                if (Streams.Count > 0)
                {
                    nextStreamIdentifier = Streams.Values.First().Manager.NextStreamIdentifier;
                }

                // Activate the source group - will terminate all active streams
                SelectGroup(device, source);

                // Create optimizer and stream selector
                var optimizer = new StreamSelectionOptimizer();
                var streams   =
                    new StreamSelection
                {
                    AC3Tracks    = { LanguageMode = LanguageModes.All },
                    MP2Tracks    = { LanguageMode = LanguageModes.All },
                    SubTitles    = { LanguageMode = LanguageModes.All },
                    ProgramGuide = true,
                    Videotext    = true,
                };

                // Prepare to optimize
                optimizer.Add(source, streams);

                // See how many we are allowed to start
                optimizer.Optimize();

                // Create
                var stream = new ActiveStream(Guid.Empty, source.Open(optimizer.GetStreams(0)), streams, null);
                try
                {
                    // Configure streaming target
                    stream.Manager.StreamingTarget = target;

                    // Attach next stream identifier
                    stream.Manager.NextStreamIdentifier = nextStreamIdentifier;

                    // See if we have to connect an optimizer for restarts
                    if (device.HasConsumerRestriction)
                    {
                        stream.EnableOptimizer(source);
                    }

                    // Try to start
                    stream.Refresh(m_RetestWatchDogInterval);

                    // Load
                    Streams.Add(stream.SourceKey, stream);
                }
                catch
                {
                    // Cleanup
                    stream.Dispose();

                    // Forward
                    throw;
                }

                // Report state
                return(CreateState(device));
            });
        }