/// <summary> /// Ermittelt die Geräteabstraktion zu einer Quellinformation. /// </summary> /// <param name="selection">Die betroffene Quellinformation.</param> /// <returns>Die zugehörige Geräteabstraktion.</returns> /// <exception cref="ArgumentNullException">Es wurde keine Quellinformation angegeben.</exception> public static Hardware GetHardware(this SourceSelection selection) { // Validate if (null == selection) { throw new ArgumentNullException("selection"); } // Forward using (HardwareManager.Open()) return(HardwareManager.OpenHardware(selection.ProfileName)); }
/// <summary> /// Erzeugt einen Aufzeichnungskontext für eine Quelle. /// </summary> /// <param name="selection">Die Informationen zur Quelle.</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 SourceSelection selection, StreamSelection streams) { // Validate if (selection == null) { throw new ArgumentNullException("selection"); } else { return(selection.Source.Open(selection.GetHardware(), selection.GetLeafProfile(), streams)); } }
/// <summary> /// Aktiviert eine Quellinformation. /// </summary> /// <param name="selection">Die gewünschte Quellinformation.</param> /// <exception cref="ArgumentNullException">Es wurden keine Informationen zur /// Quelle angegeben.</exception> public static void SelectGroup(this SourceSelection selection) { // Validate if (null == selection) { throw new ArgumentNullException("selection"); } // Forward using (HardwareManager.Open()) selection.SelectGroup(selection.GetHardware()); }
/// <summary> /// Wählt eine Quellgruppe an. /// </summary> /// <param name="source">Eine der Quellen der Gruppe.</param> /// <returns>Die Liste aller Quellen der Gruppe.</returns> public CancellableTask<SourceSelection[]> Activate( SourceSelection source ) { // Map to indicated device var localSource = m_profile.FindSource( source.Source ).FirstOrDefault(); if (localSource == null) throw new ArgumentException( "bad source", "source" ); // Create task return CancellableTask<SourceSelection[]>.Run( cancel => { // Check for cancel if (cancel.IsCancellationRequested) return _NoSources; // Start the hardware on first call - this may take some time var device = localSource.GetHardware(); // Check for cancel if (cancel.IsCancellationRequested) return _NoSources; // Select the group - again this may last a bit localSource.SelectGroup( device ); // Check for cancel if (cancel.IsCancellationRequested) return _NoSources; // Validate var groupReader = device.GroupReader; if (groupReader == null) return _NoSources; if (!groupReader.CancellableWait( cancel )) return _NoSources; // Load the map var groupInformation = groupReader.Result; if (groupInformation == null) return _NoSources; // Use profile to map to full source information return groupInformation .Sources .Select( s => m_profile.FindSource( s ).FirstOrDefault() ) .Where( s => s != null ) .ToArray(); } ); }
/// <summary> /// Ermittelt das Geräteprofile mit der Senderliste für eine Quellinformation. /// </summary> /// <param name="selection">Die betroffene Quellinformation.</param> /// <returns>Das zugehörige Profil mit der Senderliste, das durchaus von <see cref="GetProfile"/> /// abweichen kann.</returns> /// <exception cref="ArgumentNullException">Es wurde keine Quellinformation angegeben.</exception> public static Profile GetLeafProfile(this SourceSelection selection) { // Forward Profile profile = selection.GetProfile(); // Check result if (null == profile) { return(null); } else { return(profile.LeafProfile); } }
/// <summary> /// Aktiviert eine Quellinformation auf einer bestimmten Hardware. /// </summary> /// <param name="selection">Die gewünschte Quellinformation.</param> /// <param name="hardware">Die Hardware, die für den Empfang zu verwenden ist.</param> /// <exception cref="ArgumentNullException">Es wurden keine Informationen zur /// Quelle angegeben.</exception> public static void SelectGroup(this SourceSelection selection, Hardware hardware) { // Validate if (null == selection) { throw new ArgumentNullException("selection"); } // Nothing to do if (null == hardware) { return; } // Forward hardware.SelectGroup(selection); }
/// <summary> /// Stellt sicher, dass eine Aufzeichnung gestartet werden kann. /// </summary> /// <param name="source">Der gewünschte Sender.</param> /// <param name="tx">Die aktuelle Änderungsumgebung.</param> /// <returns>Gesetzt, wenn die Aufzeichnung möglich war.</returns> private Device EnsureRecordingFeed( SourceSelection source, FeedTransaction tx ) { // Make sure we can receive it var device = EnsurePrimaryFeed( source, tx ); if (device != null) return device; // See if there is a primary var primary = PrimaryView; if (primary == null) return null; // Switch off primary tx.DisablePrimaryView( primary ); // Try again - may fail return EnsurePrimaryFeed( source, tx ); }
/// <summary> /// Ermittelt das Geräteprofile für eine Quellinformation. /// </summary> /// <param name="selection">Die betroffene Quellinformation.</param> /// <returns>Das zugehörige Profil.</returns> /// <exception cref="ArgumentNullException">Es wurde keine Quellinformation angegeben.</exception> public static Profile GetProfile(this SourceSelection selection) { // Validate if (null == selection) { throw new ArgumentNullException("selection"); } // Forward if (string.IsNullOrEmpty(selection.ProfileName)) { return(null); } else { return(ProfileManager.FindProfile(selection.ProfileName)); } }
/// <summary> /// Prüft, ob zwei Quellauswahlen die selbe Quelle bezeichnen. /// </summary> /// <param name="other">Die andere Quelle.</param> /// <param name="transponderOnly">Gesetzt, wenn die eigentliche Quelle bei der Prüfung /// nicht berücksichtigt werden soll</param> /// <returns>Gesetzt, wenn beide Auswahlen die selbe Quelle bezeichnen.</returns> public bool CompareTo(SourceSelection other, bool transponderOnly) { // Not possible if (null == other) { return(false); } // Profile if (0 != string.Compare(ProfileName, other.ProfileName, true)) { return(false); } // Source if (!transponderOnly) { if (!Equals(Source, other.Source)) { return(false); } } // Use semantic compare if (!Equals(Location, other.Location)) { return(false); } // Group pre-test if ((null == Group) || (null == other.Group)) { return(false); } // Group tame test - more or less frequency only return(Group.CompareTo(other.Group, true)); }
/// <summary> /// Versucht einen Sender für die primäre Anzeige zu aktivieren. /// </summary> /// <param name="source">Der gewünschte Sender.</param> /// <param name="tx">Die aktuelle Änderungsumgebung.</param> /// <returns>Gesetzt, wenn die Aktivierung erfolgreich war.</returns> private Device EnsurePrimaryFeed( SourceSelection source, FeedTransaction tx ) { // Make sure we can receive it var device = EnsureFeed( source ); if (device != null) return device; // See if there is any device we can free var availableDevice = m_devices .Where( cancidate => cancidate.ReusePossible ) .Aggregate( default( Device ), ( best, test ) => ((best != null) && (best.SecondaryFeeds.Count() <= test.SecondaryFeeds.Count())) ? best : test ); // None if (availableDevice == null) return null; // Stop all secondaries foreach (var secondaryFeed in availableDevice.SecondaryFeeds) tx.DisableSecondaryView( secondaryFeed ); // Run test again - can not fail return EnsureFeed( source ); }
/// <summary> /// Prüft, ob zwei Quellauswahlen die selbe Quelle bezeichnen. /// </summary> /// <param name="other">Die andere Quelle.</param> /// <returns>Gesetzt, wenn beide Auswahlen die selbe Quelle bezeichnen.</returns> public bool CompareTo(SourceSelection other) { // Forward return(CompareTo(other, false)); }
/// <summary> /// Beginnt mit dem Auslesen der Quelldaten. /// </summary> /// <param name="source">Alle Informationen zur Quelle.</param> /// <returns>Die Hintergrundaufgabe zum Auslesen der Quelldaten.</returns> public static CancellableTask <SourceInformation> GetSourceInformationAsync(this SourceSelection source) { return(source.GetHardware().GetSourceInformationAsync(source.Source, source.GetProfile())); }
/// <summary> /// Stellt sicher, dass ein Sender empfangen wird. /// </summary> /// <param name="source">Der gewünschte Sender.</param> /// <returns>Gesetzt, wenn ein Empfang möglich ist.</returns> private Device EnsureFeed( SourceSelection source ) { // First see if there is a device handling the source var feed = FindFeed( source ); if (feed != null) return feed.Device; // See if there is any device activated but idle and then reuse it - better than starting a brand new device foreach (var device in m_devices) if (device.IsIdle) { // Tune it device.EnsureFeed( source ); // Report success return device; } // See if there is any device not yet activated foreach (var device in m_devices) if (!device.IsAllocated) { // Tune it device.EnsureFeed( source ); // Report success return device; } // All devices are in use return null; }
/// <summary> /// Ermittelt einen Sender. /// </summary> /// <param name="source">Die zugehörige Quelle.</param> /// <returns>Der Sender, sofern dieser verfügbar ist.</returns> public Feed FindFeed( SourceSelection source ) { return Feeds.SingleOrDefault( feed => ReferenceEquals( feed.Source, source ) ); }
/// <summary> /// Ermittelt die aktuelle Konfiguration einer Quelle. /// </summary> /// <param name="source">Die gewünschte Quelle.</param> /// <returns>Die aktuelle Auswahl oder <i>null</i>.</returns> public static SourceSelection FindSource( SourceSelection source ) { // Never if (source == null) return null; if (source.Source == null) return null; // Find the source return FindSource( source.ProfileName, source.Source ); }
/// <summary> /// Ermittelt den eindeutigen Namen einer Quelle. /// </summary> /// <param name="source">Die gewünschte Quelle.</param> /// <returns>Der eindeutige Name oder <i>null</i>, wenn die Quelle nicht /// bekannt ist..</returns> public static string GetUniqueName( SourceSelection source ) { // Map to current var active = FindSource( source ); if (active == null) return null; // Find the name string name; if (!CurrentState.UniqueNameBySelectionMap.TryGetValue( active.SelectionKey, out name )) return null; // Report it return name; }
/// <summary> /// Stellt sicher, dass für diesen Auftrag ein Geräteprprofil ausgewählt ist. /// </summary> internal void SetProfile() { // No need if (!string.IsNullOrEmpty( Source?.ProfileName )) return; // Attach to the default profile var defaultProfile = VCRProfiles.DefaultProfile; if (defaultProfile == null) return; // Process if (Source == null) Source = new SourceSelection { ProfileName = defaultProfile.Name }; else Source.ProfileName = defaultProfile.Name; }
/// <summary> /// Stellt sicher, dass für diesen Auftrag ein Geräteprprofil ausgewählt ist. /// </summary> /// <param name="defaultProfileName">Der Name des bevorzugten Geräteprofils.</param> internal void SetProfile( string defaultProfileName ) { // No source at all if (Source == null) Source = new SourceSelection { ProfileName = defaultProfileName }; else if (string.IsNullOrEmpty( Source.ProfileName )) Source.ProfileName = defaultProfileName; }
/// <summary> /// Prüft, ob zwei Quellauswahlen die selbe Quelle bezeichnen. /// </summary> /// <param name="other">Die andere Quelle.</param> /// <returns>Gesetzt, wenn beide Auswahlen die selbe Quelle bezeichnen.</returns> public bool CompareTo( SourceSelection other ) { // Forward return CompareTo( other, false ); }
/// <summary> /// Zeigt den Zustand des <i>Card Servers</i> an. /// </summary> /// <param name="result">Gesamtinformationen zum Zustand.</param> private void ProcessState( object result ) { // Convert ServerInformation info = (ServerInformation) result; // Reconstruct the selection SourceSelection selection = new SourceSelection { SelectionKey = info.Selection }; // Fill txLocation.Text = ((null == selection) || (null == selection.Location)) ? null : selection.Location.ToString(); txGroup.Text = ((null == selection) || (null == selection.Group)) ? null : selection.Group.ToString(); txProfile.Text = (null == selection) ? null : selection.ProfileName; txEPGItems.Text = info.CurrentProgramGuideItems.ToString(); epgProgress.Visible = info.ProgramGuideProgress.HasValue; txPSISources.Text = info.UpdateSourceCount.ToString(); psiProgress.Visible = info.UpdateProgress.HasValue; // Set error mode txLocation.BackColor = info.HasGroupInformation ? txProfile.BackColor : Color.Yellow; txGroup.BackColor = txLocation.BackColor; // Show pnlState.Visible = true; // Set the progress values if (epgProgress.Visible) epgProgress.Value = Math.Max( 0, Math.Min( epgProgress.Maximum, (int) (info.ProgramGuideProgress.Value * epgProgress.Maximum) ) ); if (psiProgress.Visible) psiProgress.Value = Math.Max( 0, Math.Min( psiProgress.Maximum, (int) (info.UpdateProgress.Value * psiProgress.Maximum) ) ); // Reset service list selServices.Items.Clear(); // Fill service list if (null != info.Services) { // Helper List<string> services = new List<string>(); // Fill foreach (ServiceInformation service in info.Services) services.Add( string.Format( "{0} ({1})", service.UniqueName, service.Service ) ); // Sort and use selServices.Items.AddRange( services.OrderBy( s => int.Parse( s.Split( ',' )[0] ) ).ToArray() ); } // Finish service list selServices.Enabled = (selServices.Items.Count > 0); // Select first if (selServices.Enabled) selServices.SelectedIndex = 0; // Load streams LoadStreams( info.Streams, selection ); }
/// <summary> /// Füllt die Informationen über die aktiven Quellen. /// </summary> /// <param name="streams">Die Liste der aktiven Quellen.</param> /// <param name="selection">Die aktive Quellgruppe.</param> private void LoadStreams( IEnumerable<StreamInformation> streams, SourceSelection selection ) { // Reset lstStreams.Items.Clear(); // Find the profile Profile profile = (null == selection) ? null : selection.GetProfile(); // Process all foreach (StreamInformation stream in streams) { // Create the item ListViewItem item = lstStreams.Items.Add( stream.Source.ToString() ); // No profile if (null != profile) foreach (SourceSelection match in profile.FindSource( stream.Source )) { // Check for location match if (null != selection.Location) if (!Equals( selection.Location, match.Location )) continue; // Check for group match if (null != selection.Group) if (!Equals( selection.Group, match.Group )) continue; // Update name item.Text = match.DisplayName; // Skip the rest break; } // Add additional data item.SubItems.Add( (null == stream.Streams) ? null : string.Join( ", ", stream.Streams.MP2Tracks.Languages.ToArray() ) ); item.SubItems.Add( (null == stream.Streams) ? null : string.Join( ", ", stream.Streams.AC3Tracks.Languages.ToArray() ) ); item.SubItems.Add( (null == stream.Streams) ? null : string.Join( ", ", stream.Streams.SubTitles.Languages.ToArray() ) ); item.SubItems.Add( (null == stream.Streams) ? null : (stream.Streams.Videotext ? "x" : null) ); item.SubItems.Add( (null == stream.Streams) ? null : (stream.Streams.ProgramGuide ? "x" : null) ); item.SubItems.Add( string.Format( "{0} ({1})", stream.BytesReceived, stream.CurrentAudioVideoBytes ) ); item.SubItems.Add( stream.IsDecrypting ? "x" : null ); item.SubItems.Add( stream.StreamTarget ); item.SubItems.Add( stream.TargetPath ); item.SubItems.Add( stream.ConsumerCount.ToString() ); item.SubItems.Add( string.Join( ", ", stream.AllFiles.Select( f => string.Format( "{0} ({1})", f.FilePath, f.VideoType ) ).ToArray() ) ); } // Set columns foreach (ColumnHeader column in lstStreams.Columns) { // First column.AutoResize( ColumnHeaderAutoResizeStyle.ColumnContent ); // Remember int w = column.Width; // Second column.AutoResize( ColumnHeaderAutoResizeStyle.HeaderSize ); // Both column.Width = Math.Max( column.Width, w ); } }
/// <summary> /// Stellt den Empfang auf die Quellgruppe der bezeichneten Quelle ein. /// </summary> /// <param name="source">Die Informationen zur gewünschten Quelle.</param> public void SelectGroup(SourceSelection source) { // Forward SelectGroup((source == null) ? null : source.Location, (source == null) ? null : source.Group); }
/// <summary> /// Prüft eine Quelle und bringt sie auf den aktuellen Stand. /// </summary> /// <param name="source">Die gewünschte Quelle.</param> /// <returns>Die überprüfte Quelle.</returns> private SourceSelection FindSource( SourceSelection source ) { // Forward return ProfileManager.FindProfile( source.ProfileName ).FindSource( source.Source ).Single(); }
/// <summary> /// Erzeugt eine Hintergrundaufgabe zum Ermitteln von Quelldaten. /// </summary> /// <param name="source">Die gewünschte Quelle.</param> /// <returns>Eine neue passende Hintergrundaufgabe.</returns> public CancellableTask<SourceInformation> GetSourceInformationAsync( SourceSelection source ) { // Make sure this device can map the source var localSource = m_profile.FindSource( source.Source ).FirstOrDefault(); if (localSource == null) throw new ArgumentException( "bad source", "source" ); else return SourceInformationReader.GetSourceInformationAsync( localSource ); }
/// <summary> /// Erstellt eine neue Beschreibung. /// </summary> /// <param name="source">Die zugehörige Quelle.</param> /// <param name="device">Das zugehörige Gerät.</param> public Feed( SourceSelection source, Device device ) { Device = device; Source = source; }
/// <summary> /// Registriert diese Aufzeichnung in einer Planungsinstanz. /// </summary> /// <param name="scheduler">Die zu verwendende Planungsinstanz.</param> /// <param name="job">Der zugehörige Auftrag.</param> /// <param name="devices">Die Liste der Geräte, auf denen die Aufzeichnung ausgeführt werden darf.</param> /// <param name="findSource">Dient zum Prüfen einer Quelle.</param> /// <param name="disabled">Alle deaktivierten Aufträge.</param> /// <param name="context">Die aktuelle Planungsumgebung.</param> /// <exception cref="ArgumentNullException">Es wurden nicht alle Parameter angegeben.</exception> public void AddToScheduler( RecordingScheduler scheduler, VCRJob job, IScheduleResource[] devices, Func<SourceSelection, SourceSelection> findSource, Func<Guid, bool> disabled, PlanContext context ) { // Validate if (scheduler == null) throw new ArgumentNullException( nameof( scheduler ) ); if (job == null) throw new ArgumentNullException( nameof( job ) ); if (findSource == null) throw new ArgumentNullException( nameof( findSource ) ); // Let VCR.NET choose a profile to do the work if (job.AutomaticResourceSelection) devices = null; // Create the source selection var persistedSource = Source ?? job.Source; var selection = findSource( persistedSource ); // Station no longer available if (selection == null) if (persistedSource != null) selection = new SourceSelection { DisplayName = persistedSource.DisplayName, ProfileName = persistedSource.ProfileName, Location = persistedSource.Location, Group = persistedSource.Group, Source = new Station { TransportStream = persistedSource.Source?.TransportStream ?? 0, Network = persistedSource.Source?.Network ?? 0, Service = persistedSource.Source?.Service ?? 0, Name = persistedSource.DisplayName, }, }; // See if we are allowed to process var identifier = UniqueID.Value; if (disabled != null) if (disabled( identifier )) return; // Load all var name = string.IsNullOrEmpty( Name ) ? job.Name : $"{job.Name} ({Name})"; var source = ProfileScheduleResource.CreateSource( selection ); var duration = TimeSpan.FromMinutes( Duration ); var noStartBefore = NoStartBefore; var start = FirstStart; // Check repetition var repeat = CreateRepeatPattern(); if (repeat == null) { // Only if not being recorded if (!noStartBefore.HasValue) scheduler.Add( RecordingDefinition.Create( this, name, identifier, devices, source, start, duration ) ); } else { // See if we have to adjust the start day if (noStartBefore.HasValue) { // Attach to the limit - actually we shift it a bit further assuming that we did have no large exception towards the past and the duration is moderate var startAfter = noStartBefore.Value.AddHours( 12 ); var startAfterDay = startAfter.ToLocalTime().Date; // Localize the start time var startTime = start.ToLocalTime().TimeOfDay; // First adjust start = (startAfterDay + startTime).ToUniversalTime(); // One more day if (start < startAfter) start = (startAfterDay.AddDays( 1 ) + startTime).ToUniversalTime(); } // Read the rest var exceptions = Exceptions.Select( e => e.ToPlanException( duration ) ).ToArray(); var endDay = LastDay.GetValueOrDefault( MaxMovableDay ); // A bit more complex if (start.Date <= endDay.Date) scheduler.Add( RecordingDefinition.Create( this, name, identifier, devices, source, start, duration, endDay, repeat ), exceptions ); } }
/// <summary> /// Prüft, ob zwei Quellauswahlen die selbe Quelle bezeichnen. /// </summary> /// <param name="other">Die andere Quelle.</param> /// <param name="transponderOnly">Gesetzt, wenn die eigentliche Quelle bei der Prüfung /// nicht berücksichtigt werden soll</param> /// <returns>Gesetzt, wenn beide Auswahlen die selbe Quelle bezeichnen.</returns> public bool CompareTo( SourceSelection other, bool transponderOnly ) { // Not possible if (null == other) return false; // Profile if (0 != string.Compare( ProfileName, other.ProfileName, true )) return false; // Source if (!transponderOnly) if (!Equals( Source, other.Source )) return false; // Use semantic compare if (!Equals( Location, other.Location )) return false; // Group pre-test if ((null == Group) || (null == other.Group)) return false; // Group tame test - more or less frequency only return Group.CompareTo( other.Group, true ); }