Reading audio output is stopped when audio visualizers are not in used.
1.1 --- a/Server/AudioManager.cs Sat Jan 07 20:21:42 2017 +0100
1.2 +++ b/Server/AudioManager.cs Sun Jan 08 12:19:35 2017 +0100
1.3 @@ -32,13 +32,47 @@
1.4 private WasapiCapture iSoundIn;
1.5 private IWaveSource iWaveSource;
1.6 private LineSpectrum iLineSpectrum;
1.7 -
1.8 + private int iVisualizerCount = 0;
1.9
1.10 public LineSpectrum Spectrum { get { return iLineSpectrum; } }
1.11 public AudioEndpointVolume Volume { get { return iAudioEndpointVolume; } }
1.12 public MMDevice DefaultDevice { get { return iMultiMediaDevice; } }
1.13
1.14 /// <summary>
1.15 + /// Increment our visualizer count
1.16 + /// </summary>
1.17 + public void AddVisualizer()
1.18 + {
1.19 + if (iVisualizerCount == 0)
1.20 + {
1.21 + // If we need at least one visualizer then we need to start our engine.
1.22 + StartAudioVisualization();
1.23 + }
1.24 +
1.25 + //TODO: Check bounds?
1.26 + iVisualizerCount++;
1.27 + }
1.28 +
1.29 + /// <summary>
1.30 + /// Decrement our visualizer counter.
1.31 + /// </summary>
1.32 + public void RemoveVisualizer()
1.33 + {
1.34 + if (iVisualizerCount == 1)
1.35 + {
1.36 + // When reaching zero visualization is not need and we stop our engine
1.37 + StopAudioVisualization();
1.38 + iVisualizerCount = 0;
1.39 + }
1.40 + // Defensive: Make sure we don't go below zero
1.41 + else if (iVisualizerCount>0)
1.42 + {
1.43 + iVisualizerCount--;
1.44 + }
1.45 + }
1.46 +
1.47 +
1.48 + /// <summary>
1.49 ///
1.50 /// </summary>
1.51 /// <param name="aDefaultDeviceChangedHandler"></param>
1.52 @@ -57,7 +91,11 @@
1.53 iAudioEndpointVolumeCallback.NotifyRecived += iVolumeChangedHandler = aVolumeChangedHandler;
1.54 iAudioEndpointVolume.RegisterControlChangeNotify(iAudioEndpointVolumeCallback);
1.55
1.56 - StartAudioVisualization();
1.57 + if (iVisualizerCount > 0)
1.58 + {
1.59 + // We probably got restarted, make sure visualization is running if needed
1.60 + StartAudioVisualization();
1.61 + }
1.62 }
1.63
1.64 /// <summary>
1.65 @@ -130,11 +168,11 @@
1.66 iLineSpectrum = new LineSpectrum(fftSize)
1.67 {
1.68 SpectrumProvider = spectrumProvider,
1.69 - UseAverage = false,
1.70 + UseAverage = false, // Does not matter since we hacked it
1.71 BarCount = 16,
1.72 BarSpacing = 1,
1.73 - IsXLogScale = true,
1.74 - ScalingStrategy = ScalingStrategy.Decibel
1.75 + IsXLogScale = true, // Does not matter since we hacked it
1.76 + ScalingStrategy = ScalingStrategy.Decibel // Does not matter since we hacked it
1.77 };
1.78
1.79
1.80 @@ -164,7 +202,12 @@
1.81 /// </summary>
1.82 private void StopAudioVisualization()
1.83 {
1.84 - if (iWaveSource != null)
1.85 + if (iSoundIn != null)
1.86 + {
1.87 + iSoundIn.Stop();
1.88 + }
1.89 +
1.90 + if (iWaveSource != null)
1.91 {
1.92 iWaveSource.Dispose();
1.93 iWaveSource = null;
1.94 @@ -172,11 +215,11 @@
1.95
1.96 if (iSoundIn != null)
1.97 {
1.98 - iSoundIn.Stop();
1.99 iSoundIn.Dispose();
1.100 iSoundIn = null;
1.101 }
1.102
1.103 + iLineSpectrum = null;
1.104 }
1.105
1.106
2.1 --- a/Server/FormMain.cs Sat Jan 07 20:21:42 2017 +0100
2.2 +++ b/Server/FormMain.cs Sun Jan 08 12:19:35 2017 +0100
2.3 @@ -256,6 +256,7 @@
2.4 #if !DEBUG
2.5 //When not debugging we want the screen to be empty until a client takes over
2.6 ClearLayout();
2.7 + iCurrentClientData = null;
2.8 #else
2.9 //When developing we want at least one client for testing
2.10 StartNewClient("abcdefghijklmnopqrst-0123456789", "ABCDEFGHIJKLMNOPQRST-0123456789");
2.11 @@ -656,7 +657,7 @@
2.12 }
2.13
2.14 // Update our math
2.15 - if (iAudioManager==null || !iAudioManager.Spectrum.Update())
2.16 + if (iAudioManager==null || iAudioManager.Spectrum==null || !iAudioManager.Spectrum.Update())
2.17 {
2.18 //Nothing changed no need to render
2.19 return;
2.20 @@ -1560,6 +1561,7 @@
2.21 if (iClients.Count == 0)
2.22 {
2.23 ClearLayout();
2.24 + iCurrentClientData = null;
2.25 }
2.26 }
2.27
2.28 @@ -1568,10 +1570,22 @@
2.29 /// </summary>
2.30 private void ClearLayout()
2.31 {
2.32 + // For each loop did not work as calling Dispose on a control removes it from the collection.
2.33 + // We make sure every control are disposed of notably to turn off visualizer when no more needed.
2.34 + // That's the only way we found to make sure Control.Disposed is called in a timely fashion.
2.35 + // 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.
2.36 + // That's what happened with our MarqueeLabel until we fixed it's Dispose override.
2.37 + while (iTableLayoutPanel.Controls.Count>0)
2.38 + {
2.39 + // Dispose our last item
2.40 + iTableLayoutPanel.Controls[iTableLayoutPanel.Controls.Count-1].Dispose();
2.41 + }
2.42 +
2.43 iTableLayoutPanel.Controls.Clear();
2.44 iTableLayoutPanel.RowStyles.Clear();
2.45 iTableLayoutPanel.ColumnStyles.Clear();
2.46 - iCurrentClientData = null;
2.47 + iTableLayoutPanel.RowCount = 0;
2.48 + iTableLayoutPanel.ColumnCount = 0;
2.49 }
2.50
2.51 /// <summary>
2.52 @@ -1751,6 +1765,7 @@
2.53 {
2.54 //Clear our screen when last client disconnects
2.55 ClearLayout();
2.56 + iCurrentClientData = null;
2.57
2.58 if (iClosing)
2.59 {
2.60 @@ -2208,11 +2223,7 @@
2.61 TableLayout layout = aClient.Layout;
2.62
2.63 //First clean our current panel
2.64 - iTableLayoutPanel.Controls.Clear();
2.65 - iTableLayoutPanel.RowStyles.Clear();
2.66 - iTableLayoutPanel.ColumnStyles.Clear();
2.67 - iTableLayoutPanel.RowCount = 0;
2.68 - iTableLayoutPanel.ColumnCount = 0;
2.69 + ClearLayout();
2.70
2.71 //Then recreate our rows...
2.72 while (iTableLayoutPanel.RowCount < layout.Rows.Count)
2.73 @@ -2331,6 +2342,21 @@
2.74 picture.Location = new System.Drawing.Point(1, 1);
2.75 picture.Margin = new System.Windows.Forms.Padding(0);
2.76 picture.Name = "pictureBox" + aField;
2.77 +
2.78 + // Make sure visualization is running
2.79 + iAudioManager.AddVisualizer();
2.80 +
2.81 + // Notify audio manager when we don't need audio visualizer anymore
2.82 + picture.Disposed += (sender, e) =>
2.83 + {
2.84 + if (iAudioManager != null)
2.85 + {
2.86 + // Make sure we stop visualization when not needed
2.87 + iAudioManager.RemoveVisualizer();
2.88 + }
2.89 + };
2.90 +
2.91 + // Create a new bitmap when control size changes
2.92 picture.SizeChanged += (sender, e) =>
2.93 {
2.94 // Somehow bitmap created when our from is invisible are not working
3.1 --- a/Server/MarqueeLabel.cs Sat Jan 07 20:21:42 2017 +0100
3.2 +++ b/Server/MarqueeLabel.cs Sun Jan 08 12:19:35 2017 +0100
3.3 @@ -411,12 +411,23 @@
3.4 return false;
3.5 }
3.6
3.7 + /// <summary>
3.8 + /// See Dispose Pattern reference:
3.9 + /// https://msdn.microsoft.com/en-us/library/b1yfkh5e%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396
3.10 + /// </summary>
3.11 + /// <param name="disposing"></param>
3.12 protected override void Dispose(bool disposing)
3.13 {
3.14 + // My sure we hook the rest of the framework.
3.15 + // That's most important for controls since they do things like removing themselves from containers upon disposal.
3.16 + base.Dispose(disposing);
3.17 + // My understanding is that one is not supose to Dispose other objects unless disposing is true.
3.18 if (disposing)
3.19 {
3.20 if (Timer != null)
3.21 + {
3.22 Timer.Dispose();
3.23 + }
3.24 }
3.25 Timer = null;
3.26 }
4.1 --- a/Server/Spectrum/SpectrumBase.cs Sat Jan 07 20:21:42 2017 +0100
4.2 +++ b/Server/Spectrum/SpectrumBase.cs Sun Jan 08 12:19:35 2017 +0100
4.3 @@ -162,10 +162,10 @@
4.4 {
4.5 var dataPoints = new List<SpectrumPointData>();
4.6
4.7 - double value0 = 0, value = 0;
4.8 - double lastValue = 0;
4.9 - double actualMaxValue = maxValue;
4.10 - int spectrumPointIndex = 0;
4.11 + //double value0 = 0, value = 0;
4.12 + //double lastValue = 0;
4.13 + //double actualMaxValue = maxValue;
4.14 + //int spectrumPointIndex = 0;
4.15
4.16 int b0 = _minimumFrequencyIndex;
4.17 int x, y;