Microphone stops providing data with NAudio - c#

I'm using WaveInEvent of NAudio to record microphone data. It works fine for a while, but after a few times, it stops providing input data- the DataAvailable callback is never called with new data.
I have tried creating a new WaveInEvent each time, but this did not resolve the problem. I've also tried using the WASAPI input, which always called DataAvailable - with zero bytes of data.
How can I record audio from the microphone reliably with NAudio?
Currently, my code looks like this:
StartRecording() {
microphone = new WaveInEvent();
microphone.DeviceNumber = 0;
microphone.WaveFormat = outformat;
microphone.BufferMilliseconds = 50;
microphone.DataAvailable += (_, recArgs) =>
{
session.OnAudioData(recArgs.Buffer, recArgs.BytesRecorded);
};
microphone.StartRecording();
}
StopRecording() {
if (microphone != null)
{
microphone.StopRecording();
microphone.Dispose();
microphone = null;
}
}
There's no other naudio code in the project except using WaveFormat to describe wave formats.
NAudio throws an access violation exception trying to call WaveInBuffer.Reuse() from a threadpool worker. I'm not sure why this doesn't do something more serious than just drop audio data.
For the condition where I did not recreate the WaveInEvent, I get an MmException instead- invalid handle calling waveInPrepareHeader, in the same place.
Frankly, the fact that I get different results heavily implies that NAudio is doing some funky shit it shouldn't to share state between instances, and looking at the source on Codeplex, I'm not really sure WTF is going on.

It seems that the drivers for the USB microphone do not behave correctly. When the buffer is sent to the user through the WIM_DATA message, it is full. However when waveInUnprepareHeader is called, it's still in the queue, even though it was literally just passed as full. So I think that the drivers for the microphone are ultimately to blame.
I've been looking more closely at the microphone and it seems that this particular unit is actually known to have been damaged.

Related

C# MIDI Device Send CC Message to Reset Trigger

I have a LaunchPad MK3 Mini MIDI device that I'm looking to tie into a C# app I'm making, where pressing buttons will invoke a various functions within the app. After a bit of research, I landed on using the RtMidi.Core library (thru NuGet). And upon debugging, it appears that I'm able to fully listen to the device and react to events appropriately, and that's good.
I should also back up a bit as well. I'm quite inexperienced to using MIDI devices so a lot of the terminology and industry usage is a bit lost on me. But it's my understanding that a MIDI device can be modified so that the individual keys can be changed to perform a different MIDI event. In my case, I'm not using this for any musical purpose, so there is no need for Note/Piano type events. So I changed all the buttons to be Control Change, all of them with unique Channel/ControlNum combinations. It appears these CC buttons can be one of 3 "Pad Modes":
Momentary - Both KeyDown and KeyUp each will trigger a separate MIDI event
Toggle - Only KeyDown will trigger a MIDI event and each one will alternate between 0 and some specified non-zero value
Trigger - Only KeyDown will trigger a MIDI event, but it will always be the specified non-zero value
Now, as it pertains to my use cases. I'm looking to utilize the 'Trigger' Pad Mode type, as this will trigger some various code which will last a variable duration. My issue is, the MIDI device will change the LED keylight color to its ON color and it NEVER goes back to its initial state (as expected, tbh). So what I'm looking to do is after my 'certain function' is done executing, that it would 'reset' this trigger back to the initial state as its last course of action.
So, I create a ControlChangeMessage with the proper channel/control/value and send it to the MIDI device, but the LED color doesn't seem to change back to the original color. The ONLY thing that seems to reset its state is to unplug the USB power from the device and plug it back in.
For reference: The input and output device names I'm using are similar, but different, as indicated in the code below:
foreach (var inputDeviceInfo in MidiDeviceManager.Default.InputDevices)
{
Console.WriteLine($"Opening {inputDeviceInfo.Name}");
if (inputDeviceInfo.Name == "MIDIIN2 (LPMiniMK3 MIDI) ")
{
var inputDevice = inputDeviceInfo.CreateDevice();
devices.Add(inputDevice);
inputDevice.ControlChange += ControlChangeHandler;
inputDevice.Open();
}
}
foreach (var outputDeviceInfo in MidiDeviceManager.Default.OutputDevices)
{
Console.WriteLine($"Opening {outputDeviceInfo.Name}");
if (outputDeviceInfo.Name == "MIDIOUT2 (LPMiniMK3 MIDI) ")
{
var outputDevice = outputDeviceInfo.CreateDevice();
devicesOut.Add(outputDevice);
outputDevice.Open();
//while (!outputDevice.IsOpen) { }
ControlChangeMessage ccMsg = new ControlChangeMessage(RtMidi.Core.Enums.Channel.Channel3, 0, 0);
outputDevice.Send(ccMsg);
}
}
So from this, I'm really unsure why this wouldn't be working. Perhaps there is another MIDI library I could be using, or perhaps I'm just missing something with respect to how these MIDI devices work.

