Beispiel #1
0
        /// <summary>
        /// Erstellt eine neue Beschreibung aus dem Aufzeichnungsplan.
        /// </summary>
        /// <param name="plan">Die Planung der Aufzeichnung.</param>
        /// <param name="context">Die aktuelle Analyseumgebung.</param>
        /// <param name="server">Der zugehörige Dienst.</param>
        /// <returns>Die gewünschte Beschreibung.</returns>
        public static PlanCurrent Create(IScheduleInformation plan, PlanContext context, VCRServer server)
        {
            // Attach to the definition
            var definition = (IScheduleDefinition <VCRSchedule>)plan.Definition;
            var job        = context.TryFindJob(definition.UniqueIdentifier);
            var schedule   = (job == null) ? null : job[definition.UniqueIdentifier];
            var source     = (schedule == null) ? null : (schedule.Source ?? job.Source);

            // Create
            var planned =
                new PlanCurrent
            {
                Identifier  = (schedule == null) ? null : ServerRuntime.GetUniqueWebId(job, schedule),
                ProfileName = plan.Resource.Name,
                Duration    = plan.Time.Duration,
                StartTime   = plan.Time.Start,
                IsLate      = plan.StartsLate,
                SizeHint    = string.Empty,
                Name        = definition.Name,
                m_source    = source,
                Files       = _NoFiles,
                Index       = -1,
            };

            // Finish
            planned.Complete(server);

            // Report
            return(planned);
        }
Beispiel #2
0
        /// <summary>
        /// Fordert zum Beenden einer Aufzeichnung oder Aufgabe aus.
        /// </summary>
        /// <param name="item">Alle notwendigen Informationen zur Aufzeichnung.</param>
        /// <param name="planner">Die zugehörige Aufzeichnungsplanung.</param>
        public void Stop(IScheduleInformation item, RecordingPlanner planner)
        {
            // Report
            Debug.WriteLine(string.Format("{0} stop {1}", m_planTime.ToLocalTime(), item.Definition.Name));

            // Readout
            var definition = item.Definition;
            var resource   = item.Resource;

            // Forward
            planner.Stop(definition.UniqueIdentifier);

            // Check mode
            if (definition is ProgramGuideTask)
            {
                m_lastRunGuide[resource.Name] = m_planTime;
            }
            else if (definition is SourceListTask)
            {
                m_lastRunScan[resource.Name] = m_planTime;
            }
            else
            {
                VCRConfiguration.Current.HasRecordedSomething = true;
            }
        }
