Server/FormMain.cs
changeset 277 71ba0dd622a5
parent 276 7cd495550d5f
child 278 2481c46d1f93
     1.1 --- a/Server/FormMain.cs	Fri Jan 06 18:27:19 2017 +0100
     1.2 +++ b/Server/FormMain.cs	Sat Jan 07 20:21:42 2017 +0100
     1.3 @@ -79,15 +79,13 @@
     1.4  
     1.5      public delegate void SetClientPriorityDelegate(string aSessionId, uint aPriority);
     1.6  
     1.7 -    public delegate void PlainUpdateDelegate();
     1.8 -
     1.9      public delegate void WndProcDelegate(ref Message aMessage);
    1.10  
    1.11      /// <summary>
    1.12      /// Our Display manager main form
    1.13      /// </summary>
    1.14      [System.ComponentModel.DesignerCategory("Form")]
    1.15 -    public partial class FormMain : FormMainHid, IMMNotificationClient
    1.16 +    public partial class FormMain : FormMainHid
    1.17      {
    1.18          //public Manager iManager = new Manager();        
    1.19          DateTime LastTickTime;
    1.20 @@ -111,15 +109,8 @@
    1.21          CoordinateTranslationDelegate iScreenX;
    1.22          //Function pointer for pixel Y coordinate intercept
    1.23          CoordinateTranslationDelegate iScreenY;
    1.24 -        //CSCore
    1.25 -        // Volume management
    1.26 -        private MMDeviceEnumerator iMultiMediaDeviceEnumerator;
    1.27 -        private MMDevice iMultiMediaDevice;
    1.28 -        private AudioEndpointVolume iAudioEndpointVolume;
    1.29 -        // Audio visualization
    1.30 -        private WasapiCapture iSoundIn;
    1.31 -        private IWaveSource iWaveSource;
    1.32 -        private LineSpectrum iLineSpectrum;
    1.33 +        //Audio
    1.34 +        private AudioManager iAudioManager;
    1.35  
    1.36          //Network
    1.37          private NetworkManager iNetworkManager;
    1.38 @@ -232,9 +223,7 @@
    1.39              }
    1.40  
    1.41              //CSCore
    1.42 -            iMultiMediaDeviceEnumerator = new MMDeviceEnumerator();
    1.43 -            iMultiMediaDeviceEnumerator.RegisterEndpointNotificationCallback(this);
    1.44 -            UpdateAudioDeviceAndMasterVolumeThreadSafe();
    1.45 +            CreateAudioManager();
    1.46  
    1.47              //Network
    1.48              iNetworkManager = new NetworkManager();
    1.49 @@ -291,6 +280,54 @@
    1.50              }
    1.51          }
    1.52  
    1.53 +
    1.54 +        private void CreateAudioManager()
    1.55 +        {
    1.56 +            iAudioManager = new AudioManager();
    1.57 +            iAudioManager.Open(OnDefaultMultiMediaDeviceChanged, OnVolumeNotification);
    1.58 +            UpdateAudioDeviceAndMasterVolumeThreadSafe();
    1.59 +        }
    1.60 +
    1.61 +        private void DestroyAudioManager()
    1.62 +        {
    1.63 +            if (iAudioManager != null)
    1.64 +            {
    1.65 +                iAudioManager.Close();
    1.66 +                iAudioManager = null;
    1.67 +            }
    1.68 +        }
    1.69 +
    1.70 +        /// <summary>
    1.71 +        /// 
    1.72 +        /// </summary>
    1.73 +        /// <param name="sender"></param>
    1.74 +        /// <param name="aEvent"></param>
    1.75 +        public void OnDefaultMultiMediaDeviceChanged(object sender, DefaultDeviceChangedEventArgs aEvent)
    1.76 +        {
    1.77 +            if (aEvent.DataFlow == DataFlow.Render && aEvent.Role == Role.Multimedia)
    1.78 +            {
    1.79 +                ResetAudioManagerThreadSafe();
    1.80 +            }
    1.81 +        }
    1.82 +
    1.83 +        /// <summary>
    1.84 +        /// 
    1.85 +        /// </summary>
    1.86 +        private void ResetAudioManagerThreadSafe()
    1.87 +        {
    1.88 +            if (InvokeRequired)
    1.89 +            {
    1.90 +                //Not in the proper thread, invoke ourselves
    1.91 +                BeginInvoke(new Action<FormMain>((sender) => { ResetAudioManagerThreadSafe(); }), this);
    1.92 +                return;
    1.93 +            }
    1.94 +
    1.95 +            //Proper thread, go ahead
    1.96 +            DestroyAudioManager();
    1.97 +            CreateAudioManager();
    1.98 +
    1.99 +        }
   1.100 +
   1.101          /// <summary>
   1.102          /// Called when our display is opened.
   1.103          /// </summary>
   1.104 @@ -511,7 +548,7 @@
   1.105          /// Receive volume change notification and reflect changes on our slider.
   1.106          /// </summary>
   1.107          /// <param name="data"></param>
   1.108 -        public void OnVolumeNotificationThreadSafe(object sender, AudioEndpointVolumeCallbackEventArgs aEvent)
   1.109 +        public void OnVolumeNotification(object sender, AudioEndpointVolumeCallbackEventArgs aEvent)
   1.110          {
   1.111              UpdateMasterVolumeThreadSafe();
   1.112          }
   1.113 @@ -524,9 +561,9 @@
   1.114          private void trackBarMasterVolume_Scroll(object sender, EventArgs e)
   1.115          {
   1.116              //Just like Windows Volume Mixer we unmute if the volume is adjusted
   1.117 -            iAudioEndpointVolume.IsMuted = false;
   1.118 +            iAudioManager.Volume.IsMuted = false;
   1.119              //Set volume level according to our volume slider new position
   1.120 -            iAudioEndpointVolume.MasterVolumeLevelScalar = trackBarMasterVolume.Value/100.0f;
   1.121 +            iAudioManager.Volume.MasterVolumeLevelScalar = trackBarMasterVolume.Value/100.0f;
   1.122          }
   1.123  
   1.124  
   1.125 @@ -537,54 +574,9 @@
   1.126          /// <param name="e"></param>
   1.127          private void checkBoxMute_CheckedChanged(object sender, EventArgs e)
   1.128          {
   1.129 -            iAudioEndpointVolume.IsMuted = checkBoxMute.Checked;
   1.130 +            iAudioManager.Volume.IsMuted = checkBoxMute.Checked;
   1.131          }
   1.132  
   1.133 -        /// <summary>
   1.134 -        /// Device State Changed
   1.135 -        /// </summary>
   1.136 -        public void OnDeviceStateChanged([MarshalAs(UnmanagedType.LPWStr)] string deviceId,
   1.137 -            [MarshalAs(UnmanagedType.I4)] DeviceState newState)
   1.138 -        {
   1.139 -        }
   1.140 -
   1.141 -        /// <summary>
   1.142 -        /// Device Added
   1.143 -        /// </summary>
   1.144 -        public void OnDeviceAdded([MarshalAs(UnmanagedType.LPWStr)] string pwstrDeviceId)
   1.145 -        {
   1.146 -        }
   1.147 -
   1.148 -        /// <summary>
   1.149 -        /// Device Removed
   1.150 -        /// </summary>
   1.151 -        public void OnDeviceRemoved([MarshalAs(UnmanagedType.LPWStr)] string deviceId)
   1.152 -        {
   1.153 -        }
   1.154 -
   1.155 -        /// <summary>
   1.156 -        /// Default Device Changed
   1.157 -        /// </summary>
   1.158 -        public void OnDefaultDeviceChanged(DataFlow flow, Role role,
   1.159 -            [MarshalAs(UnmanagedType.LPWStr)] string defaultDeviceId)
   1.160 -        {
   1.161 -            if (role == Role.Multimedia && flow == DataFlow.Render)
   1.162 -            {
   1.163 -                UpdateAudioDeviceAndMasterVolumeThreadSafe();
   1.164 -            }
   1.165 -        }
   1.166 -
   1.167 -        /// <summary>
   1.168 -        /// Property Value Changed
   1.169 -        /// </summary>
   1.170 -        /// <param name="pwstrDeviceId"></param>
   1.171 -        /// <param name="key"></param>
   1.172 -        public void OnPropertyValueChanged([MarshalAs(UnmanagedType.LPWStr)] string pwstrDeviceId, PropertyKey key)
   1.173 -        {
   1.174 -        }
   1.175 -
   1.176 -
   1.177 -
   1.178  
   1.179          /// <summary>
   1.180          /// Update master volume indicators based our current system states.
   1.181 @@ -592,19 +584,18 @@
   1.182          /// </summary>
   1.183          private void UpdateMasterVolumeThreadSafe()
   1.184          {
   1.185 -            if (this.InvokeRequired)
   1.186 +            if (InvokeRequired)
   1.187              {
   1.188                  //Not in the proper thread, invoke ourselves
   1.189 -                PlainUpdateDelegate d = new PlainUpdateDelegate(UpdateMasterVolumeThreadSafe);
   1.190 -                this.Invoke(d, new object[] {});
   1.191 +                BeginInvoke(new Action<FormMain>((sender) => { UpdateMasterVolumeThreadSafe(); }), this);
   1.192                  return;
   1.193              }
   1.194  
   1.195              //Update volume slider
   1.196 -            float volumeLevelScalar = iAudioEndpointVolume.MasterVolumeLevelScalar;
   1.197 +            float volumeLevelScalar = iAudioManager.Volume.MasterVolumeLevelScalar;
   1.198              trackBarMasterVolume.Value = Convert.ToInt32(volumeLevelScalar*100);
   1.199              //Update mute checkbox
   1.200 -            checkBoxMute.Checked = iAudioEndpointVolume.IsMuted;
   1.201 +            checkBoxMute.Checked = iAudioManager.Volume.IsMuted;
   1.202  
   1.203              //If our display connection is open we need to update its icons
   1.204              if (iDisplay.IsOpen())
   1.205 @@ -646,83 +637,11 @@
   1.206                  }
   1.207  
   1.208                  //Take care of our mute icon
   1.209 -                iDisplay.SetIconOnOff(MiniDisplay.IconType.Mute, iAudioEndpointVolume.IsMuted);
   1.210 +                iDisplay.SetIconOnOff(MiniDisplay.IconType.Mute, iAudioManager.Volume.IsMuted);
   1.211              }
   1.212  
   1.213          }
   1.214  
   1.215 -        /// <summary>
   1.216 -        /// 
   1.217 -        /// </summary>
   1.218 -        private void StartAudioVisualization()
   1.219 -        {
   1.220 -            StopAudioVisualization();
   1.221 -            //Open the default device 
   1.222 -            iSoundIn = new WasapiLoopbackCapture();
   1.223 -            //Our loopback capture opens the default render device by default so the following is not needed
   1.224 -            //iSoundIn.Device = MMDeviceEnumerator.DefaultAudioEndpoint(DataFlow.Render, Role.Console);
   1.225 -            iSoundIn.Initialize();
   1.226 -
   1.227 -            SoundInSource soundInSource = new SoundInSource(iSoundIn);
   1.228 -            ISampleSource source = soundInSource.ToSampleSource();
   1.229 -
   1.230 -            const FftSize fftSize = FftSize.Fft2048;
   1.231 -            //create a spectrum provider which provides fft data based on some input
   1.232 -            BasicSpectrumProvider spectrumProvider = new BasicSpectrumProvider(source.WaveFormat.Channels, source.WaveFormat.SampleRate, fftSize);
   1.233 -
   1.234 -            //linespectrum and voiceprint3dspectrum used for rendering some fft data
   1.235 -            //in oder to get some fft data, set the previously created spectrumprovider 
   1.236 -            iLineSpectrum = new LineSpectrum(fftSize)
   1.237 -            {
   1.238 -                SpectrumProvider = spectrumProvider,
   1.239 -                UseAverage = false,
   1.240 -                BarCount = 16,
   1.241 -                BarSpacing = 1,
   1.242 -                IsXLogScale = true,
   1.243 -                ScalingStrategy = ScalingStrategy.Decibel
   1.244 -            };
   1.245 -
   1.246 -
   1.247 -            //the SingleBlockNotificationStream is used to intercept the played samples
   1.248 -            var notificationSource = new SingleBlockNotificationStream(source);
   1.249 -            //pass the intercepted samples as input data to the spectrumprovider (which will calculate a fft based on them)
   1.250 -            notificationSource.SingleBlockRead += (s, a) => spectrumProvider.Add(a.Left, a.Right);
   1.251 -
   1.252 -            iWaveSource = notificationSource.ToWaveSource(16);
   1.253 -
   1.254 -
   1.255 -            // We need to read from our source otherwise SingleBlockRead is never called and our spectrum provider is not populated
   1.256 -            byte[] buffer = new byte[iWaveSource.WaveFormat.BytesPerSecond / 2];
   1.257 -            soundInSource.DataAvailable += (s, aEvent) =>
   1.258 -            {
   1.259 -                int read;
   1.260 -                while ((read = iWaveSource.Read(buffer, 0, buffer.Length)) > 0) ;
   1.261 -            };
   1.262 -
   1.263 -
   1.264 -            //Start recording
   1.265 -            iSoundIn.Start();
   1.266 -        }
   1.267 -
   1.268 -        /// <summary>
   1.269 -        /// 
   1.270 -        /// </summary>
   1.271 -        private void StopAudioVisualization()
   1.272 -        {
   1.273 -
   1.274 -            if (iSoundIn != null)
   1.275 -            {
   1.276 -                iSoundIn.Stop();
   1.277 -                iSoundIn.Dispose();
   1.278 -                iSoundIn = null;
   1.279 -            }
   1.280 -            if (iWaveSource != null)
   1.281 -            {
   1.282 -                iWaveSource.Dispose();
   1.283 -                iWaveSource = null;
   1.284 -            }
   1.285 -
   1.286 -        }
   1.287  
   1.288  
   1.289          /// <summary>
   1.290 @@ -737,7 +656,7 @@
   1.291              }
   1.292  
   1.293              // Update our math
   1.294 -            if (!iLineSpectrum.Update())
   1.295 +            if (iAudioManager==null || !iAudioManager.Spectrum.Update())
   1.296              {
   1.297                  //Nothing changed no need to render
   1.298                  return;
   1.299 @@ -755,7 +674,7 @@
   1.300                      if (ctrl is PictureBox)
   1.301                      {
   1.302                          PictureBox pb = (PictureBox)ctrl;
   1.303 -                        if (iLineSpectrum.Render(pb.Image, Color.Black, Color.Black, Color.White, false))
   1.304 +                        if (iAudioManager.Spectrum.Render(pb.Image, Color.Black, Color.Black, Color.White, false))
   1.305                          {
   1.306                              pb.Invalidate();
   1.307                          }
   1.308 @@ -769,35 +688,24 @@
   1.309          /// 
   1.310          /// </summary>
   1.311          private void UpdateAudioDeviceAndMasterVolumeThreadSafe()
   1.312 -        {
   1.313 -            if (this.InvokeRequired)
   1.314 +        {            
   1.315 +            if (InvokeRequired)
   1.316              {
   1.317                  //Not in the proper thread, invoke ourselves
   1.318 -                PlainUpdateDelegate d = new PlainUpdateDelegate(UpdateAudioDeviceAndMasterVolumeThreadSafe);
   1.319 -                this.Invoke(d, new object[] {});
   1.320 +                BeginInvoke(new Action<FormMain>((sender) => { UpdateAudioDeviceAndMasterVolumeThreadSafe(); }), this);
   1.321                  return;
   1.322              }
   1.323  
   1.324              //We are in the correct thread just go ahead.
   1.325              try
   1.326              {
   1.327 -                //Get our master volume
   1.328 -                iMultiMediaDevice = iMultiMediaDeviceEnumerator.GetDefaultAudioEndpoint(DataFlow.Render, Role.Multimedia);
   1.329 -                iAudioEndpointVolume = AudioEndpointVolume.FromDevice(iMultiMediaDevice);
   1.330 -                
   1.331 +                  
   1.332                  //Update our label
   1.333 -                labelDefaultAudioDevice.Text = iMultiMediaDevice.FriendlyName;
   1.334 +                iLabelDefaultAudioDevice.Text = iAudioManager.DefaultDevice.FriendlyName;
   1.335  
   1.336                  //Show our volume in our track bar
   1.337                  UpdateMasterVolumeThreadSafe();
   1.338  
   1.339 -                //Register to get volume modifications
   1.340 -                AudioEndpointVolumeCallback callback = new AudioEndpointVolumeCallback();
   1.341 -                callback.NotifyRecived += OnVolumeNotificationThreadSafe;
   1.342 -                // Do we need to unregister?
   1.343 -                iAudioEndpointVolume.RegisterControlChangeNotify(callback);
   1.344 -                //
   1.345 -                StartAudioVisualization();
   1.346                  //
   1.347                  trackBarMasterVolume.Enabled = true;
   1.348              }
   1.349 @@ -1573,10 +1481,9 @@
   1.350  
   1.351          private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
   1.352          {
   1.353 -            //TODO: discard other CSCore audio objects
   1.354 -            StopAudioVisualization();
   1.355              iCecManager.Stop();
   1.356              iNetworkManager.Dispose();
   1.357 +            DestroyAudioManager();
   1.358              CloseDisplayConnection();
   1.359              StopServer();
   1.360              e.Cancel = iClosing;