Need for thread.sleep() when playing a sound array using DirectSoundOut

dso = new DirectSoundOut(Guid.Parse(AudioOutDevice));
var ms = new MemoryStream(soundArray.ToArray()))
{
IWaveProvider provider = new RawSourceWaveStream(ms, new WaveFormat());
dso.Init(provider);
dso.Play();
Thread.Sleep(3000);
}
I am able to play sound array through desired output device using the above code, and i am unable to hear the sound if there is thread.sleep. But I am unable to understand the reason for using thread.sleep. Can any one let me know the reason for thread.sleep()
The call to Play is not blocking. It simply starts playback. So you must keep dso alive until playback ends or you have stopped it manually.
You can use code like this if you want to block yourself (obviously only use this if your audio isn't infinitely long)
dso.Play();
while (dso.PlaybackState == PlaybackState.Playing)
{
Thread.Sleep(500);
}
dso.Dispose();

Send mixed sound from WCF using callbacks

I would like transfer mixed sound from WCF server to all connected clients. Using WCF service callbacks for this. Sound is mixed using naudio library.
Here is little example of server-side (WCF method):
MixingSampleProvider _mixer = new MixingSampleProvider(sound32.WaveFormat);
SampleToWaveProvider _sampleToWave = new SampleToWaveProvider(_mixer);
// service method
byte[] buffer = new byte[1000];
do{
_sampleToWave.Read(buffer, 0, 1000);
client.Callback.SendBuffer(buffer);
} while (_isPlaying)
and client-side:
BufferedWaveProvider _bufferedWave = new BufferedWaveProvider(sound32.WaveFormat);
// DirectSoundOut _output = new DirectSoundOut();
WaveOut _output = new WaveOut();
_output.Init(_bufferedWave);
// callback event method
if (_output.PlaybackState != PlaybackState.Playing)
_bufferedWave.AddSamples(buffer, 0, 1000);
// now in timer_tick event method
// if(_bufferedWave.BufferedDuration.TotalSeconds > 0.5)
// _output.Play();
// else
// _output.Pause();
I'm new in this, so I have a few questions.
Is this idea a good one? Is there simpler option to handle this?
[EDIT_1] I created test app with local two methods, which should simulate this and I found, that _bufferedWave.BufferedBytes are not clearing when is buffered sound playing (and it will overflow immediately). Can somebody tell me, why?
[EDIT_1] Changed type of _output field from DirectSoundOut to WaveOut and it's helpful.
Second change I did was, that I added DispatcherTimer to handle when is buffered duration greater than 0.5 (according naudio MP3Streaming example).
Now, I'm fighting with buffer time. I can hear sound only for time in _timer_Tick event method:
_bufferedWave.BufferedDuration.TotalSeconds > XX // this XX is time I can hear sound
Any ideas or opinions?
I'm not sure that this will work the way you hope. WCF is TCP based and TCP is not designed for broadcasting audio video or anything that requires speed (like games) due to it's constant checking of packets.
I have previously used naudio to transmit sound over a network to a listener client but for it to work you will need to use UDP.
If you want this to work over the internet then you will need to look into UDP hole-punching.
Also before you transmit your audio you should compress it from 16bit to 8bit and then back to 16bit upon receiving it using something like an ALaw or MuLaw Decoder/Encoder.

ObjectDisposedException: Safe handle has been closed

So this is a rather small question with a big explanation. As is noted by the title I am getting an unhandled exception telling me my Safe handle has been closed. What I'll probably have to do is edit this post a few times with more and more code to help me diagnose what the problem is.
I'm using POS for .NET to make a Service Object for my RFID and MSR device. Although my devices are the same, I have 2 different Virtual COM Port chips that communicate to those devices. One by Silicon labs, the other by FTDI. I wanted to use the plug and play features with POS for .NET so I gave it both my Hardware ID's. Because it is plug and play I have the full hardware path available to me which I can then create a SafeFileHandle using a call to PInvoke and using that SafeFileHandle I create a FileStream. The FTDI chip doesn't let me talk to the devices directly like that so I have to get the friendly name of the device then use mutex to pull out the COM port then create a SerialPort instance. That step works fine and great. As a FYI I have tried to use the Friendly name of both chips to get the COM port and the Silicon Labs one (for some strange reason) doesn't get listed using SetupAPI.GetDeviceDetails using the Ports GUID. I'm not sure on that one since in Device Manager the Silicon labs Device Class Guid is the Ports GUID.
Well since both the SerialPort and the FileStream have a Stream object I decided to use that to read and write to that port. The problem with that is if I send a RFID command to the MSR device the MSR device doesn't respond back with anything. So if I use this code int fromReader = ReaderStream.ReadByte(); my thread is blocked. It's a blocking call and requires a minimum of 1 byte to proceed. So I looked around and it appears the only solution is to use a separate thread and set a timeout. If the timeout happens then abort the thread.
Thread t = new Thread(new ThreadStart(ReadFromStream));
t.Start();
if (!t.Join(timeout))
{
t.Abort();
}
(t.Abort has been surrounded with a try/catch to no avail, since it didn't fix the problem I removed it)
ReadFromStream is Abstract method in RFID Device. Here is one of the implementations
protected override void ReadFromStream()
{
var commandLength = USN3170Constants.MIN_RESPONSE_LENGTH;
var response = new System.Collections.Generic.List<byte>(USN3170Constants.MIN_RESPONSE_LENGTH);
for (int i = 0; i <= commandLength; i++)
{
int fromReader = ReaderStream.ReadByte();
if (fromReader == -1) break; //at end of stream
response.Add((byte)fromReader);
if (response.Count > USN3170Constants.DATA_LENGTH_INDEX && response[USN3170Constants.DATA_LENGTH_INDEX] > 0)
{
commandLength = response[USN3170Constants.DATA_LENGTH_INDEX] + 3;
}
}
streamBuffer = response.ToArray();
}
(int fromReader = ReaderStream.ReadByte(); was surrounded with a try/catch. Only thing it caught was the aborted thread exception, so I took it out)
The above code is where I suspect the problem lies. The strange thing is, though, is that I have a unit test which I feel mimics rather well the Microsoft Test App.
(FYI QUADPORT is the FTDI chipset)
PosExplorer posExplorer;
DeviceCollection smartCardRWs;
[Test]
public void TestQuadPortOpen()
{
posExplorer = new PosExplorer();
smartCardRWs = posExplorer.GetDevices(DeviceType.SmartCardRW, DeviceCompatibilities.CompatibilityLevel1);
//if using quadport one item is the MSR and the other is the RFID
//because of that one of them will fail. Currently the first Device in the collection is the the RFID, and the second is MSR
Assert.GreaterOrEqual(smartCardRWs.Count, 2);
//Hardware Id: QUADPORT\QUAD_SERIAL_INTERFACE
foreach(DeviceInfo item in smartCardRWs)
{
Assert.AreEqual("QUADPORT\\QUAD_SERIAL_INTERFACE", item.HardwareId);
}
SmartCardRW rfidDevice = (SmartCardRW)posExplorer.CreateInstance(smartCardRWs[0]);
SmartCardRW msrDevice = (SmartCardRW)posExplorer.CreateInstance(smartCardRWs[1]);
rfidDevice.Open();
Assert.AreNotEqual(ControlState.Closed, rfidDevice.State);
rfidDevice.Close();
try
{
msrDevice.Open();
Assert.Fail("MSR Device is not a RFID Device");
}
catch
{
Assert.AreEqual(ControlState.Closed, msrDevice.State);
}
rfidDevice = null;
msrDevice = null;
}
When I run that test I do not get the SafeFileHandle exception. In fact the test passes.
So I am at a loss as to how to track down this bug. Since I'll be using this Service Object in a different program that I am also creating I'll probably end up using this code from this test in that program. However I feel that the Microsoft Test App is more or less the "Golden Standard". Is it really... probably not. But it does work good for my purposes, SO I feel it is a problem with my code and not theirs.
Any tricks on how I can narrow this down? FYI I've tried using the debugger but walking the Open Code the error does not occur. I also walked the Update Status Timer and it also does not throw the error. Once I hit continue then I'll get the exception. I turned of Just My Code and Loaded Symbols and it tells me "Source Information is missing from teh debug information for this module"
This problem (and in particular the reference to a SerialPort instance) sounds suspiciously like the problem documented at http://connect.microsoft.com/VisualStudio/feedback/details/140018/serialport-crashes-after-disconnect-of-usb-com-port.
As I understand it, in the case of a non-permanent SerialPort (like one associated with a USB device, for example) when the port "goes away" unexpectedly the underlying Stream associated with it gets disposed. If there is an active read or write operation on the port at the time a subsequent call to SerialPort.Close can lead to the exception you mention, however the exception is occurring in Microsoft's code running on a different thread and cannot be caught from within your code. (It will still be seen by any "last chance" exception handler you have bound to the UnhandledException event on the AppDomain.)
There seem to be two basic workaround styles in the linked document. In both instances, after opening the port you store a reference to the BaseStream instance for the open port. One workaround then suppresses garbage collection on that base stream. The other explicitly calls Close on the base stream, capturing any exceptions thrown during that operation, before calling Close on the SerialPort.
EDIT: For what it's worth, under the .NET framework V4.5, it appears that none of the documented workarounds on the Microsoft Connect site fully resolve the problem although they may be reducing the frequency with which it occurs. :-(
I had the same error when I used a thread to read from a SerialPort. Calling Interrupt on the thread occasionally caused the uncatchable ObjectDisposedException. After hours of debugging and carefully reading this:
https://blogs.msdn.microsoft.com/bclteam/2006/10/10/top-5-serialport-tips-kim-hamilton/
I realized that the problem is just this:
NET 2.0 (and above) isn’t letting you get away with some things, such as attempting to cancel a SerialPort read by interrupting the thread accessing the SerialPort.
So before you call Thread.Interrupt() you have to close the COM... This will cause a catchable exception on the ReadByte operation.
Or you may use the ReadTimeout property on the SerialPort to avoid using a thread just to have a timeout.
I would like to post my case in which I had a similar issue trying to read from a serial port (virtual com driven by a Moxa RS232 to ethernet).
Since I did have no chance to catch the ObjectDisposedException, the only solution was to increase the ReadTimeout property which was originally set to -1 (continuous reading).
Setting the ReadTimeout to 100 millis solved this issue in my case.
EDIT
It is not the definitive solution: it can happen that if you close the application during a read attempt you can get the same uncatchable exception.
My final solution is to kill the process of the application directly in the FormClosing event :
private void MyForm_FormClosing(object sender, FormClosingEventArgs e)
{
Process p = Process.GetCurrentProcess();
p.Kill();
}
Please take a look at this:
https://github.com/jcurl/SerialPortStream
I replaced System.IO.Ports with RJPC.IO.Ports, fixed up a couple parameter differences in the initialization, and all the problems went away with this issue.

C# "using" SerialPort transmit with data loss

I'm new to this forum, and I have a question that has been bothering me for a while.
My setup is a serial enabled character display connected to my pc with a usb/uart converter. I'm transmitting bytes to the display via the serialPort class in a separate write buffer thread in a C++ style:
private void transmitThread(){
while(threadAlive){
if(q.Count > 0){ // Queue not empty
byte[] b = q.Dequeue();
s.Write(b,0,b.Length);
System.Threading.Thread.Sleep(100);
}
else{ // Queue empty
System.Threading.Thread.Sleep(10);
}
}
}
Assuming the serial port is already opened, this works perfectly and transmits all the data to the display. There are though no exception handling at all in this snippet. Therefore I was looking into implementing a typical C# feature, the 'using' statement and only opening the port when needed, like so:
private void transmitThread(){
while(threadAlive){
if(q.Count > 0){ // Queue not empty
byte[] b = q.Dequeue();
using(s){ //using the serialPort
s.Open();
s.Write(b,0,b.Length);
s.Close();
}
System.Threading.Thread.Sleep(100);
}
else{ // Queue empty
System.Threading.Thread.Sleep(10);
}
}
}
The problem with this function is, that it only transmits a random amount of the data, typically about one third of the byte-array of 80 bytes. I have tried different priority settings of the thread, but nothing changes.
Am I missing something important, or do I simply close the port too fast after a transmit request?
I hope you can help me. Thanks :)
No, that was a Really Bad Idea. The things that go wrong, roughly in the order you'll encounter them:
the serial port driver discards any bytes left in the transmit buffer that were not yet transmitted when you close the port. Which is what you are seeing now.
the MSDN article for SerialPort.Close() warns that you must "wait a while" before opening the port again. There's an internal worker thread that needs to shut down. The amount of time you have to wait is not specified and is variable, depending on machine load.
closing a port allows another program to grab the port and open it. Serial ports cannot be shared, your program will fail when you try to open it again.
Serial ports were simply not designed to be opened and closed on-the-fly. Only open it at the start of your program, close it when it ends. Not calling Close() at all is quite acceptable and avoids a deadlock scenario.
I think you're missing the point of the using block. A typical using block will look like this:
using (var resource = new SomeResource())
{
resource.DoSomething();
}
The opening happens at the very beginning. Typically as part of the constructor. But sometimes on the first line of the using block.
But the big red flag I see is that the closing happens automatically. You don't need the .Close() call.
If the successful operation of your serial device is dependent on the calls to Thread.Sleep then perhaps the thread is being interrupted at some point, sufficient to make the data transmission out of sync with the device. There would most likely be ways to solve this but the first thing I would do is try to use the .NET SerialPort class instead. The Write method is very similar to what you want to do, and there are C++ code examples in those articles.

Categories