diff --git a/.gitignore b/.gitignore index 0e34f8a..c58b51e 100644 --- a/.gitignore +++ b/.gitignore @@ -185,4 +185,10 @@ $RECYCLE.BIN/ /VCR.NET/packages *.sln *.openAsAdmin -/VCR.NET/.vs +/VCR.NET/node_modules +/VCR.NET/WebClient41/content/styles.css +/VCR.NET/WebClient41/scripts/vcrnet.js* + +.vs + +package-lock.json \ No newline at end of file diff --git a/DVB.NET/Administration/PlugIns/Transponder Scanner/Properties/Resources.Designer.cs b/DVB.NET/Administration/PlugIns/Transponder Scanner/Properties/Resources.Designer.cs index 6ef1eba..754c167 100644 --- a/DVB.NET/Administration/PlugIns/Transponder Scanner/Properties/Resources.Designer.cs +++ b/DVB.NET/Administration/PlugIns/Transponder Scanner/Properties/Resources.Designer.cs @@ -1,7 +1,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.18444 +// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -141,6 +141,15 @@ internal static string Save_Profile_Titel { } } + /// + /// Looks up a localized string similar to Scan reported Errors. + /// + internal static string Scanner_Error { + get { + return ResourceManager.GetString("Scanner_Error", resourceCulture); + } + } + /// /// Looks up a localized string similar to Scan for new or updated Sources (Transponder Scan). /// diff --git a/DVB.NET/Administration/PlugIns/Transponder Scanner/Properties/Resources.de.resx b/DVB.NET/Administration/PlugIns/Transponder Scanner/Properties/Resources.de.resx index 72a6cb0..d1659ea 100644 --- a/DVB.NET/Administration/PlugIns/Transponder Scanner/Properties/Resources.de.resx +++ b/DVB.NET/Administration/PlugIns/Transponder Scanner/Properties/Resources.de.resx @@ -112,10 +112,10 @@ 2.0 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 Quellgruppen von der Aktualisierung ausschliessen @@ -144,6 +144,9 @@ Suchlauf beendet + + Es wurden Fehler erkannt + Nach neuen oder aktualisierten Quellen suchen (Sendersuchlauf) diff --git a/DVB.NET/Administration/PlugIns/Transponder Scanner/Properties/Resources.resx b/DVB.NET/Administration/PlugIns/Transponder Scanner/Properties/Resources.resx index 6c23d6b..a3deea1 100644 --- a/DVB.NET/Administration/PlugIns/Transponder Scanner/Properties/Resources.resx +++ b/DVB.NET/Administration/PlugIns/Transponder Scanner/Properties/Resources.resx @@ -112,10 +112,10 @@ 2.0 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 Exclude Source Groups from Update @@ -144,6 +144,9 @@ Operation completed + + Scan reported Errors + Scan for new or updated Sources (Transponder Scan) diff --git a/DVB.NET/Administration/PlugIns/Transponder Scanner/ScannerDialog.cs b/DVB.NET/Administration/PlugIns/Transponder Scanner/ScannerDialog.cs index 4c7d68f..a322c68 100644 --- a/DVB.NET/Administration/PlugIns/Transponder Scanner/ScannerDialog.cs +++ b/DVB.NET/Administration/PlugIns/Transponder Scanner/ScannerDialog.cs @@ -38,7 +38,7 @@ public partial class ScannerDialog : UserControl, IPlugInControl /// Die Konfiguration für diesen Suchlauf. /// Die Arbeitsumgebung der Erweiterung - üblicherweise das DVB.NET /// Administrationswerkzeug. - public ScannerDialog( Scanner scanner, IPlugInUISite site ) + public ScannerDialog(Scanner scanner, IPlugInUISite site) { // Remember m_PlugIn = scanner; @@ -56,10 +56,10 @@ public ScannerDialog( Scanner scanner, IPlugInUISite site ) /// /// Wird ignoriert. /// Wird ignoriert. - private void ScannerDialog_Load( object sender, EventArgs e ) + private void ScannerDialog_Load(object sender, EventArgs e) { // Set up the name of the selected profile - lbProfile.Text = string.Format( lbProfile.Text, m_PlugIn.Profile.Name ); + lbProfile.Text = string.Format(lbProfile.Text, m_PlugIn.Profile.Name); } /// @@ -68,7 +68,7 @@ private void ScannerDialog_Load( object sender, EventArgs e ) /// /// Wird ignoriert. /// Wird ignoriert. - private void tickEnd_Tick( object sender, EventArgs e ) + private void tickEnd_Tick(object sender, EventArgs e) { // See if scanner is done if (!m_Scanner.Done) @@ -78,7 +78,7 @@ private void tickEnd_Tick( object sender, EventArgs e ) tickEnd.Enabled = false; // Final update - UpdateCounter( null ); + UpdateCounter(null); // Prepare to terminate using (TransponderScanner scanner = m_Scanner) @@ -89,11 +89,16 @@ private void tickEnd_Tick( object sender, EventArgs e ) // Must finish try { + // Check for error + var error = scanner.Error; + if (error != null) + MessageBox.Show(this, error.ToString(), Properties.Resources.Scanner_Error, MessageBoxButtons.OK, MessageBoxIcon.Warning); + // Create question - string quest = string.Format( Properties.Resources.Save_Profile, scanner.Profile.Name ); + string quest = string.Format(Properties.Resources.Save_Profile, scanner.Profile.Name); // Ask user - DialogResult saveMode = MessageBox.Show( this, quest, Properties.Resources.Save_Profile_Titel, MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1 ); + DialogResult saveMode = MessageBox.Show(this, quest, Properties.Resources.Save_Profile_Titel, MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1); // Profile if (DialogResult.Cancel != saveMode) @@ -112,14 +117,14 @@ private void tickEnd_Tick( object sender, EventArgs e ) // Protocol if (DialogResult.Yes == saveMode) if (DialogResult.OK == saveProtocol.ShowDialog(this)) - using (StreamWriter protocol = new StreamWriter( saveProtocol.FileName, false, Encoding.Unicode )) + using (StreamWriter protocol = new StreamWriter(saveProtocol.FileName, false, Encoding.Unicode)) { // Head line - protocol.WriteLine( ProtocolRecord.LineFormat ); + protocol.WriteLine(ProtocolRecord.LineFormat); // All lines foreach (ProtocolRecord record in scanner.Protocol) - protocol.WriteLine( record ); + protocol.WriteLine(record); } } finally @@ -137,11 +142,11 @@ private void tickEnd_Tick( object sender, EventArgs e ) /// /// Detailinformationen zur aktuellen Position. /// Gesetzt, wenn der aktuelle Suchlauf fortgesetzt werden darf. - private bool UpdateCounter( string hint ) + private bool UpdateCounter(string hint) { // Call self if (InvokeRequired) - return (bool) Invoke( new Func( UpdateCounter ), hint ); + return (bool)Invoke(new Func(UpdateCounter), hint); // Private counters Dictionary found = new Dictionary(); @@ -162,7 +167,7 @@ private bool UpdateCounter( string hint ) // This type int sum; - if (!found.TryGetValue( source.Key, out sum )) + if (!found.TryGetValue(source.Key, out sum)) sum = 0; // Update @@ -170,7 +175,7 @@ private bool UpdateCounter( string hint ) } // Set it - lbFound.Text = string.Format( Properties.Resources.Report, total, found[SourceTypes.TV], found[SourceTypes.Radio], found[SourceTypes.Unknown], "\r\n\r\n " + hint ); + lbFound.Text = string.Format(Properties.Resources.Report, total, found[SourceTypes.TV], found[SourceTypes.Radio], found[SourceTypes.Unknown], "\r\n\r\n " + hint); // Try to get a new progress value decimal newProgress = 0; @@ -196,7 +201,7 @@ private bool UpdateCounter( string hint ) try { // Update - prgProgress.Value = (int) newProgress; + prgProgress.Value = (int)newProgress; } catch { @@ -215,16 +220,16 @@ private bool UpdateCounter( string hint ) bool IPlugInControl.Start() { // Create scanner - m_Scanner = new TransponderScanner( m_PlugIn.Profile ); + m_Scanner = new TransponderScanner(m_PlugIn.Profile); // Connect all events - m_Scanner.OnStartGroup += ( l, g, s ) => UpdateCounter( string.Format( "{0} {1}", g, l ) ); - m_Scanner.OnStartLocation += ( l, s ) => UpdateCounter( null ); - m_Scanner.OnDoneGroup += ( l, g, s ) => UpdateCounter( null ); - m_Scanner.OnDoneLocation += ( l, s ) => UpdateCounter( null ); + m_Scanner.OnStartGroup += (l, g, s) => UpdateCounter(string.Format("{0} {1}", g, l)); + m_Scanner.OnStartLocation += (l, s) => UpdateCounter(null); + m_Scanner.OnDoneGroup += (l, g, s) => UpdateCounter(null); + m_Scanner.OnDoneLocation += (l, s) => UpdateCounter(null); // Start with counter - UpdateCounter( null ); + UpdateCounter(null); // Start the scan m_Scanner.Scan(); diff --git a/DVB.NET/Algorithms/Scheduler/AllocationMap.cs b/DVB.NET/Algorithms/Scheduler/AllocationMap.cs index 8817db4..681323f 100644 --- a/DVB.NET/Algorithms/Scheduler/AllocationMap.cs +++ b/DVB.NET/Algorithms/Scheduler/AllocationMap.cs @@ -356,7 +356,7 @@ private void Allocate( int allocationIndex, IScheduleSource source, ref PlannedT } // Correct it all - for (; ; ) + for (;;) { // On change we must create a clone var allocationIsPrivate = false; @@ -447,7 +447,7 @@ public AllocationPlan PrepareAllocation( IScheduleSource source, SuggestedPlanne var time = timeHolder.Planned; // As long as needed - for (var scanStart = 0; ; ) + for (var scanStart = 0; ;) { // See if there is at least one allocation area available var allocationIndex = m_Allocations.FindIndex( scanStart, a => a.Overlaps( time ) ); @@ -505,21 +505,8 @@ public AllocationMap Clone( DateTime? planTime ) var index = allocations.FindIndex( allocation => allocation.End > planTime.Value ); // Cut off if not the very first - if (--index > 0) - { - // Collapse if only two are left - if (index == allocations.Count - 2) - index++; - - // Load the very start of it all - var allocation = allocations[0]; - - // Update it's end time - allocations[0] = allocation.Clone( allocation.Start, allocations[index].End ); - - // Cleanup the rest - allocations.RemoveRange( 1, index ); - } + if (index > 1) + allocations.RemoveRange( 0, index ); // Report return clone; diff --git a/DVB.NET/BDA4/Editors/DeviceIndex.Designer.cs b/DVB.NET/BDA4/Editors/DeviceIndex.Designer.cs index 4ace2cc..2c5311f 100644 --- a/DVB.NET/BDA4/Editors/DeviceIndex.Designer.cs +++ b/DVB.NET/BDA4/Editors/DeviceIndex.Designer.cs @@ -28,52 +28,57 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { - System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(DeviceIndex)); - this.cmdSave = new System.Windows.Forms.Button(); - this.cmdCancel = new System.Windows.Forms.Button(); - this.selIndex = new System.Windows.Forms.NumericUpDown(); - ((System.ComponentModel.ISupportInitialize)(this.selIndex)).BeginInit(); - this.SuspendLayout(); - // - // cmdSave - // - this.cmdSave.DialogResult = System.Windows.Forms.DialogResult.OK; - resources.ApplyResources(this.cmdSave, "cmdSave"); - this.cmdSave.Name = "cmdSave"; - this.cmdSave.UseVisualStyleBackColor = true; - this.cmdSave.Click += new System.EventHandler(this.cmdSave_Click); - // - // cmdCancel - // - this.cmdCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; - resources.ApplyResources(this.cmdCancel, "cmdCancel"); - this.cmdCancel.Name = "cmdCancel"; - this.cmdCancel.UseVisualStyleBackColor = true; - // - // selIndex - // - resources.ApplyResources(this.selIndex, "selIndex"); - this.selIndex.Name = "selIndex"; - this.selIndex.ValueChanged += new System.EventHandler(this.selIndex_ValueChanged); - // - // DeviceIndex - // - this.AcceptButton = this.cmdSave; - resources.ApplyResources(this, "$this"); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.CancelButton = this.cmdCancel; - this.Controls.Add(this.selIndex); - this.Controls.Add(this.cmdCancel); - this.Controls.Add(this.cmdSave); - this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; - this.MaximizeBox = false; - this.MinimizeBox = false; - this.Name = "DeviceIndex"; - this.ShowIcon = false; - this.ShowInTaskbar = false; - this.Load += new System.EventHandler(this.DeviceIndex_Load); - ((System.ComponentModel.ISupportInitialize)(this.selIndex)).EndInit(); - this.ResumeLayout(false); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(DeviceIndex)); + this.cmdSave = new System.Windows.Forms.Button(); + this.cmdCancel = new System.Windows.Forms.Button(); + this.selIndex = new System.Windows.Forms.NumericUpDown(); + ((System.ComponentModel.ISupportInitialize)(this.selIndex)).BeginInit(); + this.SuspendLayout(); + // + // cmdSave + // + this.cmdSave.DialogResult = System.Windows.Forms.DialogResult.OK; + resources.ApplyResources(this.cmdSave, "cmdSave"); + this.cmdSave.Name = "cmdSave"; + this.cmdSave.UseVisualStyleBackColor = true; + this.cmdSave.Click += new System.EventHandler(this.cmdSave_Click); + // + // cmdCancel + // + this.cmdCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + resources.ApplyResources(this.cmdCancel, "cmdCancel"); + this.cmdCancel.Name = "cmdCancel"; + this.cmdCancel.UseVisualStyleBackColor = true; + // + // selIndex + // + resources.ApplyResources(this.selIndex, "selIndex"); + this.selIndex.Maximum = new decimal(new int[] { + 65535, + 0, + 0, + 0}); + this.selIndex.Name = "selIndex"; + this.selIndex.ValueChanged += new System.EventHandler(this.selIndex_ValueChanged); + // + // DeviceIndex + // + this.AcceptButton = this.cmdSave; + resources.ApplyResources(this, "$this"); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.cmdCancel; + this.Controls.Add(this.selIndex); + this.Controls.Add(this.cmdCancel); + this.Controls.Add(this.cmdSave); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "DeviceIndex"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.Load += new System.EventHandler(this.DeviceIndex_Load); + ((System.ComponentModel.ISupportInitialize)(this.selIndex)).EndInit(); + this.ResumeLayout(false); } diff --git a/DVB.NET/BDA4/Editors/DeviceIndex.de.resx b/DVB.NET/BDA4/Editors/DeviceIndex.de.resx index b42caf4..7b2c4fc 100644 --- a/DVB.NET/BDA4/Editors/DeviceIndex.de.resx +++ b/DVB.NET/BDA4/Editors/DeviceIndex.de.resx @@ -124,6 +124,6 @@ &Verwerfen - Gerätenummer auswählen + Wert auswählen \ No newline at end of file diff --git a/DVB.NET/BDA4/Editors/DeviceIndex.resx b/DVB.NET/BDA4/Editors/DeviceIndex.resx index fc96d67..53b68b5 100644 --- a/DVB.NET/BDA4/Editors/DeviceIndex.resx +++ b/DVB.NET/BDA4/Editors/DeviceIndex.resx @@ -112,16 +112,16 @@ 2.0 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - + False - + 93, 10 @@ -138,7 +138,7 @@ cmdSave - System.Windows.Forms.Button, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 $this @@ -162,7 +162,7 @@ cmdCancel - System.Windows.Forms.Button, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 $this @@ -179,7 +179,7 @@ 0 - + Center @@ -187,7 +187,7 @@ selIndex - System.Windows.Forms.NumericUpDown, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Windows.Forms.NumericUpDown, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 $this @@ -195,7 +195,7 @@ 0 - + True @@ -208,12 +208,12 @@ CenterParent - Choose Device Index + Select Value DeviceIndex - System.Windows.Forms.Form, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 \ No newline at end of file diff --git a/DVB.NET/BDA4/Editors/FreeText.Designer.cs b/DVB.NET/BDA4/Editors/FreeText.Designer.cs new file mode 100644 index 0000000..8f71c33 --- /dev/null +++ b/DVB.NET/BDA4/Editors/FreeText.Designer.cs @@ -0,0 +1,85 @@ +namespace JMS.DVB.DeviceAccess.Editors +{ + partial class FreeText + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FreeText)); + this.cmdSave = new System.Windows.Forms.Button(); + this.cmdCancel = new System.Windows.Forms.Button(); + this.txtValue = new System.Windows.Forms.TextBox(); + this.SuspendLayout(); + // + // cmdSave + // + this.cmdSave.DialogResult = System.Windows.Forms.DialogResult.OK; + resources.ApplyResources(this.cmdSave, "cmdSave"); + this.cmdSave.Name = "cmdSave"; + this.cmdSave.UseVisualStyleBackColor = true; + this.cmdSave.Click += new System.EventHandler(this.cmdSave_Click); + // + // cmdCancel + // + this.cmdCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + resources.ApplyResources(this.cmdCancel, "cmdCancel"); + this.cmdCancel.Name = "cmdCancel"; + this.cmdCancel.UseVisualStyleBackColor = true; + // + // txtValue + // + resources.ApplyResources(this.txtValue, "txtValue"); + this.txtValue.Name = "txtValue"; + this.txtValue.TextChanged += new System.EventHandler(this.txtValue_TextChanged); + // + // FreeText + // + this.AcceptButton = this.cmdSave; + resources.ApplyResources(this, "$this"); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.cmdCancel; + this.Controls.Add(this.txtValue); + this.Controls.Add(this.cmdCancel); + this.Controls.Add(this.cmdSave); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "FreeText"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.Load += new System.EventHandler(this.FreeText_Load); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Button cmdSave; + private System.Windows.Forms.Button cmdCancel; + private System.Windows.Forms.TextBox txtValue; + } +} \ No newline at end of file diff --git a/DVB.NET/BDA4/Editors/FreeText.cs b/DVB.NET/BDA4/Editors/FreeText.cs new file mode 100644 index 0000000..f270703 --- /dev/null +++ b/DVB.NET/BDA4/Editors/FreeText.cs @@ -0,0 +1,95 @@ +using System; +using System.Windows.Forms; + + +namespace JMS.DVB.DeviceAccess.Editors +{ + /// + /// Erlaubt die Bearbeitung einer Zeichenkette. + /// + public partial class FreeText : Form, IParameterEditor + { + /// + /// Der Name des Parameters, der gepflegt wird. + /// + private string m_Name = null; + + /// + /// Der ursprüngliche Wert des Parameters. + /// + private ParameterValue m_Value = null; + + /// + /// Erzeugt ein neues Formular. + /// + public FreeText() + { + // Set up + InitializeComponent(); + } + + #region IParameterEditor Members + + /// + /// Bietet einen Parameter zum Ändern an. + /// + /// Das übergeordnete Fenster. + /// Der Name des Parameters. + /// Der Wert des Parameters. + /// Gesetzt, wenn der Wert verändert wurde. + public virtual bool Edit(IWin32Window dialog, string parameterName, ref ParameterValue parameterValue) + { + // Remember context + m_Name = parameterName; + m_Value = parameterValue; + + // Run + if (ShowDialog(dialog) != DialogResult.OK) + return false; + + // Update + parameterValue = m_Value; + + // Report + return true; + } + + #endregion + + /// + /// Übernimmt den aktuellen Wert des Parameters. + /// + /// Wird ignoriert. + /// Wird ignoriert. + private void FreeText_Load(object sender, EventArgs e) + { + // Load setting + txtValue.Text = (m_Value == null) ? string.Empty : m_Value.Value; + } + + /// + /// Der Anwender möchte einen veränderten Wert übernehmen. + /// + /// Wird ignoriert. + /// Wird ignoriert. + private void cmdSave_Click(object sender, EventArgs e) + { + // Update + m_Value = new ParameterValue(string.IsNullOrEmpty(txtValue.Text) ? " " : txtValue.Text, txtValue.Text ?? string.Empty); + } + + /// + /// Der Anwender hat den Wert verändert. + /// + /// Wird ignoriert. + /// Wird ignoriert. + private void txtValue_TextChanged(object sender, EventArgs e) + { + // Convert + var value = (m_Value == null) ? string.Empty : m_Value.Value; + + // Enabled button + cmdSave.Enabled = (txtValue.Text != value); + } + } +} \ No newline at end of file diff --git a/DVB.NET/BDA4/Editors/FreeText.de.resx b/DVB.NET/BDA4/Editors/FreeText.de.resx new file mode 100644 index 0000000..8856fad --- /dev/null +++ b/DVB.NET/BDA4/Editors/FreeText.de.resx @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + &Speichern + + + &Verwerfen + + + Wert eingeben + + \ No newline at end of file diff --git a/DVB.NET/BDA4/Editors/FreeText.resx b/DVB.NET/BDA4/Editors/FreeText.resx new file mode 100644 index 0000000..bef0ff9 --- /dev/null +++ b/DVB.NET/BDA4/Editors/FreeText.resx @@ -0,0 +1,216 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + False + + + + 304, 10 + + + 75, 23 + + + 1 + + + &Update + + + cmdSave + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 2 + + + 385, 10 + + + 75, 23 + + + 2 + + + &Discard + + + cmdCancel + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 1 + + + 12, 12 + + + 286, 20 + + + 0 + + + txtValue + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 0 + + + True + + + 6, 13 + + + 472, 45 + + + + CenterParent + + + Enter Value + + + FreeText + + + System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/DVB.NET/BDA4/JMS.DVB.DeviceAccess.csproj b/DVB.NET/BDA4/JMS.DVB.DeviceAccess.csproj index 5cda12e..0780e8c 100644 --- a/DVB.NET/BDA4/JMS.DVB.DeviceAccess.csproj +++ b/DVB.NET/BDA4/JMS.DVB.DeviceAccess.csproj @@ -79,6 +79,12 @@ + + Form + + + FreeText.cs + Form @@ -210,6 +216,14 @@ + + FreeText.cs + Designer + + + FreeText.cs + Designer + DeviceIndex.cs Designer diff --git a/DVB.NET/Card Server/CardServerCore/ActiveStream.cs b/DVB.NET/Card Server/CardServerCore/ActiveStream.cs index 00c8886..0e4325c 100644 --- a/DVB.NET/Card Server/CardServerCore/ActiveStream.cs +++ b/DVB.NET/Card Server/CardServerCore/ActiveStream.cs @@ -200,7 +200,7 @@ public void Refresh( TimeSpan interval ) return; // Get the source information - var info = manager.GetCurrentInformation(); + var info = manager.GetCurrentInformationAsync().CancelAfter( 15000 ).Result; // Must start if (!FirstActivationDone) diff --git a/DVB.NET/Card Server/CardServerCore/Implementation/InMemoryCardServer_EPG.cs b/DVB.NET/Card Server/CardServerCore/Implementation/InMemoryCardServer_EPG.cs index bc0acd0..63c42fd 100644 --- a/DVB.NET/Card Server/CardServerCore/Implementation/InMemoryCardServer_EPG.cs +++ b/DVB.NET/Card Server/CardServerCore/Implementation/InMemoryCardServer_EPG.cs @@ -469,7 +469,7 @@ private void CollectProgramGuide( Hardware device ) device.SelectGroup( next.Location, next.Group ); // See if there is something on this group - if (null == device.GetGroupInformation( 5000 )) + if (null == device.GetGroupInformation( 15000 )) { // Push back m_EPGPending.Add( next ); diff --git a/DVB.NET/Card Server/CardServerCore/InMemoryCardServer.cs b/DVB.NET/Card Server/CardServerCore/InMemoryCardServer.cs index fb6c684..39a6208 100644 --- a/DVB.NET/Card Server/CardServerCore/InMemoryCardServer.cs +++ b/DVB.NET/Card Server/CardServerCore/InMemoryCardServer.cs @@ -248,7 +248,7 @@ private void TestForRestart( Hardware device ) return; // Get the group information - var info = device.GetGroupInformation( 5000 ); + var info = device.GetGroupInformation( 15000 ); if (info == null) { // See if we are already out of retries @@ -510,7 +510,7 @@ private ServerInformation CreateState( Hardware device ) var info = new ServerInformation { - HasGroupInformation = (device.GetGroupInformation( 5000 ) != null), + HasGroupInformation = (device.GetGroupInformation( 15000 ) != null), ProgramGuideProgress = EPGProgress, Selection = selection.SelectionKey }; diff --git a/DVB.NET/EPG/Descriptor.cs b/DVB.NET/EPG/Descriptor.cs index 2e15cfc..3ea1af6 100644 --- a/DVB.NET/EPG/Descriptor.cs +++ b/DVB.NET/EPG/Descriptor.cs @@ -38,33 +38,38 @@ public abstract class Descriptor /// of type with a single parameter. This method /// has to report true for any descriptor tag it is responsible for. /// - private static readonly Type[] m_Handlers = - { - typeof(Descriptors.ShortEvent), - typeof(Descriptors.Content), - typeof(Descriptors.Component), - typeof(Descriptors.ExtendedEvent), - typeof(Descriptors.PrivateData), - typeof(Descriptors.PDCDescriptor), - typeof(Descriptors.ParentalRating), - typeof(Descriptors.Linkage), + private static readonly Type[] m_Handlers = + { + typeof(Descriptors.ShortEvent), + typeof(Descriptors.Content), + typeof(Descriptors.Component), + typeof(Descriptors.ExtendedEvent), + typeof(Descriptors.PrivateData), + typeof(Descriptors.PDCDescriptor), + typeof(Descriptors.ParentalRating), + typeof(Descriptors.Linkage), typeof(Descriptors.StreamIdentifier), typeof(Descriptors.Service), typeof(Descriptors.ISOLanguage), typeof(Descriptors.DataBroadcast), typeof(Descriptors.Teletext), typeof(Descriptors.AC3), - typeof(Descriptors.NetworkName), - typeof(Descriptors.CableDelivery), - typeof(Descriptors.SatelliteDelivery), + typeof(Descriptors.AAC), + typeof(Descriptors.NetworkName), + typeof(Descriptors.CableDelivery), + typeof(Descriptors.SatelliteDelivery), typeof(Descriptors.TerrestrialDelivery), - typeof(Descriptors.ServiceList), + typeof(Descriptors.ServiceList), typeof(Descriptors.Subtitle), typeof(Descriptors.ContentTransmissionPremiere), typeof(Descriptors.CellList), typeof(Descriptors.FrequencyList), - typeof(Descriptors.CellFrequencyLink) - }; + typeof(Descriptors.CellFrequencyLink), + typeof(Descriptors.AncillaryData), + typeof(Descriptors.ApplicationSignalling), + typeof(Descriptors.DataBroadastId), + typeof(Descriptors.CarouselIdentifier) + }; /// /// Populate the descriptor tag lookup map. @@ -72,7 +77,7 @@ public abstract class Descriptor static Descriptor() { // Use helper - Tools.InitializeDynamicCreate( m_Handlers, m_HandlerForTag, typeof( Descriptors.Generic ) ); + Tools.InitializeDynamicCreate(m_Handlers, m_HandlerForTag, typeof(Descriptors.Generic)); } /// @@ -114,10 +119,10 @@ static Descriptor() /// The number of bytes for this instance. Since this /// does not include the tag and the length /// will be two greater than the value of this parameter. - protected Descriptor( IDescriptorContainer container, int offset, int length ) + protected Descriptor(IDescriptorContainer container, int offset, int length) { // Set - Tag = (DescriptorTags) container.Section[offset - 2]; + Tag = (DescriptorTags)container.Section[offset - 2]; // Remember Container = container; @@ -128,7 +133,7 @@ protected Descriptor( IDescriptorContainer container, int offset, int length ) /// /// /// - protected Descriptor( DescriptorTags tag ) + protected Descriptor(DescriptorTags tag) { // Remember Tag = tag; @@ -149,13 +154,13 @@ protected Descriptor( DescriptorTags tag ) /// does not include the tag and the length /// will be two greater than the value of this parameter. /// A newly created instance. - static public Descriptor Create( IDescriptorContainer container, int offset, int length ) + static public Descriptor Create(IDescriptorContainer container, int offset, int length) { // Attach to the type - Type pHandler = (Type) m_HandlerForTag[container.Section[offset - 2]]; + Type pHandler = (Type)m_HandlerForTag[container.Section[offset - 2]]; // Create - return (Descriptor) Activator.CreateInstance( pHandler, new object[] { container, offset, length } ); + return (Descriptor)Activator.CreateInstance(pHandler, new object[] { container, offset, length }); } /// @@ -175,7 +180,7 @@ static public Descriptor Create( IDescriptorContainer container, int offset, int /// event. New instances are created until /// there is no space left. /// All instances for an event. - static public Descriptor[] Load( IDescriptorContainer container, int offset, int length ) + static public Descriptor[] Load(IDescriptorContainer container, int offset, int length) { // Attach to data Section section = container.Section; @@ -196,10 +201,10 @@ static public Descriptor[] Load( IDescriptorContainer container, int offset, int if ((2 + bytes) > length) break; // Create instance - Descriptor pNew = Create( container, offset + 2, bytes ); + Descriptor pNew = Create(container, offset + 2, bytes); // Remember - all.Add( pNew ); + all.Add(pNew); // Adjust offset += pNew.Length; @@ -207,20 +212,13 @@ static public Descriptor[] Load( IDescriptorContainer container, int offset, int } // Create - return (Descriptor[]) all.ToArray( typeof( Descriptor ) ); + return (Descriptor[])all.ToArray(typeof(Descriptor)); } /// /// Report if this instance is valid. /// - public bool IsValid - { - get - { - // Report - return m_Valid; - } - } + public bool IsValid => m_Valid; /// /// The related . @@ -228,14 +226,7 @@ public bool IsValid /// /// This is the of our . /// - public Table Table - { - get - { - // Forward - return Container.Container; - } - } + public Table Table => Container.Container; /// /// The related . @@ -243,39 +234,32 @@ public Table Table /// /// This is the of our . /// - public Section Section - { - get - { - // Forward - return Table.Section; - } - } + public Section Section => Table.Section; /// /// Append the binary formatted descriptor to the buffer provided. /// /// Some buffer. - internal void CreateDescriptor( TableConstructor buffer ) + internal void CreateDescriptor(TableConstructor buffer) { // Write the tag - buffer.Add( (byte) Tag ); + buffer.Add((byte)Tag); // Position of length int lengthPos = buffer.CreateDynamicLength(); // Add payload - CreatePayload( buffer ); + CreatePayload(buffer); // Update the length - buffer.SetDynamicLength( lengthPos ); + buffer.SetDynamicLength(lengthPos); } /// /// /// /// - protected virtual void CreatePayload( TableConstructor buffer ) + protected virtual void CreatePayload(TableConstructor buffer) { // Must be implemented by derived classes throw new NotImplementedException(); @@ -294,14 +278,14 @@ public static class DescriptorExtensions /// Die Liste der zu durchsuchenden Beschreibungen. /// Die gewünschte Beschreibung oder null, wenn keine Beschreibung /// der gesuchten Art in der Liste vorhanden ist. - public static T Find( this Descriptor[] descriptors ) where T : Descriptor + public static T Find(this Descriptor[] descriptors) where T : Descriptor { // Not possible if (null == descriptors) return null; // Lookup - return (T) Array.Find( descriptors, d => typeof( T ) == d.GetType() ); + return (T)Array.Find(descriptors, d => typeof(T) == d.GetType()); } } diff --git a/DVB.NET/EPG/DescriptorTags.cs b/DVB.NET/EPG/DescriptorTags.cs index fea186f..bcc87b7 100644 --- a/DVB.NET/EPG/DescriptorTags.cs +++ b/DVB.NET/EPG/DescriptorTags.cs @@ -2,17 +2,17 @@ namespace JMS.DVB.EPG { - /// - /// The various descriptor types as defined in the original documentation, - /// e.g. ETSI EN 300 468 V1.6.1 (2004-06) or alternate versions. - /// - /// - /// - /// 0x80 to 0xfe are user defined and 0xff - /// is forbidden. - /// - public enum DescriptorTags - { + /// + /// The various descriptor types as defined in the original documentation, + /// e.g. ETSI EN 300 468 V1.6.1 (2004-06) or alternate versions. + /// + /// + /// + /// 0x80 to 0xfe are user defined and 0xff + /// is forbidden. + /// + public enum DescriptorTags + { /// /// 0x00 /// @@ -52,7 +52,7 @@ public enum DescriptorTags /// 0x07 /// TargetBackgroundGrid, - + /// /// 0x08 /// @@ -111,302 +111,312 @@ public enum DescriptorTags /// /// 0x13 /// - ISOReservedLow = 0x13, + CarouselIdentifier, + + /// + /// 0x14 + /// + ISOReservedLow = 0x14, /// /// 0x3f /// ISOReservedHigh = 0x3f, - /// - /// 0x40 - /// - NetworkName, + /// + /// 0x40 + /// + NetworkName, - /// - /// 0x41 - /// - SeviceList, + /// + /// 0x41 + /// + SeviceList, - /// - /// 0x42 - /// - Stuffing, + /// + /// 0x42 + /// + Stuffing, - /// - /// 0x43 - /// - SatelliteDeliverySystem, + /// + /// 0x43 + /// + SatelliteDeliverySystem, - /// - /// 0x44 - /// - CableDeliverySystem, + /// + /// 0x44 + /// + CableDeliverySystem, - /// - /// 0x45 - /// - VBIData, - - /// - /// 0x46 - /// - VBITeletext, - - /// - /// 0x47 - /// - BouquetName, - - /// - /// 0x48 - /// - Service, - - /// - /// 0x49 - /// - CountryAvailability, - - /// - /// 0x4a - /// - Linkage, - - /// - /// 0x4b - /// - NVODReference, - - /// - /// 0x4c - /// - TimeShiftedService, - - /// - /// 0x4d - /// - ShortEvent, - - /// - /// 0x4e - /// - ExtendedEvent, - - /// - /// 0x4f - /// - TimeShiftedEvent, - - /// - /// 0x50 - /// - Component, - - /// - /// 0x51 - /// - Mosaic, - - /// - /// 0x52 - /// - StreamIdentifier, - - /// - /// 0x53 - /// - CAIdentifier, - - /// - /// 0x54 - /// - Content, - - /// - /// 0x55 - /// - ParentalRating, - - /// - /// 0x56 - /// - Teletext, - - /// - /// 0x57 - /// - Telephone, - - /// - /// 0x58 - /// - LocalTimeOffset, - - /// - /// 0x59 - /// - Subtitling, - - /// - /// 0x5a - /// - TerrestrialDeliverySystem, - - /// - /// 0x5b - /// - MultilingualNetworkName, - - /// - /// 0x5c - /// - MultilingualBouquetName, - - /// - /// 0x5d - /// - MultilingualServiceName, - - /// - /// 0x5e - /// - MultilingualComponent, - - /// - /// 0x5f - /// - PrivateDataSpecifier, - - /// - /// 0x60 - /// - ServiceMove, - - /// - /// 0x61 - /// - ShortSmoothingBuffer, - - /// - /// 0x62 - /// - FrequencyList, - - /// - /// 0x63 - /// - PartialTransportStream, - - /// - /// 0x64 - /// - DataBroadcast, - - /// - /// 0x65 - /// - CASystem, - - /// - /// 0x66 - /// - DataBroadcastId, - - /// - /// 0x67 - /// - TransportStream, - - /// - /// 0x68 - /// - DSNG, - - /// - /// 0x69 - /// - PDC, - - /// - /// 0x6a - /// - AC3, - - /// - /// 0x6b - /// - AncillaryData, - - /// - /// 0x6c - /// - CellList, - - /// - /// 0x6d - /// - CellFrequencyLink, - - /// - /// 0x6e - /// - AnnouncementSupport, - - /// - /// 0x6f - /// - ApplicationSignalling, - - /// - /// 0x70 - /// - AdaptationFieldData, - - /// - /// 0x71 - /// - ServiceIdentifier, - - /// - /// 0x72 - /// - ServiceAvailability, - - /// - /// 0x73 - /// - DefaultAuthority, + /// + /// 0x45 + /// + VBIData, - /// - /// 0x74 - /// - RelatedContent, - - /// - /// 0x75 - /// - TVAId, - - /// - /// 0x76 - /// - ContentIdentifier, - - /// - /// 0x77 - /// - TimeSliceFecIdentifier, - - /// - /// 0x78 + /// + /// 0x46 + /// + VBITeletext, + + /// + /// 0x47 + /// + BouquetName, + + /// + /// 0x48 + /// + Service, + + /// + /// 0x49 + /// + CountryAvailability, + + /// + /// 0x4a + /// + Linkage, + + /// + /// 0x4b + /// + NVODReference, + + /// + /// 0x4c + /// + TimeShiftedService, + + /// + /// 0x4d + /// + ShortEvent, + + /// + /// 0x4e + /// + ExtendedEvent, + + /// + /// 0x4f + /// + TimeShiftedEvent, + + /// + /// 0x50 + /// + Component, + + /// + /// 0x51 + /// + Mosaic, + + /// + /// 0x52 + /// + StreamIdentifier, + + /// + /// 0x53 + /// + CAIdentifier, + + /// + /// 0x54 + /// + Content, + + /// + /// 0x55 + /// + ParentalRating, + + /// + /// 0x56 + /// + Teletext, + + /// + /// 0x57 + /// + Telephone, + + /// + /// 0x58 + /// + LocalTimeOffset, + + /// + /// 0x59 + /// + Subtitling, + + /// + /// 0x5a + /// + TerrestrialDeliverySystem, + + /// + /// 0x5b + /// + MultilingualNetworkName, + + /// + /// 0x5c + /// + MultilingualBouquetName, + + /// + /// 0x5d + /// + MultilingualServiceName, + + /// + /// 0x5e + /// + MultilingualComponent, + + /// + /// 0x5f + /// + PrivateDataSpecifier, + + /// + /// 0x60 + /// + ServiceMove, + + /// + /// 0x61 + /// + ShortSmoothingBuffer, + + /// + /// 0x62 + /// + FrequencyList, + + /// + /// 0x63 + /// + PartialTransportStream, + + /// + /// 0x64 + /// + DataBroadcast, + + /// + /// 0x65 + /// + CASystem, + + /// + /// 0x66 + /// + DataBroadcastId, + + /// + /// 0x67 + /// + TransportStream, + + /// + /// 0x68 + /// + DSNG, + + /// + /// 0x69 + /// + PDC, + + /// + /// 0x6a + /// + AC3, + + /// + /// 0x6b + /// + AncillaryData, + + /// + /// 0x6c + /// + CellList, + + /// + /// 0x6d + /// + CellFrequencyLink, + + /// + /// 0x6e + /// + AnnouncementSupport, + + /// + /// 0x6f + /// + ApplicationSignalling, + + /// + /// 0x70 + /// + AdaptationFieldData, + + /// + /// 0x71 + /// + ServiceIdentifier, + + /// + /// 0x72 + /// + ServiceAvailability, + + /// + /// 0x73 + /// + DefaultAuthority, + + /// + /// 0x74 + /// + RelatedContent, + + /// + /// 0x75 + /// + TVAId, + + /// + /// 0x76 + /// + ContentIdentifier, + + /// + /// 0x77 + /// + TimeSliceFecIdentifier, + + /// + /// 0x78 + /// + ECMRepetitionRate, + + /// + /// 0x7c /// - ECMRepetitionRate, + AAC = 0x7c, /// /// Enthält die Ausstrahlungsdaten einer Sendung des deutschen PayTV /// Anbieters PREMIERE. /// ContentTransmissionPremiere = 0xf2 - } + } } diff --git a/DVB.NET/EPG/Descriptors/AAC.cs b/DVB.NET/EPG/Descriptors/AAC.cs new file mode 100644 index 0000000..0abc26a --- /dev/null +++ b/DVB.NET/EPG/Descriptors/AAC.cs @@ -0,0 +1,129 @@ +using System; +using System.Collections.Generic; + +namespace JMS.DVB.EPG.Descriptors +{ + /// + /// AAC descriptor. + /// + public class AAC : Descriptor + { + /// + /// Profile and level of the content. + /// + public byte ProfileAndLevel { get; set; } + + /// + /// AAC Type of the content. + /// + public byte? Type { get; set; } + + /// + /// Additional information. + /// + private byte[] m_AdditionalInformation = { }; + + /// + /// + /// + public byte[] AdditionalInformation + { + get + { + // Report + return m_AdditionalInformation; + } + set + { + // Never null it + m_AdditionalInformation = value ?? new byte[0]; + } + } + + /// + /// + /// + public AAC(byte profileAndLevel, byte? type) + : base(DescriptorTags.AAC) + { + ProfileAndLevel = profileAndLevel; + Type = type; + } + + /// + /// Create a new descriptor instance. + /// + /// + /// will only be set if the payload is + /// consistent. + /// + /// The related container instance. + /// First byte of the descriptor data - the first byte after the tag. + /// Number of payload bytes for this descriptor. + public AAC(IDescriptorContainer container, int offset, int length) + : base(container, offset, length) + { + // Attach to the section + Section section = container.Section; + + // Check minimum length + if (length-- < 1) return; + + // Read profile and level. + ProfileAndLevel = section[offset++]; + + // Check minimum length + if (length-- < 1) return; + + // Read flags + byte flags = section[offset++]; + + // Load type. + if (0x80 == (0x80 & flags)) + { + // Check minimum length + if (length-- < 1) return; + + Type = section[offset++]; + } + + // Load the additional information + m_AdditionalInformation = section.ReadBytes(offset, length); + + // Done + m_Valid = true; + } + + /// + /// Check if this class is responsible for a given descriptor tag. + /// + /// The tag to test for. + /// Set if this class can handle the payload for the given tag. + public static bool IsHandlerFor(byte tag) => (DescriptorTags.AAC == (DescriptorTags)tag); + + /// + /// + /// + /// + protected override void CreatePayload(TableConstructor buffer) + { + // Profile and level. + buffer.Add(ProfileAndLevel); + + // Collected flags + byte flags = 0; + + // Load flags + if (Type.HasValue) flags |= 0x80; + + // Write flags + buffer.Add(flags); + + // Write all + if (Type.HasValue) buffer.Add(Type.Value); + + // Load the additional information + buffer.Add(m_AdditionalInformation); + } + } +} diff --git a/DVB.NET/EPG/Descriptors/AncillaryData.cs b/DVB.NET/EPG/Descriptors/AncillaryData.cs new file mode 100644 index 0000000..9cc0f9b --- /dev/null +++ b/DVB.NET/EPG/Descriptors/AncillaryData.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; + +namespace JMS.DVB.EPG.Descriptors +{ + /// + /// Ancillary data . + /// + /// + /// For details please refer to the original documentation, + /// e.g. ETSI EN 300 468 V1.6.1 (2004-06) or alternate versions. + /// + public class AncillaryData : Descriptor + { + /// + /// The Data Identifier. + /// + public readonly byte Identifier; + + /// + /// + /// + public AncillaryData(byte identifier) + : base(DescriptorTags.AncillaryData) + { + // Remember + Identifier = identifier; + } + + /// + /// Create a new descriptor instance. + /// + /// + /// will only be set if the payload is + /// consistent. + /// + /// The related container instance. + /// First byte of the descriptor data - the first byte after the tag. + /// Number of payload bytes for this descriptor. + public AncillaryData(IDescriptorContainer container, int offset, int length) + : base(container, offset, length) + { + // Validate size + if (1 != length) return; + + // Attach to data + Section section = container.Section; + + // Load + Identifier = section[offset]; + + // We are valid + m_Valid = true; + } + + /// + /// Check if this class is responsible for a given descriptor tag. + /// + /// The tag to test for. + /// Set if this class can handle the payload for the given tag. + public static bool IsHandlerFor(byte tag) => DescriptorTags.AncillaryData == (DescriptorTags)tag; + + /// + /// + /// + /// + protected override void CreatePayload(TableConstructor buffer) + { + // Add + buffer.Add(Identifier); + } + } +} diff --git a/DVB.NET/EPG/Descriptors/ApplicationSignalling.cs b/DVB.NET/EPG/Descriptors/ApplicationSignalling.cs new file mode 100644 index 0000000..12ef505 --- /dev/null +++ b/DVB.NET/EPG/Descriptors/ApplicationSignalling.cs @@ -0,0 +1,118 @@ +using System; +using System.Collections.Generic; + +namespace JMS.DVB.EPG.Descriptors +{ + /// + /// Application Signalling . + /// + /// + /// For details please refer to the original documentation, + /// e.g. ETSI TS 102 809 V1.3.1 (2017-06) or alternate versions. + /// + public class ApplicationSignalling : Descriptor + { + /// + /// Informationen zu einer einzelnen Anwendung. + /// + public struct Application + { + /// + /// Die Art der Anwendung. + /// + readonly ushort Type; + + /// + /// Die Version der Anwendung. + /// + readonly byte Version; + + /// + /// Erstellt eine neue Information zu einer Anwendung. + /// + /// Die Art der Anwendung. + /// Die Version der Anwendung. + public Application(ushort type, byte version) + { + Type = type; + Version = version; + } + + /// + /// Rekonstruiert die Anewnedungsinformation. + /// + /// Sammelt rekonstruierte Daten. + public void createPayload(TableConstructor buffer) + { + buffer.Add((byte)(Type >> 8)); + buffer.Add((byte)Type); + buffer.Add((byte)(Version | 0xe0)); + } + }; + + /// + /// Alle Anwendungen. + /// + public readonly List Applications = new List(); + + /// + /// + /// + public ApplicationSignalling(params Application[] applications) + : base(DescriptorTags.ApplicationSignalling) + { + Applications.AddRange(applications); + } + + /// + /// Create a new descriptor instance. + /// + /// + /// will only be set if the payload is + /// consistent. + /// + /// The related container instance. + /// First byte of the descriptor data - the first byte after the tag. + /// Number of payload bytes for this descriptor. + public ApplicationSignalling(IDescriptorContainer container, int offset, int length) + : base(container, offset, length) + { + // Attach to data + Section section = container.Section; + + // Readhte list + for (; length >= 3; length -= 3) + { + // Type and version. + var typeH = section[offset++] & 0x7f; + var typeL = section[offset++]; + var version = section[offset++] & 0x1f; + + Applications.Add(new Application((ushort)((typeH << 8) + typeL), (byte)version)); + } + + // Validate size + if (0 != length) return; + + // We are valid + m_Valid = true; + } + + /// + /// Check if this class is responsible for a given descriptor tag. + /// + /// The tag to test for. + /// Set if this class can handle the payload for the given tag. + public static bool IsHandlerFor(byte tag) => DescriptorTags.ApplicationSignalling == (DescriptorTags)tag; + + /// + /// + /// + /// + protected override void CreatePayload(TableConstructor buffer) + { + // Das machen die Anwendungen selbst. + Applications.ForEach(a => a.createPayload(buffer)); + } + } +} diff --git a/DVB.NET/EPG/Descriptors/CarouselIdentifier.cs b/DVB.NET/EPG/Descriptors/CarouselIdentifier.cs new file mode 100644 index 0000000..0e53d37 --- /dev/null +++ b/DVB.NET/EPG/Descriptors/CarouselIdentifier.cs @@ -0,0 +1,103 @@ +using System; +using System.Collections.Generic; + +namespace JMS.DVB.EPG.Descriptors +{ + /// + /// Carousel Identifier . + /// + /// + /// For details please refer to the original documentation, + /// e.g. ETSI TS 102 809 V1.3.1 (2017-06) or alternate versions. + /// + public class CarouselIdentifier : Descriptor + { + /// + /// Identification of the carousel. + /// + public uint Identifier; + + /// + /// Format of the Carousel. + /// + public byte Format; + + /// + /// Nicht weiter ausgewertet Informationen zum Format. + /// + public readonly List RawFormat = new List(); + + /// + /// + /// + public CarouselIdentifier(uint identifier, byte format, params byte[] rawFormat) + : base(DescriptorTags.CarouselIdentifier) + { + Identifier = identifier; + Format = format; + + RawFormat.AddRange(rawFormat); + } + + /// + /// Create a new descriptor instance. + /// + /// + /// will only be set if the payload is + /// consistent. + /// + /// The related container instance. + /// First byte of the descriptor data - the first byte after the tag. + /// Number of payload bytes for this descriptor. + public CarouselIdentifier(IDescriptorContainer container, int offset, int length) + : base(container, offset, length) + { + // Validate size + if (length < 5) return; + + // Attach to data + Section section = container.Section; + + // Load + var id3 = section[offset++]; + var id2 = section[offset++]; + var id1 = section[offset++]; + var id0 = section[offset++]; + + Identifier = (uint)(id0 + 256 * (id1 + 256 * (id2 + 256 * id3))); + Format = section[offset++]; + + // Load the selector bytes. + for (length -= 5; length > 0; length--) + { + RawFormat.Add(section[offset++]); + } + + // We are valid + m_Valid = true; + } + + /// + /// Check if this class is responsible for a given descriptor tag. + /// + /// The tag to test for. + /// Set if this class can handle the payload for the given tag. + public static bool IsHandlerFor(byte tag) => DescriptorTags.CarouselIdentifier == (DescriptorTags)tag; + + /// + /// + /// + /// + protected override void CreatePayload(TableConstructor buffer) + { + buffer.Add((byte)(Identifier >> 24)); + buffer.Add((byte)(Identifier >> 16)); + buffer.Add((byte)(Identifier >> 8)); + buffer.Add((byte)Identifier); + + buffer.Add(Format); + + buffer.Add(RawFormat.ToArray()); + } + } +} diff --git a/DVB.NET/EPG/Descriptors/DataBroadastId.cs b/DVB.NET/EPG/Descriptors/DataBroadastId.cs new file mode 100644 index 0000000..5976fd8 --- /dev/null +++ b/DVB.NET/EPG/Descriptors/DataBroadastId.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections.Generic; + +namespace JMS.DVB.EPG.Descriptors +{ + /// + /// Data Broadcast Identifier . + /// + /// + /// For details please refer to the original documentation, + /// e.g. ETSI EN 300 468 V1.6.1 (2004-06) or alternate versions. + /// + public class DataBroadastId : Descriptor + { + /// + /// Identification of the broadcast. + /// + public ushort Identifier; + + /// + /// Selector Bytes. + /// + public readonly List Selectors = new List(); + + /// + /// + /// + public DataBroadastId(ushort identifier, params byte[] selectors) + : base(DescriptorTags.DataBroadcastId) + { + Identifier = identifier; + + Selectors.AddRange(selectors); + } + + /// + /// Create a new descriptor instance. + /// + /// + /// will only be set if the payload is + /// consistent. + /// + /// The related container instance. + /// First byte of the descriptor data - the first byte after the tag. + /// Number of payload bytes for this descriptor. + public DataBroadastId(IDescriptorContainer container, int offset, int length) + : base(container, offset, length) + { + // Validate size + if (length < 2) return; + + // Attach to data + Section section = container.Section; + + // Load + var idH = section[offset++]; + var idL = section[offset++]; + + Identifier = (ushort)((idH << 8) + idL); + + // Load the selector bytes. + for (length -= 2; length > 0; length--) + { + Selectors.Add(section[offset++]); + } + + // We are valid + m_Valid = true; + } + + /// + /// Check if this class is responsible for a given descriptor tag. + /// + /// The tag to test for. + /// Set if this class can handle the payload for the given tag. + public static bool IsHandlerFor(byte tag) => DescriptorTags.DataBroadcastId == (DescriptorTags)tag; + + /// + /// + /// + /// + protected override void CreatePayload(TableConstructor buffer) + { + buffer.Add(Identifier); + buffer.Add(Selectors.ToArray()); + } + } +} diff --git a/DVB.NET/EPG/Descriptors/Generic.cs b/DVB.NET/EPG/Descriptors/Generic.cs index e0543f5..4ce6f38 100644 --- a/DVB.NET/EPG/Descriptors/Generic.cs +++ b/DVB.NET/EPG/Descriptors/Generic.cs @@ -1,16 +1,22 @@ using System; +using System.Collections.Generic; namespace JMS.DVB.EPG.Descriptors { - /// - /// A generic class used for all unsupported - /// descriptor tags. - /// - /// - /// will always be unset. - /// - public class Generic: Descriptor - { + /// + /// A generic class used for all unsupported + /// descriptor tags. + /// + /// + /// will always be unset. + /// + public class Generic : Descriptor + { + /// + /// Die nicht ausgewerteten Rohdaten - vor allem zu Testzwecken. + /// + public readonly List RawData = new List(); + /// /// Create a new descriptor instance. /// @@ -23,7 +29,11 @@ public class Generic: Descriptor /// Number of payload bytes for this descriptor. public Generic(IDescriptorContainer container, int offset, int length) : base(container, offset, length) - { + { + while (length-- > 0) + { + RawData.Add(container.Section[offset++]); + } } - } + } } diff --git a/DVB.NET/EPG/JMS.DVB.EPG.csproj b/DVB.NET/EPG/JMS.DVB.EPG.csproj index 263abfc..1b2073b 100644 --- a/DVB.NET/EPG/JMS.DVB.EPG.csproj +++ b/DVB.NET/EPG/JMS.DVB.EPG.csproj @@ -127,6 +127,11 @@ + + + + + diff --git a/DVB.NET/EPG/ProgramEntry.cs b/DVB.NET/EPG/ProgramEntry.cs index 0a43d30..be3e839 100644 --- a/DVB.NET/EPG/ProgramEntry.cs +++ b/DVB.NET/EPG/ProgramEntry.cs @@ -1,6 +1,7 @@ using System; using System.Globalization; using System.Collections.Generic; +using System.Linq; namespace JMS.DVB.EPG { @@ -12,7 +13,7 @@ public class ProgramEntry : EntryBase /// /// Maps ISO language names to their native representation. /// - private static Dictionary m_CultureMap = new Dictionary( StringComparer.InvariantCultureIgnoreCase ); + private static Dictionary m_CultureMap = new Dictionary(StringComparer.InvariantCultureIgnoreCase); /// /// The constructor is private to make this class static. @@ -20,35 +21,35 @@ public class ProgramEntry : EntryBase static ProgramEntry() { // Load all - foreach (CultureInfo info in CultureInfo.GetCultures( CultureTypes.NeutralCultures )) + foreach (CultureInfo info in CultureInfo.GetCultures(CultureTypes.NeutralCultures)) { // Remember m_CultureMap[info.ThreeLetterISOLanguageName] = info; } // Add special entries (bibliographic - see ISO639-2) - AddBibliographicShortcut( "bod", "tib" ); - AddBibliographicShortcut( "ces", "cze" ); - AddBibliographicShortcut( "cym", "wel" ); - AddBibliographicShortcut( "deu", "ger" ); - AddBibliographicShortcut( "ell", "gre" ); - AddBibliographicShortcut( "eus", "baq" ); - AddBibliographicShortcut( "fas", "per" ); - AddBibliographicShortcut( "fra", "fre" ); - AddBibliographicShortcut( "hrv", "scr" ); - AddBibliographicShortcut( "hye", "arm" ); - AddBibliographicShortcut( "isl", "ice" ); - AddBibliographicShortcut( "kat", "geo" ); - AddBibliographicShortcut( "mkd", "mac" ); - AddBibliographicShortcut( "mri", "mao" ); - AddBibliographicShortcut( "msa", "may" ); - AddBibliographicShortcut( "mya", "bur" ); - AddBibliographicShortcut( "nld", "dut" ); - AddBibliographicShortcut( "ron", "rum" ); - AddBibliographicShortcut( "slk", "slo" ); - AddBibliographicShortcut( "sqi", "alb" ); - AddBibliographicShortcut( "srp", "scc" ); - AddBibliographicShortcut( "zho", "chi" ); + AddBibliographicShortcut("bod", "tib"); + AddBibliographicShortcut("ces", "cze"); + AddBibliographicShortcut("cym", "wel"); + AddBibliographicShortcut("deu", "ger"); + AddBibliographicShortcut("ell", "gre"); + AddBibliographicShortcut("eus", "baq"); + AddBibliographicShortcut("fas", "per"); + AddBibliographicShortcut("fra", "fre"); + AddBibliographicShortcut("hrv", "scr"); + AddBibliographicShortcut("hye", "arm"); + AddBibliographicShortcut("isl", "ice"); + AddBibliographicShortcut("kat", "geo"); + AddBibliographicShortcut("mkd", "mac"); + AddBibliographicShortcut("mri", "mao"); + AddBibliographicShortcut("msa", "may"); + AddBibliographicShortcut("mya", "bur"); + AddBibliographicShortcut("nld", "dut"); + AddBibliographicShortcut("ron", "rum"); + AddBibliographicShortcut("slk", "slo"); + AddBibliographicShortcut("sqi", "alb"); + AddBibliographicShortcut("srp", "scc"); + AddBibliographicShortcut("zho", "chi"); } /// @@ -56,15 +57,15 @@ static ProgramEntry() /// /// Official three letter code. /// Alternat (bibliographic) three letter code. - private static void AddBibliographicShortcut( string terminologyCode, string bibliographicCode ) + private static void AddBibliographicShortcut(string terminologyCode, string bibliographicCode) { // See if code already exists - if (m_CultureMap.ContainsKey( bibliographicCode )) + if (m_CultureMap.ContainsKey(bibliographicCode)) return; // Load entry CultureInfo terminologic; - if (!m_CultureMap.TryGetValue( terminologyCode, out terminologic )) + if (!m_CultureMap.TryGetValue(terminologyCode, out terminologic)) return; // Connect @@ -109,20 +110,20 @@ private static void AddBibliographicShortcut( string terminologyCode, string bib /// The maximum number of bytes available. If this number /// is greater than the of this program another event will /// follow in the same table. - internal ProgramEntry( Table table, int offset, int length ) - : base( table ) + internal ProgramEntry(Table table, int offset, int length) + : base(table) { // Access section Section section = Section; // Load - ElementaryPID = (ushort) (0x1fff & Tools.MergeBytesToWord( section[offset + 2], section[offset + 1] )); - StreamType = (StreamTypes) section[offset + 0]; + ElementaryPID = (ushort)(0x1fff & Tools.MergeBytesToWord(section[offset + 2], section[offset + 1])); + StreamType = (StreamTypes)section[offset + 0]; // Read the length - int descrLength = 0xfff & Tools.MergeBytesToWord( section[offset + 4], section[offset + 3] ); + int descrLength = 0xfff & Tools.MergeBytesToWord(section[offset + 4], section[offset + 3]); - // Caluclate the total length + // Calculate the total length Length = 5 + descrLength; // Verify @@ -130,7 +131,7 @@ internal ProgramEntry( Table table, int offset, int length ) return; // Try to load descriptors - Descriptors = Descriptor.Load( this, offset + 5, descrLength ); + Descriptors = Descriptor.Load(this, offset + 5, descrLength); // Can use it IsValid = true; @@ -147,14 +148,14 @@ internal ProgramEntry( Table table, int offset, int length ) /// follow in the same table. /// A new service instance or null if there are less than /// 5 bytes available. - static internal ProgramEntry Create( Table table, int offset, int length ) + static internal ProgramEntry Create(Table table, int offset, int length) { // Validate if (length < 5) return null; // Create - return new ProgramEntry( table, offset, length ); + return new ProgramEntry(table, offset, length); } /// @@ -176,15 +177,15 @@ public string ProgrammeName // Remember the first one set string name = language.Languages[0].ISOLanguage; - if (string.IsNullOrEmpty( name )) + if (string.IsNullOrEmpty(name)) continue; // Convert - return GetLanguageFromISOLanguage( name ); + return GetLanguageFromISOLanguage(name); } // Use default - return string.Format( "#{0}", ElementaryPID ); + return string.Format("#{0}", ElementaryPID); } } @@ -194,11 +195,11 @@ public string ProgrammeName /// /// Eine ISO Kurzbezeichnung. /// Der Name der Sprache, ausgerückt in der Sprache selbst. - public static string GetLanguageFromISOLanguage( string language ) + public static string GetLanguageFromISOLanguage(string language) { // Find CultureInfo cult; - if (m_CultureMap.TryGetValue( language, out cult )) + if (m_CultureMap.TryGetValue(language, out cult)) return cult.NativeName; // Report as is diff --git a/DVB.NET/EPG/StreamTypes.cs b/DVB.NET/EPG/StreamTypes.cs index 54c3d13..709f44b 100644 --- a/DVB.NET/EPG/StreamTypes.cs +++ b/DVB.NET/EPG/StreamTypes.cs @@ -8,7 +8,7 @@ namespace JMS.DVB.EPG /// The type of a transport stream. /// public enum StreamTypes - { + { /// /// ITU-T | ISO/IEC Reserved /// @@ -67,7 +67,7 @@ public enum StreamTypes /// /// ISO/IEC 13818-6 type B /// - TypeB, + Carousel, /// /// ISO/IEC 13818-6 type C @@ -77,17 +77,22 @@ public enum StreamTypes /// /// ISO/IEC 13818-6 type D /// - TypeD, + MultiProtocolDataStream, /// /// ISO/IEC 13818-1 auxiliary /// Auxiliary, - /// - /// Intermediate entry for H.264 video. + /// + /// Intermediate entry for AAC Audio. /// - H264 = 0x1b, + AAC = 0x11, + + /// + /// Intermediate entry for H.264 video. + /// + H264 = 0x1b, /// /// ITU-T Rec. H.222.0 | ISO/IEC 13818-1 Reserved, lowest value @@ -108,5 +113,5 @@ public enum StreamTypes /// User Private, highest value /// UserPrivateHigh = 0xff - } + } } diff --git a/DVB.NET/HardwareAbstraction/SourceStreamsManager.cs b/DVB.NET/HardwareAbstraction/SourceStreamsManager.cs index 30a4ad5..70c6770 100644 --- a/DVB.NET/HardwareAbstraction/SourceStreamsManager.cs +++ b/DVB.NET/HardwareAbstraction/SourceStreamsManager.cs @@ -154,15 +154,15 @@ public class SourceStreamsManager : IDisposable /// Die Quelle, die zu betrachten ist. /// Die zu betrachtenden Datenströme. /// Ein Parameter wurde nicht angegeben. - public SourceStreamsManager( Hardware hardware, Profile profile, SourceIdentifier source, StreamSelection selection ) + public SourceStreamsManager(Hardware hardware, Profile profile, SourceIdentifier source, StreamSelection selection) { // Validate if (null == hardware) - throw new ArgumentNullException( "hardware" ); + throw new ArgumentNullException("hardware"); if (null == source) - throw new ArgumentNullException( "source" ); + throw new ArgumentNullException("source"); if (null == selection) - throw new ArgumentNullException( "selection" ); + throw new ArgumentNullException("selection"); // Remember all StreamSelection = selection; @@ -175,13 +175,13 @@ public SourceStreamsManager( Hardware hardware, Profile profile, SourceIdentifie /// Startet das Auslesen der aktuellen Daten zur aktiven Quelle im Hintergrund. /// /// Eine Steuerinstanz zum asynchronen Zugriff auf die aktuellen Daten. - public CancellableTask GetCurrentInformationAsync() => Hardware.GetSourceInformationAsync( Source, Profile ); + public CancellableTask GetCurrentInformationAsync() => Hardware.GetSourceInformationAsync(Source, Profile); /// /// Ermittelt die aktuellen Daten zur aktiven Quelle. /// /// Die neu ermittelten aktuellen Daten. - public SourceInformation GetCurrentInformation() => GetCurrentInformationAsync().CancelAfter( 5000 ).Result; + public SourceInformation GetCurrentInformation() => GetCurrentInformationAsync().CancelAfter(5000).Result; /// /// Meldet die aktuell verwendeten Daten der Quelle. @@ -213,7 +213,7 @@ public Action OnWritingPCR /// Optional die Angabe eines Dateinames. /// Gesetzt, wenn die Quelle bekannt ist und der Empfang aktiviert wurde. /// Es ist bereits eine Aufzeichnung aktiv. - public bool CreateStream( string filePath ) => CreateStream( filePath, null ); + public bool CreateStream(string filePath) => CreateStream(filePath, null); /// /// Beginnt die Aufzeichnung in einen Transport Stream - optional als @@ -223,7 +223,7 @@ public Action OnWritingPCR /// Die aktuelle Konfiguration der Quelle oder null, wenn keine bekannt ist. /// Gesetzt, wenn die Quelle bekannt ist und der Empfang aktiviert wurde. /// Es ist bereits eine Aufzeichnung aktiv. - public bool CreateStream( string filePath, SourceInformation info ) + public bool CreateStream(string filePath, SourceInformation info) { // Validate if (m_TransportStream != null) @@ -243,13 +243,13 @@ public bool CreateStream( string filePath, SourceInformation info ) return false; // Forward - CreateStream( NextStreamIdentifier, false ); + CreateStream(NextStreamIdentifier, false); // Update signature - m_CurrentSignature = CreateRecordingSignature( m_OriginalSettings ); + m_CurrentSignature = CreateRecordingSignature(m_OriginalSettings); // Activate streaming - if (!string.IsNullOrEmpty( m_LastStreamTarget )) + if (!string.IsNullOrEmpty(m_LastStreamTarget)) StreamingTarget = m_LastStreamTarget; // Did it @@ -294,27 +294,27 @@ public string StreamingTarget set { // Check mode - if (string.IsNullOrEmpty( value )) + if (string.IsNullOrEmpty(value)) { // Clear if (null != m_TransportStream) - m_TransportStream.SetStreamTarget( string.Empty, 0 ); + m_TransportStream.SetStreamTarget(string.Empty, 0); } else { // Split - var parts = value.Split( ':' ); + var parts = value.Split(':'); if (2 != parts.Length) - throw new ArgumentException( value, "value" ); + throw new ArgumentException(value, "value"); // Get port ushort port; - if (!ushort.TryParse( parts[1], out port )) - throw new ArgumentException( value, "value" ); + if (!ushort.TryParse(parts[1], out port)) + throw new ArgumentException(value, "value"); // Update if (null != m_TransportStream) - m_TransportStream.SetStreamTarget( parts[0], port ); + m_TransportStream.SetStreamTarget(parts[0], port); } // Remember @@ -375,7 +375,7 @@ public int ConsumerCount /// /// Die aktuellen Daten zur zugehörigen Quelle. /// Ein Schlüssel passend zur aktuellen Aufzeichnung. - private string CreateRecordingSignature( SourceInformation information ) + private string CreateRecordingSignature(SourceInformation information) { // All keys - will be sorted to make sure that lists are ordered var flags = new List(); @@ -395,8 +395,8 @@ private string CreateRecordingSignature( SourceInformation information ) var videoType = (information.VideoType == VideoTypes.H264) ? EPG.StreamTypes.H264 : EPG.StreamTypes.Video13818; // Register - flags.Add( Offset_VideoType + (int) videoType ); - flags.Add( Offset_VideoPID + (int) information.VideoStream ); + flags.Add(Offset_VideoType + (int)videoType); + flags.Add(Offset_VideoPID + (int)information.VideoStream); } // All MP2 audio @@ -405,15 +405,15 @@ private string CreateRecordingSignature( SourceInformation information ) if (StreamSelection.MP2Tracks.LanguageMode == LanguageModes.Primary) { // Add as is - flags.Add( Offset_MP2PID + (int) audio.AudioStream ); + flags.Add(Offset_MP2PID + (int)audio.AudioStream); // Finish break; } - else if (StreamSelection.MP2Tracks.Contains( audio.Language )) + else if (StreamSelection.MP2Tracks.Contains(audio.Language)) { // Add as is - flags.Add( Offset_MP2PID + (int) audio.AudioStream ); + flags.Add(Offset_MP2PID + (int)audio.AudioStream); } // All AC3 audio @@ -422,21 +422,21 @@ private string CreateRecordingSignature( SourceInformation information ) if (StreamSelection.AC3Tracks.LanguageMode == LanguageModes.Primary) { // Add as is - flags.Add( Offset_AC3PID + (int) audio.AudioStream ); + flags.Add(Offset_AC3PID + (int)audio.AudioStream); // Finish break; } - else if (StreamSelection.AC3Tracks.Contains( audio.Language )) + else if (StreamSelection.AC3Tracks.Contains(audio.Language)) { // Add as is - flags.Add( Offset_AC3PID + (int) audio.AudioStream ); + flags.Add(Offset_AC3PID + (int)audio.AudioStream); } // Videotext if (StreamSelection.Videotext) if (0 != information.TextStream) - flags.Add( Offset_TTXPID + (int) information.TextStream ); + flags.Add(Offset_TTXPID + (int)information.TextStream); // Subtitle streams var subtitles = new Dictionary(); @@ -451,7 +451,7 @@ private string CreateRecordingSignature( SourceInformation information ) // Finish break; } - else if (StreamSelection.SubTitles.Contains( subtitle.Language )) + else if (StreamSelection.SubTitles.Contains(subtitle.Language)) { // Add as is subtitles[subtitle.SubtitleStream] = true; @@ -459,10 +459,10 @@ private string CreateRecordingSignature( SourceInformation information ) // Process all subtitles foreach (var subtitleStream in subtitles.Keys) - flags.Add( Offset_SUBPID + (int) subtitleStream ); + flags.Add(Offset_SUBPID + (int)subtitleStream); // Create the key - return (information.IsEncrypted ? "+" : "-") + string.Join( ".", flags.ConvertAll( f => f.ToString( "x5" ) ).ToArray() ); + return (information.IsEncrypted ? "+" : "-") + string.Join(".", flags.ConvertAll(f => f.ToString("x5")).ToArray()); } /// @@ -474,7 +474,7 @@ private string CreateRecordingSignature( SourceInformation information ) /// Prüft, ob sich an der Konfiguration der Quelle etwas verändert hat. /// /// Gesetzt, wenn nun der Empfang aktiv ist. - public bool RetestSourceInformation() => RetestSourceInformation( GetCurrentInformation() ); + public bool RetestSourceInformation() => RetestSourceInformation(GetCurrentInformation()); /// /// Prüft, ob sich an der Konfiguration der Quelle etwas verändert hat. @@ -483,7 +483,7 @@ private string CreateRecordingSignature( SourceInformation information ) /// Gesetzt, wenn nun der Empfang aktiv ist. /// Der angegebenen Konfiguration ist keine Quelle zugeordnet. /// Die Konfiguration gehört zu einer anderen Quelle als der aktuellen. - public bool RetestSourceInformation( SourceInformation information ) + public bool RetestSourceInformation(SourceInformation information) { // Must get the current source information if (information == null) @@ -497,24 +497,24 @@ public bool RetestSourceInformation( SourceInformation information ) // Validate if (information.Source == null) - throw new ArgumentNullException( "information.Source" ); - if (!information.Source.Equals( Source )) - throw new ArgumentException( information.Source.ToString(), "information.Source" ); + throw new ArgumentNullException("information.Source"); + if (!information.Source.Equals(Source)) + throw new ArgumentException(information.Source.ToString(), "information.Source"); // Nothing changed - var signature = CreateRecordingSignature( information ); + var signature = CreateRecordingSignature(information); if (m_TransportStream != null) { // No need to switch - if (signature.Equals( m_CurrentSignature )) + if (signature.Equals(m_CurrentSignature)) return true; // Report to see what happened - if (!string.IsNullOrEmpty( m_CurrentSignature )) + if (!string.IsNullOrEmpty(m_CurrentSignature)) try { // Report and ignore - EventLog.WriteEntry( "DVB.NET", $"Detected PSI Change: {m_CurrentSignature} => {signature}", EventLogEntryType.Information ); + EventLog.WriteEntry("DVB.NET", $"Detected PSI Change: {m_CurrentSignature} => {signature}", EventLogEntryType.Information); } catch { @@ -535,7 +535,7 @@ public bool RetestSourceInformation( SourceInformation information ) if (BeforeRecreateStream != null) { // Request new stream configuration - var newSelection = BeforeRecreateStream( this ); + var newSelection = BeforeRecreateStream(this); if (newSelection == null) return false; @@ -544,7 +544,7 @@ public bool RetestSourceInformation( SourceInformation information ) } // Forward - CreateStream( NextStreamIdentifier, true ); + CreateStream(NextStreamIdentifier, true); // Reactivate streaming if (streamTarget != null) @@ -561,7 +561,7 @@ public bool RetestSourceInformation( SourceInformation information ) /// Die erste Datenstromkennung (PID), die in der Aufzeichnungsdatei verwendet werden darf. /// Gesetzt, wenn ein Neustart aufgrund veränderter Nutzdatenströme erforderlich wurde. /// Eine Aufzeichnung der angegebenen Quelle ist nicht möglich. - private void CreateStream( short nextPID, bool recreate ) + private void CreateStream(short nextPID, bool recreate) { // Try to get the full name var filePath = m_OriginalPath; @@ -569,12 +569,12 @@ private void CreateStream( short nextPID, bool recreate ) if (m_FileCount > 0) { // Split off the parts - var name = Path.GetFileNameWithoutExtension( filePath ); - var dir = Path.GetDirectoryName( filePath ); - var ext = Path.GetExtension( filePath ); + var name = Path.GetFileNameWithoutExtension(filePath); + var dir = Path.GetDirectoryName(filePath); + var ext = Path.GetExtension(filePath); // Construct new name - filePath = Path.Combine( dir, $"{name} - {m_FileCount}{ext}" ); + filePath = Path.Combine(dir, $"{name} - {m_FileCount}{ext}"); } // Try to decrypt @@ -582,7 +582,7 @@ private void CreateStream( short nextPID, bool recreate ) try { // Process - Hardware.Decrypt( Source ); + Hardware.Decrypt(Source); } catch { @@ -600,10 +600,10 @@ private void CreateStream( short nextPID, bool recreate ) videoType = (m_OriginalSettings.VideoType == VideoTypes.H264) ? EPG.StreamTypes.H264 : EPG.StreamTypes.Video13818; // Get the buffer size - var bufferSize = (FileBufferSizeChooser == null) ? null : FileBufferSizeChooser( videoType ); + var bufferSize = (FileBufferSizeChooser == null) ? null : FileBufferSizeChooser(videoType); // Create the new stream - m_TransportStream = new Manager( filePath, nextPID, bufferSize.GetValueOrDefault( Manager.DefaultBufferSize ) ); + m_TransportStream = new Manager(filePath, nextPID, bufferSize.GetValueOrDefault(Manager.DefaultBufferSize)); // Attach PCR sink m_TransportStream.OnWritingPCR = m_WritePCRSink; @@ -616,18 +616,18 @@ private void CreateStream( short nextPID, bool recreate ) { // Video first if (videoType.HasValue) - AddConsumer( m_OriginalSettings.VideoStream, StreamTypes.Video, m_TransportStream.AddVideo( (byte) videoType.Value ) ); + AddConsumer(m_OriginalSettings.VideoStream, StreamTypes.Video, m_TransportStream.AddVideo((byte)videoType.Value)); // Select audio - ProcessAudioSelection( AudioTypes.MP2, result.MP2Tracks, StreamSelection.MP2Tracks ); - ProcessAudioSelection( AudioTypes.AC3, result.AC3Tracks, StreamSelection.AC3Tracks ); + ProcessAudioSelection(AudioTypes.MP2, result.MP2Tracks, StreamSelection.MP2Tracks); + ProcessAudioSelection(AudioTypes.AC3, result.AC3Tracks, StreamSelection.AC3Tracks); // Videotext if (StreamSelection.Videotext) if (0 != m_OriginalSettings.TextStream) { // Register - AddConsumer( m_OriginalSettings.TextStream, StreamTypes.VideoText, m_TransportStream.AddTeleText() ); + AddConsumer(m_OriginalSettings.TextStream, StreamTypes.VideoText, m_TransportStream.AddTeleText()); // Remember result.Videotext = true; @@ -647,26 +647,26 @@ private void CreateStream( short nextPID, bool recreate ) if (StreamSelection.SubTitles.LanguageMode == LanguageModes.Primary) { // Attach to the list - AddSubtitleInformation( subtitle, subtitles ); + AddSubtitleInformation(subtitle, subtitles); // Copy over result.SubTitles.LanguageMode = LanguageModes.Primary; // Remember - result.SubTitles.Languages.Add( subtitle.Language ); + result.SubTitles.Languages.Add(subtitle.Language); // Done break; } // Standard selection - if (StreamSelection.SubTitles.Contains( subtitle.Language )) + if (StreamSelection.SubTitles.Contains(subtitle.Language)) { // Attach to the list - AddSubtitleInformation( subtitle, subtitles ); + AddSubtitleInformation(subtitle, subtitles); // Remember - result.SubTitles.Languages.Add( subtitle.Language ); + result.SubTitles.Languages.Add(subtitle.Language); } else { @@ -682,7 +682,7 @@ private void CreateStream( short nextPID, bool recreate ) // Process all subtitles foreach (var current in subtitles) - AddConsumer( current.Key, StreamTypes.SubTitle, m_TransportStream.AddSubtitles( current.Value.ToArray() ) ); + AddConsumer(current.Key, StreamTypes.SubTitle, m_TransportStream.AddSubtitles(current.Value.ToArray())); // See if program guide is requested bool epg = StreamSelection.ProgramGuide; @@ -692,17 +692,17 @@ private void CreateStream( short nextPID, bool recreate ) if ((Hardware.Profile != null) && Hardware.Profile.DisableProgramGuide) epg = false; else if (Profile != null) - if (Profile.GetFilter( Source ).DisableProgramGuide) + if (Profile.GetFilter(Source).DisableProgramGuide) epg = false; // EPG if (epg) { // Activate dispatch - m_TransportStream.SetEPGMapping( Source.Network, Source.TransportStream, Source.Service ); + m_TransportStream.SetEPGMapping(Source.Network, Source.TransportStream, Source.Service); // Start it - Hardware.AddProgramGuideConsumer( DispatchEPG ); + Hardware.AddProgramGuideConsumer(DispatchEPG); // Remember result.ProgramGuide = true; @@ -717,7 +717,7 @@ private void CreateStream( short nextPID, bool recreate ) try { // Forward - Hardware.SetConsumerState( consumer, true ); + Hardware.SetConsumerState(consumer, true); // Count it ++started; @@ -725,20 +725,20 @@ private void CreateStream( short nextPID, bool recreate ) catch (OutOfConsumersException) { // Translate - throw new OutOfConsumersException( m_Consumers.Count, started ) { RequestedSelection = result }; + throw new OutOfConsumersException(m_Consumers.Count, started) { RequestedSelection = result }; } } catch { // Detach EPG - Hardware.RemoveProgramGuideConsumer( DispatchEPG ); + Hardware.RemoveProgramGuideConsumer(DispatchEPG); // Cleanup on all errors foreach (var consumer in m_Consumers) try { // Remove - Hardware.SetConsumerState( consumer, null ); + Hardware.SetConsumerState(consumer, null); } catch { @@ -751,7 +751,7 @@ private void CreateStream( short nextPID, bool recreate ) // Remember path if (filePath != null) - m_AllFiles.Add( new FileStreamInformation { FilePath = filePath, VideoType = m_OriginalSettings.VideoType } ); + m_AllFiles.Add(new FileStreamInformation { FilePath = filePath, VideoType = m_OriginalSettings.VideoType }); // Remember the time LastActivationTime = DateTime.UtcNow; @@ -777,7 +777,7 @@ private void CreateStream( short nextPID, bool recreate ) // Report if (createNotify != null) - createNotify( this ); + createNotify(this); } /// @@ -785,7 +785,7 @@ private void CreateStream( short nextPID, bool recreate ) /// /// Die neue Aufzeichnungsdatei. /// Gesetzt, wenn die Trennung erfolgreich angenommen wurde. - public bool SplitFile( string newPath ) + public bool SplitFile(string newPath) { // No stream active if (m_TransportStream == null) @@ -806,17 +806,17 @@ public bool SplitFile( string newPath ) try { // Do the split - m_TransportStream.SplitFile( newPath ); + m_TransportStream.SplitFile(newPath); // Create new entry - m_AllFiles.Add( new FileStreamInformation { FilePath = newPath, VideoType = last.VideoType } ); + m_AllFiles.Add(new FileStreamInformation { FilePath = newPath, VideoType = last.VideoType }); // Attach to clients var createNotify = OnCreatedStream; // Report if (createNotify != null) - createNotify( this ); + createNotify(this); // Did it return true; @@ -833,11 +833,11 @@ public bool SplitFile( string newPath ) /// /// Die Untertitelspur. /// Alle bisher aufgenommenen Spuren. - private void AddSubtitleInformation( SubtitleInformation subtitle, Dictionary> subtitles ) + private void AddSubtitleInformation(SubtitleInformation subtitle, Dictionary> subtitles) { // Attach to the list List list; - if (!subtitles.TryGetValue( subtitle.SubtitleStream, out list )) + if (!subtitles.TryGetValue(subtitle.SubtitleStream, out list)) { // Create new list = new List(); @@ -851,10 +851,10 @@ private void AddSubtitleInformation( SubtitleInformation subtitle, Dictionary @@ -863,15 +863,8 @@ private void AddSubtitleInformation( SubtitleInformation subtitle, DictionaryDie gewünschte Art der Tonspur. /// Die aktive Auswahl der Tonspuren. /// Die gewünschten Sprachen. - private void ProcessAudioSelection( AudioTypes type, LanguageSelection selected, LanguageSelection requested ) + private void ProcessAudioSelection(AudioTypes type, LanguageSelection selected, LanguageSelection requested) { - // Get method for adding streams - Func addConsumer; - if (type == AudioTypes.MP2) - addConsumer = m_TransportStream.AddAudio; - else - addConsumer = m_TransportStream.AddDolby; - // Preset mode selected.LanguageMode = LanguageModes.All; @@ -883,26 +876,40 @@ private void ProcessAudioSelection( AudioTypes type, LanguageSelection selected, if (requested.LanguageMode == LanguageModes.Primary) { // Register - AddConsumer( audio.AudioStream, StreamTypes.Audio, addConsumer( audio.Language.ToISOLanguage() ) ); + if (type == AudioTypes.MP2) + { + AddConsumer(audio.AudioStream, StreamTypes.Audio, m_TransportStream.AddAudio(audio.Language.ToISOLanguage(), audio.AAC)); + } + else + { + AddConsumer(audio.AudioStream, StreamTypes.Audio, m_TransportStream.AddDolby(audio.Language.ToISOLanguage())); + } // Copy over selected.LanguageMode = LanguageModes.Primary; // Remember - selected.Languages.Add( audio.Language ); + selected.Languages.Add(audio.Language); // Done return; } // Regular test - if (requested.Contains( audio.Language )) + if (requested.Contains(audio.Language)) { // Register - AddConsumer( audio.AudioStream, StreamTypes.Audio, addConsumer( audio.Language.ToISOLanguage() ) ); + if (type == AudioTypes.MP2) + { + AddConsumer(audio.AudioStream, StreamTypes.Audio, m_TransportStream.AddAudio(audio.Language.ToISOLanguage(), audio.AAC)); + } + else + { + AddConsumer(audio.AudioStream, StreamTypes.Audio, m_TransportStream.AddDolby(audio.Language.ToISOLanguage())); + } // Remember - selected.Languages.Add( audio.Language ); + selected.Languages.Add(audio.Language); } else { @@ -926,14 +933,14 @@ private void ProcessAudioSelection( AudioTypes type, LanguageSelection selected, /// Übermittelt die Daten zur Programmzeitschrift. /// /// Eine Tabelle der Programmzeitschrift. - private void DispatchEPG( EIT table ) + private void DispatchEPG(EIT table) { // Be safe try { // Forward if (null != m_TransportStream) - m_TransportStream.AddEventTable( table.Table ); + m_TransportStream.AddEventTable(table.Table); } catch { @@ -947,7 +954,7 @@ private void DispatchEPG( EIT table ) /// Die gewünschte Datestromkennung (PID). /// Die Art der Nutzdaten im Datenstrom. /// Der Empfänger der Daten. - private void AddConsumer( ushort pid, StreamTypes type, StreamBase stream ) => m_Consumers.Add( Hardware.AddConsumer( pid, type, stream.AddPayload ) ); + private void AddConsumer(ushort pid, StreamTypes type, StreamBase stream) => m_Consumers.Add(Hardware.AddConsumer(pid, type, stream.AddPayload)); /// /// Beendet die Aufzeichnung in eine Datei. @@ -974,14 +981,14 @@ public void CloseStream() ++m_FileCount; // Stop EPG receiver - Hardware.RemoveProgramGuideConsumer( DispatchEPG ); + Hardware.RemoveProgramGuideConsumer(DispatchEPG); // Stop all consumers foreach (var consumer in m_Consumers) try { // Try to stop the individual stream - Hardware.SetConsumerState( consumer, null ); + Hardware.SetConsumerState(consumer, null); } catch { diff --git a/DVB.NET/HardwareAbstraction/TableExtensions.cs b/DVB.NET/HardwareAbstraction/TableExtensions.cs index f2b3f67..f1c6afc 100644 --- a/DVB.NET/HardwareAbstraction/TableExtensions.cs +++ b/DVB.NET/HardwareAbstraction/TableExtensions.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Linq; using JMS.DVB.SI; - +using JMS.DVB.EPG.Descriptors; namespace JMS.DVB { @@ -21,16 +21,16 @@ public static class TableExtensions /// Die Methode, an die alle erkannten SI Tabellen der gewünschten Art gemeldet werden. /// Die eindeutige Kennung des neu angemeldeten Verbrauchers. /// Die Hardware Abstraktion und / oder der Verbraucher sind nicht gesetzt. - public static Guid AddConsumer( this Hardware provider, ushort stream, Action consumer ) where T : Table + public static Guid AddConsumer(this Hardware provider, ushort stream, Action consumer) where T : Table { // Validate if (null == provider) - throw new ArgumentNullException( "provider" ); + throw new ArgumentNullException("provider"); if (null == consumer) - throw new ArgumentNullException( "consumer" ); + throw new ArgumentNullException("consumer"); // Forward - return provider.AddConsumer( stream, TableParser.Create( consumer ), Table.GetIsExtendedTable() ? StreamTypes.ExtendedTable : StreamTypes.StandardTable ); + return provider.AddConsumer(stream, TableParser.Create(consumer), Table.GetIsExtendedTable() ? StreamTypes.ExtendedTable : StreamTypes.StandardTable); } /// @@ -42,19 +42,19 @@ public static Guid AddConsumer( this Hardware provider, ushort stream, Action /// Die Methode, an die alle erkannten SI Tabellen der gewünschten Art gemeldet werden. /// Die eindeutige Kennung des neu angemeldeten Verbrauchers. /// Die Hardware Abstraktion und / oder der Verbraucher sind nicht gesetzt. - public static Guid AddConsumer( this Hardware provider, Action consumer ) where T : WellKnownTable + public static Guid AddConsumer(this Hardware provider, Action consumer) where T : WellKnownTable { // Validate if (null == provider) - throw new ArgumentNullException( "provider" ); + throw new ArgumentNullException("provider"); if (null == consumer) - throw new ArgumentNullException( "consumer" ); + throw new ArgumentNullException("consumer"); // Read the stream ushort stream = WellKnownTable.GetWellKnownStream(); // Forward - return provider.AddConsumer( stream, TableParser.Create( consumer ), Table.GetIsExtendedTable() ? StreamTypes.ExtendedTable : StreamTypes.StandardTable ); + return provider.AddConsumer(stream, TableParser.Create(consumer), Table.GetIsExtendedTable() ? StreamTypes.ExtendedTable : StreamTypes.StandardTable); } /// @@ -66,10 +66,10 @@ public static Guid AddConsumer( this Hardware provider, Action consumer ) /// Die eindeutige Kennung des neu angemeldeten Verbrauchers. /// Die Hardware Abstraktion und / oder die Analyseinstanz /// sind nicht gesetzt. - public static Guid AddConsumer( this Hardware provider, ushort stream, TableParser parser ) + public static Guid AddConsumer(this Hardware provider, ushort stream, TableParser parser) { // Forward - return provider.AddConsumer( stream, parser, StreamTypes.StandardTable ); + return provider.AddConsumer(stream, parser, StreamTypes.StandardTable); } /// @@ -82,16 +82,16 @@ public static Guid AddConsumer( this Hardware provider, ushort stream, TablePars /// Die eindeutige Kennung der neu angemeldeten Analyseeinheit. /// Die Hardware Abstraktion und / oder die Analyseinstanz /// sind nicht gesetzt. - public static Guid AddConsumer( this Hardware provider, ushort stream, TableParser parser, StreamTypes streamType ) + public static Guid AddConsumer(this Hardware provider, ushort stream, TableParser parser, StreamTypes streamType) { // Validate if (null == provider) - throw new ArgumentNullException( "provider" ); + throw new ArgumentNullException("provider"); if (null == parser) - throw new ArgumentNullException( "parser" ); + throw new ArgumentNullException("parser"); // Register - return provider.AddConsumer( stream, streamType, parser.AddPayload ); + return provider.AddConsumer(stream, streamType, parser.AddPayload); } /// @@ -101,10 +101,10 @@ public static Guid AddConsumer( this Hardware provider, ushort stream, TablePars /// Die maximale Wartezeit auf die Informationen in Millisekunden. /// Die gewünschten Informationen oder null, wenn diese in der angegebenen /// Zeit nicht bereit gestellt werden konnten. - public static SatelliteLocationInformation GetLocationInformation( this SatelliteHardware provider, int milliSeconds ) + public static SatelliteLocationInformation GetLocationInformation(this SatelliteHardware provider, int milliSeconds) { // Forward - return (SatelliteLocationInformation) ((Hardware) provider).GetLocationInformation( milliSeconds ); + return (SatelliteLocationInformation)((Hardware)provider).GetLocationInformation(milliSeconds); } /// @@ -114,10 +114,10 @@ public static SatelliteLocationInformation GetLocationInformation( this Satellit /// Die maximale Wartezeit auf die Informationen in Millisekunden. /// Die gewünschten Informationen oder null, wenn diese in der angegebenen /// Zeit nicht bereit gestellt werden konnten. - public static CableLocationInformation GetLocationInformation( this CableHardware provider, int milliSeconds ) + public static CableLocationInformation GetLocationInformation(this CableHardware provider, int milliSeconds) { // Forward - return (CableLocationInformation) ((Hardware) provider).GetLocationInformation( milliSeconds ); + return (CableLocationInformation)((Hardware)provider).GetLocationInformation(milliSeconds); } /// @@ -127,10 +127,10 @@ public static CableLocationInformation GetLocationInformation( this CableHardwar /// Die maximale Wartezeit auf die Informationen in Millisekunden. /// Die gewünschten Informationen oder null, wenn diese in der angegebenen /// Zeit nicht bereit gestellt werden konnten. - public static TerrestrialLocationInformation GetLocationInformation( this TerrestrialHardware provider, int milliSeconds ) + public static TerrestrialLocationInformation GetLocationInformation(this TerrestrialHardware provider, int milliSeconds) { // Forward - return (TerrestrialLocationInformation) ((Hardware) provider).GetLocationInformation( milliSeconds ); + return (TerrestrialLocationInformation)((Hardware)provider).GetLocationInformation(milliSeconds); } /// @@ -140,11 +140,11 @@ public static TerrestrialLocationInformation GetLocationInformation( this Terres /// Die Rohinformationen als SI NIT Tabellen. /// Das zugehörige DVB.NET Gerät, das noch auf den Ursprung eingestellt ist. /// Die gewünschten Informationen. - public static LocationInformation ToLocationInformation( this NIT[] tables, Hardware provider ) + public static LocationInformation ToLocationInformation(this NIT[] tables, Hardware provider) { // Validate if (null == provider) - throw new ArgumentNullException( "provider" ); + throw new ArgumentNullException("provider"); // None if (null == tables) @@ -153,20 +153,20 @@ public static LocationInformation ToLocationInformation( this NIT[] tables, Hard // Check DVB-S(2) Hardware sat = provider as Hardware; if (null != sat) - return tables.ToLocationInformation( sat ); + return tables.ToLocationInformation(sat); // Check DVB-C Hardware cab = provider as Hardware; if (null != cab) - return tables.ToLocationInformation( cab ); + return tables.ToLocationInformation(cab); // Check DVB-T Hardware ter = provider as Hardware; if (null != ter) - return tables.ToLocationInformation( ter ); + return tables.ToLocationInformation(ter); // Not supported - throw new ArgumentException( provider.GetType().FullName, "provider" ); + throw new ArgumentException(provider.GetType().FullName, "provider"); } /// @@ -176,13 +176,13 @@ public static LocationInformation ToLocationInformation( this NIT[] tables, Hard /// Die Rohinformationen als SI NIT Tabellen. /// Das zugehörige DVB.NET Gerät, das noch auf den Ursprung eingestellt ist. /// Die gewünschten Informationen. - public static SatelliteLocationInformation ToLocationInformation( this NIT[] tables, Hardware provider ) + public static SatelliteLocationInformation ToLocationInformation(this NIT[] tables, Hardware provider) { // Forward if (null == provider) - return CreateLocationInformation( new SatelliteLocation(), tables ); + return CreateLocationInformation(new SatelliteLocation(), tables); else - return CreateLocationInformation( SatelliteLocation.Parse( provider.CurrentLocation.ToString() ), tables ); + return CreateLocationInformation(SatelliteLocation.Parse(provider.CurrentLocation.ToString()), tables); } /// @@ -194,7 +194,7 @@ public static SatelliteLocationInformation ToLocationInformation( this NIT[] tab /// Der Usprung, zu dem die Tabellen ermittelt wurden. /// Die SI NIT Tabellengruppe zum noch angewählten Ursprung. /// Eine Informationsisntanz passend zur SI NIT Tabellengruppe oder null. - private static L CreateLocationInformation( GroupLocation location, NIT[] tables ) + private static L CreateLocationInformation(GroupLocation location, NIT[] tables) where G : SourceGroup, new() where L : LocationInformation, new() { @@ -219,7 +219,7 @@ private static L CreateLocationInformation( GroupLocation location, NIT // Add if possible if (null != group) - info.SourceGroups.Add( group ); + info.SourceGroups.Add(group); // Process next group break; @@ -234,7 +234,7 @@ private static L CreateLocationInformation( GroupLocation location, NIT // Add if possible if (null != group) - info.SourceGroups.Add( group ); + info.SourceGroups.Add(group); // Process next group break; @@ -249,7 +249,7 @@ private static L CreateLocationInformation( GroupLocation location, NIT // Add if possible if (null != group) - info.SourceGroups.Add( group ); + info.SourceGroups.Add(group); // Process next group break; @@ -266,16 +266,16 @@ private static L CreateLocationInformation( GroupLocation location, NIT /// /// Die Daten zur Quellgruppe. /// Die Quellgruppe. - private static CableGroup ToGroup( this EPG.Descriptors.CableDelivery descriptor ) + private static CableGroup ToGroup(this EPG.Descriptors.CableDelivery descriptor) { // Create core CableGroup group = new CableGroup - { - Frequency = descriptor.Frequency, - SpectrumInversion = SpectrumInversions.Auto, - SymbolRate = descriptor.SymbolRate * 1000, - Bandwidth = Bandwidths.NotDefined - }; + { + Frequency = descriptor.Frequency, + SpectrumInversion = SpectrumInversions.Auto, + SymbolRate = descriptor.SymbolRate * 1000, + Bandwidth = Bandwidths.NotDefined + }; // Modulation switch (descriptor.Modulation) @@ -297,14 +297,14 @@ private static CableGroup ToGroup( this EPG.Descriptors.CableDelivery descriptor /// /// Die Daten zur Quellgruppe. /// Die Quellgruppe. - private static TerrestrialGroup ToGroup( this EPG.Descriptors.TerrestrialDelivery descriptor ) + private static TerrestrialGroup ToGroup(this EPG.Descriptors.TerrestrialDelivery descriptor) { // Create core TerrestrialGroup group = new TerrestrialGroup - { - Frequency = descriptor.Frequency - }; + { + Frequency = descriptor.Frequency + }; // Bandwidth switch (descriptor.Bandwidth) @@ -329,16 +329,16 @@ private static TerrestrialGroup ToGroup( this EPG.Descriptors.TerrestrialDeliver /// /// Die Daten zur Quellgruppe. /// Die Quellgruppe. - private static SatelliteGroup ToGroup( this EPG.Descriptors.SatelliteDelivery descriptor ) + private static SatelliteGroup ToGroup(this EPG.Descriptors.SatelliteDelivery descriptor) { // Create core var group = new SatelliteGroup - { - Frequency = descriptor.Frequency, - IsWestPosition = descriptor.West, - OrbitalPosition = descriptor.OrbitalPosition.ToString( "0000" ), - SymbolRate = descriptor.SymbolRate * 1000 - }; + { + Frequency = descriptor.Frequency, + IsWestPosition = descriptor.West, + OrbitalPosition = descriptor.OrbitalPosition.ToString("0000"), + SymbolRate = descriptor.SymbolRate * 1000 + }; // DVB-S2 modulation group.UsesS2Modulation = (0 != (0x04 & descriptor.Modulation)); @@ -403,10 +403,10 @@ private static SatelliteGroup ToGroup( this EPG.Descriptors.SatelliteDelivery de /// Die Rohinformationen als SI NIT Tabellen. /// Das zugehörige DVB.NET Gerät, das noch auf den Ursprung eingestellt ist. /// Die gewünschten Informationen. - public static CableLocationInformation ToLocationInformation( this NIT[] tables, Hardware provider ) + public static CableLocationInformation ToLocationInformation(this NIT[] tables, Hardware provider) { // Forward - return CreateLocationInformation( new CableLocation(), tables ); + return CreateLocationInformation(new CableLocation(), tables); } /// @@ -416,10 +416,10 @@ public static CableLocationInformation ToLocationInformation( this NIT[] tables, /// Die Rohinformationen als SI NIT Tabellen. /// Das zugehörige DVB.NET Gerät, das noch auf den Ursprung eingestellt ist. /// Die gewünschten Informationen. - public static TerrestrialLocationInformation ToLocationInformation( this NIT[] tables, Hardware provider ) + public static TerrestrialLocationInformation ToLocationInformation(this NIT[] tables, Hardware provider) { // Forward - return CreateLocationInformation( new TerrestrialLocation(), tables ); + return CreateLocationInformation(new TerrestrialLocation(), tables); } /// @@ -430,7 +430,7 @@ public static TerrestrialLocationInformation ToLocationInformation( this NIT[] t /// Die SI Informationen mit der Zuordnung der Dienste /// zu den Program Mapping Table (PMT) Tabellen. /// Die gewünschte Informationsinstanz. - public static GroupInformation ToGroupInformation( this SDT[] services, PAT[] associations ) + public static GroupInformation ToGroupInformation(this SDT[] services, PAT[] associations) { // Create new var info = new GroupInformation(); @@ -458,7 +458,7 @@ public static GroupInformation ToGroupInformation( this SDT[] services, PAT[] as if (associations[0][entry.ServiceIdentifier].HasValue) { // Find the description - var descr = EPG.DescriptorExtensions.Find( entry.Descriptors ); + var descr = EPG.DescriptorExtensions.Find(entry.Descriptors); if (descr == null) continue; @@ -470,6 +470,8 @@ public static GroupInformation ToGroupInformation( this SDT[] services, PAT[] as type = SourceTypes.TV; else if (descr.ServiceType == EPG.ServiceTypes.DigitalRadio) type = SourceTypes.Radio; + else if (descr.ServiceType == EPG.ServiceTypes.FMRadio) + type = SourceTypes.Radio; else if (descr.ServiceType == EPG.ServiceTypes.SDTVDigitalTelevision) type = SourceTypes.TV; else if (descr.ServiceType == EPG.ServiceTypes.HDTVDigitalTelevision) @@ -484,18 +486,18 @@ public static GroupInformation ToGroupInformation( this SDT[] services, PAT[] as // Add the station info.Sources.Add( new Station - { - TransportStream = service.TransportStream, - Service = entry.ServiceIdentifier, - Provider = descr.ProviderName, - IsEncrypted = entry.Scrambled, - Network = service.Network, - Name = descr.ServiceName, - SourceType = type, - } ); + { + TransportStream = service.TransportStream, + Service = entry.ServiceIdentifier, + Provider = descr.ProviderName, + IsEncrypted = entry.Scrambled, + Network = service.Network, + Name = descr.ServiceName, + SourceType = type, + }); // Mark as done - processed.Add( entry.ServiceIdentifier ); + processed.Add(entry.ServiceIdentifier); } // Get the first SDT as a reference @@ -503,18 +505,18 @@ public static GroupInformation ToGroupInformation( this SDT[] services, PAT[] as // No check all services foreach (var serviceIdentifier in associations[0].Services) - if (!processed.Contains( serviceIdentifier )) + if (!processed.Contains(serviceIdentifier)) info.Sources.Add( new Station { - Name = string.Format( "Service {0}", serviceIdentifier ), + Name = string.Format("Service {0}", serviceIdentifier), TransportStream = sdt.TransportStream, SourceType = SourceTypes.Unknown, Service = serviceIdentifier, Network = sdt.Network, Provider = "Service", IsService = true, - } ); + }); // Report return info; @@ -526,12 +528,12 @@ public static GroupInformation ToGroupInformation( this SDT[] services, PAT[] as /// Die Liste der Assoziationen. /// Die eindeutige Kennung des gewünschten Dienstes. /// Die Datenstromkennung der SI Tabelle PMT des gewünschten Dienstes. - public static ushort? FindService( this PAT[] associations, ushort serviceIdentifier ) + public static ushort? FindService(this PAT[] associations, ushort serviceIdentifier) { return (associations ?? Enumerable.Empty()) - .Select( association => association[serviceIdentifier] ) - .FirstOrDefault( pmt => pmt.HasValue ); + .Select(association => association[serviceIdentifier]) + .FirstOrDefault(pmt => pmt.HasValue); } /// @@ -540,7 +542,7 @@ public static GroupInformation ToGroupInformation( this SDT[] services, PAT[] as /// /// Die Daten zu einer Quelle, die vervollständigt werden sollen. /// Die SI Programmbeschreibung. - public static void Update( this SourceInformation source, EPG.ProgramEntry program ) + public static void Update(this SourceInformation source, EPG.ProgramEntry program) { // MPEG-2 Video if (EPG.StreamTypes.Video13818 == program.StreamType) @@ -568,10 +570,44 @@ public static void Update( this SourceInformation source, EPG.ProgramEntry progr if ((EPG.StreamTypes.Audio11172 == program.StreamType) || (EPG.StreamTypes.Audio13818 == program.StreamType)) { // Create new entry - AudioInformation audio = new AudioInformation { AudioType = AudioTypes.MP2, AudioStream = program.ElementaryPID, Language = program.ProgrammeName.Trim() }; + var audio = new AudioInformation { AudioType = AudioTypes.MP2, AudioStream = program.ElementaryPID, Language = program.ProgrammeName.Trim() }; // Remember it - source.AudioTracks.Add( audio ); + source.AudioTracks.Add(audio); + + // Done + return; + } + + // AAC Audio + if (EPG.StreamTypes.AAC == program.StreamType) + { + // The AAC information. + int? aac = null; + + // Find corresponding AAC descriptor. + var aacDescriptor = program.Descriptors.OfType().FirstOrDefault(); + + if (aacDescriptor != null) + { + // Optional type. + aac = aacDescriptor.Type ?? 255; + + // Profile and level. + aac = (aac << 8) + aacDescriptor.ProfileAndLevel; + } + + // Create new entry + var audio = new AudioInformation + { + AAC = aac.HasValue ? (ushort)aac : (ushort?)null, + Language = program.ProgrammeName.Trim(), + AudioType = AudioTypes.MP2, + AudioStream = program.ElementaryPID, + }; + + // Remember it + source.AudioTracks.Add(audio); // Done return; @@ -592,7 +628,7 @@ public static void Update( this SourceInformation source, EPG.ProgramEntry progr AudioInformation audio = new AudioInformation { AudioType = AudioTypes.AC3, AudioStream = program.ElementaryPID, Language = program.ProgrammeName.Trim() }; // Remember it - source.AudioTracks.Add( audio ); + source.AudioTracks.Add(audio); // Done return; @@ -618,16 +654,16 @@ public static void Update( this SourceInformation source, EPG.ProgramEntry progr { // Create the information var info = new SubtitleInformation - { - SubtitleStream = program.ElementaryPID, - Language = subTitle.Language, - SubtitleType = (SubtitleTypes) subTitle.Type, - CompositionPage = subTitle.CompositionPage, - AncillaryPage = subTitle.AncillaryPage - }; + { + SubtitleStream = program.ElementaryPID, + Language = subTitle.Language, + SubtitleType = (SubtitleTypes)subTitle.Type, + CompositionPage = subTitle.CompositionPage, + AncillaryPage = subTitle.AncillaryPage + }; // Remember - source.Subtitles.Add( info ); + source.Subtitles.Add(info); } // Done @@ -641,14 +677,14 @@ public static void Update( this SourceInformation source, EPG.ProgramEntry progr /// /// Die gewünschte Sprache. /// Die ISO Kurznotation. - public static string ToISOLanguage( this string language ) + public static string ToISOLanguage(this string language) { // Not possible if (null == language) return null; // Use helper - return EPG.LanguageItemExtensions.ToISOLanguage( language ); + return EPG.LanguageItemExtensions.ToISOLanguage(language); } /// @@ -656,14 +692,14 @@ public static string ToISOLanguage( this string language ) /// /// Eine ISO Kurznotation. /// Die zugehörige Sprache, wie sie in DVB.NET verwendet wird. - public static string FromISOLanguage( this string language ) + public static string FromISOLanguage(this string language) { // Not possible if (null == language) return null; // Use helper - return EPG.ProgramEntry.GetLanguageFromISOLanguage( language ); + return EPG.ProgramEntry.GetLanguageFromISOLanguage(language); } } } diff --git a/DVB.NET/Provider/DVBNETLegacy/DVBNETProviders.xml b/DVB.NET/Provider/DVBNETLegacy/DVBNETProviders.xml index 963cbfc..3d7f670 100644 --- a/DVB.NET/Provider/DVBNETLegacy/DVBNETProviders.xml +++ b/DVB.NET/Provider/DVBNETLegacy/DVBNETProviders.xml @@ -191,4 +191,21 @@ 50 + + + Ubuntu DVB-S2 + + JMS.DVB.Provider.Ubuntu.DeviceProvider, JMS.DVB.Provider.Ubuntu + 200 + + true + + + + + 29713 + + + + diff --git a/DVB.NET/Provider/DVBNETLegacy/JMS.DVB.Provider.Legacy.csproj b/DVB.NET/Provider/DVBNETLegacy/JMS.DVB.Provider.Legacy.csproj index edeadef..9088ca7 100644 --- a/DVB.NET/Provider/DVBNETLegacy/JMS.DVB.Provider.Legacy.csproj +++ b/DVB.NET/Provider/DVBNETLegacy/JMS.DVB.Provider.Legacy.csproj @@ -64,6 +64,10 @@ ..\..\Assemblies\Adapter\JMS.DVB.Provider.TTPremium.dll False + + ..\..\Assemblies\Adapter\JMS.DVB.Provider.Ubuntu.dll + False + False diff --git a/DVB.NET/Provider/DVBNETLegacy/LegacyHardware.cs b/DVB.NET/Provider/DVBNETLegacy/LegacyHardware.cs index 070d659..050014b 100644 --- a/DVB.NET/Provider/DVBNETLegacy/LegacyHardware.cs +++ b/DVB.NET/Provider/DVBNETLegacy/LegacyHardware.cs @@ -5,7 +5,6 @@ using JMS.DVB.Editors; using JMS.TechnoTrend; - namespace JMS.DVB.Provider.Legacy { /// @@ -106,6 +105,10 @@ public static HardwareRestriction GetRestriction( Profile profile ) // But is able to provide signal information restr.ProvidesSignalInformation = true; } + else if (typeof(Ubuntu.DeviceProvider).IsAssignableFrom(driver)) + { + restr.ProvidesSignalInformation = true; + } else if (typeof( TTBudget.BudgetProvider ).IsAssignableFrom( driver )) { // Maximum number of streams is restricted diff --git a/DVB.NET/Provider/TechnoTrend/TTPremium/JMS.DVB.Provider.TTPremium.csproj b/DVB.NET/Provider/TechnoTrend/TTPremium/JMS.DVB.Provider.TTPremium.csproj index 1bd2abf..125bd70 100644 --- a/DVB.NET/Provider/TechnoTrend/TTPremium/JMS.DVB.Provider.TTPremium.csproj +++ b/DVB.NET/Provider/TechnoTrend/TTPremium/JMS.DVB.Provider.TTPremium.csproj @@ -102,7 +102,6 @@ ..\..\..\Assemblies\RunTime\JMS.DVB.SourceManagement.dll - False False diff --git a/DVB.NET/Provider/Ubuntu/DeviceProvider.cs b/DVB.NET/Provider/Ubuntu/DeviceProvider.cs new file mode 100644 index 0000000..3b6d14b --- /dev/null +++ b/DVB.NET/Provider/Ubuntu/DeviceProvider.cs @@ -0,0 +1,364 @@ +using JMS.DVB.DeviceAccess.Interfaces; +using JMS.DVB.TS; +using JMS.TechnoTrend; +using System; +using System.Collections; +using System.Diagnostics; +using System.Net.Sockets; +using System.Runtime.InteropServices; +using System.Threading; + +namespace JMS.DVB.Provider.Ubuntu +{ + public class DeviceProvider : ILegacyDevice + { + private readonly string m_server; + + private readonly int m_port; + + private TcpClient m_connection; + + private readonly object m_lock = new object(); + + private TSParser m_parser = new TSParser(true); + + public DeviceProvider(Hashtable args) + { + m_server = (string)args["Adapter.Server"]; + m_port = ArgumentToNumber(args["Adapter.Port"], 29713); + } + + private static int ArgumentToNumber(object arg, int fallback = 0) + { + if (int.TryParse((string)arg, out int number)) + return number; + + return fallback; + } + + private void SendRequest(FrontendRequestType type, TData data) + { + Open(); + + var size = 4 + Marshal.SizeOf(data); + var buf = new byte[size]; + var bufptr = GCHandle.Alloc(buf, GCHandleType.Pinned); + + try + { + Marshal.WriteInt32(bufptr.AddrOfPinnedObject() + 0, (Int32)type); + Marshal.StructureToPtr(data, bufptr.AddrOfPinnedObject() + 4, true); + } + finally + { + bufptr.Free(); + } + + SafeWrite(buf); + } + + private void SafeWrite(byte[] buf) + { + try + { + m_connection.GetStream().Write(buf, 0, buf.Length); + } + catch (Exception e) + { + Debug.WriteLine("Failed to send request: {0}", e); + } + } + + private void SendRequest(FrontendRequestType type, UInt16 data) + { + Open(); + + var buf = new byte[6]; + var bufptr = GCHandle.Alloc(buf, GCHandleType.Pinned); + + try + { + Marshal.WriteInt32(bufptr.AddrOfPinnedObject() + 0, (Int32)type); + Marshal.WriteInt16(bufptr.AddrOfPinnedObject() + 4, (Int16)data); + } + finally + { + bufptr.Free(); + } + + SafeWrite(buf); + } + + private void SendRequest(FrontendRequestType type) + { + Open(); + + var buf = new byte[4]; + var bufptr = GCHandle.Alloc(buf, GCHandleType.Pinned); + + try + { + Marshal.WriteInt32(bufptr.AddrOfPinnedObject() + 0, (Int32)type); + } + finally + { + bufptr.Free(); + } + + SafeWrite(buf); + } + + + + private void StartReader(object state) + { + var buffer = new byte[180000]; + + try + { + var stream = m_connection.GetStream(); + + for (; ; ) + { + var read = stream.Read(buffer, 0, buffer.Length); + + if (read <= 0) + { + return; + } + + m_parser.AddPayload(buffer, 0, read); + } + } + catch (Exception) + { + return; + } + } + + private void Open() + { + if (m_connection != null) + return; + + m_connection = new TcpClient { ReceiveBufferSize = 10 * 1024 * 1024 }; + + try + { + m_connection.Connect(m_server, m_port); + + ThreadPool.QueueUserWorkItem(StartReader); + + SendRequest(FrontendRequestType.connect_adapter); + } + catch (Exception) + { + Close(); + + throw; + } + } + + private void Close() + { + using (m_parser) + { + m_parser = new TSParser(true); + } + + + if (m_connection == null) + return; + + using (m_connection) + { + try + { + m_connection.Close(); + } + finally + { + m_connection = null; + } + } + } + + public void StopFilters() + { + using (m_parser) + { + m_parser = new TSParser(true); + } + + if (m_connection != null) + SendRequest(FrontendRequestType.del_all_filters); + } + + private static DiSEqCModes ConvertDiSEqC(DiSEqCLocations location) + { + switch (location) + { + case DiSEqCLocations.BurstOff: + return DiSEqCModes.burst_off; + case DiSEqCLocations.BurstOn: + return DiSEqCModes.burst_on; + case DiSEqCLocations.DiSEqC1: + return DiSEqCModes.diseqc1; + case DiSEqCLocations.DiSEqC2: + return DiSEqCModes.diseqc2; + case DiSEqCLocations.DiSEqC3: + return DiSEqCModes.diseqc3; + case DiSEqCLocations.DiSEqC4: + return DiSEqCModes.diseqc4; + default: + return DiSEqCModes.none; + } + } + + private static FeModulation ConvertModulation(SatelliteModulations modulation) + { + switch (modulation) + { + case SatelliteModulations.Auto: + return FeModulation.QAM_AUTO; + case SatelliteModulations.PSK8: + return FeModulation.PSK_8; + case SatelliteModulations.QAM16: + return FeModulation.QAM_16; + default: + return FeModulation.QPSK; + } + } + + private static FeCodeRate ConvertCodeRate(InnerForwardErrorCorrectionModes modulation) + { + switch (modulation) + { + case InnerForwardErrorCorrectionModes.Conv1_2: + return FeCodeRate.FEC_1_2; + case InnerForwardErrorCorrectionModes.Conv2_3: + return FeCodeRate.FEC_2_3; + case InnerForwardErrorCorrectionModes.Conv3_4: + return FeCodeRate.FEC_3_4; + case InnerForwardErrorCorrectionModes.Conv3_5: + return FeCodeRate.FEC_3_5; + case InnerForwardErrorCorrectionModes.Conv4_5: + return FeCodeRate.FEC_4_5; + case InnerForwardErrorCorrectionModes.Conv5_6: + return FeCodeRate.FEC_5_6; + case InnerForwardErrorCorrectionModes.Conv7_8: + return FeCodeRate.FEC_7_8; + case InnerForwardErrorCorrectionModes.Conv8_9: + return FeCodeRate.FEC_8_9; + case InnerForwardErrorCorrectionModes.Conv9_10: + return FeCodeRate.FEC_9_10; + case InnerForwardErrorCorrectionModes.NoConv: + return FeCodeRate.FEC_NONE; + default: + return FeCodeRate.FEC_AUTO; + } + } + + private static FeRolloff ConvertRolloff(S2RollOffs modulation) + { + switch (modulation) + { + case S2RollOffs.Alpha20: + return FeRolloff.ROLLOFF_20; + case S2RollOffs.Alpha25: + return FeRolloff.ROLLOFF_25; + case S2RollOffs.Alpha35: + return FeRolloff.ROLLOFF_35; + default: + return FeRolloff.ROLLOFF_AUTO; + } + } + + public void Tune(SourceGroup group, GroupLocation location) + { + StopFilters(); + + var satGroup = group as SatelliteGroup; + + if (satGroup == null) + return; + + var satLocation = location as SatelliteLocation; + + if (satLocation == null) + return; + + var tune = new SatelliteTune + { + frequency = satGroup.Frequency, + horizontal = satGroup.Polarization == Polarizations.Horizontal, + innerFEC = ConvertCodeRate(satGroup.InnerFEC), + lnb1 = satLocation.Frequency1, + lnb2 = satLocation.Frequency2, + lnbMode = ConvertDiSEqC(satLocation.LNB), + lnbPower = satLocation.UsePower, + lnbSwitch = satLocation.SwitchFrequency, + modulation = ConvertModulation(satGroup.Modulation), + rolloff = ConvertRolloff(satGroup.RollOff), + s2 = satGroup.UsesS2Modulation, + symbolrate = satGroup.SymbolRate, + }; + + SendRequest(FrontendRequestType.tune, tune); + } + + public void SetVideoAudio(ushort videoPID, ushort audioPID) + { + Open(); + } + + public void StartSectionFilter(ushort pid, Action callback, byte[] filterData, byte[] filterMask) + { + m_parser.SetFilter(pid, true, callback); + + SendRequest(FrontendRequestType.add_filter, pid); + } + + public void RegisterPipingFilter(ushort pid, bool video, bool smallBuffer, Action callback) + { + m_parser.SetFilter(pid, false, callback); + + SendRequest(FrontendRequestType.add_filter, pid); + } + + public void StartFilter(ushort pid) + { + } + + public void StopFilter(ushort pid) + { + m_parser.RemoveFilter(pid); + + if (m_connection != null) + SendRequest(FrontendRequestType.del_filter, pid); + } + + public void Decrypt(ushort? station) + { + } + + public override string ToString() + { + return string.Format("Ubuntu DVB Proxy to {0}:{1}", m_server, m_port); + } + + public void WakeUp() + { + } + + public SignalStatus SignalStatus { get; private set; } = new SignalStatus(true, 0, 0); + + public virtual void Dispose() + { + StopFilters(); + + Close(); + } + } + +} diff --git a/DVB.NET/Provider/Ubuntu/DiSEqCModes.cs b/DVB.NET/Provider/Ubuntu/DiSEqCModes.cs new file mode 100644 index 0000000..9ad4b87 --- /dev/null +++ b/DVB.NET/Provider/Ubuntu/DiSEqCModes.cs @@ -0,0 +1,13 @@ +namespace JMS.DVB.Provider.Ubuntu +{ + public enum DiSEqCModes + { + none = 0, + burst_off = 5, + burst_on = 6, + diseqc1 = 1, + diseqc2 = 2, + diseqc3 = 3, + diseqc4 = 4, + } +} \ No newline at end of file diff --git a/DVB.NET/Provider/Ubuntu/FeCodeRate.cs b/DVB.NET/Provider/Ubuntu/FeCodeRate.cs new file mode 100644 index 0000000..34dc4b1 --- /dev/null +++ b/DVB.NET/Provider/Ubuntu/FeCodeRate.cs @@ -0,0 +1,19 @@ +namespace JMS.DVB.Provider.Ubuntu +{ + public enum FeCodeRate + { + FEC_NONE = 0, + FEC_1_2 = 1, + FEC_2_3 = 2, + FEC_3_4 = 3, + FEC_4_5 = 4, + FEC_5_6 = 5, + FEC_6_7 = 6, + FEC_7_8 = 7, + FEC_8_9 = 8, + FEC_AUTO = 9, + FEC_3_5 = 10, + FEC_9_10 = 11, + FEC_2_5 = 12, + } +} \ No newline at end of file diff --git a/DVB.NET/Provider/Ubuntu/FeModulation.cs b/DVB.NET/Provider/Ubuntu/FeModulation.cs new file mode 100644 index 0000000..16ae9be --- /dev/null +++ b/DVB.NET/Provider/Ubuntu/FeModulation.cs @@ -0,0 +1,20 @@ +namespace JMS.DVB.Provider.Ubuntu +{ + public enum FeModulation + { + QPSK = 0, + QAM_16 = 1, + QAM_32 = 2, + QAM_64 = 3, + QAM_128 = 4, + QAM_256 = 5, + QAM_AUTO = 6, + VSB_8 = 7, + VSB_16 = 8, + PSK_8 = 9, + APSK_16 = 10, + APSK_32 = 11, + DQPSK = 12, + QAM_4_NR = 13, + } +} \ No newline at end of file diff --git a/DVB.NET/Provider/Ubuntu/FeRolloff.cs b/DVB.NET/Provider/Ubuntu/FeRolloff.cs new file mode 100644 index 0000000..1f3355b --- /dev/null +++ b/DVB.NET/Provider/Ubuntu/FeRolloff.cs @@ -0,0 +1,10 @@ +namespace JMS.DVB.Provider.Ubuntu +{ + public enum FeRolloff + { + ROLLOFF_35 = 0, + ROLLOFF_20 = 1, + ROLLOFF_25 = 2, + ROLLOFF_AUTO = 3, + } +} \ No newline at end of file diff --git a/DVB.NET/Provider/Ubuntu/FeStatus.cs b/DVB.NET/Provider/Ubuntu/FeStatus.cs new file mode 100644 index 0000000..255c634 --- /dev/null +++ b/DVB.NET/Provider/Ubuntu/FeStatus.cs @@ -0,0 +1,17 @@ +using System; + +namespace JMS.DVB.Provider.Ubuntu +{ + [Flags] + public enum FeStatus + { + FE_NONE = 0x00, + FE_HAS_SIGNAL = 0x01, + FE_HAS_CARRIER = 0x02, + FE_HAS_VITERBI = 0x04, + FE_HAS_SYNC = 0x08, + FE_HAS_LOCK = 0x10, + FE_TIMEDOUT = 0x20, + FE_REINIT = 0x40, + } +} \ No newline at end of file diff --git a/DVB.NET/Provider/Ubuntu/FrontendRequestType.cs b/DVB.NET/Provider/Ubuntu/FrontendRequestType.cs new file mode 100644 index 0000000..1e0c6d0 --- /dev/null +++ b/DVB.NET/Provider/Ubuntu/FrontendRequestType.cs @@ -0,0 +1,11 @@ +namespace JMS.DVB.Provider.Ubuntu +{ + public enum FrontendRequestType + { + add_filter = 0, + connect_adapter = 1, + del_all_filters = 2, + del_filter = 3, + tune = 4, + } +} \ No newline at end of file diff --git a/DVB.NET/Provider/Ubuntu/JMS.DVB.Provider.Ubuntu.csproj b/DVB.NET/Provider/Ubuntu/JMS.DVB.Provider.Ubuntu.csproj new file mode 100644 index 0000000..a9228b3 --- /dev/null +++ b/DVB.NET/Provider/Ubuntu/JMS.DVB.Provider.Ubuntu.csproj @@ -0,0 +1,86 @@ + + + + + Debug + AnyCPU + {7FC369A1-D9B5-441A-873E-CB6AC92B9956} + Library + Properties + JMS.DVB.Provider.Ubuntu + JMS.DVB.Provider.Ubuntu + v4.5.1 + 512 + true + + + + true + full + false + ..\..\Assemblies\Adapter\ + DEBUG;TRACE + prompt + 4 + ..\..\Assemblies\Adapter\JMS.DVB.Provider.Ubuntu.xml + true + CS1591 + + + pdbonly + true + ..\..\Assemblies\Adapter\ + TRACE + prompt + 4 + ..\..\Assemblies\Adapter\JMS.DVB.Provider.Ubuntu.xml + true + CS1591 + + + true + + + ..\..\..\..\dvbnet4.snk + + + + ..\..\Assemblies\RunTime\JMS.DVB.SourceManagement.dll + False + + + ..\..\Assemblies\RunTime\JMS.DVB.TS.dll + False + + + ..\..\Assemblies\Adapter\JMS.TechnoTrend.MFCWrapper.dll + False + + + + + + + + + + + + + + + + + + + + + + + + ..\..\Assemblies\RunTime\JMS.DVB.DeviceAccess.dll + False + + + + \ No newline at end of file diff --git a/DVB.NET/Provider/Ubuntu/Properties/AssemblyInfo.cs b/DVB.NET/Provider/Ubuntu/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..f52cd93 --- /dev/null +++ b/DVB.NET/Provider/Ubuntu/Properties/AssemblyInfo.cs @@ -0,0 +1,56 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +// +[assembly: AssemblyTitle("DVB.NET Provider for Ubuntu DVB Proxy")] +[assembly: AssemblyDescription("TCP/IP Connector to Ubuntu DVB.NET DVB-S Proxy Server")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("JMS")] +[assembly: AssemblyProduct("DVB.NET")] +[assembly: AssemblyCopyright("Copyright © 2019")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: + +[assembly: AssemblyVersion("4.3.0.0")] + +// +// In order to sign your assembly you must specify a key to use. Refer to the +// Microsoft .NET Framework documentation for more information on assembly signing. +// +// Use the attributes below to control which key is used for signing. +// +// Notes: +// (*) If no key is specified, the assembly is not signed. +// (*) KeyName refers to a key that has been installed in the Crypto Service +// Provider (CSP) on your machine. KeyFile refers to a file which contains +// a key. +// (*) If the KeyFile and the KeyName values are both specified, the +// following processing occurs: +// (1) If the KeyName can be found in the CSP, that key is used. +// (2) If the KeyName does not exist and the KeyFile does exist, the key +// in the KeyFile is installed into the CSP and used. +// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility. +// When specifying the KeyFile, the location of the KeyFile should be +// relative to the project output directory which is +// %Project Directory%\obj\. For example, if your KeyFile is +// located in the project directory, you would specify the AssemblyKeyFile +// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")] +// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework +// documentation for more information on this. +// +[assembly: AssemblyDelaySign(false)] \ No newline at end of file diff --git a/DVB.NET/Provider/Ubuntu/SatelliteTune.cs b/DVB.NET/Provider/Ubuntu/SatelliteTune.cs new file mode 100644 index 0000000..13140ca --- /dev/null +++ b/DVB.NET/Provider/Ubuntu/SatelliteTune.cs @@ -0,0 +1,22 @@ +using System; +using System.Runtime.InteropServices; + +namespace JMS.DVB.Provider.Ubuntu +{ + [StructLayout(LayoutKind.Sequential)] + public struct SatelliteTune + { + public DiSEqCModes lnbMode; + public UInt32 lnb1; + public UInt32 lnb2; + public UInt32 lnbSwitch; + public bool lnbPower; + public FeModulation modulation; + public UInt32 frequency; + public UInt32 symbolrate; + public bool horizontal; + public FeCodeRate innerFEC; + public bool s2; + public FeRolloff rolloff; + } +} \ No newline at end of file diff --git a/DVB.NET/Setups/Core/Core.sln b/DVB.NET/Setups/Core/Core.sln index bf47007..fb6de2f 100644 --- a/DVB.NET/Setups/Core/Core.sln +++ b/DVB.NET/Setups/Core/Core.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.21005.1 +# Visual Studio 15 +VisualStudioVersion = 15.0.28307.902 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JMS.DVB.Common", "..\..\Common\JMS.DVB.Common.csproj", "{A224B2D5-7987-4C86-8FF7-CDD09ED76BA0}" EndProject @@ -29,11 +29,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JMS.DVB.TS", "..\..\TS\JMS. EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JMS.DVB.HardwareAbstraction", "..\..\HardwareAbstraction\JMS.DVB.HardwareAbstraction.csproj", "{76D4B1A1-14FF-4265-8351-06DFD98F2DC3}" ProjectSection(ProjectDependencies) = postProject + {046BA60E-E22F-48AA-AB52-5D8AA7F0A6C4} = {046BA60E-E22F-48AA-AB52-5D8AA7F0A6C4} {B2325F13-C217-4D96-846C-3FF857DA6128} = {B2325F13-C217-4D96-846C-3FF857DA6128} {6662DE38-74C1-4432-9512-C7E94C2EFDFA} = {6662DE38-74C1-4432-9512-C7E94C2EFDFA} {620B2A8D-ACCC-401A-A67B-70F3AAE47F55} = {620B2A8D-ACCC-401A-A67B-70F3AAE47F55} {90D05FCC-70F9-4423-A79F-B8D31BFBC228} = {90D05FCC-70F9-4423-A79F-B8D31BFBC228} - {046BA60E-E22F-48AA-AB52-5D8AA7F0A6C4} = {046BA60E-E22F-48AA-AB52-5D8AA7F0A6C4} {A224B2D5-7987-4C86-8FF7-CDD09ED76BA0} = {A224B2D5-7987-4C86-8FF7-CDD09ED76BA0} EndProjectSection EndProject @@ -41,29 +41,30 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JMS.FavoriteManager", "..\. EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JMS.TechnoTrend.MFCWrapper", "..\..\Provider\TechnoTrend\TTAPI\JMS.TechnoTrend.MFCWrapper.csproj", "{CC42C4D5-3158-4E1C-9FC8-8138DBE52D8F}" ProjectSection(ProjectDependencies) = postProject + {046BA60E-E22F-48AA-AB52-5D8AA7F0A6C4} = {046BA60E-E22F-48AA-AB52-5D8AA7F0A6C4} {B2325F13-C217-4D96-846C-3FF857DA6128} = {B2325F13-C217-4D96-846C-3FF857DA6128} {6662DE38-74C1-4432-9512-C7E94C2EFDFA} = {6662DE38-74C1-4432-9512-C7E94C2EFDFA} {90D05FCC-70F9-4423-A79F-B8D31BFBC228} = {90D05FCC-70F9-4423-A79F-B8D31BFBC228} - {046BA60E-E22F-48AA-AB52-5D8AA7F0A6C4} = {046BA60E-E22F-48AA-AB52-5D8AA7F0A6C4} EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JMS.DVB.Provider.Legacy", "..\..\Provider\DVBNETLegacy\JMS.DVB.Provider.Legacy.csproj", "{D528B63E-EE1A-4297-BE78-90D38F6CE0C2}" ProjectSection(ProjectDependencies) = postProject - {CC42C4D5-3158-4E1C-9FC8-8138DBE52D8F} = {CC42C4D5-3158-4E1C-9FC8-8138DBE52D8F} + {0FF2B905-EBFC-47D8-BEDA-6961C9438114} = {0FF2B905-EBFC-47D8-BEDA-6961C9438114} + {046BA60E-E22F-48AA-AB52-5D8AA7F0A6C4} = {046BA60E-E22F-48AA-AB52-5D8AA7F0A6C4} {6662DE38-74C1-4432-9512-C7E94C2EFDFA} = {6662DE38-74C1-4432-9512-C7E94C2EFDFA} {620B2A8D-ACCC-401A-A67B-70F3AAE47F55} = {620B2A8D-ACCC-401A-A67B-70F3AAE47F55} - {744054D8-2B4A-42D1-A84B-781561F575EB} = {744054D8-2B4A-42D1-A84B-781561F575EB} - {0FF2B905-EBFC-47D8-BEDA-6961C9438114} = {0FF2B905-EBFC-47D8-BEDA-6961C9438114} + {7FC369A1-D9B5-441A-873E-CB6AC92B9956} = {7FC369A1-D9B5-441A-873E-CB6AC92B9956} {76D4B1A1-14FF-4265-8351-06DFD98F2DC3} = {76D4B1A1-14FF-4265-8351-06DFD98F2DC3} - {046BA60E-E22F-48AA-AB52-5D8AA7F0A6C4} = {046BA60E-E22F-48AA-AB52-5D8AA7F0A6C4} {A224B2D5-7987-4C86-8FF7-CDD09ED76BA0} = {A224B2D5-7987-4C86-8FF7-CDD09ED76BA0} + {CC42C4D5-3158-4E1C-9FC8-8138DBE52D8F} = {CC42C4D5-3158-4E1C-9FC8-8138DBE52D8F} + {744054D8-2B4A-42D1-A84B-781561F575EB} = {744054D8-2B4A-42D1-A84B-781561F575EB} EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JMS.DVB.DirectShow", "..\..\BDA\JMS.DVB.DirectShow.csproj", "{18E9D0C8-8AC6-4F86-AD43-DBDCFBFB2F26}" ProjectSection(ProjectDependencies) = postProject + {046BA60E-E22F-48AA-AB52-5D8AA7F0A6C4} = {046BA60E-E22F-48AA-AB52-5D8AA7F0A6C4} {B2325F13-C217-4D96-846C-3FF857DA6128} = {B2325F13-C217-4D96-846C-3FF857DA6128} {90D05FCC-70F9-4423-A79F-B8D31BFBC228} = {90D05FCC-70F9-4423-A79F-B8D31BFBC228} - {046BA60E-E22F-48AA-AB52-5D8AA7F0A6C4} = {046BA60E-E22F-48AA-AB52-5D8AA7F0A6C4} {A224B2D5-7987-4C86-8FF7-CDD09ED76BA0} = {A224B2D5-7987-4C86-8FF7-CDD09ED76BA0} EndProjectSection EndProject @@ -77,45 +78,45 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JMS.DVB.Algorithms", "..\.. EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JMS.DVB.Provider.TTPremium", "..\..\Provider\TechnoTrend\TTPremium\JMS.DVB.Provider.TTPremium.csproj", "{744054D8-2B4A-42D1-A84B-781561F575EB}" ProjectSection(ProjectDependencies) = postProject - {CC42C4D5-3158-4E1C-9FC8-8138DBE52D8F} = {CC42C4D5-3158-4E1C-9FC8-8138DBE52D8F} - {6662DE38-74C1-4432-9512-C7E94C2EFDFA} = {6662DE38-74C1-4432-9512-C7E94C2EFDFA} {046BA60E-E22F-48AA-AB52-5D8AA7F0A6C4} = {046BA60E-E22F-48AA-AB52-5D8AA7F0A6C4} + {6662DE38-74C1-4432-9512-C7E94C2EFDFA} = {6662DE38-74C1-4432-9512-C7E94C2EFDFA} + {CC42C4D5-3158-4E1C-9FC8-8138DBE52D8F} = {CC42C4D5-3158-4E1C-9FC8-8138DBE52D8F} EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JMS.DVB.Provider.TTBudget", "..\..\Provider\TechnoTrend\TTBudget\JMS.DVB.Provider.TTBudget.csproj", "{0FF2B905-EBFC-47D8-BEDA-6961C9438114}" ProjectSection(ProjectDependencies) = postProject - {CC42C4D5-3158-4E1C-9FC8-8138DBE52D8F} = {CC42C4D5-3158-4E1C-9FC8-8138DBE52D8F} + {046BA60E-E22F-48AA-AB52-5D8AA7F0A6C4} = {046BA60E-E22F-48AA-AB52-5D8AA7F0A6C4} {6662DE38-74C1-4432-9512-C7E94C2EFDFA} = {6662DE38-74C1-4432-9512-C7E94C2EFDFA} {620B2A8D-ACCC-401A-A67B-70F3AAE47F55} = {620B2A8D-ACCC-401A-A67B-70F3AAE47F55} {76D4B1A1-14FF-4265-8351-06DFD98F2DC3} = {76D4B1A1-14FF-4265-8351-06DFD98F2DC3} {90D05FCC-70F9-4423-A79F-B8D31BFBC228} = {90D05FCC-70F9-4423-A79F-B8D31BFBC228} - {046BA60E-E22F-48AA-AB52-5D8AA7F0A6C4} = {046BA60E-E22F-48AA-AB52-5D8AA7F0A6C4} + {CC42C4D5-3158-4E1C-9FC8-8138DBE52D8F} = {CC42C4D5-3158-4E1C-9FC8-8138DBE52D8F} EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JMS.DVB.Provider.FireDTV", "..\..\Provider\FireDTV\JMS.DVB.Provider.FireDTV.csproj", "{D02922AD-4064-4B13-8B81-073079788FEA}" ProjectSection(ProjectDependencies) = postProject + {046BA60E-E22F-48AA-AB52-5D8AA7F0A6C4} = {046BA60E-E22F-48AA-AB52-5D8AA7F0A6C4} {6662DE38-74C1-4432-9512-C7E94C2EFDFA} = {6662DE38-74C1-4432-9512-C7E94C2EFDFA} {620B2A8D-ACCC-401A-A67B-70F3AAE47F55} = {620B2A8D-ACCC-401A-A67B-70F3AAE47F55} {76D4B1A1-14FF-4265-8351-06DFD98F2DC3} = {76D4B1A1-14FF-4265-8351-06DFD98F2DC3} {90D05FCC-70F9-4423-A79F-B8D31BFBC228} = {90D05FCC-70F9-4423-A79F-B8D31BFBC228} - {046BA60E-E22F-48AA-AB52-5D8AA7F0A6C4} = {046BA60E-E22F-48AA-AB52-5D8AA7F0A6C4} EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JMS.DVB.Provider.KNC", "..\..\Provider\KNC\JMS.DVB.Provider.KNC.csproj", "{7294F8A2-5ABF-40A5-BE22-4E6ACCEE9394}" ProjectSection(ProjectDependencies) = postProject + {046BA60E-E22F-48AA-AB52-5D8AA7F0A6C4} = {046BA60E-E22F-48AA-AB52-5D8AA7F0A6C4} {6662DE38-74C1-4432-9512-C7E94C2EFDFA} = {6662DE38-74C1-4432-9512-C7E94C2EFDFA} {620B2A8D-ACCC-401A-A67B-70F3AAE47F55} = {620B2A8D-ACCC-401A-A67B-70F3AAE47F55} {76D4B1A1-14FF-4265-8351-06DFD98F2DC3} = {76D4B1A1-14FF-4265-8351-06DFD98F2DC3} {90D05FCC-70F9-4423-A79F-B8D31BFBC228} = {90D05FCC-70F9-4423-A79F-B8D31BFBC228} - {046BA60E-E22F-48AA-AB52-5D8AA7F0A6C4} = {046BA60E-E22F-48AA-AB52-5D8AA7F0A6C4} EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JMS.DVB.Provider.NovaS2", "..\..\Provider\Hauppauge\NovaS2\JMS.DVB.Provider.NovaS2.csproj", "{08D0AD01-4137-49E2-8B28-3B466A142C8A}" ProjectSection(ProjectDependencies) = postProject + {046BA60E-E22F-48AA-AB52-5D8AA7F0A6C4} = {046BA60E-E22F-48AA-AB52-5D8AA7F0A6C4} {6662DE38-74C1-4432-9512-C7E94C2EFDFA} = {6662DE38-74C1-4432-9512-C7E94C2EFDFA} {620B2A8D-ACCC-401A-A67B-70F3AAE47F55} = {620B2A8D-ACCC-401A-A67B-70F3AAE47F55} {76D4B1A1-14FF-4265-8351-06DFD98F2DC3} = {76D4B1A1-14FF-4265-8351-06DFD98F2DC3} - {046BA60E-E22F-48AA-AB52-5D8AA7F0A6C4} = {046BA60E-E22F-48AA-AB52-5D8AA7F0A6C4} EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JMS.DVB.Administration.Framework", "..\..\Administration\PlugIns\AdminFramework\JMS.DVB.Administration.Framework.csproj", "{A5C02DC8-7FBD-4653-AD40-D540F2B05220}" @@ -127,20 +128,20 @@ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JMS.DVB.Administration.Profiles", "..\..\Administration\PlugIns\Profile Manager\JMS.DVB.Administration.Profiles.csproj", "{E20D7FF6-2358-4B25-8D45-F523E0C6B816}" ProjectSection(ProjectDependencies) = postProject {6662DE38-74C1-4432-9512-C7E94C2EFDFA} = {6662DE38-74C1-4432-9512-C7E94C2EFDFA} - {620B2A8D-ACCC-401A-A67B-70F3AAE47F55} = {620B2A8D-ACCC-401A-A67B-70F3AAE47F55} {D528B63E-EE1A-4297-BE78-90D38F6CE0C2} = {D528B63E-EE1A-4297-BE78-90D38F6CE0C2} - {76D4B1A1-14FF-4265-8351-06DFD98F2DC3} = {76D4B1A1-14FF-4265-8351-06DFD98F2DC3} - {E1ED756B-6A4D-4CF3-9E8F-B191E2029C54} = {E1ED756B-6A4D-4CF3-9E8F-B191E2029C54} {9B137745-492B-46DF-A525-3CA83D64AA96} = {9B137745-492B-46DF-A525-3CA83D64AA96} + {E1ED756B-6A4D-4CF3-9E8F-B191E2029C54} = {E1ED756B-6A4D-4CF3-9E8F-B191E2029C54} + {620B2A8D-ACCC-401A-A67B-70F3AAE47F55} = {620B2A8D-ACCC-401A-A67B-70F3AAE47F55} + {76D4B1A1-14FF-4265-8351-06DFD98F2DC3} = {76D4B1A1-14FF-4265-8351-06DFD98F2DC3} {A5C02DC8-7FBD-4653-AD40-D540F2B05220} = {A5C02DC8-7FBD-4653-AD40-D540F2B05220} EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JMS.DVB.Administration.TransponderScan", "..\..\Administration\PlugIns\Transponder Scanner\JMS.DVB.Administration.TransponderScan.csproj", "{9B137745-492B-46DF-A525-3CA83D64AA96}" ProjectSection(ProjectDependencies) = postProject {6662DE38-74C1-4432-9512-C7E94C2EFDFA} = {6662DE38-74C1-4432-9512-C7E94C2EFDFA} + {E1ED756B-6A4D-4CF3-9E8F-B191E2029C54} = {E1ED756B-6A4D-4CF3-9E8F-B191E2029C54} {620B2A8D-ACCC-401A-A67B-70F3AAE47F55} = {620B2A8D-ACCC-401A-A67B-70F3AAE47F55} {76D4B1A1-14FF-4265-8351-06DFD98F2DC3} = {76D4B1A1-14FF-4265-8351-06DFD98F2DC3} - {E1ED756B-6A4D-4CF3-9E8F-B191E2029C54} = {E1ED756B-6A4D-4CF3-9E8F-B191E2029C54} {A5C02DC8-7FBD-4653-AD40-D540F2B05220} = {A5C02DC8-7FBD-4653-AD40-D540F2B05220} EndProjectSection EndProject @@ -149,8 +150,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DVBNETAdmin", "..\..\Admini {6662DE38-74C1-4432-9512-C7E94C2EFDFA} = {6662DE38-74C1-4432-9512-C7E94C2EFDFA} {620B2A8D-ACCC-401A-A67B-70F3AAE47F55} = {620B2A8D-ACCC-401A-A67B-70F3AAE47F55} {76D4B1A1-14FF-4265-8351-06DFD98F2DC3} = {76D4B1A1-14FF-4265-8351-06DFD98F2DC3} - {A224B2D5-7987-4C86-8FF7-CDD09ED76BA0} = {A224B2D5-7987-4C86-8FF7-CDD09ED76BA0} {A5C02DC8-7FBD-4653-AD40-D540F2B05220} = {A5C02DC8-7FBD-4653-AD40-D540F2B05220} + {A224B2D5-7987-4C86-8FF7-CDD09ED76BA0} = {A224B2D5-7987-4C86-8FF7-CDD09ED76BA0} EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UserProfileManager", "..\..\Tools\UserProfileManager\UserProfileManager.csproj", "{E6A0DED8-7C22-4FB0-BDC9-AD93E24EE76C}" @@ -168,11 +169,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JMS.DVB.DeviceAccess", "..\ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JMS.DVB.Provider.Duoflex", "..\..\Provider\Duoflex\JMS.DVB.Provider.Duoflex.csproj", "{7D7FD386-E5C4-4264-853E-3C484BEFCDA6}" ProjectSection(ProjectDependencies) = postProject + {046BA60E-E22F-48AA-AB52-5D8AA7F0A6C4} = {046BA60E-E22F-48AA-AB52-5D8AA7F0A6C4} {6662DE38-74C1-4432-9512-C7E94C2EFDFA} = {6662DE38-74C1-4432-9512-C7E94C2EFDFA} {620B2A8D-ACCC-401A-A67B-70F3AAE47F55} = {620B2A8D-ACCC-401A-A67B-70F3AAE47F55} {76D4B1A1-14FF-4265-8351-06DFD98F2DC3} = {76D4B1A1-14FF-4265-8351-06DFD98F2DC3} {90D05FCC-70F9-4423-A79F-B8D31BFBC228} = {90D05FCC-70F9-4423-A79F-B8D31BFBC228} - {046BA60E-E22F-48AA-AB52-5D8AA7F0A6C4} = {046BA60E-E22F-48AA-AB52-5D8AA7F0A6C4} EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RCLearner", "..\..\Tools\RC Learner\RCLearner.csproj", "{822E86FA-1BB4-4860-A97C-413DB4773A8B}" @@ -191,10 +192,18 @@ Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "CoreSetup", "CoreSetup.wixp EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JMS.DVB.Provider.TeViiS2", "..\..\Provider\TeViiS2\JMS.DVB.Provider.TeViiS2.csproj", "{B26CE348-CB62-4DA1-949D-EDA4526F892D}" ProjectSection(ProjectDependencies) = postProject + {046BA60E-E22F-48AA-AB52-5D8AA7F0A6C4} = {046BA60E-E22F-48AA-AB52-5D8AA7F0A6C4} {6662DE38-74C1-4432-9512-C7E94C2EFDFA} = {6662DE38-74C1-4432-9512-C7E94C2EFDFA} {620B2A8D-ACCC-401A-A67B-70F3AAE47F55} = {620B2A8D-ACCC-401A-A67B-70F3AAE47F55} {76D4B1A1-14FF-4265-8351-06DFD98F2DC3} = {76D4B1A1-14FF-4265-8351-06DFD98F2DC3} + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JMS.DVB.Provider.Ubuntu", "..\..\Provider\Ubuntu\JMS.DVB.Provider.Ubuntu.csproj", "{7FC369A1-D9B5-441A-873E-CB6AC92B9956}" + ProjectSection(ProjectDependencies) = postProject {046BA60E-E22F-48AA-AB52-5D8AA7F0A6C4} = {046BA60E-E22F-48AA-AB52-5D8AA7F0A6C4} + {B2325F13-C217-4D96-846C-3FF857DA6128} = {B2325F13-C217-4D96-846C-3FF857DA6128} + {6662DE38-74C1-4432-9512-C7E94C2EFDFA} = {6662DE38-74C1-4432-9512-C7E94C2EFDFA} + {CC42C4D5-3158-4E1C-9FC8-8138DBE52D8F} = {CC42C4D5-3158-4E1C-9FC8-8138DBE52D8F} EndProjectSection EndProject Global @@ -477,8 +486,23 @@ Global {B26CE348-CB62-4DA1-949D-EDA4526F892D}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {B26CE348-CB62-4DA1-949D-EDA4526F892D}.Release|Mixed Platforms.Build.0 = Release|Any CPU {B26CE348-CB62-4DA1-949D-EDA4526F892D}.Release|x86.ActiveCfg = Release|Any CPU + {7FC369A1-D9B5-441A-873E-CB6AC92B9956}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7FC369A1-D9B5-441A-873E-CB6AC92B9956}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7FC369A1-D9B5-441A-873E-CB6AC92B9956}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {7FC369A1-D9B5-441A-873E-CB6AC92B9956}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {7FC369A1-D9B5-441A-873E-CB6AC92B9956}.Debug|x86.ActiveCfg = Debug|Any CPU + {7FC369A1-D9B5-441A-873E-CB6AC92B9956}.Debug|x86.Build.0 = Debug|Any CPU + {7FC369A1-D9B5-441A-873E-CB6AC92B9956}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7FC369A1-D9B5-441A-873E-CB6AC92B9956}.Release|Any CPU.Build.0 = Release|Any CPU + {7FC369A1-D9B5-441A-873E-CB6AC92B9956}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {7FC369A1-D9B5-441A-873E-CB6AC92B9956}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {7FC369A1-D9B5-441A-873E-CB6AC92B9956}.Release|x86.ActiveCfg = Release|Any CPU + {7FC369A1-D9B5-441A-873E-CB6AC92B9956}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {0F83CADA-641F-4A22-B3E8-35A2FCDF6952} + EndGlobalSection EndGlobal diff --git a/DVB.NET/Setups/Core/CoreSetup.wixproj b/DVB.NET/Setups/Core/CoreSetup.wixproj index 90d72aa..dfeeb22 100644 --- a/DVB.NET/Setups/Core/CoreSetup.wixproj +++ b/DVB.NET/Setups/Core/CoreSetup.wixproj @@ -17,7 +17,7 @@ obj\$(Configuration)\ Debug True - SETUPVERSION=4.3.13 + SETUPVERSION=4.3.19 de-de ICE57 @@ -25,7 +25,7 @@ ..\..\..\msi\ obj\$(Configuration)\ True - SETUPVERSION=4.3.13 + SETUPVERSION=4.3.19 de-de ICE57 @@ -264,6 +264,16 @@ + + JMS.DVB.Provider.Ubuntu + {7fc369a1-d9b5-441a-873e-cb6ac92b9956} + True + + + Binaries;Sources;Content;Documents + + + JMS.DVB.SITables {620b2a8d-accc-401a-a67b-70f3aae47f55} diff --git a/DVB.NET/Setups/Core/DirectoryTree.wxs b/DVB.NET/Setups/Core/DirectoryTree.wxs index f0ee94e..9a35d0f 100644 --- a/DVB.NET/Setups/Core/DirectoryTree.wxs +++ b/DVB.NET/Setups/Core/DirectoryTree.wxs @@ -36,6 +36,8 @@ + + @@ -159,6 +161,9 @@ + + + diff --git a/DVB.NET/Setups/Core/Product.wxs b/DVB.NET/Setups/Core/Product.wxs index 2fb1345..9961ec9 100644 --- a/DVB.NET/Setups/Core/Product.wxs +++ b/DVB.NET/Setups/Core/Product.wxs @@ -62,6 +62,7 @@ + @@ -141,6 +142,8 @@ + + @@ -163,6 +166,7 @@ + diff --git a/DVB.NET/Setups/Server/CardServerSetup.wixproj b/DVB.NET/Setups/Server/CardServerSetup.wixproj index 9ffb9b1..596f677 100644 --- a/DVB.NET/Setups/Server/CardServerSetup.wixproj +++ b/DVB.NET/Setups/Server/CardServerSetup.wixproj @@ -16,14 +16,14 @@ ..\..\..\msi\ obj\$(Configuration)\ Debug - SETUPVERSION=4.3.12 + SETUPVERSION=4.3.14 True de-de ..\..\..\msi\ obj\$(Configuration)\ - SETUPVERSION=4.3.12 + SETUPVERSION=4.3.14 True de-de diff --git a/DVB.NET/Setups/Tools/ToolSetup.wixproj b/DVB.NET/Setups/Tools/ToolSetup.wixproj index f4eb476..a6e1bb3 100644 --- a/DVB.NET/Setups/Tools/ToolSetup.wixproj +++ b/DVB.NET/Setups/Tools/ToolSetup.wixproj @@ -16,7 +16,7 @@ ..\..\..\msi\ obj\$(Configuration)\ Debug - SETUPVERSION=4.3.12 + SETUPVERSION=4.3.15 de-de True ICE57 @@ -24,7 +24,7 @@ ..\..\..\msi\ obj\$(Configuration)\ - SETUPVERSION=4.3.12 + SETUPVERSION=4.3.15 de-de True ICE57 diff --git a/DVB.NET/Setups/rebuild.cmd b/DVB.NET/Setups/rebuild.cmd index 3fb0f33..48d18ea 100644 --- a/DVB.NET/Setups/rebuild.cmd +++ b/DVB.NET/Setups/rebuild.cmd @@ -1,4 +1,4 @@ -set msbuild="C:\Program Files\MSBuild\12.0\Bin\MSBuild.exe" +set msbuild="C:\Program Files (x86)\MSBuild\14.0\Bin\MSBuild.exe" rd /s /q ..\Assemblies diff --git a/DVB.NET/SourceManagement/Information/AudioInformation.cs b/DVB.NET/SourceManagement/Information/AudioInformation.cs index 7cfea7d..09917f5 100644 --- a/DVB.NET/SourceManagement/Information/AudioInformation.cs +++ b/DVB.NET/SourceManagement/Information/AudioInformation.cs @@ -23,6 +23,11 @@ public class AudioInformation : ICloneable /// public string Language { get; set; } + /// + /// Liest´oder setzt die AAC Informationen zur Tonspur. + /// + public ushort? AAC { get; set; } + /// /// Erzeugt eine neue Beschreibung. /// @@ -38,9 +43,11 @@ public override string ToString() { // Report if (AudioType == AudioTypes.AC3) - return string.Format( "{0} (AC3) [{1}]", Language, AudioStream ); + return string.Format("{0} (AC3) [{1}]", Language, AudioStream); + else if (AAC.HasValue) + return string.Format("{0} (AAC {2:X4}) [{1}]", Language, AudioStream, AAC.Value); else - return string.Format( "{0} [{1}]", Language, AudioStream ); + return string.Format("{0} [{1}]", Language, AudioStream); } #region ICloneable Members @@ -49,29 +56,19 @@ public override string ToString() /// Erzeugt eine exakte Kopie dieser Information. /// /// Die gewünschte Kopie. - public AudioInformation Clone() + public AudioInformation Clone() => new AudioInformation { - // Create empty - AudioInformation clone = new AudioInformation(); - - // Fill - clone.AudioStream = AudioStream; - clone.AudioType = AudioType; - clone.Language = Language; - - // Report - return clone; - } + AAC = AAC, + AudioStream = AudioStream, + AudioType = AudioType, + Language = Language, + }; /// /// Erzeugt eine exakte Kopie dieser Information. /// /// Die gewünschte Kopie. - object ICloneable.Clone() - { - // Forward - return Clone(); - } + object ICloneable.Clone() => Clone(); #endregion } diff --git a/DVB.NET/TS/Manager.cs b/DVB.NET/TS/Manager.cs index 4477b2e..c590525 100644 --- a/DVB.NET/TS/Manager.cs +++ b/DVB.NET/TS/Manager.cs @@ -106,7 +106,7 @@ public class Manager : IDisposable, IStreamConsumer2 /// private long m_VideoDelay; - private UDPStreaming m_UDPStream = new UDPStreaming( MulticastTTL, MaxUDPQueueLength ); + private UDPStreaming m_UDPStream = new UDPStreaming(MulticastTTL, MaxUDPQueueLength); /// /// Set as soon as the first PCR arrived. @@ -248,7 +248,7 @@ public class Manager : IDisposable, IStreamConsumer2 static Manager() { // Create padding - for (int i = Padding.Length; i-- > 0; ) + for (int i = Padding.Length; i-- > 0;) Padding[i] = 0xff; // Check settings @@ -261,27 +261,27 @@ static Manager() var pcrDelay = ConfigurationManager.AppSettings["TS.PCRDelay"]; // Overwrite - if (!string.IsNullOrEmpty( pcrDelay )) - PCRDelay = long.Parse( pcrDelay ); - if (!string.IsNullOrEmpty( videoDelay )) - VideoDelay = long.Parse( videoDelay ); - if (!string.IsNullOrEmpty( multiTTL )) - MulticastTTL = int.Parse( multiTTL ); - if (!string.IsNullOrEmpty( videoLength )) - SetVideoLength = bool.Parse( videoLength ); - if (!string.IsNullOrEmpty( maxUDPQueue )) - MaxUDPQueueLength = int.Parse( maxUDPQueue ); - if (!string.IsNullOrEmpty( noHDTVPCR )) - DisablePCRForHDTV = bool.Parse( noHDTVPCR ); - if (!string.IsNullOrEmpty( noSDTVPCR )) - DisablePCRForSDTV = bool.Parse( noSDTVPCR ); + if (!string.IsNullOrEmpty(pcrDelay)) + PCRDelay = long.Parse(pcrDelay); + if (!string.IsNullOrEmpty(videoDelay)) + VideoDelay = long.Parse(videoDelay); + if (!string.IsNullOrEmpty(multiTTL)) + MulticastTTL = int.Parse(multiTTL); + if (!string.IsNullOrEmpty(videoLength)) + SetVideoLength = bool.Parse(videoLength); + if (!string.IsNullOrEmpty(maxUDPQueue)) + MaxUDPQueueLength = int.Parse(maxUDPQueue); + if (!string.IsNullOrEmpty(noHDTVPCR)) + DisablePCRForHDTV = bool.Parse(noHDTVPCR); + if (!string.IsNullOrEmpty(noSDTVPCR)) + DisablePCRForSDTV = bool.Parse(noSDTVPCR); } /// /// Create a transport stream with no attached physical file. /// public Manager() - : this( (Stream) null ) + : this((Stream)null) { } @@ -289,8 +289,8 @@ public Manager() /// Create a transport stream on a . /// /// Typically a disk file. - public Manager( Stream target ) - : this( target, 0 ) + public Manager(Stream target) + : this(target, 0) { } @@ -298,8 +298,8 @@ public Manager( Stream target ) /// Erzeugt einen neuen Datenstrom. /// /// Optional der volle Pfad zu einer Datei. - public Manager( string path ) - : this( path, 0 ) + public Manager(string path) + : this(path, 0) { } @@ -308,8 +308,8 @@ public Manager( string path ) /// /// Path to the file. /// Optional initial PID counter. - public Manager( string path, short nextPID ) - : this( path, nextPID, DefaultBufferSize ) + public Manager(string path, short nextPID) + : this(path, nextPID, DefaultBufferSize) { } @@ -320,19 +320,19 @@ public Manager( string path, short nextPID ) /// Die als nächstes zu verwendende Datenstromkennung. /// Die Größe des zu verwendenden Zwischenspeichers. /// Der Zwischenspeicher muss mindestens 1.000 Bytes groß sein. - public Manager( string path, short nextPID, int bufferSize ) - : this( (Stream) null, nextPID ) + public Manager(string path, short nextPID, int bufferSize) + : this((Stream)null, nextPID) { // Validate if (bufferSize <= 1000) - throw new ArgumentOutOfRangeException( "bufferSize" ); + throw new ArgumentOutOfRangeException("bufferSize"); // Remember m_BufferSize = bufferSize; // Open the file if (path != null) - BufferedTarget = CreateBuffered( path ); + BufferedTarget = CreateBuffered(path); } /// @@ -340,10 +340,10 @@ public Manager( string path, short nextPID, int bufferSize ) /// /// Der volle Pfad zur Datei. /// Der gewünschte Speicherbereich. - private DoubleBufferedFile CreateBuffered( string filePath ) + private DoubleBufferedFile CreateBuffered(string filePath) { // Process - return new DoubleBufferedFile( filePath, m_BufferSize ); + return new DoubleBufferedFile(filePath, m_BufferSize); } /// @@ -368,18 +368,18 @@ public bool CanSplitFile /// /// Der volle Pfad zur gewünschten Zieldatei. /// Es wurde keine Zieldatei angegeben. - public void SplitFile( string newFilePath ) + public void SplitFile(string newFilePath) { // Validate - if (string.IsNullOrEmpty( newFilePath )) - throw new ArgumentNullException( "newFilePath" ); + if (string.IsNullOrEmpty(newFilePath)) + throw new ArgumentNullException("newFilePath"); // Check mode of operation if (!CanSplitFile) throw new InvalidOperationException(); // Create new file and install it - using (Interlocked.Exchange( ref PendingTarget, CreateBuffered( newFilePath ) )) + using (Interlocked.Exchange(ref PendingTarget, CreateBuffered(newFilePath))) { // The new target is now installed and the previous one will be discarded unused - if any existed } @@ -390,7 +390,7 @@ public void SplitFile( string newFilePath ) /// /// Typically a disk file. /// Optional initial PID counter. - public Manager( Stream target, short nextPID ) + public Manager(Stream target, short nextPID) { // Fix delay m_NoHDTVPCR = DisablePCRForHDTV; @@ -413,8 +413,8 @@ public Manager( Stream target, short nextPID ) ProgramAssociation.ProgramNumber = NextPID++; // Create helper - ProgramMap = new Tables.PMT( ProgramAssociation.ProgramStream, ProgramAssociation.ProgramNumber ); - ServiceDescription = new Tables.SDT( ProgramAssociation.NetworkIdentifier, ProgramAssociation.ProgramNumber ); + ProgramMap = new Tables.PMT(ProgramAssociation.ProgramStream, ProgramAssociation.ProgramNumber); + ServiceDescription = new Tables.SDT(ProgramAssociation.NetworkIdentifier, ProgramAssociation.ProgramNumber); } /// @@ -450,8 +450,8 @@ private void SendPAT() PATSent = true; // Forward - ProgramAssociation.Send( this ); - ProgramMap.Send( this ); + ProgramAssociation.Send(this); + ProgramMap.Send(this); //ServiceDescription.Send(this); } } @@ -462,14 +462,14 @@ private void SendPAT() /// Individual packet counter. /// Transport stream identifier to use. /// Full table data. - public void SendTable( ref int counter, int pid, byte[] buffer ) + public void SendTable(ref int counter, int pid, byte[] buffer) { // Get the chunks int packs = (buffer.Length + PacketSize - 1) / PacketSize; int rest = buffer.Length % PacketSize; // Forward - Send( ref counter, pid, buffer, 0, packs, true, (0 == rest) ? PacketSize : rest, true, -1 ); + Send(ref counter, pid, buffer, 0, packs, true, (0 == rest) ? PacketSize : rest, true, -1); } /// @@ -477,10 +477,10 @@ public void SendTable( ref int counter, int pid, byte[] buffer ) /// /// Encoding of the video stream. /// The newly created video stream instance. - public VideoStream AddVideo( byte encoding ) + public VideoStream AddVideo(byte encoding) { // Forward - return AddVideo( encoding, false ); + return AddVideo(encoding, false); } /// @@ -489,15 +489,15 @@ public VideoStream AddVideo( byte encoding ) /// Encoding of the video stream. /// Set to disable PCR generation. /// The newly created video stream instance. - public VideoStream AddVideo( byte encoding, bool noPCR ) + public VideoStream AddVideo(byte encoding, bool noPCR) { // Check mode - var isH264 = (encoding == (byte) EPG.StreamTypes.H264); + var isH264 = (encoding == (byte)EPG.StreamTypes.H264); var forbidPCR = (m_NoHDTVPCR && isH264) || (m_NoSDTVPCR && !isH264); // Run bool isPCR; - short pid = AddStream( StreamTypes.Video, encoding, noPCR || forbidPCR, false, null, out isPCR ); + short pid = AddStream(StreamTypes.Video, encoding, noPCR || forbidPCR, false, null, null, out isPCR); // Create the correct type of stream VideoStream video; @@ -507,16 +507,16 @@ public VideoStream AddVideo( byte encoding, bool noPCR ) m_IsHDTV = true; // H.264 - video = new HDTVStream( this, pid, isPCR ); + video = new HDTVStream(this, pid, isPCR); } else { // MPEG-2 - video = new VideoStream( this, pid, isPCR ); + video = new VideoStream(this, pid, isPCR); } // Remember - m_Streams.Add( video ); + m_Streams.Add(video); // Report return video; @@ -525,36 +525,37 @@ public VideoStream AddVideo( byte encoding, bool noPCR ) /// /// Report if this Transport Stream includes a H.264 video stream. /// - public bool HasHDTVVideo - { - get - { - // Report - return m_IsHDTV; - } - } + public bool HasHDTVVideo => m_IsHDTV; /// /// Create a new audio stream and add it to this transport stream. /// /// The ISO name of the language for this audio stream. /// The newly created audio stream instance. - public AudioStream AddAudio( string name ) + public AudioStream AddAudio(string name) => AddAudio(name, null); + + /// + /// Create a new audio stream and add it to this transport stream. + /// + /// The ISO name of the language for this audio stream. + /// Optional AAC Profile, level and type. + /// The newly created audio stream instance. + public AudioStream AddAudio(string name, ushort? aac) { // Flag bool isPCR; // Run - short pid = AddStream( StreamTypes.Audio, 255, false, false, null, out isPCR ); + short pid = AddStream(StreamTypes.Audio, 255, false, false, null, aac, out isPCR); // Set the name of the language - if (!string.IsNullOrEmpty( name )) ProgramMap.SetAudioLanguage( pid, name ); + if (!string.IsNullOrEmpty(name)) ProgramMap.SetAudioLanguage(pid, name); // Create - AudioStream audio = new AudioStream( this, pid, isPCR ); + AudioStream audio = new AudioStream(this, pid, isPCR); // Remember - m_Streams.Add( audio ); + m_Streams.Add(audio); // Make it the guide if ((null != m_Splitter) && (0 == m_GuidePID)) m_GuidePID = pid; @@ -567,32 +568,28 @@ public AudioStream AddAudio( string name ) /// Add a new Dolby Digital Audio Stream to this Transport Stream. /// /// The new data stream. - public DolbyStream AddDolby() - { - // Forward - return AddDolby( null ); - } + public DolbyStream AddDolby() => AddDolby(null); /// /// Create a new Dobly Digital (AC3) audio stream and add it to this transport stream. /// /// The newly created AC3 audio stream instance. - public DolbyStream AddDolby( string name ) + public DolbyStream AddDolby(string name) { // Flag bool isPCR; // Run - short pid = AddStream( StreamTypes.Private, 255, false, false, null, out isPCR ); + short pid = AddStream(StreamTypes.Private, 255, false, false, null, null, out isPCR); // Set the name of the language - if (!string.IsNullOrEmpty( name )) ProgramMap.SetAudioLanguage( pid, name ); + if (!string.IsNullOrEmpty(name)) ProgramMap.SetAudioLanguage(pid, name); // Create - DolbyStream dolby = new DolbyStream( this, pid, isPCR ); + DolbyStream dolby = new DolbyStream(this, pid, isPCR); // Remember - m_Streams.Add( dolby ); + m_Streams.Add(dolby); // Make it the guide if ((null != m_Splitter) && (0 == m_GuidePID)) m_GuidePID = pid; @@ -611,13 +608,13 @@ public TTXStream AddTeleText() bool isPCR; // Run - short pid = AddStream( StreamTypes.TeleText, 255, false, true, null, out isPCR ); + short pid = AddStream(StreamTypes.TeleText, 255, false, true, null, null, out isPCR); // Create - TTXStream ttx = new TTXStream( this, pid, isPCR ); + TTXStream ttx = new TTXStream(this, pid, isPCR); // Remember - m_Streams.Add( ttx ); + m_Streams.Add(ttx); // Make it the guide if ((null != m_Splitter) && (0 == m_GuidePID)) m_GuidePID = pid; @@ -631,19 +628,19 @@ public TTXStream AddTeleText() /// /// Information on the contents of this subtitle stream. /// The new subtitle stream. - public SubtitleStream AddSubtitles( EPG.SubtitleInfo[] info ) + public SubtitleStream AddSubtitles(EPG.SubtitleInfo[] info) { // Flag bool isPCR; // Run - short pid = AddStream( StreamTypes.SubTitles, 255, false, true, info, out isPCR ); + short pid = AddStream(StreamTypes.SubTitles, 255, false, true, info, null, out isPCR); // Create - SubtitleStream sub = new SubtitleStream( this, pid, isPCR ); + SubtitleStream sub = new SubtitleStream(this, pid, isPCR); // Remember - m_Streams.Add( sub ); + m_Streams.Add(sub); // Make it the guide if ((null != m_Splitter) && (0 == m_GuidePID)) m_GuidePID = pid; @@ -661,9 +658,10 @@ public SubtitleStream AddSubtitles( EPG.SubtitleInfo[] info ) /// Set if the stream will be the PCR reference. /// Set if the stream should not participate in PTS synchronisation. /// Information on the contents of a subtitle stream. + /// Optional AAC profile, level and type. /// Set to disable PCR from PTS generation. /// A randomly choosen but unique transport stream identifier. - private short AddStream( StreamTypes type, byte encoding, bool noPCR, bool noPTS, EPG.SubtitleInfo[] info, out bool isPCR ) + private short AddStream(StreamTypes type, byte encoding, bool noPCR, bool noPTS, EPG.SubtitleInfo[] info, ushort? aac, out bool isPCR) { // Create pid short pid = NextPID++; @@ -672,7 +670,7 @@ private short AddStream( StreamTypes type, byte encoding, bool noPCR, bool noPTS int keyPID = pid; // Forward - isPCR = ProgramMap.Add( type, encoding, pid, noPCR, info ); + isPCR = ProgramMap.Add(type, encoding, pid, noPCR, info, aac); // Reload lock (m_Queue) @@ -681,13 +679,13 @@ private short AddStream( StreamTypes type, byte encoding, bool noPCR, bool noPTS PATSent = false; // Load - Packet buffers = (Packet) m_Buffers[keyPID]; + Packet buffers = (Packet)m_Buffers[keyPID]; // Create new if (null == buffers) { // Create new - buffers = new Packet( this, keyPID ); + buffers = new Packet(this, keyPID); // Remember m_Buffers[keyPID] = buffers; @@ -695,9 +693,9 @@ private short AddStream( StreamTypes type, byte encoding, bool noPCR, bool noPTS // Set up if (StreamTypes.Video == type) - buffers.SetAudioVideo( true ); + buffers.SetAudioVideo(true); else if ((StreamTypes.Audio == type) || (StreamTypes.Private == type)) - buffers.SetAudioVideo( false ); + buffers.SetAudioVideo(false); // May disable PTS synchronisation (e.g. for TeleText streams) buffers.IgnorePTS = noPTS; @@ -713,7 +711,7 @@ private short AddStream( StreamTypes type, byte encoding, bool noPCR, bool noPTS /// Individual packet counter which will not be incremented. /// Related transport stream identifier. /// The PTS from a PES header used for PCR. - void IStreamConsumer.SendPCR( int counter, int pid, long pts ) + void IStreamConsumer.SendPCR(int counter, int pid, long pts) { // Remember if (0 == m_PCRAvailable) @@ -724,9 +722,9 @@ void IStreamConsumer.SendPCR( int counter, int pid, long pts ) // Validate if ((counter < 0) || (counter > 0xf)) - throw new ArgumentOutOfRangeException( "counter", counter, "only four bits allowed" ); + throw new ArgumentOutOfRangeException("counter", counter, "only four bits allowed"); if ((pid < 0) || (pid >= 0x1fff)) - throw new ArgumentOutOfRangeException( "pid", pid, "only 13 bits allowed" ); + throw new ArgumentOutOfRangeException("pid", pid, "only 13 bits allowed"); // Correct a bit (90kHz) long pcr = pts - m_PCRDelay; @@ -738,8 +736,8 @@ void IStreamConsumer.SendPCR( int counter, int pid, long pts ) pcr -= Packet.PTSOverrun; // Split - byte pidh = (byte) (pid >> 8); - byte pidl = (byte) (pid & 0xff); + byte pidh = (byte)(pid >> 8); + byte pidl = (byte)(pid & 0xff); // Allocate data byte[] ts = new byte[FullSize]; @@ -748,23 +746,23 @@ void IStreamConsumer.SendPCR( int counter, int pid, long pts ) ts[0] = 0x47; ts[1] = pidh; ts[2] = pidl; - ts[3] = (byte) (0x20 | ((counter - 1) & 0x0f)); + ts[3] = (byte)(0x20 | ((counter - 1) & 0x0f)); // Process adaption control ts[4] = 0xb7; ts[5] = 0x10; - ts[6] = (byte) ((pcr >> 25) & 0xff); - ts[7] = (byte) ((pcr >> 17) & 0xff); - ts[8] = (byte) ((pcr >> 9) & 0xff); - ts[9] = (byte) ((pcr >> 1) & 0xff); - ts[10] = (byte) (128 * (pcr & 0x01)); + ts[6] = (byte)((pcr >> 25) & 0xff); + ts[7] = (byte)((pcr >> 17) & 0xff); + ts[8] = (byte)((pcr >> 9) & 0xff); + ts[9] = (byte)((pcr >> 1) & 0xff); + ts[10] = (byte)(128 * (pcr & 0x01)); ts[11] = 0x00; // Pad the rest - Array.Copy( Padding, 0, ts, 12, ts.Length - 12 ); + Array.Copy(Padding, 0, ts, 12, ts.Length - 12); // Enqueue to writer - Enqueue( ts, pid, false, true, pts ); + Enqueue(ts, pid, false, true, pts); } /// @@ -773,7 +771,7 @@ void IStreamConsumer.SendPCR( int counter, int pid, long pts ) /// /// Ein elementares Paket. /// Die gewünschte Systemzeit. - public static TimeSpan GetPCR( byte[] packet ) + public static TimeSpan GetPCR(byte[] packet) { // Load parts long b0 = packet[6]; @@ -786,7 +784,7 @@ public static TimeSpan GetPCR( byte[] packet ) long clockTicks = b4 + 2 * (b3 + 256 * (b2 + 256 * (b1 + 256 * b0))); // Calculate back from 90kHz clock - return new TimeSpan( clockTicks * 1000 / 9 ); + return new TimeSpan(clockTicks * 1000 / 9); } /// @@ -829,10 +827,10 @@ bool IStreamConsumer2.IgnoreInput /// Set if the first byte is the first byte of a PES header. /// Number of bytes in the last packet - which may be padded. /// If not negative this is the PES headers PTS - isFirst will be set. - void IStreamConsumer.Send( ref int counter, int pid, byte[] buffer, int start, int packs, bool isFirst, int sizeOfLast, long pts ) + void IStreamConsumer.Send(ref int counter, int pid, byte[] buffer, int start, int packs, bool isFirst, int sizeOfLast, long pts) { // Forward - Send( ref counter, pid, buffer, start, packs, isFirst, sizeOfLast, false, pts ); + Send(ref counter, pid, buffer, start, packs, isFirst, sizeOfLast, false, pts); } /// @@ -848,7 +846,7 @@ void IStreamConsumer.Send( ref int counter, int pid, byte[] buffer, int start, i /// Set if padding will be done using an adpation field /// just before the payload data. /// If not negative this is the PES headers PTS - isFirst will be set. - private void Send( ref int counter, int pid, byte[] buffer, int start, int packs, bool isFirst, int sizeOfLast, bool standardPadding, long pts ) + private void Send(ref int counter, int pid, byte[] buffer, int start, int packs, bool isFirst, int sizeOfLast, bool standardPadding, long pts) { // Inform the splitter as soon as possible if ((pts >= 0) && (pid == m_GuidePID) && (null != m_Splitter)) @@ -859,17 +857,17 @@ private void Send( ref int counter, int pid, byte[] buffer, int start, int packs // Validate if ((counter < 0) || (counter > 0xf)) - throw new ArgumentOutOfRangeException( "counter", counter, "only four bits allowed" ); + throw new ArgumentOutOfRangeException("counter", counter, "only four bits allowed"); if ((pid < 0) || (pid >= 0x1fff)) - throw new ArgumentOutOfRangeException( "pid", pid, "only 13 bits allowed" ); + throw new ArgumentOutOfRangeException("pid", pid, "only 13 bits allowed"); if (null == buffer) - throw new ArgumentNullException( "buffer" ); + throw new ArgumentNullException("buffer"); if ((start < 0) || (start > buffer.Length)) - throw new ArgumentOutOfRangeException( "start", start, "exceeds buffer size" ); + throw new ArgumentOutOfRangeException("start", start, "exceeds buffer size"); if ((packs < 0) || (packs > (buffer.Length / PacketSize + 1))) - throw new ArgumentOutOfRangeException( "packs", packs, "exceeds buffer size" ); + throw new ArgumentOutOfRangeException("packs", packs, "exceeds buffer size"); if ((sizeOfLast < 0) || (sizeOfLast > PacketSize)) - throw new ArgumentOutOfRangeException( "sizeOfLast", sizeOfLast, "exceeds packet size" ); + throw new ArgumentOutOfRangeException("sizeOfLast", sizeOfLast, "exceeds packet size"); // Done if (0 == packs) @@ -886,14 +884,14 @@ private void Send( ref int counter, int pid, byte[] buffer, int start, int packs // Validate if (end > buffer.Length) - throw new ArgumentOutOfRangeException( "packs", packs, "exceeds buffer size" ); + throw new ArgumentOutOfRangeException("packs", packs, "exceeds buffer size"); // Allocate data byte[] ts = new byte[packs * FullSize]; // Split - byte pidh = (byte) (pid >> 8); - byte pidl = (byte) (pid & 0xff); + byte pidh = (byte)(pid >> 8); + byte pidl = (byte)(pid & 0xff); // Flag if (isFirst) @@ -906,7 +904,7 @@ private void Send( ref int counter, int pid, byte[] buffer, int start, int packs ts[tsi++] = 0x47; ts[tsi++] = pidh; ts[tsi++] = pidl; - ts[tsi++] = (byte) (0x10 | counter++); + ts[tsi++] = (byte)(0x10 | counter++); // Reset if (4 == tsi) @@ -931,23 +929,23 @@ private void Send( ref int counter, int pid, byte[] buffer, int start, int packs int pad = PacketSize - rest - 2; // Add adaption - ts[tsi + 0] = (byte) (pad + 1); + ts[tsi + 0] = (byte)(pad + 1); ts[tsi + 1] = 0x00; // Pad first - Array.Copy( Padding, 0, ts, tsi + 2, pad ); + Array.Copy(Padding, 0, ts, tsi + 2, pad); // Data last - Array.Copy( buffer, start, ts, tsi + 2 + pad, rest ); + Array.Copy(buffer, start, ts, tsi + 2 + pad, rest); } else { // Move in - Array.Copy( buffer, start, ts, tsi, (rest >= PacketSize) ? PacketSize : rest ); + Array.Copy(buffer, start, ts, tsi, (rest >= PacketSize) ? PacketSize : rest); // Pad if (last) - Array.Copy( Padding, 0, ts, tsi + rest, PacketSize - rest ); + Array.Copy(Padding, 0, ts, tsi + rest, PacketSize - rest); } } @@ -955,7 +953,7 @@ private void Send( ref int counter, int pid, byte[] buffer, int start, int packs lock (m_Queue) { // Enqueue to writer - Enqueue( ts, pid, isFirst, false, pts ); + Enqueue(ts, pid, isFirst, false, pts); // Count PacketCounter += packs; @@ -971,10 +969,10 @@ private void Send( ref int counter, int pid, byte[] buffer, int start, int packs /// /// /// Set to flush PCR, too. - private void Flush( int pid, bool withPCR ) + private void Flush(int pid, bool withPCR) { // Move full packet to synchronizer queue - Enqueue( pid, withPCR ); + Enqueue(pid, withPCR); // Cleanup as much as possible for (bool processed = true; processed; processed = false) @@ -985,7 +983,7 @@ private void Flush( int pid, bool withPCR ) processed = true; // Process as long as there are packets in each stream - for (bool find = true; find; ) + for (bool find = true; find;) { // The minium PTS packet Packet minHolder = null; @@ -1058,10 +1056,10 @@ private void Flush( int pid, bool withPCR ) /// /// /// Set to flush PCR, too. - private void Enqueue( int pid, bool withPCR ) + private void Enqueue(int pid, bool withPCR) { // Attach to the list - Packet buffers = (Packet) m_Buffers[pid]; + Packet buffers = (Packet)m_Buffers[pid]; // Is empty if (null == buffers) @@ -1074,7 +1072,7 @@ private void Enqueue( int pid, bool withPCR ) if (!withPCR) { // Create new - collect = new Packet( buffers ); + collect = new Packet(buffers); // Clone PTS from PES collect.PTS = buffers.PTS; @@ -1089,7 +1087,7 @@ private void Enqueue( int pid, bool withPCR ) bool isPCR = false; // Process all - for (int ib = 0, imax = buffers.Count; ib < imax; ) + for (int ib = 0, imax = buffers.Count; ib < imax;) { // Load next byte[] buf = buffers[ib++]; @@ -1113,12 +1111,12 @@ private void Enqueue( int pid, bool withPCR ) buffers.Clear(); // Append as PCR - buffers.Add( null ); - buffers.Add( buf ); + buffers.Add(null); + buffers.Add(buf); // Remember collected data if (collect.Count > 0) - buffers.Enqueue( collect ); + buffers.Enqueue(collect); // Finish return; @@ -1131,12 +1129,12 @@ private void Enqueue( int pid, bool withPCR ) if (null == collect) { // Send to file immediately to clenaup all buffers - SendBuffer( buf, buffers ); + SendBuffer(buf, buffers); } else { // Save for later processing - collect.Add( buf ); + collect.Add(buf); } } @@ -1144,7 +1142,7 @@ private void Enqueue( int pid, bool withPCR ) buffers.Clear(); // Remember collected data - if (null != collect) buffers.Enqueue( collect ); + if (null != collect) buffers.Enqueue(collect); } /// @@ -1153,10 +1151,10 @@ private void Enqueue( int pid, bool withPCR ) /// Full buffer to send. /// The originator of the buffer. /// Set if buffer is not empty. - internal bool SendBuffer( byte[] buf, Packet source ) + internal bool SendBuffer(byte[] buf, Packet source) { // Validate - Debug.Assert( (buf.Length % FullSize) == 0 ); + Debug.Assert((buf.Length % FullSize) == 0); // Count m_Length += buf.Length; @@ -1180,7 +1178,7 @@ internal bool SendBuffer( byte[] buf, Packet source ) WaitDisk(); // Start an asynchronous write operation - m_Writer = Target.BeginWrite( buf, 0, buf.Length, null, null ); + m_Writer = Target.BeginWrite(buf, 0, buf.Length, null, null); } // Has buffered output @@ -1194,14 +1192,14 @@ internal bool SendBuffer( byte[] buf, Packet source ) if ((buf[3] & 0x20) != 0) if (buf[4] >= 1) if ((buf[5] & 0x10) != 0) - pcrReport( BufferedTarget.FilePath, BufferedTarget.TotalBytesWritten, buf ); + pcrReport(BufferedTarget.FilePath, BufferedTarget.TotalBytesWritten, buf); // Send to file - BufferedTarget.Write( buf, 0, buf.Length ); + BufferedTarget.Write(buf, 0, buf.Length); } // See if there is a file switch pending - var pendingSwitch = Interlocked.Exchange( ref PendingTarget, null ); + var pendingSwitch = Interlocked.Exchange(ref PendingTarget, null); // Activate the new one - this will enforce a flush on the previous file and may lead to corruption if (pendingSwitch != null) @@ -1213,14 +1211,14 @@ internal bool SendBuffer( byte[] buf, Packet source ) return false; // Forward to optional stream - m_UDPStream.Send( buf ); + m_UDPStream.Send(buf); // Read consumer var consumer = InProcessConsumer; // Finally send to in-process consumer if (null != consumer) - consumer( buf ); + consumer(buf); // Found some return true; @@ -1234,7 +1232,7 @@ internal bool SendBuffer( byte[] buf, Packet source ) /// Set if the first packet starts at a PES header. /// Set if this is a PCR report. /// If not negative this is the PES headers PTS - isFirst will be set. - private void Enqueue( byte[] buf, int pid, bool isFirst, bool isPCR, long pts ) + private void Enqueue(byte[] buf, int pid, bool isFirst, bool isPCR, long pts) { // Check mode bool isTSInfo = ((ProgramAssociation.PID == pid) || (ProgramMap.PID == pid) || (ServiceDescription.PID == pid) || (0x12 == pid)); @@ -1246,17 +1244,17 @@ private void Enqueue( byte[] buf, int pid, bool isFirst, bool isPCR, long pts ) if (isTSInfo) { // Forward - SendBuffer( buf, null ); + SendBuffer(buf, null); // Done return; } // Attach to buffer - Packet buffers = (Packet) m_Buffers[pid]; + Packet buffers = (Packet)m_Buffers[pid]; // Send complete PES packet collected - if (isFirst) Flush( pid, false ); + if (isFirst) Flush(pid, false); // Create once if (null == buffers) return; @@ -1265,10 +1263,10 @@ private void Enqueue( byte[] buf, int pid, bool isFirst, bool isPCR, long pts ) buffers.PTS = pts; // PCR mark - if (isPCR) buffers.Add( null ); + if (isPCR) buffers.Add(null); // Data - buffers.Add( buf ); + buffers.Add(buf); } } @@ -1284,7 +1282,7 @@ private void WaitDisk() if (!m_Writer.IsCompleted) m_Writer.AsyncWaitHandle.WaitOne(); // Finish - if (null != Target) Target.EndWrite( m_Writer ); + if (null != Target) Target.EndWrite(m_Writer); // Reset m_Writer = null; @@ -1308,25 +1306,25 @@ public string Flush() foreach (DictionaryEntry ent in m_Buffers) { // Retrieve - int pid = (int) ent.Key; - Packet buffers = (Packet) ent.Value; + int pid = (int)ent.Key; + Packet buffers = (Packet)ent.Value; // Send - Flush( pid, true ); + Flush(pid, true); } // Create report foreach (DictionaryEntry ent in m_Buffers) { // Retrieve - int pid = (int) ent.Key; - Packet buffers = (Packet) ent.Value; + int pid = (int)ent.Key; + Packet buffers = (Packet)ent.Value; // Separate - if (stat.Length > 0) stat.Append( "\r\n" ); + if (stat.Length > 0) stat.Append("\r\n"); // Add report - stat.AppendFormat( "{0}: MaxQueue={1} Overflow(s)={2}", pid, buffers.MaxQueueLength, buffers.Overflows ); + stat.AppendFormat("{0}: MaxQueue={1} Overflow(s)={2}", pid, buffers.MaxQueueLength, buffers.Overflows); } // Forward @@ -1373,7 +1371,7 @@ public void StartFilters() public void StopFilters() { // Stop streaming - SetStreamTarget( "localhost", 0 ); + SetStreamTarget("localhost", 0); // Forward to splitter if (m_Splitter != null) @@ -1410,10 +1408,10 @@ public long AVLength /// Name of the client system. If the format *IP Address is /// used multicast addressing is assumed. /// TCP/IP UDP Port to use. - public void SetStreamTarget( string client, int port ) + public void SetStreamTarget(string client, int port) { // Forward - m_UDPStream.SetStreamTarget( client, port ); + m_UDPStream.SetStreamTarget(client, port); } /// @@ -1488,19 +1486,19 @@ public int StreamCount /// Ergänzt einen Eintrag der Programmzeitschrift. /// /// Ein beliebiger Eintrag der Programmzeitschrift. - public void AddEventTable( EPG.Section section ) + public void AddEventTable(EPG.Section section) { // Forward if (null != section) if (section.IsValid) - AddEventTable( section.Table as EPG.Tables.EIT ); + AddEventTable(section.Table as EPG.Tables.EIT); } /// /// Ergänzt einen Eintrag der Programmzeitschrift. /// /// Ein beliebiger Eintrag der Programmzeitschrift. - public void AddEventTable( EPG.Tables.EIT eit ) + public void AddEventTable(EPG.Tables.EIT eit) { // Ignore until PCR is available if (m_PCRAvailable <= 0) @@ -1526,12 +1524,12 @@ public void AddEventTable( EPG.Tables.EIT eit ) return; // Update the table - eit.OriginalNetworkIdentifier = (ushort) ProgramAssociation.NetworkIdentifier; + eit.OriginalNetworkIdentifier = (ushort)ProgramAssociation.NetworkIdentifier; eit.TransportStreamIdentifier = 1; - eit.ServiceIdentifier = (ushort) ProgramAssociation.ProgramNumber; + eit.ServiceIdentifier = (ushort)ProgramAssociation.ProgramNumber; // Has running or nearly running? - if (!Array.Exists( eit.Entries, entry => (EPG.EventStatus.Running == entry.Status) || (EPG.EventStatus.NotRunning == entry.Status) )) + if (!Array.Exists(eit.Entries, entry => (EPG.EventStatus.Running == entry.Status) || (EPG.EventStatus.NotRunning == entry.Status))) return; // Try to recreate @@ -1539,7 +1537,7 @@ public void AddEventTable( EPG.Tables.EIT eit ) // Inject if (null != table) - SendTable( ref m_EPGCounter, 0x12, table ); + SendTable(ref m_EPGCounter, 0x12, table); } /// @@ -1548,10 +1546,10 @@ public void AddEventTable( EPG.Tables.EIT eit ) /// Die originale Netzwerkkenung des zugehörigen Dienstes. /// Die Kennung des Transport Streams. /// Die eindeutige Kennung des Dienstes zu dieser Datei. - public void SetEPGMapping( ushort network, ushort transportStream, ushort service ) + public void SetEPGMapping(ushort network, ushort transportStream, ushort service) { // Forward - EPGMapping = new SourceIdentifier( network, transportStream, service ); + EPGMapping = new SourceIdentifier(network, transportStream, service); } #region IDisposable Members @@ -1589,7 +1587,7 @@ public void Dispose() BufferedTarget = null; // Release socket - SetStreamTarget( "localhost", 0 ); + SetStreamTarget("localhost", 0); } #endregion diff --git a/DVB.NET/TS/TSParser.cs b/DVB.NET/TS/TSParser.cs index f207a0a..1c48ce1 100644 --- a/DVB.NET/TS/TSParser.cs +++ b/DVB.NET/TS/TSParser.cs @@ -37,13 +37,13 @@ private class PESInfo : IDisposable /// Die zugehörige Instanz zum Gesamtdatenstrom. /// Die betroffenen Datenstromkennung. /// Der Empfänger der eigentlichen Nutzdaten. - public PESInfo( TSParser parser, ushort pid, Action callback ) + public PESInfo(TSParser parser, ushort pid, Action callback) { // Remember PID = pid; // Create - m_Builder = new PESBuilder( parser, callback ); + m_Builder = new PESBuilder(parser, callback); } /// @@ -64,10 +64,10 @@ public void Reset() /// Gesetzt, wenn der Rohdatenpaketzähler nicht erhöht werden darf. /// Gesetzt, wenn dieses Rohdatenpaket einen PES Kopf enthält. /// Der Rohdatenpaktzähler zu diesem Paket. - public void AddPacket( byte[] packet, int offset, int length, bool noincrement, bool first, byte counter ) + public void AddPacket(byte[] packet, int offset, int length, bool noincrement, bool first, byte counter) { // Forward - m_Builder.AddPacket( packet, offset, length, noincrement, first, counter ); + m_Builder.AddPacket(packet, offset, length, noincrement, first, counter); } /// @@ -85,7 +85,7 @@ public void Dispose() /// Die Anzahl der potentiellen Rohdatenpakete, die zur Synchronisation am Anfang des Gesamtdatenstroms /// verwendet werden. /// - private const int SyncCount = 100; + private readonly int SyncCount = 100; /// /// Verwaltet alle Verbraucher von einzelnen Datenströmen innerhalb des Gesamtdatenstroms. @@ -110,7 +110,7 @@ public void Dispose() /// /// Zwischenspeicher zur Synchronisation am Beginn einer Rohdatenübertragung. /// - private byte[] m_SyncBuffer = new byte[SyncCount * Manager.FullSize]; + private byte[] m_SyncBuffer; /// /// Aktuelle Synchronisationsposition. @@ -218,7 +218,7 @@ public void Dispose() /// Signatur einer Methode, die über eine bestimmte PMT informiert. /// /// Die zugehörige Informationstabelle. - public delegate void PMTFoundHandler( PMT pmt ); + public delegate void PMTFoundHandler(PMT pmt); /// /// Wird aktiviert, wenn eine bestimmte PMT zur Verfügung steht. @@ -228,25 +228,40 @@ public void Dispose() /// /// Erzeugt eine neue Analyseinstanz für einen Transport Stream. /// - public TSParser() + public TSParser() : this(false) { + } + + /// + /// Erzeugt eine neue Analyseinstanz für einen Transport Stream. + /// + /// Gesetzt, wenn die Synchronisation bereits nach 10 statt + /// 100 empfangenen Paketen erfolgen soll. + public TSParser(bool fastSync) + { + if (fastSync) + SyncCount = 10; + + + m_SyncBuffer = new byte[SyncCount * Manager.FullSize]; + // Register m_PATParser.TableFound += OnPATFound; m_PMTParser.TableFound += OnPMTFound; // Install the analyser - m_PATBuilder = new SIBuilder( this, m_PATParser.OnData ); - m_PMTBuilder = new SIBuilder( this, m_PMTParser.OnData ); + m_PATBuilder = new SIBuilder(this, m_PATParser.OnData); + m_PMTBuilder = new SIBuilder(this, m_PMTParser.OnData); } /// /// Wertet eine SI Tabelle aus. /// /// - private void OnPATFound( PAT pat ) + private void OnPATFound(PAT pat) { // At least count it - Interlocked.Increment( ref m_ValidPATCount ); + Interlocked.Increment(ref m_ValidPATCount); // Disabled if (m_WaitForService == 0) @@ -258,7 +273,7 @@ private void OnPATFound( PAT pat ) // Try to find the PID of the service ushort pmtPID; - if (pat.ProgramIdentifier.TryGetValue( m_WaitForService, out pmtPID ) && (pmtPID != 0)) + if (pat.ProgramIdentifier.TryGetValue(m_WaitForService, out pmtPID) && (pmtPID != 0)) { // Can wait m_WaitForPID = pmtPID; @@ -274,7 +289,7 @@ private void OnPATFound( PAT pat ) /// Wertet eine SI Tabelle aus. /// /// - private void OnPMTFound( PMT pmt ) + private void OnPMTFound(PMT pmt) { // Validate if (pmt != null) @@ -292,17 +307,17 @@ private void OnPMTFound( PMT pmt ) // Forward var callback = PMTFound; if (callback != null) - callback( pmt ); + callback(pmt); } /// /// Ermittelt die nächste PMT zu einem Sender. /// /// Der gewünschte Sender. - public void RequestPMT( ushort serviceIdentifier ) + public void RequestPMT(ushort serviceIdentifier) { // Forward - RequestPMT( serviceIdentifier, false ); + RequestPMT(serviceIdentifier, false); } /// @@ -311,13 +326,13 @@ public void RequestPMT( ushort serviceIdentifier ) /// Der gewünschte Sender. /// Gesetzt, wenn nach dem Melden der Kennung /// weiter überwacht werden soll. - public void RequestPMT( ushort serviceIdentifier, bool resetAfterEvent ) + public void RequestPMT(ushort serviceIdentifier, bool resetAfterEvent) { // Activate PMT scanning lock (m_Consumers) { // Reset to find the indicated PMT - m_ResetAfterServiceFound = resetAfterEvent ? serviceIdentifier : (ushort) 0; + m_ResetAfterServiceFound = resetAfterEvent ? serviceIdentifier : (ushort)0; m_WaitForService = serviceIdentifier; m_WaitForPID = 0; } @@ -327,20 +342,20 @@ public void RequestPMT( ushort serviceIdentifier, bool resetAfterEvent ) /// Überträgte Rohdatenpakete in den Gesamtdatenstrom. /// /// Ein Speicherblock mit Rohdatenpaketen. - public void AddPayload( byte[] buffer ) + public void AddPayload(byte[] buffer) { // Forward - AddPayload( buffer, 0, buffer.Length ); + AddPayload(buffer, 0, buffer.Length); } /// /// Injiziert Daten in den Datenstrom, ohne dass diese sofort wieder extrahiert werden. /// /// Speicher mit Nutzdaten. - public void Inject( byte[] buffer ) + public void Inject(byte[] buffer) { // Forward - Inject( buffer, 0, buffer.Length ); + Inject(buffer, 0, buffer.Length); } /// @@ -349,21 +364,21 @@ public void Inject( byte[] buffer ) /// Speicher mit Nutzdaten. /// Der 0-basierte Index des ersten zu nutzenden Bytes im Speicher. /// Die Anzahl der zu nutzenden Bytes im Speicher. - public void Inject( byte[] buffer, int index, int length ) + public void Inject(byte[] buffer, int index, int length) { // Validate if (buffer == null) - throw new ArgumentNullException( "buffer" ); + throw new ArgumentNullException("buffer"); if ((index < 0) || (index > buffer.Length)) - throw new ArgumentException( index.ToString(), "index" ); + throw new ArgumentException(index.ToString(), "index"); if ((length < 0) || (length > buffer.Length)) - throw new ArgumentException( length.ToString(), "length" ); + throw new ArgumentException(length.ToString(), "length"); if ((index + length) > buffer.Length) - throw new ArgumentException( length.ToString(), "length" ); + throw new ArgumentException(length.ToString(), "length"); // We may only inject full packages if ((length % m_Packet.Length) != 0) - throw new ArgumentException( length.ToString(), "length" ); + throw new ArgumentException(length.ToString(), "length"); // Full protect and serialize processing - normally only a single thread will call on us lock (m_Consumers) @@ -385,8 +400,8 @@ public void Inject( byte[] buffer, int index, int length ) return; // Numbers - var pid = (ushort) (pidl + 256 * (0x1f & pidh)); - var counter = (byte) (0xf & flags); + var pid = (ushort)(pidl + 256 * (0x1f & pidh)); + var counter = (byte)(0xf & flags); // Load flags var adaption = (0x20 == (0x20 & flags)); @@ -419,8 +434,8 @@ public void Inject( byte[] buffer, int index, int length ) // Check for custom handler TSBuilder consumer; - if (m_Consumers.TryGetValue( pid, out consumer )) - consumer.AddPacket( buffer, start, realSize, noInc, first, counter ); + if (m_Consumers.TryGetValue(pid, out consumer)) + consumer.AddPacket(buffer, start, realSize, noInc, first, counter); } } @@ -430,17 +445,17 @@ public void Inject( byte[] buffer, int index, int length ) /// Ein Speicherblock mit Rohdatenpaketen. /// Erstes Byte im Speicherblock, das analysiert werden soll. /// Anzahl der zu analyiserenden Bytes. - public void AddPayload( byte[] buffer, int index, int length ) + public void AddPayload(byte[] buffer, int index, int length) { // Validate if (buffer == null) - throw new ArgumentNullException( "buffer" ); + throw new ArgumentNullException("buffer"); if ((index < 0) || (index > buffer.Length)) - throw new ArgumentException( index.ToString(), "index" ); + throw new ArgumentException(index.ToString(), "index"); if ((length < 0) || (length > buffer.Length)) - throw new ArgumentException( length.ToString(), "length" ); + throw new ArgumentException(length.ToString(), "length"); if ((index + length) > buffer.Length) - throw new ArgumentException( length.ToString(), "length" ); + throw new ArgumentException(length.ToString(), "length"); // Full protect and serialize processing - normally only a single thread will call on us lock (m_Consumers) @@ -457,9 +472,9 @@ public void AddPayload( byte[] buffer, int index, int length ) while (m_SyncIndex < m_SyncBuffer.Length) { // How many to copy - var copy = Math.Min( m_SyncBuffer.Length - m_SyncIndex, length ); + var copy = Math.Min(m_SyncBuffer.Length - m_SyncIndex, length); if (copy > 0) - Array.Copy( buffer, index, m_SyncBuffer, m_SyncIndex, copy ); + Array.Copy(buffer, index, m_SyncBuffer, m_SyncIndex, copy); // Advance and count m_SyncIndex += copy; @@ -469,6 +484,7 @@ public void AddPayload( byte[] buffer, int index, int length ) if (m_SyncIndex < m_SyncBuffer.Length) return; + // Adjust length -= copy; index += copy; @@ -484,7 +500,7 @@ public void AddPayload( byte[] buffer, int index, int length ) continue; // Test all - for (j = SyncCount, t = i; j-- > 1; ) + for (j = SyncCount, t = i; j-- > 1;) if (m_SyncBuffer[t += Manager.FullSize] != 0x47) break; @@ -520,7 +536,7 @@ public void AddPayload( byte[] buffer, int index, int length ) BytesSkipped -= m_PacketPos; // Copy in - Array.Copy( m_SyncBuffer, m_SyncBuffer.Length - m_PacketPos, m_Packet, 0, m_PacketPos ); + Array.Copy(m_SyncBuffer, m_SyncBuffer.Length - m_PacketPos, m_Packet, 0, m_PacketPos); } @@ -534,11 +550,11 @@ public void AddPayload( byte[] buffer, int index, int length ) } // Finish the packet - int packet = Math.Min( Manager.FullSize - m_PacketPos, length ); + int packet = Math.Min(Manager.FullSize - m_PacketPos, length); // Copy over if (packet > 0) - Array.Copy( buffer, index, m_Packet, m_PacketPos, packet ); + Array.Copy(buffer, index, m_Packet, m_PacketPos, packet); // Adjust m_PacketPos += packet; @@ -571,15 +587,15 @@ public void AddPayload( byte[] buffer, int index, int length ) byte flags = m_Packet[3]; // Numbers - var pid = (ushort) (pidl + 256 * (0x1f & pidh)); - var counter = (byte) (0xf & flags); + var pid = (ushort)(pidl + 256 * (0x1f & pidh)); + var counter = (byte)(0xf & flags); // See if statistics should be updated if (m_FillStatisics) { // Overall counter long countPackets; - if (!m_PacketStatistics.TryGetValue( pid, out countPackets )) + if (!m_PacketStatistics.TryGetValue(pid, out countPackets)) countPackets = 0; // Update @@ -598,10 +614,10 @@ public void AddPayload( byte[] buffer, int index, int length ) // Check for complete extraction Action extractor; - if (m_Extractors.TryGetValue( pid, out extractor )) + if (m_Extractors.TryGetValue(pid, out extractor)) { // Feed it - extractor( m_Packet ); + extractor(m_Packet); // Next continue; @@ -654,20 +670,20 @@ public void AddPayload( byte[] buffer, int index, int length ) // Check for custom handler TSBuilder consumer; - if (m_Consumers.TryGetValue( pid, out consumer )) - consumer.AddPacket( m_Packet, start, realSize, noInc, first, counter ); + if (m_Consumers.TryGetValue(pid, out consumer)) + consumer.AddPacket(m_Packet, start, realSize, noInc, first, counter); // Forward to PAT if (m_PATBuilder != null) if (pid == 0) - m_PATBuilder.AddPacket( m_Packet, start, realSize, noInc, first, counter ); + m_PATBuilder.AddPacket(m_Packet, start, realSize, noInc, first, counter); // Forward to PMT if (m_PMTBuilder != null) if (m_WaitForService != 0) if (pid != 0) if (m_WaitForPID == pid) - m_PMTBuilder.AddPacket( m_Packet, start, realSize, noInc, first, counter ); + m_PMTBuilder.AddPacket(m_Packet, start, realSize, noInc, first, counter); } } } @@ -686,7 +702,7 @@ public TSBuilder this[ushort pid] // Synchronize lock (m_Consumers) - if (m_Consumers.TryGetValue( pid, out consumer )) + if (m_Consumers.TryGetValue(pid, out consumer)) return consumer; // Not dound @@ -701,21 +717,21 @@ public TSBuilder this[ushort pid] /// Gesetzt, wenn es sich um einen Kontroll- und keinen /// Nutzdatenstrom handelt. /// - public void SetFilter( ushort pid, bool isSITable, Action callback ) + public void SetFilter(ushort pid, bool isSITable, Action callback) { // Validate if (callback == null) - throw new ArgumentNullException( "callback" ); + throw new ArgumentNullException("callback"); // Create TSBuilder consumer; if (isSITable) - consumer = new SIBuilder( this, callback ); + consumer = new SIBuilder(this, callback); else - consumer = new PESBuilder( this, callback ); + consumer = new PESBuilder(this, callback); // Remember - RegisterCustomFilter( pid, consumer ); + RegisterCustomFilter(pid, consumer); } /// @@ -724,14 +740,14 @@ public void SetFilter( ushort pid, bool isSITable, Action callback ) /// Die gewünschte Datenstromkennung. /// Der Verbrqaucher für die Daten. /// Es wurde kein Verbraucher angegeben. - public void RegisterCustomFilter( ushort pid, TSBuilder consumer ) + public void RegisterCustomFilter(ushort pid, TSBuilder consumer) { // Validate if (consumer == null) - throw new ArgumentNullException( "consumer" ); + throw new ArgumentNullException("consumer"); // Remove previous - RemoveFilter( pid ); + RemoveFilter(pid); // Add synchronized lock (m_Consumers) @@ -743,14 +759,14 @@ public void RegisterCustomFilter( ushort pid, TSBuilder consumer ) /// /// Die gewünschte Datenstromkennung. /// Der zu verwendende Verbraucher. - public void RegisterExtractor( ushort pid, Action filter ) + public void RegisterExtractor(ushort pid, Action filter) { // Validate if (filter == null) - throw new ArgumentNullException( "filter" ); + throw new ArgumentNullException("filter"); // Remove previous - RemoveExtractor( pid ); + RemoveExtractor(pid); // Add synchronized lock (m_Consumers) @@ -761,24 +777,24 @@ public void RegisterExtractor( ushort pid, Action filter ) /// Entfernt einen Extraktionsverbraucher. /// /// Die gewünschte Datenstromkennung. - public void RemoveExtractor( ushort pid ) + public void RemoveExtractor(ushort pid) { // Do it lock (m_Consumers) - m_Extractors.Remove( pid ); + m_Extractors.Remove(pid); } /// /// Entfernt einen Verbraucher für einen Datenstrom. /// /// Die gewünschte Datenstromkennung. - public void RemoveFilter( ushort pid ) + public void RemoveFilter(ushort pid) { // Synchronize TSBuilder consumer; lock (m_Consumers) - if (m_Consumers.TryGetValue( pid, out consumer )) - m_Consumers.Remove( pid ); + if (m_Consumers.TryGetValue(pid, out consumer)) + m_Consumers.Remove(pid); else return; @@ -841,10 +857,10 @@ public Dictionary PacketStatistics { // Validate if (!m_FillStatisics) - throw new InvalidOperationException( "Statisics are disabled" ); + throw new InvalidOperationException("Statisics are disabled"); // Clone - return new Dictionary( m_PacketStatistics ); + return new Dictionary(m_PacketStatistics); } } } @@ -856,7 +872,7 @@ public Dictionary PacketStatistics public void RestartPATCounter() { // Do it - Interlocked.Exchange( ref m_ValidPATCount, 0 ); + Interlocked.Exchange(ref m_ValidPATCount, 0); } /// @@ -867,7 +883,7 @@ public long ValidPATCount get { // Report - return Thread.VolatileRead( ref m_ValidPATCount ); + return Thread.VolatileRead(ref m_ValidPATCount); } } diff --git a/DVB.NET/TS/Tables/PAT.cs b/DVB.NET/TS/Tables/PAT.cs index 2d90d33..d9f9853 100644 --- a/DVB.NET/TS/Tables/PAT.cs +++ b/DVB.NET/TS/Tables/PAT.cs @@ -2,152 +2,139 @@ namespace JMS.DVB.TS.Tables { - /// - /// Represents the one and only Process Association Section in a - /// transport stream. - /// - public class PAT: SITableBase - { - /// - /// A random program number. - /// - private short m_ProgramNumber = 0x0102; - - /// - /// A random transport stream identifier for the . - /// - private short m_ProgramStream = 0x0100; - - /// - /// A random network identifier. - /// - private short m_NetworkIdentifier = 1; - - /// - /// Create a new instance which will be bound to the transport stream - /// identifier 0. - /// - public PAT() : base(0x0000) - { - } - - /// - /// The table identifier for a PAT is 0. - /// - protected override byte TableIdentifier - { - get - { - // PAT - return 0x00; - } - } - - /// - /// The optional field in the table header will be filled with our network - /// identifier. - /// - protected override short PrivateData - { - get - { - // Report - return m_NetworkIdentifier; - } - } - - /// - /// Create the PAT based on the current settings. - /// - /// - /// In this context the output is always fixed. - /// - /// The table contents for the PAT describing a single program. - protected override byte[] CreateTable() - { - // Load - int prog = m_ProgramNumber; - int stream = m_ProgramStream; - - // Cut - prog &= 0xffff; - stream &= 0xffff; - - // Construct - return new byte[] { (byte)(prog / 256), (byte)(prog & 0xff), (byte)(0xe0 | (stream / 256)), (byte)(stream & 0xff) }; - } - - /// - /// Get or set the related netowrk identifier. - /// - /// - public short NetworkIdentifier - { - get - { - // Report - return m_NetworkIdentifier; - } - set - { - // Check - if ( value == m_NetworkIdentifier ) return; - - // Update - m_NetworkIdentifier = value; - - // Mark - Changed(); - } - } - - /// - /// Get or set the number of the only program supported. - /// - /// - public short ProgramNumber - { - get - { - // Report - return m_ProgramNumber; - } - set - { - // Check - if ( value == m_ProgramNumber ) return; - - // Update - m_ProgramNumber = value; - - // Mark - Changed(); - } - } - - /// - /// Get or set the transport stream identifier of the only - /// program supported. - /// - /// - public short ProgramStream - { - get - { - // Report - return m_ProgramStream; - } - set - { - // Check - if ( value == m_ProgramStream ) return; - - // Update - m_ProgramStream = value; - - // Mark - Changed(); - } - } - } + /// + /// Represents the one and only Process Association Section in a + /// transport stream. + /// + public class PAT : SITableBase + { + /// + /// A random program number. + /// + private short m_ProgramNumber = 0x0102; + + /// + /// A random transport stream identifier for the . + /// + private short m_ProgramStream = 0x0100; + + /// + /// A random network identifier. + /// + private short m_NetworkIdentifier = 1; + + /// + /// Create a new instance which will be bound to the transport stream + /// identifier 0. + /// + public PAT() : base(0x0000) + { + } + + /// + /// The table identifier for a PAT is 0. + /// + protected override byte TableIdentifier => 0x00; + + /// + /// The optional field in the table header will be filled with our network + /// identifier. + /// + protected override short PrivateData => m_NetworkIdentifier; + + + /// + /// Create the PAT based on the current settings. + /// + /// + /// In this context the output is always fixed. + /// + /// The table contents for the PAT describing a single program. + protected override byte[] CreateTable() + { + // Load + int prog = m_ProgramNumber; + int stream = m_ProgramStream; + + // Cut + prog &= 0xffff; + stream &= 0xffff; + + // Construct + return new byte[] { (byte)(prog / 256), (byte)(prog & 0xff), (byte)(0xe0 | (stream / 256)), (byte)(stream & 0xff) }; + } + + /// + /// Get or set the related netowrk identifier. + /// + /// + public short NetworkIdentifier + { + get + { + // Report + return m_NetworkIdentifier; + } + set + { + // Check + if (value == m_NetworkIdentifier) return; + + // Update + m_NetworkIdentifier = value; + + // Mark + Changed(); + } + } + + /// + /// Get or set the number of the only program supported. + /// + /// + public short ProgramNumber + { + get + { + // Report + return m_ProgramNumber; + } + set + { + // Check + if (value == m_ProgramNumber) return; + + // Update + m_ProgramNumber = value; + + // Mark + Changed(); + } + } + + /// + /// Get or set the transport stream identifier of the only + /// program supported. + /// + /// + public short ProgramStream + { + get + { + // Report + return m_ProgramStream; + } + set + { + // Check + if (value == m_ProgramStream) return; + + // Update + m_ProgramStream = value; + + // Mark + Changed(); + } + } + } } diff --git a/DVB.NET/TS/Tables/PMT.cs b/DVB.NET/TS/Tables/PMT.cs index 79efd45..929cefa 100644 --- a/DVB.NET/TS/Tables/PMT.cs +++ b/DVB.NET/TS/Tables/PMT.cs @@ -31,6 +31,11 @@ public class PMT : SITableBase /// private Dictionary m_Type = new Dictionary(); + /// + /// Maps each stream to the related AAC information. + /// + private Dictionary m_AAC = new Dictionary(); + /// /// Encoding if known. /// @@ -79,8 +84,8 @@ public class PMT : SITableBase /// /// The related transport stream identifier. /// The unique program number. - public PMT( short pid, short program ) - : base( pid ) + public PMT(short pid, short program) + : base(pid) { // Remember ProgrammNumber = program; @@ -89,26 +94,12 @@ public PMT( short pid, short program ) /// /// A PMT has a table identifier of 2. /// - protected override byte TableIdentifier - { - get - { - // Identifier - return 0x02; - } - } + protected override byte TableIdentifier => 0x02; /// /// The optional field in the table header holds our program number. /// - protected override short PrivateData - { - get - { - // Report - return ProgrammNumber; - } - } + protected override short PrivateData => ProgrammNumber; /// /// Create a PMT for the program. @@ -125,16 +116,18 @@ protected override byte[] CreateTable() TableConstructor buffer = new TableConstructor(); // Append to buffer - buffer.Add( (byte) (0xe0 | (PCRPID / 256)) ); - buffer.Add( (byte) (PCRPID & 0xff) ); - buffer.Add( 0xf0, 0x00 ); + buffer.Add((byte)(0xe0 | (PCRPID / 256))); + buffer.Add((byte)(PCRPID & 0xff)); + buffer.Add(0xf0, 0x00); // All entries - for (int ip = 0; ip < m_Streams.Count; ) + for (int ip = 0; ip < m_Streams.Count;) { // Load - short pid = m_Streams[ip++]; - StreamTypes type = m_Type[pid]; + var pid = m_Streams[ip++]; + + var aac = m_AAC[pid]; + var type = m_Type[pid]; // Is teletext or audio bool ttx = (StreamTypes.TeleText == type); @@ -143,22 +136,22 @@ protected override byte[] CreateTable() bool aud = ac3 || (!ttx && !sub && (StreamTypes.Audio == type)); // Append to buffer - buffer.Add( (ttx || sub) ? (byte) StreamTypes.Private : m_Encoding[pid] ); - buffer.Add( (byte) (0xe0 | (pid / 256)) ); - buffer.Add( (byte) (pid & 0xff) ); - buffer.Add( 0xf0 ); + buffer.Add((ttx || sub) ? (byte)StreamTypes.Private : aac.HasValue ? (byte)EPG.StreamTypes.AAC : m_Encoding[pid]); + buffer.Add((byte)(0xe0 | (pid / 256))); + buffer.Add((byte)(pid & 0xff)); + buffer.Add(0xf0); // Length int lengthPos = buffer.CreateDynamicLength(); // Create stream identifier - buffer.Add( new StreamIdentifier( (byte) ip ) ); + buffer.Add(new StreamIdentifier((byte)ip)); // Check for additional data if (ttx) { // Create teletext descriptor - buffer.Add( new Teletext() ); + buffer.Add(new Teletext()); } else if (sub) { @@ -172,39 +165,50 @@ protected override byte[] CreateTable() if ((null == subInfos) || (subInfos.Length < 1)) { // Create a brand new pseudo entry - subDescr.Subtitles.Add( new SubtitleInfo( "deu", EPG.SubtitleTypes.DVBNormal, 1, 1 ) ); + subDescr.Subtitles.Add(new SubtitleInfo("deu", EPG.SubtitleTypes.DVBNormal, 1, 1)); } else { // Use as is - subDescr.Subtitles.AddRange( subInfos ); + subDescr.Subtitles.AddRange(subInfos); } // Serialize to buffer - buffer.Add( subDescr ); + buffer.Add(subDescr); } else if (aud) { // Load language string language; - if (!m_AudioNames.TryGetValue( pid, out language )) language = "deu"; + if (!m_AudioNames.TryGetValue(pid, out language)) language = "deu"; // Create language descriptor ISOLanguage audioDescriptor = new ISOLanguage(); // Append language item - audioDescriptor.Languages.Add( new LanguageItem( language, ac3 ? EPG.AudioTypes.Undefined : EPG.AudioTypes.CleanEffects ) ); + audioDescriptor.Languages.Add(new LanguageItem(language, ac3 ? EPG.AudioTypes.Undefined : EPG.AudioTypes.CleanEffects)); // Append to buffer - buffer.Add( audioDescriptor ); + buffer.Add(audioDescriptor); - // Fill AC3 descriptor + // Fill AC3 descriptor. if (ac3) - buffer.Add( new AC3() ); + buffer.Add(new AC3()); + + // Fill AAC descriptor. + if (aac.HasValue) + { + // Split parts. + var profileAndLevel = (byte)aac.Value; + var aacType = (byte)(aac.Value >> 8); + + // Remember descriptor. + buffer.Add(new AAC(profileAndLevel, aacType == 255 ? (byte?)null : aacType)); + } } // Finish - buffer.SetDynamicLength( lengthPos ); + buffer.SetDynamicLength(lengthPos); } // Report @@ -221,11 +225,7 @@ protected override byte[] CreateTable() /// Set if the first video stream is added and it is used as the PCR /// source. Currently this function always reports false since no /// PCR will be registered in the transport stream for the only program. - public bool Add( StreamTypes type, byte encoding, short pid ) - { - // Forward - return Add( type, encoding, pid, false, null ); - } + public bool Add(StreamTypes type, byte encoding, short pid) => Add(type, encoding, pid, false, null); /// /// Add a stream to this program. @@ -239,11 +239,22 @@ public bool Add( StreamTypes type, byte encoding, short pid ) /// Set if the first video stream is added and it is used as the PCR /// source. Currently this function always reports false since no /// PCR will be registered in the transport stream for the only program. - public bool Add( StreamTypes type, byte encoding, short pid, bool noPCR ) - { - // Forward - return Add( type, encoding, pid, noPCR, null ); - } + public bool Add(StreamTypes type, byte encoding, short pid, bool noPCR) => Add(type, encoding, pid, noPCR, null, null); + + /// + /// Add a stream to this program. + /// + /// Type of the stream. + /// Transport stream identifier of this stream. + /// Set when adding a video stream to disable PCR + /// from PTS generation. + /// Encoding used - 255 means that the encoding is + /// unknown or irrelevant. + /// Extended information on the contents of a subtitle stream. + /// Set if the first video stream is added and it is used as the PCR + /// source. Currently this function always reports false since no + /// PCR will be registered in the transport stream for the only program. + public bool Add(StreamTypes type, byte encoding, short pid, bool noPCR, SubtitleInfo[] info) => Add(type, encoding, pid, noPCR, info, null); /// /// Add a stream to this program. @@ -255,16 +266,17 @@ public bool Add( StreamTypes type, byte encoding, short pid, bool noPCR ) /// Encoding used - 255 means that the encoding is /// unknown or irrelevant. /// Extended information on the contents of a subtitle stream. + /// Optional AAC profile, level and type. /// Set if the first video stream is added and it is used as the PCR /// source. Currently this function always reports false since no /// PCR will be registered in the transport stream for the only program. - public bool Add( StreamTypes type, byte encoding, short pid, bool noPCR, SubtitleInfo[] info ) + public bool Add(StreamTypes type, byte encoding, short pid, bool noPCR, SubtitleInfo[] info, ushort? aac) { // Validate - if ((pid < 0) || (pid >= 0x1fff)) throw new ArgumentOutOfRangeException( "pid", pid, "only 13 bits allowed" ); + if ((pid < 0) || (pid >= 0x1fff)) throw new ArgumentOutOfRangeException("pid", pid, "only 13 bits allowed"); // Must be unique - if (m_Streams.Contains( pid )) throw new ArgumentException( "Duplicate PID " + pid.ToString(), "pid" ); + if (m_Streams.Contains(pid)) throw new ArgumentException("Duplicate PID " + pid.ToString(), "pid"); // Disable PCR generation if (!m_AllowPCR) noPCR = true; @@ -273,10 +285,11 @@ public bool Add( StreamTypes type, byte encoding, short pid, bool noPCR, Subtitl bool isPCR = false; // Remember - m_Streams.Add( pid ); + m_Streams.Add(pid); // Connect - m_Encoding[pid] = (255 == encoding) ? (byte) type : encoding; + m_AAC[pid] = aac; + m_Encoding[pid] = (255 == encoding) ? (byte)type : encoding; m_Type[pid] = type; // Count @@ -307,11 +320,11 @@ public bool Add( StreamTypes type, byte encoding, short pid, bool noPCR, Subtitl /// /// The internal stream identifier. /// The three-letter ISO name of the language. - public void SetAudioLanguage( short pid, string isoName ) + public void SetAudioLanguage(short pid, string isoName) { // Remember - if (!string.IsNullOrEmpty( isoName )) - if (!isoName.StartsWith( "#" )) + if (!string.IsNullOrEmpty(isoName)) + if (!isoName.StartsWith("#")) m_AudioNames[pid] = isoName; } diff --git a/DVB.NET/Test Applications/JMS.DVB.SchedulerTests/ManagerSpecs.cs b/DVB.NET/Test Applications/JMS.DVB.SchedulerTests/ManagerSpecs.cs index 0f8c61b..b790044 100644 --- a/DVB.NET/Test Applications/JMS.DVB.SchedulerTests/ManagerSpecs.cs +++ b/DVB.NET/Test Applications/JMS.DVB.SchedulerTests/ManagerSpecs.cs @@ -867,5 +867,50 @@ public void WillNotShowCurrentRecordingInPlanIfCut() Assert.AreEqual( initial[1].Time.Start, follower.Time.Start ); } } + + + /// + /// Eine laufende Aufgabe wird korrekt berücksichtigt. + /// + [TestMethod] + public void CanAddRecordingOverlappingRunning() + { + // Create component under test + using (var cut = ResourceManager.Create( StringComparer.InvariantCultureIgnoreCase )) + { + // Add a single device + cut.Add( ResourceMock.Device1 ); + + // Time to use + var now = new DateTime( 2013, 12, 3, 17, 0, 0, DateTimeKind.Utc ); + + // Start a task + Assert.IsTrue( cut.Start( ResourceMock.Device1, null, Guid.NewGuid(), "EPG", now, now.AddMinutes( 20 ) ), "epg" ); + + // Create the recording + var plan1 = RecordingDefinition.Create( false, "testA", Guid.NewGuid(), null, SourceMock.Source1Group1Free, now.AddMinutes( 1 ), TimeSpan.FromMinutes( 120 ) ); + var plan2 = RecordingDefinition.Create( false, "testB", Guid.NewGuid(), null, SourceMock.Source1Group2Free, now.AddDays( 1 ).AddHours( 1 ), TimeSpan.FromMinutes( 30 ) ); + var plan3 = RecordingDefinition.Create( false, "testC", Guid.NewGuid(), null, SourceMock.Source1Group3Free, now.AddDays( 1 ).AddHours( 2 ), TimeSpan.FromMinutes( 30 ) ); + + // Loading helper + Func> loader = + ( s, d ) => + { + // Load recording + s.Add( plan1 ); + s.Add( plan2 ); + s.Add( plan3 ); + + // Report + return s.GetSchedules( d ); + }; + + // Find empty list + var schedules = cut.GetSchedules( now, loader ).ToArray(); + + // Validate + Assert.AreEqual( 3, schedules.Count( s => s.Resource != null ), "#" ); + } + } } } diff --git a/DVB.NET/Test Applications/JMS.DVB.SchedulerTests/SingleDeviceSpecs.cs b/DVB.NET/Test Applications/JMS.DVB.SchedulerTests/SingleDeviceSpecs.cs index 69a369c..78e51dc 100644 --- a/DVB.NET/Test Applications/JMS.DVB.SchedulerTests/SingleDeviceSpecs.cs +++ b/DVB.NET/Test Applications/JMS.DVB.SchedulerTests/SingleDeviceSpecs.cs @@ -465,11 +465,11 @@ public void A_Repeating_Recording_Can_Have_Exceptions() ); var exception1 = new PlanException - { - ExceptionDate = repeatStartLocal.AddDays( 12 ).Date, - DurationDelta = TimeSpan.FromMinutes( -10 ), - StartDelta = TimeSpan.FromMinutes( 10 ), - }; + { + ExceptionDate = repeatStartLocal.AddDays( 12 ).Date, + DurationDelta = TimeSpan.FromMinutes( -10 ), + StartDelta = TimeSpan.FromMinutes( 10 ), + }; var exception2 = new PlanException { @@ -486,16 +486,16 @@ public void A_Repeating_Recording_Can_Have_Exceptions() // Create component under test var cut = new RecordingScheduler( StringComparer.InvariantCultureIgnoreCase ) - { - { FreeTVDevice }, - { plan, exception1, exception2, exception3 }, + { + { FreeTVDevice }, + { plan, exception1, exception2, exception3 }, }; // Load var schedules = cut.GetSchedules( TimeBias ).Take( 30 ).ToArray(); // Check - for (int i = 30; i-- > 0; ) + for (int i = 30; i-- > 0;) if (i == 12) { // Validate diff --git a/DVB.NET/Tools/SignalTools/StreamDisplay.cs b/DVB.NET/Tools/SignalTools/StreamDisplay.cs index e4d64f8..0bacb70 100644 --- a/DVB.NET/Tools/SignalTools/StreamDisplay.cs +++ b/DVB.NET/Tools/SignalTools/StreamDisplay.cs @@ -151,8 +151,8 @@ private void selSource_SelectionChangeCommitted( object sender, EventArgs e ) // Select the source source.Source.SelectGroup(); - // Get the stream information - var info = source.Source.GetSourceInformationAsync().CancelAfter( 5000 ).Result; + // Get the stream information. + var info = source.Source.GetSourceInformationAsync().CancelAfter( 15000 ).Result; if (info == null) return; diff --git a/README.md b/README.md index 49e7dfb..0d37540 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ -DVB.NET / VCR.NET -================= +# DVB.NET / VCR.NET Der VCR.NET Recording Service ist ein Windows Dienst zur Aufzeichnung von DVB Ausstrahlungen. Der Zugriff auf die DVB Hardware erfolgt dabei über das DVB.NET Paket. Das gesamte Softwarepaket ist ausschließlich in C# unter Verwendung des Microsoft .NET Frameworks entwickelt worden. + +Zur Zukunft des VCR.NET Recording Server findet man eine erste Übersicht in diesem [Blog-Eintrag](http://jochen.jochen-manns.de/2024/06/02/vcr-net-4-alles-geht-einmal-zu-ende/). diff --git a/VCR.NET/ControlCenter/ControlCenter.csproj b/VCR.NET/ControlCenter/ControlCenter.csproj index d5f5aed..349bae8 100644 --- a/VCR.NET/ControlCenter/ControlCenter.csproj +++ b/VCR.NET/ControlCenter/ControlCenter.csproj @@ -52,9 +52,9 @@ false - - False - ..\packages\Newtonsoft.Json.6.0.7\lib\net45\Newtonsoft.Json.dll + + ..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll + True diff --git a/VCR.NET/ControlCenter/PerServerSettings.cs b/VCR.NET/ControlCenter/PerServerSettings.cs index af751aa..47714e7 100644 --- a/VCR.NET/ControlCenter/PerServerSettings.cs +++ b/VCR.NET/ControlCenter/PerServerSettings.cs @@ -52,7 +52,7 @@ private struct IpNetRow /// /// Meldet die physikalische Adresse. /// - public byte[] MAC { get { return m_physicalAddress.Take( checked( (int) m_physicalAddressBytes ) ).ToArray(); } } + public byte[] MAC { get { return m_physicalAddress.Take( checked((int)m_physicalAddressBytes) ).ToArray(); } } /// /// Die Netzwerkadresse. @@ -125,7 +125,7 @@ public void Refresh() /// /// Meldet die Liste aller Geräte. /// - public IEnumerable Profiles { get { return (IEnumerable) m_Info; } } + public IEnumerable Profiles { get { return (IEnumerable)m_Info; } } /// /// Meldet den aktuellen Zustand des Dienstes. @@ -234,7 +234,7 @@ public void DetectMAC() return; // Load address table - var table = Marshal.AllocHGlobal( checked( (int) size ) ); + var table = Marshal.AllocHGlobal( checked((int)size) ); try { // Get the table @@ -242,13 +242,13 @@ public void DetectMAC() return; // Get the number of entries in the table - var count = checked( (UInt32) Marshal.ReadInt32( table, 0 ) ); + var count = checked((UInt32)Marshal.ReadInt32( table, 0 )); // Process entries for (int offset = 4; count-- > 0; offset += IpNetRow.SizeOf) { // Unmarshal from native representation - var data = (IpNetRow) Marshal.PtrToStructure( table + offset, typeof( IpNetRow ) ); + var data = (IpNetRow)Marshal.PtrToStructure( table + offset, typeof( IpNetRow ) ); // See if this is it if (data.Matches( server.AddressList )) @@ -328,6 +328,6 @@ public bool IsLocal /// /// Die Adresse des REST Web Dienstes. /// - public string EndPoint { get { return string.Format( "http://{0}:{1}/VCR.NET", ServerName, ServerPort ); } } + public string EndPoint => $"http://{ServerName}:{ServerPort}/VCR.NET"; } } diff --git a/VCR.NET/ControlCenter/ProcessingItem.cs b/VCR.NET/ControlCenter/ProcessingItem.cs index 4794f72..3008fb8 100644 --- a/VCR.NET/ControlCenter/ProcessingItem.cs +++ b/VCR.NET/ControlCenter/ProcessingItem.cs @@ -34,7 +34,7 @@ public ProcessingItem( PerServerSettings.PerServerView view, VCRNETControl conte /// /// Meldet die Adresse des VCR.NET Recording Service /// - public string EndPoint { get { return string.Format( "http://{0}:{1}/VCR.NET", ServerName, ServerPort ); } } + public string EndPoint => $"http://{ServerName}:{ServerPort}/VCR.NET"; /// /// Wird periodisch aufgerufen und frage den aktuellen Zustand des Dienstes auf einem Rechner ab. diff --git a/VCR.NET/ControlCenter/Properties/AssemblyInfo.cs b/VCR.NET/ControlCenter/Properties/AssemblyInfo.cs index eec26db..8d20b3d 100644 --- a/VCR.NET/ControlCenter/Properties/AssemblyInfo.cs +++ b/VCR.NET/ControlCenter/Properties/AssemblyInfo.cs @@ -30,5 +30,5 @@ // Build Number // Revision // -[assembly: AssemblyVersion( "4.3.0.0" )] -[assembly: AssemblyFileVersion( "4.3.0.0" )] +[assembly: AssemblyVersion( "4.5.0.0" )] +[assembly: AssemblyFileVersion( "4.5.0.0" )] diff --git a/VCR.NET/ControlCenter/VCRNETControl.cs b/VCR.NET/ControlCenter/VCRNETControl.cs index 7e64eb8..36c44d9 100644 --- a/VCR.NET/ControlCenter/VCRNETControl.cs +++ b/VCR.NET/ControlCenter/VCRNETControl.cs @@ -164,7 +164,7 @@ public VCRNETControl( string[] args ) } // Get the related color - var colorIndex = (TrayColors) Enum.Parse( typeof( TrayColors ), iconname, true ); + var colorIndex = (TrayColors)Enum.Parse( typeof( TrayColors ), iconname, true ); // Add to map m_TrayIcons[colorIndex] = icon; @@ -209,7 +209,7 @@ public VCRNETControl( string[] args ) // Load settings ckAutoStart.Checked = m_Settings.AutoStartService; ckHibernate.Checked = (m_Settings.HibernationDelay > 0); - selHibernate.Value = ckHibernate.Checked ? (int) m_Settings.HibernationDelay : 5; + selHibernate.Value = ckHibernate.Checked ? (int)m_Settings.HibernationDelay : 5; txMultiCast.Text = m_Settings.MulticastIP; selStreamPort.Value = m_Settings.MinPort; selDelay.Value = m_Settings.StartupDelay; @@ -253,7 +253,7 @@ public VCRNETControl( string[] args ) if (null != vcr) { // Load path - string image = (string) vcr.GetValue( "ImagePath" ); + string image = (string)vcr.GetValue( "ImagePath" ); if (!string.IsNullOrEmpty( image )) { // Correct @@ -273,7 +273,7 @@ public VCRNETControl( string[] args ) dom.Load( config.FullName ); // Check for port - var portNode = (XmlElement) dom.SelectSingleNode( "configuration/appSettings/add[@key='TCPPort']" ); + var portNode = (XmlElement)dom.SelectSingleNode( "configuration/appSettings/add[@key='TCPPort']" ); var port = ushort.Parse( portNode.GetAttribute( "value" ) ); // At least there is a valid local server @@ -339,7 +339,7 @@ private PerServerSettings CurrentServer if (index >= lstServers.Items.Count) return null; // Attach to the related server view - var view = (PerServerSettings.PerServerView) lstServers.Items[index]; + var view = (PerServerSettings.PerServerView)lstServers.Items[index]; // Report server return view.Settings; @@ -355,7 +355,7 @@ private void CreateTrayIcons() HideHibernation(); // Reset all - for (int n = components.Components.Count; n-- > 0; ) + for (int n = components.Components.Count; n-- > 0;) { // Read it NotifyIcon icon = components.Components[n] as NotifyIcon; @@ -433,7 +433,7 @@ private NotifyIcon CreateTrayIcon( string text ) private void SetActiveTray( object sender, MouseEventArgs e ) { // Remember - m_Active = (NotifyIcon) sender; + m_Active = (NotifyIcon)sender; } private void mnuClose_Click( object sender, EventArgs e ) @@ -501,7 +501,7 @@ private void trayMenu_Opening( object sender, CancelEventArgs e ) if (settings != null) { // Change top menu - mnuDefault.Text += string.Format( " ({0})", settings.ServerName ); + mnuDefault.Text += $" ({settings.ServerName})"; // Check mode if (settings.View.State != TrayColors.Red) @@ -636,10 +636,10 @@ private void LiveConnect( object sender, EventArgs e ) try { // Attach to menu item - ToolStripItem menu = (ToolStripItem) sender; + ToolStripItem menu = (ToolStripItem)sender; // Get the corresponding parameter - string dvbnetURL = (string) menu.Tag; + string dvbnetURL = (string)menu.Tag; // Attach to server Process.Start( m_Settings.Viewer, dvbnetURL ); @@ -653,10 +653,10 @@ private void LiveConnect( object sender, EventArgs e ) void SetHibernateDelay( object sender, EventArgs e ) { // Convert - ToolStripMenuItem item = (ToolStripMenuItem) sender; + ToolStripMenuItem item = (ToolStripMenuItem)sender; // Just update - m_BlockHibernate = (DateTime) item.Tag; + m_BlockHibernate = (DateTime)item.Tag; } private void OpenBrowser( string page ) @@ -747,8 +747,8 @@ private void cmdAdd_Click( object sender, EventArgs e ) var settings = new PerServerSettings { - RefreshInterval = (int) selInterval.Value, - ServerPort = (ushort) selPort.Value, + RefreshInterval = (int)selInterval.Value, + ServerPort = (ushort)selPort.Value, WakeUpBroadcast = txSubNet.Text, ServerName = txServer.Text, }; @@ -818,7 +818,7 @@ private void lstServers_SelectedIndexChanged( object sender, EventArgs e ) else { // Attach to the selected item - var view = (PerServerSettings.PerServerView) lstServers.SelectedItems[0]; + var view = (PerServerSettings.PerServerView)lstServers.SelectedItems[0]; var settings = view.Settings; // Load all @@ -892,8 +892,8 @@ private void cmdUpdate_Click( object sender, EventArgs e ) var port = settings.ServerPort; // Update - settings.RefreshInterval = (int) selInterval.Value; - settings.ServerPort = (ushort) selPort.Value; + settings.RefreshInterval = (int)selInterval.Value; + settings.ServerPort = (ushort)selPort.Value; settings.WakeUpBroadcast = txSubNet.Text; settings.ServerName = txServer.Text; @@ -966,7 +966,7 @@ private void CheckLocal( object sender, EventArgs e ) if (m_Settings.AutoStartService == ckAutoStart.Checked) { // Get the delay - int delay = ckHibernate.Checked ? (int) selHibernate.Value : 0; + int delay = ckHibernate.Checked ? (int)selHibernate.Value : 0; // Compare if (m_Settings.HibernationDelay == delay) return; @@ -981,7 +981,7 @@ private string CurrentLanguage get { // Attach to selected language - CultureItem culture = (CultureItem) selLanguage.SelectedItem; + CultureItem culture = (CultureItem)selLanguage.SelectedItem; // Report return (null == culture) ? string.Empty : culture.Info.TwoLetterISOLanguageName; @@ -995,7 +995,7 @@ private void cmdUpdateAll_Click( object sender, EventArgs e ) int delay = m_Settings.HibernationDelay; // Update the all - m_Settings.HibernationDelay = ckHibernate.Checked ? (int) selHibernate.Value : 0; + m_Settings.HibernationDelay = ckHibernate.Checked ? (int)selHibernate.Value : 0; m_Settings.AutoStartService = ckAutoStart.Checked; // Try save @@ -1110,7 +1110,7 @@ internal bool ProcessStateAndCheckHibernation( ProcessingItem controller, TrayCo if (InvokeRequired) { // Forward - return (bool) Invoke( new ReportPattern( ProcessStateAndCheckHibernation ), controller, state, mustHibernate, pendingExtensions ); + return (bool)Invoke( new ReportPattern( ProcessStateAndCheckHibernation ), controller, state, mustHibernate, pendingExtensions ); } // Get the previous state @@ -1210,7 +1210,7 @@ private bool GetHibernationDialogPoppedUp( ProcessingItem controller, TrayColors { // See if there are pending extensions if (!pendingExtensions) - m_Hibernation.TryHibernate(controller); + m_Hibernation.TryHibernate( controller ); // No change required return null; @@ -1311,7 +1311,7 @@ private void CheckStream() if (Equals( txViewer.Text, m_Settings.Viewer )) if (Equals( txArgs.Text, m_Settings.ViewerArgs )) if (Equals( txMultiCast.Text, m_Settings.MulticastIP )) - if (m_Settings.MinPort == (int) selStreamPort.Value) + if (m_Settings.MinPort == (int)selStreamPort.Value) return; // Can save @@ -1403,7 +1403,7 @@ private void cmdStreaming_Click( object sender, EventArgs e ) ushort port = m_Settings.MinPort; // Update the all - m_Settings.MinPort = (ushort) selStreamPort.Value; + m_Settings.MinPort = (ushort)selStreamPort.Value; m_Settings.MulticastIP = txMultiCast.Text; m_Settings.ViewerArgs = txArgs.Text; m_Settings.Viewer = txViewer.Text; @@ -1443,7 +1443,7 @@ private void StartStopStreaming( object sender, EventArgs e ) return; // Attach to item - var item = (ToolStripDropDownItem) sender; + var item = (ToolStripDropDownItem)sender; if (item == null) return; @@ -1552,7 +1552,7 @@ private void selDelay_ValueChanged( object sender, EventArgs e ) int delay = m_Settings.StartupDelay; // Update - m_Settings.StartupDelay = (int) selDelay.Value; + m_Settings.StartupDelay = (int)selDelay.Value; // Try save try @@ -1629,14 +1629,14 @@ private void mnuWakeupServer_Click( object sender, EventArgs e ) socket.Connect( settings.SubNetAddress, 7 ); // Buffer - var buffer = new List( checked( (int) (6 + 16 * mac.Length) ) ); + var buffer = new List( checked((int)(6 + 16 * mac.Length)) ); // Start with prefix - for (var i = 6; i-- > 0; ) + for (var i = 6; i-- > 0;) buffer.Add( 0xff ); // Add physical address - for (var i = 16; i-- > 0; ) + for (var i = 16; i-- > 0;) buffer.AddRange( mac ); // Process diff --git a/VCR.NET/ControlCenter/packages.config b/VCR.NET/ControlCenter/packages.config index ba2b301..3e14be6 100644 --- a/VCR.NET/ControlCenter/packages.config +++ b/VCR.NET/ControlCenter/packages.config @@ -1,4 +1,4 @@  - + \ No newline at end of file diff --git a/VCR.NET/EasyCut/AssemblyInfo.cs b/VCR.NET/EasyCut/AssemblyInfo.cs index 60ab738..3956e4c 100644 --- a/VCR.NET/EasyCut/AssemblyInfo.cs +++ b/VCR.NET/EasyCut/AssemblyInfo.cs @@ -26,5 +26,7 @@ // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion( "4.3.0.0" )] +[assembly: AssemblyVersion( "4.5.0.0" )] +[assembly: AssemblyFileVersion("4.5.0.0")] + diff --git a/VCR.NET/EasyCut/CPFReader.cs b/VCR.NET/EasyCut/CPFReader.cs index 3fb2710..a10c832 100644 --- a/VCR.NET/EasyCut/CPFReader.cs +++ b/VCR.NET/EasyCut/CPFReader.cs @@ -123,7 +123,7 @@ public CPFReader( string path ) private FileInfo FindVideoFile( int videoIndex ) { // Find the video - XmlElement video = (XmlElement) m_Document.DocumentElement.SelectSingleNode( string.Format( "cm:usedVideoFiles[@FileID='{0}']", videoIndex ), m_Namespaces ); + XmlElement video = (XmlElement)m_Document.DocumentElement.SelectSingleNode( $"cm:usedVideoFiles[@FileID='{videoIndex}']", m_Namespaces ); // Not found if (null == video) diff --git a/VCR.NET/EasyCut/CutMain.cs b/VCR.NET/EasyCut/CutMain.cs index bed8a0f..f27b110 100644 --- a/VCR.NET/EasyCut/CutMain.cs +++ b/VCR.NET/EasyCut/CutMain.cs @@ -1,8 +1,13 @@ using System; using System.Configuration; +using System.Diagnostics; using System.IO; using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; using System.Windows.Forms; +using System.Xml; namespace EasyCut { @@ -28,12 +33,23 @@ public class CutMain : System.Windows.Forms.Form private System.ComponentModel.Container components = null; private SaveFileDialog saveCut; private ComboBox selPage; + private CheckBox ckMux; /// /// Die aktuelle Projektdatei. /// private CPFReader m_ProjectFile; + /// + /// Ermittelt den kurzen Dateinamen. + /// + /// Ein langer Dateiname. + /// Der kurze Name. + /// Die maximale Länge des kurzen Namens. + /// Die Länge des Namens. + [DllImport( "Kernel32.dll" )] + private static extern int GetShortPathName( string path, StringBuilder shortPath, int bufferSize ); + /// /// Create the cutter main window. /// @@ -71,7 +87,7 @@ protected override void Dispose( bool disposing ) /// private void InitializeComponent() { - System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(CutMain)); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager( typeof( CutMain ) ); this.cmdRun = new System.Windows.Forms.Button(); this.label1 = new System.Windows.Forms.Label(); this.label2 = new System.Windows.Forms.Label(); @@ -84,122 +100,130 @@ private void InitializeComponent() this.openCuttermaran = new System.Windows.Forms.OpenFileDialog(); this.saveCut = new System.Windows.Forms.SaveFileDialog(); this.selPage = new System.Windows.Forms.ComboBox(); - ((System.ComponentModel.ISupportInitialize)(this.udMinimum)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.udCorrect)).BeginInit(); + this.ckMux = new System.Windows.Forms.CheckBox(); + ((System.ComponentModel.ISupportInitialize) (this.udMinimum)).BeginInit(); + ((System.ComponentModel.ISupportInitialize) (this.udCorrect)).BeginInit(); this.SuspendLayout(); // // cmdRun // - resources.ApplyResources(this.cmdRun, "cmdRun"); + resources.ApplyResources( this.cmdRun, "cmdRun" ); this.cmdRun.Name = "cmdRun"; - this.cmdRun.Click += new System.EventHandler(this.cmdRun_Click); + this.cmdRun.Click += new System.EventHandler( this.cmdRun_Click ); // // label1 // - resources.ApplyResources(this.label1, "label1"); + resources.ApplyResources( this.label1, "label1" ); this.label1.Name = "label1"; // // label2 // - resources.ApplyResources(this.label2, "label2"); + resources.ApplyResources( this.label2, "label2" ); this.label2.Name = "label2"; // // selRate // + resources.ApplyResources( this.selRate, "selRate" ); this.selRate.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; - resources.ApplyResources(this.selRate, "selRate"); this.selRate.Name = "selRate"; // // label3 // - resources.ApplyResources(this.label3, "label3"); + resources.ApplyResources( this.label3, "label3" ); this.label3.Name = "label3"; // // udMinimum // + resources.ApplyResources( this.udMinimum, "udMinimum" ); this.udMinimum.DecimalPlaces = 2; - this.udMinimum.Increment = new decimal(new int[] { + this.udMinimum.Increment = new decimal( new int[] { 1, 0, 0, - 65536}); - resources.ApplyResources(this.udMinimum, "udMinimum"); - this.udMinimum.Maximum = new decimal(new int[] { + 65536} ); + this.udMinimum.Maximum = new decimal( new int[] { 5, 0, 0, - 0}); + 0} ); this.udMinimum.Name = "udMinimum"; // // label4 // - resources.ApplyResources(this.label4, "label4"); + resources.ApplyResources( this.label4, "label4" ); this.label4.Name = "label4"; // // udCorrect // - this.udCorrect.Increment = new decimal(new int[] { + resources.ApplyResources( this.udCorrect, "udCorrect" ); + this.udCorrect.Increment = new decimal( new int[] { 15, 0, 0, - 0}); - resources.ApplyResources(this.udCorrect, "udCorrect"); - this.udCorrect.Maximum = new decimal(new int[] { + 0} ); + this.udCorrect.Maximum = new decimal( new int[] { 10000, 0, 0, - 0}); - this.udCorrect.Minimum = new decimal(new int[] { + 0} ); + this.udCorrect.Minimum = new decimal( new int[] { 10000, 0, 0, - -2147483648}); + -2147483648} ); this.udCorrect.Name = "udCorrect"; // // ckDVB // - resources.ApplyResources(this.ckDVB, "ckDVB"); + resources.ApplyResources( this.ckDVB, "ckDVB" ); this.ckDVB.Name = "ckDVB"; this.ckDVB.UseVisualStyleBackColor = true; - this.ckDVB.CheckedChanged += new System.EventHandler(this.ckDVB_CheckedChanged); + this.ckDVB.CheckedChanged += new System.EventHandler( this.ckDVB_CheckedChanged ); // // openCuttermaran // - resources.ApplyResources(this.openCuttermaran, "openCuttermaran"); + resources.ApplyResources( this.openCuttermaran, "openCuttermaran" ); // // saveCut // - resources.ApplyResources(this.saveCut, "saveCut"); + resources.ApplyResources( this.saveCut, "saveCut" ); this.saveCut.FilterIndex = 2; // // selPage // + resources.ApplyResources( this.selPage, "selPage" ); this.selPage.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; this.selPage.FormattingEnabled = true; - resources.ApplyResources(this.selPage, "selPage"); this.selPage.Name = "selPage"; this.selPage.Sorted = true; // + // ckMux + // + resources.ApplyResources( this.ckMux, "ckMux" ); + this.ckMux.Name = "ckMux"; + this.ckMux.UseVisualStyleBackColor = true; + // // CutMain // - resources.ApplyResources(this, "$this"); - this.Controls.Add(this.selPage); - this.Controls.Add(this.ckDVB); - this.Controls.Add(this.udCorrect); - this.Controls.Add(this.udMinimum); - this.Controls.Add(this.label4); - this.Controls.Add(this.label3); - this.Controls.Add(this.selRate); - this.Controls.Add(this.label2); - this.Controls.Add(this.label1); - this.Controls.Add(this.cmdRun); + resources.ApplyResources( this, "$this" ); + this.Controls.Add( this.ckMux ); + this.Controls.Add( this.selPage ); + this.Controls.Add( this.ckDVB ); + this.Controls.Add( this.udCorrect ); + this.Controls.Add( this.udMinimum ); + this.Controls.Add( this.label4 ); + this.Controls.Add( this.label3 ); + this.Controls.Add( this.selRate ); + this.Controls.Add( this.label2 ); + this.Controls.Add( this.label1 ); + this.Controls.Add( this.cmdRun ); this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; this.MaximizeBox = false; this.Name = "CutMain"; - this.Load += new System.EventHandler(this.CutMain_Load); - ((System.ComponentModel.ISupportInitialize)(this.udMinimum)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.udCorrect)).EndInit(); - this.ResumeLayout(false); + this.Load += new System.EventHandler( this.CutMain_Load ); + ((System.ComponentModel.ISupportInitialize) (this.udMinimum)).EndInit(); + ((System.ComponentModel.ISupportInitialize) (this.udCorrect)).EndInit(); + this.ResumeLayout( false ); this.PerformLayout(); } @@ -249,6 +273,7 @@ private void cmdRun_Click( object sender, System.EventArgs e ) // Update settings Properties.Settings.Default.Framerate = FrameRateInfo.FindFrameRate( selRate.SelectedIndex ).Rate; Properties.Settings.Default.Threshold = udMinimum.Value; + Properties.Settings.Default.MuxDefault = ckMux.Checked; Properties.Settings.Default.Save(); // Check selection of page @@ -259,54 +284,55 @@ private void cmdRun_Click( object sender, System.EventArgs e ) try { // Load file - FileInfo outFile = new FileInfo( saveCut.FileName ); + var outFile = new FileInfo( saveCut.FileName ); // Get the type - string suffix = outFile.Extension; + var suffix = outFile.Extension; // Check - if ((null == suffix) || (suffix.Length < 2)) + if ((suffix == null) || (suffix.Length < 2)) throw new ApplicationException( Properties.Resources.Error_Format ); // Cut off suffix = suffix.Substring( 1 ); // Load type name - string typeName = ConfigurationManager.AppSettings[suffix.ToUpper()]; + var typeName = ConfigurationManager.AppSettings[suffix.ToUpper()]; // Check - if ((null == typeName) || (typeName.Length < 1)) + if ((typeName == null) || (typeName.Length < 1)) throw new ApplicationException( Properties.Resources.Error_Format ); // Find the type - Type cutType = Type.GetType( typeName, true ); + var cutType = Type.GetType( typeName, true ); // Create extractor - using (ICutter cutter = (ICutter) Activator.CreateInstance( cutType )) + using (var cutter = (ICutter) Activator.CreateInstance( cutType )) { // Configure cutter.Framerate = FrameRateInfo.FindFrameRate( selRate.SelectedIndex ).Rate; cutter.MinDuration = (double) udMinimum.Value; // Check for VCR.NET 3.1 or later - ICutter2 cutter31 = cutter as ICutter2; - if (null != cutter31) cutter31.TimeCorrection = (double) udCorrect.Value; + var cutter31 = cutter as ICutter2; + if (cutter31 != null) + cutter31.TimeCorrection = (double) udCorrect.Value; // Position in output file long pos = 0; // Process all cuts - foreach (CutElement cut in m_ProjectFile.CutElements) + foreach (var cut in m_ProjectFile.CutElements) { // Get the core name - string coreName = Path.GetFileNameWithoutExtension( cut.VideoFile.FullName ); + var coreName = Path.GetFileNameWithoutExtension( cut.VideoFile.FullName ); // Append page number if (!ckDVB.Checked) coreName += "[" + Properties.Settings.Default.SubtitlePage.ToString() + "]"; // Replace suffix - FileInfo ttxFile = new FileInfo( cut.VideoFile.DirectoryName + @"\" + coreName + "." + suffix ); + var ttxFile = new FileInfo( cut.VideoFile.DirectoryName + @"\" + coreName + "." + suffix ); // Must exist if (!ttxFile.Exists) @@ -325,6 +351,10 @@ private void cmdRun_Click( object sender, System.EventArgs e ) // Finish cutter.Save( saveCut.FileName ); + + // Mux it + if (ckMux.Checked) + DoMux( saveCut.FileName ); } // Done on success @@ -337,6 +367,132 @@ private void cmdRun_Click( object sender, System.EventArgs e ) } } + /// + /// Mischt die Untertitel in eine Datei ein. + /// + /// Der volle Pfad zur Untertiteldatei. + private void DoMux( string supPath ) + { + // Check mode + var palPath = supPath + ".pal"; + if (!File.Exists( palPath )) + return; + + // Must have GfD Path + var gfdPath = Properties.Settings.Default.GfDFolder; + if (!string.IsNullOrEmpty( gfdPath )) + if (!Directory.Exists( gfdPath )) + gfdPath = null; + + // Ask user + if (string.IsNullOrEmpty( gfdPath )) + using (var dlg = new FolderBrowserDialog()) + { + dlg.Description = Properties.Resources.Browse_GfD; + dlg.ShowNewFolderButton = false; + + if (dlg.ShowDialog( this ) != DialogResult.OK) + return; + + // Take it + Properties.Settings.Default.GfDFolder = gfdPath = dlg.SelectedPath; + Properties.Settings.Default.Save(); + } + + // Ask for source file + string videoFile; + + using (var mpg = new OpenFileDialog()) + { + // Configure + mpg.Title = Properties.Resources.Browse_Mpg; + mpg.Filter = "Videos|*.mpg"; + mpg.CheckFileExists = true; + mpg.AddExtension = true; + mpg.DefaultExt = "mpg"; + + // Select the file + if (mpg.ShowDialog( this ) != DialogResult.OK) + return; + + videoFile = mpg.FileName; + } + + // Fixed output path + var supDir = Path.Combine( Path.GetDirectoryName( supPath ), Path.GetFileNameWithoutExtension( supPath ) + ".d" ); + + if (Directory.Exists( supDir )) + Directory.Delete( supDir, true ); + + // Generate pictures + var procInfo = + new ProcessStartInfo + { + Arguments = $"\"{supPath.Replace( "\"", "\"\"" )}\" \"{palPath.Replace( "\"", "\"\"" )}\"", + FileName = Path.Combine( gfdPath, "sup2png.exe" ), + UseShellExecute = false, + }; + + using (var process = Process.Start( procInfo )) + process.WaitForExit(); + + // Manipulate XML + var spumuxXml = Path.Combine( supDir, "spumux.xml" ); + var ansiXml = File.ReadAllText( spumuxXml, Encoding.GetEncoding( 1252 ) ); + + var xml = new XmlDocument(); + xml.LoadXml( ansiXml ); + + // Convert names + foreach (XmlElement img in xml.SelectNodes( "//spu" )) + { + // Convert and write back + var path = img.GetAttribute( "image" ); + var buffer = new StringBuilder( 1000 ); + if (GetShortPathName( path, buffer, buffer.Capacity - 1 ) > 0) + img.SetAttribute( "image", buffer.ToString() ); + } + + // Write back + File.WriteAllText( spumuxXml, xml.OuterXml, Encoding.GetEncoding( 1252 ) ); + + // Mux - in-place, better user SSD! + procInfo = + new ProcessStartInfo + { + Arguments = $"-s0 \"{spumuxXml.Replace( "\"", "\"\"" )}\"", + FileName = Path.Combine( gfdPath, "spumux.exe" ), + RedirectStandardOutput = true, + RedirectStandardInput = true, + UseShellExecute = false, + }; + + using (var process = Process.Start( procInfo )) + { + var outbuffer = new byte[10000000]; + + // Send input file + Task.Run( () => + { + var inbuffer = new byte[outbuffer.Length]; + + using (var input = new FileStream( videoFile, FileMode.Open, FileAccess.Read, FileShare.Read, inbuffer.Length )) + for (int n; (n = input.Read( inbuffer, 0, inbuffer.Length )) > 0;) + process.StandardInput.BaseStream.Write( inbuffer, 0, n ); + + process.StandardInput.BaseStream.Close(); + } ); + + // Generate target file + using (var output = new FileStream( Path.Combine( Path.GetDirectoryName( videoFile ), Path.GetFileNameWithoutExtension( videoFile ) + "_SUP.mpg" ), FileMode.Create, FileAccess.Write, FileShare.None, outbuffer.Length )) + for (int n; (n = process.StandardOutput.BaseStream.Read( outbuffer, 0, outbuffer.Length )) > 0;) + output.Write( outbuffer, 0, n ); + + // Synchronize + process.WaitForExit(); + } + } + /// /// Füllt das Hauptfenster mit Voreinstellungen. /// @@ -385,6 +541,7 @@ private void CutMain_Load( object sender, System.EventArgs e ) udMinimum.Value = Properties.Settings.Default.Threshold; // Prepare UI + ckMux.Checked = Properties.Settings.Default.MuxDefault; ckDVB.Enabled = false; // Load pages diff --git a/VCR.NET/EasyCut/CutMain.de.resx b/VCR.NET/EasyCut/CutMain.de.resx index c52a4c2..758352c 100644 --- a/VCR.NET/EasyCut/CutMain.de.resx +++ b/VCR.NET/EasyCut/CutMain.de.resx @@ -112,10 +112,10 @@ 2.0 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 &Los @@ -123,24 +123,6 @@ Untertitel &Seite - - Cuttermaran Projektdateien|*.cpf|Alle Dateien|*.* - - - Cuttermaran Projektdatei auswählen - - - Text (SUB)|*.sub|Bild (SUP)|*.sup|Alle Dateien|*.* - - - Untertiteldatei auswählen - - - Fehler beim Schneiden - - - Format nicht unterstützt - bitte eine andere Dateiendung verwenden - &Bildrate @@ -162,7 +144,13 @@ Untertiteldatei auswählen - + + + 148, 17 + + + Ein&mischen wenn möglich + AAABAAIAICAQAAAAAADoAgAAJgAAABAQEAAAAAAAKAEAAA4DAAAoAAAAIAAAAEAAAAABAAQAAAAAAIAC diff --git a/VCR.NET/EasyCut/CutMain.resx b/VCR.NET/EasyCut/CutMain.resx index a938934..a35f7a5 100644 --- a/VCR.NET/EasyCut/CutMain.resx +++ b/VCR.NET/EasyCut/CutMain.resx @@ -117,294 +117,207 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System - - - - Microsoft Sans Serif, 18pt, style=Bold + + 1 - + + NoControl - - 232, 16 - - - 104, 91 - - - - 9 + + + 152, 40 - - &Cut + + 152, 89 - - cmdRun + + $this - - System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + $this - + $this + + ckDVB + - 9 + 10 - + NoControl - - 16, 42 - - - 80, 16 - - - 2 + + CutMain - - Subtitle &Page + + 3 label1 - - System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - $this - - - 8 - - - NoControl - - - 16, 18 - - - 80, 16 + + System.Windows.Forms.NumericUpDown, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - 0 + + openCuttermaran - - &Framerate + + + 7 - - label2 + + selRate - - System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + 128, 16 - - $this + + &Cut - - 7 + + label3 13 - - 102, 16 - - - 9 - - - 114, 21 - - - 1 - - - selRate + + udCorrect - - System.Windows.Forms.ComboBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - + $this - - 6 - - - NoControl + + 64, 20 16, 66 - - 128, 16 - - - 5 - - - &Threshold (sec) - - - label3 + + 9 - - System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + 48, 17 - - $this + + 2 - - 5 + + 0 - - 152, 64 + + 102, 16 - - 64, 20 + + 80, 16 6 - - udMinimum + + 114, 21 - - System.Windows.Forms.NumericUpDown, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + System.Windows.Forms.ComboBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - $this + + 4 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Windows.Forms.ComboBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - 3 + 4 + + + 8 NoControl - - 16, 91 - - - 128, 16 - - - 7 + + 80, 16 - - &Correction (sec) + + $this label4 - - System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + &Correction (sec) - + $this - - 4 - - - 152, 89 + + System.Windows.Forms.SaveFileDialog, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - 64, 20 + + NoControl - - 8 + + cmdRun - - udCorrect + + 7 - - System.Windows.Forms.NumericUpDown, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + 10 - - $this + + ckMux - + 2 - - True - - - 102, 42 + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - 48, 17 + + 9 - - 3 + + True - - &DVB + + 5 - - ckDVB + + Text (SUB)|*.sub|Image (SUP)|*.sup|All Files|*.* - + System.Windows.Forms.CheckBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - + $this - - 1 - - - 17, 17 - - - Cuttermaran Project Files|*.cpf|All Files|*.* + + $this - - Please choose the Cuttermaran Project File + + 16, 91 - - 155, 17 - - - Text (SUB)|*.sub|Image (SUP)|*.sup|All Files|*.* + + Microsoft Sans Serif, 18pt, style=Bold Please choose the Subtitle Target File - - 152, 40 - - - 64, 21 - - - 4 - - - selPage - - - System.Windows.Forms.ComboBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + NoControl - + $this - - 0 - - - True - - - 5, 13 - - - 346, 116 - AAABAAIAICAQAAAAAADoAgAAJgAAABAQEAAAAAAAKAEAAA4DAAAoAAAAIAAAAEAAAAABAAQAAAAAAIAC @@ -427,25 +340,139 @@ AAD8QQAA+IEAAIwBAACCAQAAgAMAAIEHAADBRwAA5l8AAPTfAADJZwAA8I8AAIofAADmdwAA57MAAA== + + 152, 64 + + + 64, 21 + + + True + + + 104, 91 + + + &DVB + + + 64, 20 + + + Cuttermaran Project Files|*.cpf|All Files|*.* + + + $this + + + 19, 124 + + + 16, 42 + VCR.NET Simple SUB/SUP Cutting Utility - - openCuttermaran + + 232, 16 + + + &Framerate + + + $this + + + 5, 13 + + + 16, 18 + + + 3 + + + 8 + + + selPage + + + 1 + + + 128, 16 + + + 116, 17 + + + System.Windows.Forms.NumericUpDown, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + &Threshold (sec) + + + 9 + + + udMinimum + + + label2 System.Windows.Forms.OpenFileDialog, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - saveCut + + 102, 42 - - System.Windows.Forms.SaveFileDialog, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + System - - CutMain + + 346, 153 + + + 5 System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + 0 + + + System.Windows.Forms.CheckBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 6 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + &Multiplex if possible + + + Please choose the Cuttermaran Project File + + + Subtitle &Page + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + saveCut + + + True + + + 155, 17 + + + 17, 17 + \ No newline at end of file diff --git a/VCR.NET/EasyCut/EasyCut.csproj b/VCR.NET/EasyCut/EasyCut.csproj index 4d31d89..ec9c642 100644 --- a/VCR.NET/EasyCut/EasyCut.csproj +++ b/VCR.NET/EasyCut/EasyCut.csproj @@ -99,6 +99,7 @@ System.Drawing + System.Windows.Forms diff --git a/VCR.NET/EasyCut/FrameRateInfo.cs b/VCR.NET/EasyCut/FrameRateInfo.cs index f667ecc..6db5b94 100644 --- a/VCR.NET/EasyCut/FrameRateInfo.cs +++ b/VCR.NET/EasyCut/FrameRateInfo.cs @@ -1,98 +1,85 @@ -using System; - namespace EasyCut { - /// - /// Maps the MPEG2 frame rate codes to more useful values. - /// - public sealed class FrameRateInfo - { - /// - /// Supported frame rate codes. - /// - private static FrameRateInfo[] m_RateMap = new FrameRateInfo[16]; - - /// - /// Load the frame rate code table. - /// - static FrameRateInfo() - { - // Load all - m_RateMap[0x0] = new FrameRateInfo(1, 1); - m_RateMap[0x1] = new FrameRateInfo(24000, 1001); - m_RateMap[0x2] = new FrameRateInfo(24, 1); - m_RateMap[0x3] = new FrameRateInfo(25, 1); - m_RateMap[0x4] = new FrameRateInfo(30000, 1001); - m_RateMap[0x5] = new FrameRateInfo(30, 1); - m_RateMap[0x6] = new FrameRateInfo(50, 1); - m_RateMap[0x7] = new FrameRateInfo(60000, 1001); - m_RateMap[0x8] = new FrameRateInfo(60, 1); - m_RateMap[0x9] = new FrameRateInfo(15, 1001); - m_RateMap[0xa] = new FrameRateInfo(5, 1001); - m_RateMap[0xb] = new FrameRateInfo(10, 1001); - m_RateMap[0xc] = new FrameRateInfo(12, 1001); - m_RateMap[0xd] = new FrameRateInfo(15, 1001); - m_RateMap[0xe] = new FrameRateInfo(1, 1); - m_RateMap[0xf] = new FrameRateInfo(1, 1); - } + /// + /// Maps the MPEG2 frame rate codes to more useful values. + /// + public sealed class FrameRateInfo + { + /// + /// Supported frame rate codes. + /// + private static readonly FrameRateInfo[] m_RateMap = new FrameRateInfo[16]; - /// - /// The nominator. - /// - public readonly int Nominator; + /// + /// Load the frame rate code table. + /// + static FrameRateInfo() + { + // Load all + m_RateMap[0x0] = new FrameRateInfo( 1, 1 ); + m_RateMap[0x1] = new FrameRateInfo( 24000, 1001 ); + m_RateMap[0x2] = new FrameRateInfo( 24, 1 ); + m_RateMap[0x3] = new FrameRateInfo( 25, 1 ); + m_RateMap[0x4] = new FrameRateInfo( 30000, 1001 ); + m_RateMap[0x5] = new FrameRateInfo( 30, 1 ); + m_RateMap[0x6] = new FrameRateInfo( 50, 1 ); + m_RateMap[0x7] = new FrameRateInfo( 60000, 1001 ); + m_RateMap[0x8] = new FrameRateInfo( 60, 1 ); + m_RateMap[0x9] = new FrameRateInfo( 15, 1001 ); + m_RateMap[0xa] = new FrameRateInfo( 5, 1001 ); + m_RateMap[0xb] = new FrameRateInfo( 10, 1001 ); + m_RateMap[0xc] = new FrameRateInfo( 12, 1001 ); + m_RateMap[0xd] = new FrameRateInfo( 15, 1001 ); + m_RateMap[0xe] = new FrameRateInfo( 1, 1 ); + m_RateMap[0xf] = new FrameRateInfo( 1, 1 ); + } - /// - /// The denominator. - /// - public readonly int Denominator; + /// + /// The nominator. + /// + public readonly int Nominator; - /// - /// Create a new instance. - /// - /// The nominator. - /// The denominator. - private FrameRateInfo(int nominator, int denominator) - { - // Remember - Nominator = nominator; - Denominator = denominator; - } + /// + /// The denominator. + /// + public readonly int Denominator; - /// - /// Report the frame rate related to the frame rate code. - /// - public double Rate - { - get - { - // Report - return Nominator * 1.0 / Denominator; - } - } + /// + /// Create a new instance. + /// + /// The nominator. + /// The denominator. + private FrameRateInfo( int nominator, int denominator ) + { + // Remember + Nominator = nominator; + Denominator = denominator; + } - /// - /// Find a frame rate for a given MPEG2 frame rate code. - /// - /// A frame rate code from 0 to 15. - /// The related information instance. - public static FrameRateInfo FindFrameRate(int index) - { - // Report - return m_RateMap[index]; - } + /// + /// Report the frame rate related to the frame rate code. + /// + public double Rate => Nominator * 1.0 / Denominator; - /// - /// Show as string. - /// - /// Formatted version of . - public override string ToString() - { - // Check mode - if ( 1 == Denominator ) return Rate.ToString("00.00"); + /// + /// Find a frame rate for a given MPEG2 frame rate code. + /// + /// A frame rate code from 0 to 15. + /// The related information instance. + public static FrameRateInfo FindFrameRate( int index ) => m_RateMap[index]; - // Special - return string.Format("{2:00.00} ({0}/{1})", Nominator, Denominator, Rate); - } + /// + /// Show as string. + /// + /// Formatted version of . + public override string ToString() + { + // Check mode + if (Denominator == 1) + return Rate.ToString( "00.00" ); - } + // Special + return $"{Rate:00.00} ({Nominator}/{Denominator})"; + } + } } diff --git a/VCR.NET/EasyCut/Properties/Resources.Designer.cs b/VCR.NET/EasyCut/Properties/Resources.Designer.cs index f4504bd..30bb95b 100644 --- a/VCR.NET/EasyCut/Properties/Resources.Designer.cs +++ b/VCR.NET/EasyCut/Properties/Resources.Designer.cs @@ -1,7 +1,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.18444 +// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -60,6 +60,24 @@ internal Resources() { } } + /// + /// Looks up a localized string similar to Locate the folder with your GfD Installation.. + /// + internal static string Browse_GfD { + get { + return ResourceManager.GetString("Browse_GfD", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Select corresponding Video File. + /// + internal static string Browse_Mpg { + get { + return ResourceManager.GetString("Browse_Mpg", resourceCulture); + } + } + /// /// Looks up a localized string similar to Error during Cut. /// @@ -77,5 +95,14 @@ internal static string Error_Format { return ResourceManager.GetString("Error_Format", resourceCulture); } } + + /// + /// Looks up a localized string similar to Invalid Characters in Path. + /// + internal static string Error_Utf8 { + get { + return ResourceManager.GetString("Error_Utf8", resourceCulture); + } + } } } diff --git a/VCR.NET/EasyCut/Properties/Resources.de.resx b/VCR.NET/EasyCut/Properties/Resources.de.resx index 0c70d21..477b04d 100644 --- a/VCR.NET/EasyCut/Properties/Resources.de.resx +++ b/VCR.NET/EasyCut/Properties/Resources.de.resx @@ -112,15 +112,24 @@ 2.0 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + Bitte das Verzeichnis mit der GfD Installation auswählen + + + Zugehörige Videodatei auswählen + Fehler beim Schneiden Format nicht unterstützt - bitte eine andere Dateiendung verwenden + + Ungültige Zeichen im Dateipfad + \ No newline at end of file diff --git a/VCR.NET/EasyCut/Properties/Resources.resx b/VCR.NET/EasyCut/Properties/Resources.resx index b509ba8..76b99c3 100644 --- a/VCR.NET/EasyCut/Properties/Resources.resx +++ b/VCR.NET/EasyCut/Properties/Resources.resx @@ -112,15 +112,24 @@ 2.0 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + Locate the folder with your GfD Installation. + + + Select corresponding Video File + Error during Cut Format not supported - please choose another file extension + + Invalid Characters in Path + \ No newline at end of file diff --git a/VCR.NET/EasyCut/Properties/Settings.Designer.cs b/VCR.NET/EasyCut/Properties/Settings.Designer.cs index fda33ff..c507be5 100644 --- a/VCR.NET/EasyCut/Properties/Settings.Designer.cs +++ b/VCR.NET/EasyCut/Properties/Settings.Designer.cs @@ -1,7 +1,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.18444 +// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -12,7 +12,7 @@ namespace EasyCut.Properties { [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "12.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")] internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); @@ -79,5 +79,29 @@ public string Version { this["Version"] = value; } } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string GfDFolder { + get { + return ((string)(this["GfDFolder"])); + } + set { + this["GfDFolder"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool MuxDefault { + get { + return ((bool)(this["MuxDefault"])); + } + set { + this["MuxDefault"] = value; + } + } } } diff --git a/VCR.NET/EasyCut/Properties/Settings.settings b/VCR.NET/EasyCut/Properties/Settings.settings index 820fab0..6f66164 100644 --- a/VCR.NET/EasyCut/Properties/Settings.settings +++ b/VCR.NET/EasyCut/Properties/Settings.settings @@ -17,5 +17,11 @@ 0.0 + + + + + False + \ No newline at end of file diff --git a/VCR.NET/EasyCut/SUPCutter.cs b/VCR.NET/EasyCut/SUPCutter.cs index cf73d89..b758412 100644 --- a/VCR.NET/EasyCut/SUPCutter.cs +++ b/VCR.NET/EasyCut/SUPCutter.cs @@ -1,254 +1,354 @@ using System; using System.IO; +using System.Runtime.InteropServices; using System.Text; namespace EasyCut { - /// - /// Implementation of a SUB format sub-title cutter. - /// - public class SUPCutter : CutterBase - { - /// - /// The path to the first source file which will be used to locate the - /// IFO color description. - /// - private string FirstSource = null; - - /// - /// Overall collector of the cut result. - /// - private MemoryStream Collector; - - /// - /// Create a new instance of the algorithm. - /// - public SUPCutter() - { - // Create result in memory - Collector = new MemoryStream(); - } - - /// - /// Cut from the indicated sub-title source into the memory buffer. - /// - /// Sub-title file name. - /// First frame to cut. - /// Last frame to cut. - /// Current frame in resulting file. - public override void Cut(string source, long startPos, long endPos, long pos) - { - // Remember - if (null == FirstSource) FirstSource = source; - - // Open the sub title file - using (FileStream ttx = new FileStream(source, FileMode.Open, FileAccess.Read, FileShare.Read, 100000)) - { - // Minimum length required - long minFrames = (long)Math.Round(MinDuration * Framerate); - - // Overall correction - long corr = startPos - pos; - - // Load all - for (byte[] head = new byte[12]; head.Length == ttx.Read(head, 0, head.Length); ) - { - // Validate - if (('S' != head[0]) || ('P' != head[1])) break; - - // Load PTS - long pts0 = head[2]; - long pts1 = head[3]; - long pts2 = head[4]; - long pts3 = head[5]; - long pts4 = head[6]; - long pts5 = head[7]; - long pts6 = head[8]; - long pts7 = head[9]; - long pts = pts0 + 256 * (pts1 + 256 * (pts2 + 256 * (pts3 + 256 * (pts4 + 256 * (pts5 + 256 * (pts6 + 256 * pts7)))))); - - // Convert - TimeSpan start = new TimeSpan(pts * 1000 / 9), originalPTS = start; - - // To frame - long ttxStart = (long)((start.TotalSeconds + TimeCorrection) * Framerate); - - // We are fully done - if (ttxStart >= endPos) break; - - // Construct length - int low = head[11]; - int high = head[10]; - int len = low + 256 * high; - - // Allocate - byte[] frame = new byte[len - 2]; - - // Load - if (frame.Length != ttx.Read(frame, 0, frame.Length)) break; - - // We didn't reach the beginning - if (ttxStart < startPos) continue; - - // Get the duration of the packet - int duration = GetDuration(frame), originalDuaration = duration; - - // Invalid packet - if (duration < 0) continue; - - // To frame + /// + /// Implementation of a SUB format sub-title cutter. + /// + public class SUPCutter : CutterBase + { + /// + /// The path to the first source file which will be used to locate the + /// IFO color description. + /// + private string FirstSource = null; + + /// + /// Overall collector of the cut result. + /// + private MemoryStream Collector; + + /// + /// Create a new instance of the algorithm. + /// + public SUPCutter() + { + // Create result in memory + Collector = new MemoryStream(); + } + + /// + /// Cut from the indicated sub-title source into the memory buffer. + /// + /// Sub-title file name. + /// First frame to cut. + /// Last frame to cut. + /// Current frame in resulting file. + public override void Cut( string source, long startPos, long endPos, long pos ) + { + // Remember + if (null == FirstSource) FirstSource = source; + + // Open the sub title file + using (FileStream ttx = new FileStream( source, FileMode.Open, FileAccess.Read, FileShare.Read, 100000 )) + { + // Minimum length required + long minFrames = (long) Math.Round( MinDuration * Framerate ); + + // Overall correction + long corr = startPos - pos; + + // Load all + for (byte[] head = new byte[12]; head.Length == ttx.Read( head, 0, head.Length );) + { + // Validate + if (('S' != head[0]) || ('P' != head[1])) break; + + // Load PTS + long pts0 = head[2]; + long pts1 = head[3]; + long pts2 = head[4]; + long pts3 = head[5]; + long pts4 = head[6]; + long pts5 = head[7]; + long pts6 = head[8]; + long pts7 = head[9]; + long pts = pts0 + 256 * (pts1 + 256 * (pts2 + 256 * (pts3 + 256 * (pts4 + 256 * (pts5 + 256 * (pts6 + 256 * pts7)))))); + + // Convert + TimeSpan start = new TimeSpan( pts * 1000 / 9 ), originalPTS = start; + + // To frame + long ttxStart = (long) ((start.TotalSeconds + TimeCorrection) * Framerate); + + // We are fully done + if (ttxStart >= endPos) break; + + // Construct length + int low = head[11]; + int high = head[10]; + int len = low + 256 * high; + + // Allocate + byte[] frame = new byte[len - 2]; + + // Load + if (frame.Length != ttx.Read( frame, 0, frame.Length )) break; + + // We didn't reach the beginning + if (ttxStart < startPos) continue; + + // Get the duration of the packet + int duration = GetDuration( frame ), originalDuaration = duration; + + // Invalid packet + if (duration < 0) continue; + + // To frame double rawFrames = duration * 1024.0 / 90000.0 * Framerate; - // Check the limit - if (minFrames > (long)rawFrames) continue; + // Check the limit + if (minFrames > (long) rawFrames) continue; // Convert down - long frames = (long)Math.Round(rawFrames), originalFrames = frames; + long frames = (long) Math.Round( rawFrames ), originalFrames = frames; // Get the end - long ttxEnd = ttxStart + frames; - - // Clip if running beyond the end of the cut - if (ttxEnd >= endPos) break; - - // Shift - ttxStart -= corr; - - // Convert to PTS - pts = (long)Math.Round(ttxStart * 90000 / Framerate); - - // Update header - head[2] = (byte)(pts & 0xff); - head[3] = (byte)((pts >> 8) & 0xff); - head[4] = (byte)((pts >> 16) & 0xff); - head[5] = (byte)((pts >> 24) & 0xff); - head[6] = (byte)((pts >> 32) & 0xff); - head[7] = (byte)((pts >> 40) & 0xff); - head[8] = (byte)((pts >> 48) & 0xff); - head[9] = (byte)((pts >> 56) & 0xff); - - // Write header - Collector.Write(head, 0, head.Length); - - // Write frame - Collector.Write(frame, 0, frame.Length); - - // Report - Log("{0} ({1} == {2}) from {3}", new TimeSpan(pts * 1000 / 9), originalDuaration, frames, originalPTS); - } - } - } - - /// - /// Schreibt eine Zeile in die Logdatei. - /// - /// Format der Zeile. - /// Parameter für die Zeile. - private static void Log(string format, params object[] args) - { - // Read the log path - string path = Properties.Settings.Default.SUPLogPath; - - // None - if (string.IsNullOrEmpty(path)) return; - - // Write it - using (StreamWriter stream = new StreamWriter(path, true, Encoding.Unicode)) stream.WriteLine(format, args); - } - - /// - /// Save the cut sub-titles from memory to the indicated summary file. - /// - /// - /// The color IFO will be taken from the first file reported to . - /// - /// Path to the sub-title file. - public override void Save(string target) - { - // Open the file - using (FileStream ttxAll = new FileStream(target, FileMode.Create, FileAccess.Write, FileShare.None)) - { - // Make sure that all data is transferred - Collector.Flush(); - - // Store all - ttxAll.Write(Collector.GetBuffer(), 0, (int)Collector.Length); - } - - // Copy the IFO file - if (null != FirstSource) File.Copy(FirstSource + ".ifo", target + ".ifo", true); - } - - /// - /// Calculate the duration from a SUP packet. - /// - /// The SUP packet excluding the length of the packet. - /// Overall delay inside the SUP packet in SUP units - multiply by 1024 - /// to get a 90kHz clock. - private static int GetDuration(byte[] buffer) - { - // We expect no error but just in case be nice to the caller - try - { - // Load offset to first packet - int offH = buffer[0]; - int offL = buffer[1]; - int offset = offL + 256 * offH - 2; - - // Total duration - int total = 0; - - // Process all sequences - for (; ; ) - { - // Load delay of command table - int delH = buffer[offset + 0]; - int delL = buffer[offset + 1]; - int del = delL + 256 * delH; - - // Sum up - total += del; - - // Start processing commands - int nextH = buffer[offset + 2]; - int nextL = buffer[offset + 3]; - int next = nextL + 256 * nextH - 2; - - // We are done - points to self - if (next == offset) return total; - - // Protect against invalid data leading to endless loops - if (next < offset) return -1; - - // Advance - offset = next; - } - } - catch - { - // Somewhere failed - return -1; - } - } - - #region IDisposable Members - - /// - /// Do proper cleanup. - /// - public override void Dispose() - { - // Cleanup - if (null != Collector) - { - // Close - Collector.Close(); - - // Done - Collector = null; - } - } - - #endregion - } + long ttxEnd = ttxStart + frames; + + // Clip if running beyond the end of the cut + if (ttxEnd >= endPos) break; + + // Shift + ttxStart -= corr; + + // Convert to PTS + pts = (long) Math.Round( ttxStart * 90000 / Framerate ); + + // Update header + head[2] = (byte) (pts & 0xff); + head[3] = (byte) ((pts >> 8) & 0xff); + head[4] = (byte) ((pts >> 16) & 0xff); + head[5] = (byte) ((pts >> 24) & 0xff); + head[6] = (byte) ((pts >> 32) & 0xff); + head[7] = (byte) ((pts >> 40) & 0xff); + head[8] = (byte) ((pts >> 48) & 0xff); + head[9] = (byte) ((pts >> 56) & 0xff); + + // Write header + Collector.Write( head, 0, head.Length ); + + // Write frame + Collector.Write( frame, 0, frame.Length ); + + // Report + Log( "{0} ({1} == {2}) from {3}", new TimeSpan( pts * 1000 / 9 ), originalDuaration, frames, originalPTS ); + } + } + } + + /// + /// Schreibt eine Zeile in die Logdatei. + /// + /// Format der Zeile. + /// Parameter für die Zeile. + private static void Log( string format, params object[] args ) + { + // Read the log path + string path = Properties.Settings.Default.SUPLogPath; + + // None + if (string.IsNullOrEmpty( path )) return; + + // Write it + using (StreamWriter stream = new StreamWriter( path, true, Encoding.Unicode )) stream.WriteLine( format, args ); + } + + /// + /// Save the cut sub-titles from memory to the indicated summary file. + /// + /// + /// The color IFO will be taken from the first file reported to . + /// + /// Path to the sub-title file. + public override void Save( string target ) + { + // Open the file + using (var ttxAll = new FileStream( target, FileMode.Create, FileAccess.Write, FileShare.None )) + { + // Make sure that all data is transferred + Collector.Flush(); + + // Store all + ttxAll.Write( Collector.GetBuffer(), 0, (int) Collector.Length ); + } + + // Copy the IFO file + if (FirstSource != null) + CopyIfo( FirstSource + ".ifo", target + ".ifo" ); + } + + /// + /// Kopiert die ISO Datei mit den Farbinformationen. + /// + /// Die Quelldatei. + /// Die Zieldatei. + private void CopyIfo( string source, string target ) + { + // Process + File.Copy( source, target, true ); + + // Safe test for color mappings + try + { + using (var ifo = new FileStream( target, FileMode.Open, FileAccess.Read, FileShare.None )) + { + var sector = new byte[2 * 1024]; + var sectorCount = ifo.Length / sector.Length; + + // Should at least have the header sector + if (ifo.Read( sector, 0, sector.Length ) != sector.Length) + return; + + // Get the sector number of the title program chain table + var pgci = ReadNumber( sector, 0xcc ); + if (pgci < 1) + return; + if (pgci >= sectorCount) + return; + + // Read the table + var pgciBase = pgci * sector.Length; + + ifo.Seek( pgciBase, SeekOrigin.Begin ); + + if (ifo.Read( sector, 0, sector.Length ) != sector.Length) + return; + + // We suport only a single chain + if (sector[0] != 0) + return; + if (sector[1] != 1) + return; + + // Read the offset of the first PGC + var start = ReadNumber( sector, 0xc ); + if (start < 0) + return; + + // Adjust to color table + var colorBias = pgciBase + start + 0xa4; + if (colorBias >= ifo.Length) + return; + + // Load the color table + var colors = new byte[16 * 4]; + + ifo.Seek( colorBias, SeekOrigin.Begin ); + + if (ifo.Read( colors, 0, colors.Length ) != colors.Length) + return; + + // Dump table + using (var writer = new StreamWriter( Path.ChangeExtension( target, ".pal" ), false, Encoding.GetEncoding( 1252 ) )) + for (var i = 0; i < colors.Length; i++) + { + // Dump as is + for (var j = 3; j-- > 0;) + writer.Write( colors[++i].ToString( "X2" ) ); + + // Separate by newline + writer.WriteLine(); + } + } + } + catch (Exception) + { + // Ignore any error + } + } + + /// + /// Liest eine Zahl. + /// + /// Ein Speicherbereich. + /// Der Anfang der Zahl (MSB first). + /// Die Zahl. + private static int ReadNumber( byte[] sector, int offset ) + { + // Parts + var b3 = sector[offset++]; + var b2 = sector[offset++]; + var b1 = sector[offset++]; + var b0 = sector[offset++]; + + // Combined + return b0 + 256 * (b1 + 256 * (b2 + 256 * b3)); + } + + /// + /// Calculate the duration from a SUP packet. + /// + /// The SUP packet excluding the length of the packet. + /// Overall delay inside the SUP packet in SUP units - multiply by 1024 + /// to get a 90kHz clock. + private static int GetDuration( byte[] buffer ) + { + // We expect no error but just in case be nice to the caller + try + { + // Load offset to first packet + int offH = buffer[0]; + int offL = buffer[1]; + int offset = offL + 256 * offH - 2; + + // Total duration + int total = 0; + + // Process all sequences + for (;;) + { + // Load delay of command table + int delH = buffer[offset + 0]; + int delL = buffer[offset + 1]; + int del = delL + 256 * delH; + + // Sum up + total += del; + + // Start processing commands + int nextH = buffer[offset + 2]; + int nextL = buffer[offset + 3]; + int next = nextL + 256 * nextH - 2; + + // We are done - points to self + if (next == offset) return total; + + // Protect against invalid data leading to endless loops + if (next < offset) return -1; + + // Advance + offset = next; + } + } + catch + { + // Somewhere failed + return -1; + } + } + + #region IDisposable Members + + /// + /// Do proper cleanup. + /// + public override void Dispose() + { + // Cleanup + if (null != Collector) + { + // Close + Collector.Close(); + + // Done + Collector = null; + } + } + + #endregion + } } diff --git a/VCR.NET/EasyCut/app.config b/VCR.NET/EasyCut/app.config index d809e4f..ac74bd8 100644 --- a/VCR.NET/EasyCut/app.config +++ b/VCR.NET/EasyCut/app.config @@ -26,6 +26,12 @@ 0.0 + + + + + False + diff --git a/VCR.NET/FTPWrap/Properties/AssemblyInfo.cs b/VCR.NET/FTPWrap/Properties/AssemblyInfo.cs index 16161cc..883aaec 100644 --- a/VCR.NET/FTPWrap/Properties/AssemblyInfo.cs +++ b/VCR.NET/FTPWrap/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ // Build Number // Revision // -[assembly: AssemblyVersion( "4.3.0.0" )] -[assembly: AssemblyFileVersion( "4.3.0.0" )] +[assembly: AssemblyVersion( "4.5.0.0" )] +[assembly: AssemblyFileVersion( "4.5.0.0" )] diff --git a/VCR.NET/InstallerActions/Properties/AssemblyInfo.cs b/VCR.NET/InstallerActions/Properties/AssemblyInfo.cs index 9cb91fd..8284159 100644 --- a/VCR.NET/InstallerActions/Properties/AssemblyInfo.cs +++ b/VCR.NET/InstallerActions/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion( "4.3.0.0" )] -[assembly: AssemblyFileVersion( "4.3.0.0" )] +[assembly: AssemblyVersion( "4.5.0.0" )] +[assembly: AssemblyFileVersion( "4.5.0.0" )] diff --git a/VCR.NET/Service/App.config.debug b/VCR.NET/Service/App.config.debug index b628e61..8c81937 100644 --- a/VCR.NET/Service/App.config.debug +++ b/VCR.NET/Service/App.config.debug @@ -8,11 +8,17 @@ + + + + + + - + @@ -23,8 +29,8 @@ - - + + diff --git a/VCR.NET/Service/App.config.release b/VCR.NET/Service/App.config.release index 0cca64e..6619e97 100644 --- a/VCR.NET/Service/App.config.release +++ b/VCR.NET/Service/App.config.release @@ -8,6 +8,12 @@ + + + + + + diff --git a/VCR.NET/Service/Properties/AssemblyInfo.cs b/VCR.NET/Service/Properties/AssemblyInfo.cs index fbfcd93..20a6344 100644 --- a/VCR.NET/Service/Properties/AssemblyInfo.cs +++ b/VCR.NET/Service/Properties/AssemblyInfo.cs @@ -26,4 +26,6 @@ // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion( "4.3.0.0" )] +[assembly: AssemblyVersion( "4.5.0.0" )] +[assembly: AssemblyFileVersion("4.5.0.0")] + diff --git a/VCR.NET/ServiceCore/JobManager.cs b/VCR.NET/ServiceCore/JobManager.cs index 8fc4531..865d165 100644 --- a/VCR.NET/ServiceCore/JobManager.cs +++ b/VCR.NET/ServiceCore/JobManager.cs @@ -148,12 +148,9 @@ public VCRJob this[Guid jobIdentifier] { get { - // The result - VCRJob result; - // Cut off lock (m_Jobs) - if (m_Jobs.TryGetValue( jobIdentifier, out result )) + if (m_Jobs.TryGetValue( jobIdentifier, out VCRJob result)) return result; // Report diff --git a/VCR.NET/ServiceCore/Persistence/VCRSchedule.cs b/VCR.NET/ServiceCore/Persistence/VCRSchedule.cs index 228ea8a..8efd582 100644 --- a/VCR.NET/ServiceCore/Persistence/VCRSchedule.cs +++ b/VCR.NET/ServiceCore/Persistence/VCRSchedule.cs @@ -406,9 +406,9 @@ public void AddToScheduler( RecordingScheduler scheduler, VCRJob job, IScheduleR Source = new Station { - TransportStream = persistedSource.Source.TransportStream, - Network = persistedSource.Source.Network, - Service = persistedSource.Source.Service, + TransportStream = persistedSource.Source?.TransportStream ?? 0, + Network = persistedSource.Source?.Network ?? 0, + Service = persistedSource.Source?.Service ?? 0, Name = persistedSource.DisplayName, }, }; diff --git a/VCR.NET/ServiceCore/Planning/PlanContext.cs b/VCR.NET/ServiceCore/Planning/PlanContext.cs index 4d0fbdc..ae8c423 100644 --- a/VCR.NET/ServiceCore/Planning/PlanContext.cs +++ b/VCR.NET/ServiceCore/Planning/PlanContext.cs @@ -29,7 +29,7 @@ private class ScheduleInformationComparer : IComparer /// Die erste Planung. /// Die zweite Planung. /// Die Anordnung der beiden Planungen. - public int Compare( IScheduleInformation left, IScheduleInformation right ) + public int Compare(IScheduleInformation left, IScheduleInformation right) { // Check mode if (left == null) @@ -40,7 +40,7 @@ public int Compare( IScheduleInformation left, IScheduleInformation right ) else if (right == null) return +1; else - return left.Time.Start.CompareTo( right.Time.Start ); + return left.Time.Start.CompareTo(right.Time.Start); } } @@ -63,10 +63,10 @@ public int Compare( IScheduleInformation left, IScheduleInformation right ) /// Erstellt eine neue Detailinformation. /// /// Alle laufenden Aufzeichnungen. - internal PlanContext( IEnumerable running ) + internal PlanContext(IEnumerable running) { // Remember - m_running = (running ?? Enumerable.Empty()).ToDictionary( info => info.Schedule.Definition.UniqueIdentifier ); + m_running = (running ?? Enumerable.Empty()).ToDictionary(info => info.Schedule.Definition.UniqueIdentifier); } /// @@ -74,30 +74,26 @@ internal PlanContext( IEnumerable running ) /// /// Die eindeutige Kennung der Aufzeichnung. /// Die Informationen, mit denen die Aufzeichnung gestartet wurde. - public ScheduleInformation GetRunState( Guid uniqueIdentifier ) - { - // Report - ScheduleInformation info; - return m_running.TryGetValue( uniqueIdentifier, out info ) ? info : null; - } + public ScheduleInformation GetRunState(Guid uniqueIdentifier) => + m_running.TryGetValue(uniqueIdentifier, out ScheduleInformation info) ? info : null; /// /// Ergänz die Abbildung von einer Aufzeichnung auf einen Auftrag. /// /// Eine Aufzeichnung. /// Der zugehörige Auftrag. - public void RegisterSchedule( VCRSchedule schedule, VCRJob job ) + public void RegisterSchedule(VCRSchedule schedule, VCRJob job) { // Validate if (schedule == null) - throw new ArgumentNullException( nameof( schedule ) ); + throw new ArgumentNullException(nameof(schedule)); if (job == null) - throw new ArgumentNullException( nameof( job ) ); + throw new ArgumentNullException(nameof(job)); // Skip on missing identifier var scheduleIdentifier = schedule.UniqueID; if (scheduleIdentifier.HasValue) - m_jobsBySchedule.Add( scheduleIdentifier.Value, job ); + m_jobsBySchedule.Add(scheduleIdentifier.Value, job); } /// @@ -105,23 +101,19 @@ public void RegisterSchedule( VCRSchedule schedule, VCRJob job ) /// /// Die Kennung einer Aufzeichnung. /// Der zugehörige Auftrag oder null. - public VCRJob TryFindJob( Guid scheduleIdentifier ) - { - // Test - VCRJob job; - return m_jobsBySchedule.TryGetValue( scheduleIdentifier, out job ) ? job : null; - } + public VCRJob TryFindJob(Guid scheduleIdentifier) => + m_jobsBySchedule.TryGetValue(scheduleIdentifier, out VCRJob job) ? job : null; /// /// Versucht zu einer Aufzeichnung den zugehörigen Auftrag zu finden. /// /// Eine Aufzeichnung. /// Der zugehörige Auftrag oder null. - public VCRJob TryFindJob( VCRSchedule schedule ) + public VCRJob TryFindJob(VCRSchedule schedule) { // Validate if (schedule == null) - throw new ArgumentNullException( nameof( schedule ) ); + throw new ArgumentNullException(nameof(schedule)); // Skip on missing identifier var scheduleIdentifier = schedule.UniqueID; @@ -129,20 +121,20 @@ public VCRJob TryFindJob( VCRSchedule schedule ) return null; // Forward - return TryFindJob( scheduleIdentifier.Value ); + return TryFindJob(scheduleIdentifier.Value); } /// /// Vermerkt den Aufzeichnungsplan. /// /// Alle einzelnen Aufzeichnungen. - public void LoadPlan( IEnumerable planItems ) + public void LoadPlan(IEnumerable planItems) { // Load m_schedules = (planItems ?? Enumerable.Empty()).ToList(); // Finish - m_schedules.Sort( ByStartComparer ); + m_schedules.Sort(ByStartComparer); } /// diff --git a/VCR.NET/ServiceCore/Planning/RecordingPlanner.cs b/VCR.NET/ServiceCore/Planning/RecordingPlanner.cs index c2c244c..7a2c008 100644 --- a/VCR.NET/ServiceCore/Planning/RecordingPlanner.cs +++ b/VCR.NET/ServiceCore/Planning/RecordingPlanner.cs @@ -131,8 +131,7 @@ public IScheduleResource GetResourceForProfile( string profileName ) return null; // Ask map - IScheduleResource resource; - if (m_resources.TryGetValue( profileName, out resource )) + if (m_resources.TryGetValue(profileName, out IScheduleResource resource)) return resource; // Not found @@ -213,8 +212,7 @@ public void DispatchNextActivity( DateTime referenceTime ) if (stop != null) { // Lookup the item and report to site - ScheduleInformation schedule; - if (!m_started.TryGetValue( stop.UniqueIdentifier, out schedule )) + if (!m_started.TryGetValue(stop.UniqueIdentifier, out ScheduleInformation schedule)) return; // Report to site @@ -288,8 +286,7 @@ public bool SetEndTime( Guid itemIdentifier, DateTime newEndTime ) return false; // See if we know it - ScheduleInformation started; - if (!m_started.TryGetValue( itemIdentifier, out started )) + if (!m_started.TryGetValue(itemIdentifier, out ScheduleInformation started)) return true; // Try to get the new schedule data diff --git a/VCR.NET/ServiceCore/ProfileState.cs b/VCR.NET/ServiceCore/ProfileState.cs index 5fb11e7..5dcabdd 100644 --- a/VCR.NET/ServiceCore/ProfileState.cs +++ b/VCR.NET/ServiceCore/ProfileState.cs @@ -393,6 +393,11 @@ public CardServerProxy ChangeStreamEnd( Guid streamIdentifier, DateTime newEndTi } } + /// + /// Meldet die Anzahl der gerade aktiven Aufzeichnungen. + /// + public int NumberOfActiveRecordings => m_CurrentRequest?.NumberOfActiveRecordings ?? 0; + /// /// Aktiviert oder deaktiviert den Netzwerkversand einer aktiven Quelle. /// diff --git a/VCR.NET/ServiceCore/ProfileStateCollection.cs b/VCR.NET/ServiceCore/ProfileStateCollection.cs index c3c511c..fcc19d7 100644 --- a/VCR.NET/ServiceCore/ProfileStateCollection.cs +++ b/VCR.NET/ServiceCore/ProfileStateCollection.cs @@ -67,11 +67,12 @@ internal ProfileStateCollection( VCRServer server ) /// Die Art der gemeldeten Informationen. /// Methode zum Erstellen der Information zu einem einzelnen Geräteprofil. /// Die Informationen zu den Profilen. - public IEnumerable InspectProfiles( Func factory ) - { - // Forward - return m_profiles.Values.Select( factory ); - } + public IEnumerable InspectProfiles( Func factory ) => m_profiles.Values.Select( factory ); + + /// + /// Meldet die Anzahl der aktiven Aufzeichnungen. + /// + public int NumberOfActiveRecordings => (m_profiles.Count < 1) ? 0 : m_profiles.Values.Sum( profile => profile.NumberOfActiveRecordings ); /// /// Ermittelt den Zustand eines einzelnen Geräteprofils. @@ -95,8 +96,7 @@ public ProfileState this[string profileName] } // Load - ProfileState profile; - if (m_profiles.TryGetValue( profileName, out profile )) + if (m_profiles.TryGetValue(profileName, out ProfileState profile)) return profile; else return null; @@ -453,7 +453,7 @@ public void EnsureNewPlan() { // Make sure that we use an up do date plan lock (m_planAvailableSync) - for (int i = 2; i-- > 0; ) + for (int i = 2; i-- > 0;) { // Enforce calculation BeginNewPlan(); @@ -584,9 +584,8 @@ internal void ConfirmOperation( Guid scheduleIdentifier, bool isStart ) PeriodicScheduler IRecordingPlannerSite.CreateProgramGuideTask( IScheduleResource resource, Profile profile ) { // Protect against misuse - ProfileState state; - if (m_profiles.TryGetValue( profile.Name, out state )) - return new ProgramGuideTask( resource, state ); + if (m_profiles.TryGetValue(profile.Name, out ProfileState state)) + return new ProgramGuideTask(resource, state); else return null; } @@ -600,9 +599,8 @@ PeriodicScheduler IRecordingPlannerSite.CreateProgramGuideTask( IScheduleResourc PeriodicScheduler IRecordingPlannerSite.CreateSourceScanTask( IScheduleResource resource, Profile profile ) { // Protect against misuse - ProfileState state; - if (m_profiles.TryGetValue( profile.Name, out state )) - return new SourceListTask( resource, state ); + if (m_profiles.TryGetValue(profile.Name, out ProfileState state)) + return new SourceListTask(resource, state); else return null; } @@ -703,8 +701,7 @@ void IRecordingPlannerSite.Stop( IScheduleInformation item, RecordingPlanner pla VCRServer.Log( LoggingLevel.Schedules, "Done 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 )) + if (!m_profiles.TryGetValue(item.Resource.Name, out ProfileState profile)) return; // Mark as pending @@ -743,8 +740,7 @@ void IRecordingPlannerSite.Start( IScheduleInformation item, RecordingPlanner pl 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 )) + if (!m_profiles.TryGetValue(item.Resource.Name, out ProfileState profile)) return; // Mark as pending diff --git a/VCR.NET/ServiceCore/ProgramGuide/ProgramGuideEntries.cs b/VCR.NET/ServiceCore/ProgramGuide/ProgramGuideEntries.cs index 37bcb3b..d79707e 100644 --- a/VCR.NET/ServiceCore/ProgramGuide/ProgramGuideEntries.cs +++ b/VCR.NET/ServiceCore/ProgramGuide/ProgramGuideEntries.cs @@ -55,9 +55,8 @@ public void Add( ProgramGuideEntry newEvent ) var key = newEvent.Source; // Attach to holder - OrderedEntries events; - if (!m_Events.TryGetValue( key, out events )) - m_Events.Add( key, events = new OrderedEntries() ); + if (!m_Events.TryGetValue(key, out OrderedEntries events)) + m_Events.Add(key, events = new OrderedEntries()); // Forward events.Add( newEvent ); @@ -73,9 +72,8 @@ public void Add( ProgramGuideEntry newEvent ) public bool HasEntry( SourceIdentifier source, DateTime start, DateTime end ) { // Attach to holder - OrderedEntries events; - if (m_Events.TryGetValue( source, out events )) - return events.HasEntry( start, end ); + if (m_Events.TryGetValue(source, out OrderedEntries events)) + return events.HasEntry(start, end); else return false; } @@ -92,11 +90,10 @@ public bool HasEntry( SourceIdentifier source, DateTime start, DateTime end ) public TTarget FindBestEntry( SourceIdentifier source, DateTime start, DateTime end, Func factory ) { // Attach to holder - OrderedEntries events; - if (m_Events.TryGetValue( source, out events )) - return events.FindBestEntry( start, end, factory ); + if (m_Events.TryGetValue(source, out OrderedEntries events)) + return events.FindBestEntry(start, end, factory); else - return default( TTarget ); + return default(TTarget); } /// @@ -108,9 +105,8 @@ public TTarget FindBestEntry( SourceIdentifier source, DateTime start, public ProgramGuideEntry FindEntry( SourceIdentifier source, DateTime start ) { // Attach to holder - OrderedEntries events; - if (m_Events.TryGetValue( source, out events )) - return events.FindEntry( start ); + if (m_Events.TryGetValue(source, out OrderedEntries events)) + return events.FindEntry(start); else return null; } @@ -179,8 +175,7 @@ public void DiscardOld() public IEnumerable GetEntries( SourceIdentifier source ) { // Load list - OrderedEntries entries; - if (!m_Events.TryGetValue( source, out entries )) + if (!m_Events.TryGetValue(source, out OrderedEntries entries)) yield break; // Process all as long as caller needs it diff --git a/VCR.NET/ServiceCore/Properties/AssemblyInfo.cs b/VCR.NET/ServiceCore/Properties/AssemblyInfo.cs index 8f55247..ee26964 100644 --- a/VCR.NET/ServiceCore/Properties/AssemblyInfo.cs +++ b/VCR.NET/ServiceCore/Properties/AssemblyInfo.cs @@ -34,7 +34,8 @@ // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion( "4.3.0.0" )] +[assembly: AssemblyVersion( "4.5.0.0" )] +[assembly: AssemblyFileVersion("4.5.0.0")] // Startcode für die Web Anwendung [assembly: PreApplicationStartMethod( typeof( ServerRuntime ), "WebStartup" )] diff --git a/VCR.NET/ServiceCore/Requests/CardServerProxy.cs b/VCR.NET/ServiceCore/Requests/CardServerProxy.cs index ae10404..ca7447c 100644 --- a/VCR.NET/ServiceCore/Requests/CardServerProxy.cs +++ b/VCR.NET/ServiceCore/Requests/CardServerProxy.cs @@ -69,6 +69,11 @@ protected CardServerProxy( ProfileState state, VCRRecordingInfo primary ) /// public string ProfileName => ProfileState.ProfileName; + /// + /// Meldet die anzahl der gerade aktiven Aufzeichnungen. + /// + public virtual int NumberOfActiveRecordings => 1; + /// /// Wird aufgerufen, wenn eine Bindung an ein Geräteprofil vorgenommen wird. /// diff --git a/VCR.NET/ServiceCore/Requests/ProgramGuideProxy.cs b/VCR.NET/ServiceCore/Requests/ProgramGuideProxy.cs index e283660..195c899 100644 --- a/VCR.NET/ServiceCore/Requests/ProgramGuideProxy.cs +++ b/VCR.NET/ServiceCore/Requests/ProgramGuideProxy.cs @@ -65,11 +65,10 @@ private ProgramGuideProxy( ProfileState state, VCRRecordingInfo recording ) continue; // Locate - SourceSelection realSource; - if (allSources.TryGetValue( legacyName, out realSource )) - m_selected.Add( realSource.Source ); + if (allSources.TryGetValue(legacyName, out SourceSelection realSource)) + m_selected.Add(realSource.Source); else - VCRServer.Log( LoggingLevel.Full, Properties.Resources.BadEPGStation, legacyName ); + VCRServer.Log(LoggingLevel.Full, Properties.Resources.BadEPGStation, legacyName); } } diff --git a/VCR.NET/ServiceCore/Requests/RecordingProxy.cs b/VCR.NET/ServiceCore/Requests/RecordingProxy.cs index 6d58d09..4f43d09 100644 --- a/VCR.NET/ServiceCore/Requests/RecordingProxy.cs +++ b/VCR.NET/ServiceCore/Requests/RecordingProxy.cs @@ -132,7 +132,7 @@ protected override void OnNewStateAvailable( ServerInformation state ) } // Total file size - Representative.TotalSize = (uint) (totalSize / 1024); + Representative.TotalSize = (uint)(totalSize / 1024); // No new files if (newFiles.Count < 1) @@ -298,6 +298,19 @@ public override void SetRestartThreshold( Guid? scheduleIdentifier ) } ); } + /// + /// Meldet die anzahl der gerade aktiven Aufzeichnungen. + /// + public override int NumberOfActiveRecordings + { + get + { + // In case there are no recordings (during startup or shutdown) make sure we block out caller + lock (m_recordings) + return Math.Max( 1, m_recordings.Count ); + } + } + /// /// Verändert den Endzeitpunkt einer Aufzeichnung. /// @@ -309,7 +322,7 @@ public override void ChangeEndTime( Guid streamIdentifier, DateTime newEndTime, // Report Tools.ExtendedLogging( "Setting End for {0} to {1}", ProfileName, newEndTime ); - // Disable hibernation + // Disable hibernation if this is the last recording in our list if (disableHibernation) Representative.DisableHibernation = true; @@ -374,15 +387,14 @@ private void EnforceUniqueFileNames() foreach (var recording in m_recordings) { // Load list - List recordings; - if (!names.TryGetValue( recording.FileName, out recordings )) + if (!names.TryGetValue(recording.FileName, out List recordings)) { // Create new recordings = new List(); // To map and ordered list - names.Add( recording.FileName, recordings ); - orderedNames.Add( recordings ); + names.Add(recording.FileName, recordings); + orderedNames.Add(recordings); } // Remember diff --git a/VCR.NET/ServiceCore/RestWebApi/ConfigurationController.cs b/VCR.NET/ServiceCore/RestWebApi/ConfigurationController.cs index 86bc423..52b1885 100644 --- a/VCR.NET/ServiceCore/RestWebApi/ConfigurationController.cs +++ b/VCR.NET/ServiceCore/RestWebApi/ConfigurationController.cs @@ -1,12 +1,12 @@ -using System; +using JMS.DVB; +using JMS.DVBVCR.RecordingService.WebServer; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using System; using System.IO; using System.Linq; using System.Runtime.Serialization; using System.Web.Http; -using JMS.DVB; -using JMS.DVBVCR.RecordingService.WebServer; -using Newtonsoft.Json; -using Newtonsoft.Json.Converters; namespace JMS.DVBVCR.RecordingService.RestWebApi @@ -25,13 +25,13 @@ public class SecuritySettings /// /// Die Gruppe der normalen Benutzer. /// - [DataMember( Name = "users" )] + [DataMember(Name = "users")] public string UserRole { get; set; } /// /// Die Gruppe der Administratoren. /// - [DataMember( Name = "admins" )] + [DataMember(Name = "admins")] public string AdminRole { get; set; } } @@ -44,13 +44,13 @@ public class DirectorySettings /// /// Die aktuelle Liste der erlaubten Verzeichnisse. /// - [DataMember( Name = "directories" )] + [DataMember(Name = "directories")] public string[] TargetDirectories { get; set; } /// /// Das Muster für die Erstellung der Dateinamen. /// - [DataMember( Name = "pattern" )] + [DataMember(Name = "pattern")] public string RecordingPattern { get; set; } } @@ -63,37 +63,37 @@ public class GuideSettings /// /// Der Schwellwert für vorgezogene Aktualisierungen (in Stunden). /// - [DataMember( Name = "joinHours" )] + [DataMember(Name = "joinHours")] public int? Threshold { get; set; } /// /// Der minimale Abstand zwischen Aktualisierungen (in Stunden). /// - [DataMember( Name = "minDelay" )] + [DataMember(Name = "minDelay")] public int? Interval { get; set; } /// /// Die maximale Dauer einer Aktualisierung (in Minuten). /// - [DataMember( Name = "duration" )] + [DataMember(Name = "duration")] public uint Duration { get; set; } /// /// Die Stunden, zu denen eine Aktualisierung stattfinden soll. /// - [DataMember( Name = "hours" )] + [DataMember(Name = "hours")] public uint[] Hours { get; set; } /// /// Die Quellen, die bei der Aktualisierung zu berücksichtigen sind. /// - [DataMember( Name = "sources" )] + [DataMember(Name = "sources")] public string[] Sources { get; set; } /// /// Gesetzt, wenn auch die britischen Sendungen zu berücksichtigen sind. /// - [DataMember( Name = "includeUK" )] + [DataMember(Name = "includeUK")] public bool WithUKGuide { get; set; } } @@ -106,31 +106,31 @@ public class SourceScanSettings /// /// Der Schwellwert für vorgezogene Aktualisierungen (in Tagen). /// - [DataMember( Name = "joinDays" )] + [DataMember(Name = "joinDays")] public int? Threshold { get; set; } /// /// Der minimale Abstand zwischen Aktualisierungen (in Tagen). /// - [DataMember( Name = "interval" )] + [DataMember(Name = "interval")] public int? Interval { get; set; } /// /// Die maximale Dauer einer Aktualisierung (in Minuten). /// - [DataMember( Name = "duration" )] + [DataMember(Name = "duration")] public uint Duration { get; set; } /// /// Die Stunden, zu denen eine Aktualisierung stattfinden soll. /// - [DataMember( Name = "hours" )] + [DataMember(Name = "hours")] public uint[] Hours { get; set; } /// /// Gesetzt, wenn die neue Liste mit der alten zusammengeführt werden soll. /// - [DataMember( Name = "merge" )] + [DataMember(Name = "merge")] public bool MergeLists { get; set; } } @@ -143,13 +143,13 @@ public class ProfileSettings /// /// Die Liste aller bekannten Geräteprofile. /// - [DataMember( Name = "profiles" )] + [DataMember(Name = "profiles")] public ConfigurationProfile[] SystemProfiles { get; set; } /// /// Der Name des bevorzugten Geräteprofils. /// - [DataMember( Name = "defaultProfile" )] + [DataMember(Name = "defaultProfile")] public string DefaultProfile { get; set; } } @@ -162,85 +162,85 @@ public class OtherSettings /// /// Gesetzt, wenn der VCR.NET Recording Service den Rechner in den Schlafzustand versetzen darf- /// - [DataMember( Name = "mayHibernate" )] + [DataMember(Name = "mayHibernate")] public bool AllowHibernate { get; set; } /// /// Gesetzt, wenn beim Übergang in den Schlafzustand StandBy verwendet werden soll. /// - [DataMember( Name = "useStandBy" )] + [DataMember(Name = "useStandBy")] public bool UseStandBy { get; set; } /// /// Verweildauer (in Wochen) von Aufträgen im Archiv. /// - [DataMember( Name = "archive" )] + [DataMember(Name = "archive")] public uint ArchiveTime { get; set; } /// /// Verweildauer (in Wochen) von Protokolleinträgen. /// - [DataMember( Name = "protocol" )] + [DataMember(Name = "protocol")] public uint ProtocolTime { get; set; } /// /// Vorlaufzeit (in Sekunden) beim Aufwecken aus dem Schlafzustand. /// - [DataMember( Name = "hibernationDelay" )] + [DataMember(Name = "hibernationDelay")] public uint HibernationDelay { get; set; } /// /// Gesetzt, wenn für H.264 Aufzeichnungen kein PCR generiert werden soll. /// - [DataMember( Name = "noH264PCR" )] + [DataMember(Name = "noH264PCR")] public bool DisablePCRFromH264 { get; set; } /// /// Gesetzt, wenn für MPEG-2 Aufzeichnungen kein PCR generiert werden soll. /// - [DataMember( Name = "noMPEG2PCR" )] + [DataMember(Name = "noMPEG2PCR")] public bool DisablePCRFromMPEG2 { get; set; } /// /// Minimale Verweildauer (in Minuten) im Schlafzustand bei einem erzwungenen Übergang. /// - [DataMember( Name = "forcedHibernationDelay" )] + [DataMember(Name = "forcedHibernationDelay")] public uint DelayAfterForcedHibernation { get; set; } /// /// Gesetzt um die minimale Verweildauer im Schlafzustand zu ignorieren. /// - [DataMember( Name = "suppressHibernationDelay" )] + [DataMember(Name = "suppressHibernationDelay")] public bool SuppressDelayAfterForcedHibernation { get; set; } /// /// Gesetzt, wenn auch das Basic Protokoll zur Autorisierung verwendet werden darf. /// - [DataMember( Name = "basicAuth" )] + [DataMember(Name = "basicAuth")] public bool AllowBasic { get; set; } /// /// Gesetzt, wenn auch eine verschlüsselter SSL Verbindung unterstützt werden soll. /// - [DataMember( Name = "ssl" )] + [DataMember(Name = "ssl")] public bool UseSSL { get; set; } /// /// Der TCP/IP Port für verschlüsselte Verbindungen. /// - [DataMember( Name = "sslPort" )] + [DataMember(Name = "sslPort")] public ushort SSLPort { get; set; } /// /// Der TCP/IP Port des Web Servers. /// - [DataMember( Name = "webPort" )] + [DataMember(Name = "webPort")] public ushort WebPort { get; set; } /// /// Die Art der Protokollierung. /// - [DataMember( Name = "logging" ), JsonConverter( typeof( StringEnumConverter ) )] + [DataMember(Name = "logging"), JsonConverter(typeof(StringEnumConverter))] public LoggingLevel Logging { get; set; } } @@ -253,7 +253,7 @@ public class SchedulerRules /// /// Der Inhalt der Regeldatei. /// - [DataMember( Name = "rules" )] + [DataMember(Name = "rules")] public string RuleFileContents { get; set; } } @@ -265,31 +265,31 @@ public class SchedulerRules /// Das Bezugsverzeichnis. /// Die Verzeichnisse innerhalb ober oberhalb des Bezugsverzeichnisses. [HttpGet] - public string[] Browse( string browse, bool toParent = false, string root = null ) + public string[] Browse(string browse, bool toParent = false, string root = null) { // Validate ServerRuntime.TestAdminAccess(); // See if we can move up - if (!string.IsNullOrEmpty( root )) + if (!string.IsNullOrEmpty(root)) if (toParent) - if (StringComparer.InvariantCultureIgnoreCase.Equals( root, Path.GetPathRoot( root ) )) + if (StringComparer.InvariantCultureIgnoreCase.Equals(root, Path.GetPathRoot(root))) root = null; else - root = Path.GetDirectoryName( root ); + root = Path.GetDirectoryName(root); // Devices - var names = string.IsNullOrEmpty( root ) + var names = string.IsNullOrEmpty(root) ? DriveInfo - .GetDrives() - .Where( drive => drive.DriveType == DriveType.Fixed ) - .Where( drive => drive.IsReady ) - .Select( drive => drive.RootDirectory.FullName ) + .GetDrives() + .Where(drive => drive.DriveType == DriveType.Fixed) + .Where(drive => drive.IsReady) + .Select(drive => drive.RootDirectory.FullName) : Directory - .GetDirectories( root ); + .GetDirectories(root); // Report - return new[] { root }.Concat( names.OrderBy( name => name, StringComparer.InvariantCultureIgnoreCase ) ).ToArray(); + return new[] { root }.Concat(names.OrderBy(name => name, StringComparer.InvariantCultureIgnoreCase)).ToArray(); } /// @@ -299,7 +299,7 @@ public string[] Browse( string browse, bool toParent = false, string root = null /// Das zu prüfende Verzeichnis. /// Gesetzt, wenn das Verzeichnis verwendet werden kann. [HttpGet] - public bool Validate( string validate, string directory ) + public bool Validate(string validate, string directory) { // Validate ServerRuntime.TestAdminAccess(); @@ -308,7 +308,7 @@ public bool Validate( string validate, string directory ) try { // Test - return Directory.Exists( directory ); + return Directory.Exists(directory); } catch (Exception) { @@ -323,11 +323,7 @@ public bool Validate( string validate, string directory ) /// Wird zur Unterscheidung der Methoden verwendet. /// Die aktuellen Regeln. [HttpGet] - public SchedulerRules ReadSchedulerRules( string rules ) - { - // Blind forward - we allow regular users to read the current rule set as well - return new SchedulerRules { RuleFileContents = ServerRuntime.VCRServer.SchedulerRules }; - } + public SchedulerRules ReadSchedulerRules(string rules) => new SchedulerRules { RuleFileContents = ServerRuntime.VCRServer.SchedulerRules }; /// /// Aktualisiert das Regelwerk für die Aufzeichnungsplanung. @@ -336,11 +332,7 @@ public SchedulerRules ReadSchedulerRules( string rules ) /// Die ab sofort zu verwendenden Regeln. /// Meldet, ob ein Neustart erforderlich ist. [HttpPut] - public bool? WriteSchedulerRules( string rules, [FromBody] SchedulerRules settings ) - { - // Process - return ServerRuntime.UpdateSchedulerRules( settings.RuleFileContents ); - } + public bool? WriteSchedulerRules(string rules, [FromBody] SchedulerRules settings) => ServerRuntime.UpdateSchedulerRules(settings.RuleFileContents); /// /// Meldet die Konfigurationsdaten der Geräte. @@ -348,13 +340,12 @@ public SchedulerRules ReadSchedulerRules( string rules ) /// Wird zur Unterscheidung der Methoden verwendet. /// Die aktuelle Konfiguration. [HttpGet] - public ProfileSettings ReadProfiles( string devices ) + public ProfileSettings ReadProfiles(string devices) { // Validate ServerRuntime.TestAdminAccess(); // Helper - string defaultName; // Create response var settings = @@ -363,8 +354,8 @@ public ProfileSettings ReadProfiles( string devices ) SystemProfiles = ServerRuntime .VCRServer - .GetProfiles( ConfigurationProfile.Create, out defaultName ) - .OrderBy( profile => profile.Name, ProfileManager.ProfileNameComparer ) + .GetProfiles(ConfigurationProfile.Create, out string defaultName) + .OrderBy(profile => profile.Name, ProfileManager.ProfileNameComparer) .ToArray() }; @@ -382,31 +373,31 @@ public ProfileSettings ReadProfiles( string devices ) /// Die gewünschten neuen Einstellungen. /// Das Ergebnis der Änderung. [HttpPut] - public bool? WriteProfiles( string devices, [FromBody] ProfileSettings settings ) + public bool? WriteProfiles(string devices, [FromBody] ProfileSettings settings) { // Validate ServerRuntime.TestAdminAccess(); // List of profiles to use - var profiles = settings.SystemProfiles.Where( profile => profile.UsedForRecording ).Select( profile => profile.Name ).ToList(); + var profiles = settings.SystemProfiles.Where(profile => profile.UsedForRecording).Select(profile => profile.Name).ToList(); // Move default to the front - var defaultIndex = profiles.IndexOf( settings.DefaultProfile ); + var defaultIndex = profiles.IndexOf(settings.DefaultProfile); if (defaultIndex >= 0) { // Insert at the very beginning - profiles.Insert( 0, profiles[defaultIndex] ); - profiles.RemoveAt( defaultIndex + 1 ); + profiles.Insert(0, profiles[defaultIndex]); + profiles.RemoveAt(defaultIndex + 1); } // Prepare - var update = VCRConfiguration.Current.BeginUpdate( SettingNames.Profiles ); + var update = VCRConfiguration.Current.BeginUpdate(SettingNames.Profiles); // Fill - update[SettingNames.Profiles].NewValue = string.Join( "|", profiles ); + update[SettingNames.Profiles].NewValue = string.Join("|", profiles); // Process - return ServerRuntime.Update( update.Values, ServerRuntime.VCRServer.UpdateProfiles( settings.SystemProfiles, profile => profile.Name, ( profile, device ) => profile.WriteBack( device ) ) ); + return ServerRuntime.Update(update.Values, ServerRuntime.VCRServer.UpdateProfiles(settings.SystemProfiles, profile => profile.Name, (profile, device) => profile.WriteBack(device))); } /// @@ -415,7 +406,7 @@ public ProfileSettings ReadProfiles( string devices ) /// Wird zur Unterscheidung der Methoden verwendet. /// Die gewünschten Einstellungen. [HttpGet] - public DirectorySettings ReadDirectory( string directory ) + public DirectorySettings ReadDirectory(string directory) { // Validate ServerRuntime.TestAdminAccess(); @@ -436,18 +427,18 @@ public DirectorySettings ReadDirectory( string directory ) /// Die neuen Daten. /// Das Ergebnis der Operation. [HttpPut] - public bool? WriteDirectory( string directory, [FromBody] DirectorySettings settings ) + public bool? WriteDirectory(string directory, [FromBody] DirectorySettings settings) { // Prepare to update - var update = VCRConfiguration.Current.BeginUpdate( SettingNames.VideoRecorderDirectory, SettingNames.AdditionalRecorderPaths, SettingNames.FileNamePattern ); + var update = VCRConfiguration.Current.BeginUpdate(SettingNames.VideoRecorderDirectory, SettingNames.AdditionalRecorderPaths, SettingNames.FileNamePattern); // Change settings - update[SettingNames.AdditionalRecorderPaths].NewValue = string.Join( ", ", settings.TargetDirectories.Skip( 1 ) ); + update[SettingNames.AdditionalRecorderPaths].NewValue = string.Join(", ", settings.TargetDirectories.Skip(1)); update[SettingNames.VideoRecorderDirectory].NewValue = settings.TargetDirectories.FirstOrDefault(); update[SettingNames.FileNamePattern].NewValue = settings.RecordingPattern; // Process - return ServerRuntime.Update( update.Values ); + return ServerRuntime.Update(update.Values); } /// @@ -456,7 +447,7 @@ public DirectorySettings ReadDirectory( string directory ) /// Unterscheidet zwischen den einzelnen Methoden. /// Die aktuellen Einstellungen. [HttpGet] - public SourceScanSettings ReadSoureScan( string scan ) + public SourceScanSettings ReadSoureScan(string scan) { // Validate ServerRuntime.TestAdminAccess(); @@ -469,11 +460,11 @@ public SourceScanSettings ReadSoureScan( string scan ) return new SourceScanSettings { - Hours = VCRConfiguration.Current.SourceListUpdateHoursAsArray.OrderBy( hour => hour ).ToArray(), - Threshold = join.HasValue ? (int) join.Value.TotalDays : default( int? ), + Hours = VCRConfiguration.Current.SourceListUpdateHoursAsArray.OrderBy(hour => hour).ToArray(), + Threshold = join.HasValue ? (int)join.Value.TotalDays : default(int?), MergeLists = VCRConfiguration.Current.MergeSourceListUpdateResult, Duration = VCRConfiguration.Current.SourceListUpdateDuration, - Interval = (interval != 0) ? interval : default( int? ), + Interval = (interval != 0) ? interval : default(int?), }; } @@ -484,26 +475,26 @@ public SourceScanSettings ReadSoureScan( string scan ) /// Die neuen Einstellungen. /// Das Ergebnis der Änderung. [HttpPut] - public bool? WriteSourceScan( string scan, [FromBody] SourceScanSettings settings ) + public bool? WriteSourceScan(string scan, [FromBody] SourceScanSettings settings) { // Check mode - if (settings.Interval == 0) + if (settings.Interval.GetValueOrDefault(0) == 0) { // Create settings - var disable = VCRConfiguration.Current.BeginUpdate( SettingNames.ScanInterval ); + var disable = VCRConfiguration.Current.BeginUpdate(SettingNames.ScanInterval); // Store disable[SettingNames.ScanInterval].NewValue = "0"; // Process - return ServerRuntime.Update( disable.Values ); + return ServerRuntime.Update(disable.Values); } // Check mode if (settings.Interval < 0) { // Create settings - var manual = VCRConfiguration.Current.BeginUpdate( SettingNames.ScanDuration, SettingNames.MergeScanResult, SettingNames.ScanInterval ); + var manual = VCRConfiguration.Current.BeginUpdate(SettingNames.ScanDuration, SettingNames.MergeScanResult, SettingNames.ScanInterval); // Store manual[SettingNames.MergeScanResult].NewValue = settings.MergeLists.ToString(); @@ -511,21 +502,21 @@ public SourceScanSettings ReadSoureScan( string scan ) manual[SettingNames.ScanInterval].NewValue = "-1"; // Process - return ServerRuntime.Update( manual.Values ); + return ServerRuntime.Update(manual.Values); } // Prepare to update - var update = VCRConfiguration.Current.BeginUpdate( SettingNames.ScanDuration, SettingNames.MergeScanResult, SettingNames.ScanInterval, SettingNames.ScanHours, SettingNames.ScanJoinThreshold ); + var update = VCRConfiguration.Current.BeginUpdate(SettingNames.ScanDuration, SettingNames.MergeScanResult, SettingNames.ScanInterval, SettingNames.ScanHours, SettingNames.ScanJoinThreshold); // Fill it - update[SettingNames.ScanHours].NewValue = string.Join( ", ", settings.Hours.Select( hour => hour.ToString() ) ); + update[SettingNames.ScanHours].NewValue = string.Join(", ", settings.Hours.Select(hour => hour.ToString())); update[SettingNames.ScanJoinThreshold].NewValue = settings.Threshold.ToString(); update[SettingNames.MergeScanResult].NewValue = settings.MergeLists.ToString(); update[SettingNames.ScanInterval].NewValue = settings.Interval.ToString(); update[SettingNames.ScanDuration].NewValue = settings.Duration.ToString(); // Process - return ServerRuntime.Update( update.Values ); + return ServerRuntime.Update(update.Values); } /// @@ -534,7 +525,7 @@ public SourceScanSettings ReadSoureScan( string scan ) /// Unterscheidet zwischen den einzelnen Methoden. /// Die aktuellen Einstellungen. [HttpGet] - public GuideSettings ReadGuide( string guide ) + public GuideSettings ReadGuide(string guide) { // Validate ServerRuntime.TestAdminAccess(); @@ -547,10 +538,10 @@ public GuideSettings ReadGuide( string guide ) return new GuideSettings { - Sources = VCRConfiguration.Current.ProgramGuideSourcesAsArray.OrderBy( name => name, StringComparer.InvariantCultureIgnoreCase ).ToArray(), - Hours = VCRConfiguration.Current.ProgramGuideUpdateHoursAsArray.OrderBy( hour => hour ).ToArray(), - Interval = interval.HasValue ? (int) interval.Value.TotalHours : default( int? ), - Threshold = join.HasValue ? (int) join.Value.TotalHours : default( int? ), + Sources = VCRConfiguration.Current.ProgramGuideSourcesAsArray.OrderBy(name => name, StringComparer.InvariantCultureIgnoreCase).ToArray(), + Hours = VCRConfiguration.Current.ProgramGuideUpdateHoursAsArray.OrderBy(hour => hour).ToArray(), + Interval = interval.HasValue ? (int)interval.Value.TotalHours : default(int?), + Threshold = join.HasValue ? (int)join.Value.TotalHours : default(int?), Duration = VCRConfiguration.Current.ProgramGuideUpdateDuration, WithUKGuide = VCRConfiguration.Current.EnableFreeSat, }; @@ -563,34 +554,34 @@ public GuideSettings ReadGuide( string guide ) /// Die neuen Einstellungen. /// Das Ergebnis der Änderung. [HttpPut] - public bool? WriteGuide( string guide, [FromBody] GuideSettings settings ) + public bool? WriteGuide(string guide, [FromBody] GuideSettings settings) { // Check mode if (settings.Duration < 1) { // Create settings - var disable = VCRConfiguration.Current.BeginUpdate( SettingNames.EPGDuration ); + var disable = VCRConfiguration.Current.BeginUpdate(SettingNames.EPGDuration); // Store disable[SettingNames.EPGDuration].NewValue = "0"; // Process - return ServerRuntime.Update( disable.Values ); + return ServerRuntime.Update(disable.Values); } // Prepare to update - var update = VCRConfiguration.Current.BeginUpdate( SettingNames.EPGDuration, SettingNames.EPGStations, SettingNames.EPGHours, SettingNames.EPGIncludeFreeSat, SettingNames.EPGInterval, SettingNames.EPGJoinThreshold ); + var update = VCRConfiguration.Current.BeginUpdate(SettingNames.EPGDuration, SettingNames.EPGStations, SettingNames.EPGHours, SettingNames.EPGIncludeFreeSat, SettingNames.EPGInterval, SettingNames.EPGJoinThreshold); // Fill it - update[SettingNames.EPGHours].NewValue = string.Join( ", ", settings.Hours.Select( hour => hour.ToString() ) ); + update[SettingNames.EPGHours].NewValue = string.Join(", ", settings.Hours.Select(hour => hour.ToString())); update[SettingNames.EPGIncludeFreeSat].NewValue = settings.WithUKGuide.ToString(); - update[SettingNames.EPGStations].NewValue = string.Join( ", ", settings.Sources ); + update[SettingNames.EPGStations].NewValue = string.Join(", ", settings.Sources); update[SettingNames.EPGJoinThreshold].NewValue = settings.Threshold.ToString(); update[SettingNames.EPGInterval].NewValue = settings.Interval.ToString(); update[SettingNames.EPGDuration].NewValue = settings.Duration.ToString(); // Process - return ServerRuntime.Update( update.Values ); + return ServerRuntime.Update(update.Values); } /// @@ -599,7 +590,7 @@ public GuideSettings ReadGuide( string guide ) /// Unterscheidet zwischen den einzelnen Methoden. /// Die aktuellen Einstellungen. [HttpGet] - public SecuritySettings ReadSecurity( string security ) + public SecuritySettings ReadSecurity(string security) { // Validate ServerRuntime.TestAdminAccess(); @@ -620,17 +611,17 @@ public SecuritySettings ReadSecurity( string security ) /// Die neuen Einstellungen. /// null bei Fehlern und ansonsten gesetzt, wenn ein Neustart des Dienstes ausgeführt wird. [HttpPut] - public bool? WriteSecurity( string security, [FromBody] SecuritySettings settings ) + public bool? WriteSecurity(string security, [FromBody] SecuritySettings settings) { // Prepare to update - var update = VCRConfiguration.Current.BeginUpdate( SettingNames.RequiredUserRole, SettingNames.RequiredAdminRole ); + var update = VCRConfiguration.Current.BeginUpdate(SettingNames.RequiredUserRole, SettingNames.RequiredAdminRole); // Change settings update[SettingNames.RequiredAdminRole].NewValue = settings.AdminRole; update[SettingNames.RequiredUserRole].NewValue = settings.UserRole; // Process - return ServerRuntime.Update( update.Values ); + return ServerRuntime.Update(update.Values); } /// @@ -639,7 +630,7 @@ public SecuritySettings ReadSecurity( string security ) /// Wird zur Unterscheidung der Methoden verwendet. /// Die aktuellen Einstellungen. [HttpGet] - public OtherSettings ReadOtherSettings( string other ) + public OtherSettings ReadOtherSettings(string other) { // Validate ServerRuntime.TestAdminAccess(); @@ -648,7 +639,7 @@ public OtherSettings ReadOtherSettings( string other ) return new OtherSettings { - DelayAfterForcedHibernation = (uint) VCRConfiguration.Current.DelayAfterForcedHibernation.TotalMinutes, + DelayAfterForcedHibernation = (uint)VCRConfiguration.Current.DelayAfterForcedHibernation.TotalMinutes, SuppressDelayAfterForcedHibernation = VCRConfiguration.Current.SuppressDelayAfterForcedHibernation, DisablePCRFromMPEG2 = VCRConfiguration.Current.DisablePCRFromMPEG2Generation, DisablePCRFromH264 = VCRConfiguration.Current.DisablePCRFromH264Generation, @@ -672,7 +663,7 @@ public OtherSettings ReadOtherSettings( string other ) /// Die neuen Einstellungen. /// Das Ergebnis der Änderung. [HttpPut] - public bool? WriteOther( string other, [FromBody] OtherSettings settings ) + public bool? WriteOther(string other, [FromBody] OtherSettings settings) { // Prepare to update var update = @@ -711,7 +702,7 @@ public OtherSettings ReadOtherSettings( string other ) update[SettingNames.UseSSL].NewValue = settings.UseSSL.ToString(); // Process - return ServerRuntime.Update( update.Values ); + return ServerRuntime.Update(update.Values); } } } diff --git a/VCR.NET/ServiceCore/RestWebApi/ConfigurationProfile.cs b/VCR.NET/ServiceCore/RestWebApi/ConfigurationProfile.cs index 6bc9b5b..fba37b4 100644 --- a/VCR.NET/ServiceCore/RestWebApi/ConfigurationProfile.cs +++ b/VCR.NET/ServiceCore/RestWebApi/ConfigurationProfile.cs @@ -58,8 +58,7 @@ private static uint ReadSetting( Profile profile, string settingName, uint setti return settingDefault; // Check value - uint value; - if (uint.TryParse( settings, out value )) + if (uint.TryParse(settings, out uint value)) return value; else return settingDefault; diff --git a/VCR.NET/ServiceCore/RestWebApi/EditController.cs b/VCR.NET/ServiceCore/RestWebApi/EditController.cs index 13a9623..29383f0 100644 --- a/VCR.NET/ServiceCore/RestWebApi/EditController.cs +++ b/VCR.NET/ServiceCore/RestWebApi/EditController.cs @@ -63,8 +63,7 @@ public JobScheduleInfo FindJob( string detail, string epg = null ) detail = detail.Substring( 1, 32 ) + Guid.NewGuid().ToString( "N" ); // Parameter analysieren - VCRJob job; - var schedule = ServerRuntime.ParseUniqueWebId( detail, out job ); + var schedule = ServerRuntime.ParseUniqueWebId(detail, out VCRJob job); // See if we have to initialize from program guide ProgramGuideEntry epgEntry = null; @@ -91,8 +90,7 @@ public JobScheduleInfo FindJob( string detail, string epg = null ) public void UpdateRecording( string detail, [FromBody] JobScheduleData data ) { // Parameter analysieren - VCRJob job; - var schedule = ServerRuntime.ParseUniqueWebId( detail, out job ); + var schedule = ServerRuntime.ParseUniqueWebId(detail, out VCRJob job); // Validate if (schedule == null) @@ -135,8 +133,7 @@ public void UpdateRecording( string detail, [FromBody] JobScheduleData data ) public void DeleteRecording( string detail ) { // Parameter analysieren - VCRJob job; - var schedule = ServerRuntime.ParseUniqueWebId( detail, out job ); + var schedule = ServerRuntime.ParseUniqueWebId(detail, out VCRJob job); // Validate if (schedule == null) @@ -162,8 +159,7 @@ public void DeleteRecording( string detail ) public string CreateNewRecording( string detail, [FromBody] JobScheduleData data ) { // Parameter analysieren - VCRJob job; - ServerRuntime.ParseUniqueWebId( detail + Guid.NewGuid().ToString( "N" ), out job ); + ServerRuntime.ParseUniqueWebId(detail + Guid.NewGuid().ToString("N"), out VCRJob job); // Validate if (job == null) diff --git a/VCR.NET/ServiceCore/RestWebApi/ExceptionController.cs b/VCR.NET/ServiceCore/RestWebApi/ExceptionController.cs index fb60456..7728729 100644 --- a/VCR.NET/ServiceCore/RestWebApi/ExceptionController.cs +++ b/VCR.NET/ServiceCore/RestWebApi/ExceptionController.cs @@ -22,10 +22,7 @@ public void ChangeException( string detail, string when, int startDelta, int dur { // Parse the date var date = new DateTime( long.Parse( when ), DateTimeKind.Utc ); - - // Split - Guid jobIdentifier, scheduleIdentifier; - ServerRuntime.ParseUniqueWebId( detail, out jobIdentifier, out scheduleIdentifier ); + ServerRuntime.ParseUniqueWebId( detail, out Guid jobIdentifier, out Guid scheduleIdentifier ); // Forward ServerRuntime.VCRServer.ChangeException( jobIdentifier, scheduleIdentifier, date, startDelta, durationDelta ); diff --git a/VCR.NET/ServiceCore/RestWebApi/GuideController.cs b/VCR.NET/ServiceCore/RestWebApi/GuideController.cs index ccba1d0..5511c66 100644 --- a/VCR.NET/ServiceCore/RestWebApi/GuideController.cs +++ b/VCR.NET/ServiceCore/RestWebApi/GuideController.cs @@ -1,10 +1,7 @@ -using System; -using System.Linq; -using System.Web.Http; -using JMS.DVB; -using JMS.DVBVCR.RecordingService.ProgramGuide; +using JMS.DVB; using JMS.DVBVCR.RecordingService.WebServer; - +using System; +using System.Web.Http; namespace JMS.DVBVCR.RecordingService.RestWebApi { @@ -21,19 +18,19 @@ public class GuideController : ApiController /// Informationen zum Abruf des Eintrags. /// Der gewünschte Eintrag. [HttpGet] - public GuideItem Find( string profile, string source, string pattern ) + public GuideItem Find(string profile, string source, string pattern) { // Check mode - var split = pattern.IndexOf( '-' ); + var split = pattern.IndexOf('-'); if (split < 0) return null; // Split pattern - var start = new DateTime( long.Parse( pattern.Substring( 0, split ) ) * Tools.UnixTimeFactor + Tools.UnixTimeBias, DateTimeKind.Utc ); - var end = new DateTime( long.Parse( pattern.Substring( split + 1 ) ) * Tools.UnixTimeFactor + Tools.UnixTimeBias, DateTimeKind.Utc ); + var start = new DateTime(long.Parse(pattern.Substring(0, split)) * Tools.UnixTimeFactor + Tools.UnixTimeBias, DateTimeKind.Utc); + var end = new DateTime(long.Parse(pattern.Substring(split + 1)) * Tools.UnixTimeFactor + Tools.UnixTimeBias, DateTimeKind.Utc); // Forward - return ServerRuntime.VCRServer.FindProgramGuideEntry( profile, SourceIdentifier.Parse( source ), start, end, GuideItem.Create ); + return ServerRuntime.VCRServer.FindProgramGuideEntry(profile, SourceIdentifier.Parse(source), start, end, GuideItem.Create); } /// @@ -42,11 +39,7 @@ public GuideItem Find( string profile, string source, string pattern ) /// Die Beschreibung des Filters. /// Die Liste aller passenden Einträge. [HttpPost] - public GuideItem[] Find( [FromBody] GuideFilter filter ) - { - // Forward - return ServerRuntime.VCRServer.GetProgramGuideEntries( filter, GuideFilter.Translate, GuideItem.Create ); - } + public GuideItem[] Find([FromBody] GuideFilter filter) => ServerRuntime.VCRServer.GetProgramGuideEntries(filter, GuideFilter.Translate, GuideItem.Create); /// /// Meldet alle Einträge der Programmzeitschrift zu einem Geräteprofil. @@ -55,11 +48,7 @@ public GuideItem[] Find( [FromBody] GuideFilter filter ) /// Die Beschreibung des Filters. /// Die Anzahl aller passenden Einträge. [HttpPost] - public int Count( string countOnly, [FromBody] GuideFilter filter ) - { - // Forward - return ServerRuntime.VCRServer.GetProgramGuideEntries( filter, GuideFilter.Translate ); - } + public int Count(string countOnly, [FromBody] GuideFilter filter) => ServerRuntime.VCRServer.GetProgramGuideEntries(filter, GuideFilter.Translate); /// @@ -68,10 +57,6 @@ public int Count( string countOnly, [FromBody] GuideFilter filter ) /// Der Name des Profils. /// Die gewünschten Informationen. [HttpGet] - public GuideInfo GetInfo( string detail ) - { - // Forward - return ServerRuntime.VCRServer.GetProgramGuideInformation( detail, GuideInfo.Create ); - } + public GuideInfo GetInfo(string detail) => ServerRuntime.VCRServer.GetProgramGuideInformation(detail, GuideInfo.Create); } } diff --git a/VCR.NET/ServiceCore/RestWebApi/GuideItem.cs b/VCR.NET/ServiceCore/RestWebApi/GuideItem.cs index fbcb843..8110640 100644 --- a/VCR.NET/ServiceCore/RestWebApi/GuideItem.cs +++ b/VCR.NET/ServiceCore/RestWebApi/GuideItem.cs @@ -30,7 +30,7 @@ public string StartTimeISO [DataMember( Name = "duration" )] public int DurationInSeconds { - get { return (int) Math.Round( Duration.TotalSeconds ); } + get { return (int)Math.Round( Duration.TotalSeconds ); } set { Duration = TimeSpan.FromSeconds( value ); } } @@ -117,7 +117,7 @@ public static GuideItem Create( ProgramGuideEntry entry, string profileName ) return new GuideItem { - Identifier = string.Format( "{0}:{1}:{2}", entry.StartTime.Ticks, profileName, SourceIdentifier.ToString( entry.Source ).Replace( " ", "" ) ), + Identifier = $"{entry.StartTime.Ticks}:{profileName}:{SourceIdentifier.ToString( entry.Source ).Replace( " ", "" )}", Station = (source == null) ? entry.StationName : source.GetUniqueName(), Duration = TimeSpan.FromSeconds( entry.Duration ), Categories = entry.Categories.ToArray(), diff --git a/VCR.NET/ServiceCore/RestWebApi/HibernateController.cs b/VCR.NET/ServiceCore/RestWebApi/HibernateController.cs index 7562c75..04981d7 100644 --- a/VCR.NET/ServiceCore/RestWebApi/HibernateController.cs +++ b/VCR.NET/ServiceCore/RestWebApi/HibernateController.cs @@ -1,5 +1,5 @@ -using System.Web.Http; -using JMS.DVBVCR.RecordingService.WebServer; +using JMS.DVBVCR.RecordingService.WebServer; +using System.Web.Http; namespace JMS.DVBVCR.RecordingService.RestWebApi @@ -14,21 +14,13 @@ public class HibernateController : ApiController /// /// Dient zur Unterscheidung der Methoden. [HttpPost] - public void ResetPendingHibernation( string reset ) - { - // Forward - ServerRuntime.VCRServer.ResetPendingHibernation(); - } + public void ResetPendingHibernation( string reset ) => ServerRuntime.VCRServer.ResetPendingHibernation(); /// /// Versucht, den Schlafzustand auszulösen. /// /// Dient zur Unterscheidung der Methoden [HttpPost] - public void TryHibernate( string hibernate ) - { - // Forward - ServerRuntime.VCRServer.TryHibernateIgnoringInteractiveUsers(); - } + public void TryHibernate( string hibernate ) => ServerRuntime.VCRServer.TryHibernateIgnoringInteractiveUsers(); } } diff --git a/VCR.NET/ServiceCore/RestWebApi/InfoController.cs b/VCR.NET/ServiceCore/RestWebApi/InfoController.cs index 6275f1d..ddcf509 100644 --- a/VCR.NET/ServiceCore/RestWebApi/InfoController.cs +++ b/VCR.NET/ServiceCore/RestWebApi/InfoController.cs @@ -1,4 +1,5 @@ -using System; +using JMS.DVBVCR.RecordingService.WebServer; +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -6,7 +7,6 @@ using System.Runtime.InteropServices; using System.Text; using System.Web.Http; -using JMS.DVBVCR.RecordingService.WebServer; namespace JMS.DVBVCR.RecordingService.RestWebApi @@ -73,7 +73,7 @@ private static string InstalledVersion // Retrieve if (MsiGetProductInfo( productCode.ToString(), "VersionString", buffer, ref bufferSize ) == 0) - _InstalledVersion = new string( buffer, 0, checked( (int) bufferSize ) ); + _InstalledVersion = new string( buffer, 0, checked((int) bufferSize) ); } } catch (Exception e) @@ -124,12 +124,8 @@ public InfoService VersionInformation() /// Wird zur Unterscheidung der Methoden verwendet. /// Die gewünschte Liste. [HttpGet] - public string[] GetRecordingDirectories( string directories ) - { - // First is default - return VCRConfiguration.Current.TargetDirectoriesNames.SelectMany( ScanDirectory ).ToArray(); - } - + public string[] GetRecordingDirectories( string directories ) => VCRConfiguration.Current.TargetDirectoriesNames.SelectMany( ScanDirectory ).ToArray(); + /// /// Meldet alle Aufträge. /// diff --git a/VCR.NET/ServiceCore/RestWebApi/InfoJob.cs b/VCR.NET/ServiceCore/RestWebApi/InfoJob.cs index 470f677..5be9855 100644 --- a/VCR.NET/ServiceCore/RestWebApi/InfoJob.cs +++ b/VCR.NET/ServiceCore/RestWebApi/InfoJob.cs @@ -1,8 +1,8 @@ -using System; +using JMS.DVBVCR.RecordingService.Persistence; +using JMS.DVBVCR.RecordingService.WebServer; +using System; using System.Linq; using System.Runtime.Serialization; -using JMS.DVBVCR.RecordingService.Persistence; -using JMS.DVBVCR.RecordingService.WebServer; namespace JMS.DVBVCR.RecordingService.RestWebApi diff --git a/VCR.NET/ServiceCore/RestWebApi/InfoSchedule.cs b/VCR.NET/ServiceCore/RestWebApi/InfoSchedule.cs index 21acfdd..0d74173 100644 --- a/VCR.NET/ServiceCore/RestWebApi/InfoSchedule.cs +++ b/VCR.NET/ServiceCore/RestWebApi/InfoSchedule.cs @@ -1,8 +1,8 @@ -using System; +using JMS.DVBVCR.RecordingService.Persistence; +using JMS.DVBVCR.RecordingService.WebServer; +using System; using System.Globalization; using System.Runtime.Serialization; -using JMS.DVBVCR.RecordingService.Persistence; -using JMS.DVBVCR.RecordingService.WebServer; namespace JMS.DVBVCR.RecordingService.RestWebApi diff --git a/VCR.NET/ServiceCore/RestWebApi/JobScheduleData.cs b/VCR.NET/ServiceCore/RestWebApi/JobScheduleData.cs index fe39925..2f28ceb 100644 --- a/VCR.NET/ServiceCore/RestWebApi/JobScheduleData.cs +++ b/VCR.NET/ServiceCore/RestWebApi/JobScheduleData.cs @@ -1,7 +1,7 @@ -using System; -using System.Runtime.Serialization; -using JMS.DVBVCR.RecordingService.Persistence; +using JMS.DVBVCR.RecordingService.Persistence; using JMS.DVBVCR.RecordingService.ProgramGuide; +using System; +using System.Runtime.Serialization; namespace JMS.DVBVCR.RecordingService.RestWebApi diff --git a/VCR.NET/ServiceCore/RestWebApi/PlanActivity.cs b/VCR.NET/ServiceCore/RestWebApi/PlanActivity.cs index 7b461eb..e45bd92 100644 --- a/VCR.NET/ServiceCore/RestWebApi/PlanActivity.cs +++ b/VCR.NET/ServiceCore/RestWebApi/PlanActivity.cs @@ -1,12 +1,12 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Runtime.Serialization; -using JMS.DVB; +using JMS.DVB; using JMS.DVB.Algorithms.Scheduler; using JMS.DVBVCR.RecordingService.Persistence; using JMS.DVBVCR.RecordingService.Planning; using JMS.DVBVCR.RecordingService.WebServer; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Runtime.Serialization; namespace JMS.DVBVCR.RecordingService.RestWebApi @@ -258,10 +258,10 @@ public static PlanActivity Create( IScheduleInformation schedule, PlanContext co var end = time.End; var activity = new PlanActivity - { - IsHidden = (schedule.Resource == null), - IsLate = schedule.StartsLate, - }; + { + IsHidden = (schedule.Resource == null), + IsLate = schedule.StartsLate, + }; // May need some correction if (runningInfo != null) @@ -333,7 +333,7 @@ public static PlanActivity Create( IScheduleInformation schedule, PlanContext co } // Copy station name - if (source != null) + if (source?.Source != null) { // Remember activity.Source = SourceIdentifier.ToString( source.Source ).Replace( " ", "" ); diff --git a/VCR.NET/ServiceCore/RestWebApi/PlanController.cs b/VCR.NET/ServiceCore/RestWebApi/PlanController.cs index e36968d..ae9835c 100644 --- a/VCR.NET/ServiceCore/RestWebApi/PlanController.cs +++ b/VCR.NET/ServiceCore/RestWebApi/PlanController.cs @@ -23,13 +23,11 @@ public class PlanController : ApiController public PlanActivity[] GetPlan( string limit, string end ) { // Get the limit - int maximum; - if (!int.TryParse( limit, out maximum ) || (maximum <= 0)) + if (!int.TryParse(limit, out int maximum) || (maximum <= 0)) maximum = 1000; // Get the date - DateTime endTime; - if (!DateTime.TryParse( end, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out endTime )) + if (!DateTime.TryParse(end, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out DateTime endTime)) endTime = DateTime.MaxValue; // Route from Web AppDomain into service AppDomain @@ -52,8 +50,7 @@ public PlanActivity[] GetPlan( string limit, string end ) public PlanActivityMobile[] GetPlanMobile( string limit, string mobile ) { // Get the limit - int maximum; - if (!int.TryParse( limit, out maximum ) || (maximum <= 0)) + if (!int.TryParse(limit, out int maximum) || (maximum <= 0)) maximum = 1000; // Use helper diff --git a/VCR.NET/ServiceCore/RestWebApi/PlanCurrent.cs b/VCR.NET/ServiceCore/RestWebApi/PlanCurrent.cs index f12a819..78a8d3b 100644 --- a/VCR.NET/ServiceCore/RestWebApi/PlanCurrent.cs +++ b/VCR.NET/ServiceCore/RestWebApi/PlanCurrent.cs @@ -1,14 +1,14 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Runtime.Serialization; -using JMS.DVB; +using JMS.DVB; using JMS.DVB.Algorithms.Scheduler; using JMS.DVBVCR.RecordingService.Persistence; using JMS.DVBVCR.RecordingService.Planning; using JMS.DVBVCR.RecordingService.Status; using JMS.DVBVCR.RecordingService.WebServer; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Runtime.Serialization; namespace JMS.DVBVCR.RecordingService.RestWebApi @@ -218,7 +218,7 @@ public static PlanCurrent[] Create( FullInfo active, VCRServer server ) { // Validate if (active == null) - throw new ArgumentNullException( "active" ); + throw new ArgumentNullException( nameof( active ) ); // Validate var recording = active.Recording; @@ -395,10 +395,6 @@ public static PlanCurrent Create( IScheduleInformation plan, PlanContext context /// /// Der Name des Geräteprofils. /// Die zugehörige Beschreibung. - public static PlanCurrent Create( string profileName ) - { - // Create - return new PlanCurrent { ProfileName = profileName, IsIdle = true }; - } + public static PlanCurrent Create( string profileName ) => new PlanCurrent { ProfileName = profileName, IsIdle = true }; } } diff --git a/VCR.NET/ServiceCore/RestWebApi/PlanException.cs b/VCR.NET/ServiceCore/RestWebApi/PlanException.cs index a17d5af..dd2d6fc 100644 --- a/VCR.NET/ServiceCore/RestWebApi/PlanException.cs +++ b/VCR.NET/ServiceCore/RestWebApi/PlanException.cs @@ -1,7 +1,7 @@ -using System; +using JMS.DVBVCR.RecordingService.Persistence; +using System; using System.Globalization; using System.Runtime.Serialization; -using JMS.DVBVCR.RecordingService.Persistence; namespace JMS.DVBVCR.RecordingService.RestWebApi @@ -106,9 +106,9 @@ public static PlanException Create( VCRScheduleException exception, VCRSchedule { // Validate if (exception == null) - throw new ArgumentNullException( "exception" ); + throw new ArgumentNullException( nameof( exception ) ); if (schedule == null) - throw new ArgumentNullException( "schedule" ); + throw new ArgumentNullException( nameof( schedule ) ); // Forward return new PlanException( exception, schedule ); diff --git a/VCR.NET/ServiceCore/RestWebApi/ProfileController.cs b/VCR.NET/ServiceCore/RestWebApi/ProfileController.cs index 6909045..dfe5a2a 100644 --- a/VCR.NET/ServiceCore/RestWebApi/ProfileController.cs +++ b/VCR.NET/ServiceCore/RestWebApi/ProfileController.cs @@ -1,9 +1,9 @@ -using System; +using JMS.DVB; +using JMS.DVBVCR.RecordingService.WebServer; +using System; using System.Globalization; using System.Linq; using System.Web.Http; -using JMS.DVB; -using JMS.DVBVCR.RecordingService.WebServer; namespace JMS.DVBVCR.RecordingService.RestWebApi @@ -36,11 +36,7 @@ public ProfileInfo[] ListProfiles() /// Der Name des zu verwendenden Geräteprofils. /// Die gewünschte Liste von Sendern. [HttpGet] - public ProfileSource[] FindSources( string detail ) - { - // Forward to other application domain - return ServerRuntime.VCRServer.GetSources( detail, true, true, ProfileSource.Create ); - } + public ProfileSource[] FindSources( string detail ) => ServerRuntime.VCRServer.GetSources( detail, true, true, ProfileSource.Create ); /// /// Verändert den Endzeitpunkt. @@ -57,7 +53,7 @@ public void SetNewEndTime( string detail, bool disableHibernate, string schedule var end = DateTime.Parse( endTime, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind ); // Forward - ServerRuntime.VCRServer.ChangeRecordingStreamEndTime( detail, scheduleIdentifier, end, disableHibernate ); + ServerRuntime.VCRServer.ChangeRecordingStreamEndTime( detail, scheduleIdentifier, end, disableHibernate ); } /// diff --git a/VCR.NET/ServiceCore/RestWebApi/ProfileInfo.cs b/VCR.NET/ServiceCore/RestWebApi/ProfileInfo.cs index bd94734..bfff7b7 100644 --- a/VCR.NET/ServiceCore/RestWebApi/ProfileInfo.cs +++ b/VCR.NET/ServiceCore/RestWebApi/ProfileInfo.cs @@ -26,7 +26,7 @@ public static ProfileInfo Create( ProfileState profile ) { // Validate if (profile == null) - throw new ArgumentNullException( "profile" ); + throw new ArgumentNullException( nameof( profile ) ); // Create return new ProfileInfo { Name = profile.ProfileName }; diff --git a/VCR.NET/ServiceCore/RestWebApi/ProfileJobInfo.cs b/VCR.NET/ServiceCore/RestWebApi/ProfileJobInfo.cs index 12d56e9..e12c401 100644 --- a/VCR.NET/ServiceCore/RestWebApi/ProfileJobInfo.cs +++ b/VCR.NET/ServiceCore/RestWebApi/ProfileJobInfo.cs @@ -1,6 +1,6 @@ -using System; +using JMS.DVBVCR.RecordingService.Persistence; +using System; using System.Runtime.Serialization; -using JMS.DVBVCR.RecordingService.Persistence; namespace JMS.DVBVCR.RecordingService.RestWebApi diff --git a/VCR.NET/ServiceCore/RestWebApi/ProfileSource.cs b/VCR.NET/ServiceCore/RestWebApi/ProfileSource.cs index 2840508..40e0994 100644 --- a/VCR.NET/ServiceCore/RestWebApi/ProfileSource.cs +++ b/VCR.NET/ServiceCore/RestWebApi/ProfileSource.cs @@ -1,6 +1,6 @@ -using System; +using JMS.DVB; +using System; using System.Runtime.Serialization; -using JMS.DVB; namespace JMS.DVBVCR.RecordingService.RestWebApi @@ -22,10 +22,6 @@ public class ProfileSource : SourceInformation /// Führt individuelle Initialisierungen aus. /// /// Die Informationen zur Quelle. - protected override void OnCreate( Station station ) - { - // If it's not definitly a radio station we guess it's television - IsTVStation = (station.SourceType != SourceTypes.Radio); - } + protected override void OnCreate( Station station ) => IsTVStation = (station.SourceType != SourceTypes.Radio); } } diff --git a/VCR.NET/ServiceCore/RestWebApi/ProtocolController.cs b/VCR.NET/ServiceCore/RestWebApi/ProtocolController.cs index 34647c9..0ea1942 100644 --- a/VCR.NET/ServiceCore/RestWebApi/ProtocolController.cs +++ b/VCR.NET/ServiceCore/RestWebApi/ProtocolController.cs @@ -1,7 +1,7 @@ -using System; +using JMS.DVBVCR.RecordingService.WebServer; +using System; using System.Globalization; using System.Web.Http; -using JMS.DVBVCR.RecordingService.WebServer; namespace JMS.DVBVCR.RecordingService.RestWebApi diff --git a/VCR.NET/ServiceCore/RestWebApi/ProtocolEntry.cs b/VCR.NET/ServiceCore/RestWebApi/ProtocolEntry.cs index 7172553..cab536a 100644 --- a/VCR.NET/ServiceCore/RestWebApi/ProtocolEntry.cs +++ b/VCR.NET/ServiceCore/RestWebApi/ProtocolEntry.cs @@ -1,9 +1,9 @@ -using System; +using JMS.DVBVCR.RecordingService.Persistence; +using System; using System.Globalization; using System.IO; using System.Linq; using System.Runtime.Serialization; -using JMS.DVBVCR.RecordingService.Persistence; namespace JMS.DVBVCR.RecordingService.RestWebApi diff --git a/VCR.NET/ServiceCore/RestWebApi/SourceInformation.cs b/VCR.NET/ServiceCore/RestWebApi/SourceInformation.cs index 5c0693b..81d7643 100644 --- a/VCR.NET/ServiceCore/RestWebApi/SourceInformation.cs +++ b/VCR.NET/ServiceCore/RestWebApi/SourceInformation.cs @@ -1,6 +1,6 @@ -using System; +using JMS.DVB; +using System; using System.Runtime.Serialization; -using JMS.DVB; namespace JMS.DVBVCR.RecordingService.RestWebApi diff --git a/VCR.NET/ServiceCore/RestWebApi/UserProfile.cs b/VCR.NET/ServiceCore/RestWebApi/UserProfile.cs index 1fc86cb..543a111 100644 --- a/VCR.NET/ServiceCore/RestWebApi/UserProfile.cs +++ b/VCR.NET/ServiceCore/RestWebApi/UserProfile.cs @@ -1,7 +1,6 @@ -using System.Linq; +using JMS.DVBVCR.RecordingService.WebServer; +using System.Linq; using System.Runtime.Serialization; -using System.Web; -using JMS.DVBVCR.RecordingService.WebServer; namespace JMS.DVBVCR.RecordingService.RestWebApi diff --git a/VCR.NET/ServiceCore/RestWebApi/UserProfileController.cs b/VCR.NET/ServiceCore/RestWebApi/UserProfileController.cs index f919122..9cafc1b 100644 --- a/VCR.NET/ServiceCore/RestWebApi/UserProfileController.cs +++ b/VCR.NET/ServiceCore/RestWebApi/UserProfileController.cs @@ -1,5 +1,5 @@ -using System.Web.Http; -using JMS.DVBVCR.RecordingService.WebServer; +using JMS.DVBVCR.RecordingService.WebServer; +using System.Web.Http; namespace JMS.DVBVCR.RecordingService.RestWebApi @@ -14,11 +14,7 @@ public class UserProfileController : ApiController /// /// Die Einstellungen des Anwenders. [HttpGet] - public UserProfile GetCurrentProfile() - { - // Report - return UserProfile.Create(); - } + public UserProfile GetCurrentProfile() => UserProfile.Create(); /// /// Aktualisiert die Daten des Geräteprofils. diff --git a/VCR.NET/ServiceCore/RestWebApi/ZappingController.cs b/VCR.NET/ServiceCore/RestWebApi/ZappingController.cs index b7a97da..5404bce 100644 --- a/VCR.NET/ServiceCore/RestWebApi/ZappingController.cs +++ b/VCR.NET/ServiceCore/RestWebApi/ZappingController.cs @@ -1,6 +1,6 @@ -using System.Web.Http; -using JMS.DVB; +using JMS.DVB; using JMS.DVBVCR.RecordingService.WebServer; +using System.Web.Http; namespace JMS.DVBVCR.RecordingService.RestWebApi @@ -17,11 +17,7 @@ public class ZappingController : ApiController /// Der Name des zu verwendenden Geräteprofils. /// Der Zustand auf dem gewählten Geräteprofil. [HttpGet] - public ZappingStatus GetCurrentStatus( string detail ) - { - // Process - return ServerRuntime.VCRServer.LiveModeOperation( detail, true, null, null, ZappingStatus.Create ); - } + public ZappingStatus GetCurrentStatus( string detail ) => ServerRuntime.VCRServer.LiveModeOperation( detail, true, null, null, ZappingStatus.Create ); /// /// Ermittelt alle verfügbaren Sender. @@ -31,11 +27,7 @@ public ZappingStatus GetCurrentStatus( string detail ) /// Gesetzt, wenn Radiosender berücksichtigt werden sollen. /// Die gewünschte Liste von Sendern. [HttpGet] - public ZappingSource[] FindSources( string detail, bool tv, bool radio ) - { - // Forward to other application domain - return ServerRuntime.VCRServer.GetSources( detail, tv, radio, ZappingSource.Create ); - } + public ZappingSource[] FindSources( string detail, bool tv, bool radio ) => ServerRuntime.VCRServer.GetSources( detail, tv, radio, ZappingSource.Create ); /// /// Aktiviert eine neue Sitzung. @@ -44,11 +36,7 @@ public ZappingSource[] FindSources( string detail, bool tv, bool radio ) /// Legt fest, wohin die Nutzdaten zu senden sind. /// Der Zustand auf dem gewählten Geräteprofil. [HttpPost] - public ZappingStatus Connect( string detail, string target ) - { - // Process - return ServerRuntime.VCRServer.LiveModeOperation( detail, true, target, null, ZappingStatus.Create ); - } + public ZappingStatus Connect( string detail, string target ) => ServerRuntime.VCRServer.LiveModeOperation( detail, true, target, null, ZappingStatus.Create ); /// /// Deaktiviert eine Sitzung. @@ -56,11 +44,7 @@ public ZappingStatus Connect( string detail, string target ) /// Der Name des zu verwendenden Geräteprofils. /// Der Zustand auf dem gewählten Geräteprofil. [HttpDelete] - public ZappingStatus Disconnect( string detail ) - { - // Process - return ServerRuntime.VCRServer.LiveModeOperation( detail, false, null, null, ZappingStatus.Create ); - } + public ZappingStatus Disconnect( string detail ) => ServerRuntime.VCRServer.LiveModeOperation( detail, false, null, null, ZappingStatus.Create ); /// /// Wählt einen Quelle aus. @@ -69,10 +53,6 @@ public ZappingStatus Disconnect( string detail ) /// Die gewünschte Quelle als Tripel analog zur Textdarstellung von . /// Der Zustand auf dem gewählten Geräteprofil. [HttpPut] - public ZappingStatus Tune( string detail, string source ) - { - // Process - return ServerRuntime.VCRServer.LiveModeOperation( detail, true, null, SourceIdentifier.Parse( source ), ZappingStatus.Create ); - } + public ZappingStatus Tune( string detail, string source ) => ServerRuntime.VCRServer.LiveModeOperation( detail, true, null, SourceIdentifier.Parse( source ), ZappingStatus.Create ); } } diff --git a/VCR.NET/ServiceCore/RestWebApi/ZappingService.cs b/VCR.NET/ServiceCore/RestWebApi/ZappingService.cs index 8fa0ea5..baa6ec4 100644 --- a/VCR.NET/ServiceCore/RestWebApi/ZappingService.cs +++ b/VCR.NET/ServiceCore/RestWebApi/ZappingService.cs @@ -1,7 +1,7 @@ -using System; -using System.Runtime.Serialization; -using JMS.DVB; +using JMS.DVB; using JMS.DVB.CardServer; +using System; +using System.Runtime.Serialization; namespace JMS.DVBVCR.RecordingService.RestWebApi @@ -47,10 +47,9 @@ private static int GetServiceIndex( string uniqueName ) return -1; // Get the part - uint result; - if (uint.TryParse( uniqueName.Substring( 0, i ), out result )) + if (uint.TryParse(uniqueName.Substring(0, i), out uint result)) if (result < int.MaxValue) - return (int) result; + return (int)result; else return -1; else @@ -66,7 +65,7 @@ public static ZappingService Create( ServiceInformation service ) { // Validate if (service == null) - throw new ArgumentNullException( "service" ); + throw new ArgumentNullException( nameof( service ) ); // Create new return diff --git a/VCR.NET/ServiceCore/RestWebApi/ZappingSource.cs b/VCR.NET/ServiceCore/RestWebApi/ZappingSource.cs index 5bd0e2c..df24280 100644 --- a/VCR.NET/ServiceCore/RestWebApi/ZappingSource.cs +++ b/VCR.NET/ServiceCore/RestWebApi/ZappingSource.cs @@ -1,6 +1,6 @@ -using System; +using JMS.DVB; +using System; using System.Runtime.Serialization; -using JMS.DVB; namespace JMS.DVBVCR.RecordingService.RestWebApi @@ -22,10 +22,6 @@ public class ZappingSource : SourceInformation /// Führt individuelle Initialisierungen aus. /// /// Die Informationen zur Quelle. - protected override void OnCreate( Station station ) - { - // Finish - Source = SourceIdentifier.ToString( station ).Replace( " ", "" ); - } + protected override void OnCreate( Station station ) => Source = SourceIdentifier.ToString( station ).Replace( " ", "" ); } } diff --git a/VCR.NET/ServiceCore/RestWebApi/ZappingStatus.cs b/VCR.NET/ServiceCore/RestWebApi/ZappingStatus.cs index 591b4c9..508317b 100644 --- a/VCR.NET/ServiceCore/RestWebApi/ZappingStatus.cs +++ b/VCR.NET/ServiceCore/RestWebApi/ZappingStatus.cs @@ -1,8 +1,8 @@ -using System; +using JMS.DVB; +using JMS.DVB.CardServer; +using System; using System.Linq; using System.Runtime.Serialization; -using JMS.DVB; -using JMS.DVB.CardServer; namespace JMS.DVBVCR.RecordingService.RestWebApi diff --git a/VCR.NET/ServiceCore/ServiceCore.csproj b/VCR.NET/ServiceCore/ServiceCore.csproj index b81d049..4fed2e9 100644 --- a/VCR.NET/ServiceCore/ServiceCore.csproj +++ b/VCR.NET/ServiceCore/ServiceCore.csproj @@ -112,9 +112,9 @@ True ..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - - False - ..\packages\Newtonsoft.Json.6.0.7\lib\net45\Newtonsoft.Json.dll + + ..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll + True @@ -127,45 +127,54 @@ True - + + ..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll False - ..\packages\Microsoft.AspNet.WebApi.Client.5.2.2\lib\net45\System.Net.Http.Formatting.dll + True + ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll False - ..\packages\Microsoft.AspNet.WebPages.3.2.2\lib\net45\System.Web.Helpers.dll + True - + + ..\packages\Microsoft.AspNet.WebApi.Core.5.2.3\lib\net45\System.Web.Http.dll False - ..\packages\Microsoft.AspNet.WebApi.Core.5.2.2\lib\net45\System.Web.Http.dll + True - + + ..\packages\Microsoft.AspNet.WebApi.WebHost.5.2.3\lib\net45\System.Web.Http.WebHost.dll False - ..\packages\Microsoft.AspNet.WebApi.WebHost.5.2.2\lib\net45\System.Web.Http.WebHost.dll + True - + + ..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll False - ..\packages\Microsoft.AspNet.Mvc.5.2.2\lib\net45\System.Web.Mvc.dll + True + ..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll False - ..\packages\Microsoft.AspNet.Razor.3.2.2\lib\net45\System.Web.Razor.dll + True + ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll False - ..\packages\Microsoft.AspNet.WebPages.3.2.2\lib\net45\System.Web.WebPages.dll + True + ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll False - ..\packages\Microsoft.AspNet.WebPages.3.2.2\lib\net45\System.Web.WebPages.Deployment.dll + True + ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll False - ..\packages\Microsoft.AspNet.WebPages.3.2.2\lib\net45\System.Web.WebPages.Razor.dll + True diff --git a/VCR.NET/ServiceCore/Tools.cs b/VCR.NET/ServiceCore/Tools.cs index a48da26..9def5dc 100644 --- a/VCR.NET/ServiceCore/Tools.cs +++ b/VCR.NET/ServiceCore/Tools.cs @@ -273,9 +273,8 @@ static public void CreateDir( string fullPath ) return null; // To to convert - DateTime result; - if (DateTime.TryParseExact( value, "u", null, DateTimeStyles.None, out result )) - return DateTime.SpecifyKind( result, DateTimeKind.Utc ); + if (DateTime.TryParseExact(value, "u", null, DateTimeStyles.None, out DateTime result)) + return DateTime.SpecifyKind(result, DateTimeKind.Utc); } catch { @@ -368,9 +367,8 @@ public static IEnumerable GetHourList( string hours ) yield break; // Process all - uint hour; - foreach (var hourAsString in hours.Split( ',' )) - if (uint.TryParse( hourAsString.Trim(), out hour )) + foreach (var hourAsString in hours.Split(',')) + if (uint.TryParse(hourAsString.Trim(), out uint hour)) if ((hour >= 0) && (hour <= 23)) yield return hour; } diff --git a/VCR.NET/ServiceCore/VCRConfiguration.cs b/VCR.NET/ServiceCore/VCRConfiguration.cs index 250755b..53e4b1a 100644 --- a/VCR.NET/ServiceCore/VCRConfiguration.cs +++ b/VCR.NET/ServiceCore/VCRConfiguration.cs @@ -26,7 +26,7 @@ public abstract class SettingDescription : MarshalByRefObject, ICloneable /// /// Meldet den Namen der Einstellung. /// - public SettingNames Name { get; private set; } + public SettingNames Name { get; } /// /// Ein eventuell veränderter Wert. @@ -37,7 +37,7 @@ public abstract class SettingDescription : MarshalByRefObject, ICloneable /// Erzeugt eine neue Beschreibung. /// /// Der Name der Beschreibung. - internal SettingDescription( SettingNames name ) + internal SettingDescription(SettingNames name) { // Remember Name = name; @@ -47,61 +47,41 @@ internal SettingDescription( SettingNames name ) /// Liest den Namen der Einstellung. /// /// Der Wert der Einstellung als Zeichenkette. - public virtual object ReadValue() - { - // Forward - return GetCurrentValue(); - } + public virtual object ReadValue() => GetCurrentValue(); /// /// Liest den Namen der Einstellung. /// /// Der Wert der Einstellung als Zeichenkette. - public string GetCurrentValue() - { - // Report - return (string) ReadRawValue( Tools.ApplicationConfiguration ); - } + public string GetCurrentValue() => (string)ReadRawValue(Tools.ApplicationConfiguration); /// /// Liest den Namen der Einstellung. /// /// Die zu verwendende Konfiguration. /// Der Wert der Einstellung als Zeichenkette. - private object ReadRawValue( Configuration configuration ) - { - // Load the setting - KeyValueConfigurationElement setting = configuration.AppSettings.Settings[Name.ToString()]; - - // Not found - if (null == setting) - return null; - else if (null == setting.Value) - return null; - else - return setting.Value.Trim(); - } + private object ReadRawValue(Configuration configuration) => configuration.AppSettings.Settings[Name.ToString()]?.Value?.Trim(); /// /// Aktualisiert einen Konfigurationswert. /// /// /// - internal bool Update( Configuration newConfiguration ) + internal bool Update(Configuration newConfiguration) { // Corret - string newValue = string.IsNullOrEmpty( NewValue ) ? string.Empty : NewValue.Trim(); + var newValue = string.IsNullOrEmpty(NewValue) ? string.Empty : NewValue.Trim(); // Not changed - if (Equals( newValue, ReadRawValue( newConfiguration ) )) + if (Equals(newValue, ReadRawValue(newConfiguration))) return false; // Load the setting - KeyValueConfigurationElement setting = newConfiguration.AppSettings.Settings[Name.ToString()]; + var setting = newConfiguration.AppSettings.Settings[Name.ToString()]; // Ups, missing - if (null == setting) - newConfiguration.AppSettings.Settings.Add( Name.ToString(), newValue ); + if (setting == null) + newConfiguration.AppSettings.Settings.Add(Name.ToString(), newValue); else setting.Value = newValue; @@ -121,21 +101,13 @@ internal bool Update( Configuration newConfiguration ) /// Erzeugt eine Kopie des Eintrags. /// /// Die gewünschte Kopie. - public SettingDescription Clone() - { - // Forward - return CreateClone(); - } + public SettingDescription Clone() => CreateClone(); /// /// Erzeugt eine Kopie des Eintrags. /// /// Die gewünschte Kopie. - object ICloneable.Clone() - { - // Forward - return Clone(); - } + object ICloneable.Clone() => Clone(); #endregion } @@ -143,18 +115,18 @@ object ICloneable.Clone() /// /// Beschreibt eine Einstellung und deren Wert. /// - /// Der Datentyp des Wertes. - public class SettingDescription : SettingDescription + /// Der Datentyp des Wertes. + public class SettingDescription : SettingDescription { /// /// Liest oder setzt den Wert. /// - public T Value { get; set; } + public TValueType Value { get; set; } /// /// Der zu verwendende Wert, wenn die Einstellung nicht gefunden wurde. /// - private T m_Default; + private TValueType m_Default; /// /// Erzeugt eine neue Beschreibung. @@ -162,8 +134,8 @@ public class SettingDescription : SettingDescription /// Der Name der Beschreibung. /// Ein Wert für den Fall, dass der gewünschte Konfigurationswert /// nicht belegt ist. - internal SettingDescription( SettingNames name, T defaultValue ) - : base( name ) + internal SettingDescription(SettingNames name, TValueType defaultValue) + : base(name) { // Remember m_Default = defaultValue; @@ -173,21 +145,13 @@ internal SettingDescription( SettingNames name, T defaultValue ) /// Erzeugt eine Kopie des Eintrags. /// /// Die gewünschte Kopie. - protected override SettingDescription CreateClone() - { - // Process - return new SettingDescription( Name, m_Default ); - } + protected override SettingDescription CreateClone() => new SettingDescription(Name, m_Default); /// /// Erzeugt eine Kopie des Eintrags. /// /// Die gewünschte Kopie. - public new SettingDescription Clone() - { - // Forward - return (SettingDescription) CreateClone(); - } + public new SettingDescription Clone() => (SettingDescription)CreateClone(); /// /// Liest den Namen der Einstellung. @@ -196,30 +160,30 @@ protected override SettingDescription CreateClone() public override object ReadValue() { // Load as string - string setting = (string) base.ReadValue(); + var setting = (string)base.ReadValue(); // None - if (string.IsNullOrEmpty( setting )) + if (string.IsNullOrEmpty(setting)) return m_Default; // Try to convert try { // Type to use for parsing - var resultType = typeof( T ); + var resultType = typeof(TValueType); // Check mode - if (resultType == typeof( string )) - return (T) (object) setting; + if (resultType == typeof(string)) + return (TValueType)(object)setting; // See if type is nullable - resultType = Nullable.GetUnderlyingType( resultType ) ?? resultType; + resultType = Nullable.GetUnderlyingType(resultType) ?? resultType; // Forward if (resultType.IsEnum) - return (T) Enum.Parse( resultType, setting ); + return (TValueType)Enum.Parse(resultType, setting); else - return (T) resultType.InvokeMember( "Parse", BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod, null, null, new object[] { setting } ); + return (TValueType)resultType.InvokeMember("Parse", BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod, null, null, new object[] { setting }); } catch { @@ -245,41 +209,41 @@ public override object ReadValue() static VCRConfiguration() { // Remember all - Add( SettingNames.FileNamePattern, "%Job% - %Schedule% - %Start%" ); - Add( SettingNames.SuppressDelayAfterForcedHibernation, false ); - Add( SettingNames.DelayAfterForcedHibernation, (uint) 5 ); - Add( SettingNames.VideoRecorderDirectory, "Recordings" ); - Add( SettingNames.DisablePCRFromMPEG2Generation, false ); - Add( SettingNames.DisablePCRFromH264Generation, false ); - Add( SettingNames.UseStandByForHibernation, false ); - Add( SettingNames.LoggingLevel, LoggingLevel.Full ); - Add( SettingNames.ScanJoinThreshold, (uint?) null ); - Add( SettingNames.EPGJoinThreshold, (uint?) null ); - Add( SettingNames.UseExternalCardServer, true ); - Add( SettingNames.HibernationDelay, (uint) 60 ); - Add( SettingNames.EPGInterval, (uint?) null ); - Add( SettingNames.MayHibernateSystem, false ); - Add( SettingNames.ArchiveLifeTime, (uint) 5 ); - Add( SettingNames.EPGIncludeFreeSat, false ); - Add( SettingNames.AdditionalRecorderPaths ); - Add( SettingNames.ScanDuration, (uint) 60 ); - Add( SettingNames.EPGDuration, (uint) 15 ); - Add( SettingNames.TCPPort, (ushort) 2909 ); - Add( SettingNames.SSLPort, (ushort) 3909 ); - Add( SettingNames.LogLifeTime, (uint) 5 ); - Add( SettingNames.MergeScanResult, true ); - Add( SettingNames.TSAudioBufferSize, 0 ); - Add( SettingNames.TSSDTVBufferSize, 0 ); - Add( SettingNames.TSHDTVBufferSize, 0 ); - Add( SettingNames.AllowBasic, false ); - Add( SettingNames.RequiredAdminRole ); - Add( SettingNames.RequiredUserRole ); - Add( SettingNames.ScanInterval, 0 ); - Add( SettingNames.UseSSL, false ); - Add( SettingNames.EPGStations ); - Add( SettingNames.ScanHours ); - Add( SettingNames.Profiles ); - Add( SettingNames.EPGHours ); + Add(SettingNames.FileNamePattern, "%Job% - %Schedule% - %Start%"); + Add(SettingNames.SuppressDelayAfterForcedHibernation, false); + Add(SettingNames.DelayAfterForcedHibernation, (uint)5); + Add(SettingNames.VideoRecorderDirectory, "Recordings"); + Add(SettingNames.DisablePCRFromMPEG2Generation, false); + Add(SettingNames.DisablePCRFromH264Generation, false); + Add(SettingNames.UseStandByForHibernation, false); + Add(SettingNames.LoggingLevel, LoggingLevel.Full); + Add(SettingNames.ScanJoinThreshold, (uint?)null); + Add(SettingNames.EPGJoinThreshold, (uint?)null); + Add(SettingNames.UseExternalCardServer, true); + Add(SettingNames.HibernationDelay, (uint)60); + Add(SettingNames.EPGInterval, (uint?)null); + Add(SettingNames.MayHibernateSystem, false); + Add(SettingNames.ArchiveLifeTime, (uint)5); + Add(SettingNames.EPGIncludeFreeSat, false); + Add(SettingNames.AdditionalRecorderPaths); + Add(SettingNames.ScanDuration, (uint)60); + Add(SettingNames.EPGDuration, (uint)15); + Add(SettingNames.TCPPort, (ushort)2909); + Add(SettingNames.SSLPort, (ushort)3909); + Add(SettingNames.LogLifeTime, (uint)5); + Add(SettingNames.MergeScanResult, true); + Add(SettingNames.TSAudioBufferSize, 0); + Add(SettingNames.TSSDTVBufferSize, 0); + Add(SettingNames.TSHDTVBufferSize, 0); + Add(SettingNames.AllowBasic, false); + Add(SettingNames.RequiredAdminRole); + Add(SettingNames.RequiredUserRole); + Add(SettingNames.ScanInterval, 0); + Add(SettingNames.UseSSL, false); + Add(SettingNames.EPGStations); + Add(SettingNames.ScanHours); + Add(SettingNames.Profiles); + Add(SettingNames.EPGHours); // Set restart items m_Restart[SettingNames.AllowBasic] = true; @@ -292,34 +256,26 @@ static VCRConfiguration() /// /// Aktiviert eine Konfiguration in der aktuellen . /// - public static void Startup() - { - // Process - Register( new VCRConfiguration() ); - } + public static void Startup() => Register(new VCRConfiguration()); /// /// Instanzen dieser Klasse sind nicht zeitgebunden. /// /// Die Antwort muss immer null sein. - public override object InitializeLifetimeService() - { - // No lease at all - return null; - } + public override object InitializeLifetimeService() => null; /// /// Bereitet eine Aktualisierung vor. /// /// Die zu aktualisierenden Einträge. /// Alle gewünschten Einträge. - public Dictionary BeginUpdate( params SettingNames[] names ) + public Dictionary BeginUpdate(params SettingNames[] names) { // Create empty - if (null == names) + if (names == null) return new Dictionary(); else - return names.ToDictionary( n => n, n => m_Settings[n].Clone() ); + return names.ToDictionary(n => n, n => m_Settings[n].Clone()); } /// @@ -327,27 +283,27 @@ public Dictionary BeginUpdate( params SettingN /// /// Die eventuell veränderten Einstellungen. /// Gesetzt, wenn ein Neustart erforderlich war. - internal bool CommitUpdate( IEnumerable settings ) + internal bool CommitUpdate(IEnumerable settings) { // Validate - if (null == settings) + if (settings == null) return false; // Clone the current configuration - var newConfiguration = ConfigurationManager.OpenExeConfiguration( Tools.ExecutablePath ); + var newConfiguration = ConfigurationManager.OpenExeConfiguration(Tools.ExecutablePath); // See if we changed at all bool changed = false, restart = false; // Process all foreach (var setting in settings) - if (setting.Update( newConfiguration )) + if (setting.Update(newConfiguration)) { // Remember changed = true; // See if this requires a restart - if (m_Restart.ContainsKey( setting.Name )) + if (m_Restart.ContainsKey(setting.Name)) restart = true; } @@ -359,16 +315,16 @@ internal bool CommitUpdate( IEnumerable settings ) string origName = Tools.ExecutablePath + ".config", tempName = origName + ".new"; // Write back to primary - newConfiguration.SaveAs( tempName ); + newConfiguration.SaveAs(tempName); // Be safe try { // Try to overwrite - File.Copy( tempName, origName, true ); + File.Copy(tempName, origName, true); // Write back to backup for upgrade installation - File.Copy( tempName, origName + ".cpy", true ); + File.Copy(tempName, origName + ".cpy", true); // Force reload if (!restart) @@ -380,7 +336,7 @@ internal bool CommitUpdate( IEnumerable settings ) finally { // Cleanup - File.Delete( tempName ); + File.Delete(tempName); } } @@ -388,12 +344,12 @@ internal bool CommitUpdate( IEnumerable settings ) /// Aktiviert eine bestimmte Konfiguration in der aktuellen . /// /// Die gewünschte Konfiguration. - internal static void Register( VCRConfiguration configuration ) + internal static void Register(VCRConfiguration configuration) { // Validate - if (null == configuration) - throw new ArgumentNullException( "configuration" ); - if (null != Current) + if (configuration == null) + throw new ArgumentNullException("configuration"); + if (Current != null) throw new InvalidOperationException(); // Remember @@ -406,51 +362,39 @@ internal static void Register( VCRConfiguration configuration ) private VCRConfiguration() { // Report - Tools.ExtendedLogging( "New Configuration Instance Created" ); + Tools.ExtendedLogging("New Configuration Instance Created"); } /// /// Vermerkt eine Einstellung. /// /// Der Name der Einstellung. - private static void Add( SettingNames name ) - { - // Forward - Add( name, (string) null ); - } + private static void Add(SettingNames name) => Add(name, (string)null); /// /// Vermerkt eine Einstellung. /// - /// Der Datentyp des zugehörigen Wertes. + /// Der Datentyp des zugehörigen Wertes. /// Der Name der Einstellung. /// Der voreingestellt Wert. - private static void Add( SettingNames name, T defaultValue ) - { - // Create new - m_Settings[name] = new SettingDescription( name, defaultValue ); - } + private static void Add(SettingNames name, TValueType defaultValue) => m_Settings[name] = new SettingDescription(name, defaultValue); /// /// Ermittelt eine einzelne Einstellung. /// /// Name der Einstellung. /// Wert der Einstellung. - private static object ReadSetting( SettingNames name ) + private static object ReadSetting(SettingNames name) { // Find and forward - SettingDescription settings; - if (m_Settings.TryGetValue( name, out settings )) - return settings.ReadValue(); - else - return null; + return m_Settings.TryGetValue(name, out SettingDescription settings) ? settings.ReadValue() : null; } /// /// Meldet den Namen der Kontogruppe der Anwender, die Zugriff auf den /// VCR.NET Recording Service haben. /// - public string UserRole { get { return (string) ReadSetting( SettingNames.RequiredUserRole ); } } + public string UserRole => (string)ReadSetting(SettingNames.RequiredUserRole); /// /// Meldet oder legt fest, ob bereits einmal eine Aufzeichnung ausgeführt wurde. @@ -466,13 +410,13 @@ private static object ReadSetting( SettingNames name ) /// Meldet den Namen der Kontogruppe der Anwender, die administrativen Zugriff auf den /// VCR.NET Recording Service haben. /// - public string AdminRole { get { return (string) ReadSetting( SettingNames.RequiredAdminRole ); } } + public string AdminRole => (string)ReadSetting(SettingNames.RequiredAdminRole); /// /// Meldet, ob der Schlafzustand S3 (Standby) anstelle von S4 (Hibernate) /// verwenden soll. /// - public bool UseS3ForHibernate { get { return (bool) ReadSetting( SettingNames.UseStandByForHibernation ); } } + public bool UseS3ForHibernate => (bool)ReadSetting(SettingNames.UseStandByForHibernation); /// /// Meldet die Größe für die Zwischenspeicherung bei Radioaufnahmen. @@ -482,11 +426,11 @@ public int? AudioBufferSize get { // Process - var buffer = (int) ReadSetting( SettingNames.TSAudioBufferSize ); + var buffer = (int)ReadSetting(SettingNames.TSAudioBufferSize); if (buffer < 1) return null; else - return Math.Max( 1000, buffer ); + return Math.Max(1000, buffer); } } @@ -498,11 +442,11 @@ public int? StandardVideoBufferSize get { // Process - var buffer = (int) ReadSetting( SettingNames.TSSDTVBufferSize ); + var buffer = (int)ReadSetting(SettingNames.TSSDTVBufferSize); if (buffer < 1) return null; else - return Math.Max( 1000, buffer ); + return Math.Max(1000, buffer); } } @@ -514,11 +458,11 @@ public int? HighDefinitionVideoBufferSize get { // Process - var buffer = (int) ReadSetting( SettingNames.TSHDTVBufferSize ); + var buffer = (int)ReadSetting(SettingNames.TSHDTVBufferSize); if (buffer < 1) return null; else - return Math.Max( 1000, buffer ); + return Math.Max(1000, buffer); } } @@ -526,46 +470,46 @@ public int? HighDefinitionVideoBufferSize /// Meldet, ob der VCR.NET Recording Service den Rechner in einen Schlafzustand /// versetzten darf. /// - public bool MayHibernateSystem { get { return (bool) ReadSetting( SettingNames.MayHibernateSystem ); } } + public bool MayHibernateSystem => (bool)ReadSetting(SettingNames.MayHibernateSystem); /// /// Meldet die geschätzte Zeit, die dieses System maximal braucht, um aus dem /// Schlafzustand zu erwachen. /// - public uint HibernationDelay { get { return (uint) ReadSetting( SettingNames.HibernationDelay ); } } + public uint HibernationDelay => (uint)ReadSetting(SettingNames.HibernationDelay); /// /// Meldet, ob der Card Server als eigenständiger Prozess gestartet werden soll. /// - public bool UseExternalCardServer { get { return (bool) ReadSetting( SettingNames.UseExternalCardServer ); } } + public bool UseExternalCardServer => (bool)ReadSetting(SettingNames.UseExternalCardServer); /// /// Gesetzt wenn es nicht gestattet ist, aus einem H.264 Bildsignal die Zeitbasis (PCR) /// abzuleiten. /// - public bool DisablePCRFromH264Generation { get { return (bool) ReadSetting( SettingNames.DisablePCRFromH264Generation ); } } + public bool DisablePCRFromH264Generation => (bool)ReadSetting(SettingNames.DisablePCRFromH264Generation); /// /// Gesetzt wenn es nicht gestattet ist, aus einem MPEG2 Bildsignal die Zeitbasis (PCR) /// abzuleiten. /// - public bool DisablePCRFromMPEG2Generation { get { return (bool) ReadSetting( SettingNames.DisablePCRFromMPEG2Generation ); } } + public bool DisablePCRFromMPEG2Generation => (bool)ReadSetting(SettingNames.DisablePCRFromMPEG2Generation); /// /// Meldet, ob die Programmzeitschrift der englischen FreeSat Sender eingeschlossen /// werden soll. /// - public bool EnableFreeSat { get { return (bool) ReadSetting( SettingNames.EPGIncludeFreeSat ); } } + public bool EnableFreeSat => (bool)ReadSetting(SettingNames.EPGIncludeFreeSat); /// /// Die Liste der Quellen, die in der Programmzeitschrift berücksichtigt werden sollen. /// - public string ProgramGuideSourcesRaw { get { return (string) ReadSetting( SettingNames.EPGStations ); } } + public string ProgramGuideSourcesRaw => (string)ReadSetting(SettingNames.EPGStations); /// /// Meldet alle Quellen, für die Daten gesammelt werden sollen. /// - public string[] ProgramGuideSourcesAsArray { get { return ProgramGuideSources.ToArray(); } } + public string[] ProgramGuideSourcesAsArray => ProgramGuideSources.ToArray(); /// /// Meldet alle Quellen, für die Daten gesammelt werden sollen. @@ -576,15 +520,15 @@ public IEnumerable ProgramGuideSources { // Load from settings var sources = ProgramGuideSourcesRaw; - if (string.IsNullOrEmpty( sources )) + if (string.IsNullOrEmpty(sources)) yield break; // Process all - foreach (var source in sources.Split( ',' )) + foreach (var source in sources.Split(',')) { // Cleanup var trimmed = source.Trim(); - if (!string.IsNullOrEmpty( trimmed )) + if (!string.IsNullOrEmpty(trimmed)) yield return trimmed; } } @@ -604,7 +548,7 @@ public bool ProgramGuideUpdateEnabled return false; else if (ProgramGuideUpdateHours.Any()) return true; - else if (ProgramGuideUpdateInterval.GetValueOrDefault( TimeSpan.Zero ).TotalDays > 0) + else if (ProgramGuideUpdateInterval.GetValueOrDefault(TimeSpan.Zero).TotalDays > 0) return true; else return false; @@ -614,17 +558,17 @@ public bool ProgramGuideUpdateEnabled /// /// Meldet alle vollen Stunden, zu denen eine Sammlung stattfinden soll. /// - public uint[] ProgramGuideUpdateHours { get { return Tools.GetHourList( ProgramGuideUpdateHoursRaw ).ToArray(); } } + public uint[] ProgramGuideUpdateHours => Tools.GetHourList(ProgramGuideUpdateHoursRaw).ToArray(); /// /// Meldet alle vollen Stunden, zu denen eine Sammlung stattfinden soll. /// - public uint[] ProgramGuideUpdateHoursAsArray { get { return ProgramGuideUpdateHours.ToArray(); } } + public uint[] ProgramGuideUpdateHoursAsArray => ProgramGuideUpdateHours.ToArray(); /// /// Meldet die maximale Laufzeit einer Aktualisierung gemäß der Konfiguration. /// - public uint ProgramGuideUpdateDuration { get { return (uint) ReadSetting( SettingNames.EPGDuration ); } } + public uint ProgramGuideUpdateDuration => (uint)ReadSetting(SettingNames.EPGDuration); /// /// Meldet die minimale Zeitspanne zwischen zwei Aktualisierungen der Programmzeitschrift. @@ -634,9 +578,9 @@ public TimeSpan? ProgramGuideUpdateInterval get { // Load - var interval = (uint?) ReadSetting( SettingNames.EPGInterval ); + var interval = (uint?)ReadSetting(SettingNames.EPGInterval); if (interval.HasValue) - return TimeSpan.FromHours( interval.Value ); + return TimeSpan.FromHours(interval.Value); else return null; } @@ -651,9 +595,9 @@ public TimeSpan? ProgramGuideJoinThreshold get { // Load - var interval = (uint?) ReadSetting( SettingNames.EPGJoinThreshold ); + var interval = (uint?)ReadSetting(SettingNames.EPGJoinThreshold); if (interval.HasValue) - return TimeSpan.FromHours( interval.Value ); + return TimeSpan.FromHours(interval.Value); else return null; } @@ -668,9 +612,9 @@ public TimeSpan? SourceListJoinThreshold get { // Load - var interval = (uint?) ReadSetting( SettingNames.ScanJoinThreshold ); + var interval = (uint?)ReadSetting(SettingNames.ScanJoinThreshold); if (interval.HasValue) - return TimeSpan.FromDays( interval.Value ); + return TimeSpan.FromDays(interval.Value); else return null; } @@ -679,116 +623,116 @@ public TimeSpan? SourceListJoinThreshold /// /// Meldet die maximale Laufzeit für die Aktualisierung der Quellen eines Geräteprofils. /// - public uint SourceListUpdateDuration { get { return (uint) ReadSetting( SettingNames.ScanDuration ); } } + public uint SourceListUpdateDuration => (uint)ReadSetting(SettingNames.ScanDuration); /// /// Meldet, wieviele Tage mindestens zwischen zwei Aktualisierungen der Liste /// der Quellen eines Geräteprofils liegen müssen. /// - public int SourceListUpdateInterval { get { return (int) ReadSetting( SettingNames.ScanInterval ); } } + public int SourceListUpdateInterval => (int)ReadSetting(SettingNames.ScanInterval); /// /// Meldet, ob nach Abschluss der Aktualisierung die Listen der Quellen zusammengeführt /// werden sollen. /// - public bool MergeSourceListUpdateResult { get { return (bool) ReadSetting( SettingNames.MergeScanResult ); } } + public bool MergeSourceListUpdateResult => (bool)ReadSetting(SettingNames.MergeScanResult); /// /// Meldet die Liste der Stunden, an denen eine Aktualisierung einer /// Liste von Quellen stattfinden darf. /// - public string SourceListUpdateHoursRaw { get { return (string) ReadSetting( SettingNames.ScanHours ); } } + public string SourceListUpdateHoursRaw => (string)ReadSetting(SettingNames.ScanHours); /// /// Meldet alle vollen Stunden, zu denen eine Sammlung stattfinden soll. /// - public uint[] SourceListUpdateHours { get { return Tools.GetHourList( SourceListUpdateHoursRaw ).ToArray(); } } + public uint[] SourceListUpdateHours => Tools.GetHourList(SourceListUpdateHoursRaw).ToArray(); /// /// Meldet alle vollen Stunden, zu denen eine Sammlung stattfinden soll. /// - public uint[] SourceListUpdateHoursAsArray { get { return SourceListUpdateHours.ToArray(); } } + public uint[] SourceListUpdateHoursAsArray => SourceListUpdateHours.ToArray(); /// /// Meldet die Liste der Stunden, an denen eine Aktualisierung einer /// Programmzeitschrift stattfinden darf. /// - public string ProgramGuideUpdateHoursRaw { get { return (string) ReadSetting( SettingNames.EPGHours ); } } + public string ProgramGuideUpdateHoursRaw => (string)ReadSetting(SettingNames.EPGHours); /// /// Meldet die Zeit in Wochen, die ein Protokolleintrag vorgehalten wird. /// - public uint LogLifeTime { get { return (uint) ReadSetting( SettingNames.LogLifeTime ); } } + public uint LogLifeTime { get { return (uint)ReadSetting(SettingNames.LogLifeTime); } } /// /// Meldet die maximale Verweildauer eines archivierten Auftrags im Archiv, bevor /// er gelöscht wird. /// - public uint ArchiveLifeTime { get { return (uint) ReadSetting( SettingNames.ArchiveLifeTime ); } } + public uint ArchiveLifeTime => (uint)ReadSetting(SettingNames.ArchiveLifeTime); /// /// Meldet die Zeit die nach einem erzwungenen Schlafzustand verstreichen muss, bevor der /// Rechner für eine Aufzeichnung aufgweckt wird. /// - public uint RawDelayAfterForcedHibernation { get { return (uint) ReadSetting( SettingNames.DelayAfterForcedHibernation ); } } + public uint RawDelayAfterForcedHibernation => (uint)ReadSetting(SettingNames.DelayAfterForcedHibernation); /// /// Meldet die Zeit die nach einem erzwungenen Schlafzustand verstreichen muss, bevor der /// Rechner für eine Aufzeichnung aufgweckt wird. /// - public TimeSpan DelayAfterForcedHibernation { get { return TimeSpan.FromMinutes( Math.Max( 1, RawDelayAfterForcedHibernation ) ); } } + public TimeSpan DelayAfterForcedHibernation => TimeSpan.FromMinutes(Math.Max(1, RawDelayAfterForcedHibernation)); /// /// Gesetzt, wenn beim Schlafzustand keine Sonderbehandlung erwünscht ist. /// - public bool SuppressDelayAfterForcedHibernation { get { return (bool) ReadSetting( SettingNames.SuppressDelayAfterForcedHibernation ); } } + public bool SuppressDelayAfterForcedHibernation => (bool)ReadSetting(SettingNames.SuppressDelayAfterForcedHibernation); /// /// Meldet den aktuellen Umfang der Protokollierung. /// - public LoggingLevel LoggingLevel { get { return (LoggingLevel) ReadSetting( SettingNames.LoggingLevel ); } } + public LoggingLevel LoggingLevel => (LoggingLevel)ReadSetting(SettingNames.LoggingLevel); /// /// Meldet den TCP/IP Port, an den der Web Server gebunden werden soll. /// - public ushort WebServerTcpPort { get { return (ushort) ReadSetting( SettingNames.TCPPort ); } } + public ushort WebServerTcpPort => (ushort)ReadSetting(SettingNames.TCPPort); /// /// Meldet den TCP/IP Port, an den der Web Server bei einer sichen Verbindung gebunden werden soll. /// - public ushort WebServerSecureTcpPort { get { return (ushort) ReadSetting( SettingNames.SSLPort ); } } + public ushort WebServerSecureTcpPort => (ushort)ReadSetting(SettingNames.SSLPort); /// /// Gesetzt, wenn die Verbindung zu den Web Diensten verschlüsselt werden soll. /// - public bool EncryptWebCommunication { get { return (bool) ReadSetting( SettingNames.UseSSL ); } } + public bool EncryptWebCommunication => (bool)ReadSetting(SettingNames.UseSSL); /// /// Gesetzt, wenn die Anwender sich auch über das Basic Prototokoll /// autorisieren dürfen. /// - public bool EnableBasicAuthentication { get { return (bool) ReadSetting( SettingNames.AllowBasic ); } } + public bool EnableBasicAuthentication => (bool)ReadSetting(SettingNames.AllowBasic); /// /// Ermittelt das Ersetzungsmuster für Dateinamen. /// - public string FileNamePattern { get { return (string) ReadSetting( SettingNames.FileNamePattern ); } } + public string FileNamePattern => (string)ReadSetting(SettingNames.FileNamePattern); /// /// Ermittelt den Namen des primären Aufzeichnungsverzeichnisses /// - public string PrimaryRecordingDirectory { get { return (string) ReadSetting( SettingNames.VideoRecorderDirectory ); } } + public string PrimaryRecordingDirectory => (string)ReadSetting(SettingNames.VideoRecorderDirectory); /// /// Meldet die zusätzlichen Aufzeichnungsverzeichnisse. /// - public string AlternateRecordingDirectories { get { return (string) ReadSetting( SettingNames.AdditionalRecorderPaths ); } } + public string AlternateRecordingDirectories => (string)ReadSetting(SettingNames.AdditionalRecorderPaths); /// /// Meldet die Namen der DVB.NET Geräteprofile, die der VCR.NET Recording Service /// verwenden darf. /// - public string ProfileNames { get { return (string) ReadSetting( SettingNames.Profiles ); } } + public string ProfileNames => (string)ReadSetting(SettingNames.Profiles); /// /// Meldet das primäre Aufzeichnungsverzeichnis. @@ -798,22 +742,22 @@ public DirectoryInfo PrimaryTargetDirectory get { // Get the path - var path = Path.Combine( Tools.ApplicationDirectory.Parent.FullName, PrimaryRecordingDirectory ); + var path = Path.Combine(Tools.ApplicationDirectory.Parent.FullName, PrimaryRecordingDirectory); // Extend it - if (!string.IsNullOrEmpty( path )) + if (!string.IsNullOrEmpty(path)) if (path[path.Length - 1] != Path.DirectorySeparatorChar) path += Path.DirectorySeparatorChar; // Create - return new DirectoryInfo( path ); + return new DirectoryInfo(path); } } /// /// Meldet alle erlaubten Aufzeichnungsverzeichnisse. /// - public string[] TargetDirectoriesNames { get { return TargetDirectories.Select( d => d.FullName ).ToArray(); } } + public string[] TargetDirectoriesNames => TargetDirectories.Select(d => d.FullName).ToArray(); /// /// Meldet alle erlaubten Aufzeichnungsverzeichnisse. @@ -829,14 +773,14 @@ public IEnumerable TargetDirectories var dirs = AlternateRecordingDirectories; // Process - if (!string.IsNullOrEmpty( dirs )) - foreach (var dir in dirs.Split( ',' )) + if (!string.IsNullOrEmpty(dirs)) + foreach (var dir in dirs.Split(',')) { // Load the path string path = dir.Trim(); // Skip - if (string.IsNullOrEmpty( path )) + if (string.IsNullOrEmpty(path)) continue; // Extend it @@ -850,12 +794,12 @@ public IEnumerable TargetDirectories try { // Load - info = new DirectoryInfo( path ); + info = new DirectoryInfo(path); } catch (Exception e) { // Report as error - VCRServer.Log( e ); + VCRServer.Log(e); // Just ignore continue; @@ -872,21 +816,21 @@ public IEnumerable TargetDirectories /// /// Der zu prüfende Dateipfad. /// Gesetzt, wenn der Pfad gültig ist. - public bool IsValidTarget( string path ) + public bool IsValidTarget(string path) { // Must habe a path - if (string.IsNullOrEmpty( path )) + if (string.IsNullOrEmpty(path)) return false; // Test it foreach (var allowed in TargetDirectories) - if (path.StartsWith( allowed.FullName, StringComparison.InvariantCultureIgnoreCase )) + if (path.StartsWith(allowed.FullName, StringComparison.InvariantCultureIgnoreCase)) { // Silent create the directory try { // Create the directory - Directory.CreateDirectory( Path.GetDirectoryName( path ) ); + Directory.CreateDirectory(Path.GetDirectoryName(path)); // Yeah return true; @@ -894,7 +838,7 @@ public bool IsValidTarget( string path ) catch (Exception e) { // Report - VCRServer.Log( e ); + VCRServer.Log(e); // Done return false; diff --git a/VCR.NET/ServiceCore/VCRProfiles.cs b/VCR.NET/ServiceCore/VCRProfiles.cs index 91d5fc2..7591b12 100644 --- a/VCR.NET/ServiceCore/VCRProfiles.cs +++ b/VCR.NET/ServiceCore/VCRProfiles.cs @@ -114,7 +114,7 @@ internal static void Reset() sourcesByIdentifier[source.Source] = source; // Correct back the name - source.DisplayName = ((Station) source.Source).FullName; + source.DisplayName = ((Station)source.Source).FullName; } } @@ -129,7 +129,7 @@ internal static void Reset() if (!source.Key.Equals( source.Value.DisplayName )) { // Unmap the station - var station = (Station) source.Value.Source; + var station = (Station)source.Value.Source; // Enter special notation profileMap[$"{station.Name} {station.ToStringKey()} [{station.Provider}]"] = source.Value; @@ -183,13 +183,11 @@ public static SourceSelection FindSource( string profileName, string name ) profileName = state.Profiles[0].Name; // Map to use - Dictionary sources; - if (!state.SourceBySelectionMap.TryGetValue( profileName, out sources )) + if (!state.SourceBySelectionMap.TryGetValue(profileName, out Dictionary sources)) return null; // Ask map - SourceSelection source; - if (!sources.TryGetValue( name, out source )) + if (!sources.TryGetValue(name, out SourceSelection source)) return null; // Report @@ -217,13 +215,11 @@ public static SourceSelection FindSource( string profileName, SourceIdentifier s profileName = state.Profiles[0].Name; // Find the map - Dictionary map; - if (!state.SourceByIdentifierMap.TryGetValue( profileName, out map )) + if (!state.SourceByIdentifierMap.TryGetValue(profileName, out Dictionary map)) return null; // Find the source - SourceSelection found; - if (!map.TryGetValue( source, out found )) + if (!map.TryGetValue(source, out SourceSelection found)) return null; else return found; @@ -251,22 +247,14 @@ public static SourceSelection FindSource( SourceSelection source ) /// /// Der Name des Geräteprofils. /// Alle Quellen zum Profil. - public static IEnumerable GetSources( string profileName ) - { - // Forward - return GetSources( profileName, (Func) null ); - } + public static IEnumerable GetSources( string profileName ) => GetSources( profileName, (Func)null ); /// /// Ermittelt alle Quellen zu einem DVB.NET Geräteprofil. /// /// Der Name des Geräteprofils. /// Alle Quellen zum Profil. - public static IEnumerable GetSources( Profile profile ) - { - // Forward - return GetSources( profile, (Func) null ); - } + public static IEnumerable GetSources( Profile profile ) => GetSources( profile, (Func)null ); /// /// Ermittelt alle Quellen zu einem DVB.NET Geräteprofil. @@ -274,11 +262,7 @@ public static IEnumerable GetSources( Profile profile ) /// Der Name des Geräteprofils. /// Methode, die prüft, ob eine Quelle gemeldet werden soll. /// Alle Quellen zum Profil. - public static IEnumerable GetSources( string profileName, Func predicate ) - { - // Forward - return GetSources( FindProfile( profileName ), predicate ); - } + public static IEnumerable GetSources( string profileName, Func predicate ) => GetSources( FindProfile( profileName ), predicate ); /// /// Ermittelt alle Quellen zu einem DVB.NET Geräteprofil. @@ -289,10 +273,10 @@ public static IEnumerable GetSources( string profileName, Func< public static IEnumerable GetSources( string profileName, Func predicate ) { // Forward - if (null == predicate) + if (predicate == null) return GetSources( FindProfile( profileName ) ); else - return GetSources( FindProfile( profileName ), s => predicate( (Station) s.Source ) ); + return GetSources( FindProfile( profileName ), s => predicate( (Station)s.Source ) ); } /// @@ -304,12 +288,11 @@ public static IEnumerable GetSources( string profileName, Func< public static IEnumerable GetSources( Profile profile, Func predicate ) { // Resolve - if (null == profile) + if (profile == null) yield break; // Load the map - Dictionary map; - if (!CurrentState.SourceByIdentifierMap.TryGetValue( profile.Name, out map )) + if (!CurrentState.SourceByIdentifierMap.TryGetValue(profile.Name, out Dictionary map)) yield break; // Use state @@ -331,8 +314,7 @@ public static Profile FindProfile( string name ) return DefaultProfile; // Read out - Profile profile; - return CurrentState.ProfileMap.TryGetValue( name, out profile ) ? profile : null; + return CurrentState.ProfileMap.TryGetValue(name, out Profile profile) ? profile : null; } /// @@ -354,8 +336,7 @@ public static string GetUniqueName( SourceSelection source ) return null; // Find the name - string name; - if (!CurrentState.UniqueNameBySelectionMap.TryGetValue( active.SelectionKey, out name )) + if (!CurrentState.UniqueNameBySelectionMap.TryGetValue(active.SelectionKey, out string name)) return null; // Report it diff --git a/VCR.NET/ServiceCore/VCRServer/VCRServer.cs b/VCR.NET/ServiceCore/VCRServer/VCRServer.cs index a93470f..42f3881 100644 --- a/VCR.NET/ServiceCore/VCRServer/VCRServer.cs +++ b/VCR.NET/ServiceCore/VCRServer/VCRServer.cs @@ -20,12 +20,12 @@ public partial class VCRServer : MarshalByRefObject, IDisposable /// /// Wird beim Bauen automatisch eingemischt. /// - private const string CURRENTDATE = "2015/12/25"; + private const string CURRENTDATE = "2019/11/17"; /// /// Aktuelle Version des VCR.NET Recording Service. /// - public const string CurrentVersion = "4.3 [" + CURRENTDATE + "]"; + public const string CurrentVersion = "4.5 [" + CURRENTDATE + "]"; /// /// Konfigurationseintrag in der Registrierung von Windows. diff --git a/VCR.NET/ServiceCore/VCRServer/VCRServer_Hibernate.cs b/VCR.NET/ServiceCore/VCRServer/VCRServer_Hibernate.cs index d03c0c6..f6dde56 100644 --- a/VCR.NET/ServiceCore/VCRServer/VCRServer_Hibernate.cs +++ b/VCR.NET/ServiceCore/VCRServer/VCRServer_Hibernate.cs @@ -18,7 +18,7 @@ partial class VCRServer /// /// Allgemeine Sperre zum Zugriff auf veränderliche globale Eigenschaften. /// - private object m_HibernateSync = new object(); + private readonly object m_HibernateSync = new object(); /// /// Gesetzt, wenn beim Übergang in den Schlafzustand auf interaktive Anwender geprüft werden soll. diff --git a/VCR.NET/ServiceCore/VCRServer/VCRServer_Recording.cs b/VCR.NET/ServiceCore/VCRServer/VCRServer_Recording.cs index 36f1c40..8b33fae 100644 --- a/VCR.NET/ServiceCore/VCRServer/VCRServer_Recording.cs +++ b/VCR.NET/ServiceCore/VCRServer/VCRServer_Recording.cs @@ -49,7 +49,12 @@ public void ForceSoureListUpdate() /// Die eindeutige Kennung des zu verwendenden Datenstroms. /// Der neue Endzeitpunkt. /// Gesetzt, wenn der Übergang in den Schlafzustand deaktiviert werden soll. - public void ChangeRecordingStreamEndTime( string profile, Guid streamIdentifier, DateTime newEndTime, bool disableHibernation ) => FindProfile( profile )?.ChangeStreamEnd( streamIdentifier, newEndTime, disableHibernation ); + public void ChangeRecordingStreamEndTime( string profile, Guid streamIdentifier, DateTime newEndTime, bool disableHibernation ) => FindProfile( profile )?.ChangeStreamEnd( streamIdentifier, newEndTime, disableHibernation && (NumberOfActiveRecordings == 1) ); + + /// + /// Meldet die Anzahl der aktiven Aufzeichnungen. + /// + public int NumberOfActiveRecordings => Profiles.NumberOfActiveRecordings; /// /// Aktiviert oder deaktiviert den Netzwerkversand für eine Quelle. diff --git a/VCR.NET/ServiceCore/VCRServer/VCRServer_Rest.cs b/VCR.NET/ServiceCore/VCRServer/VCRServer_Rest.cs index 7fd77af..0d1997a 100644 --- a/VCR.NET/ServiceCore/VCRServer/VCRServer_Rest.cs +++ b/VCR.NET/ServiceCore/VCRServer/VCRServer_Rest.cs @@ -80,15 +80,7 @@ public TTarget FindProgramGuideEntry( string profileName, SourceIdentif /// Die Quelle, deren Eintrag ermittelt werden soll. /// Der exakte Startzeitpunkt. /// Der gewünschte Eintrag. - public ProgramGuideEntry FindProgramGuideEntry( string profileName, SourceIdentifier source, DateTime start ) - { - // See if profile exists - var profile = Profiles[profileName]; - if (profile == null) - return null; - else - return profile.ProgramGuide.FindEntry( source, start ); - } + public ProgramGuideEntry FindProgramGuideEntry( string profileName, SourceIdentifier source, DateTime start ) => Profiles[profileName]?.ProgramGuide.FindEntry( source, start ); /// /// Verändert eine Ausnahme. diff --git a/VCR.NET/ServiceCore/WebServer/ApplicationEndPoint.cs b/VCR.NET/ServiceCore/WebServer/ApplicationEndPoint.cs index 2bc694f..4ace114 100644 --- a/VCR.NET/ServiceCore/WebServer/ApplicationEndPoint.cs +++ b/VCR.NET/ServiceCore/WebServer/ApplicationEndPoint.cs @@ -27,12 +27,12 @@ public abstract class ApplicationEndPoint : IDisposable where TRun /// /// Die Anzahl der gestarteten aber noch nicht zu Ende durchgeführten Operationen. /// - private int m_Threads = 0; + private int m_Threads; /// /// Die ASP.NET Laufzeitumgebung. /// - private TRuntimeType m_runtime = null; + private TRuntimeType m_runtime; /// /// Synchronisiert den Zugriff auf die Laufzeitumgebung. diff --git a/VCR.NET/ServiceCore/WebServer/ContextAccessor.cs b/VCR.NET/ServiceCore/WebServer/ContextAccessor.cs index 0272c79..6bfd681 100644 --- a/VCR.NET/ServiceCore/WebServer/ContextAccessor.cs +++ b/VCR.NET/ServiceCore/WebServer/ContextAccessor.cs @@ -235,8 +235,7 @@ public IntPtr UserToken var domain = (parts.Length == 2) ? parts[0] : "."; // Try to logon - IntPtr handle; - if (!LogonUser( name, domain, basicIdentity.Password, 3, 0, out handle )) + if (!LogonUser(name, domain, basicIdentity.Password, 3, 0, out IntPtr handle)) { // Set result var response = Context.Response; diff --git a/VCR.NET/ServiceCore/WebServer/ServerRuntime.cs b/VCR.NET/ServiceCore/WebServer/ServerRuntime.cs index 5c2e9a5..6507d21 100644 --- a/VCR.NET/ServiceCore/WebServer/ServerRuntime.cs +++ b/VCR.NET/ServiceCore/WebServer/ServerRuntime.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Diagnostics; -using System.Security.Principal; using System.Web; @@ -247,7 +246,7 @@ public static string GetUniqueWebId( VCRJob job, VCRSchedule schedule ) if (job == null) return "*"; else if (schedule == null) - return string.Format( "*{0:N}", job.UniqueID.Value ); + return $"*{job.UniqueID.Value:N}"; else return GetUniqueWebId( job.UniqueID.Value, schedule.UniqueID.Value ); } @@ -268,7 +267,7 @@ public static string GetUniqueWebId( string job, string schedule ) schedule = Guid.Empty.ToString( "N" ); // Create - return string.Format( "{0}{1}", job, schedule ); + return $"{job}{schedule}"; } /// @@ -301,9 +300,7 @@ public static void ParseUniqueWebId( string id, out Guid job, out Guid schedule /// Die zugehörige Aufzeichnung im Auftrag. public static VCRSchedule ParseUniqueWebId( string id, out VCRJob job ) { - // Read all - Guid jobID, scheduleID; - ParseUniqueWebId( id, out jobID, out scheduleID ); + ParseUniqueWebId( id, out Guid jobID, out Guid scheduleID ); // Find the job job = VCRServer.FindJob( jobID ); diff --git a/VCR.NET/ServiceCore/WebServer/StarterModule.cs b/VCR.NET/ServiceCore/WebServer/StarterModule.cs index 651d2d5..c04f839 100644 --- a/VCR.NET/ServiceCore/WebServer/StarterModule.cs +++ b/VCR.NET/ServiceCore/WebServer/StarterModule.cs @@ -22,8 +22,8 @@ public class StarterModule : IHttpModule /// Alle Dateiendungen, für die wir ETags erzeugen. /// private static readonly HashSet _ETagExtensions = - new HashSet( StringComparer.InvariantCultureIgnoreCase ) - { + new HashSet( StringComparer.InvariantCultureIgnoreCase ) + { ".html", ".css", ".js", @@ -93,7 +93,7 @@ private static void OnBeginRequest( object sender, EventArgs e ) // Check out context var context = HttpContext.Current; - var worker = ((IServiceProvider) context).GetService( typeof( HttpWorkerRequest ) ) as Request; + var worker = ((IServiceProvider)context).GetService( typeof( HttpWorkerRequest ) ) as Request; if (worker == null) return; @@ -138,7 +138,7 @@ private static void OnEndRequest( object sender, EventArgs e ) return; // Check our context - var worker = ((IServiceProvider) context).GetService( typeof( HttpWorkerRequest ) ) as Request; + var worker = ((IServiceProvider)context).GetService( typeof( HttpWorkerRequest ) ) as Request; if (worker == null) return; @@ -178,7 +178,7 @@ private static string GetETag() // Convert var modifiedAsFileTime = lastModified.ToFileTime(); var nowAsFileTime = utcNow.ToFileTime(); - var etag = string.Format( "\"{0:X8}\"", modifiedAsFileTime ); + var etag = $"\"{modifiedAsFileTime:X8}\""; // Check mode if ((nowAsFileTime - modifiedAsFileTime) <= 30000000L) diff --git a/VCR.NET/ServiceCore/Win32Tools/LogonManager.cs b/VCR.NET/ServiceCore/Win32Tools/LogonManager.cs index 1863a2a..2dece9e 100644 --- a/VCR.NET/ServiceCore/Win32Tools/LogonManager.cs +++ b/VCR.NET/ServiceCore/Win32Tools/LogonManager.cs @@ -69,21 +69,18 @@ private static string ShellName get { // Try to open - 64 Bit first on 64 Bit OS - IntPtr key; - if (RegOpenKeyEx( LocalMachineKey, KeyName, 0, 0x20119, out key ) == 0) + if (RegOpenKeyEx(LocalMachineKey, KeyName, 0, 0x20119, out IntPtr key) == 0) try { - // Try to read the value - Int32 size, type; - if (RegQueryValueEx( key, ValueName, IntPtr.Zero, out type, null, out size ) == 0) + if (RegQueryValueEx(key, ValueName, IntPtr.Zero, out int type, null, out int size) == 0) if ((type == 1) || (type == 2)) if (size > 1) { // Allocate enough space - var buffer = new StringBuilder( size + 1 ); + var buffer = new StringBuilder(size + 1); // Read - if (RegQueryValueEx( key, ValueName, IntPtr.Zero, out type, buffer, out size ) == 0) + if (RegQueryValueEx(key, ValueName, IntPtr.Zero, out type, buffer, out size) == 0) { // Finish buffer buffer.Length = size - 1; @@ -96,7 +93,7 @@ private static string ShellName finally { // Free resources - RegCloseKey( key ); + RegCloseKey(key); } // Find the name of the shell diff --git a/VCR.NET/ServiceCore/packages.config b/VCR.NET/ServiceCore/packages.config index 2d0a340..6d69429 100644 --- a/VCR.NET/ServiceCore/packages.config +++ b/VCR.NET/ServiceCore/packages.config @@ -1,11 +1,11 @@  - - - - - - + + + + + + - + \ No newline at end of file diff --git a/VCR.NET/TVBrowserPlugIn/Properties/AssemblyInfo.cs b/VCR.NET/TVBrowserPlugIn/Properties/AssemblyInfo.cs index 2455163..5aea79a 100644 --- a/VCR.NET/TVBrowserPlugIn/Properties/AssemblyInfo.cs +++ b/VCR.NET/TVBrowserPlugIn/Properties/AssemblyInfo.cs @@ -29,4 +29,5 @@ // Build Number // Revision // -[assembly: AssemblyVersion( "4.3.0.0" )] +[assembly: AssemblyVersion( "4.5.0.0" )] +[assembly: AssemblyFileVersion("4.5.0.0")] diff --git a/VCR.NET/TVBrowserPlugIn/TVBrowserPlugIn.csproj b/VCR.NET/TVBrowserPlugIn/TVBrowserPlugIn.csproj index c712b2b..9e922d7 100644 --- a/VCR.NET/TVBrowserPlugIn/TVBrowserPlugIn.csproj +++ b/VCR.NET/TVBrowserPlugIn/TVBrowserPlugIn.csproj @@ -54,9 +54,9 @@ false - - False - ..\packages\Newtonsoft.Json.6.0.7\lib\net45\Newtonsoft.Json.dll + + ..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll + True diff --git a/VCR.NET/TVBrowserPlugIn/packages.config b/VCR.NET/TVBrowserPlugIn/packages.config index ba2b301..3e14be6 100644 --- a/VCR.NET/TVBrowserPlugIn/packages.config +++ b/VCR.NET/TVBrowserPlugIn/packages.config @@ -1,4 +1,4 @@  - + \ No newline at end of file diff --git a/VCR.NET/Unit Test Collection/CombinedSchedulerTests.cs b/VCR.NET/Unit Test Collection/CombinedSchedulerTests.cs index ef86b7f..df8d484 100644 --- a/VCR.NET/Unit Test Collection/CombinedSchedulerTests.cs +++ b/VCR.NET/Unit Test Collection/CombinedSchedulerTests.cs @@ -68,17 +68,13 @@ public CombinedSchedulerTests() // Create directory m_jobDirectory.Create(); - // Path of the scratch file - var zipPath = Path.Combine( m_jobDirectory.FullName, "temp.zip" ); - - // Copy our archive to the directory - File.WriteAllBytes( zipPath, Properties.Resources.TestJobs ); - // Extract [.NET 4.5] - //ZipFile.ExtractToDirectory( zipPath, m_jobDirectory.FullName ); - - // Forget it - File.Delete( zipPath ); + using (var zipStream = new MemoryStream( Properties.Resources.TestJobs )) + using (var zip = new ZipArchive( zipStream )) + foreach (var entry in zip.Entries) + using (var source = entry.Open()) + using (var target = new FileStream( Path.Combine( m_jobDirectory.FullName, entry.Name ), FileMode.CreateNew, FileAccess.Write, FileShare.None )) + source.CopyTo( target ); // Process all files m_jobs = @@ -174,7 +170,7 @@ public void FullValidation() // Create component under Test using (var cfg = TestConfigurationProvider.Create( Properties.Resources.AllSchedulers )) using (var cut = RecordingPlanner.Create( this )) - for (int i = 250; i-- > 0; ) + for (int i = 250; i-- > 0;) cut.DispatchNextActivity( m_planTime ); } diff --git a/VCR.NET/Unit Test Collection/Unit Test Collection.csproj b/VCR.NET/Unit Test Collection/Unit Test Collection.csproj index 93a2b92..c24a408 100644 --- a/VCR.NET/Unit Test Collection/Unit Test Collection.csproj +++ b/VCR.NET/Unit Test Collection/Unit Test Collection.csproj @@ -65,6 +65,7 @@ 3.5 + diff --git a/VCR.NET/Unit Test Collection/app.config b/VCR.NET/Unit Test Collection/app.config index 4429813..8460dd4 100644 --- a/VCR.NET/Unit Test Collection/app.config +++ b/VCR.NET/Unit Test Collection/app.config @@ -4,7 +4,7 @@ - + diff --git a/VCR.NET/VCR.NET.sln b/VCR.NET/VCR.NET.sln index 959a0e5..35cbfae 100644 --- a/VCR.NET/VCR.NET.sln +++ b/VCR.NET/VCR.NET.sln @@ -1,11 +1,12 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.21005.1 +# Visual Studio 15 +VisualStudioVersion = 15.0.28307.902 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{EFF4945E-6C0C-4179-97C8-6FF592789C19}" ProjectSection(SolutionItems) = preProject Local.testsettings = Local.testsettings + package.json = package.json TraceAndTestImpact.testsettings = TraceAndTestImpact.testsettings VCR.NET.vsmdi = VCR.NET.vsmdi EndProjectSection @@ -145,6 +146,9 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {6487A231-0153-4E1F-9080-DD46EC6452D0} + EndGlobalSection GlobalSection(TestCaseManagementSettings) = postSolution CategoryFile = VCR.NET.vsmdi EndGlobalSection diff --git a/VCR.NET/VCRNETSetup/Deutsch.wxl b/VCR.NET/VCRNETSetup/Deutsch.wxl index 226f831..d473933 100644 --- a/VCR.NET/VCRNETSetup/Deutsch.wxl +++ b/VCR.NET/VCRNETSetup/Deutsch.wxl @@ -2,7 +2,6 @@ VCR.NET Recording Service - Quellcode Der VCR.NET Recording Service setzt eine Installation des Microsoft .NET Frameworks in der Version 4.5.1 voraus. Vor der Installation muss die existierende Version des VCR.NET Recording Service deinstalliert werden. Zur Installation des VCR.NET Recording Service muss DVB.NET inklusive des Card Servers bereits installiert sein. Die aktuelle Version kann hier heruntergeladen werden: diff --git a/VCR.NET/VCRNETSetup/DirectoryTree.wxs b/VCR.NET/VCRNETSetup/DirectoryTree.wxs index ff7d44a..064d5fe 100644 --- a/VCR.NET/VCRNETSetup/DirectoryTree.wxs +++ b/VCR.NET/VCRNETSetup/DirectoryTree.wxs @@ -43,70 +43,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -119,17 +55,5 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/VCR.NET/VCRNETSetup/Product.wxs b/VCR.NET/VCRNETSetup/Product.wxs index 5e3577f..cc2e0ed 100644 --- a/VCR.NET/VCRNETSetup/Product.wxs +++ b/VCR.NET/VCRNETSetup/Product.wxs @@ -93,28 +93,6 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/VCR.NET/VCRNETSetup/VCRNETSetup.wixproj b/VCR.NET/VCRNETSetup/VCRNETSetup.wixproj index db82df3..d419f1a 100644 --- a/VCR.NET/VCRNETSetup/VCRNETSetup.wixproj +++ b/VCR.NET/VCRNETSetup/VCRNETSetup.wixproj @@ -22,7 +22,7 @@ _Extensions.wxs obj\$(Configuration)\_Extensions.wixobj ICE57;ICE43 - SETUPVERSION=4.3.45 + SETUPVERSION=4.5.14 ..\..\msi\ @@ -33,7 +33,7 @@ ICE57;ICE43 _Extensions.wxs obj\$(Configuration)\_Extensions.wixobj - SETUPVERSION=4.3.45 + SETUPVERSION=4.5.14 diff --git a/VCR.NET/WebClient41/FAQ/archive.html b/VCR.NET/WebClient41/FAQ/archive.html deleted file mode 100644 index 5b23222..0000000 --- a/VCR.NET/WebClient41/FAQ/archive.html +++ /dev/null @@ -1,57 +0,0 @@ - - - - [Fragment] - - -
-
- Jede Aufzeichnung hat einen Zeitpunkt, an dem ihre letzte Ausführung abgeschlossen - ist. Für einzelne Aufzeichnungen ist dies einfach die Summe aus dem programmierten - Startzeitpunkt und der Aufzeichnungsdauer. Für Serienaufzeichnungen - ist das etwas komplizierter, da hier auch die Ausnahmeregelungen berücksichtigt - werden, das Prinzip ist aber sehr ähnlich. -
-
- Der VCR.NET Recording Service betrachtet eine Aufzeichnung als abgeschlossen, wenn - der Zeitpunkt der letzten Ausführung vor der aktuellen Zeit liegt. Dies hat erst - einmal keine Konsequenzen für die Aufzeichnung. Besitzt allerdings ein Auftrag - nur abgeschlossene Aufzeichnungen, so wird auch dieser als abgeschlossen - betrachtet. Der Auftrag wird dann aus der Liste der vorhandenen Aufträge entfernt - und in das so genannte Archiv übernommen. Die Übertragung ins Archiv kann auch manuell über das - Löschen eines Auftrags oder der letzten Aufzeichnung eines Auftrags erfolgen. Die - Aufzeichnungen des Auftrags werden dann nicht weiter bei der Planung berücksichtigt. -
-
- Interessant ist nun, dass ein Auftrag aus dem Archiv jederzeit reaktiviert werden - kann. Ist er noch nicht abgeschlossen, so reicht das alleinige Öffnen und Speichern - um die zugehörigen Aufträge wieder in die Planung aufzunehmen. Damit bereits abgeschlossene - Aufträge wieder berücksichtigt werden können müssen natürlich die Aufzeichnungsdaten - wie etwa der Startzeitpunkt geeignet verändert werden. -
-
- Abhängig von der Konfiguration - werden die Aufträge im Archiv nach einer gewissen Zeit endgültig gelöscht - dies - ist durch manuelles Löschen auch jederzeit vorab möglich. Der VCR.NET Recording - Service führt diese Bereinigung allerdings nur durch, wenn der Anwender aktiv die - Liste der Aufträge - im Archiv aufruft. - Als Kriterium wird der Zeitpunkt verwendet, an dem ein - Auftrag in das Archiv übernommen wurde. -
-
- Unter gewissen Umständen werden Aufträge nicht sofort in das Archiv übertragen, - obwohl sie faktisch abgeschlossen sind. Das betrifft einfache Aufzeichnungen, die - während der Ausführung vorzeitig durch den Anwender abgebrochen - wurden. Sie wandern erst ins Archiv, wenn die programmierte Endzeit überschritten - wird - umgekehrt kann die Verlängerung einer laufenden Aufzeichnung auch dazu führen, - dass ein Auftrag im Archiv erscheint, obwohl eine zugehörige Aufzeichnung noch aktiv - ist. Bei Serienaufzeichnungen gibt es einen Sicherheitszeitraum von einem Tag, in - dem eine Aufzeichnung noch im aktiven Bereich verbleibt, obwohl der Tag der letzten - Ausführung bereits erreicht wurde. In keinem Fall sollten diese Verhaltensweise - zu Problemen beim Betrieb des VCR.NET Recording Service führen - maximal wird es - notwendig sein, einen Auftrag an zwei Stellen zu suchen. -
-
- - diff --git a/VCR.NET/WebClient41/FAQ/configuration.html b/VCR.NET/WebClient41/FAQ/configuration.html deleted file mode 100644 index cc7d1e5..0000000 --- a/VCR.NET/WebClient41/FAQ/configuration.html +++ /dev/null @@ -1,41 +0,0 @@ - - - - [Fragment] - - -
-
- Der VCR.NET Recording Service bietet auch zusätzliche Konfigurationsmöglichkeiten an, - die hier kurz vorgestellt werden sollen. -
-
- Nach der Installation darf jeder Benutzer nicht nur Aufzeichnungen programmieren - sondern auch sämtliche Konfigurationsoptionen nutzen. Mit Hilfe von Windows Benutzergruppen - ist es aber möglich festzulegen, - welche Anwender Aufzeichnungen programmieren dürfen und welchen Anwendern zusätzlich - die Konfiguration des VCR.NET Recording Service gestattet wird.
-
- Es empfiehlt sich unbedingt mindestens ein Verzeichnis zu bestimmen, - in dem die Aufzeichnungsdateien abgelegt werden - - nach der Installation wird ein Unterverzeichnis des Installationsverzeichnisses - verwendet, was fast immer unerwünscht ist. Es können mehrere Verzeichnisse angegeben - werden und mit der Auswahl eines Verzeichnisses werden auch alle Unterverzeichnisse - zur Ablage freigeschaltet. Wenn keine gesonderte Auswahl bei der Programmierung einer Aufzeichnung - erfolgt, so verwendet der VCR.NET Recording Service immer das erste angegebene Verzeichnis.
-
- Sind auf dem Rechner mehrere DVB Geräte vorhanden, so kann es dem VCR.NET Recording Service gestattet - werden, eine - beliebige Anzahl davon zu verwenden. Dazu werden die entsprechenden DVB.NET Geräteprofile - in einer Auswahlliste markiert und eines davon als Voreinstellung ausgezeichnet.
-
- Die Web Oberfläche des VCR.NET Recording Service ist üblicherweise über den Standard Web Server - Port 80 zu erreichen. Dieser kann an die eigenen Bedürfnissen angepasst werden- - man beachte allerdings, dass eine Umschaltung einen erneuten Aufruf des Browsers mit dem veränderten Port erforderlich macht.
-
- Zusätzlich ist es möglich, den Umfang der Protokollierung einzustellen, - die der VCR.NET Recording Service im Ereignisprokoll von Windows (Bereich Anwendung) vornimmt. -
-
- - diff --git a/VCR.NET/WebClient41/FAQ/controlcenter.html b/VCR.NET/WebClient41/FAQ/controlcenter.html deleted file mode 100644 index 31dd71b..0000000 --- a/VCR.NET/WebClient41/FAQ/controlcenter.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - [Fragment] - - -
-
- Der VCR.NET Recording Service ist ein völlig eigenständiger Windows Dienst, der - über seine Web Oberfläche vollständig bedient werden kann. Eine Installation bringt - aber auch zusätzlich eine kleine Anwendung mit, die VCR.NET Kontrollzentrum - genannt wird. Sie wird üblicherweise automatisch beim Anmelden eines Benutzers gestartet - und erscheint als kleines Kamerasymbol im System Tray von Windows. Normalerweise - ist das Kontrollzentrum mit dem lokalen VCR.NET Recording Service verbunden, allerdings - kann diese Konfiguration verändert und auch eine Verbindung mit einem Dienst auf - einem anderen Rechner hergestellt werden. Es ist sogar möglich, die Anwendung gleichzeitig - mit mehreren Rechner zu verbinden, auf denen ein VCR.NET Recording Service aktiv - ist - in diesem Fall erscheinen dann mehrere Kamerasymbole, deren Tooltips den zugehörigen - Rechner anzeigen.
-
- Schon das Kamerasymbol hat einen gewissen Nutzen für den Anwender: seine Hinterlegung - mit einer Farbe zeigt an, in welchem Zustand sich der zugehörige VCR.NET Recording - Service befindet. Eine rote Hinterlegung bedeutet, dass - keine Verbindung hergestellt werden konnte - bei einem lokalen VCR.NET Recording - Service kann es sein, dass der zugehörige Windows Dienst gerade nicht aktiv ist - und bei einem entfernten System kann es zusätzlich an der Konfiguration der Firewalls - liegen. Ist eine blaue Hinterlegung zu sehen, so führt - der VCR.NET Recording Service mindestens eine Aktivität - aus und es empfiehlt sich, den zugehörigen Rechner nicht neu zu starten oder in - den Schlafzustand zu versetzen. Das gilt auch für - eine gelbe Hinterlegung, bei der zwar kein DVB Gerät - in Benutzung ist, eine Aktivität aber kurz bevor steht. Im Normalzustand ist das - Kamerasymbol Grün hinterlegt und der VCR.NET Recording - Service wartet auf die nächste anstehende Aufzeichnung - fehlt die grüne Hinterlegung, - so ist der Aufzeichnungsplan leer.
-
- Hier nun einige weitere Funktionalitäten des Kontrollzentrums - in einigen Fällen - wird eine korrekte Konfiguration der Anwendung vorausgesetzt, auf die aber nicht - weiter eingegangen wird:
    -
  • Aufruf einiger ausgewählter Seiten der Web Oberfläche des zugehörigen VCR.NET Recording - Service.
  • -
  • Aktivierung des Live Modus auf einem gerade - nicht benutzten DVB Gerät - das macht nur bei lokal installiertem DVB.NET / VCR.NET Viewer Sinn.
  • -
  • Betrachten einer laufenden Aufzeichnung.
  • -
  • Unterstützung des Übergangs in den Schlafzustand.
  • -
-
-
- - diff --git a/VCR.NET/WebClient41/FAQ/currentstream.html b/VCR.NET/WebClient41/FAQ/currentstream.html deleted file mode 100644 index 0968234..0000000 --- a/VCR.NET/WebClient41/FAQ/currentstream.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - [Fragment] - - -
-
- Die Aktivitäten - auf einem DVB Gerät können in einem - gewissen Rahmen verändert werden. Handelt es sich um eine Sonderaufgabe - wie der Aktualisierung der Programmzeitschrift, so - ist das vorzeitige Beenden ebenso möglich wie eine Veränderung der Laufzeit. Grundsätzlich - wird allerdings empfohlen, Sonderaufgaben nicht in der konfigurierten Ausführung - zu behindern - maximal kann ein vorzeitiger Abbruch Sinn machen, wenn es äußere - Umstände erforderlich machen.
-
- Laufzeit verändern
-
- Interessanter ist es, wenn der der VCR.NET Recording Service eine DVB Hardware nutzt - um Aufzeichnungen auszuführen. Je nach konkreter Situation können dies auch mehrere Aufzeichnungen - sein, die parallel ausgeführt werden, wobei diese allerdings separat in der Aktivitätenliste aufgeführt werden. Hier - sind nun folgende Veränderungen möglich:
-
    -
  • Eine Aufzeichnung kann vorzeitig beendet werden.
  • -
  • Das Ende einer Aufzeichnung kann verschoben werden - eine Verkürzung ist nur soweit - möglich, dass der Endzeitpunkt immer noch in der Zukunft liegt.
  • -
- Es empfiehlt sich grundsätzlich, Manipulationen an laufenden Aufzeichnungen mit - Bedacht vorzunehmen. Bei Veränderungen des Endzeitpunktes kann es etwa dazu kommen, - dass die betroffenen Aufzeichnungen nicht mehr in der Aufzeichnungsplanung - erscheinen. -
-
- - diff --git a/VCR.NET/WebClient41/FAQ/customschedule.html b/VCR.NET/WebClient41/FAQ/customschedule.html deleted file mode 100644 index 7d5fe57..0000000 --- a/VCR.NET/WebClient41/FAQ/customschedule.html +++ /dev/null @@ -1,137 +0,0 @@ - - - - [Fragment] - - -
-
- Der VCR.NET Recording Service verwendet nach der Installation ein festes Regelwerk zur Planung von - Aufzeichnungen für den Fall, dass mehrere DVB.NET Geräteprofile verwendet werden. Über die - Konfiguration - kann dieses speziellen Bedürfnissen angepasst werden. -
-

- Für die Aufzeichnungsplanung ermittelt der VCR.NET Recording Service in einer - ersten Phase Zeitbereiche mit sich überlappenden Aufzeichnungen. Der Zeitraum - eines solchen Bereiches definiert sich durch den Startzeitpunkt der als erstes - beginnenden Aufzeichnung und dem Endzeitpunkt der als letztes endenden Aufzeichnung - darin. Zu jedem Zeitpunkt in einem Bereich ist mindestens eine Aufzeichnung aktiv. - Alle anderen Aufzeichnungen, die nicht im Bereich erfasst werden, beginnen entweder - frühestens am Endzeitpunkt oder enden spätestens am Startzeitpunkt. -

-

- Für jeden Bereich berechnet VCR.NET in der aktuellen Implementierung alle möglichen - Zuordnungen von Aufzeichnungen zu Geräten - dieses Vorgehen ist bei sehr vielen - insbesondere gleichartigen Geräten nicht sonderlich clever und wird sich in zukünftigen - Versionen sicher ändern müssen. Alle diese Zuordnungen werden nach einem - Regelwerk bewertet und die dadurch definierte beste Zuordnung zur Aufzeichnung verwendet. - Sind mehrere Zuordnungsvarianten gemäß den Regeln gleichwertig als beste Alternative - bewertet so wird eine Zuordnung zufällig ausgewählt. -

-

- Hier in der Konfiguration kann durch eine einfache Abfolge von Regeln die Bewertung - einer Zuordnung relativ zu einer anderen festgelegt werden. Eine Regel hat dabei immer - das Format Eigenschaft:Ordnung - Leerzeilen und Zeichen, die auf ein # folgen - werden gänzlich ignoriert. -

-

- Das bei der Installation mitgelieferte Regelwerk verwendet folgende Einzelregeln - in - der hier aufgeführten Reihenfolge: -

-

- TotalCut:Min Die Eigenschaft TotalCut einer Zuordnung beschreibt die - gesamte Verspätung von Aufzeichnungen. Wenn etwa zwei überlappende Aufzeichnungen - auf verschiedenen Quellgruppen (aka Transponder) auf einem Gerät ausgeführt werden, - so wird die zweite Aufzeichnung verspätet beginnen und somit eventuell die gewünschte - Aufzeichnung beschnitten. Die Ordnung Min bedeutet hier, dass eine Zuordnung - umso besser ist, je weniger Verspätung auftritt. Dies ist die erste und damit wichtigste - Regel im Regelwerk von VCR.NET: soviel der gewünschten Aufzeichnungen ausführen, wie - nur irgendwie möglich. Diese Regel alleine reicht eigentlich für die meisten Anwendungen - aus. -

-

- ResourceCount:Min Mit der Eigenschaft ResourceCount meldet eine - Zuordnung wie viele Geräte im Zeitbereich eingesetzt werden. VCR.NET sieht eine - Zuordnung als umso besser an je weniger Geräte verwendet werden. Da es - sich hier um die zweite Regel im Regelwerk handelt ist sie nur für die Zuordnungen - relevant, die die geringsten Aufzeichnungsverluste aufweisen. -

-

- ByPriority:Descending Mit dieser Regel wird die - Bewertung der Zuordnungen verlassen und auf die Betrachtung einzelner Geräte - gewechselt. Die Ordnung Descending bedeutet dabei, dass zuerst das DVB.NET - Gerät mit der höchsten Aufzeichnungspriorität betrachtet wird, dann das mit der - nächst niedrigeren und so weiter - für die andere Reihenfolge kann die Ordnung - Ascending verwendet werden. Bei mehreren Geräten gleicher Priorität ist - die Reihenfolge willkürlich und kann sich mit jedem Start des VCR.NET Dienstes - ändern. -

-

- RecordingCount:Max Für ein einzelnes Gerät meldet die Eigenschaft RecordingCount - die Anzahl der diesem Gerät im Zeitbereich zugeordneten Aufzeichnungen. Die Ordnung - Max bevorzugt hier Zuordnungen mit mehr Aufzeichnungen auf einem Gerät - eine - rein willkürliche Entscheidung. In Kombination mit ByPriority:Descending - bedeutet dies, dass zuerst einmal das Gerät mit der höchsten Aufzeichnungspriorität - untersucht wird. Eine Zuordnung ist besser als eine andere, wenn auf diesem Gerät - mehr Aufzeichnungen stattfinden - durch die Position im Regelwerk wird dieser Vergleich - aber nur vorgenommen, wenn die beiden Zuordnungen bereits den minimalen Aufzeichnungsverlust - haben und zudem auch eine minimale Gerätenutzung garantieren. Ist die Anzahl der Aufzeichnung - auf dem höchstpriorisierten Gerät identisch, so wird das nächste untersucht und so weiter. -

-

- ByPriority:End Beendet die Betrachtung einzelner Geräte und wechselt - zurück in die Bewertung der Zuordnungen an sich. Das nach der Erstinstallation - verwendete Regelwerk endet an dieser Stelle. Gibt es mehrere gleichwertige Zuordnungen, - wird nun eine zufällig ausgewählt. -

-
-# Der Verlust an Aufzeichnungszeit muss minimiert werden
-TotalCut:Min
-
-# Es sollen so wenige Geräte wie möglich verwendet werden
-ResourceCount:Min
-
-# Die einzelnen Geräte werden mit absteigender Aufzeichnungspriorität untersucht
-ByPriority:Descending
-
-    # Je mehr Aufzeichnungen auf einem Gerät, desto besser
-    RecordingCount:Max
-
-ByPriority:End
-

Die im Folgenden aufgeführten Eigenschaften werden im Standardregelwerk nicht verwendet:

-

- SourceCount Ermittelt für ein Gerät wie viele unterschiedliche Quellen - (aka Sender) im Zeitbereich angesteuert werden. Mit der Ordnung Min würde so eine - Planung bevorzugt bei der eine Quelle immer vom selben Gerät aufgezeichnet wird. Bei - vielen gleichzeitigen Aufzeichnungen mit und ohne Überlappung ist diese Bewertung - allerdings recht unzuverlässig, obwohl sie in Einzelfällen durchaus Sinn macht. -

-

- ParallelSource ermittelt über einen Planungszeitraum für jede Quelle - die Gesamtzeit, über die diese auf mehreren Geräten gleichzeitig aufgezeichnet wird. Mit der - Ordnung Min wird VCR.NET aufgefordert diese Zeit auf ein Minimum zu reduzieren, - selbst wenn dadurch die Planungspriorität der Geräte überschrieben wird. -

-

- StartTime:regelwerk untersucht die relativen Startzeitpunkte von Geräten und - versucht zu verhindern, dass ein Geräte nach einem anderen aktiviert wird - etwa - weil bekannt ist, dass bei dem Start der zugehörigen Gerätetreiber auf anderen Geräten - Störungen ausgelöst werden. Anstelle einer Ordnung wird hier ein Regelwerk aus Einzelregeln - angegeben, die durch einen senkrechten Strich (|) getrennt sind. Jede Regel beginnt mit dem - Namen eines Gerätes, darauf folgt das Symbol für kleiner als (<) und dann eine - ebenfalls durch kleiner als getrennte Liste von Gerätenamen. -

-

- Ein kleines Beispiel dazu: dev1<dev2<dev3|dev4<dev2 bevorzugt Planungen, bei denen das Gerät - dev1 nicht nach dev2 und dev3 gestartet wird und - dev4 nicht nach dev2. Der einfachste Fall ist mein privates - Beispiel mit der Hauppauge Nexus-S unter Windows 7 (32-Bit natürlich) die beim Starten - Aufzeichnungen anderer Geräte stört: Nexus<* mit der Sonderregel, dass der Stern (*) - alle (anderen) für VCR.NET freigeschalteten DVB Geräte bezeichnet. -

-
-
-
- - diff --git a/VCR.NET/WebClient41/FAQ/decryption.html b/VCR.NET/WebClient41/FAQ/decryption.html deleted file mode 100644 index 8c1e782..0000000 --- a/VCR.NET/WebClient41/FAQ/decryption.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - [Fragment] - - -
-
- Der VCR.NET Recording Service kann die Fähigkeiten von DVB.NET - nutzen, um mit Hilfe einer CI/CAM Hardware und einer entsprechenden Abonnementen-Karte - Quellen zu entschlüsseln und in unverschlüsselter Form aufzuzeichnen. Im Allgemeinen - sind dabei besondere Einstellungen des DVB.NET Geräteprofils notwendig, auf die - hier aber nicht eingegangen werden kann.
-
- Eine wichtige, wenn auch zurzeit noch irrelevante Einstellung - ist die Anzahl der gleichzeitig entschlüsselbarer Quellen. - Irrelevant ist diese Einstellung in der - vorliegenden Version, da DVB.NET zu jeder Zeit immer nur eine Quelle entschlüsseln - kann. Im DVB.NET Geräteprofil wird bei den Aufzeichnungseinstellungen ein entsprechender - Grenzwert verwaltet, der als Voreinstellung 1 verwendet.
-
- Gleichzeitige Entschlüsselung
-
- Die Aufzeichnungsplanung berücksichtigt diesen Wert und garantiert bei der Voreinstellung, - dass auch in parallelen Aufzeichnungen zu jedem - Zeitpunkt pro DVB Gerät maximal die festgelegte Anzahl von Quellen entschlüsselt wird. Wird dieser Wert - auf 0 verändert, so werden Aufzeichnungen von verschlüsselten Quellen automatisch - aus der Planung entfernt.
-
- Es wird empfohlen die Voreinstellung nicht zu verändern. In seltenen Fällen kann - es vorkommen, dass eine Quelle zwar als verschlüsselte gekennzeichnet ist, dies - aber entweder nicht wirklich der Tatsache entspricht oder die Verschlüsselung nur - zeitweise aktiv ist. Wäre die Anzahl gleichzeitiger Entschlüsselung im DVB.NET Geräteprofil - 0, so könnte eine solche Quelle grundsätzlich nicht aufgezeichnet werden, da sie - aus der Planung entfernt wird. Zusätzlich ist zu beachten, dass die Planung sich - immer an der Liste der Quellen eines DVB.NET Geräteprofils orientiert. Dies wird - zu bestimmten Zeitpunkten aktualisiert und kann eventuell - falsche Informationen enthalten, wenn die Sendeanstalten fehlerhafte Informationen - bezüglich der Quellen liefern. -
-
- - diff --git a/VCR.NET/WebClient41/FAQ/decryptlimit.png b/VCR.NET/WebClient41/FAQ/decryptlimit.png deleted file mode 100644 index fdb2b70..0000000 Binary files a/VCR.NET/WebClient41/FAQ/decryptlimit.png and /dev/null differ diff --git a/VCR.NET/WebClient41/FAQ/dvbnet.html b/VCR.NET/WebClient41/FAQ/dvbnet.html deleted file mode 100644 index 015952f..0000000 --- a/VCR.NET/WebClient41/FAQ/dvbnet.html +++ /dev/null @@ -1,22 +0,0 @@ - - - - [Fragment] - - -
-
- Der VCR.NET Recording Service ist ausschließlich der Koordinator von Aufzeichnungen. - Die eigentlichen Aktivitäten auf den DVB Geräten werden - mit Hilfe der DVB.NET Bibliothek - ausgeführt. Insbesondere muss für jedes DVB Gerät, das der VCR.NET Recording Service - nutzen soll, ein DVB.NET Geräteprofil - angelegt und korrekt konfiguriert werden. Es wird empfohlen, - sich mit den grundsätzlichen Konzepten von DVB.NET vertraut zu machen, um zu verstehen, - wie der VCR.NET Recording Service auf die vorhandene Hardware zugreift. Insbesondere - für die Liste der Quellen und deren Aktualisierung - ist eine korrekte Konfiguration von vitaler Bedeutung. -
-
- - diff --git a/VCR.NET/WebClient41/FAQ/editcurrent.html b/VCR.NET/WebClient41/FAQ/editcurrent.html deleted file mode 100644 index e8ade84..0000000 --- a/VCR.NET/WebClient41/FAQ/editcurrent.html +++ /dev/null @@ -1,29 +0,0 @@ - - - - [Fragment] - - -
-
- Sobald eine Aufzeichnung gestartet wird kennt der VCR.NET Recording Service diese - in zweierlei Weise: da ist zum einen die ursprüngliche Programmierung der Aufzeichnung, - die im Regelfall unverändert bleibt. Es gibt aber auch eine zweite Sicht über die - gerade laufende Aufzeichnung. - In dieser wird etwa vermerkt, wenn der Anwender den Endzeitpunkt verschiebt. - Manchmal ist es wichtig zu verstehen, welche Veränderung den VCR.NET Recording Service beeinflussen.
-
- Der einfachste Fall ist es, die Programmierung einer Aufzeichnung zu verändern, - ohne die gerade aktive Ausführung anzurühren. In dieser Situation gilt folgende - einfache Regel: jede Veränderung wird ignoriert. Der VCR.NET Recording Service wird - die laufende Aufzeichnung wie ursprünglich programmiert beenden.
-
- Wird die laufende Ausführung verändert, so entfernt der VCR.NET Recording Service - die zugehörige Aufzeichnung aus der Planungsansicht. Handelt - es sich um eine Serienaufzeichnung, so erscheint - diese erst bei der nächsten Wiederholung im Plan. Dies kann verwirrend für den Anwender - sein, stört die Gesamtplanung im VCR.NET Recording Service allerdings nicht. -
-
- - diff --git a/VCR.NET/WebClient41/FAQ/endchange.png b/VCR.NET/WebClient41/FAQ/endchange.png deleted file mode 100644 index b965338..0000000 Binary files a/VCR.NET/WebClient41/FAQ/endchange.png and /dev/null differ diff --git a/VCR.NET/WebClient41/FAQ/epg.html b/VCR.NET/WebClient41/FAQ/epg.html deleted file mode 100644 index 1b83f58..0000000 --- a/VCR.NET/WebClient41/FAQ/epg.html +++ /dev/null @@ -1,44 +0,0 @@ - - - - [Fragment] - - -
-
- Die elektronische Programmzeitschrift (EPG) ist ein optionales Leistungsmerkmal, - dass von vielen Sendeanstalten angeboten wird. Zusätzlich zur digitalen Ausstrahlung - von Bild und Ton werden Informationen übermittelt, welche Sendungen in nächster - Zeit auf welcher Quelle (Radio- oder Fernsehsender) ausgestrahlt werden. Im Allgemeinen - sind in diesen Informationen auch kurze Beschreibungen der Inhalte vorhanden, einige - Sender beschränken sich aber auf den Titel und den Sendezeitraum. Genauso unterschiedlich - wie der Umfang des Inhalts ist auch die zeitliche Vorschau: zurzeit wird für die - Sender der ARD eine Vorschau von etwa 4 Wochen angeboten, die Sender rund um das - ZDF beschränken sich auf eine Woche und bei einigen Privatsendern sind es nur wenige - Tage. -
-
- Der VCR.NET Recording Service kann dazu konfiguriert - werden, für eine ausgewählte Liste von Quellen die Programmzeitschrift periodisch - zu aktualisieren - üblich ist ein oder zweimal am Tag. Auf Basis dieser Daten lassen - sich dann Aufzeichnungen programmieren. Zur Auswahl - stehen dabei erst - einmal alle Informationen aller Quellen aller DVB Geräte, die der VCR.NET Recording - Service verwenden darf. Um die richtige Sendung zu finden gibt es neben der Inhaltssuche - auf einen Freitext weitere Filtermöglichkeiten. So ist es möglich, sich auf die Sendungen - einer einzelnen Quelle zu beschränken oder alle Sendung ab einer bestimmten Uhrzeit - eines bestimmten Tages anzeigen zu lassen. -
-
- Die Programmierung über die Programmzeitschrift ist ansonsten einfach gehalten. - Normalerweise wird nach der Auswahl eine neue Aufzeichnung angelegt - auf Wunsch - kann auch eine Aufzeichnung zu einem existierenden Auftrag ergänzt werden. Die Zeiten - aus der Programmzeitschrift werden um Vor- und Nachlaufzeiten gemäß den - Voreinstellungen - des Anwenders erweitert. Die eigentliche Programmierung muss noch einmal bestätigt werden, - wobei dann auch noch Detailänderungen möglich sind - zum Beispiel um direkt eine - Serienaufzeichnung anzulegen. -
-
- - diff --git a/VCR.NET/WebClient41/FAQ/epgconfig.html b/VCR.NET/WebClient41/FAQ/epgconfig.html deleted file mode 100644 index 4490fa5..0000000 --- a/VCR.NET/WebClient41/FAQ/epgconfig.html +++ /dev/null @@ -1,73 +0,0 @@ - - - - [Fragment] - - -
-
- Damit der VCR.NET Recording Service eine Programmzeitschrift - zur Programmierung neuer Aufzeichnungen zur Verfügung stellen kann muss erst einmal - festgelegt werden, mit welchem Inhalt diese zu füllen ist. Im Administrationsbereich - der Web Oberfläche gibt es dazu eine gesonderten - Seite. - Damit die Programmzeitschrift überhaupt erstellt wird, muss erst - einmal die Sammlung der Informationen an sich aktiviert werden.
-
- Sammlung aktivieren
-
- Die wesentliche Information ist dann, für welche Quellen der VCR.NET Recording Service - versuchen soll Sendungsdaten zu ermitteln. Bedenkt man, dass alleine auf Astra - 1 mehr als 1,000 Radio- und Fernsehsender angeboten werden, so macht eine Einschränkungen - auf die eigenen Lieblingssender durchaus Sinn. Nach Vorauswahl eines der vom VCR.NET - Recording Service verwendeten DVB Geräte können mit den üblichen Methoden Quellen - ausgewählt und zur Liste hinzugefügt werden - - natürlich können Quellen auch wieder aus der Liste entfernt werden. -
-
- Quellen konfigurieren
-
- Sind unter den Quellen auch englische Sender von Astra 2, so muss die FreeSat UK - Option aktiviert werden. Die Programmzeitschrift der BBC, ITV et al Sender wird - auf einem anderen Wege übertragen als bei uns üblich. Ohne die Aktivierung der Option - würden immer nur die Sendungsbeschreibungen in der Programmzeitschrift des VCR.NET - Recording Service landen, die zum Zeitpunkt der Sammlung entweder gerade liefen - oder als nächstes gesendet würden. Diese Information ist für eine Programmierung - fast immer unbrauchbar.
-
- Nun muss dem VCR.NET Recording Service nur noch mitgeteilt werden, wann die Programmzeitschrift - zu aktualisieren ist. Dazu können bis zu die Stunden pro Tag angegeben werden, - zu dem eine entsprechende Aktivität gestartet werden soll - wie bei normalen Aufzeichnung - wird der Rechner dazu wenn notwendig aus dem Schlafzustand - aufgeweckt. Damit diese Sammlung auch in der Planung der Aufzeichnungen berücksichtigt - werden kann, muss auch immer eine maximale Laufzeit für die Aktualisierung angegeben - werden. Ist diese zu kurz eingestellt, so wird der VCR.NET Recording Service die - Aktualisierung vorzeitig beenden und die Programmzeitschrift ist unvollständig. - Der genaue Wert ist abhängig von den ausgewählten Quellen und kann nur individuell - selbst bestimmt werden. Ist die Aktualisierung doch vorzeitig abgeschlossen, so - wird auch die Aktivität - auf dem DVB Gerät beendet. - Mit Hilfe der Protokollliste lässt sich dann leicht feststellen, - was ein typischer Wert für die Laufzeit ist. -
-
- Aktualisierungszeitpunkte
-
- In manchen Fällen ist die Einstellung von vier festen Uhrzeiten unzureichend, daher - bietet der VCR.NET Recording Service zwei weitere Konfigurationswerte an. Die Wartezeit - zwischen zwei Aktualisierungen stellt sicher, dass zwischen zwei Aktualisierungen - mindestens die angegebene Anzahl von Stunden verstreicht. Umgekehrt erlaubt es die - Latenzzeit das Vorziehen einer Aktualisierung, wenn der Rechner sowieso - gerade für eine Aufzeichnung oder Sonderaufgabe aktiviert wurde und ansonsten in - den Schlafzustand versetzt würde.
-
- Ergänzend ist es jederzeit möglich, eine Aktualisierung manuell - anzufordern. Der VCR.NET Recording Service wird - dann zum nächstmöglichen Zeitpunkt die gewünschte Aktion ausführen. Hier gilt wie - grundsätzlich für alle Sonderaufgaben: ist eine programmiert Aufzeichnung aktiv - oder steht kurz bevor, so wird die Aktualisierung verschoben, bis das verwendete - DVB Gerät sicher für die konfigurierte maximale Laufzeit unbenutzt ist. -
-
- - diff --git a/VCR.NET/WebClient41/FAQ/epgonoff.png b/VCR.NET/WebClient41/FAQ/epgonoff.png deleted file mode 100644 index fc9e42f..0000000 Binary files a/VCR.NET/WebClient41/FAQ/epgonoff.png and /dev/null differ diff --git a/VCR.NET/WebClient41/FAQ/epgsources.png b/VCR.NET/WebClient41/FAQ/epgsources.png deleted file mode 100644 index e411b14..0000000 Binary files a/VCR.NET/WebClient41/FAQ/epgsources.png and /dev/null differ diff --git a/VCR.NET/WebClient41/FAQ/epgtimes.png b/VCR.NET/WebClient41/FAQ/epgtimes.png deleted file mode 100644 index 7c2deb4..0000000 Binary files a/VCR.NET/WebClient41/FAQ/epgtimes.png and /dev/null differ diff --git a/VCR.NET/WebClient41/FAQ/exceptions.png b/VCR.NET/WebClient41/FAQ/exceptions.png deleted file mode 100644 index d4beebf..0000000 Binary files a/VCR.NET/WebClient41/FAQ/exceptions.png and /dev/null differ diff --git a/VCR.NET/WebClient41/FAQ/filecontents.html b/VCR.NET/WebClient41/FAQ/filecontents.html deleted file mode 100644 index 044893b..0000000 --- a/VCR.NET/WebClient41/FAQ/filecontents.html +++ /dev/null @@ -1,69 +0,0 @@ - - - - [Fragment] - - -
-
- Für jede programmierte Aufzeichnung erstellt der VCR.NET Recording Service eine - Datei mit der Endung TS (Transport Stream). Abhängig von der Auswahl der - Quelle (des Senders) und den bei der Programmierung verwendeten Optionen können - in einer solchen Datei folgende Informationen enthalten sein: -
    -
  • Für Fernsehsender ist immer ein Bildsignal vorhanden, für Radiosender natürlich - nie. Je nach programmiertem Sender kann es sich um ein digitales Signal einfacher - Auflösung (SDTV, MPEG-2) oder hoher Auflösung (HDTV, H.264) handeln.
  • -
  • Jeder Sender bietet immer eine primäre Tonspur an, üblicherweise als Stereosignal. - Der VCR.NET Recording Service zeichnet dieses Signal immer mit auf.
  • -
  • Optional können weitere Stereotonspuren angeboten sein, etwa alternative Sprachen - (wie bei ARTE üblich) oder mit eingemischtem Begleittext (wie von ARD und ZDF vereinzelt - angeboten). Der VCR.NET Recording Service kann durch die Programmierung einer Aufzeichnung - aufgefordert werden, alle diese Stereosignale mit aufzuzeichnen. Eine Einzelauswahl - ist nicht möglich.
  • -
  • Je nach Sender werden auch höherwertige Tonspuren im Dolby Digital Format angeboten. - Bei der Programmierung ist es möglich, diese mit aufzuzeichnen. Entweder nur das - primäre Signal oder alle Dolby Digital Spuren - in letzterem Fall aber nur in Kombination - mit allen alternativen Stereosignalen.
  • -
  • Wenn ein Videotext gesendet wird, kann dieser als Ganzes in die Aufzeichnungsdatei - integriert werden. Eine Beschränkung auf einzelne Seiten ist nicht vorgesehen.
  • -
  • Viele Sender bieten für ausgewählte Sendungen Untertitel über den Videotext an - - üblich sind hier in Deutschland die Seiten 150, 777 und 149, je nach Sender. Zusätzlich - werden inzwischen aber auch vielfach digitale Untertitel unabhängig vom Videotext - ausgestrahlt. Auch hierfür bietet die Programmierung im VCR.NET Recording Service - eine Option zur Aufzeichnung an.
  • -
  • Im Allgemeinen wird in jede Aufzeichnungsdatei ein Auszug aus der Programmzeitschrift - eingebettet, in dem ausschließlich die aufgezeichneten Sendungen beschrieben sind - - sofern die Quelle eine elektronische Programmzeitschrift anbietet, was aber in - der Praxis immer der Fall ist. In einzelnen Fällen kann es notwendig sein, diese - Integration zu deaktivieren, was aber nur über die Konfiguration des DVB.NET Geräteprofils möglich ist.
  • -
- Am Rande sei bemerkt, dass auch viele Radiosender alternative Tonspuren anbieten. - Je nach aufgezeichneter Sendung kann zum Beispiel die höherwertige Dolby Digital - Spur von Interesse sein. -
-
- Bei der Programmierung einer Aufzeichnung kann nach der Auswahl - einer Quelle festgelegt werden, welche der aufgeführten optionalen - Informationen in die Aufzeichnungsdatei gelangen sollen. Ist eine technische Bereitstellung - der gewünschten Informationen möglich, so erfüllt der VCR.NET Recording Server die - mit der Programmierung geäußerten Wünsche, ansonsten werden die Einstellungen kommentarlos - ignoriert - etwa wenn ein Videotext aufgezeichnet werden soll, die Quelle aber keinen - anbietet weil es sich um einen Radiosender handelt.
-
- Optionen festlegen -
-
- Die einzelnen Auswahlpunkte haben dabei folgende Bedeutung (von links nach rechts): -
-
    -
  • Primäre Dolby Digital Tonspur aufzeichnen.
  • -
  • Alle Stereotonspuren aufzeichnen - inklusive aller Dolby Digital Spuren, wenn auch - die vorherige Option gewählt wurde.
  • -
  • Videotext in die Aufzeichnungsdatei mit aufnehmen.
  • -
  • Alle digitalen Untertitel zusätzlich aufzeichnen.
  • -
-
-
- - diff --git a/VCR.NET/WebClient41/FAQ/hibernate.png b/VCR.NET/WebClient41/FAQ/hibernate.png deleted file mode 100644 index 7faf40e..0000000 Binary files a/VCR.NET/WebClient41/FAQ/hibernate.png and /dev/null differ diff --git a/VCR.NET/WebClient41/FAQ/hibernation.html b/VCR.NET/WebClient41/FAQ/hibernation.html deleted file mode 100644 index b89fbf3..0000000 --- a/VCR.NET/WebClient41/FAQ/hibernation.html +++ /dev/null @@ -1,115 +0,0 @@ - - - - [Fragment] - - -
-
- Der VCR.NET Recording Service ist ein unsichtbar im Hintergrund laufender Windows - Dienst, der selbstständig programmierte Aufzeichnungen und Sonderaufgaben - ausführen soll. Dabei ist die Zusammenarbeit mit dem Schlafzustand des Rechners - ein wichtiger Aspekt. Zum Verständnis der Abläufen werden nun einige Szenarien vorgestellt, - beginnend mit einem eher untypischen Fall: dem Betrieb des VCR.NET auf einem gesonderten - Rechner, dessen einzige Aufgabe die Aufzeichnung von DVB Ausstrahlungen ist. Der - untypische Fall für dieses Beispiel ist, dass es dem VCR.NET auch gestattet sei, - den Rechner in den Schlafzustand zu versetzen - ohne zusätzliche Maßnahmen steht - der Rechner dann nicht ständig zur Programmierung neuer Aufzeichnungen zur Verfügung.
-
- Einstellungen zum Schlafzustand -
-
- Grundsätzlich stellt der VCR.NET Recording Service sicher, dass der Rechner für - programmierte Aufzeichnungen aus dem Schlafzustand aufgeweckt wird, egal wie der - Übergang in den Schlafzustand erfolgt ist. Dieses Verhalten kann nicht deaktiviert - werden. Im ersten Szenario arbeitet der VCR.NET Recording Service wie folgt: für - jede Aufzeichnung oder Sonderaufgabe wird der Rechner aus dem Schlafzustand aufgeweckt. - Da dieser Vorgang alleine von System zu System verschieden lange dauert, kann in - der Konfiguration eine entsprechende Vorlaufzeit programmiert werden. Diese ergibt - sich aus Erfahrungswerten und ist im Beispiel 30 Sekunden - auf einem anderen Rechner - reichten 150 Sekunden gerade einmal aus. Diese Zeit hat keinen Einfluss auf den - Beginn einer Aufzeichnung, sofern sie vernünftig gewählt wurde. -
-
- Nach Abschluss einer Aufzeichnung oder Sonderaufgabe prüft der VCR.NET Recording - Service wann die nächste Aktion ansteht. Ist die Wartezeit kürzer als die in der - Konfiguration eingetragene minimale Pause (im Beispiel 5 Minuten), so wird nicht - nur auf den Übergang in den Schlafzustand verzichtet sondern zusätzlich sichergestellt, - dass das Betriebssystem keinen solchen Übergang von sich aus auslöst. Ist die Wartezeit - allerdings länger, so versetzt der VCR.NET Recording Service den Rechner in den - Schlafzustand, der in der Konfiguration gewählt wurde. -
-
- Wird der Rechner aus anderen Gründen in den Schlafzustand versetzt und die nächste - Aufzeichnung liegt in unmittelbarer Zukunft, so kann es sein, dass VCR.NET den Rechner - relativ kurzfristig wieder aufweckt. Ist die Option nicht aktiviert, die oben - im Bild ganz unten zu sehen ist, so versucht der VCR.NET eine minimale Verweildauer - im Schlafzustand herzustellen (im Beispiel 5 Minuten). Allerdings ist dies nicht in - jeder Systemkonfiguration möglich und kann im Extremfall dazu führen, dass der Rechner - gar nicht mehr für eine Folgeaufzeichnung aufgeweckt wird. -
-
- Verbietet die Konfiguration den Übergang in den Schlafzustand, so werden nach Abschluss - der Aufzeichnung oder Sonderaufgabe keine weiteren Schritte unternommen. Je nach - Einstellungen der Energieverwaltung von Windows bleibt der Rechner dann ständig - an oder geht nach einer bestimmten Wartezeit automatisch in den Schlafzustand. Der - VCR.NET Recording Service stellt in diesem Szenario lediglich sicher, dass dies - nicht geschieht, wenn die Zeit im Schlafzustand bis zur nächsten Aufzeichnung oder - Sonderaufgabe kleiner als die konfigurierte minimale Pause ist. -
-
- Ein etwas typischeres Szenario ist es wenn der VCR.NET Recording Service auf einem - Rechner betrieben wird, der auch für andere Aufgaben genutzt wird. Im Normalfall - ist dann häufig ein Anwender angemeldet und es wäre sehr lästig, wenn der - Rechner nach einer Aufzeichnung oder einer Sonderaufgabe spontan in den Schlafzustand - übergeht. Daher ist es dem VCR.NET Recording Service grundsätzlich untersagt, selbstständig - in den Schlafzustand zu wechseln, so lange noch ein Anwender angemeldet ist. -
-
- Für einen möglichst einfachen Betrieb in diesem Szenario besitzt das VCR.NET Kontrollzentrum - eine besondere Einstellung - es handelt sich bei - dem Kontrollzentrum um die Anwendung, die normalerweise im so genannten System Tray - von Windows durch das Kamerasymbol visualisiert wird. Auf Wunsch ist es damit möglich, - einen Schlafzustand verzögert auslösen zu lassen.
-
- Kontrollzentrum -
-
- Das Kontrollzentrum erkennt wenn der VCR.NET Recording Service eigentlich in den - Schlafzustand übergehen möchte und führt dann nach der angegebenen Verzögerung genau - diesen Übergang aus. In der Zwischenzeit kann der Anwender über einen entsprechenden - Dialog den Vorgang jederzeit abbrechen und normal weiter arbeiten. Ist der Anwender - gerade nicht aktiv, so greifen zusätzlich die Einstellung der Energieoptionen von - Windows. Dadurch kann es dann sogar sein, dass der Rechner vor der angegebenen Zeit - in den Schlafzustand geht, weil Windows keine Aktivitäten des Anwenders mehr wahrnimmt. -
-
- Warten auf den Schlafzustand
-
- Das VCR.NET Kontrollzentrum hat aber noch eine - weitere - nützliche Funktion - , die nicht deaktiviert werden kann. Aus der Hintergrundfarbe - des Kamerasymbols kann direkt abgelesen werden, was der VCR.NET Recording Service - gerade tut. Ist die Farbe Blau, so wird gerade mindestens eine Aufzeichnung oder - Sonderaufgabe ausgeführt. Bei Gelb steht eine Aufzeichnung in naher Zukunft an - - konkret wie oben konfiguriert näher als die minimale Verweilzeit im Schlafzustand. - Der Anwender ist angehalten, diese Farbe zu beachten, wenn der Rechner spontan manuell - in den Schlafzustand versetzt wird. -
-
- Es ist dem VCR.NET Recording Service nicht möglich, einen solchen manuellen Übergang - in den Schlafzustand zu verhindern. Tritt ein solcher Fall ein, so werden alle laufenden - Aufzeichnung und Sonderaufgaben so abgebrochen, als würde der Anwender dies über - die Web Oberfläche tun - das heißt vor allem, dass die jeweilige Aktion nach einem - Neustart nicht fortgesetzt wird. Damit der Rechner nicht aufwacht, wird zusätzlich - die minimale Verweilzeit im Schlafzustand beachtet. Würde eine Aufzeichnung in näherer - Zukunft anstehen, so wird sich der Start entsprechend verzögern, was bei Aufzeichnungen - einem Verlust durch zu spätem Starten gleichkommt. Daher die goldene Regel: wird - der Rechner mit dem VCR.NET Recording Service in den Schlafzustand versetzt während - das Kontrollzentrum Blau oder Gelb hinterlegt ist, so ist mit einem Verlust an Aufzeichnungsdaten - zu rechnen. -
-
- - diff --git a/VCR.NET/WebClient41/FAQ/jobsandschedules.html b/VCR.NET/WebClient41/FAQ/jobsandschedules.html deleted file mode 100644 index 2db71a3..0000000 --- a/VCR.NET/WebClient41/FAQ/jobsandschedules.html +++ /dev/null @@ -1,56 +0,0 @@ - - - - [Fragment] - - -
-
- Schaut man sich die Programmierung von Aufzeichnungen etwas genauer an, dann sieht - man, dass der VCR.NET Recording Service hier auf zwei Konzepten aufsetzt.
-
- Auftrag und Aufzeichnung -
-
- Eine Aufzeichnung wird grundsätzlich als Teil eines Auftrags angelegt. Über die - Liste aller Aufzeichnungen (nicht den - Aufzeichnungsplan) ist - es dann auch möglich, einem Auftrag mehrere Aufzeichnungen zuzuordnen. Einige der - für eine Aufzeichnung notwendigen Parameter sind nur über den Auftrag verfügbar - und werden von allen Aufzeichnungen gemeinsam genutzt. -
-
- Der Hintergrund dieser Trennung liegt in der Historie des VCR.NET Recording Service - begründet. In der Entstehungszeit im Jahre 2003 wurde der VCR.NET hauptsächlich - dafür eingesetzt Serien aufzuzeichnen. Zwar - bietet die Serienaufnahme einer einzelnen Aufzeichnung die Möglichkeit, diese an - verschiedenen Wochentagen zu wiederholen, aber das war es noch nicht ganz. Gerade - bei Serien, die auch am Wochenende ausgestrahlt werden ergeben sich oft deutlich - andere Sendezeiten. Manchmal lassen diese sich durch großzügige Vor- und Nachlaufzeiten - kompensieren, manchmal ufert dieser Ansatz aber auch einfach aus. Daher hat der - VCR.NET Recording Service die Möglichkeit erhalten, mehrere Aufzeichnungen in einem - Auftrag zu bündeln. -
-
- Für alle Aufzeichnungen ist insbesondere die Auswahl des verwendeten DVB Gerätes - und des Ablageverzeichnisses für die Aufzeichnungsdateien - gemeinsam. Auf Wunsch kann sogar die Quelle (der Sender) vorgewählt werden und muss - dann nicht mehr pro Aufzeichnung explizit angegeben werden - es ist aber möglich, - die Quelle individuell für jede Aufzeichnung festzulegen. Ähnlich verhält es sich - mit dem Namen: ein Auftrag hat immer einen Namen, der im Allgemeinen ein wesentlicher - Bestandteil des Dateinamens von Aufzeichnungsdateien - ist. Eine Aufzeichnung muss keinen eigenen Namen haben. Wird allerdings ein solcher - angegeben, so trägt er üblicherweise zusätzlich zum Namen des Auftrags zum Dateinamen - bei. -
-
- Es ist möglich, einzelne Aufzeichnungen eines Auftrags zu löschen. Diese werden - dann aus dem Auftrag entfernt, alle weiteren Aufzeichnungen bleiben unberührt. Beim - Entfernen der letzten Aufzeichnung wird der Auftrag automatisch - mit entfernt - das ist vermutlich der Normalfall bei Einsatz des VCR.NET - Recording Service. Ergänzend ist es auch möglich, einen Auftrag als Ganzes samt - aller Aufzeichnungen drin in einem Rutsch zu entfernen. -
-
- - diff --git a/VCR.NET/WebClient41/FAQ/jobsandschedules.png b/VCR.NET/WebClient41/FAQ/jobsandschedules.png deleted file mode 100644 index 0bf9308..0000000 Binary files a/VCR.NET/WebClient41/FAQ/jobsandschedules.png and /dev/null differ diff --git a/VCR.NET/WebClient41/FAQ/log.html b/VCR.NET/WebClient41/FAQ/log.html deleted file mode 100644 index 533e07c..0000000 --- a/VCR.NET/WebClient41/FAQ/log.html +++ /dev/null @@ -1,40 +0,0 @@ - - - - [Fragment] - - -
-
- Der VCR.NET Recording Service erstellt für jede ausgeführte Aktivität - einen gesonderten Protokolleintrag. Eine Aktivität ist hierbei - immer ein geschlossener Nutzungszeitraum eines DVB Gerätes. In diesem Zeitraum kann - entweder eine einzelne Sonderaufgabe oder eine Gruppe - von Aufzeichnungen ausgeführt worden sein. Die Protokolleinträge können direkt über die Web Oberfläche - abgerufen werden.
-
- In der Liste sieht man immer die Einträge einer Woche für ein einzelnes DVB Geräte. - Über Auswahllisten ist es möglich, sowohl den Zeitraum als auch das betrachtete - Gerät festzulegen. Die Konfiguration - des VCR.NET Recording Service sieht vor, dass veraltete Protokolleinträge automatisch - entfernt werden. Man beachte aber, dass dies nicht periodisch geschieht, sondern - nur bei Aufruf der Liste über die Web Oberfläche.
-
- Erst einmal werden nur die Protokolleinträge angezeigt, die von Aufzeichnungen erzeugt - wurden. Auf Wunsch ist es möglich, auch die Einträge der Sonderaufgaben - hinzu zu schalten - einzeln pro Art der Aufgabe. -
-
- Wählt man einen einzelnen Eintrag an, so wird eine Detailanzeige geöffnet. In dieser - lässt sich für Aufzeichnungen zum Beispiel die gesamte Größe aller zugehörigen Aufzeichnungsdateien - sowie Beginn und Ende der Aktivität über alle enthaltenen Aufzeichnungen ablesen.
-
- Sind die Aufzeichnungsdateien zu einem Eintrag noch - vorhanden, so wird dies durch kleine Symbole - bei dem Eintrag visualisiert. Ist auf dem Rechner, von dem die Web Oberfläche - aufgerufen wurde, der DVB.NET / VCR.NET Viewer lokal installiert, so kann durch Klicken auf ein - Symbol die zugehörige Aufzeichnungsdatei zur Anzeige geöffnet werden. -
-
- - diff --git a/VCR.NET/WebClient41/FAQ/nexus.html b/VCR.NET/WebClient41/FAQ/nexus.html deleted file mode 100644 index 72344e9..0000000 --- a/VCR.NET/WebClient41/FAQ/nexus.html +++ /dev/null @@ -1,72 +0,0 @@ - - - - [Fragment] - - -
-
- Der VCR.NET Recording Service würde im Jahre 2003 ursprünglich für die Hauppauge Nexus-S entwickelt - diese Karte ist eigentlich - eine TechnoTrend S-2300 - PremiumLine und wurde damals von Hauppauge unter einem eigenen Namen vertrieben. - Die meisten DVB Geräte verwenden damals wie heute mehr oder weniger einheitliche - Treiber, die dem Microsoft BDA (Broadcast Device Architecture) Standard - genügen. Dabei ist es im Allgemeinen (Ausnahmen bestätigen die Regel) vorgesehen, - dass die verarbeitende Software alle Daten so entgegen nehmen kann, wie sie digital - empfangen werden. Insbesondere werden nach Ansteuern einer Quellgruppe (Transponder, - Frequenz, ...) alle darauf angebotenen Quellen (Radio- und Fernsehsender) - gleichzeitig - verfügbar. So ist es mit einem über BDA angesteuerten Gerät - normalerweise problemlos möglich, zusätzlich zum Empfang zum Beispiel von RTL auch - noch RTL2, VOX und SuperRTL Sendungen zu verarbeiten.
-
- Es gibt mehrere Gründe, warum das bei der Nexus nicht so ist - auch gute Gründe, - aber darauf kann hier nicht eingegangen werden. Tatsache ist, dass über die proprietäre - Softwareschnittelle der Nexus maximal 8 Nutzdatenströme - gleichzeitig empfangen werden können. Ein Nutzdatenstrom bedeutet dabei den Empfang - eines Bild- oder Tonsignals, von Videotext oder DVB Untertiteln. Beschränkt man - sich also nur auf das Bild und eine Tonspur, so kann man maximal 4 Quellen gleichzeitig - empfangen. Möchte man einen Sender wie ZDF vollständig mit Bild, drei Stereotonspuren, - einem Dolby Digital Signal, dem Videotext und DVB Untertiteln aufzeichnen, so bleibt - noch nicht einmal Kapazität für einen weiteren Fernsehsender.
-
- Dazu kommt, dass die Firmware auf der Nexus nicht mehr mit den aktuellen Herausforderungen - des digitalen Empfangs mithalten kann. Die Erfahrung zeigt, dass zwar der gleichzeitig - Empfang von RTL, RTL2, VOX und SuperRTL möglich wäre, nicht aber ZDF, 3Sat, KIKA - und ZDF.info - immer beschränkt auf nur das Bild und eine Tonspur. Das ZDF überträgt - seine Sender mit deutlich höheren Datenraten, was auch zu einem besseren Bild führt. - Nach aktuellen Kenntnisstand kommt die Nexus mit einer Gesamtbildrate von etwa 14 - MBit/s zurecht, ab etwa 15 MBit/s kommt es aber zu dramatischen Störungen, die alle - parallelen Aufzeichnungen gleichzeitig unbrauchbar macht.
-
- Tatsächlich ist es in der Praxis bisher nicht vorgekommen, dass die Zahl gleichzeitiger - Aufzeichnungen grundsätzlich nicht möglich war - mehr als zwei gleichzeitige Sendungen - ist schon recht selten. Es bleibt aber immer die Beschränkung auf die 8 Nutzdatenströme, - die je nach konkreter Situation von Unannehmlichkeiten bis zu fehlgeschlagenen Aufzeichnungen - führen kann.
-
- Der VCR.NET Recording Service war eines der ersten Programme, die parallele Aufzeichnungen - bei Einsatz einer Nexus / 2300 überhaupt erlaubten. Die ersten Versionen haben sich - dabei auch große Mühe gegeben, die Einschränkungen der DVB Hardware bei der Aufzeichnungsplanung - zu berücksichtigen und entsprechend intelligente Korrekturen vorzunehmen, um die - Wünsche des Anwenders so gut wie möglich zu erfüllen. Heute ist die Nexus allerdings - eher ein Exot und die Sonderbehandlungen wurden weitgehend aus dem VCR.NET Recording - Service entfernt. Es ist natürlich immer noch möglich, - mehrere Sendungen gleichzeitig - aufzuzeichnen. Allerdings liegt es nun weitgehend - in der Hand des Anwenders durch intelligente Programmierung dazu beizutragen, dass - Aufzeichnungen durch die existierenden Beschränkungen nicht gänzlich verloren gehen - oder durch die Unzulänglichkeiten der Firmware nicht unbrauchbar werden.
-
- Ein ärgerlicher Punkt in der aktuellen Implementierung darf aber nicht unerwähnt - bleiben. Der VCR.NET Recording Service hat in der vorliegenden Version keine Möglichkeit - zu protokollieren, wenn das Starten einer zusätzlichen Aufzeichnung aufgrund der - Hardwarebeschränkung nicht möglich war. Läuft im Beispiel oben die volle ZDF Aufzeichnung - mit 7 Datenströmen und muss eine weitere Aufzeichnung gestartet werden, so geschieht - dies nicht. Der VCR.NET Recording Service verhält sich aber, als wäre die Aufzeichnung - aktiviert worden. -
-
- - diff --git a/VCR.NET/WebClient41/FAQ/numberoffiles.html b/VCR.NET/WebClient41/FAQ/numberoffiles.html deleted file mode 100644 index 6f9fdc5..0000000 --- a/VCR.NET/WebClient41/FAQ/numberoffiles.html +++ /dev/null @@ -1,88 +0,0 @@ - - - - [Fragment] - - -
-
- Im Allgemeinen erzeugt der VCR.NET Recording Service pro Aufzeichnung eine einzige - Aufzeichnungsdatei mit allen gewünschten Informationen. - Es gibt allerdings auch Situationen, in denen mehrere Aufzeichnungsdateien angelegt - werden. Einige Situationen werden bewusst und hoffentlich auch erwünscht auftreten, - andere dienen der Korrektur von Fehlverhalten. -
-
- Der wichtigste beabsichtigte Fall mehrerer Aufzeichnungsdateien tritt bei der Aufzeichnung - von Regionalsendern wie etwa WDR Bonn auf. Eine Aufzeichnung der Quelle WDR Bonn - wird die meisten Zeit exakt identische Ergebnisse liefern wie die Aufzeichnung von - WDR Köln oder WDR Aachen. Nur in ganz bestimmten Zeiträumen unterscheiden sich die - Inhalte der lokalen Varianten des WDR - zum Zeitpunkt der Erstellung dieser Beschreibung - werden zum Beispiel werktags zwischen 19:30 und 20:00 unter dem Namen Lokalzeit - regionale Nachrichten aus jeweils eigenen Sendestudios ausgestrahlt. -
-
- Der VCR.NET Recording Service erkennt diese Umschaltung und erstellt basierend auf - diesen Zeiten separate Dateien, die neben einem gemeinsamen Namensteil einfach mit - Hilfe eines Anhängsels durchnummeriert sind. Programmiert man etwa in der Woche - eine Aufzeichnung auf WDR Bonn von 19:15 bis 20:15, so werden im Allgemeinen drei - Datei erzeugt: von 19:15 bis 19:30 ein Abschnitt WDR Köln, dann von 19:30 bis 20:00 - die Bonner Lokalzeit und schließlich von 20:00 bis 20:15 die gemeinsamen - Nachrichten der ARD, die über alle lokalen Varianten identisch empfangen werden. - Ist man nur an der regionalen Lokalzeit interessiert, so braucht man sich nur um - die mittlere Aufzeichnungsdatei zu kümmern. -
-
- Dieses Verhalten ist eine grundsätzlich Eigenschaft des VCR.NET Recording Service - bei der Aufzeichnung. Ständig wird überwacht, ob sich die Informationen, die in - die Aufzeichnungsdatei übertragen werden, ursächlich verändern. Im Fall der Lokalfenster - des WDR werden sowohl Bild als auch Ton umgeschaltet. Eine derartige Trennung würde - aber auch vorgenommen, wenn einzelne Informationen nachträglich an oder abgeschaltet - werden. Diese Situation wurde schon lange Zeit nicht mehr beobachtet, trotzdem aber - hier das Beispiel aus der Vergangenheit: der PayTV Sender PREMIERE hatte die Angewohnheit, - bei Ausstrahlungen mit Originalton die dafür benötigte Tonspur mit Beginn der Sendung - anzuschalten und am Ende wieder vollständig zu deaktivieren. Mit dem heutigen Stand - würde der VCR.NET Recording Service auch hier mehrere Dateien erzeugen - was allerdings - je nach genauem Vorgehen des Senders durchaus zu unerwünschten Nebeneffekten führen - kann. -
-
- Eine Trennung wird zusätzlich auch bei gewissen Fehlersituationen vorgenommen. Je - nach verwendeter DVB Karte und Installation der Empfangsanlage kann es bei Unwettern - schon einmal dazu kommen, dass der Empfang nicht nur gestört ist sondern vollständig - zusammen bricht. Einige DVB Karten stellen dann die Datenübertragung ein und sind - nicht von sich aus in der Lage, den Normalbetrieb wieder aufzunehmen. Der VCR.NET - Recording Service erkennt eine solche Situation und versucht dann, die laufenden - Aufzeichnungen zu beenden und nach einer Re-Initialisierung der Hardware neu zu - starten. Bei jedem Versuch wird dann eine neue Aufzeichnungsdatei angelegt - werden - mehrere Versuche dieser Art benötigt, so können auch einige dieser Dateien leer - sein. -
-
- Über die DVB.NET Geräteprofile der verwendeten Hardware - ist es in begrenztem Maße möglich, das Verhalten bei der Dateitrennung zu beeinflussen. -
-
- Schutzeinstellungen
-
- Die Einträge haben in dieser Reihenfolge folgende Bedeutung:
-
    -
  • Das Intervall, in dem geprüft wird, ob noch Daten empfangen werden. Ist dieses zu - klein gewählt, so kann fälschlicherweise ein Neustart der Aufzeichnungen erfolgen - - dadurch können Aufnahmen unbrauchbar werden.
  • -
  • Bisher nicht vorgestellt das Intervall, in dem geprüft wird, ob die Entschlüsselung - einer Quelle erfolgreich ist. Einige CI/CAM Kombinationen erfordern - ein mehrfaches Ansteuern der Entschlüsselungsschnittstelle bis ein stabiler Empfang - gewährleistet ist. Werden in dem angegebenen Intervall keine Daten empfangen, so - startet der VCR.NET Recording Service die betroffene Aufzeichnung neu. Ein zu klein - gewählter Wert kann bei träger CI/CAM Hardware dazu führen, dass die Initialisierung - immer wieder unterbrochen und die Aufnahme unbrauchbar wird.
  • -
  • Ein Intervall in dem wie beschrieben geprüft wird, ob sich Informationen in den - Aufzeichnungsdateien verändert haben. Ist dieser Wert wie in der Voreinstellung - 0 so reagiert der VCR.NET Recording Service unmittelbar auf Veränderung wie dem - Wechsel in ein Lokalfenster des WDR.
  • -
-
-
- - diff --git a/VCR.NET/WebClient41/FAQ/overview.html b/VCR.NET/WebClient41/FAQ/overview.html deleted file mode 100644 index 439eedd..0000000 --- a/VCR.NET/WebClient41/FAQ/overview.html +++ /dev/null @@ -1,103 +0,0 @@ - - - - [Fragment] - - -
-
-

- Wie jede andere Anwendung auch arbeitet der VCR.NET Recording Service nach gewissen - Prinzipien, die man für einen erfolgreichen Einsatz verstanden haben sollte. Letztlich - soll VCR.NET ja genau das tun, was man eigentlich will. Auch wenn die Web Oberfläche - ein intuitives Bedienungskonzept verwendet, so erschließen sich die Funktionalitäten - sicher nicht immer von selbst. Hier im Hilfebereich, der mit dem VCR.NET Recording - Service installiert wird und auch ohne Online Verbindung jederzeit zur Verfügung - steht, sind einige der wesentlichen Aspekte der Bedienung unter Oberbegriffen zusammengefasst. - Zusätzlich findet man in den einzelnen Bereichen der Anwendung oft das kleine Symbol - , über das direkt zu einer passenden - Erklärung gesprungen werden kann. -

-

- In einigen Fällen führen die im Folgenden aufgeführten Verweise unmittelbar - zu entsprechenden Seiten der Web Anwendung. Diese bieten dann die Option an, die gewünschten Erläuterungen direkt - in die Seite einzublenden. -

-

Aufzeichnungen

-
    -
  • Was wird aufgezeichnet?
  • -
  • - Wann kann es mehr als eine Aufzeichnungsdatei für - eine einzige Aufzeichnung geben? -
  • -
  • Welche Aufzeichnungen können gleichzeitig erfolgen?
  • -
  • Warum gibt es Aufträge und Aufzeichnungen?
  • -
  • - Wie geht das mit einer Serienaufzeichnung - und den Ausnahmeregeln? -
  • -
  • Wie wird eine Quelle (ein Sender) für eine Aufzeichnung ausgewählt?
  • -
  • - Wie wird die Programmzeitschrift für die Programmierung von - Aufzeichnungen eingesetzt? -
  • -
  • Wann werden Aufzeichnungen gelöscht und was ist das Archiv?
  • -
  • - Was gibt es bei der Aufzeichnung verschlüsselter Quellen - zu beachten? -
  • -
  • - Wie kommt eine Aufzeichnung zu einem Dateinamen für - die Aufzeichnungsdatei? -
  • -
  • Was fängt man mit einer Aufzeichnungsdatei an?
  • -
  • Wie wird entschieden, welche Aufzeichnung von welcher DVB Karte ausgeführt wird?
  • -
-

Aktivitäten

- -

Hauppauge Nexus / TechnoTrend 2300

-
    -
  • Was ist an dieser DVB Hardware so besonders?
  • -
  • - Wie kann die Aufzeichnungsplanung auf eine bestimmte Anzahl gleichzeitiger Quellen - beschränkt werden? -
  • -
-

Betriebsumgebung und Konfiguration

- -
-
- - diff --git a/VCR.NET/WebClient41/FAQ/parallelrecording.html b/VCR.NET/WebClient41/FAQ/parallelrecording.html deleted file mode 100644 index cdd7864..0000000 --- a/VCR.NET/WebClient41/FAQ/parallelrecording.html +++ /dev/null @@ -1,70 +0,0 @@ - - - - [Fragment] - - -
-
- Selbstverständlich ist es keine Problem unabhängig Aufzeichnungen auf mehreren DVB - Karten zu programmieren, wenn diese dem VCR.NET Recording Service zur Nutzung - zur Verfügung - gestellt wurden. Hier soll allerdings - beschrieben werden, unter welchen Bedingungen es möglich ist, mit einer DVB Hardware - zum gleichen Zeitpunkt mehrere Quellen aufzuzeichnen. -
-
- Zuerst einmal ist festzustellen, dass bei dem digitalen Radio- und Fernsehempfang - die Quellen (Radio- und Fernsehsender) in Gruppen (Transponder, Frequenzen, ...) - empfangen werden. Zur Aufzeichnung einer Quelle muss das DVB Gerät erst einmal die - zugehörige Quellgruppe anwählen - pro Tuner in einer Hardware kann zu jedem Zeitpunkt - immer nur eine Gruppe angesteuert werden, DVB Hardware mit mehreren Tunern präsentiert - sich im Allgemeine als mehrere DVB Geräte. Damit werden dann erst einmal automatisch - alle Quellen dieser Gruppe empfangen. Die Aufzeichnung filtert nun eine dieser Quellen - aus und verwirft alle anderen empfangenen Daten. Hier setzt der VCR.NET Recording - Service bei gleichzeitigen Aufzeichnung an: alle Aufzeichnungen, die Quellen aus - ein und derselben Quellgruppe verwenden, können parallel aufgezeichnet werden. Hier - einmal ein Beispiel aus dem täglichen Leben. Auf einer der Quellgruppen RTL World - werden die Sender RTL, RTL2, VOX, SuperRTL und andere empfangen, analog auf einer - der ProSiebenSat.1 Gruppen ProSieben, Kabel1, SAT.1 und andere. -
-
- Es sollen nun auf einem DVB Gerät folgende Aufzeichnungen programmiert werden:
-
    -
  • RTL am 20. August 2012 von 14:00 bis 16:00
  • -
  • RTL2 am 20. August 2012 von 14:30 bis 15:30
  • -
  • VOX am 20. August 2012 von 15:45 bis 17:30
  • -
- Obwohl sich diese Aufzeichnungen zeitlich überlappen können alle uneingeschränkt - und in voller Länge aufgezeichnet werden. Sollte nun eine weitere Aufzeichnung einer - anderen Quellgruppe hinzugefügt werden, so hat der VCR.NET Recording Service verschiedene - Strategien, die programmierten Wünsche so gut wie möglich zu erfüllen. - Die genauen Regeln - sind etwas komplexer und berücksichtigen neben der programmierten Anfangszeit - der Aufzeichnungen unter anderem auch die mögliche Anzahl vollständig durchgeführter - Aufzeichnungen und den Gesamtverlust verspätet beginnender Aufzeichnungen. -
-
- Zusätzlich zu den drei Aufzeichnungen oben wird nun eine Aufzeichnung auf SAT.1 - am gleichen Tag programmiert, die von 17:00 bis 19:00 durchgeführt werden soll. - Im Zeitraum von 17:00 bis 17:30 gibt es dabei einen Konflikt, bei dem die spätere - Aufzeichnung auf SAT.1 den kürzeren zieht: sie wird verspätet um 17:30 beginnen. -
-
- Etwas anders sieht es aus, wenn die SAT.1 Aufzeichnung um 14:15 beginnen soll - - die Länge von 2 Stunden wird beibehalten, i.e. die Aufzeichnung endet um 16:15. - Hier werden erst einmal die Aufzeichnungen auf RTL und RTL2 in voller Länge durchgeführt - - vor allem aufgrund des frühestens Startzeitpunktes der RTL Programmierung und - der Tatsache, dass die RTL2 Aufzeichnung verlustfrei nebenher laufen kann. Danach - folgen die letzten 15 Minuten der SAT.1 Aufzeichnung, die also deutlich verspätet - beginnen wird. Aufgrund des Startzeitpunktes wandert die VOX Aufnahme ganz ans Ende - und kann erst nach der SAT.1 Aufzeichnung um 16:15 beginnen - es fehlt also eine - halbe Stunde. -
-
- Das Ergebnis einer Planung wird im Aufzeichnungsplan - durch entsprechende farbige Symbole dargestellt. -
-
- - diff --git a/VCR.NET/WebClient41/FAQ/psi.png b/VCR.NET/WebClient41/FAQ/psi.png deleted file mode 100644 index 99188ff..0000000 Binary files a/VCR.NET/WebClient41/FAQ/psi.png and /dev/null differ diff --git a/VCR.NET/WebClient41/FAQ/psiconfig.html b/VCR.NET/WebClient41/FAQ/psiconfig.html deleted file mode 100644 index 2f2dbf8..0000000 --- a/VCR.NET/WebClient41/FAQ/psiconfig.html +++ /dev/null @@ -1,65 +0,0 @@ - - - - [Fragment] - - -
-
- Zur Programmierung von Aufzeichnungen bietet der VCR.NET Recording Service für jedes - DVB Gerät die Quellen (Sender) an, die im zugehörigen - DVB.NET Geräteprofil hinterlegt sind. Diese Liste ändert - sich je nach Empfangsart von Zeit zu Zeit und es macht dann Sinn, eine Aktualisierung - durchzuführen. Das kann manuell mit dem DVB.NET Konfigurations- und Administrationswerkzeug - geschehen - in diesem Fall wird empfohlen, den VCR.NET Recording Service für den - Zeitraum der Aktualisierung zu beenden.
-
- Alternativ ist es aber auch möglich, dem VCR.NET Recording Service dafür einzurichten, - für alle DVB Geräte eine entsprechende Aktualisierung - periodisch auszuführen.
-
- Aktualisierung konfigurieren
-
- Im Endeffekt erfolgt die Konfiguration ganz analog zur Programmzeitschrift. - Die Aktualisierung kann gänzlich deaktiviert werden, nur manuell erfolgen oder wie - im Bild gezeigt einem Zeitplan folgen. Zuerst einmal erfolgt die Angabe der vollen - Stunden, an denen eine Aktualisierung stattfinden darf - je nach Planung - der Aufzeichnungen kann dieser Zeitpunkt auch nach hinten geschoben werden, da Sonderaufgaben wie die Aktualisierung der Liste der Quellen - eine niedrigere Priorität als reguläre Aufzeichnungen haben. Es macht hier durchaus - Sinn, mindestens zwei Zeiten zu verwenden, wobei die eine im Nachtbereich und die - andere tagsüber liegt, da es eine ganze Reihe von Quellen gibt, die nur zeitweise - verfügbar sind.
-
- Zusätzlich wird festgelegt, wie viel Zeit zwischen zwei Aktualisierungen verstreichen - soll. Im Allgemeinen sollte eine Aktualisierung alle ein bis vier Wochen reichen - - es ist auch bei einer periodischen Aktualisierung bei Bedarf jederzeit möglich, - eine manuelle Aktualisierung anzufordern. -
-
- Die Angabe der maximalen Laufzeit erlaubt es dem VCR.NET Recording Service die Aktualisierung - im Aufzeichnungsplan zu berücksichtigen. Ist dieser Wert zu klein gewählt, so wird - die Aktualisierung vorzeitig beendet und es werden eventuell nicht alle Neuerungen - übernommen. Diesbezüglich ist ein zu großer Wert kein Problem, da die Aktualisierung - dann einfach zu früh beendet wird. Es wird aber empfohlen, immer einen sinnvollen - Erfahrungswert zu verwenden, der knapp über dem tatsächlichen Bedürfnis liegt - - dieser Wert kann den Protokollen entnommen werden.
-
- Normalerweise wird die neue Liste mit der vorherigen zusammen geführt. Das ist gerade - für Quellen wichtig, die nicht ständig verfügbar, da ansonsten nur die Quellen für - eine Programmierung verwendet werden können, die gerade zum Zeitpunkt der Aktualisierung - aktiv waren. Manchmal allerdings haben sich in der Liste der Quellen so viele Leichen - nicht mehr existierender oder verschobener Quellen angesammelt, dass sich eine vollständige - Bereinigung lohnt. In diesem Fall sollte die Markierung der Option entfernt, eine - neue Aktualisierung manuell gestartet und danach die Markierung wieder hergestellt - werden.
-
- Genau wie bei der Programmzeitschrift gibt es auch bei der Aktualisierung der Liste - der Quellen einen optionalen Wert für die Latenzzeit, hier allerdings in Tagen. - Diese Einstellung erlaubt es dem VCR.NET Recording Service eine Aktualisierung vorzuziehen, - wenn gerade ein Übergang in den Schlafzustand bevor steht und seit der vorherige Aktualisierung - das konfigurierte Zeitintervall bereits überschritten wurde.
-
-
- - diff --git a/VCR.NET/WebClient41/FAQ/recover.png b/VCR.NET/WebClient41/FAQ/recover.png deleted file mode 100644 index 850d061..0000000 Binary files a/VCR.NET/WebClient41/FAQ/recover.png and /dev/null differ diff --git a/VCR.NET/WebClient41/FAQ/repeating.png b/VCR.NET/WebClient41/FAQ/repeating.png deleted file mode 100644 index 1dfaf65..0000000 Binary files a/VCR.NET/WebClient41/FAQ/repeating.png and /dev/null differ diff --git a/VCR.NET/WebClient41/FAQ/repeatingschedules.html b/VCR.NET/WebClient41/FAQ/repeatingschedules.html deleted file mode 100644 index 629e37f..0000000 --- a/VCR.NET/WebClient41/FAQ/repeatingschedules.html +++ /dev/null @@ -1,53 +0,0 @@ - - - - [Fragment] - - -
-
- Für eine Aufzeichnung kann angegeben werden, ob diese periodisch wiederholt werden - soll. Der VCR.NET Recording Service bietet hier die Möglichkeit, die Wochentage - auszuwählen, an denen die Aufzeichnung durchgeführt werden soll - die jeweilige - Uhrzeit wird dabei beibehalten. Ergänzend kann der Tag angegeben werden, an dem - die Aufzeichnung letztmalig auszuführen ist - ohne diese Einstellung wird die Aufzeichnung - unbegrenzt wiederholt. Diese Eingabe ist nur möglich, wenn mindestens ein Wochentag - zur Wiederholung aktiviert ist. -
-
- Serienaufzeichnung -
-
- Als Besonderheit ist zu erwähnen, dass nur die Kombination aus dem Zeitpunkt - der ersten Aufzeichnung und den gewählten Wochentagen die Tage der Aufzeichnung - festlegt. Würde im gezeigten Beispiel als erster Zeitpunkt etwa der 11. Januar 2013 - gewählt, so würde die erste Aufzeichnung am 17. Januar 2013 erfolgen, da der Freitag - kein gültiger Aufzeichnungstag ist. -
-
- Bei sich wiederholenden Ausstrahlungen ist es oft so, dass diese nicht immer - zum exakt gleichen Zeitpunkt stattfinden. Kleinere Abweichungen lassen sich durch - vergrößerte Vor- und Nachlaufzeiten kompensieren. Manchmal kann es aber durch Sondersendungen - vor der gewünschten Ausstrahlung einmalig zu deutlichen Verschiebungen kommen. Der - VCR.NET Recording Service bietet hier im Aufzeichnungsplan - die Möglichkeit, Ausnahmeregelungen für die einzelnen Aufzeichnungstage zu definieren. Dabei - kann der Startzeitpunkt verschoben oder die Laufzeit und damit das Ende der Aufzeichnung - pro geplanter Aufzeichnung individuell verändert werden - auf Wunsch kann auch eine Aufzeichnung ganz - entfallen. -
-
- Ausnahmeregelung
-
- Wurde eine Aufzeichnung auf diesem Weg aus dem Aufzeichnungsplan entfernt, so kann sie nur über die - direkte Pflege der Aufzeichnung wieder aktiviert werden. Dazu ist die entsprechende Markierung in - der Liste der aktiven Ausnahmen zu entfernen und dann die Änderung zu bestätigen. Dieses - Vorgehen kann auch zur Wiederherstellung der ursprünglichen Planung verwendet werden, wenn nur eine - einfache Ausnahme definiert worden ist - das ginge allerdings auch direkt aus dem Aufzeichnungsplan - heraus. -
-
- Ausnahmeregelung entfernen -
-
- - diff --git a/VCR.NET/WebClient41/FAQ/sendtonetwork.png b/VCR.NET/WebClient41/FAQ/sendtonetwork.png deleted file mode 100644 index 6f75809..0000000 Binary files a/VCR.NET/WebClient41/FAQ/sendtonetwork.png and /dev/null differ diff --git a/VCR.NET/WebClient41/FAQ/sourcechooser.html b/VCR.NET/WebClient41/FAQ/sourcechooser.html deleted file mode 100644 index 55c0151..0000000 --- a/VCR.NET/WebClient41/FAQ/sourcechooser.html +++ /dev/null @@ -1,59 +0,0 @@ - - - - [Fragment] - - -
-
- Jedes DVB Gerät kann bestimmte Quellen (Radio- und Fernsehsender) empfangen. Die - Anzahl dieser Quellen kann erheblich sei: für Astra 1 auf 19.2° Ost sind es mehr als - 1.000 verschiedene Quellen, aus denen ausgewählt werden kann. Der VCR.NET Recording - Service kennt zwar kein Favoritensystem wie es bei Fernsehern üblich ist, bietet - aber einige andere Möglichkeiten an, die bei der Auswahl der benötigten Quelle helfen - sollten.
-
- Quelle auswählen
-
- Abhängig von der zweiten Auswahlliste wird die Liste der Quellen links daneben wie - folgt beschränkt - in der Reihenfolge der Einträge der im Bild geöffnet gezeigten - Liste:
-
    -
  • Interessant ist die Voreinstellung der ersten Auswahlliste direkt neben dem Namen der Quelle. Bei - dieser Auswahl werden die zuletzt verwendeten Quellen in alphabetischer Anordnung - angezeigt - jeder Anwender kann individuell festlegen, - wie viele Quellen die Liste maximal enthalten darf. Nach einiger gewissen Nutzungszeit - des VCR.NET Recording Service zeigt sich im Allgemeinen, dass diese Liste fast immer - die gewünschte Quelle enthält. Ist die Liste leer, so werden automatisch alle möglichen - Quellen zur Auswahl angeboten.
  • -
  • Da meistens der Name der gewünschten Quelle bekannt ist kann alternativ der Einstieg - auch über den ersten Buchstaben des Namens der Quelle erfolgen. Der Übersichtlichkeit - halber erfolgt die Unterteilung nicht auf Basis einzelner Buchstaben sondern auf - einer Gruppierung von im Allgemeinen drei aufeinanderfolgenden Buchstaben.
  • -
  • Es werden im Prinzip alle verfügbaren Quellen angezeigt. Mit den beiden Auswahllisten - rechts ist es dann noch möglich, sich auf Fernseh- oder Radiosender sowie - verschlüsselte respektive unverschlüsselte Quellen zu beschränken.
  • -
- Die Liste der zuletzt verwendeten Quellen hat bei der Auswahl eine weitere Besonderheit: - in diesem Auswahlmodus werden keine weiteren Auswahllisten zur Einschränkung der - angezeigten Quellen angeboten. Das macht im Allgemeinen auch Sinn, da die Anzahl der - Quellen in der Liste beschränkt ist. -
-
- Interessant wird es aber, wenn eine andere Auswahlmöglichkeit verwendet wird. Hier - erscheinen nun zwei weitere Auswahllisten, wie oben im Bild auch gezeigt: -
    -
  • Es ist möglich, nur Radio- oder nur Fernsehsender zur Auswahl anzubieten - oder - einfach alle Quellen, aber im Allgemeinen weiß man ja, was man programmieren möchte. - Auch diese Voreinstellung ist individuell konfigurierbar.
  • -
  • Die Quellen können auf verschlüsselte und unverschlüsselte Quellen beschränkt werden - - die Beschränkung kann auch jederzeit wiederrufen werden. Die Voreinstellung kann - jeder Anwender für sich frei wählen.
  • -
- Wird in einer Aufzeichnung keine Quelle angegeben, so wird die Quelle des Auftrags - verwendet. Ist auch diese nicht definiert, so kann die Programmierung - nicht erfolgreich abgeschlossen werden. -
-
- - diff --git a/VCR.NET/WebClient41/FAQ/sourcelimit.html b/VCR.NET/WebClient41/FAQ/sourcelimit.html deleted file mode 100644 index 33035e7..0000000 --- a/VCR.NET/WebClient41/FAQ/sourcelimit.html +++ /dev/null @@ -1,37 +0,0 @@ - - - - [Fragment] - - -
-
- Die Planung des VCR.NET Recording Service erwartet, dass im Normalfall auf jedem - DVB Gerät beliebige viele Aufzeichnungen einer Quellgruppe gleichzeitig - ausgeführt werden können. In gewissen Situation ist dies allerdings - nicht empfehlenswert oder bei bestimmter DVB Hardware auch - gar nicht möglich. -
-
- Über die Aufzeichnungseinstellung im zugehörigen DVB.NET Geräteprofil ist es möglich, - die Anzahl der gleichzeitig verwendeten Quellen zu beschränken. Der VCR.NET Recording - Service wird dann davon ausgehen, dass nur die angegeben Anzahl unterschiedlicher - Quellen einer Quellgruppe gleichzeitig verwendet werden dürfen - mehrere Aufzeichnung - auf ein und derselben Quelle sind von dieser Einschränkung natürlich nicht betroffen.
-
- Quellen beschränken
-
- Im Allgemeinen macht es aber wenig Sinn, diesen Wert von der Voreinstellung (15) - weg zu verändern. Vor allem unterscheidet der VCR.NET Recording Service nicht zwischen - Fernseh- und Radiosendern. Selbst wenn eine Aufzeichnung von zwei bis drei Fernsehsendern - an die Grenzen einer DVB Hardware stößt kann es trotzdem sein, dass 8 Radiosender - ohne Probleme gleichzeitig aufgezeichnet werden können. Den Wert höher als die Voreinstellung - zu setzen sollte auch in den wenigsten Situationen notwendig sein.
-
- Insgesamt kann nur empfohlen werden, die Einstellung nicht zu verändern und den - gesunden Menschenverstand auch bei der Programmierung von Aufzeichnungen sinnvoll - zu nutzen. -
-
- - diff --git a/VCR.NET/WebClient41/FAQ/sourcelimit.png b/VCR.NET/WebClient41/FAQ/sourcelimit.png deleted file mode 100644 index 3d30008..0000000 Binary files a/VCR.NET/WebClient41/FAQ/sourcelimit.png and /dev/null differ diff --git a/VCR.NET/WebClient41/FAQ/sources.png b/VCR.NET/WebClient41/FAQ/sources.png deleted file mode 100644 index 8058a8a..0000000 Binary files a/VCR.NET/WebClient41/FAQ/sources.png and /dev/null differ diff --git a/VCR.NET/WebClient41/FAQ/streaming.html b/VCR.NET/WebClient41/FAQ/streaming.html deleted file mode 100644 index da70e5d..0000000 --- a/VCR.NET/WebClient41/FAQ/streaming.html +++ /dev/null @@ -1,40 +0,0 @@ - - - - [Fragment] - - -
-
- Laufen Aufzeichnungen, - so erlaubt es der VCR.NET Recording - Service auch, die Aufzeichnungsdateien an eine Netzwerkadresse - zu senden. Übertragen wird dabei genau der Inhalt der Aufzeichnungsdatei. Dieses - Format wird außer von dem DVB.NET / VCR.NET Viewer - auch von anderen Media Player Anwendungen wie VLC verstanden und kann zur Anzeige verwendet werden. - Bei Benutzung des DVB.NET / VCR.NET Viewers übernimmt dieser alle notwendigen Maßnahmen - zur Steuerung des Netzwerkversands.
-
- Netzwerkversand
-
- Ist auf dem Rechner, von dem aus die Web Oberfläche aufgerufen wurde, der DVB.NET - / VCR.NET Viewer lokal installiert, so kann dieser über den ersten Verweis - gestartet werden, wobei die Wiedergabe der aktuellen Aufzeichnung - erfolgt. Der zweite Verweis handelt analog, startet allerdings die Wiedergabe - am Anfang der Aufzeichnungsdatei - im Viewer ist es im Allgemeinen über die Stern-Taste auf dem Nummernfeld der Tastatur möglich - zwischen diesen Anzeigealternativen zu wechseln.
-
- Werden die Daten einer Aufzeichnung gerade versendet, so zeigt der VCR.NET Recording - Service wie oben im Bild die Netzwerkadresse des Empfängers der Daten an. -
-
- Man beachte, dass für einen Empfang der über Netzwerk versendeten Daten im Allgemeinen - eine Systemkonfiguration vorgenommen werden muss, wenn der VCR.NET Recording Service - nicht auf dem Rechner läuft, der auch die empfangenen Daten darstellen soll. Dies - betrifft vor allem die Einstellungen der Firewalls auf allen beteiligten Netzwerkkomponenten. -
-
- - diff --git a/VCR.NET/WebClient41/FAQ/streamoptions.png b/VCR.NET/WebClient41/FAQ/streamoptions.png deleted file mode 100644 index 1301639..0000000 Binary files a/VCR.NET/WebClient41/FAQ/streamoptions.png and /dev/null differ diff --git a/VCR.NET/WebClient41/FAQ/tasks.html b/VCR.NET/WebClient41/FAQ/tasks.html deleted file mode 100644 index 8e3317f..0000000 --- a/VCR.NET/WebClient41/FAQ/tasks.html +++ /dev/null @@ -1,69 +0,0 @@ - - - - [Fragment] - - -
-
- Neben der Ausführung der vom Anwender programmierten Aufzeichnungen kann der VCR.NET - Recording Service die DVB Hardware auch für andere Zwecke nutzen. -
-
- Zum einen sind da die konfigurierbaren periodischen Aufgaben zur Aktualisierung - von Programmzeitschrift und der Liste der verfügbaren Quellen. - Bei der Aktualisierung der Programmzeitschrift - wird für ausgewählte Quellen die von den Sendeanstalten angebotene elektronische Programmzeitschrift - (EPG) ausgewertet und für die spätere - Programmierung von Aufzeichnungen zusammengeführt. Bei der Aktualisierung der Liste - der Quellen (Sendersuchlauf) wird für jedes relevante DVB Gerät geprüft, welche - Quellen grundsätzlich empfangen werden können. - Je nach Konfiguration im zugehörigen DVB.NET Geräteprofil können auf diese Weise - auch neu bereitgestellte Quellen ohne weiteres Zutun erkannt werden. -
-
- Zum anderen ist es möglich, für jedes DVB Gerät den so genannten Live Modus - zu aktivieren. Ähnlich wie bei einer einzelnen Aufzeichnung wird dabei eine Quelle - angewählt. Allerdings wird keine Aufzeichnungsdatei erstellt, sondern es werden - vielmehr die Informationen, die eigentlich in einer solchen abgelegt würden, an - eine Netzwerkadresse versendet. Diverse frei verfügbare Programme - wie VLC können einen so erzeugten Datenstrom empfangen und darstellen. Speziell - für diese Aufgabe entwickelt wurde der DVB.NET / VCR.NET Viewer. Dieser kann die Informationen - nicht nur als Bild und Ton visualisieren, sondern auch den VCR.NET Recording Service - dazu bewegen, die Quelle nach Wunsch des Anwenders zu ändern. Der Viewer ist damit - vergleichbar mit einem primitiven Fernseher, der als Empfängereinheit jedes DVB - Gerät nutzen kann, das auch dem VCR.NET Recording Service zur Verfügung steht. -
-
- Bei der Planung von Aufzeichnungen haben periodische Aufgaben grundsätzlich eine - geringere Priorität als programmierte Aufzeichnungen. Würden sich etwa eine Aktualisierung - und eine Aufzeichnung überschneiden, so wird die Aktualisierung so lange verschoben, - bis ein ausreichendes Zeitfenster für die Durchführung gefunden wurde. Etwas anders - sieht es allerdings aus, wenn bereits eine Aktualisierung aktiv ist. Wird im Zeitraum - der Aktualisierung eine neue Aufzeichnung hinzugefügt und überschneidet sich diese - mit der laufenden Aktualisierung, so wird die Aufzeichnung verzögert beginnen: eine - einmal gestartete Aktualisierung wird nicht zwangsweise beendet um einer Aufzeichnung - Platz zu machen. -
-
- Der Live Modus kann in der Planung natürlich grundsätzlich nicht berücksichtigt - werden. Soll eine Aufzeichnung stattfinden, so wird ein aktiver Live Modus - automatisch beendet. Darüber hinaus ist es sogar nicht möglich, in den Live - Modus zu wechseln, wenn eine neue Aufzeichnung in naher Zukunft beginnen - würde. Gegenüber den Aktualisierungen hat der Live Modus allerdings Vorrang: - es kann in den Live Modus gewechselt werden, selbst wenn eine Aktualisierung - unmittelbar bevorsteht. Soll eine Aktualisierung stattfinden, während der Live - Modus verwendet wird, so wird diese nach hinten verschoben, bis der Live - Modus beendet wird. Während einer laufenden Aufzeichnung oder Aktualisierung steht - der Live Modus grundsätzlich nicht zur Verfügung. -
-
- Anders als bei Aufzeichnungen nutzt der Live Modus ein DVB Gerät immer - exklusiv. Es ist daher nicht wie bei parallelen Aufzeichnungen - möglich zwei Quellen der gleichen Gruppe im Live Modus an zwei Empfänger - zur Anzeige zu schicken. -
-
- - diff --git a/VCR.NET/WebClient41/FAQ/tsplayer.html b/VCR.NET/WebClient41/FAQ/tsplayer.html deleted file mode 100644 index b5c9e22..0000000 --- a/VCR.NET/WebClient41/FAQ/tsplayer.html +++ /dev/null @@ -1,31 +0,0 @@ - - - - [Fragment] - - -
-
- Der VCR.NET Recording Service erstellt Aufzeichnungsdateien - im TS (Transport Stream) Format. Obwohl es sich nicht um ein Standardformat - von Windows handelt, kann es von den meisten Media Playern direkt angezeigt werden - - in einigen Fällen sogar von der Windows eigenen Anwendung. Erwähnenswert ist an - dieser Stelle vor allem der kostenlose VLC - Media Player, mit dem auch ergänzende Informationen wie der Videotext - angezeigt werden können - natürlich nur wenn ein solcher auch aufgezeichnet wurde.
-
- Für die Nachbearbeitung um etwa eine Aufzeichnung auf einer DVD zu verewigen erwarten - viele Autorenwerkzeuge keine einzelne Datei sondern vielmehr separate Dateien für - die einzelnen Inhalte wie Bild oder Ton. Manche Werkzeuge haben eine solche Zerlegung - fest integriert, kostenlose Anwendungen wie die Kombination aus Cuttermaran und GfD - hingegen erwarten, dass diese im Vorfeld geschieht. Auch hier gibt - es kostenlose Alternativen wie ProjectX oder PVStrumento, - die nicht nur eine solche Zerlegung vornehmen, sondern - dabei auch gleichzeitig den Inhalt der Aufzeichnungsdatei auf Fehler prüfen und - einfache Korrekturen vornehmen. -
-
- - diff --git a/VCR.NET/WebClient41/FAQ/webserver.png b/VCR.NET/WebClient41/FAQ/webserver.png deleted file mode 100644 index 66f6cc2..0000000 Binary files a/VCR.NET/WebClient41/FAQ/webserver.png and /dev/null differ diff --git a/VCR.NET/WebClient41/FAQ/websettings.html b/VCR.NET/WebClient41/FAQ/websettings.html deleted file mode 100644 index b0cd41b..0000000 --- a/VCR.NET/WebClient41/FAQ/websettings.html +++ /dev/null @@ -1,72 +0,0 @@ - - - - [Fragment] - - -
-
- Der VCR.NET Recording Service enthält einen Web Server, der über das - HTTP Protokoll sowohl einen Web Client als auch REST Web Dienste anbietet. Der Web - Client, in dem diese Erläuterungen in diesem Moment angezeigt werden, wird durch einen Internet - Browser aufgerufen und erlaubt die interaktive Steuerung und Überwachung des VCR.NET - Recording Service. Die REST Web Dienste werden von Programmen wie dem VCR.NET Kontrollzentrum - verwendet, um diese Aufgaben direkt aus einer Anwendung heraus vorzunehmen.
-
- Damit der Web Server auf Anfragen reagieren kann, müssen einige Einstellungen - korrekt vorgenommen werden. VCR.NET - wurde ursprünglich für den Betrieb in einem lokalen (LAN) Windows Netzwerk entwickelt. - Für diese Nutzung muss lediglich der TCP/IP Port für das HTTP Protokoll festgelegt - werden, üblicherweise wird hier Port 80 verwendet, was auch der Voreinstellung nach - der Erstinstallation entspricht. Zusätzlich erwartet VCR.NET, dass zur Benutzererkennung - die in Windows integrierten Sicherheitsprotokolle verwendet werden. Alle mit VCR.NET - ausgelieferten Werkzeuge wie das Kontrollzentrum nutzen entsprechende Mechanismen.
-
- Web Server Konfiguration
-
- Leider erfordern es die Windows eigenen Sicherheitsprotokolle, dass etwa zwischen - einem Internet Browser, der den Web Client aufruft, und dem VCR.NET Server nicht - nur eine Kommunikation über den konfigurierten TCP/IP Port möglich ist sondern dass - vielmehr weitere elementare TCP/IP Ports zwischen Client und Server freigeschaltet - werden. Ist dies in einem LAN üblicherweise problemlos möglich, so ist eine Freischaltung - über Firewalls hinaus eher unüblich. Soll etwa auf den VCR.NET Web Client aus dem - Internet heraus zugegriffen werden, so ist eine Benutzererkennung auf diesem Wege - im Allgemeinen nicht möglich.
-
- Andere Verfahren zur Benutzererkennung bieten allerdings die Option, ausschließlich - eine HTTP Port zwischen Client und Server zu nutzen. Das wichtigste ist das Basic - Protokoll, das von allen Browsern unterstützt wird. Leider hat gerade dieser Standardmechanismus - die entscheidende Schwäche, dass das Kennwort des Anwenders quasi im Klartext zwischen - Client und Server ausgetauscht wird. Sind Client und Server nicht identische Rechner, - so kann dieses Kennwort durch Abhören der Netzwerkkommunikation in falsche Hände - geraten. Der VCR.NET Recording Service erlaubt trotzdem die Nutzung dieses Protokolls - ergänzend zur Benutzererkennung über die Windows eigenen Mechanismen, allerdings - wird von einer alleinigen Aktivierung dieser Möglichkeit abgeraten. Alle VCR.NET - Werkzeuge nutzen wie erwähnt immer die sichere Benutzererkennung.
-
- Aufgrund der mangelnden Sicherheit wird eine Benutzererkennung über das Basic Protokoll - oft an eine verschlüsselte HTTP Verbindung gebunden. Hier erfolgt der Aufruf des - Web Clients aus dem Internet Browser heraus über das HTTPS Präfix, wodurch dann - die Kommunikation zwischen Client und Server mittels SSL verschlüsselt wird. Der - VCR.NET Recording Service erlaubt es, zusätzlich zur regulären Konfiguration über - HTTP auch diesen Weg freizuschalten. In diesem Fall muss ein weiterer TCP/IP Port - festgelegt werden, auf den der Web Server im VCR.NET Recording Service bei verschlüsselten - Verbindungen reagieren soll. Voreigestellt ist hier als Standard der Port 443.
-
- Die Konfiguration des VCR.NET Recording Service bietet allerdings weder die Möglichkeit, - ein SSL Zertifikat zu erstellen noch ein existierendes zur Verschlüsselung der - Kommunikation zu nutzen. Diese Zuordnung muss einmalig gesondert manuell vorgenommen - werden - unter Windows 7 übernimmt der netsh http add sslcert den entscheidenden - Schritt, eine SSL Zertifikat auf dem in der VCR.NET Konfiguration festgelegten TCP/IP - Port zu nutzen. Erst nach dieser Zuordnung kann VCR.NET die Zugriffe auf die Web - Dienste wie gewünscht verschlüsseln.
-
- Wie auch bei der Benutzererkennung ignorieren alle VCR.NET Werkzeuge diese Einstellungen - und können daher nur im lokalen Windows Netzwerk eingesetzt werden. Das gilt vor - allem auch für den VCR.NET / DVB.NET Viewer : - das Betrachten von laufenden Aufzeichnungen etwa - ist über einen Internet Zugang grundsätzlich nicht möglich. -
-
- - diff --git a/VCR.NET/WebClient41/Properties/AssemblyInfo.cs b/VCR.NET/WebClient41/Properties/AssemblyInfo.cs index 306313e..df97b82 100644 --- a/VCR.NET/WebClient41/Properties/AssemblyInfo.cs +++ b/VCR.NET/WebClient41/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion( "4.3.0.0" )] -[assembly: AssemblyFileVersion( "4.3.0.0" )] +[assembly: AssemblyVersion( "4.5.0.0" )] +[assembly: AssemblyFileVersion( "4.5.0.0" )] diff --git a/VCR.NET/WebClient41/Web.config b/VCR.NET/WebClient41/Web.config index 0f11f1e..55f49ee 100644 --- a/VCR.NET/WebClient41/Web.config +++ b/VCR.NET/WebClient41/Web.config @@ -4,6 +4,10 @@ + + + + diff --git a/VCR.NET/WebClient41/WebClient41.csproj b/VCR.NET/WebClient41/WebClient41.csproj index 5c0a38c..565eafa 100644 --- a/VCR.NET/WebClient41/WebClient41.csproj +++ b/VCR.NET/WebClient41/WebClient41.csproj @@ -1,5 +1,6 @@  + Debug @@ -20,6 +21,10 @@ enabled false + + + + 3.7 true @@ -33,6 +38,17 @@ true true false + React + True + False + AMD + True + scripts/vcrnet.js + + False + True + + pdbonly @@ -45,6 +61,17 @@ true true false + React + True + False + AMD + True + scripts/vcrnet.js + + False + True + + @@ -75,200 +102,336 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - jmslib.less - - - jmslib.less - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - jmslib.ts - - - - jmslib.css - - - vcrnet.css - - - - - - - - - - vcrnet.ts - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - vcrnet.less + + + + + + + + + + styles.scss - - - vcrnet.less - + + + vcrnet.js + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Designer + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - vcrserver.ts - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Designer - - - vcrnet.ts - - - jmslib.ts - - - vcrserver.ts - Web.config @@ -295,15 +458,7 @@ - True - True - 50324 - / - http://localhost:49897/ - False - False - http://localhost:81 - False + True @@ -312,6 +467,17 @@ + + ..\..\node_modules\.bin\gulp sass + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + |EventPluginHub| | Event | + * | | . | | +-----------+ | Propagators| + * | ReactEvent | . | | |TapEvent | |------------| + * | Emitter | . | |<---+|Plugin | |other plugin| + * | | . | | +-----------+ | utilities | + * | +-----------.--->| | +------------+ + * | | | . +--------------+ + * +-----|------+ . ^ +-----------+ + * | . | |Enter/Leave| + * + . +-------+|Plugin | + * +-------------+ . +-----------+ + * | application | . + * |-------------| . + * | | . + * | | . + * +-------------+ . + * . + * React Core . General Purpose Event Plugin System + */ + +var alreadyListeningTo = {}; +var isMonitoringScrollValue = false; +var reactTopListenersCounter = 0; + +// For events like 'submit' which don't consistently bubble (which we trap at a +// lower node than `document`), binding at `document` would cause duplicate +// events so we don't include them here +var topEventMapping = { + topAbort: 'abort', + topBlur: 'blur', + topCanPlay: 'canplay', + topCanPlayThrough: 'canplaythrough', + topChange: 'change', + topClick: 'click', + topCompositionEnd: 'compositionend', + topCompositionStart: 'compositionstart', + topCompositionUpdate: 'compositionupdate', + topContextMenu: 'contextmenu', + topCopy: 'copy', + topCut: 'cut', + topDoubleClick: 'dblclick', + topDrag: 'drag', + topDragEnd: 'dragend', + topDragEnter: 'dragenter', + topDragExit: 'dragexit', + topDragLeave: 'dragleave', + topDragOver: 'dragover', + topDragStart: 'dragstart', + topDrop: 'drop', + topDurationChange: 'durationchange', + topEmptied: 'emptied', + topEncrypted: 'encrypted', + topEnded: 'ended', + topError: 'error', + topFocus: 'focus', + topInput: 'input', + topKeyDown: 'keydown', + topKeyPress: 'keypress', + topKeyUp: 'keyup', + topLoadedData: 'loadeddata', + topLoadedMetadata: 'loadedmetadata', + topLoadStart: 'loadstart', + topMouseDown: 'mousedown', + topMouseMove: 'mousemove', + topMouseOut: 'mouseout', + topMouseOver: 'mouseover', + topMouseUp: 'mouseup', + topPaste: 'paste', + topPause: 'pause', + topPlay: 'play', + topPlaying: 'playing', + topProgress: 'progress', + topRateChange: 'ratechange', + topScroll: 'scroll', + topSeeked: 'seeked', + topSeeking: 'seeking', + topSelectionChange: 'selectionchange', + topStalled: 'stalled', + topSuspend: 'suspend', + topTextInput: 'textInput', + topTimeUpdate: 'timeupdate', + topTouchCancel: 'touchcancel', + topTouchEnd: 'touchend', + topTouchMove: 'touchmove', + topTouchStart: 'touchstart', + topVolumeChange: 'volumechange', + topWaiting: 'waiting', + topWheel: 'wheel' +}; + +/** + * To ensure no conflicts with other potential React instances on the page + */ +var topListenersIDKey = '_reactListenersID' + String(Math.random()).slice(2); + +function getListeningForDocument(mountAt) { + // In IE8, `mountAt` is a host object and doesn't have `hasOwnProperty` + // directly. + if (!Object.prototype.hasOwnProperty.call(mountAt, topListenersIDKey)) { + mountAt[topListenersIDKey] = reactTopListenersCounter++; + alreadyListeningTo[mountAt[topListenersIDKey]] = {}; + } + return alreadyListeningTo[mountAt[topListenersIDKey]]; +} + +/** + * `ReactBrowserEventEmitter` is used to attach top-level event listeners. For + * example: + * + * ReactBrowserEventEmitter.putListener('myID', 'onClick', myFunction); + * + * This would allocate a "registration" of `('onClick', myFunction)` on 'myID'. + * + * @internal + */ +var ReactBrowserEventEmitter = assign({}, ReactEventEmitterMixin, { + + /** + * Injectable event backend + */ + ReactEventListener: null, + + injection: { + /** + * @param {object} ReactEventListener + */ + injectReactEventListener: function (ReactEventListener) { + ReactEventListener.setHandleTopLevel(ReactBrowserEventEmitter.handleTopLevel); + ReactBrowserEventEmitter.ReactEventListener = ReactEventListener; + } + }, + + /** + * Sets whether or not any created callbacks should be enabled. + * + * @param {boolean} enabled True if callbacks should be enabled. + */ + setEnabled: function (enabled) { + if (ReactBrowserEventEmitter.ReactEventListener) { + ReactBrowserEventEmitter.ReactEventListener.setEnabled(enabled); + } + }, + + /** + * @return {boolean} True if callbacks are enabled. + */ + isEnabled: function () { + return !!(ReactBrowserEventEmitter.ReactEventListener && ReactBrowserEventEmitter.ReactEventListener.isEnabled()); + }, + + /** + * We listen for bubbled touch events on the document object. + * + * Firefox v8.01 (and possibly others) exhibited strange behavior when + * mounting `onmousemove` events at some node that was not the document + * element. The symptoms were that if your mouse is not moving over something + * contained within that mount point (for example on the background) the + * top-level listeners for `onmousemove` won't be called. However, if you + * register the `mousemove` on the document object, then it will of course + * catch all `mousemove`s. This along with iOS quirks, justifies restricting + * top-level listeners to the document object only, at least for these + * movement types of events and possibly all events. + * + * @see http://www.quirksmode.org/blog/archives/2010/09/click_event_del.html + * + * Also, `keyup`/`keypress`/`keydown` do not bubble to the window on IE, but + * they bubble to document. + * + * @param {string} registrationName Name of listener (e.g. `onClick`). + * @param {object} contentDocumentHandle Document which owns the container + */ + listenTo: function (registrationName, contentDocumentHandle) { + var mountAt = contentDocumentHandle; + var isListening = getListeningForDocument(mountAt); + var dependencies = EventPluginRegistry.registrationNameDependencies[registrationName]; + + var topLevelTypes = EventConstants.topLevelTypes; + for (var i = 0; i < dependencies.length; i++) { + var dependency = dependencies[i]; + if (!(isListening.hasOwnProperty(dependency) && isListening[dependency])) { + if (dependency === topLevelTypes.topWheel) { + if (isEventSupported('wheel')) { + ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(topLevelTypes.topWheel, 'wheel', mountAt); + } else if (isEventSupported('mousewheel')) { + ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(topLevelTypes.topWheel, 'mousewheel', mountAt); + } else { + // Firefox needs to capture a different mouse scroll event. + // @see http://www.quirksmode.org/dom/events/tests/scroll.html + ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(topLevelTypes.topWheel, 'DOMMouseScroll', mountAt); + } + } else if (dependency === topLevelTypes.topScroll) { + + if (isEventSupported('scroll', true)) { + ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(topLevelTypes.topScroll, 'scroll', mountAt); + } else { + ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(topLevelTypes.topScroll, 'scroll', ReactBrowserEventEmitter.ReactEventListener.WINDOW_HANDLE); + } + } else if (dependency === topLevelTypes.topFocus || dependency === topLevelTypes.topBlur) { + + if (isEventSupported('focus', true)) { + ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(topLevelTypes.topFocus, 'focus', mountAt); + ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(topLevelTypes.topBlur, 'blur', mountAt); + } else if (isEventSupported('focusin')) { + // IE has `focusin` and `focusout` events which bubble. + // @see http://www.quirksmode.org/blog/archives/2008/04/delegating_the.html + ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(topLevelTypes.topFocus, 'focusin', mountAt); + ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(topLevelTypes.topBlur, 'focusout', mountAt); + } + + // to make sure blur and focus event listeners are only attached once + isListening[topLevelTypes.topBlur] = true; + isListening[topLevelTypes.topFocus] = true; + } else if (topEventMapping.hasOwnProperty(dependency)) { + ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(dependency, topEventMapping[dependency], mountAt); + } + + isListening[dependency] = true; + } + } + }, + + trapBubbledEvent: function (topLevelType, handlerBaseName, handle) { + return ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(topLevelType, handlerBaseName, handle); + }, + + trapCapturedEvent: function (topLevelType, handlerBaseName, handle) { + return ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(topLevelType, handlerBaseName, handle); + }, + + /** + * Listens to window scroll and resize events. We cache scroll values so that + * application code can access them without triggering reflows. + * + * NOTE: Scroll events do not bubble. + * + * @see http://www.quirksmode.org/dom/events/scroll.html + */ + ensureScrollValueMonitoring: function () { + if (!isMonitoringScrollValue) { + var refresh = ViewportMetrics.refreshScrollValues; + ReactBrowserEventEmitter.ReactEventListener.monitorScrollValue(refresh); + isMonitoringScrollValue = true; + } + }, + + eventNameDispatchConfigs: EventPluginHub.eventNameDispatchConfigs, + + registrationNameModules: EventPluginHub.registrationNameModules, + + putListener: EventPluginHub.putListener, + + getListener: EventPluginHub.getListener, + + deleteListener: EventPluginHub.deleteListener, + + deleteAllListeners: EventPluginHub.deleteAllListeners + +}); + +ReactPerf.measureMethods(ReactBrowserEventEmitter, 'ReactBrowserEventEmitter', { + putListener: 'putListener', + deleteListener: 'deleteListener' +}); + +module.exports = ReactBrowserEventEmitter; +},{"114":114,"133":133,"15":15,"16":16,"17":17,"24":24,"62":62,"78":78}],29:[function(_dereq_,module,exports){ +/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @typechecks + * @providesModule ReactCSSTransitionGroup + */ + +'use strict'; + +var React = _dereq_(26); + +var assign = _dereq_(24); + +var ReactTransitionGroup = _dereq_(94); +var ReactCSSTransitionGroupChild = _dereq_(30); + +function createTransitionTimeoutPropValidator(transitionType) { + var timeoutPropName = 'transition' + transitionType + 'Timeout'; + var enabledPropName = 'transition' + transitionType; + + return function (props) { + // If the transition is enabled + if (props[enabledPropName]) { + // If no timeout duration is provided + if (props[timeoutPropName] == null) { + return new Error(timeoutPropName + ' wasn\'t supplied to ReactCSSTransitionGroup: ' + 'this can cause unreliable animations and won\'t be supported in ' + 'a future version of React. See ' + 'https://fb.me/react-animation-transition-group-timeout for more ' + 'information.'); + + // If the duration isn't a number + } else if (typeof props[timeoutPropName] !== 'number') { + return new Error(timeoutPropName + ' must be a number (in milliseconds)'); + } + } + }; +} + +var ReactCSSTransitionGroup = React.createClass({ + displayName: 'ReactCSSTransitionGroup', + + propTypes: { + transitionName: ReactCSSTransitionGroupChild.propTypes.name, + + transitionAppear: React.PropTypes.bool, + transitionEnter: React.PropTypes.bool, + transitionLeave: React.PropTypes.bool, + transitionAppearTimeout: createTransitionTimeoutPropValidator('Appear'), + transitionEnterTimeout: createTransitionTimeoutPropValidator('Enter'), + transitionLeaveTimeout: createTransitionTimeoutPropValidator('Leave') + }, + + getDefaultProps: function () { + return { + transitionAppear: false, + transitionEnter: true, + transitionLeave: true + }; + }, + + _wrapChild: function (child) { + // We need to provide this childFactory so that + // ReactCSSTransitionGroupChild can receive updates to name, enter, and + // leave while it is leaving. + return React.createElement(ReactCSSTransitionGroupChild, { + name: this.props.transitionName, + appear: this.props.transitionAppear, + enter: this.props.transitionEnter, + leave: this.props.transitionLeave, + appearTimeout: this.props.transitionAppearTimeout, + enterTimeout: this.props.transitionEnterTimeout, + leaveTimeout: this.props.transitionLeaveTimeout + }, child); + }, + + render: function () { + return React.createElement(ReactTransitionGroup, assign({}, this.props, { childFactory: this._wrapChild })); + } +}); + +module.exports = ReactCSSTransitionGroup; +},{"24":24,"26":26,"30":30,"94":94}],30:[function(_dereq_,module,exports){ +/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @typechecks + * @providesModule ReactCSSTransitionGroupChild + */ + +'use strict'; + +var React = _dereq_(26); +var ReactDOM = _dereq_(40); + +var CSSCore = _dereq_(145); +var ReactTransitionEvents = _dereq_(93); + +var onlyChild = _dereq_(135); + +// We don't remove the element from the DOM until we receive an animationend or +// transitionend event. If the user screws up and forgets to add an animation +// their node will be stuck in the DOM forever, so we detect if an animation +// does not start and if it doesn't, we just call the end listener immediately. +var TICK = 17; + +var ReactCSSTransitionGroupChild = React.createClass({ + displayName: 'ReactCSSTransitionGroupChild', + + propTypes: { + name: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.shape({ + enter: React.PropTypes.string, + leave: React.PropTypes.string, + active: React.PropTypes.string + }), React.PropTypes.shape({ + enter: React.PropTypes.string, + enterActive: React.PropTypes.string, + leave: React.PropTypes.string, + leaveActive: React.PropTypes.string, + appear: React.PropTypes.string, + appearActive: React.PropTypes.string + })]).isRequired, + + // Once we require timeouts to be specified, we can remove the + // boolean flags (appear etc.) and just accept a number + // or a bool for the timeout flags (appearTimeout etc.) + appear: React.PropTypes.bool, + enter: React.PropTypes.bool, + leave: React.PropTypes.bool, + appearTimeout: React.PropTypes.number, + enterTimeout: React.PropTypes.number, + leaveTimeout: React.PropTypes.number + }, + + transition: function (animationType, finishCallback, userSpecifiedDelay) { + var node = ReactDOM.findDOMNode(this); + + if (!node) { + if (finishCallback) { + finishCallback(); + } + return; + } + + var className = this.props.name[animationType] || this.props.name + '-' + animationType; + var activeClassName = this.props.name[animationType + 'Active'] || className + '-active'; + var timeout = null; + + var endListener = function (e) { + if (e && e.target !== node) { + return; + } + + clearTimeout(timeout); + + CSSCore.removeClass(node, className); + CSSCore.removeClass(node, activeClassName); + + ReactTransitionEvents.removeEndEventListener(node, endListener); + + // Usually this optional callback is used for informing an owner of + // a leave animation and telling it to remove the child. + if (finishCallback) { + finishCallback(); + } + }; + + CSSCore.addClass(node, className); + + // Need to do this to actually trigger a transition. + this.queueClass(activeClassName); + + // If the user specified a timeout delay. + if (userSpecifiedDelay) { + // Clean-up the animation after the specified delay + timeout = setTimeout(endListener, userSpecifiedDelay); + this.transitionTimeouts.push(timeout); + } else { + // DEPRECATED: this listener will be removed in a future version of react + ReactTransitionEvents.addEndEventListener(node, endListener); + } + }, + + queueClass: function (className) { + this.classNameQueue.push(className); + + if (!this.timeout) { + this.timeout = setTimeout(this.flushClassNameQueue, TICK); + } + }, + + flushClassNameQueue: function () { + if (this.isMounted()) { + this.classNameQueue.forEach(CSSCore.addClass.bind(CSSCore, ReactDOM.findDOMNode(this))); + } + this.classNameQueue.length = 0; + this.timeout = null; + }, + + componentWillMount: function () { + this.classNameQueue = []; + this.transitionTimeouts = []; + }, + + componentWillUnmount: function () { + if (this.timeout) { + clearTimeout(this.timeout); + } + this.transitionTimeouts.forEach(function (timeout) { + clearTimeout(timeout); + }); + }, + + componentWillAppear: function (done) { + if (this.props.appear) { + this.transition('appear', done, this.props.appearTimeout); + } else { + done(); + } + }, + + componentWillEnter: function (done) { + if (this.props.enter) { + this.transition('enter', done, this.props.enterTimeout); + } else { + done(); + } + }, + + componentWillLeave: function (done) { + if (this.props.leave) { + this.transition('leave', done, this.props.leaveTimeout); + } else { + done(); + } + }, + + render: function () { + return onlyChild(this.props.children); + } +}); + +module.exports = ReactCSSTransitionGroupChild; +},{"135":135,"145":145,"26":26,"40":40,"93":93}],31:[function(_dereq_,module,exports){ +/** + * Copyright 2014-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactChildReconciler + * @typechecks static-only + */ + +'use strict'; + +var ReactReconciler = _dereq_(84); + +var instantiateReactComponent = _dereq_(132); +var shouldUpdateReactComponent = _dereq_(141); +var traverseAllChildren = _dereq_(142); +var warning = _dereq_(173); + +function instantiateChild(childInstances, child, name) { + // We found a component instance. + var keyUnique = childInstances[name] === undefined; + if ("development" !== 'production') { + "development" !== 'production' ? warning(keyUnique, 'flattenChildren(...): Encountered two children with the same key, ' + '`%s`. Child keys must be unique; when two children share a key, only ' + 'the first child will be used.', name) : undefined; + } + if (child != null && keyUnique) { + childInstances[name] = instantiateReactComponent(child, null); + } +} + +/** + * ReactChildReconciler provides helpers for initializing or updating a set of + * children. Its output is suitable for passing it onto ReactMultiChild which + * does diffed reordering and insertion. + */ +var ReactChildReconciler = { + /** + * Generates a "mount image" for each of the supplied children. In the case + * of `ReactDOMComponent`, a mount image is a string of markup. + * + * @param {?object} nestedChildNodes Nested child maps. + * @return {?object} A set of child instances. + * @internal + */ + instantiateChildren: function (nestedChildNodes, transaction, context) { + if (nestedChildNodes == null) { + return null; + } + var childInstances = {}; + traverseAllChildren(nestedChildNodes, instantiateChild, childInstances); + return childInstances; + }, + + /** + * Updates the rendered children and returns a new set of children. + * + * @param {?object} prevChildren Previously initialized set of children. + * @param {?object} nextChildren Flat child element maps. + * @param {ReactReconcileTransaction} transaction + * @param {object} context + * @return {?object} A new set of child instances. + * @internal + */ + updateChildren: function (prevChildren, nextChildren, transaction, context) { + // We currently don't have a way to track moves here but if we use iterators + // instead of for..in we can zip the iterators and check if an item has + // moved. + // TODO: If nothing has changed, return the prevChildren object so that we + // can quickly bailout if nothing has changed. + if (!nextChildren && !prevChildren) { + return null; + } + var name; + for (name in nextChildren) { + if (!nextChildren.hasOwnProperty(name)) { + continue; + } + var prevChild = prevChildren && prevChildren[name]; + var prevElement = prevChild && prevChild._currentElement; + var nextElement = nextChildren[name]; + if (prevChild != null && shouldUpdateReactComponent(prevElement, nextElement)) { + ReactReconciler.receiveComponent(prevChild, nextElement, transaction, context); + nextChildren[name] = prevChild; + } else { + if (prevChild) { + ReactReconciler.unmountComponent(prevChild, name); + } + // The child must be instantiated before it's mounted. + var nextChildInstance = instantiateReactComponent(nextElement, null); + nextChildren[name] = nextChildInstance; + } + } + // Unmount children that are no longer present. + for (name in prevChildren) { + if (prevChildren.hasOwnProperty(name) && !(nextChildren && nextChildren.hasOwnProperty(name))) { + ReactReconciler.unmountComponent(prevChildren[name]); + } + } + return nextChildren; + }, + + /** + * Unmounts all rendered children. This should be used to clean up children + * when this component is unmounted. + * + * @param {?object} renderedChildren Previously initialized set of children. + * @internal + */ + unmountChildren: function (renderedChildren) { + for (var name in renderedChildren) { + if (renderedChildren.hasOwnProperty(name)) { + var renderedChild = renderedChildren[name]; + ReactReconciler.unmountComponent(renderedChild); + } + } + } + +}; + +module.exports = ReactChildReconciler; +},{"132":132,"141":141,"142":142,"173":173,"84":84}],32:[function(_dereq_,module,exports){ +/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactChildren + */ + +'use strict'; + +var PooledClass = _dereq_(25); +var ReactElement = _dereq_(57); + +var emptyFunction = _dereq_(153); +var traverseAllChildren = _dereq_(142); + +var twoArgumentPooler = PooledClass.twoArgumentPooler; +var fourArgumentPooler = PooledClass.fourArgumentPooler; + +var userProvidedKeyEscapeRegex = /\/(?!\/)/g; +function escapeUserProvidedKey(text) { + return ('' + text).replace(userProvidedKeyEscapeRegex, '//'); +} + +/** + * PooledClass representing the bookkeeping associated with performing a child + * traversal. Allows avoiding binding callbacks. + * + * @constructor ForEachBookKeeping + * @param {!function} forEachFunction Function to perform traversal with. + * @param {?*} forEachContext Context to perform context with. + */ +function ForEachBookKeeping(forEachFunction, forEachContext) { + this.func = forEachFunction; + this.context = forEachContext; + this.count = 0; +} +ForEachBookKeeping.prototype.destructor = function () { + this.func = null; + this.context = null; + this.count = 0; +}; +PooledClass.addPoolingTo(ForEachBookKeeping, twoArgumentPooler); + +function forEachSingleChild(bookKeeping, child, name) { + var func = bookKeeping.func; + var context = bookKeeping.context; + + func.call(context, child, bookKeeping.count++); +} + +/** + * Iterates through children that are typically specified as `props.children`. + * + * The provided forEachFunc(child, index) will be called for each + * leaf child. + * + * @param {?*} children Children tree container. + * @param {function(*, int)} forEachFunc + * @param {*} forEachContext Context for forEachContext. + */ +function forEachChildren(children, forEachFunc, forEachContext) { + if (children == null) { + return children; + } + var traverseContext = ForEachBookKeeping.getPooled(forEachFunc, forEachContext); + traverseAllChildren(children, forEachSingleChild, traverseContext); + ForEachBookKeeping.release(traverseContext); +} + +/** + * PooledClass representing the bookkeeping associated with performing a child + * mapping. Allows avoiding binding callbacks. + * + * @constructor MapBookKeeping + * @param {!*} mapResult Object containing the ordered map of results. + * @param {!function} mapFunction Function to perform mapping with. + * @param {?*} mapContext Context to perform mapping with. + */ +function MapBookKeeping(mapResult, keyPrefix, mapFunction, mapContext) { + this.result = mapResult; + this.keyPrefix = keyPrefix; + this.func = mapFunction; + this.context = mapContext; + this.count = 0; +} +MapBookKeeping.prototype.destructor = function () { + this.result = null; + this.keyPrefix = null; + this.func = null; + this.context = null; + this.count = 0; +}; +PooledClass.addPoolingTo(MapBookKeeping, fourArgumentPooler); + +function mapSingleChildIntoContext(bookKeeping, child, childKey) { + var result = bookKeeping.result; + var keyPrefix = bookKeeping.keyPrefix; + var func = bookKeeping.func; + var context = bookKeeping.context; + + var mappedChild = func.call(context, child, bookKeeping.count++); + if (Array.isArray(mappedChild)) { + mapIntoWithKeyPrefixInternal(mappedChild, result, childKey, emptyFunction.thatReturnsArgument); + } else if (mappedChild != null) { + if (ReactElement.isValidElement(mappedChild)) { + mappedChild = ReactElement.cloneAndReplaceKey(mappedChild, + // Keep both the (mapped) and old keys if they differ, just as + // traverseAllChildren used to do for objects as children + keyPrefix + (mappedChild !== child ? escapeUserProvidedKey(mappedChild.key || '') + '/' : '') + childKey); + } + result.push(mappedChild); + } +} + +function mapIntoWithKeyPrefixInternal(children, array, prefix, func, context) { + var escapedPrefix = ''; + if (prefix != null) { + escapedPrefix = escapeUserProvidedKey(prefix) + '/'; + } + var traverseContext = MapBookKeeping.getPooled(array, escapedPrefix, func, context); + traverseAllChildren(children, mapSingleChildIntoContext, traverseContext); + MapBookKeeping.release(traverseContext); +} + +/** + * Maps children that are typically specified as `props.children`. + * + * The provided mapFunction(child, key, index) will be called for each + * leaf child. + * + * @param {?*} children Children tree container. + * @param {function(*, int)} func The map function. + * @param {*} context Context for mapFunction. + * @return {object} Object containing the ordered map of results. + */ +function mapChildren(children, func, context) { + if (children == null) { + return children; + } + var result = []; + mapIntoWithKeyPrefixInternal(children, result, null, func, context); + return result; +} + +function forEachSingleChildDummy(traverseContext, child, name) { + return null; +} + +/** + * Count the number of children that are typically specified as + * `props.children`. + * + * @param {?*} children Children tree container. + * @return {number} The number of children. + */ +function countChildren(children, context) { + return traverseAllChildren(children, forEachSingleChildDummy, null); +} + +/** + * Flatten a children object (typically specified as `props.children`) and + * return an array with appropriately re-keyed children. + */ +function toArray(children) { + var result = []; + mapIntoWithKeyPrefixInternal(children, result, null, emptyFunction.thatReturnsArgument); + return result; +} + +var ReactChildren = { + forEach: forEachChildren, + map: mapChildren, + mapIntoWithKeyPrefixInternal: mapIntoWithKeyPrefixInternal, + count: countChildren, + toArray: toArray +}; + +module.exports = ReactChildren; +},{"142":142,"153":153,"25":25,"57":57}],33:[function(_dereq_,module,exports){ +/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactClass + */ + +'use strict'; + +var ReactComponent = _dereq_(34); +var ReactElement = _dereq_(57); +var ReactPropTypeLocations = _dereq_(81); +var ReactPropTypeLocationNames = _dereq_(80); +var ReactNoopUpdateQueue = _dereq_(76); + +var assign = _dereq_(24); +var emptyObject = _dereq_(154); +var invariant = _dereq_(161); +var keyMirror = _dereq_(165); +var keyOf = _dereq_(166); +var warning = _dereq_(173); + +var MIXINS_KEY = keyOf({ mixins: null }); + +/** + * Policies that describe methods in `ReactClassInterface`. + */ +var SpecPolicy = keyMirror({ + /** + * These methods may be defined only once by the class specification or mixin. + */ + DEFINE_ONCE: null, + /** + * These methods may be defined by both the class specification and mixins. + * Subsequent definitions will be chained. These methods must return void. + */ + DEFINE_MANY: null, + /** + * These methods are overriding the base class. + */ + OVERRIDE_BASE: null, + /** + * These methods are similar to DEFINE_MANY, except we assume they return + * objects. We try to merge the keys of the return values of all the mixed in + * functions. If there is a key conflict we throw. + */ + DEFINE_MANY_MERGED: null +}); + +var injectedMixins = []; + +var warnedSetProps = false; +function warnSetProps() { + if (!warnedSetProps) { + warnedSetProps = true; + "development" !== 'production' ? warning(false, 'setProps(...) and replaceProps(...) are deprecated. ' + 'Instead, call render again at the top level.') : undefined; + } +} + +/** + * Composite components are higher-level components that compose other composite + * or native components. + * + * To create a new type of `ReactClass`, pass a specification of + * your new class to `React.createClass`. The only requirement of your class + * specification is that you implement a `render` method. + * + * var MyComponent = React.createClass({ + * render: function() { + * return
Hello World
; + * } + * }); + * + * The class specification supports a specific protocol of methods that have + * special meaning (e.g. `render`). See `ReactClassInterface` for + * more the comprehensive protocol. Any other properties and methods in the + * class specification will be available on the prototype. + * + * @interface ReactClassInterface + * @internal + */ +var ReactClassInterface = { + + /** + * An array of Mixin objects to include when defining your component. + * + * @type {array} + * @optional + */ + mixins: SpecPolicy.DEFINE_MANY, + + /** + * An object containing properties and methods that should be defined on + * the component's constructor instead of its prototype (static methods). + * + * @type {object} + * @optional + */ + statics: SpecPolicy.DEFINE_MANY, + + /** + * Definition of prop types for this component. + * + * @type {object} + * @optional + */ + propTypes: SpecPolicy.DEFINE_MANY, + + /** + * Definition of context types for this component. + * + * @type {object} + * @optional + */ + contextTypes: SpecPolicy.DEFINE_MANY, + + /** + * Definition of context types this component sets for its children. + * + * @type {object} + * @optional + */ + childContextTypes: SpecPolicy.DEFINE_MANY, + + // ==== Definition methods ==== + + /** + * Invoked when the component is mounted. Values in the mapping will be set on + * `this.props` if that prop is not specified (i.e. using an `in` check). + * + * This method is invoked before `getInitialState` and therefore cannot rely + * on `this.state` or use `this.setState`. + * + * @return {object} + * @optional + */ + getDefaultProps: SpecPolicy.DEFINE_MANY_MERGED, + + /** + * Invoked once before the component is mounted. The return value will be used + * as the initial value of `this.state`. + * + * getInitialState: function() { + * return { + * isOn: false, + * fooBaz: new BazFoo() + * } + * } + * + * @return {object} + * @optional + */ + getInitialState: SpecPolicy.DEFINE_MANY_MERGED, + + /** + * @return {object} + * @optional + */ + getChildContext: SpecPolicy.DEFINE_MANY_MERGED, + + /** + * Uses props from `this.props` and state from `this.state` to render the + * structure of the component. + * + * No guarantees are made about when or how often this method is invoked, so + * it must not have side effects. + * + * render: function() { + * var name = this.props.name; + * return
Hello, {name}!
; + * } + * + * @return {ReactComponent} + * @nosideeffects + * @required + */ + render: SpecPolicy.DEFINE_ONCE, + + // ==== Delegate methods ==== + + /** + * Invoked when the component is initially created and about to be mounted. + * This may have side effects, but any external subscriptions or data created + * by this method must be cleaned up in `componentWillUnmount`. + * + * @optional + */ + componentWillMount: SpecPolicy.DEFINE_MANY, + + /** + * Invoked when the component has been mounted and has a DOM representation. + * However, there is no guarantee that the DOM node is in the document. + * + * Use this as an opportunity to operate on the DOM when the component has + * been mounted (initialized and rendered) for the first time. + * + * @param {DOMElement} rootNode DOM element representing the component. + * @optional + */ + componentDidMount: SpecPolicy.DEFINE_MANY, + + /** + * Invoked before the component receives new props. + * + * Use this as an opportunity to react to a prop transition by updating the + * state using `this.setState`. Current props are accessed via `this.props`. + * + * componentWillReceiveProps: function(nextProps, nextContext) { + * this.setState({ + * likesIncreasing: nextProps.likeCount > this.props.likeCount + * }); + * } + * + * NOTE: There is no equivalent `componentWillReceiveState`. An incoming prop + * transition may cause a state change, but the opposite is not true. If you + * need it, you are probably looking for `componentWillUpdate`. + * + * @param {object} nextProps + * @optional + */ + componentWillReceiveProps: SpecPolicy.DEFINE_MANY, + + /** + * Invoked while deciding if the component should be updated as a result of + * receiving new props, state and/or context. + * + * Use this as an opportunity to `return false` when you're certain that the + * transition to the new props/state/context will not require a component + * update. + * + * shouldComponentUpdate: function(nextProps, nextState, nextContext) { + * return !equal(nextProps, this.props) || + * !equal(nextState, this.state) || + * !equal(nextContext, this.context); + * } + * + * @param {object} nextProps + * @param {?object} nextState + * @param {?object} nextContext + * @return {boolean} True if the component should update. + * @optional + */ + shouldComponentUpdate: SpecPolicy.DEFINE_ONCE, + + /** + * Invoked when the component is about to update due to a transition from + * `this.props`, `this.state` and `this.context` to `nextProps`, `nextState` + * and `nextContext`. + * + * Use this as an opportunity to perform preparation before an update occurs. + * + * NOTE: You **cannot** use `this.setState()` in this method. + * + * @param {object} nextProps + * @param {?object} nextState + * @param {?object} nextContext + * @param {ReactReconcileTransaction} transaction + * @optional + */ + componentWillUpdate: SpecPolicy.DEFINE_MANY, + + /** + * Invoked when the component's DOM representation has been updated. + * + * Use this as an opportunity to operate on the DOM when the component has + * been updated. + * + * @param {object} prevProps + * @param {?object} prevState + * @param {?object} prevContext + * @param {DOMElement} rootNode DOM element representing the component. + * @optional + */ + componentDidUpdate: SpecPolicy.DEFINE_MANY, + + /** + * Invoked when the component is about to be removed from its parent and have + * its DOM representation destroyed. + * + * Use this as an opportunity to deallocate any external resources. + * + * NOTE: There is no `componentDidUnmount` since your component will have been + * destroyed by that point. + * + * @optional + */ + componentWillUnmount: SpecPolicy.DEFINE_MANY, + + // ==== Advanced methods ==== + + /** + * Updates the component's currently mounted DOM representation. + * + * By default, this implements React's rendering and reconciliation algorithm. + * Sophisticated clients may wish to override this. + * + * @param {ReactReconcileTransaction} transaction + * @internal + * @overridable + */ + updateComponent: SpecPolicy.OVERRIDE_BASE + +}; + +/** + * Mapping from class specification keys to special processing functions. + * + * Although these are declared like instance properties in the specification + * when defining classes using `React.createClass`, they are actually static + * and are accessible on the constructor instead of the prototype. Despite + * being static, they must be defined outside of the "statics" key under + * which all other static methods are defined. + */ +var RESERVED_SPEC_KEYS = { + displayName: function (Constructor, displayName) { + Constructor.displayName = displayName; + }, + mixins: function (Constructor, mixins) { + if (mixins) { + for (var i = 0; i < mixins.length; i++) { + mixSpecIntoComponent(Constructor, mixins[i]); + } + } + }, + childContextTypes: function (Constructor, childContextTypes) { + if ("development" !== 'production') { + validateTypeDef(Constructor, childContextTypes, ReactPropTypeLocations.childContext); + } + Constructor.childContextTypes = assign({}, Constructor.childContextTypes, childContextTypes); + }, + contextTypes: function (Constructor, contextTypes) { + if ("development" !== 'production') { + validateTypeDef(Constructor, contextTypes, ReactPropTypeLocations.context); + } + Constructor.contextTypes = assign({}, Constructor.contextTypes, contextTypes); + }, + /** + * Special case getDefaultProps which should move into statics but requires + * automatic merging. + */ + getDefaultProps: function (Constructor, getDefaultProps) { + if (Constructor.getDefaultProps) { + Constructor.getDefaultProps = createMergedResultFunction(Constructor.getDefaultProps, getDefaultProps); + } else { + Constructor.getDefaultProps = getDefaultProps; + } + }, + propTypes: function (Constructor, propTypes) { + if ("development" !== 'production') { + validateTypeDef(Constructor, propTypes, ReactPropTypeLocations.prop); + } + Constructor.propTypes = assign({}, Constructor.propTypes, propTypes); + }, + statics: function (Constructor, statics) { + mixStaticSpecIntoComponent(Constructor, statics); + }, + autobind: function () {} }; + +// noop +function validateTypeDef(Constructor, typeDef, location) { + for (var propName in typeDef) { + if (typeDef.hasOwnProperty(propName)) { + // use a warning instead of an invariant so components + // don't show up in prod but not in __DEV__ + "development" !== 'production' ? warning(typeof typeDef[propName] === 'function', '%s: %s type `%s` is invalid; it must be a function, usually from ' + 'React.PropTypes.', Constructor.displayName || 'ReactClass', ReactPropTypeLocationNames[location], propName) : undefined; + } + } +} + +function validateMethodOverride(proto, name) { + var specPolicy = ReactClassInterface.hasOwnProperty(name) ? ReactClassInterface[name] : null; + + // Disallow overriding of base class methods unless explicitly allowed. + if (ReactClassMixin.hasOwnProperty(name)) { + !(specPolicy === SpecPolicy.OVERRIDE_BASE) ? "development" !== 'production' ? invariant(false, 'ReactClassInterface: You are attempting to override ' + '`%s` from your class specification. Ensure that your method names ' + 'do not overlap with React methods.', name) : invariant(false) : undefined; + } + + // Disallow defining methods more than once unless explicitly allowed. + if (proto.hasOwnProperty(name)) { + !(specPolicy === SpecPolicy.DEFINE_MANY || specPolicy === SpecPolicy.DEFINE_MANY_MERGED) ? "development" !== 'production' ? invariant(false, 'ReactClassInterface: You are attempting to define ' + '`%s` on your component more than once. This conflict may be due ' + 'to a mixin.', name) : invariant(false) : undefined; + } +} + +/** + * Mixin helper which handles policy validation and reserved + * specification keys when building React classses. + */ +function mixSpecIntoComponent(Constructor, spec) { + if (!spec) { + return; + } + + !(typeof spec !== 'function') ? "development" !== 'production' ? invariant(false, 'ReactClass: You\'re attempting to ' + 'use a component class as a mixin. Instead, just use a regular object.') : invariant(false) : undefined; + !!ReactElement.isValidElement(spec) ? "development" !== 'production' ? invariant(false, 'ReactClass: You\'re attempting to ' + 'use a component as a mixin. Instead, just use a regular object.') : invariant(false) : undefined; + + var proto = Constructor.prototype; + + // By handling mixins before any other properties, we ensure the same + // chaining order is applied to methods with DEFINE_MANY policy, whether + // mixins are listed before or after these methods in the spec. + if (spec.hasOwnProperty(MIXINS_KEY)) { + RESERVED_SPEC_KEYS.mixins(Constructor, spec.mixins); + } + + for (var name in spec) { + if (!spec.hasOwnProperty(name)) { + continue; + } + + if (name === MIXINS_KEY) { + // We have already handled mixins in a special case above. + continue; + } + + var property = spec[name]; + validateMethodOverride(proto, name); + + if (RESERVED_SPEC_KEYS.hasOwnProperty(name)) { + RESERVED_SPEC_KEYS[name](Constructor, property); + } else { + // Setup methods on prototype: + // The following member methods should not be automatically bound: + // 1. Expected ReactClass methods (in the "interface"). + // 2. Overridden methods (that were mixed in). + var isReactClassMethod = ReactClassInterface.hasOwnProperty(name); + var isAlreadyDefined = proto.hasOwnProperty(name); + var isFunction = typeof property === 'function'; + var shouldAutoBind = isFunction && !isReactClassMethod && !isAlreadyDefined && spec.autobind !== false; + + if (shouldAutoBind) { + if (!proto.__reactAutoBindMap) { + proto.__reactAutoBindMap = {}; + } + proto.__reactAutoBindMap[name] = property; + proto[name] = property; + } else { + if (isAlreadyDefined) { + var specPolicy = ReactClassInterface[name]; + + // These cases should already be caught by validateMethodOverride. + !(isReactClassMethod && (specPolicy === SpecPolicy.DEFINE_MANY_MERGED || specPolicy === SpecPolicy.DEFINE_MANY)) ? "development" !== 'production' ? invariant(false, 'ReactClass: Unexpected spec policy %s for key %s ' + 'when mixing in component specs.', specPolicy, name) : invariant(false) : undefined; + + // For methods which are defined more than once, call the existing + // methods before calling the new property, merging if appropriate. + if (specPolicy === SpecPolicy.DEFINE_MANY_MERGED) { + proto[name] = createMergedResultFunction(proto[name], property); + } else if (specPolicy === SpecPolicy.DEFINE_MANY) { + proto[name] = createChainedFunction(proto[name], property); + } + } else { + proto[name] = property; + if ("development" !== 'production') { + // Add verbose displayName to the function, which helps when looking + // at profiling tools. + if (typeof property === 'function' && spec.displayName) { + proto[name].displayName = spec.displayName + '_' + name; + } + } + } + } + } + } +} + +function mixStaticSpecIntoComponent(Constructor, statics) { + if (!statics) { + return; + } + for (var name in statics) { + var property = statics[name]; + if (!statics.hasOwnProperty(name)) { + continue; + } + + var isReserved = (name in RESERVED_SPEC_KEYS); + !!isReserved ? "development" !== 'production' ? invariant(false, 'ReactClass: You are attempting to define a reserved ' + 'property, `%s`, that shouldn\'t be on the "statics" key. Define it ' + 'as an instance property instead; it will still be accessible on the ' + 'constructor.', name) : invariant(false) : undefined; + + var isInherited = (name in Constructor); + !!isInherited ? "development" !== 'production' ? invariant(false, 'ReactClass: You are attempting to define ' + '`%s` on your component more than once. This conflict may be ' + 'due to a mixin.', name) : invariant(false) : undefined; + Constructor[name] = property; + } +} + +/** + * Merge two objects, but throw if both contain the same key. + * + * @param {object} one The first object, which is mutated. + * @param {object} two The second object + * @return {object} one after it has been mutated to contain everything in two. + */ +function mergeIntoWithNoDuplicateKeys(one, two) { + !(one && two && typeof one === 'object' && typeof two === 'object') ? "development" !== 'production' ? invariant(false, 'mergeIntoWithNoDuplicateKeys(): Cannot merge non-objects.') : invariant(false) : undefined; + + for (var key in two) { + if (two.hasOwnProperty(key)) { + !(one[key] === undefined) ? "development" !== 'production' ? invariant(false, 'mergeIntoWithNoDuplicateKeys(): ' + 'Tried to merge two objects with the same key: `%s`. This conflict ' + 'may be due to a mixin; in particular, this may be caused by two ' + 'getInitialState() or getDefaultProps() methods returning objects ' + 'with clashing keys.', key) : invariant(false) : undefined; + one[key] = two[key]; + } + } + return one; +} + +/** + * Creates a function that invokes two functions and merges their return values. + * + * @param {function} one Function to invoke first. + * @param {function} two Function to invoke second. + * @return {function} Function that invokes the two argument functions. + * @private + */ +function createMergedResultFunction(one, two) { + return function mergedResult() { + var a = one.apply(this, arguments); + var b = two.apply(this, arguments); + if (a == null) { + return b; + } else if (b == null) { + return a; + } + var c = {}; + mergeIntoWithNoDuplicateKeys(c, a); + mergeIntoWithNoDuplicateKeys(c, b); + return c; + }; +} + +/** + * Creates a function that invokes two functions and ignores their return vales. + * + * @param {function} one Function to invoke first. + * @param {function} two Function to invoke second. + * @return {function} Function that invokes the two argument functions. + * @private + */ +function createChainedFunction(one, two) { + return function chainedFunction() { + one.apply(this, arguments); + two.apply(this, arguments); + }; +} + +/** + * Binds a method to the component. + * + * @param {object} component Component whose method is going to be bound. + * @param {function} method Method to be bound. + * @return {function} The bound method. + */ +function bindAutoBindMethod(component, method) { + var boundMethod = method.bind(component); + if ("development" !== 'production') { + boundMethod.__reactBoundContext = component; + boundMethod.__reactBoundMethod = method; + boundMethod.__reactBoundArguments = null; + var componentName = component.constructor.displayName; + var _bind = boundMethod.bind; + /* eslint-disable block-scoped-var, no-undef */ + boundMethod.bind = function (newThis) { + for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + args[_key - 1] = arguments[_key]; + } + + // User is trying to bind() an autobound method; we effectively will + // ignore the value of "this" that the user is trying to use, so + // let's warn. + if (newThis !== component && newThis !== null) { + "development" !== 'production' ? warning(false, 'bind(): React component methods may only be bound to the ' + 'component instance. See %s', componentName) : undefined; + } else if (!args.length) { + "development" !== 'production' ? warning(false, 'bind(): You are binding a component method to the component. ' + 'React does this for you automatically in a high-performance ' + 'way, so you can safely remove this call. See %s', componentName) : undefined; + return boundMethod; + } + var reboundMethod = _bind.apply(boundMethod, arguments); + reboundMethod.__reactBoundContext = component; + reboundMethod.__reactBoundMethod = method; + reboundMethod.__reactBoundArguments = args; + return reboundMethod; + /* eslint-enable */ + }; + } + return boundMethod; +} + +/** + * Binds all auto-bound methods in a component. + * + * @param {object} component Component whose method is going to be bound. + */ +function bindAutoBindMethods(component) { + for (var autoBindKey in component.__reactAutoBindMap) { + if (component.__reactAutoBindMap.hasOwnProperty(autoBindKey)) { + var method = component.__reactAutoBindMap[autoBindKey]; + component[autoBindKey] = bindAutoBindMethod(component, method); + } + } +} + +/** + * Add more to the ReactClass base class. These are all legacy features and + * therefore not already part of the modern ReactComponent. + */ +var ReactClassMixin = { + + /** + * TODO: This will be deprecated because state should always keep a consistent + * type signature and the only use case for this, is to avoid that. + */ + replaceState: function (newState, callback) { + this.updater.enqueueReplaceState(this, newState); + if (callback) { + this.updater.enqueueCallback(this, callback); + } + }, + + /** + * Checks whether or not this composite component is mounted. + * @return {boolean} True if mounted, false otherwise. + * @protected + * @final + */ + isMounted: function () { + return this.updater.isMounted(this); + }, + + /** + * Sets a subset of the props. + * + * @param {object} partialProps Subset of the next props. + * @param {?function} callback Called after props are updated. + * @final + * @public + * @deprecated + */ + setProps: function (partialProps, callback) { + if ("development" !== 'production') { + warnSetProps(); + } + this.updater.enqueueSetProps(this, partialProps); + if (callback) { + this.updater.enqueueCallback(this, callback); + } + }, + + /** + * Replace all the props. + * + * @param {object} newProps Subset of the next props. + * @param {?function} callback Called after props are updated. + * @final + * @public + * @deprecated + */ + replaceProps: function (newProps, callback) { + if ("development" !== 'production') { + warnSetProps(); + } + this.updater.enqueueReplaceProps(this, newProps); + if (callback) { + this.updater.enqueueCallback(this, callback); + } + } +}; + +var ReactClassComponent = function () {}; +assign(ReactClassComponent.prototype, ReactComponent.prototype, ReactClassMixin); + +/** + * Module for creating composite components. + * + * @class ReactClass + */ +var ReactClass = { + + /** + * Creates a composite component class given a class specification. + * + * @param {object} spec Class specification (which must define `render`). + * @return {function} Component constructor function. + * @public + */ + createClass: function (spec) { + var Constructor = function (props, context, updater) { + // This constructor is overridden by mocks. The argument is used + // by mocks to assert on what gets mounted. + + if ("development" !== 'production') { + "development" !== 'production' ? warning(this instanceof Constructor, 'Something is calling a React component directly. Use a factory or ' + 'JSX instead. See: https://fb.me/react-legacyfactory') : undefined; + } + + // Wire up auto-binding + if (this.__reactAutoBindMap) { + bindAutoBindMethods(this); + } + + this.props = props; + this.context = context; + this.refs = emptyObject; + this.updater = updater || ReactNoopUpdateQueue; + + this.state = null; + + // ReactClasses doesn't have constructors. Instead, they use the + // getInitialState and componentWillMount methods for initialization. + + var initialState = this.getInitialState ? this.getInitialState() : null; + if ("development" !== 'production') { + // We allow auto-mocks to proceed as if they're returning null. + if (typeof initialState === 'undefined' && this.getInitialState._isMockFunction) { + // This is probably bad practice. Consider warning here and + // deprecating this convenience. + initialState = null; + } + } + !(typeof initialState === 'object' && !Array.isArray(initialState)) ? "development" !== 'production' ? invariant(false, '%s.getInitialState(): must return an object or null', Constructor.displayName || 'ReactCompositeComponent') : invariant(false) : undefined; + + this.state = initialState; + }; + Constructor.prototype = new ReactClassComponent(); + Constructor.prototype.constructor = Constructor; + + injectedMixins.forEach(mixSpecIntoComponent.bind(null, Constructor)); + + mixSpecIntoComponent(Constructor, spec); + + // Initialize the defaultProps property after all mixins have been merged. + if (Constructor.getDefaultProps) { + Constructor.defaultProps = Constructor.getDefaultProps(); + } + + if ("development" !== 'production') { + // This is a tag to indicate that the use of these method names is ok, + // since it's used with createClass. If it's not, then it's likely a + // mistake so we'll warn you to use the static property, property + // initializer or constructor respectively. + if (Constructor.getDefaultProps) { + Constructor.getDefaultProps.isReactClassApproved = {}; + } + if (Constructor.prototype.getInitialState) { + Constructor.prototype.getInitialState.isReactClassApproved = {}; + } + } + + !Constructor.prototype.render ? "development" !== 'production' ? invariant(false, 'createClass(...): Class specification must implement a `render` method.') : invariant(false) : undefined; + + if ("development" !== 'production') { + "development" !== 'production' ? warning(!Constructor.prototype.componentShouldUpdate, '%s has a method called ' + 'componentShouldUpdate(). Did you mean shouldComponentUpdate()? ' + 'The name is phrased as a question because the function is ' + 'expected to return a value.', spec.displayName || 'A component') : undefined; + "development" !== 'production' ? warning(!Constructor.prototype.componentWillRecieveProps, '%s has a method called ' + 'componentWillRecieveProps(). Did you mean componentWillReceiveProps()?', spec.displayName || 'A component') : undefined; + } + + // Reduce time spent doing lookups by setting these on the prototype. + for (var methodName in ReactClassInterface) { + if (!Constructor.prototype[methodName]) { + Constructor.prototype[methodName] = null; + } + } + + return Constructor; + }, + + injection: { + injectMixin: function (mixin) { + injectedMixins.push(mixin); + } + } + +}; + +module.exports = ReactClass; +},{"154":154,"161":161,"165":165,"166":166,"173":173,"24":24,"34":34,"57":57,"76":76,"80":80,"81":81}],34:[function(_dereq_,module,exports){ +/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactComponent + */ + +'use strict'; + +var ReactNoopUpdateQueue = _dereq_(76); + +var canDefineProperty = _dereq_(117); +var emptyObject = _dereq_(154); +var invariant = _dereq_(161); +var warning = _dereq_(173); + +/** + * Base class helpers for the updating state of a component. + */ +function ReactComponent(props, context, updater) { + this.props = props; + this.context = context; + this.refs = emptyObject; + // We initialize the default updater but the real one gets injected by the + // renderer. + this.updater = updater || ReactNoopUpdateQueue; +} + +ReactComponent.prototype.isReactComponent = {}; + +/** + * Sets a subset of the state. Always use this to mutate + * state. You should treat `this.state` as immutable. + * + * There is no guarantee that `this.state` will be immediately updated, so + * accessing `this.state` after calling this method may return the old value. + * + * There is no guarantee that calls to `setState` will run synchronously, + * as they may eventually be batched together. You can provide an optional + * callback that will be executed when the call to setState is actually + * completed. + * + * When a function is provided to setState, it will be called at some point in + * the future (not synchronously). It will be called with the up to date + * component arguments (state, props, context). These values can be different + * from this.* because your function may be called after receiveProps but before + * shouldComponentUpdate, and this new state, props, and context will not yet be + * assigned to this. + * + * @param {object|function} partialState Next partial state or function to + * produce next partial state to be merged with current state. + * @param {?function} callback Called after state is updated. + * @final + * @protected + */ +ReactComponent.prototype.setState = function (partialState, callback) { + !(typeof partialState === 'object' || typeof partialState === 'function' || partialState == null) ? "development" !== 'production' ? invariant(false, 'setState(...): takes an object of state variables to update or a ' + 'function which returns an object of state variables.') : invariant(false) : undefined; + if ("development" !== 'production') { + "development" !== 'production' ? warning(partialState != null, 'setState(...): You passed an undefined or null state object; ' + 'instead, use forceUpdate().') : undefined; + } + this.updater.enqueueSetState(this, partialState); + if (callback) { + this.updater.enqueueCallback(this, callback); + } +}; + +/** + * Forces an update. This should only be invoked when it is known with + * certainty that we are **not** in a DOM transaction. + * + * You may want to call this when you know that some deeper aspect of the + * component's state has changed but `setState` was not called. + * + * This will not invoke `shouldComponentUpdate`, but it will invoke + * `componentWillUpdate` and `componentDidUpdate`. + * + * @param {?function} callback Called after update is complete. + * @final + * @protected + */ +ReactComponent.prototype.forceUpdate = function (callback) { + this.updater.enqueueForceUpdate(this); + if (callback) { + this.updater.enqueueCallback(this, callback); + } +}; + +/** + * Deprecated APIs. These APIs used to exist on classic React classes but since + * we would like to deprecate them, we're not going to move them over to this + * modern base class. Instead, we define a getter that warns if it's accessed. + */ +if ("development" !== 'production') { + var deprecatedAPIs = { + getDOMNode: ['getDOMNode', 'Use ReactDOM.findDOMNode(component) instead.'], + isMounted: ['isMounted', 'Instead, make sure to clean up subscriptions and pending requests in ' + 'componentWillUnmount to prevent memory leaks.'], + replaceProps: ['replaceProps', 'Instead, call render again at the top level.'], + replaceState: ['replaceState', 'Refactor your code to use setState instead (see ' + 'https://github.com/facebook/react/issues/3236).'], + setProps: ['setProps', 'Instead, call render again at the top level.'] + }; + var defineDeprecationWarning = function (methodName, info) { + if (canDefineProperty) { + Object.defineProperty(ReactComponent.prototype, methodName, { + get: function () { + "development" !== 'production' ? warning(false, '%s(...) is deprecated in plain JavaScript React classes. %s', info[0], info[1]) : undefined; + return undefined; + } + }); + } + }; + for (var fnName in deprecatedAPIs) { + if (deprecatedAPIs.hasOwnProperty(fnName)) { + defineDeprecationWarning(fnName, deprecatedAPIs[fnName]); + } + } +} + +module.exports = ReactComponent; +},{"117":117,"154":154,"161":161,"173":173,"76":76}],35:[function(_dereq_,module,exports){ +/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactComponentBrowserEnvironment + */ + +'use strict'; + +var ReactDOMIDOperations = _dereq_(45); +var ReactMount = _dereq_(72); + +/** + * Abstracts away all functionality of the reconciler that requires knowledge of + * the browser context. TODO: These callers should be refactored to avoid the + * need for this injection. + */ +var ReactComponentBrowserEnvironment = { + + processChildrenUpdates: ReactDOMIDOperations.dangerouslyProcessChildrenUpdates, + + replaceNodeWithMarkupByID: ReactDOMIDOperations.dangerouslyReplaceNodeWithMarkupByID, + + /** + * If a particular environment requires that some resources be cleaned up, + * specify this in the injected Mixin. In the DOM, we would likely want to + * purge any cached node ID lookups. + * + * @private + */ + unmountIDFromEnvironment: function (rootNodeID) { + ReactMount.purgeID(rootNodeID); + } + +}; + +module.exports = ReactComponentBrowserEnvironment; +},{"45":45,"72":72}],36:[function(_dereq_,module,exports){ +/** + * Copyright 2014-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactComponentEnvironment + */ + +'use strict'; + +var invariant = _dereq_(161); + +var injected = false; + +var ReactComponentEnvironment = { + + /** + * Optionally injectable environment dependent cleanup hook. (server vs. + * browser etc). Example: A browser system caches DOM nodes based on component + * ID and must remove that cache entry when this instance is unmounted. + */ + unmountIDFromEnvironment: null, + + /** + * Optionally injectable hook for swapping out mount images in the middle of + * the tree. + */ + replaceNodeWithMarkupByID: null, + + /** + * Optionally injectable hook for processing a queue of child updates. Will + * later move into MultiChildComponents. + */ + processChildrenUpdates: null, + + injection: { + injectEnvironment: function (environment) { + !!injected ? "development" !== 'production' ? invariant(false, 'ReactCompositeComponent: injectEnvironment() can only be called once.') : invariant(false) : undefined; + ReactComponentEnvironment.unmountIDFromEnvironment = environment.unmountIDFromEnvironment; + ReactComponentEnvironment.replaceNodeWithMarkupByID = environment.replaceNodeWithMarkupByID; + ReactComponentEnvironment.processChildrenUpdates = environment.processChildrenUpdates; + injected = true; + } + } + +}; + +module.exports = ReactComponentEnvironment; +},{"161":161}],37:[function(_dereq_,module,exports){ +/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactComponentWithPureRenderMixin + */ + +'use strict'; + +var shallowCompare = _dereq_(140); + +/** + * If your React component's render function is "pure", e.g. it will render the + * same result given the same props and state, provide this Mixin for a + * considerable performance boost. + * + * Most React components have pure render functions. + * + * Example: + * + * var ReactComponentWithPureRenderMixin = + * require('ReactComponentWithPureRenderMixin'); + * React.createClass({ + * mixins: [ReactComponentWithPureRenderMixin], + * + * render: function() { + * return
foo
; + * } + * }); + * + * Note: This only checks shallow equality for props and state. If these contain + * complex data structures this mixin may have false-negatives for deeper + * differences. Only mixin to components which have simple props and state, or + * use `forceUpdate()` when you know deep data structures have changed. + */ +var ReactComponentWithPureRenderMixin = { + shouldComponentUpdate: function (nextProps, nextState) { + return shallowCompare(this, nextProps, nextState); + } +}; + +module.exports = ReactComponentWithPureRenderMixin; +},{"140":140}],38:[function(_dereq_,module,exports){ +/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactCompositeComponent + */ + +'use strict'; + +var ReactComponentEnvironment = _dereq_(36); +var ReactCurrentOwner = _dereq_(39); +var ReactElement = _dereq_(57); +var ReactInstanceMap = _dereq_(68); +var ReactPerf = _dereq_(78); +var ReactPropTypeLocations = _dereq_(81); +var ReactPropTypeLocationNames = _dereq_(80); +var ReactReconciler = _dereq_(84); +var ReactUpdateQueue = _dereq_(95); + +var assign = _dereq_(24); +var emptyObject = _dereq_(154); +var invariant = _dereq_(161); +var shouldUpdateReactComponent = _dereq_(141); +var warning = _dereq_(173); + +function getDeclarationErrorAddendum(component) { + var owner = component._currentElement._owner || null; + if (owner) { + var name = owner.getName(); + if (name) { + return ' Check the render method of `' + name + '`.'; + } + } + return ''; +} + +function StatelessComponent(Component) {} +StatelessComponent.prototype.render = function () { + var Component = ReactInstanceMap.get(this)._currentElement.type; + return Component(this.props, this.context, this.updater); +}; + +/** + * ------------------ The Life-Cycle of a Composite Component ------------------ + * + * - constructor: Initialization of state. The instance is now retained. + * - componentWillMount + * - render + * - [children's constructors] + * - [children's componentWillMount and render] + * - [children's componentDidMount] + * - componentDidMount + * + * Update Phases: + * - componentWillReceiveProps (only called if parent updated) + * - shouldComponentUpdate + * - componentWillUpdate + * - render + * - [children's constructors or receive props phases] + * - componentDidUpdate + * + * - componentWillUnmount + * - [children's componentWillUnmount] + * - [children destroyed] + * - (destroyed): The instance is now blank, released by React and ready for GC. + * + * ----------------------------------------------------------------------------- + */ + +/** + * An incrementing ID assigned to each component when it is mounted. This is + * used to enforce the order in which `ReactUpdates` updates dirty components. + * + * @private + */ +var nextMountID = 1; + +/** + * @lends {ReactCompositeComponent.prototype} + */ +var ReactCompositeComponentMixin = { + + /** + * Base constructor for all composite component. + * + * @param {ReactElement} element + * @final + * @internal + */ + construct: function (element) { + this._currentElement = element; + this._rootNodeID = null; + this._instance = null; + + // See ReactUpdateQueue + this._pendingElement = null; + this._pendingStateQueue = null; + this._pendingReplaceState = false; + this._pendingForceUpdate = false; + + this._renderedComponent = null; + + this._context = null; + this._mountOrder = 0; + this._topLevelWrapper = null; + + // See ReactUpdates and ReactUpdateQueue. + this._pendingCallbacks = null; + }, + + /** + * Initializes the component, renders markup, and registers event listeners. + * + * @param {string} rootID DOM ID of the root node. + * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction + * @return {?string} Rendered markup to be inserted into the DOM. + * @final + * @internal + */ + mountComponent: function (rootID, transaction, context) { + this._context = context; + this._mountOrder = nextMountID++; + this._rootNodeID = rootID; + + var publicProps = this._processProps(this._currentElement.props); + var publicContext = this._processContext(context); + + var Component = this._currentElement.type; + + // Initialize the public class + var inst; + var renderedElement; + + // This is a way to detect if Component is a stateless arrow function + // component, which is not newable. It might not be 100% reliable but is + // something we can do until we start detecting that Component extends + // React.Component. We already assume that typeof Component === 'function'. + var canInstantiate = ('prototype' in Component); + + if (canInstantiate) { + if ("development" !== 'production') { + ReactCurrentOwner.current = this; + try { + inst = new Component(publicProps, publicContext, ReactUpdateQueue); + } finally { + ReactCurrentOwner.current = null; + } + } else { + inst = new Component(publicProps, publicContext, ReactUpdateQueue); + } + } + + if (!canInstantiate || inst === null || inst === false || ReactElement.isValidElement(inst)) { + renderedElement = inst; + inst = new StatelessComponent(Component); + } + + if ("development" !== 'production') { + // This will throw later in _renderValidatedComponent, but add an early + // warning now to help debugging + if (inst.render == null) { + "development" !== 'production' ? warning(false, '%s(...): No `render` method found on the returned component ' + 'instance: you may have forgotten to define `render`, returned ' + 'null/false from a stateless component, or tried to render an ' + 'element whose type is a function that isn\'t a React component.', Component.displayName || Component.name || 'Component') : undefined; + } else { + // We support ES6 inheriting from React.Component, the module pattern, + // and stateless components, but not ES6 classes that don't extend + "development" !== 'production' ? warning(Component.prototype && Component.prototype.isReactComponent || !canInstantiate || !(inst instanceof Component), '%s(...): React component classes must extend React.Component.', Component.displayName || Component.name || 'Component') : undefined; + } + } + + // These should be set up in the constructor, but as a convenience for + // simpler class abstractions, we set them up after the fact. + inst.props = publicProps; + inst.context = publicContext; + inst.refs = emptyObject; + inst.updater = ReactUpdateQueue; + + this._instance = inst; + + // Store a reference from the instance back to the internal representation + ReactInstanceMap.set(inst, this); + + if ("development" !== 'production') { + // Since plain JS classes are defined without any special initialization + // logic, we can not catch common errors early. Therefore, we have to + // catch them here, at initialization time, instead. + "development" !== 'production' ? warning(!inst.getInitialState || inst.getInitialState.isReactClassApproved, 'getInitialState was defined on %s, a plain JavaScript class. ' + 'This is only supported for classes created using React.createClass. ' + 'Did you mean to define a state property instead?', this.getName() || 'a component') : undefined; + "development" !== 'production' ? warning(!inst.getDefaultProps || inst.getDefaultProps.isReactClassApproved, 'getDefaultProps was defined on %s, a plain JavaScript class. ' + 'This is only supported for classes created using React.createClass. ' + 'Use a static property to define defaultProps instead.', this.getName() || 'a component') : undefined; + "development" !== 'production' ? warning(!inst.propTypes, 'propTypes was defined as an instance property on %s. Use a static ' + 'property to define propTypes instead.', this.getName() || 'a component') : undefined; + "development" !== 'production' ? warning(!inst.contextTypes, 'contextTypes was defined as an instance property on %s. Use a ' + 'static property to define contextTypes instead.', this.getName() || 'a component') : undefined; + "development" !== 'production' ? warning(typeof inst.componentShouldUpdate !== 'function', '%s has a method called ' + 'componentShouldUpdate(). Did you mean shouldComponentUpdate()? ' + 'The name is phrased as a question because the function is ' + 'expected to return a value.', this.getName() || 'A component') : undefined; + "development" !== 'production' ? warning(typeof inst.componentDidUnmount !== 'function', '%s has a method called ' + 'componentDidUnmount(). But there is no such lifecycle method. ' + 'Did you mean componentWillUnmount()?', this.getName() || 'A component') : undefined; + "development" !== 'production' ? warning(typeof inst.componentWillRecieveProps !== 'function', '%s has a method called ' + 'componentWillRecieveProps(). Did you mean componentWillReceiveProps()?', this.getName() || 'A component') : undefined; + } + + var initialState = inst.state; + if (initialState === undefined) { + inst.state = initialState = null; + } + !(typeof initialState === 'object' && !Array.isArray(initialState)) ? "development" !== 'production' ? invariant(false, '%s.state: must be set to an object or null', this.getName() || 'ReactCompositeComponent') : invariant(false) : undefined; + + this._pendingStateQueue = null; + this._pendingReplaceState = false; + this._pendingForceUpdate = false; + + if (inst.componentWillMount) { + inst.componentWillMount(); + // When mounting, calls to `setState` by `componentWillMount` will set + // `this._pendingStateQueue` without triggering a re-render. + if (this._pendingStateQueue) { + inst.state = this._processPendingState(inst.props, inst.context); + } + } + + // If not a stateless component, we now render + if (renderedElement === undefined) { + renderedElement = this._renderValidatedComponent(); + } + + this._renderedComponent = this._instantiateReactComponent(renderedElement); + + var markup = ReactReconciler.mountComponent(this._renderedComponent, rootID, transaction, this._processChildContext(context)); + if (inst.componentDidMount) { + transaction.getReactMountReady().enqueue(inst.componentDidMount, inst); + } + + return markup; + }, + + /** + * Releases any resources allocated by `mountComponent`. + * + * @final + * @internal + */ + unmountComponent: function () { + var inst = this._instance; + + if (inst.componentWillUnmount) { + inst.componentWillUnmount(); + } + + ReactReconciler.unmountComponent(this._renderedComponent); + this._renderedComponent = null; + this._instance = null; + + // Reset pending fields + // Even if this component is scheduled for another update in ReactUpdates, + // it would still be ignored because these fields are reset. + this._pendingStateQueue = null; + this._pendingReplaceState = false; + this._pendingForceUpdate = false; + this._pendingCallbacks = null; + this._pendingElement = null; + + // These fields do not really need to be reset since this object is no + // longer accessible. + this._context = null; + this._rootNodeID = null; + this._topLevelWrapper = null; + + // Delete the reference from the instance to this internal representation + // which allow the internals to be properly cleaned up even if the user + // leaks a reference to the public instance. + ReactInstanceMap.remove(inst); + + // Some existing components rely on inst.props even after they've been + // destroyed (in event handlers). + // TODO: inst.props = null; + // TODO: inst.state = null; + // TODO: inst.context = null; + }, + + /** + * Filters the context object to only contain keys specified in + * `contextTypes` + * + * @param {object} context + * @return {?object} + * @private + */ + _maskContext: function (context) { + var maskedContext = null; + var Component = this._currentElement.type; + var contextTypes = Component.contextTypes; + if (!contextTypes) { + return emptyObject; + } + maskedContext = {}; + for (var contextName in contextTypes) { + maskedContext[contextName] = context[contextName]; + } + return maskedContext; + }, + + /** + * Filters the context object to only contain keys specified in + * `contextTypes`, and asserts that they are valid. + * + * @param {object} context + * @return {?object} + * @private + */ + _processContext: function (context) { + var maskedContext = this._maskContext(context); + if ("development" !== 'production') { + var Component = this._currentElement.type; + if (Component.contextTypes) { + this._checkPropTypes(Component.contextTypes, maskedContext, ReactPropTypeLocations.context); + } + } + return maskedContext; + }, + + /** + * @param {object} currentContext + * @return {object} + * @private + */ + _processChildContext: function (currentContext) { + var Component = this._currentElement.type; + var inst = this._instance; + var childContext = inst.getChildContext && inst.getChildContext(); + if (childContext) { + !(typeof Component.childContextTypes === 'object') ? "development" !== 'production' ? invariant(false, '%s.getChildContext(): childContextTypes must be defined in order to ' + 'use getChildContext().', this.getName() || 'ReactCompositeComponent') : invariant(false) : undefined; + if ("development" !== 'production') { + this._checkPropTypes(Component.childContextTypes, childContext, ReactPropTypeLocations.childContext); + } + for (var name in childContext) { + !(name in Component.childContextTypes) ? "development" !== 'production' ? invariant(false, '%s.getChildContext(): key "%s" is not defined in childContextTypes.', this.getName() || 'ReactCompositeComponent', name) : invariant(false) : undefined; + } + return assign({}, currentContext, childContext); + } + return currentContext; + }, + + /** + * Processes props by setting default values for unspecified props and + * asserting that the props are valid. Does not mutate its argument; returns + * a new props object with defaults merged in. + * + * @param {object} newProps + * @return {object} + * @private + */ + _processProps: function (newProps) { + if ("development" !== 'production') { + var Component = this._currentElement.type; + if (Component.propTypes) { + this._checkPropTypes(Component.propTypes, newProps, ReactPropTypeLocations.prop); + } + } + return newProps; + }, + + /** + * Assert that the props are valid + * + * @param {object} propTypes Map of prop name to a ReactPropType + * @param {object} props + * @param {string} location e.g. "prop", "context", "child context" + * @private + */ + _checkPropTypes: function (propTypes, props, location) { + // TODO: Stop validating prop types here and only use the element + // validation. + var componentName = this.getName(); + for (var propName in propTypes) { + if (propTypes.hasOwnProperty(propName)) { + var error; + try { + // This is intentionally an invariant that gets caught. It's the same + // behavior as without this statement except with a better message. + !(typeof propTypes[propName] === 'function') ? "development" !== 'production' ? invariant(false, '%s: %s type `%s` is invalid; it must be a function, usually ' + 'from React.PropTypes.', componentName || 'React class', ReactPropTypeLocationNames[location], propName) : invariant(false) : undefined; + error = propTypes[propName](props, propName, componentName, location); + } catch (ex) { + error = ex; + } + if (error instanceof Error) { + // We may want to extend this logic for similar errors in + // top-level render calls, so I'm abstracting it away into + // a function to minimize refactoring in the future + var addendum = getDeclarationErrorAddendum(this); + + if (location === ReactPropTypeLocations.prop) { + // Preface gives us something to blacklist in warning module + "development" !== 'production' ? warning(false, 'Failed Composite propType: %s%s', error.message, addendum) : undefined; + } else { + "development" !== 'production' ? warning(false, 'Failed Context Types: %s%s', error.message, addendum) : undefined; + } + } + } + } + }, + + receiveComponent: function (nextElement, transaction, nextContext) { + var prevElement = this._currentElement; + var prevContext = this._context; + + this._pendingElement = null; + + this.updateComponent(transaction, prevElement, nextElement, prevContext, nextContext); + }, + + /** + * If any of `_pendingElement`, `_pendingStateQueue`, or `_pendingForceUpdate` + * is set, update the component. + * + * @param {ReactReconcileTransaction} transaction + * @internal + */ + performUpdateIfNecessary: function (transaction) { + if (this._pendingElement != null) { + ReactReconciler.receiveComponent(this, this._pendingElement || this._currentElement, transaction, this._context); + } + + if (this._pendingStateQueue !== null || this._pendingForceUpdate) { + this.updateComponent(transaction, this._currentElement, this._currentElement, this._context, this._context); + } + }, + + /** + * Perform an update to a mounted component. The componentWillReceiveProps and + * shouldComponentUpdate methods are called, then (assuming the update isn't + * skipped) the remaining update lifecycle methods are called and the DOM + * representation is updated. + * + * By default, this implements React's rendering and reconciliation algorithm. + * Sophisticated clients may wish to override this. + * + * @param {ReactReconcileTransaction} transaction + * @param {ReactElement} prevParentElement + * @param {ReactElement} nextParentElement + * @internal + * @overridable + */ + updateComponent: function (transaction, prevParentElement, nextParentElement, prevUnmaskedContext, nextUnmaskedContext) { + var inst = this._instance; + + var nextContext = this._context === nextUnmaskedContext ? inst.context : this._processContext(nextUnmaskedContext); + var nextProps; + + // Distinguish between a props update versus a simple state update + if (prevParentElement === nextParentElement) { + // Skip checking prop types again -- we don't read inst.props to avoid + // warning for DOM component props in this upgrade + nextProps = nextParentElement.props; + } else { + nextProps = this._processProps(nextParentElement.props); + // An update here will schedule an update but immediately set + // _pendingStateQueue which will ensure that any state updates gets + // immediately reconciled instead of waiting for the next batch. + + if (inst.componentWillReceiveProps) { + inst.componentWillReceiveProps(nextProps, nextContext); + } + } + + var nextState = this._processPendingState(nextProps, nextContext); + + var shouldUpdate = this._pendingForceUpdate || !inst.shouldComponentUpdate || inst.shouldComponentUpdate(nextProps, nextState, nextContext); + + if ("development" !== 'production') { + "development" !== 'production' ? warning(typeof shouldUpdate !== 'undefined', '%s.shouldComponentUpdate(): Returned undefined instead of a ' + 'boolean value. Make sure to return true or false.', this.getName() || 'ReactCompositeComponent') : undefined; + } + + if (shouldUpdate) { + this._pendingForceUpdate = false; + // Will set `this.props`, `this.state` and `this.context`. + this._performComponentUpdate(nextParentElement, nextProps, nextState, nextContext, transaction, nextUnmaskedContext); + } else { + // If it's determined that a component should not update, we still want + // to set props and state but we shortcut the rest of the update. + this._currentElement = nextParentElement; + this._context = nextUnmaskedContext; + inst.props = nextProps; + inst.state = nextState; + inst.context = nextContext; + } + }, + + _processPendingState: function (props, context) { + var inst = this._instance; + var queue = this._pendingStateQueue; + var replace = this._pendingReplaceState; + this._pendingReplaceState = false; + this._pendingStateQueue = null; + + if (!queue) { + return inst.state; + } + + if (replace && queue.length === 1) { + return queue[0]; + } + + var nextState = assign({}, replace ? queue[0] : inst.state); + for (var i = replace ? 1 : 0; i < queue.length; i++) { + var partial = queue[i]; + assign(nextState, typeof partial === 'function' ? partial.call(inst, nextState, props, context) : partial); + } + + return nextState; + }, + + /** + * Merges new props and state, notifies delegate methods of update and + * performs update. + * + * @param {ReactElement} nextElement Next element + * @param {object} nextProps Next public object to set as properties. + * @param {?object} nextState Next object to set as state. + * @param {?object} nextContext Next public object to set as context. + * @param {ReactReconcileTransaction} transaction + * @param {?object} unmaskedContext + * @private + */ + _performComponentUpdate: function (nextElement, nextProps, nextState, nextContext, transaction, unmaskedContext) { + var inst = this._instance; + + var hasComponentDidUpdate = Boolean(inst.componentDidUpdate); + var prevProps; + var prevState; + var prevContext; + if (hasComponentDidUpdate) { + prevProps = inst.props; + prevState = inst.state; + prevContext = inst.context; + } + + if (inst.componentWillUpdate) { + inst.componentWillUpdate(nextProps, nextState, nextContext); + } + + this._currentElement = nextElement; + this._context = unmaskedContext; + inst.props = nextProps; + inst.state = nextState; + inst.context = nextContext; + + this._updateRenderedComponent(transaction, unmaskedContext); + + if (hasComponentDidUpdate) { + transaction.getReactMountReady().enqueue(inst.componentDidUpdate.bind(inst, prevProps, prevState, prevContext), inst); + } + }, + + /** + * Call the component's `render` method and update the DOM accordingly. + * + * @param {ReactReconcileTransaction} transaction + * @internal + */ + _updateRenderedComponent: function (transaction, context) { + var prevComponentInstance = this._renderedComponent; + var prevRenderedElement = prevComponentInstance._currentElement; + var nextRenderedElement = this._renderValidatedComponent(); + if (shouldUpdateReactComponent(prevRenderedElement, nextRenderedElement)) { + ReactReconciler.receiveComponent(prevComponentInstance, nextRenderedElement, transaction, this._processChildContext(context)); + } else { + // These two IDs are actually the same! But nothing should rely on that. + var thisID = this._rootNodeID; + var prevComponentID = prevComponentInstance._rootNodeID; + ReactReconciler.unmountComponent(prevComponentInstance); + + this._renderedComponent = this._instantiateReactComponent(nextRenderedElement); + var nextMarkup = ReactReconciler.mountComponent(this._renderedComponent, thisID, transaction, this._processChildContext(context)); + this._replaceNodeWithMarkupByID(prevComponentID, nextMarkup); + } + }, + + /** + * @protected + */ + _replaceNodeWithMarkupByID: function (prevComponentID, nextMarkup) { + ReactComponentEnvironment.replaceNodeWithMarkupByID(prevComponentID, nextMarkup); + }, + + /** + * @protected + */ + _renderValidatedComponentWithoutOwnerOrContext: function () { + var inst = this._instance; + var renderedComponent = inst.render(); + if ("development" !== 'production') { + // We allow auto-mocks to proceed as if they're returning null. + if (typeof renderedComponent === 'undefined' && inst.render._isMockFunction) { + // This is probably bad practice. Consider warning here and + // deprecating this convenience. + renderedComponent = null; + } + } + + return renderedComponent; + }, + + /** + * @private + */ + _renderValidatedComponent: function () { + var renderedComponent; + ReactCurrentOwner.current = this; + try { + renderedComponent = this._renderValidatedComponentWithoutOwnerOrContext(); + } finally { + ReactCurrentOwner.current = null; + } + !( + // TODO: An `isValidNode` function would probably be more appropriate + renderedComponent === null || renderedComponent === false || ReactElement.isValidElement(renderedComponent)) ? "development" !== 'production' ? invariant(false, '%s.render(): A valid ReactComponent must be returned. You may have ' + 'returned undefined, an array or some other invalid object.', this.getName() || 'ReactCompositeComponent') : invariant(false) : undefined; + return renderedComponent; + }, + + /** + * Lazily allocates the refs object and stores `component` as `ref`. + * + * @param {string} ref Reference name. + * @param {component} component Component to store as `ref`. + * @final + * @private + */ + attachRef: function (ref, component) { + var inst = this.getPublicInstance(); + !(inst != null) ? "development" !== 'production' ? invariant(false, 'Stateless function components cannot have refs.') : invariant(false) : undefined; + var publicComponentInstance = component.getPublicInstance(); + if ("development" !== 'production') { + var componentName = component && component.getName ? component.getName() : 'a component'; + "development" !== 'production' ? warning(publicComponentInstance != null, 'Stateless function components cannot be given refs ' + '(See ref "%s" in %s created by %s). ' + 'Attempts to access this ref will fail.', ref, componentName, this.getName()) : undefined; + } + var refs = inst.refs === emptyObject ? inst.refs = {} : inst.refs; + refs[ref] = publicComponentInstance; + }, + + /** + * Detaches a reference name. + * + * @param {string} ref Name to dereference. + * @final + * @private + */ + detachRef: function (ref) { + var refs = this.getPublicInstance().refs; + delete refs[ref]; + }, + + /** + * Get a text description of the component that can be used to identify it + * in error messages. + * @return {string} The name or null. + * @internal + */ + getName: function () { + var type = this._currentElement.type; + var constructor = this._instance && this._instance.constructor; + return type.displayName || constructor && constructor.displayName || type.name || constructor && constructor.name || null; + }, + + /** + * Get the publicly accessible representation of this component - i.e. what + * is exposed by refs and returned by render. Can be null for stateless + * components. + * + * @return {ReactComponent} the public component instance. + * @internal + */ + getPublicInstance: function () { + var inst = this._instance; + if (inst instanceof StatelessComponent) { + return null; + } + return inst; + }, + + // Stub + _instantiateReactComponent: null + +}; + +ReactPerf.measureMethods(ReactCompositeComponentMixin, 'ReactCompositeComponent', { + mountComponent: 'mountComponent', + updateComponent: 'updateComponent', + _renderValidatedComponent: '_renderValidatedComponent' +}); + +var ReactCompositeComponent = { + + Mixin: ReactCompositeComponentMixin + +}; + +module.exports = ReactCompositeComponent; +},{"141":141,"154":154,"161":161,"173":173,"24":24,"36":36,"39":39,"57":57,"68":68,"78":78,"80":80,"81":81,"84":84,"95":95}],39:[function(_dereq_,module,exports){ +/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactCurrentOwner + */ + +'use strict'; + +/** + * Keeps track of the current owner. + * + * The current owner is the component who should own any components that are + * currently being constructed. + */ +var ReactCurrentOwner = { + + /** + * @internal + * @type {ReactComponent} + */ + current: null + +}; + +module.exports = ReactCurrentOwner; +},{}],40:[function(_dereq_,module,exports){ +/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactDOM + */ + +/* globals __REACT_DEVTOOLS_GLOBAL_HOOK__*/ + +'use strict'; + +var ReactCurrentOwner = _dereq_(39); +var ReactDOMTextComponent = _dereq_(51); +var ReactDefaultInjection = _dereq_(54); +var ReactInstanceHandles = _dereq_(67); +var ReactMount = _dereq_(72); +var ReactPerf = _dereq_(78); +var ReactReconciler = _dereq_(84); +var ReactUpdates = _dereq_(96); +var ReactVersion = _dereq_(97); + +var findDOMNode = _dereq_(122); +var renderSubtreeIntoContainer = _dereq_(137); +var warning = _dereq_(173); + +ReactDefaultInjection.inject(); + +var render = ReactPerf.measure('React', 'render', ReactMount.render); + +var React = { + findDOMNode: findDOMNode, + render: render, + unmountComponentAtNode: ReactMount.unmountComponentAtNode, + version: ReactVersion, + + /* eslint-disable camelcase */ + unstable_batchedUpdates: ReactUpdates.batchedUpdates, + unstable_renderSubtreeIntoContainer: renderSubtreeIntoContainer +}; + +// Inject the runtime into a devtools global hook regardless of browser. +// Allows for debugging when the hook is injected on the page. +/* eslint-enable camelcase */ +if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== 'undefined' && typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.inject === 'function') { + __REACT_DEVTOOLS_GLOBAL_HOOK__.inject({ + CurrentOwner: ReactCurrentOwner, + InstanceHandles: ReactInstanceHandles, + Mount: ReactMount, + Reconciler: ReactReconciler, + TextComponent: ReactDOMTextComponent + }); +} + +if ("development" !== 'production') { + var ExecutionEnvironment = _dereq_(147); + if (ExecutionEnvironment.canUseDOM && window.top === window.self) { + + // First check if devtools is not installed + if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === 'undefined') { + // If we're in Chrome or Firefox, provide a download link if not installed. + if (navigator.userAgent.indexOf('Chrome') > -1 && navigator.userAgent.indexOf('Edge') === -1 || navigator.userAgent.indexOf('Firefox') > -1) { + console.debug('Download the React DevTools for a better development experience: ' + 'https://fb.me/react-devtools'); + } + } + + // If we're in IE8, check to see if we are in compatibility mode and provide + // information on preventing compatibility mode + var ieCompatibilityMode = document.documentMode && document.documentMode < 8; + + "development" !== 'production' ? warning(!ieCompatibilityMode, 'Internet Explorer is running in compatibility mode; please add the ' + 'following tag to your HTML to prevent this from happening: ' + '') : undefined; + + var expectedFeatures = [ + // shims + Array.isArray, Array.prototype.every, Array.prototype.forEach, Array.prototype.indexOf, Array.prototype.map, Date.now, Function.prototype.bind, Object.keys, String.prototype.split, String.prototype.trim, + + // shams + Object.create, Object.freeze]; + + for (var i = 0; i < expectedFeatures.length; i++) { + if (!expectedFeatures[i]) { + console.error('One or more ES5 shim/shams expected by React are not available: ' + 'https://fb.me/react-warning-polyfills'); + break; + } + } + } +} + +module.exports = React; +},{"122":122,"137":137,"147":147,"173":173,"39":39,"51":51,"54":54,"67":67,"72":72,"78":78,"84":84,"96":96,"97":97}],41:[function(_dereq_,module,exports){ +/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactDOMButton + */ + +'use strict'; + +var mouseListenerNames = { + onClick: true, + onDoubleClick: true, + onMouseDown: true, + onMouseMove: true, + onMouseUp: true, + + onClickCapture: true, + onDoubleClickCapture: true, + onMouseDownCapture: true, + onMouseMoveCapture: true, + onMouseUpCapture: true +}; + +/** + * Implements a