Beispiel #3
0
        /// <summary>
        /// Fordert zum Starten einer Aufzeichnung oder Aufgabe auf.
        /// </summary>
        /// <param name="item">Die Beschreibung der Aufgabe.</param>
        /// <param name="planner">Die zugehörige Aufzeichnungsplanung.</param>
        /// <param name="context">Zusatzinformationen zur Aufzeichnungsplanung.</param>
        public void Start(IScheduleInformation item, RecordingPlanner planner, PlanContext context)
        {
            // Report
            Debug.WriteLine(string.Format("{0} start{3} on {1}: {2}", m_planTime.ToLocalTime(), item.Resource, item.Definition.Name, item.StartsLate ? " late" : string.Empty));

            // Forward
            planner.Start(item);
        }
        /// <summary>
        /// Erstellt eine neue Beschreibung.
        /// </summary>
        /// <param name="original">Die originalen Informationen.</param>
        public ScheduleInformation( IScheduleInformation original )
        {
            // Validate
            if (original == null)
                throw new ArgumentNullException( nameof( original ) );

            // Remember
            RealTime = original.Time;
            Schedule = original;
        }
        /// <summary>
        /// Erstellt eine neue Beschreibung.
        /// </summary>
        /// <param name="original">Die originalen Informationen.</param>
        public ScheduleInformation(IScheduleInformation original)
        {
            // Validate
            if (original == null)
            {
                throw new ArgumentNullException(nameof(original));
            }

            // Remember
            RealTime = original.Time;
            Schedule = original;
        }
        /// <summary>
        /// Bestätigt den Abschluss einer Operation und die Bereitschaft, die nächste Operation
        /// zu starten.
        /// </summary>
        /// <param name="scheduleIdentifier">Die eindeutige Kennung der Operation.</param>
        /// <param name="isStart">Gesetzt, wenn es sich um einen Startbefehl handelt.</param>
        internal void ConfirmOperation(Guid scheduleIdentifier, bool isStart)
        {
            // Protect and check
            var planner = m_planner;

            if (planner == null)
            {
                return;
            }

            // Make sure that we synchronize with the planning thread
            lock (planner)
                if (m_pendingSchedule == null)
                {
                    // Report
                    VCRServer.Log(LoggingLevel.Errors, "There is no outstanding asynchronous Recording Request for Schedule '{0}'", scheduleIdentifier);
                }
                else if (m_pendingSchedule.Definition.UniqueIdentifier != scheduleIdentifier)
                {
                    // Report
                    VCRServer.Log(LoggingLevel.Errors, "Confirmed asynchronous Recording Request for Schedule '{0}' but waiting for '{1}'", scheduleIdentifier, m_pendingSchedule.Definition.UniqueIdentifier);
                }
                else
                {
                    // Report
                    VCRServer.Log(LoggingLevel.Schedules, "Confirmed asynchronous Recording Request for Schedule '{0}'", scheduleIdentifier);

                    // Check mode
                    if (isStart != m_pendingStart)
                    {
                        VCRServer.Log(LoggingLevel.Errors, "Recording Request confirmed wrong Type of Operation");
                    }

                    // Finish
                    if (m_pendingStart)
                    {
                        planner.Start(m_pendingSchedule);
                    }
                    else
                    {
                        planner.Stop(scheduleIdentifier);
                    }

                    // Reset
                    m_pendingSchedule = null;
                }

            // See what to do next
            BeginNewPlan();
        }
        /// <summary>
        /// Meldet, dass eine Aufzeichnung nun beendet werden kann.
        /// </summary>
        /// <param name="item">Die betroffene Aufzeichnung.</param>
        /// <param name="planner">Die Planungsinstanz.</param>
        void IRecordingPlannerSite.Stop(IScheduleInformation item, RecordingPlanner planner)
        {
            // Report
            VCRServer.Log(LoggingLevel.Schedules, "Done recording '{0}'", item.Definition.Name);

            // Locate the profile - if we don't find it we are in big trouble!
            if (!m_profiles.TryGetValue(item.Resource.Name, out ProfileState profile))
            {
                return;
            }

            // Mark as pending
            m_pendingSchedule = item;
            m_pendingStart    = false;

            // Forward request to profile manager
            m_pendingActions += () => profile.EndRecording(item.Definition.UniqueIdentifier);
        }
