Server/AudioManager.cs
changeset 277 71ba0dd622a5
child 278 2481c46d1f93
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/Server/AudioManager.cs	Sat Jan 07 20:21:42 2017 +0100
     1.3 @@ -0,0 +1,184 @@
     1.4 +´╗┐using System;
     1.5 +using System.Collections.Generic;
     1.6 +using System.Linq;
     1.7 +using System.Text;
     1.8 +using System.Threading.Tasks;
     1.9 +
    1.10 +//CSCore
    1.11 +using CSCore;
    1.12 +using CSCore.Win32;
    1.13 +using CSCore.DSP;
    1.14 +using CSCore.Streams;
    1.15 +using CSCore.CoreAudioAPI;
    1.16 +using CSCore.SoundIn;
    1.17 +// Visualization
    1.18 +using Visualization;
    1.19 +
    1.20 +
    1.21 +namespace SharpDisplayManager
    1.22 +{
    1.23 +    class AudioManager
    1.24 +    {
    1.25 +        // Volume management
    1.26 +        private MMDeviceEnumerator iMultiMediaDeviceEnumerator;
    1.27 +        private MMNotificationClient iMultiMediaNotificationClient;
    1.28 +        private MMDevice iMultiMediaDevice;
    1.29 +        private AudioEndpointVolume iAudioEndpointVolume;
    1.30 +        private AudioEndpointVolumeCallback iAudioEndpointVolumeCallback;
    1.31 +        EventHandler<DefaultDeviceChangedEventArgs> iDefaultDeviceChangedHandler;
    1.32 +        EventHandler<AudioEndpointVolumeCallbackEventArgs> iVolumeChangedHandler;
    1.33 +
    1.34 +        // Audio visualization
    1.35 +        private WasapiCapture iSoundIn;
    1.36 +        private IWaveSource iWaveSource;
    1.37 +        private LineSpectrum iLineSpectrum;
    1.38 +
    1.39 +
    1.40 +        public LineSpectrum Spectrum { get { return iLineSpectrum; } }
    1.41 +        public AudioEndpointVolume Volume { get { return iAudioEndpointVolume; } }
    1.42 +        public MMDevice DefaultDevice { get { return iMultiMediaDevice; } }
    1.43 +
    1.44 +        /// <summary>
    1.45 +        /// 
    1.46 +        /// </summary>
    1.47 +        /// <param name="aDefaultDeviceChangedHandler"></param>
    1.48 +        /// <param name="aVolumeChangedHandler"></param>
    1.49 +        public void Open(   EventHandler<DefaultDeviceChangedEventArgs> aDefaultDeviceChangedHandler,
    1.50 +                            EventHandler<AudioEndpointVolumeCallbackEventArgs> aVolumeChangedHandler)
    1.51 +        {
    1.52 +            //Create device and register default device change notification
    1.53 +            iMultiMediaDeviceEnumerator = new MMDeviceEnumerator();
    1.54 +            iMultiMediaNotificationClient = new MMNotificationClient(iMultiMediaDeviceEnumerator);
    1.55 +            iMultiMediaNotificationClient.DefaultDeviceChanged += iDefaultDeviceChangedHandler = aDefaultDeviceChangedHandler;
    1.56 +            iMultiMediaDevice = iMultiMediaDeviceEnumerator.GetDefaultAudioEndpoint(DataFlow.Render,Role.Multimedia);
    1.57 +            //Register to get volume modifications
    1.58 +            iAudioEndpointVolume = AudioEndpointVolume.FromDevice(iMultiMediaDevice);
    1.59 +            iAudioEndpointVolumeCallback = new AudioEndpointVolumeCallback();
    1.60 +            iAudioEndpointVolumeCallback.NotifyRecived += iVolumeChangedHandler = aVolumeChangedHandler;
    1.61 +            iAudioEndpointVolume.RegisterControlChangeNotify(iAudioEndpointVolumeCallback);
    1.62 +
    1.63 +            StartAudioVisualization();
    1.64 +        }
    1.65 +
    1.66 +        /// <summary>
    1.67 +        /// 
    1.68 +        /// </summary>
    1.69 +        public void Close()
    1.70 +        {
    1.71 +            StopAudioVisualization();
    1.72 +
    1.73 +            // Client up our MM objects in reverse order
    1.74 +            if (iAudioEndpointVolumeCallback != null && iAudioEndpointVolume != null)
    1.75 +            {
    1.76 +                iAudioEndpointVolume.UnregisterControlChangeNotify(iAudioEndpointVolumeCallback);
    1.77 +            }
    1.78 +
    1.79 +            if (iAudioEndpointVolumeCallback != null)
    1.80 +            {
    1.81 +                iAudioEndpointVolumeCallback.NotifyRecived -= iVolumeChangedHandler;
    1.82 +                iAudioEndpointVolumeCallback = null;
    1.83 +            }
    1.84 +
    1.85 +            if (iAudioEndpointVolume != null)
    1.86 +            {
    1.87 +                iAudioEndpointVolume.Dispose();
    1.88 +                iAudioEndpointVolume = null;
    1.89 +            }
    1.90 +
    1.91 +            if (iMultiMediaDevice != null)
    1.92 +            {
    1.93 +                iMultiMediaDevice.Dispose();
    1.94 +                iMultiMediaDevice = null;
    1.95 +            }
    1.96 +
    1.97 +            if (iMultiMediaNotificationClient != null)
    1.98 +            {
    1.99 +                iMultiMediaNotificationClient.DefaultDeviceChanged -= iDefaultDeviceChangedHandler;
   1.100 +                iMultiMediaNotificationClient.Dispose();
   1.101 +                iMultiMediaNotificationClient = null;
   1.102 +            }
   1.103 +
   1.104 +            if (iMultiMediaDeviceEnumerator != null)
   1.105 +            {
   1.106 +                iMultiMediaDeviceEnumerator.Dispose();
   1.107 +                iMultiMediaDeviceEnumerator = null;
   1.108 +            }
   1.109 +
   1.110 +        }
   1.111 +
   1.112 +
   1.113 +        /// <summary>
   1.114 +        /// 
   1.115 +        /// </summary>
   1.116 +        private void StartAudioVisualization()
   1.117 +        {
   1.118 +            //Open the default device 
   1.119 +            iSoundIn = new WasapiLoopbackCapture();
   1.120 +            //Our loopback capture opens the default render device by default so the following is not needed
   1.121 +            //iSoundIn.Device = MMDeviceEnumerator.DefaultAudioEndpoint(DataFlow.Render, Role.Console);
   1.122 +            iSoundIn.Initialize();
   1.123 +
   1.124 +            SoundInSource soundInSource = new SoundInSource(iSoundIn);
   1.125 +            ISampleSource source = soundInSource.ToSampleSource();
   1.126 +
   1.127 +            const FftSize fftSize = FftSize.Fft2048;
   1.128 +            //create a spectrum provider which provides fft data based on some input
   1.129 +            BasicSpectrumProvider spectrumProvider = new BasicSpectrumProvider(source.WaveFormat.Channels, source.WaveFormat.SampleRate, fftSize);
   1.130 +
   1.131 +            //linespectrum and voiceprint3dspectrum used for rendering some fft data
   1.132 +            //in oder to get some fft data, set the previously created spectrumprovider 
   1.133 +            iLineSpectrum = new LineSpectrum(fftSize)
   1.134 +            {
   1.135 +                SpectrumProvider = spectrumProvider,
   1.136 +                UseAverage = false,
   1.137 +                BarCount = 16,
   1.138 +                BarSpacing = 1,
   1.139 +                IsXLogScale = true,
   1.140 +                ScalingStrategy = ScalingStrategy.Decibel
   1.141 +            };
   1.142 +
   1.143 +
   1.144 +            //the SingleBlockNotificationStream is used to intercept the played samples
   1.145 +            var notificationSource = new SingleBlockNotificationStream(source);
   1.146 +            //pass the intercepted samples as input data to the spectrumprovider (which will calculate a fft based on them)
   1.147 +            notificationSource.SingleBlockRead += (s, a) => spectrumProvider.Add(a.Left, a.Right);
   1.148 +
   1.149 +            iWaveSource = notificationSource.ToWaveSource(16);
   1.150 +
   1.151 +
   1.152 +            // We need to read from our source otherwise SingleBlockRead is never called and our spectrum provider is not populated
   1.153 +            byte[] buffer = new byte[iWaveSource.WaveFormat.BytesPerSecond / 2];
   1.154 +            soundInSource.DataAvailable += (s, aEvent) =>
   1.155 +            {
   1.156 +                int read;
   1.157 +                while ((read = iWaveSource.Read(buffer, 0, buffer.Length)) > 0) ;
   1.158 +            };
   1.159 +
   1.160 +
   1.161 +            //Start recording
   1.162 +            iSoundIn.Start();
   1.163 +        }
   1.164 +
   1.165 +        /// <summary>
   1.166 +        /// 
   1.167 +        /// </summary>
   1.168 +        private void StopAudioVisualization()
   1.169 +        {
   1.170 +            if (iWaveSource != null)
   1.171 +            {
   1.172 +                iWaveSource.Dispose();
   1.173 +                iWaveSource = null;
   1.174 +            }
   1.175 +
   1.176 +            if (iSoundIn != null)
   1.177 +            {
   1.178 +                iSoundIn.Stop();
   1.179 +                iSoundIn.Dispose();
   1.180 +                iSoundIn = null;
   1.181 +            }
   1.182 +
   1.183 +        }
   1.184 +
   1.185 +
   1.186 +    }
   1.187 +}