/// <summary> /// Aktiviert eine einzelne Quelle für den <i>Zapping Modus</i>. /// </summary> /// <param name="selectionKey">Die gewünschte Quelle.</param> /// <param name="target">Die Netzwerkadresse, an die alle Daten versendet werden sollen.</param> /// <returns>Steuereinheit für diesen Aufruf.</returns> /// <exception cref="ArgumentNullException">Ein Parameter wurde nicht angegeben.</exception> public IAsyncResult <ServerInformation> BeginSetZappingSource(string selectionKey, string target) { // Validate if (string.IsNullOrEmpty(selectionKey)) { throw new ArgumentNullException("selectionKey"); } if (string.IsNullOrEmpty(target)) { throw new ArgumentNullException("target"); } // Create the selection var source = new SourceSelection { SelectionKey = selectionKey }; // Check for profile match if (string.IsNullOrEmpty(m_Profile) || !string.Equals(m_Profile, source.ProfileName, StringComparison.InvariantCultureIgnoreCase)) { CardServerException.Throw(new ProfileMismatchFault(m_Profile, source.ProfileName)); } // Start action return((IAsyncResult <ServerInformation>)Start <ServerInformation>(() => { OnSetZappingSource(source, target); })); }
/// <summary> /// Aktiviert die Nutzung eines DVB.NET Geräteprofils. /// </summary> /// <param name="profileName">Der Name des Geräteprofils.</param> /// <param name="reset">Gesetzt, wenn das zugehörige Windows Gerät neu initialisiert werden soll.</param> /// <param name="disablePCRFromH264">Wird gesetzt um zu verhindern, dass die Systemzeit (PCR) aus /// dem H.264 Bildsignal ermittelt wird, da dieser Mechanismus hochgradig unsicher ist.</param> /// <param name="disablePCRFromMPEG2">Wird gesetzt um zu verhindern, dass die Systemzeit (PCR) aus /// dem MPEG2 Bildsignal ermittelt wird, da dieser Mechanismus hochgradig unsicher ist.</param> /// <exception cref="CardServerException">Es existiert kein Geräteprofil mit dem /// angegebenen Namen.</exception> protected override void OnAttachProfile(string profileName, bool reset, bool disablePCRFromH264, bool disablePCRFromMPEG2) { // Overwrite flags Manager.DisablePCRForSDTV = disablePCRFromMPEG2; Manager.DisablePCRForHDTV = disablePCRFromH264; // Load the profile Profile = ProfileManager.FindProfile(profileName); // Validate if (Profile == null) { CardServerException.Throw(new NoProfileFault(profileName)); } // Load special overwrites ReadRecordingParameter(RecordingSettings.DecryptWatchDogIntervalName, ref m_DecryptionWatchDogInterval, TimeSpan.MaxValue); ReadRecordingParameter(RecordingSettings.PSIWatchDogIntervalName, ref m_RetestWatchDogInterval, m_RetestWatchDogInterval); ReadRecordingParameter(RecordingSettings.StreamWatchDogIntervalName, ref m_GroupWatchDogInterval, TimeSpan.MaxValue); // Create the thread m_Thread = new Thread(WorkerThread) { Name = "DVB.NET Card Server Worker Thread", Priority = ThreadPriority.AboveNormal }; m_Thread.SetApartmentState(ApartmentState.STA); m_Thread.Start(reset); // Create the idle thread m_IdleThread = new Thread(Idle) { Name = "DVB.NET Card Server Idle Thread" }; m_IdleThread.Start(); }
/// <summary> /// Beendet die Aktualisierung der Programmzeitschrift. /// </summary> protected override void OnEndEPGCollection() { // Process Start(device => { // Check mode if (!EPGProgress.HasValue) { CardServerException.Throw(new EPGNotActiveFault()); } // Disable all consumers device.SelectGroup(null, null); // Preserve some memory m_EPGPending.Clear(); m_EPGSources.Clear(); m_EPGGroups.Clear(); // Terminate EPGProgress = null; // Process result - will reset the list return(CreateGuideItems()); }); }
/// <summary> /// Beendet einen Sendersuchlauf auf dem aktuellen Geräteprofil. /// </summary> /// <param name="updateProfile">Gesetzt, wenn das Geräteprofil aktualisiert werden soll.</param> protected override void OnEndScan(bool?updateProfile) { // Process Start(device => { // Check mode if (m_ScanProgress < 0) { CardServerException.Throw(new SourceUpdateNotActiveFault()); } if (null != m_ScanAbort) { CardServerException.Throw(new SourceUpdateNotActiveFault()); } // Install action m_ScanAbort = () => { // With cleanup using (TransponderScanner scanner = m_Scanner) { // Mark as done m_ScanProgress = -1; m_Scanner = null; // Check mode if (updateProfile.HasValue) { // Do NOT merge if (!updateProfile.Value) { scanner.Profile.Locations.Clear(); } // Process scanner.UpdateProfile(); // Save it scanner.Profile.Save(); } } // Report ActionDone(null, null); }; // Done return(DelayedOperationTag); }); }
/// <summary> /// Verändert den Netzwerkversand für eine aktive Quelle. /// </summary> /// <param name="source">Die Auswahl der Quelle.</param> /// <param name="uniqueIdentifier">Der eindeutige Name der Quelle.</param> /// <param name="target">Die Daten zum Netzwerkversand.</param> /// <exception cref="ArgumentNullException">Es wurde keine Quelle angegeben.</exception> protected override void OnSetStreamTarget(SourceIdentifier source, Guid uniqueIdentifier, string target) { // Prepare operation Start(() => { // Find the source var stream = FindSource(new SourceIdenfierWithKey(uniqueIdentifier, source)); if (stream == null) { CardServerException.Throw(new NoSourceFault(source)); } // Process stream.Manager.StreamingTarget = target; }); }
/// <summary> /// Aktiviert den Empfang einer Quelle. /// </summary> /// <param name="sources">Informationen zu den zu aktivierenden Quellen.</param> /// <returns>Steuereinheit für diesen Aufruf. Der Ergebniswert enthält alle Quellen, die erfolgreich /// aktiviert wurden - eventuell mit reduzierten Detailaspekten.</returns> /// <exception cref="ArgumentNullException">Mindestens eine Quelle ist nicht gesetzt.</exception> public IAsyncResult <StreamInformation[]> BeginAddSources(ReceiveInformation[] sources) { // Validate if (sources == null) { throw new ArgumentNullException("sources"); } // Create helper var clones = new List <ReceiveInformation>(); // Process all for (int i = 0; i < sources.Length; ++i) { // Load the one var source = sources[i]; if (null == source) { throw new ArgumentNullException(string.Format("sources[{0}]", i)); } // Clone it source = source.Clone(); // More tests if (source.SelectionKey == null) { throw new ArgumentNullException(string.Format("sources[{0}].SelectionKey", i)); } if (source.Streams == null) { throw new ArgumentNullException(string.Format("sources[{0}].Streams", i)); } // Check for profile match if (string.IsNullOrEmpty(m_Profile) || !string.Equals(m_Profile, source.Selection.ProfileName, StringComparison.InvariantCultureIgnoreCase)) { CardServerException.Throw(new ProfileMismatchFault(m_Profile, source.Selection.ProfileName)); } // Merge clones.Add(source); } // Start action return((IAsyncResult <StreamInformation[]>)Start <StreamInformation[]>(() => { OnAddSources(clones.ToArray()); })); }
/// <summary> /// Stellt den Empfang für eine Quelle ein. /// </summary> /// <param name="source">Die betroffene Quelle.</param> /// <param name="uniqueIdentifier">Der eindeutige Name der Quelle.</param> protected override void OnRemoveSource(SourceIdentifier source, Guid uniqueIdentifier) { // Prepare operation Start(() => { // Find the source var stream = FindSource(new SourceIdenfierWithKey(uniqueIdentifier, source)); if (stream == null) { CardServerException.Throw(new NoSourceFault(source)); } // Stop all activity on the source using (stream) Streams.Remove(stream.SourceKey); }); }
/// <summary> /// Setzt das aktuell zugeordnete DVB.NET Geräteprofil. /// </summary> /// <param name="profileName">Der Name des zu verwendenden Geräteprofils.</param> /// <param name="reset">Gesetzt, wenn das zugehörige Windows Gerät neu initialisiert werden soll.</param> /// <param name="disablePCRFromH264">Wird gesetzt um zu verhindern, dass die Systemzeit (PCR) aus /// dem H.264 Bildsignal ermittelt wird, da dieser Mechanismus hochgradig unsicher ist.</param> /// <param name="disablePCRFromMPEG2">Wird gesetzt um zu verhindern, dass die Systemzeit (PCR) aus /// dem MPEG2 Bildsignal ermittelt wird, da dieser Mechanismus hochgradig unsicher ist.</param> /// <returns>Steuerinstanz zur asynchronen Ausführung.</returns> /// <exception cref="ArgumentNullException">Es wurde kein Geräteprofil angegeben.</exception> /// <exception cref="CardServerException">Es wurde bereits ein Geräteprofil aktiviert.</exception> public IAsyncResult BeginSetProfile(string profileName, bool reset, bool disablePCRFromH264, bool disablePCRFromMPEG2) { // Validate if (string.IsNullOrEmpty(profileName)) { throw new ArgumentNullException("value"); } // We are in use if (!string.IsNullOrEmpty(m_Profile)) { CardServerException.Throw(new ProfileAlreadyAttachedFault(m_Profile)); } // Set the closing action return(Start <object>(() => { OnAttachProfile(profileName, reset, disablePCRFromH264, disablePCRFromMPEG2); }, r => { m_Profile = profileName; })); }
/// <summary> /// Stellt den Empfang für alle Quellen ein. /// </summary> protected override void OnRemoveAllSources() { // Dispatch Start(() => { // Check mode if (EPGProgress.HasValue) { CardServerException.Throw(new EPGActiveFault()); } if (m_ScanProgress >= 0) { CardServerException.Throw(new SourceUpdateActiveFault()); } // Forward RemoveAll(); }); }
/// <summary> /// Meldet, dass die aktuelle Aufgabe abgeschlossen wurde. /// </summary> /// <param name="e">Die zugehörige Ausnahme oder <i>null</i>, wenn bei der Ausführung /// kein Fehler aufgetreten ist.</param> /// <param name="result">Das Ergebnis der ausgeführten Aktion</param> protected void ActionDone(Exception e, object result) { // Remember m_Result = result; // Remember if (e == null) { m_LastError = null; } else if (e is CardServerException) { m_LastError = (CardServerException)e; } else { m_LastError = new CardServerException(new CardServerFault(e.Message)); } // Finish if (m_Pending != null) { try { // Process if there was no error if (m_LastError == null) { m_Pending(m_Result); } } finally { // Forget m_Pending = null; } } // Signal m_Done.Set(); }
/// <summary> /// Wählt eine bestimmte Quellgruppe (Transponder) an. /// </summary> /// <param name="selectionKey">Die Beschreibung einer Quelle, deren Gruppe aktiviert werden soll.</param> /// <returns>Steuereinheit für diesen Aufruf.</returns> /// <exception cref="ArgumentNullException">Es wurde keine Quellgruppe angegeben.</exception> /// <exception cref="CardServerException">Es wird bereits eine Anfrage ausgeführt.</exception> public IAsyncResult BeginSelect(string selectionKey) { // Validate if (selectionKey == null) { throw new ArgumentNullException("selectionKey"); } // Reconstruct var selection = new SourceSelection { SelectionKey = selectionKey }; // Check for profile match if (string.IsNullOrEmpty(m_Profile) || !string.Equals(m_Profile, selection.ProfileName, StringComparison.InvariantCultureIgnoreCase)) { CardServerException.Throw(new ProfileMismatchFault(m_Profile, selection.ProfileName)); } // Start action return(Start <object>(() => { OnSelect(selection); })); }
/// <summary> /// Wählt eine Quellgruppe an. /// </summary> /// <param name="device">Die zu verwendende Hardware.</param> /// <param name="selection">Die gewünschte Quellgruppe.</param> private void SelectGroup(Hardware device, SourceSelection selection) { // Check mode if (EPGProgress.HasValue) { CardServerException.Throw(new EPGActiveFault()); } if (m_ScanProgress >= 0) { CardServerException.Throw(new SourceUpdateActiveFault()); } // Stop all current recordings RemoveAll(); // Forward device.SelectGroup(selection.Location, selection.Group); // Time to reset counters m_LastGroupInfoTime = DateTime.UtcNow; GroupRestart = 0; }
/// <summary> /// Führt eine Erweiterungsoperation aus. /// </summary> /// <param name="actionType">Die Klasse, von der aus die Erweiterungsmethode abgerufen werden kann.</param> /// <param name="parameters">Optionale Parameter zur Ausführung.</param> protected override void OnCustomAction <TInput, TOutput>(string actionType, TInput parameters) { // Process Start(device => { // Resolve the type var type = Type.GetType(actionType, false); if (type == null) { CardServerException.Throw(new NoSuchActionFault(actionType)); } // Create the instance of the type var customAction = Activator.CreateInstance(type, new object[] { this }) as CustomAction <TInput, TOutput>; if (customAction == null) { CardServerException.Throw(new NoSuchActionFault(actionType)); } // Process return(customAction.Execute(device, parameters)); }); }
/// <summary> /// Meldet das Ergebnis der letzten Befehlsausführung. Diese Methode /// kann nur ein einziges Mal aufgerufen werden. /// </summary> /// <returns>Das Ergebnis der letzten Befehlsausführung.</returns> private T GetResult <T>() { // Still running if (IsBusy) { CardServerException.Throw(new ServerBusyFault()); } // Result var e = m_LastError; // Clear m_LastError = null; // Report error if (e != null) { throw e; } // Report result return((T)m_Result); }
/// <summary> /// Beginnt einen Sendersuchlauf auf dem aktuellen Geräteprofil. /// </summary> protected override void OnStartScan() { // Process Start(device => { // Check mode if (EPGProgress.HasValue) { CardServerException.Throw(new EPGActiveFault()); } if (m_ScanProgress >= 0) { CardServerException.Throw(new SourceUpdateActiveFault()); } if (!string.IsNullOrEmpty(Profile.UseSourcesFrom)) { CardServerException.Throw(new NoSourceListFault(Profile.Name)); } // Stop all RemoveAll(); // Create scanner m_Scanner = new TransponderScanner(Profile); // Configure m_Scanner.OnDoneLocation += (l, s) => OnUpdateScan(); m_Scanner.OnDoneGroup += (l, g, s) => OnUpdateScan(); // Mark as started m_ScanProgress = 0; m_ScanSources = 0; // Start it m_Scanner.Scan(); }); }
/// <summary> /// Beginnt mit der Ausführung einer Aufgabe. /// </summary> /// <typeparam name="TResult">Die Art des Rückgabewertes.</typeparam> /// <param name="action">Die auszuführende Aktion.</param> /// <param name="finalizer"></param> /// <returns>Steuereinheit für diesen Aufruf.</returns> private IAsyncResult Start <TResult>(Action action, Action <object> finalizer) { // We are Processing if (IsBusy) { CardServerException.Throw(new ServerBusyFault()); } // Set the closing action m_Pending = finalizer; // Reset error m_LastError = null; m_Result = null; // Reset synchronizer m_Done.Reset(); // Be safe try { // Initiate the operation action(); // Report control element return(_AsyncControl.Create <TResult>(this)); } catch (Exception e) { // Synchronous error ActionDone(e, null); // Forward throw e; } }
/// <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> /// Beginnt mit der Sammlung der Daten für die elektronische Programmzeitschrift /// (EPG). /// </summary> /// <param name="device">Das zu verwendende DVB.NET Gerät.</param> /// <param name="sources">Die zu berücksichtigenden Quellen.</param> /// <param name="extensions">Spezielle Zusatzfunktionalitäten der Sammlung.</param> private void StartEPGCollection(Hardware device, SourceIdentifier[] sources, EPGExtensions extensions) { // Check mode if (EPGProgress.HasValue) { CardServerException.Throw(new EPGActiveFault()); } if (m_ScanProgress >= 0) { CardServerException.Throw(new SourceUpdateActiveFault()); } // Reset lists m_EPGSources.Clear(); m_EPGGroups.Clear(); // Load all identifiers to scan if (null != sources) { foreach (SourceIdentifier source in sources) { AddEPGSource(source); } } // Add specials if (0 != (extensions & EPGExtensions.PREMIEREDirect)) { if (AddEPGGroup(DirectCIT.TriggerSource).Length < 1) { extensions &= ~EPGExtensions.PREMIEREDirect; } } if (0 != (extensions & EPGExtensions.PREMIERESport)) { if (AddEPGGroup(SportCIT.TriggerSource).Length < 1) { extensions &= ~EPGExtensions.PREMIERESport; } } if (0 != (extensions & EPGExtensions.FreeSatUK)) { if (AddEPGGroup(EIT.FreeSatEPGTriggerSource).Length < 1) { extensions &= ~EPGExtensions.FreeSatUK; } } // Stop all RemoveAll(); // Prepare m_EPGPending = new List <GroupKey>(m_EPGGroups.Keys); m_EPGLastItemCheck = DateTime.MaxValue; m_EPGLastTune = DateTime.MinValue; m_EPGLastItemCount = -1; m_EPGItems.Clear(); m_EPGItemCount = 0; // Mark as active m_EPGExtensions = extensions; EPGProgress = 0; // Enforce start CollectProgramGuide(device); }