Beispiel #8
0
        /// <summary>
        /// Überträgt eine geplante Ausführung.
        /// </summary>
        /// <param name="manager">Die zu erweiternde Schnittstelle.</param>
        /// <param name="schedule">Die Planungsinformationen zur Aufzeichnung.</param>
        /// <returns>Gesetzt, wenn ein Start möglich war.</returns>
        /// <exception cref="NullReferenceException">Es wurde keine Schnittstelle angegeben.</exception>
        /// <exception cref="ArgumentNullException">Es wurde keine Planung angegeben.</exception>
        public static bool Start(this IResourceManager manager, IScheduleInformation schedule)
        {
            // Validate
            if (manager == null)
            {
                throw new NullReferenceException();
            }
            if (schedule == null)
            {
                throw new ArgumentNullException("schedule");
            }

            // Load
            var definition = schedule.Definition;
            var recording  = definition as IRecordingDefinition;

            // Forward
            return(manager.Start(schedule.Resource, (recording == null) ? null : recording.Source, definition.UniqueIdentifier, definition.Name, schedule.Time.Start, schedule.Time.End));
        }
        /// <summary>
        /// Startet eine Aufzeichnung oder eine Aufgabe.
        /// </summary>
        /// <param name="item">Die Beschreibung der Aufgabe.</param>
        /// <returns>Gesetzt, wenn der Vorgang erfolgreich war.</returns>
        public bool Start(IScheduleInformation item)
        {
            // Validate
            if (item is ScheduleInformation)
            {
                VCRServer.LogError(Properties.Resources.BadScheduleInformation, item.Definition.UniqueIdentifier, item.Definition.Name);
            }

            // Try start
            if (!m_manager.Start(item))
            {
                return(false);
            }

            // Remember
            m_started.Add(item.Definition.UniqueIdentifier, new ScheduleInformation(item));

            // Did it
            return(true);
        }
        /// <summary>
        /// Meldet, dass eine Aufzeichnung nun beginnen sollte.
        /// </summary>
        /// <param name="item">Die zu startende Aufzeichnung.</param>
        /// <param name="planner">Die Planungsinstanz.</param>
        /// <param name="context">Zusatzinformationen zur Aufzeichnungsplanung.</param>
        void IRecordingPlannerSite.Start(IScheduleInformation item, RecordingPlanner planner, PlanContext context)
        {
            // We are no longer active - simulate start and do nothing
            if (!m_plannerActive)
            {
                // Make planner believe we did it
                planner.Start(item);

                // Make sure that we wake up after the grace period
                if (PowerManager.IsSuspended && VCRConfiguration.Current.SuppressDelayAfterForcedHibernation)
                {
                    Tools.ExtendedLogging("Hibernation Delay is disabled and can not be enforced");
                }
                else
                {
                    m_timer.SecondsToWait = VCRConfiguration.Current.DelayAfterForcedHibernation.TotalSeconds;
                }

                // Done
                return;
            }

            // Report
            VCRServer.Log(LoggingLevel.Schedules, "Start recording '{0}'", item.Definition.Name);

            // Locate the profile - if we don't find it we are in big trouble!
            ProfileState profile;

            if (!m_profiles.TryGetValue(item.Resource.Name, out profile))
            {
                return;
            }

            // Mark as pending
            m_pendingSchedule = item;
            m_pendingStart    = true;

            // Create the recording
            var recording = VCRRecordingInfo.Create(item, context);

            // Check for EPG
            var guideUpdate = item.Definition as ProgramGuideTask;

            if (guideUpdate != null)
            {
                // Start a new guide collector
                m_pendingActions += ProgramGuideProxy.Create(profile, recording).Start;
            }
            else
            {
                // Check for PSI
                var sourceUpdate = item.Definition as SourceListTask;
                if (sourceUpdate != null)
                {
                    // Start a new update
                    m_pendingActions += SourceScanProxy.Create(profile, recording).Start;
                }
                else
                {
                    // Start a regular recording - profile will decide if to join an existing recording
                    m_pendingActions += () => profile.StartRecording(recording);
                }
            }
        }
        /// <summary>
        /// Aktualisiert ständig die Planung.
        /// </summary>
        private void PlanThread()
        {
            // Always loop
            while (m_planThread != null)
            {
                // See if a new plan is requested
                lock (m_newPlanSync)
                    while (!m_newPlan)
                    {
                        if (m_planThread == null)
                        {
                            return;
                        }
                        else
                        {
                            Monitor.Wait(m_newPlanSync);
                        }
                    }

                // At least we accepted the request
                m_newPlan = false;

                // See if we still have a planner
                var planner = m_planner;
                if (planner == null)
                {
                    break;
                }

                // Just take a look what to do next
                using (PowerManager.StartForbidHibernation())
                    try
                    {
                        // Reset start actions
                        m_pendingActions = null;

                        // Protect planning.
                        lock (planner)
                        {
                            // Report
                            Tools.ExtendedLogging("Woke up for Plan Calculation at {0}", DateTime.Now);

                            // Retest
                            if (m_planThread == null)
                            {
                                break;
                            }

                            // See if we are allowed to take the next step in plan - we schedule only one activity at a time
                            if (m_pendingSchedule == null)
                            {
                                // Release our lock
                                AllowHibernation();

                                // Reset timer
                                if (PowerManager.IsSuspended && VCRConfiguration.Current.SuppressDelayAfterForcedHibernation)
                                {
                                    Tools.ExtendedLogging("VCR.NET is suspending - not updating Timer");
                                }
                                else
                                {
                                    m_timer.SecondsToWait = 0;
                                }

                                // Analyse plan
                                planner.DispatchNextActivity(DateTime.UtcNow);

                                // If we are shutting down better forget anything we did in the previous step - only timer setting matters!
                                if (!m_plannerActive)
                                {
                                    // Reset to initial state
                                    m_pendingSchedule = null;
                                    m_pendingActions  = null;
                                    m_pendingStart    = false;

                                    // And forget all allocations
                                    planner.Reset();

                                    // Just in case allow hibernation again
                                    AllowHibernation();
                                }
                            }
                        }

                        // Run start and stop actions outside the planning lock (to avoid deadlocks) but inside the hibernation protection (to forbid hibernation)
                        var toStart = m_pendingActions;
                        if (toStart != null)
                        {
                            toStart();
                        }
                    }
                    catch (Exception e)
                    {
                        // Report and ignore - we do not expect any error to occur
                        VCRServer.Log(e);
                    }

                // New plan is now available - beside termination this will do nothing at all but briefly aquiring an idle lock
                lock (m_planAvailableSync)
                    Monitor.PulseAll(m_planAvailableSync);
            }
        }
 /// <summary>
 /// Erzeugt eine neue Beschreibung.
 /// </summary>
 /// <param name="definition">Die Daten zur Aufzeichnung oder Aufgabe.</param>
 internal StartActivity(IScheduleInformation definition)
 {
     // Remember
     Recording = definition;
 }
