Starting renaming to HTCIC.
Setup update and test.
2 using System.Collections.Generic;
5 using System.Threading.Tasks;
12 using CSCore.CoreAudioAPI;
18 namespace SharpDisplayManager
23 private MMDeviceEnumerator iMultiMediaDeviceEnumerator;
24 private MMNotificationClient iMultiMediaNotificationClient;
25 private MMDevice iMultiMediaDevice;
26 private AudioEndpointVolume iAudioEndpointVolume;
27 private AudioEndpointVolumeCallback iAudioEndpointVolumeCallback;
28 EventHandler<DefaultDeviceChangedEventArgs> iDefaultDeviceChangedHandler;
29 EventHandler<AudioEndpointVolumeCallbackEventArgs> iVolumeChangedHandler;
31 // Audio visualization
32 private WasapiCapture iSoundIn;
33 private IWaveSource iWaveSource;
34 private LineSpectrum iLineSpectrum;
35 private int iVisualizerCount = 0;
37 public LineSpectrum Spectrum { get { return iLineSpectrum; } }
38 public AudioEndpointVolume Volume { get { return iAudioEndpointVolume; } }
39 public MMDevice DefaultDevice { get { return iMultiMediaDevice; } }
42 /// Increment our visualizer count
44 public void AddVisualizer()
46 if (iVisualizerCount == 0)
48 // If we need at least one visualizer then we need to start our engine.
49 StartAudioVisualization();
57 /// Decrement our visualizer counter.
59 public void RemoveVisualizer()
61 if (iVisualizerCount == 1)
63 // When reaching zero visualization is not need and we stop our engine
64 StopAudioVisualization();
67 // Defensive: Make sure we don't go below zero
68 else if (iVisualizerCount>0)
78 /// <param name="aDefaultDeviceChangedHandler"></param>
79 /// <param name="aVolumeChangedHandler"></param>
80 public void Open( EventHandler<DefaultDeviceChangedEventArgs> aDefaultDeviceChangedHandler,
81 EventHandler<AudioEndpointVolumeCallbackEventArgs> aVolumeChangedHandler)
83 //Create device and register default device change notification
84 iMultiMediaDeviceEnumerator = new MMDeviceEnumerator();
85 iMultiMediaNotificationClient = new MMNotificationClient(iMultiMediaDeviceEnumerator);
86 iMultiMediaNotificationClient.DefaultDeviceChanged += iDefaultDeviceChangedHandler = aDefaultDeviceChangedHandler;
87 iMultiMediaDevice = iMultiMediaDeviceEnumerator.GetDefaultAudioEndpoint(DataFlow.Render,Role.Multimedia);
88 //Register to get volume modifications
89 iAudioEndpointVolume = AudioEndpointVolume.FromDevice(iMultiMediaDevice);
90 iAudioEndpointVolumeCallback = new AudioEndpointVolumeCallback();
91 iAudioEndpointVolumeCallback.NotifyRecived += iVolumeChangedHandler = aVolumeChangedHandler;
92 iAudioEndpointVolume.RegisterControlChangeNotify(iAudioEndpointVolumeCallback);
94 if (iVisualizerCount > 0)
96 // We probably got restarted, make sure visualization is running if needed
97 StartAudioVisualization();
106 StopAudioVisualization();
108 // Client up our MM objects in reverse order
109 if (iAudioEndpointVolumeCallback != null && iAudioEndpointVolume != null)
111 iAudioEndpointVolume.UnregisterControlChangeNotify(iAudioEndpointVolumeCallback);
114 if (iAudioEndpointVolumeCallback != null)
116 iAudioEndpointVolumeCallback.NotifyRecived -= iVolumeChangedHandler;
117 iAudioEndpointVolumeCallback = null;
120 if (iAudioEndpointVolume != null)
122 iAudioEndpointVolume.Dispose();
123 iAudioEndpointVolume = null;
126 if (iMultiMediaDevice != null)
128 iMultiMediaDevice.Dispose();
129 iMultiMediaDevice = null;
132 if (iMultiMediaNotificationClient != null)
134 iMultiMediaNotificationClient.DefaultDeviceChanged -= iDefaultDeviceChangedHandler;
135 iMultiMediaNotificationClient.Dispose();
136 iMultiMediaNotificationClient = null;
139 if (iMultiMediaDeviceEnumerator != null)
141 iMultiMediaDeviceEnumerator.Dispose();
142 iMultiMediaDeviceEnumerator = null;
151 private void StartAudioVisualization()
153 //Open the default device
154 iSoundIn = new WasapiLoopbackCapture();
155 //Our loopback capture opens the default render device by default so the following is not needed
156 //iSoundIn.Device = MMDeviceEnumerator.DefaultAudioEndpoint(DataFlow.Render, Role.Console);
157 iSoundIn.Initialize();
159 SoundInSource soundInSource = new SoundInSource(iSoundIn);
160 ISampleSource source = soundInSource.ToSampleSource();
162 const FftSize fftSize = FftSize.Fft2048;
163 //create a spectrum provider which provides fft data based on some input
164 BasicSpectrumProvider spectrumProvider = new BasicSpectrumProvider(source.WaveFormat.Channels, source.WaveFormat.SampleRate, fftSize);
166 //linespectrum and voiceprint3dspectrum used for rendering some fft data
167 //in oder to get some fft data, set the previously created spectrumprovider
168 iLineSpectrum = new LineSpectrum(fftSize)
170 SpectrumProvider = spectrumProvider,
171 UseAverage = false, // Does not matter since we hacked it
174 IsXLogScale = true, // Does not matter since we hacked it
175 ScalingStrategy = ScalingStrategy.Decibel // Does not matter since we hacked it
179 //the SingleBlockNotificationStream is used to intercept the played samples
180 var notificationSource = new SingleBlockNotificationStream(source);
181 //pass the intercepted samples as input data to the spectrumprovider (which will calculate a fft based on them)
182 notificationSource.SingleBlockRead += (s, a) => spectrumProvider.Add(a.Left, a.Right);
184 iWaveSource = notificationSource.ToWaveSource(16);
187 // We need to read from our source otherwise SingleBlockRead is never called and our spectrum provider is not populated
188 byte[] buffer = new byte[iWaveSource.WaveFormat.BytesPerSecond / 2];
189 soundInSource.DataAvailable += (s, aEvent) =>
192 while ((read = iWaveSource.Read(buffer, 0, buffer.Length)) > 0) ;
203 private void StopAudioVisualization()
205 if (iSoundIn != null)
210 if (iWaveSource != null)
212 iWaveSource.Dispose();
216 if (iSoundIn != null)
222 iLineSpectrum = null;