# HG changeset patch # User StephaneLenclud # Date 1483874375 -3600 # Node ID 2481c46d1f933a0af7b665d780fdcd73a79e1603 # Parent 71ba0dd622a5394dbd4119bf002a0015b4b4d68a Reading audio output is stopped when audio visualizers are not in used. diff -r 71ba0dd622a5 -r 2481c46d1f93 Server/AudioManager.cs --- a/Server/AudioManager.cs Sat Jan 07 20:21:42 2017 +0100 +++ b/Server/AudioManager.cs Sun Jan 08 12:19:35 2017 +0100 @@ -32,13 +32,47 @@ private WasapiCapture iSoundIn; private IWaveSource iWaveSource; private LineSpectrum iLineSpectrum; - + private int iVisualizerCount = 0; public LineSpectrum Spectrum { get { return iLineSpectrum; } } public AudioEndpointVolume Volume { get { return iAudioEndpointVolume; } } public MMDevice DefaultDevice { get { return iMultiMediaDevice; } } /// + /// Increment our visualizer count + /// + public void AddVisualizer() + { + if (iVisualizerCount == 0) + { + // If we need at least one visualizer then we need to start our engine. + StartAudioVisualization(); + } + + //TODO: Check bounds? + iVisualizerCount++; + } + + /// + /// Decrement our visualizer counter. + /// + public void RemoveVisualizer() + { + if (iVisualizerCount == 1) + { + // When reaching zero visualization is not need and we stop our engine + StopAudioVisualization(); + iVisualizerCount = 0; + } + // Defensive: Make sure we don't go below zero + else if (iVisualizerCount>0) + { + iVisualizerCount--; + } + } + + + /// /// /// /// @@ -57,7 +91,11 @@ iAudioEndpointVolumeCallback.NotifyRecived += iVolumeChangedHandler = aVolumeChangedHandler; iAudioEndpointVolume.RegisterControlChangeNotify(iAudioEndpointVolumeCallback); - StartAudioVisualization(); + if (iVisualizerCount > 0) + { + // We probably got restarted, make sure visualization is running if needed + StartAudioVisualization(); + } } /// @@ -130,11 +168,11 @@ iLineSpectrum = new LineSpectrum(fftSize) { SpectrumProvider = spectrumProvider, - UseAverage = false, + UseAverage = false, // Does not matter since we hacked it BarCount = 16, BarSpacing = 1, - IsXLogScale = true, - ScalingStrategy = ScalingStrategy.Decibel + IsXLogScale = true, // Does not matter since we hacked it + ScalingStrategy = ScalingStrategy.Decibel // Does not matter since we hacked it }; @@ -164,7 +202,12 @@ /// private void StopAudioVisualization() { - if (iWaveSource != null) + if (iSoundIn != null) + { + iSoundIn.Stop(); + } + + if (iWaveSource != null) { iWaveSource.Dispose(); iWaveSource = null; @@ -172,11 +215,11 @@ if (iSoundIn != null) { - iSoundIn.Stop(); iSoundIn.Dispose(); iSoundIn = null; } + iLineSpectrum = null; } diff -r 71ba0dd622a5 -r 2481c46d1f93 Server/FormMain.cs --- a/Server/FormMain.cs Sat Jan 07 20:21:42 2017 +0100 +++ b/Server/FormMain.cs Sun Jan 08 12:19:35 2017 +0100 @@ -256,6 +256,7 @@ #if !DEBUG //When not debugging we want the screen to be empty until a client takes over ClearLayout(); + iCurrentClientData = null; #else //When developing we want at least one client for testing StartNewClient("abcdefghijklmnopqrst-0123456789", "ABCDEFGHIJKLMNOPQRST-0123456789"); @@ -656,7 +657,7 @@ } // Update our math - if (iAudioManager==null || !iAudioManager.Spectrum.Update()) + if (iAudioManager==null || iAudioManager.Spectrum==null || !iAudioManager.Spectrum.Update()) { //Nothing changed no need to render return; @@ -1560,6 +1561,7 @@ if (iClients.Count == 0) { ClearLayout(); + iCurrentClientData = null; } } @@ -1568,10 +1570,22 @@ /// private void ClearLayout() { + // For each loop did not work as calling Dispose on a control removes it from the collection. + // We make sure every control are disposed of notably to turn off visualizer when no more needed. + // That's the only way we found to make sure Control.Disposed is called in a timely fashion. + // Though that loop is admetitly dangerous as if one of the control does not removes itself from the list we end up with infinite loop. + // That's what happened with our MarqueeLabel until we fixed it's Dispose override. + while (iTableLayoutPanel.Controls.Count>0) + { + // Dispose our last item + iTableLayoutPanel.Controls[iTableLayoutPanel.Controls.Count-1].Dispose(); + } + iTableLayoutPanel.Controls.Clear(); iTableLayoutPanel.RowStyles.Clear(); iTableLayoutPanel.ColumnStyles.Clear(); - iCurrentClientData = null; + iTableLayoutPanel.RowCount = 0; + iTableLayoutPanel.ColumnCount = 0; } /// @@ -1751,6 +1765,7 @@ { //Clear our screen when last client disconnects ClearLayout(); + iCurrentClientData = null; if (iClosing) { @@ -2208,11 +2223,7 @@ TableLayout layout = aClient.Layout; //First clean our current panel - iTableLayoutPanel.Controls.Clear(); - iTableLayoutPanel.RowStyles.Clear(); - iTableLayoutPanel.ColumnStyles.Clear(); - iTableLayoutPanel.RowCount = 0; - iTableLayoutPanel.ColumnCount = 0; + ClearLayout(); //Then recreate our rows... while (iTableLayoutPanel.RowCount < layout.Rows.Count) @@ -2331,6 +2342,21 @@ picture.Location = new System.Drawing.Point(1, 1); picture.Margin = new System.Windows.Forms.Padding(0); picture.Name = "pictureBox" + aField; + + // Make sure visualization is running + iAudioManager.AddVisualizer(); + + // Notify audio manager when we don't need audio visualizer anymore + picture.Disposed += (sender, e) => + { + if (iAudioManager != null) + { + // Make sure we stop visualization when not needed + iAudioManager.RemoveVisualizer(); + } + }; + + // Create a new bitmap when control size changes picture.SizeChanged += (sender, e) => { // Somehow bitmap created when our from is invisible are not working diff -r 71ba0dd622a5 -r 2481c46d1f93 Server/MarqueeLabel.cs --- a/Server/MarqueeLabel.cs Sat Jan 07 20:21:42 2017 +0100 +++ b/Server/MarqueeLabel.cs Sun Jan 08 12:19:35 2017 +0100 @@ -411,12 +411,23 @@ return false; } + /// + /// See Dispose Pattern reference: + /// https://msdn.microsoft.com/en-us/library/b1yfkh5e%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396 + /// + /// protected override void Dispose(bool disposing) { + // My sure we hook the rest of the framework. + // That's most important for controls since they do things like removing themselves from containers upon disposal. + base.Dispose(disposing); + // My understanding is that one is not supose to Dispose other objects unless disposing is true. if (disposing) { if (Timer != null) + { Timer.Dispose(); + } } Timer = null; } diff -r 71ba0dd622a5 -r 2481c46d1f93 Server/Spectrum/SpectrumBase.cs --- a/Server/Spectrum/SpectrumBase.cs Sat Jan 07 20:21:42 2017 +0100 +++ b/Server/Spectrum/SpectrumBase.cs Sun Jan 08 12:19:35 2017 +0100 @@ -162,10 +162,10 @@ { var dataPoints = new List(); - double value0 = 0, value = 0; - double lastValue = 0; - double actualMaxValue = maxValue; - int spectrumPointIndex = 0; + //double value0 = 0, value = 0; + //double lastValue = 0; + //double actualMaxValue = maxValue; + //int spectrumPointIndex = 0; int b0 = _minimumFrequencyIndex; int x, y;