Beispiel #13
0
        /// <summary>
        /// Erstellt eine neue Beschreibung aus dem Aufzeichnungsplan.
        /// </summary>
        /// <param name="plan">Die Planung der Aufzeichnung.</param>
        /// <param name="context">Die aktuelle Analyseumgebung.</param>
        /// <param name="server">Der zugehörige Dienst.</param>
        /// <returns>Die gewünschte Beschreibung.</returns>
        public static PlanCurrent Create( IScheduleInformation plan, PlanContext context, VCRServer server )
        {
            // Attach to the definition
            var definition = (IScheduleDefinition<VCRSchedule>) plan.Definition;
            var job = context.TryFindJob( definition.UniqueIdentifier );
            var schedule = (job == null) ? null : job[definition.UniqueIdentifier];
            var source = (schedule == null) ? null : (schedule.Source ?? job.Source);

            // Create
            var planned =
                new PlanCurrent
                {
                    Identifier = (schedule == null) ? null : ServerRuntime.GetUniqueWebId( job, schedule ),
                    ProfileName = plan.Resource.Name,
                    Duration = plan.Time.Duration,
                    StartTime = plan.Time.Start,
                    IsLate = plan.StartsLate,
                    SizeHint = string.Empty,
                    Name = definition.Name,
                    m_source = source,
                    Files = _NoFiles,
                    Index = -1,
                };

            // Finish
            planned.Complete( server );

            // Report
            return planned;
        }
        /// <summary>
        /// Fordert zum Starten einer Aufzeichnung oder Aufgabe auf.
        /// </summary>
        /// <param name="item">Die Beschreibung der Aufgabe.</param>
        /// <param name="planner">Die zugehörige Aufzeichnungsplanung.</param>
        /// <param name="context">Zusatzinformationen zur Aufzeichnungsplanung.</param>
        public void Start( IScheduleInformation item, RecordingPlanner planner, PlanContext context )
        {
            // Report
            Debug.WriteLine( string.Format( "{0} start{3} on {1}: {2}", m_planTime.ToLocalTime(), item.Resource, item.Definition.Name, item.StartsLate ? " late" : string.Empty ) );

            // Forward
            planner.Start( item );
        }
        /// <summary>
        /// Fordert zum Beenden einer Aufzeichnung oder Aufgabe aus.
        /// </summary>
        /// <param name="item">Alle notwendigen Informationen zur Aufzeichnung.</param>
        /// <param name="planner">Die zugehörige Aufzeichnungsplanung.</param>
        public void Stop( IScheduleInformation item, RecordingPlanner planner )
        {
            // Report
            Debug.WriteLine( string.Format( "{0} stop {1}", m_planTime.ToLocalTime(), item.Definition.Name ) );

            // Readout
            var definition = item.Definition;
            var resource = item.Resource;

            // Forward
            planner.Stop( definition.UniqueIdentifier );

            // Check mode
            if (definition is ProgramGuideTask)
                m_lastRunGuide[resource.Name] = m_planTime;
            else if (definition is SourceListTask)
                m_lastRunScan[resource.Name] = m_planTime;
            else
                VCRConfiguration.Current.HasRecordedSomething = true;
        }
 /// <summary>
 /// Erzeugt eine neue Beschreibung.
 /// </summary>
 /// <param name="definition">Die Daten zur Aufzeichnung oder Aufgabe.</param>
 internal StartActivity( IScheduleInformation definition )
 {
     // Remember
     Recording = definition;
 }
