I am dipping my toes in Tasks (.NET 4.5) and am experiencing increasing handles (in task manager). I have a class doing a simple Play/Stop of audio file using MediaPlayer class (System.Windows.Media namespace). I have a second class which wraps it and exposes sync/async playback.
All is working fine and functionality is OK, but see the number of handles increasing in Task manager which worries me.... Am I doing something wrong here?
Important note: if I comment our the "await Task.Delay(1000);" --> then all is just fine and no leaks are observed... How come??
public partial class Form1 : Form
{
AudioActions syncAction = new AudioActions(#"c:\1.wav", false);
AudioActions asyncAction = new AudioActions(#"c:\1.wav", true);
public Form1()
{
InitializeComponent();
}
private async void syncPlayback(object sender, EventArgs e)
{
for (int i = 0; i < 10; i++)
{
await syncAction.Start();
}
}
private async void asyncPlayback(object sender, EventArgs e)
{
for (int i = 0; i < 100; i++)
{
await asyncAction.Start();
await Task.Delay(100); //remove this line and all is fine!!!!
asyncAction.Stop();
}
Console.WriteLine("done");
}
}
public class AudioActions
{
private Audio audio = null;
private TaskCompletionSource<bool> tcs = null;
private string pathToWaveFile;
private bool async;
public AudioActions(string pathToWaveFile, bool async)
{
this.pathToWaveFile=pathToWaveFile;
this.async=async;
}
public Task Start()
{
tcs = new TaskCompletionSource<bool>();
audio = new Audio();
audio.mediaPlayerPlaybackStoppedEvent += Audio_wmPlaybackStopped;
if (async)
tcs.TrySetResult(true); //since its async operation, lets return immediately and free the task from waiting
audio.PlayAudioFileInMediaPlayer(pathToWaveFile);
return tcs.Task;
}
private void Audio_wmPlaybackStopped()
{
audio.mediaPlayerPlaybackStoppedEvent -= Audio_wmPlaybackStopped;
tcs.TrySetResult(true); //playback stopped. Lets free the task from waiting
}
public void Stop()
{
audio.StopAudioFilePlaybackInMediaPlayer();
}
}
public class Audio
{
MediaPlayer mediaPlayer = null;
public delegate void MediaPlayerPlaybackStoppedDelegate();
public event MediaPlayerPlaybackStoppedDelegate mediaPlayerPlaybackStoppedEvent;
public void PlayAudioFileInMediaPlayer(string pathToWavFile)
{
mediaPlayer = new MediaPlayer();
mediaPlayer.MediaEnded += mediaPlayer_MediaEnded;
mediaPlayer.Open(new Uri(pathToWavFile));
mediaPlayer.Play();
}
void mediaPlayer_MediaEnded(object sender, EventArgs e)
{
mediaPlayerPlaybackStoppedEvent.Invoke();
MediaPlayer mediaPlayer = (MediaPlayer)sender;
mediaPlayer.MediaEnded -= mediaPlayer_MediaEnded;
mediaPlayer.Close();
mediaPlayer = null;
}
public void StopAudioFilePlaybackInMediaPlayer()
{
mediaPlayer.Stop();
mediaPlayer.Close();
mediaPlayer = null;
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
}
}
Adding a strip down code:
private async void asyncPlayback(object sender, EventArgs e)
{
AudioActions asyncAction = new AudioActions();
for (int i = 0; i < 100; i++)
{
await asyncAction.Start();
await Task.Delay(1000); //remove this line and all is fine!!!!
asyncAction.Stop();
}
}
public class AudioActions
{
private Audio audio = null;
private TaskCompletionSource<bool> tcs = null;
public Task Start()
{
tcs = new TaskCompletionSource<bool>();
audio = new Audio();
tcs.TrySetResult(true); //since its async operation, lets return immediately and free the task from waiting
audio.PlayAudioFileInMediaPlayer(#"c:\1.wav");
return tcs.Task;
}
public void Stop()
{
audio.StopAudioFilePlaybackInMediaPlayer();
}
}
public class Audio
{
MediaPlayer mediaPlayer = null;
public void PlayAudioFileInMediaPlayer(string pathToWavFile)
{
mediaPlayer = new MediaPlayer();
mediaPlayer.Open(new Uri(pathToWavFile));
mediaPlayer.Play();
}
public void StopAudioFilePlaybackInMediaPlayer()
{
mediaPlayer.Stop();
mediaPlayer.Close();
mediaPlayer = null;
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
}
}
Modified class solving the problem:
public class Audio
{
public delegate void NaudioPlaybackStoppedDelegate();
public event NaudioPlaybackStoppedDelegate naudioPlaybackStoppedEvent;
private WaveOut player = null;
public void PlayAudioFileUsingNaudio(string pathToWavFile)
{
player = new WaveOut();
AudioFileReader waveFileReader = new AudioFileReader(pathToWavFile);
player.Init(waveFileReader);
player.PlaybackStopped += NAudio_Stopped;
player.Play();
}
private void NAudio_Stopped(object sender, StoppedEventArgs e)
{
player.PlaybackStopped -= NAudio_Stopped;
if (naudioPlaybackStoppedEvent!=null)
naudioPlaybackStoppedEvent.Invoke();
player.Dispose();
}
public void StopAudioFilePlaybackInNaudio()
{
player.Stop();
}
}
Replacing MediaPlayer with NAudio 3rd party solved it.
public class Audio
{
public delegate void NaudioPlaybackStoppedDelegate();
public event NaudioPlaybackStoppedDelegate naudioPlaybackStoppedEvent;
private WaveOut player = null;
public void PlayAudioFileUsingNaudio(string pathToWavFile)
{
player = new WaveOut();
AudioFileReader waveFileReader = new AudioFileReader(pathToWavFile);
player.Init(waveFileReader);
player.PlaybackStopped += NAudio_Stopped;
player.Play();
}
private void NAudio_Stopped(object sender, StoppedEventArgs e)
{
player.PlaybackStopped -= NAudio_Stopped;
if (naudioPlaybackStoppedEvent!=null)
naudioPlaybackStoppedEvent.Invoke();
player.Dispose();
}
public void StopAudioFilePlaybackInNaudio()
{
player.Stop();
}
}
Related
I have a WPF (.NET Framework 4.6) application that uses websocket-sharp (version 3.0.0) to create a websocket server.
I have a WebsocketServer and using EventHandler to tranfer event to MainWindow.xaml.cs but it not working. The MainWindow.xaml.cs listened to a RaiseOnScanDevice event but not any event invoked here.
I think this issue is relative to different thread. I try using Dispatcher.Invoke but it still not working.
System.Windows.Application.Current.Dispatcher.Invoke(new System.Action(() =>
{
RaiseOnScanDevice(this, new EventArgs());
}));
I found an issue (https://github.com/sta/websocket-sharp/issues/350) but the answers do not resolve my issue.
Please help me a solution for this issue.
WebsocketServer.cs file
public class WebsocketServer : WebSocketBehavior
{
private static readonly Lazy<WebsocketServer> lazyInstance = new Lazy<WebsocketServer>(() => new WebsocketServer());
public static WebsocketServer Instance
{
get
{
return lazyInstance.Value;
}
}
private const string TAG = "WebsocketServer";
private const string HOST_IP_ADDRESS = "127.0.0.2"; // localhost
private const int PORT = 38001;
public WebSocketServer socket;
private PacketHandler packetHandler = new PacketHandler();
public event EventHandler<EventArgs> RaiseOnScanDevice = new EventHandler<EventArgs>((a, e) => { });
public WebsocketServer()
{
Initialize();
}
public void Initialize()
{
socket = new WebSocketServer(IPAddress.Parse(HOST_IP_ADDRESS), PORT);
socket.AddWebSocketService<WebsocketServer>("/");
StartServer();
}
public void StartServer()
{
socket.Start();
}
public void StopServer()
{
socket.Stop();
}
protected override Task OnOpen()
{
return base.OnOpen();
}
protected override Task OnClose(CloseEventArgs e)
{
return base.OnClose(e);
}
protected override Task OnError(ErrorEventArgs e)
{
return base.OnError(e);
}
protected override Task OnMessage(MessageEventArgs e)
{
System.IO.StreamReader reader = new System.IO.StreamReader(e.Data);
string message = reader.ReadToEnd();
//Converting the event back to 'eventName' and 'JsonPayload'
PacketModel packet = packetHandler.OpenPacket(message);
HandleMessageFromClient(packet);
return base.OnMessage(e);
}
private void HandleMessageFromClient(PacketModel packet) {
var eventName = packet.EventName;
var data = packet.Data;
if (eventName == null || eventName.Equals(""))
{
return;
}
switch (eventName)
{
case SocketEvent.Hello:
Send("OK");
break;
case SocketEvent.ScanDevice:
ScanDevice();
break;
default:
break;
}
}
private void ScanDevice()
{
try
{
RaiseOnScanDevice(this, new EventArgs());
// or dispatch to Main Thread
System.Windows.Application.Current.Dispatcher.Invoke(new System.Action(() =>
{
RaiseOnScanDevice(this, new EventArgs());
}));
}
catch (Exception exception)
{
Console.WriteLine(exception);
}
}
}
MainWindow.xaml.cs file
public partial class MainWindow : Window
{
public WebsocketServer WebsocketConnection
{
get { return WebsocketServer.Instance; }
}
public MainWindow()
{
InitializeComponent();
WebsocketConnection.RaiseOnScanDevice += SocketConnection_RaiseOnScanDevice;
}
private void SocketConnection_RaiseOnScanDevice(object sender, EventArgs e)
{
Console.WriteLine("SocketConnection_RaiseOnScanDevice");
}
The queue of messages is a good idea but you may want to use a lock to guard access to it. Most likely it won't be an issue but if you don't, you leave yourself open to the possibility of an error if the coroutine is reading from the queue as the websocket is writing to it. For example you could do something like this:
var queueLock = new object();
var queue = new Queue<MyMessageType>();
// use this to read from the queue
MyMessageType GetNextMessage()
{
lock (queueLock) {
if (queue.Count > 0) return queue.Dequeue();
else return null;
}
}
// use this to write to the queue
void QueueMessage(MyMessageType msg)
{
lock(queueLock) {
queue.Enqueue(msg);
}
}
I am trying to save the image from the camera as mp4(etc) on WPF application. But so far I have not been successful.
Thanks for your help.
Sorry for my bad english at first.I am receiving the image from the webcam. Below are the codes.
public partial class MainWindow : Window
{
private FilterInfoCollection cihazlar;
private VideoCaptureDevice yakala_resim
;
public MainWindow()
{
InitializeComponent();
cihazlar = new FilterInfoCollection(FilterCategory.VideoInputDevice);
foreach (FilterInfo device in cihazlar)
{
kameralar.Items.Add(device.Name);
kameralar.SelectedIndex = 2;
}
}
private void Başla_Click(object sender, RoutedEventArgs e)
{
yakala_resim = new VideoCaptureDevice(cihazlar[kameralar.SelectedIndex].MonikerString);
yakala_resim.NewFrame += Yakala_NewFrame1;
yakala_resim.Start();
}
private void Yakala_NewFrame1(object sender, NewFrameEventArgs eventArgs)
{
try
{
BitmapImage bi;
using (var bitmap = (Bitmap)eventArgs.Frame.Clone())
{
bi = bitmap.ToBitmapImage();
}
bi.Freeze();
Dispatcher.BeginInvoke(new ThreadStart(delegate { video.Source = bi; }));
}
catch (Exception)
{
}
}
no problem currently. But I don't know what to do when I want to save the image come from webcam as mp4.
You can use from OpenCvSharp
namespace BlackBears.Recording
{
using System;
using System.Drawing;
using System.Threading;
using OpenCvSharp;
using OpenCvSharp.Extensions;
using Size = OpenCvSharp.Size;
public class Recorder : IDisposable
{
private readonly VideoCaptureAPIs _videoCaptureApi = VideoCaptureAPIs.DSHOW;
private readonly ManualResetEventSlim _writerReset = new(false);
private readonly VideoCapture _videoCapture;
private VideoWriter _videoWriter;
private Thread _writerThread;
private bool IsVideoCaptureValid => _videoCapture is not null && _videoCapture.IsOpened();
public Recorder(int deviceIndex, int frameWidth, int frameHeight, double fps)
{
_videoCapture = VideoCapture.FromCamera(deviceIndex, _videoCaptureApi);
_videoCapture.Open(deviceIndex, _videoCaptureApi);
_videoCapture.FrameWidth = frameWidth;
_videoCapture.FrameHeight = frameHeight;
_videoCapture.Fps = fps;
}
/// <inheritdoc />
public void Dispose()
{
GC.SuppressFinalize(this);
Dispose(true);
}
~Recorder()
{
Dispose(false);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
StopRecording();
_videoCapture?.Release();
_videoCapture?.Dispose();
}
}
public void StartRecording(string path)
{
if (_writerThread is not null)
return;
if (!IsVideoCaptureValid)
ThrowHelper.ThrowVideoCaptureNotReadyException();
_videoWriter = new VideoWriter(path, FourCC.XVID, _videoCapture.Fps, new Size(_videoCapture.FrameWidth, _videoCapture.FrameHeight));
_writerReset.Reset();
_writerThread = new Thread(AddCameraFrameToRecordingThread);
_writerThread.Start();
}
public void StopRecording()
{
if (_writerThread is not null)
{
_writerReset.Set();
_writerThread.Join();
_writerThread = null;
_writerReset.Reset();
}
_videoWriter?.Release();
_videoWriter?.Dispose();
_videoWriter = null;
}
private void AddCameraFrameToRecordingThread()
{
var waitTimeBetweenFrames = (int)(1_000 / _videoCapture.Fps);
using var frame = new Mat();
while (!_writerReset.Wait(waitTimeBetweenFrames))
{
if (!_videoCapture.Read(frame))
return;
_videoWriter.Write(frame);
}
}
}
}
Recording Video from Webcam with OpenCvSharp - Resulting File playback to fast
I have a class that generates images in a thread and invokes an event on every frame. A Form subscribes to this event and displays the image in a PictureBox using Invoke.
If the image generation process is allowed to finish, all is good. However, if the Form is closed while the thread is running, the Form tries to stop the thread but ends up in some sort of a deadlock.
When I try to use the threaded class in without a Form or in a Console app, start the process, wait for a second, then Cancel it, everything works fine.
The question is, something must be wrong with either the Form_Closing method of the Form or the Stop method of the threaded class.
I have kept the code to a minimum and it can be pasted into LinqPad, etc.
An auxiliary question: Should the Process method invoke the Stop method to clean up?
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Reflection;
using System.Threading;
using System.Windows.Forms;
namespace VideoMask.WinFormsAppApp
{
internal static class Program
{
[STAThread]
private static void Main ()
{
Program.TestWithoutForm(); // Runs fine.
Program.TestWithForm(); // Deadlocks.
}
private static void TestWithForm ()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new FormMain());
}
private static void TestWithoutForm ()
{
new TestWithoutForm().Run();
}
}
public class TestWithoutForm
{
private VideoProcessor VideoProcessor = new VideoProcessor();
public TestWithoutForm ()
{
this.VideoProcessor.SourceFrameRead += this.VideoProcessor_SourceFrameRead;
}
public void Run ()
{
this.VideoProcessor.Start();
Thread.Sleep(1000);
this.VideoProcessor.Stop();
MessageBox.Show("Done");
}
private void VideoProcessor_SourceFrameRead (object sender, VideoProcessorEventArgs e)
{
var filename = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Sample.png");
e.Bitmap.Save(filename, ImageFormat.Png);
}
}
public class FormMain: Form
{
private PictureBox PictureBox = new PictureBox();
private VideoProcessor VideoProcessor = new VideoProcessor();
public FormMain ()
{
this.Controls.Add(this.PictureBox);
this.PictureBox.Dock = DockStyle.Fill;
this.Shown += this.FormMain_Shown;
this.FormClosing += this.FormMain_FormClosing;
this.WindowState = FormWindowState.Maximized;
}
private void FormMain_Shown (object sender, EventArgs e)
{
this.VideoProcessor.SourceFrameRead += this.VideoProcessor_SourceFrameRead;
this.VideoProcessor.Start();
}
private void FormMain_FormClosing (object sender, FormClosingEventArgs e)
{
this.VideoProcessor.Stop();
this.VideoProcessor.Dispose();
this.VideoProcessor = null;
}
private void VideoProcessor_SourceFrameRead (object sender, VideoProcessorEventArgs e)
{
this.Invoke
(
new Action
(
() =>
{
using (var bitmap = this.PictureBox.Image)
{
this.PictureBox.Image = new Bitmap(e.Bitmap);
}
}
)
);
}
}
public sealed class VideoProcessor: IDisposable
{
public event EventHandler<ErrorEventArgs> ConversionError = null;
public event EventHandler<VideoProcessorEventArgs> SourceFrameRead = null;
private Font Font = null;
private Bitmap Bitmap = null;
private Thread Thread = null;
private Graphics Graphics = null;
private readonly object SyncRoot = new object();
private CancellationTokenSource CancellationTokenSource = null;
public VideoProcessor ()
{
this.Bitmap = new Bitmap(800, 600, PixelFormat.Format32bppArgb);
this.Graphics = Graphics.FromImage(this.Bitmap);
this.Font = new Font(FontFamily.GenericSansSerif, 48, GraphicsUnit.Point);
}
public bool IsRunning { get; private set; }
public void Start ()
{
lock (this.SyncRoot)
{
if (this.IsRunning) { throw (new Exception("A video conversion process is already running.")); }
this.Stop();
this.CancellationTokenSource = new CancellationTokenSource();
this.Thread = new Thread(new ParameterizedThreadStart(this.Process));
this.Thread.Start(this.CancellationTokenSource);
}
}
public void Stop ()
{
lock (this.SyncRoot)
{
if (!this.IsRunning) { return; }
this.CancellationTokenSource?.Cancel();
this.Thread.Join();
this.Thread = null;
this.CancellationTokenSource?.Dispose();
this.CancellationTokenSource = null;
}
}
private void Process (object cancellationTokenSource)
{
var source = (CancellationTokenSource) cancellationTokenSource ?? throw (new ArgumentNullException(nameof(cancellationTokenSource)));
lock (this.SyncRoot) { if (this.IsRunning) { throw (new Exception("A conversion process is already running.")); } }
this.IsRunning = true;
for (var i = 1; i <= int.MaxValue; i++)
{
if (source.IsCancellationRequested) { break; }
this.Graphics.Clear(Color.White);
this.Graphics.DrawString(i.ToString(), this.Font, Brushes.Black, 10, 10);
this.SourceFrameRead?.Invoke(this, new VideoProcessorEventArgs(this.Bitmap));
Thread.Sleep(33);
}
this.IsRunning = false;
}
public void Dispose () => this.Stop();
}
public class VideoProcessorEventArgs: EventArgs
{
public Bitmap Bitmap { get; private set; }
public VideoProcessorEventArgs (Bitmap bitmap) { this.Bitmap = bitmap; }
}
}
I have WinForms App where I am using the code in this following Post to check the InActivity Status of my app (Please see the accepted answer in the post). InActivity In WinForms. Once the app reaches inactivity its stopping the inactivity monitor. But then I want to restart the time once the user logs in.
So I have a notification mechanism when the user logs in and I am calling the start timer method again. I get the Started Monitor Message but the app never tracks inactivity and I don't get Timer reporting app is InACTIVE message at all. Please help.
public static System.Windows.Forms.Timer IdleTimer =null;
static int MilliSeconds = 60000;
static void Main(string[] args)
{
f = new GeneStudyForm(true, arguments.SystemTimeOutFolder, arguments.SystemTimeOutFile, StartInActivityMonitor);
int x = StartInActivityMonitor();
}
public static void StartInActivityMonitor()
{
IdleTimer = new Timer();
LeaveIdleMessageFilter limf = new LeaveIdleMessageFilter();
Application.AddMessageFilter(limf);
IdleTimer.Interval = MilliSeconds; //One minute; change as needed
Application.Idle += new EventHandler(Application_Idle);
if (IdleTimer != null)
{
MessageBox.Show(IdleTimer.Interval.ToString());
}
IdleTimer.Tick += TimeDone;
IdleTimer.Tag = InActivityTimer.Started;
MessageBox.Show("starting");
IdleTimer.Start();
}
static private void Application_Idle(object sender, EventArgs e)
{
if (!IdleTimer.Enabled) // not yet idling?
IdleTimer.Start();
}
static private void TimeDone(object sender, EventArgs e)
{
try
{
MessageBox.Show("Stopped");
IdleTimer.Stop(); // not really necessary
f.MonitorDirectory();
f.UpdateInActivityStatus();
IdleTimer.Tick -= TimeDone;
Application.Idle -= new EventHandler(Application_Idle);
}
catch(Exception ex)
{
MessageBox.Show(ex.InnerException + ex.Data.ToString());
}
}
Here is my GeneStudyForm
public partial class GeneStudyForm
{
GeneStudySystemTimeOutIO GeneStudyIO;
Func<int> StartTimer;
//Passing the StartInActivityMonitor Method as Func Delegate
public GeneStudyForm(bool isStandalone, string TimeOutFolder, string TimeOutFile, System.Func<int> MyMethod)
{
GeneStudyIO = GeneStudySystemTimeOutIO.GetInstance(TimeOutFolder, TimeOutFile);
UpdateActivityStatus(AppName.GeneStudyStatus, ActivityStatus.Active);
this.StartTimer = MyMethod;
}
public void UpdateActivityStatus(AppName name, ActivityStatus status)
{
if (GeneStudyIO != null)
{
GeneStudyIO.WriteToFile(name, status);
}
}
public void MonitorDirectory()
{
FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(GeneStudyIO.GetDriectory());
fileSystemWatcher.NotifyFilter = NotifyFilters.LastWrite;
fileSystemWatcher.Filter = "*.json";
fileSystemWatcher.Changed += FileSystemWatcher_Changed;
fileSystemWatcher.EnableRaisingEvents = true;
}
public void UnRegister(FileSystemWatcher fileSystemWatcher)
{
fileSystemWatcher.Changed -= FileSystemWatcher_Changed;
}
// I am writing the inactive status to a file. So this event will fill
private void FileSystemWatcher_Changed(object sender, FileSystemEventArgs e)
{
try
{
var root = GeneStudyIO.GetDesrializedJson();
if (root != null && root.AllApplications != null)
{
var item = root.AllApplications.Any(x => x.Status == ActivityStatus.Active.ToString());
if (!item)
{
if (InActivecount == 0)
{
GeneStudyAndApplicationCommon.TimeStatus = InActivityTimer.Ended;
MessageBox.Show("I am hiding");
this.Hide();
InActivecount++;
}
}
else
{
if (GeneStudyAndApplicationCommon.TimeStatus == InActivityTimer.Ended)
{
MessageBox.Show("I am showing");
this.Show();
UnRegister(sender as FileSystemWatcher);
UpdateActivityStatus(AppName.GeneStudyStatus, ActivityStatus.Active);
MessageBox.Show("Updated Status");
if (StartTimer != null)
{
MessageBox.Show("Starting Timer again");
if (StartTimer() == -1)
{
MessageBox.Show("Couldn't start timer");
}
}
}
}
}
}
catch (Exception ex)
{
SystemDebugLogLogger.LogException(ex);
}
}
}
This soulution is quite different from what I have posted. But I could solve my problem with this. But I want to post it if it helps someone. Here is the post I am following Last User Input
I created a class called IdleCheck where I am getting LastUserInput as follows
public static class IdleCheck
{
[StructLayout(LayoutKind.Sequential)]
private struct LASTINPUTINFO
{
[MarshalAs(UnmanagedType.U4)]
public int cbSize;
[MarshalAs(UnmanagedType.U4)]
public int dwTime;
}
[DllImport("user32.dll")]
private static extern bool GetLastInputInfo(ref LASTINPUTINFO x);
public static int GetLastInputTime()
{
var inf = new LASTINPUTINFO();
inf.cbSize = Marshal.SizeOf(inf);
inf.dwTime = 0;
return (GetLastInputInfo(ref inf)) ? Environment.TickCount - inf.dwTime : 0;
}
}
Next in the actual Form this is my code. I am using a simple yes no message box to see if the timer can be stopped and recalled again when needed. You can apply your own locking mechanism.
I want the app to time out if it is InActive for 20 seconds. Change it as needed.
public partial class Form1 : Form
{
Timer timer;
const int TIMEOUT_DONE = 20000;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Reset();
}
void timer_Tick(object sender, EventArgs e)
{
//var ms = TIMEOUT_DONE - IdleCheck.GetLastInputTime();
if (IdleCheck.GetLastInputTime() > TIMEOUT_DONE)
{
DialogResult dialogResult = MessageBox.Show("Sure", "Some Title", MessageBoxButtons.YesNo);
if (dialogResult == DialogResult.Yes)
{
Stop();
Reset();
}
}
}
public void Reset()
{
timer = new Timer();
timer.Interval = 10000;
timer.Tick += timer_Tick;
timer.Start();
}
public void Stop()
{
timer.Tick -= timer_Tick;
timer.Stop();
}
}
I have this class called AudioInput:
class AudioInput
{
private WaveIn waveIn;
public delegate void DataAvailableEventHandler(byte[] data, int size);
private DataAvailableEventHandler dataAvailableProc;
public AudioInput(DataAvailableEventHandler dataHandlerProc)
{
dataAvailableProc = dataHandlerProc;
}
private void initWaveInMic()
{
Console.WriteLine("initWaveInMic");
waveIn = new WaveIn();
waveIn.BufferMilliseconds = 50;
waveIn.DeviceNumber = 0;
waveIn.WaveFormat = new WaveFormat(8000, 1);
waveIn.DataAvailable += new EventHandler<WaveInEventArgs>(waveIn_DataAvailable);
waveIn.StartRecording();
}
void waveIn_DataAvailable(object sender, WaveInEventArgs e)
{
Console.WriteLine("waveIn_DataAvailable e.buffer length: {0}", e.Buffer.Length);
dataAvailableProc(e.Buffer, e.Buffer.Length);
}
public void startNAudio()
{
this.initWaveInMic(); //start mic wavein
}
}
From the calling class:
public partial class AudioTest : Form
{
Thread audioInputThread;
AudioInput audioInput;
private void audioInputCreateThread()
{
audioInput = new AudioInput(audioDataToSend);
audioInput.startNAudio();
Console.WriteLine("audioInputCreateThread at the end");
}
private void AudioTest_Load(object sender, EventArgs e)
{
// this will work
//audioInputCreateThread();
//this will not work
audioInputThread = new Thread(audioInputCreateThread);
audioInputThread.Start();
}
private void audioDataToSend(byte[] data, int size)
{
Console.WriteLine("audioDataToSend size: {0}", size);
}
}
The waveIn_DataAvailable callback in the AudioInput class is not getting called. Any suggestions what I did wrong?
The WaveInEvent class should be used in this instance. It will create its own background thread, and use a SyncContext to marshal callbacks onto the GUI thread if possible.