ufbSoundDetect.cs 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. using CoreAudioApi;
  2. using System;
  3. using System.Diagnostics;
  4. using System.Linq;
  5. using System.Threading;
  6. using System.Threading.Tasks;
  7. class Ears
  8. {
  9. private MMDevice _sndDevice;
  10. private readonly LimitedCollection<int> _volumeQueue;
  11. private int _tickrate = 50; //ms pause between sound checks
  12. private const int MaxVolumeQueueLength = 5;
  13. public Ears()
  14. {
  15. _volumeQueue = new LimitedCollection<int>(MaxVolumeQueueLength) {0};
  16. }
  17. public async Task<bool> Listen(int millisecondsToListen, CancellationToken cancellationToken)
  18. {
  19. var stopwatch = new Stopwatch();
  20. stopwatch.Start();
  21. var sndDevEnum = new MMDeviceEnumerator();
  22. _sndDevice = Properties.Settings.Default.AudioDevice != ""
  23. ? sndDevEnum.GetDevice(Properties.Settings.Default.AudioDevice)
  24. : sndDevEnum.GetDefaultAudioEndpoint(EDataFlow.eRender, ERole.eMultimedia);
  25. Func<bool> heardFish;
  26. if (Properties.Settings.Default.AverageSound)
  27. heardFish = ListenTimerTickAvg;
  28. else
  29. heardFish = ListenTimerTick;
  30. while (stopwatch.ElapsedMilliseconds <= millisecondsToListen) {
  31. await Task.Delay(_tickrate, cancellationToken);
  32. if (heardFish()) {
  33. return true;
  34. }
  35. }
  36. return false;
  37. }
  38. private bool ListenTimerTick() {
  39. // Get the current level
  40. var currentVolumnLevel = (int)(_sndDevice.AudioMeterInformation.MasterPeakValue * 100);
  41. if (currentVolumnLevel >= Properties.Settings.Default.SplashLimit)
  42. return true;
  43. return false;
  44. }
  45. private bool ListenTimerTickAvg()
  46. {
  47. // Get the current level
  48. var currentVolumnLevel = (int)(_sndDevice.AudioMeterInformation.MasterPeakValue * 100);
  49. var avgVol = GetAverageVolume();
  50. var hear = false;
  51. // Determine if the current level is high enough to be a fish
  52. if (currentVolumnLevel - avgVol >= Properties.Settings.Default.SplashLimit) {
  53. Serilog.Log.Information("Hear: {av},{cvl},{queue}", avgVol, currentVolumnLevel, _volumeQueue);
  54. hear = true;
  55. }
  56. // Keep a running queue of the last X sounds as a reference point
  57. _volumeQueue.Add(currentVolumnLevel);
  58. return hear;
  59. }
  60. private int GetAverageVolume()
  61. {
  62. return (int)_volumeQueue.Average();
  63. }
  64. }