Beispiel #17
0
        /// <summary>
        /// Erstellt einen neuen Eintrag.
        /// </summary>
        /// <param name="schedule">Die zugehörige Beschreibung der geplanten Aktivität.</param>
        /// <param name="context">Die Abbildung auf die Aufträge.</param>
        /// <param name="profiles">Die Verwaltung der Geräteprofile.</param>
        /// <returns>Die angeforderte Repräsentation.</returns>
        public static PlanActivity Create(IScheduleInformation schedule, PlanContext context, ProfileStateCollection profiles)
        {
            // Request context information
            var definition   = schedule.Definition;
            var runningInfo  = context.GetRunState(definition.UniqueIdentifier);
            var isAllocation = definition is IResourceAllocationInformation;

            // Maybe it's an resource allocation
            if (isAllocation)
            {
                if (runningInfo != null)
                {
                    definition = runningInfo.Schedule.Definition;
                }
                else
                {
                    return(null);
                }
            }

            // Create initial entry
            var time     = schedule.Time;
            var start    = time.Start;
            var end      = time.End;
            var activity =
                new PlanActivity
            {
                IsHidden = (schedule.Resource == null),
                IsLate   = schedule.StartsLate,
            };

            // May need some correction
            if (runningInfo != null)
            {
                if (end == runningInfo.Schedule.Time.End)
                {
                    // Only report the allocation itself
                    if (!isAllocation)
                    {
                        return(null);
                    }

                    // Reload the real start and times - just in case someone manipulated
                    start = runningInfo.Schedule.Time.Start;
                    end   = runningInfo.RealTime.End;

                    // Never report as late - actually since we have some spin up time most of the time the recording is late
                    activity.IsLate = false;
                }
            }

            // Get the beautified range
            start = PlanCurrent.RoundToSecond(start);
            end   = PlanCurrent.RoundToSecond(end);

            // Set times
            activity.Duration  = end - start;
            activity.StartTime = start;

            // Set name
            if (definition != null)
            {
                activity.FullName = definition.Name;
            }

            // Set resource
            var resource = schedule.Resource;

            if (resource != null)
            {
                activity.Device = resource.Name;
            }

            // Schedule to process
            VCRSchedule vcrSchedule = null;
            VCRJob      vcrJob      = null;

            // Analyse definition
            var scheduleDefinition = definition as IScheduleDefinition <VCRSchedule>;

            if (scheduleDefinition != null)
            {
                // Regular plan
                vcrSchedule = scheduleDefinition.Context;
                vcrJob      = context.TryFindJob(vcrSchedule);
            }

            // Process if we found one
            if (vcrSchedule != null)
            {
                // See if we have a job
                if (vcrJob != null)
                {
                    activity.LegacyReference = ServerRuntime.GetUniqueWebId(vcrJob, vcrSchedule);
                }

                // Find the source to use - stream selection is always bound to the context of the source
                var streams = vcrSchedule.Streams;
                var source  = vcrSchedule.Source;
                if (source == null)
                {
                    if (vcrJob != null)
                    {
                        // Try job
                        source = vcrJob.Source;

                        // Adjust stream flags to use
                        if (source == null)
                        {
                            streams = null;
                        }
                        else
                        {
                            streams = vcrJob.Streams;
                        }
                    }
                }

                // Copy station name
                if (source != null)
                {
                    // Remember
                    activity.Source  = SourceIdentifier.ToString(source.Source).Replace(" ", "");
                    activity.Station = source.DisplayName;

                    // Load the profile
                    var profile = profiles[activity.GuideEntryDevice = source.ProfileName];
                    if (profile != null)
                    {
                        activity.HasGuideEntry = profile.ProgramGuide.HasEntry(source.Source, activity.StartTime, activity.StartTime + activity.Duration);
                    }
                }

                // Apply special settings
                activity.CurrentProgramGuide = streams.GetUsesProgramGuide();
                activity.AllLanguages        = streams.GetUsesAllAudio();
                activity.SubTitles           = streams.GetUsesSubtitles();
                activity.VideoText           = streams.GetUsesVideotext();
                activity.Dolby = streams.GetUsesDolbyAudio();

                // Check for exception rule on the day
                var exception = vcrSchedule.FindException(time.End);
                if (exception != null)
                {
                    activity.ExceptionRule = PlanException.Create(exception, vcrSchedule);
                }

                // May want to add end time checks
                if (!isAllocation)
                {
                    if (!activity.IsLate)
                    {
                        if (!activity.IsHidden)
                        {
                            if ((exception == null) || exception.IsEmpty)
                            {
                                activity.EndTimeCouldBeWrong = activity.CheckEndTime(vcrSchedule.FirstStart);
                            }
                        }
                    }
                }
            }
            else if (definition is ProgramGuideTask)
            {
                activity.Station = VCRJob.ProgramGuideName;
            }
            else if (definition is SourceListTask)
            {
                activity.Station = VCRJob.SourceScanName;
            }

            // Report
            return(activity);
        }
        /// <summary>
        /// Startet eine Aufzeichnung oder eine Aufgabe.
        /// </summary>
        /// <param name="item">Die Beschreibung der Aufgabe.</param>
        /// <returns>Gesetzt, wenn der Vorgang erfolgreich war.</returns>
        public bool Start( IScheduleInformation item )
        {
            // Validate
            if (item is ScheduleInformation)
                VCRServer.LogError( Properties.Resources.BadScheduleInformation, item.Definition.UniqueIdentifier, item.Definition.Name );

            // Try start
            if (!m_manager.Start( item ))
                return false;

            // Remember
            m_started.Add( item.Definition.UniqueIdentifier, new ScheduleInformation( item ) );

            // Did it
            return true;
        }
        /// <summary>
        /// Überträgt eine geplante Ausführung.
        /// </summary>
        /// <param name="manager">Die zu erweiternde Schnittstelle.</param>
        /// <param name="schedule">Die Planungsinformationen zur Aufzeichnung.</param>
        /// <returns>Gesetzt, wenn ein Start möglich war.</returns>
        /// <exception cref="NullReferenceException">Es wurde keine Schnittstelle angegeben.</exception>
        /// <exception cref="ArgumentNullException">Es wurde keine Planung angegeben.</exception>
        public static bool Start( this IResourceManager manager, IScheduleInformation schedule )
        {
            // Validate
            if (manager == null)
                throw new NullReferenceException();
            if (schedule == null)
                throw new ArgumentNullException( "schedule" );

            // Load
            var definition = schedule.Definition;
            var recording = definition as IRecordingDefinition;

            // Forward
            return manager.Start( schedule.Resource, (recording == null) ? null : recording.Source, definition.UniqueIdentifier, definition.Name, schedule.Time.Start, schedule.Time.End );
        }
Beispiel #20
0
        /// <summary>
        /// Erstellt einen neuen Eintrag.
        /// </summary>
        /// <param name="planItem">Die zugehörige Beschreibung der geplanten Aktivität.</param>
        /// <param name="context">Die Abbildung auf die Aufträge.</param>
        /// <returns>Die angeforderte Repräsentation.</returns>
        public static VCRRecordingInfo Create(IScheduleInformation planItem, PlanContext context)
        {
            // Validate
            if (planItem == null)
            {
                throw new ArgumentNullException(nameof(planItem));
            }
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            // Check type
            var definition = planItem.Definition as IScheduleDefinition <VCRSchedule>;

            if (definition == null)
            {
                // Check for program guide collector
                var guideCollection = planItem.Definition as ProgramGuideTask;
                if (guideCollection != null)
                {
                    return
                        new VCRRecordingInfo
                        {
                            Source = new SourceSelection {
                                ProfileName = planItem.Resource.Name, DisplayName = VCRJob.ProgramGuideName
                            },
                            FileName         = Path.Combine(guideCollection.CollectorDirectory.FullName, Guid.NewGuid().ToString("N") + ".epg"),
                            ScheduleUniqueID = guideCollection.UniqueIdentifier,
                            IsHidden         = planItem.Resource == null,
                            StartsLate       = planItem.StartsLate,
                            StartsAt         = planItem.Time.Start,
                            Name             = guideCollection.Name,
                            EndsAt           = planItem.Time.End,
                        }
                }
                ;

                // Check for source list update
                var sourceUpdater = planItem.Definition as SourceListTask;
                if (sourceUpdater != null)
                {
                    return
                        new VCRRecordingInfo
                        {
                            Source = new SourceSelection {
                                ProfileName = planItem.Resource.Name, DisplayName = VCRJob.SourceScanName
                            },
                            FileName         = Path.Combine(sourceUpdater.CollectorDirectory.FullName, Guid.NewGuid().ToString("N") + ".psi"),
                            ScheduleUniqueID = sourceUpdater.UniqueIdentifier,
                            IsHidden         = planItem.Resource == null,
                            StartsLate       = planItem.StartsLate,
                            StartsAt         = planItem.Time.Start,
                            EndsAt           = planItem.Time.End,
                            Name             = sourceUpdater.Name,
                        }
                }
                ;

                // None
                return(null);
            }

            // Attach to the schedule and its job - using the context and the map is the easiest way although there may be better alternatives
            var job      = context.TryFindJob(definition.UniqueIdentifier);
            var schedule = definition.Context;

            // Find the source
            var source = schedule.Source ?? job.Source;

            if (source != null)
            {
                // Create a clone
                source = new SourceSelection {
                    DisplayName = source.DisplayName, SelectionKey = source.SelectionKey
                };

                // Update the name of the profile
                var resource = planItem.Resource;
                if (resource != null)
                {
                    source.ProfileName = resource.Name;
                }
            }

            // Create the description of this recording
            var recording =
                new VCRRecordingInfo
            {
                Streams          = (schedule.Source == null) ? job.Streams : schedule.Streams,
                ScheduleUniqueID = schedule.UniqueID,
                IsHidden         = planItem.Resource == null,
                StartsLate       = planItem.StartsLate,
                StartsAt         = planItem.Time.Start,
                EndsAt           = planItem.Time.End,
                JobUniqueID      = job.UniqueID,
                RelatedSchedule  = schedule,
                FileName         = job.Directory,
                Name             = definition.Name,
                RelatedJob       = job,
                Source           = source,
            };

            // May want to adjust start time if job is active
            var runningInfo = context.GetRunState(definition.UniqueIdentifier);

            if (runningInfo != null)
            {
                if (runningInfo.Schedule.Time.End == recording.EndsAt)
                {
                    // Assume we never start late - we are running
                    recording.StartsLate = false;

                    // If we started prior to this plan report the time we really started
                    if (planItem.Time.Start > runningInfo.Schedule.Time.Start)
                    {
                        recording.StartsAt = runningInfo.Schedule.Time.Start;
                    }
                }
            }

            // Finish
            recording.LoadDefaults();

            // Report
            return(recording);
        }