filoe / cscore

An advanced audio library, written in C#. Provides tons of features. From playing/recording audio to decoding/encoding audio streams/files to processing audio data in realtime (e.g. applying custom effects during playback, create visualizations,...). The possibilities are nearly unlimited.
Other
2.15k stars 451 forks source link

WasapiLoopbackCapture noisy #382

Closed JohnsonGao closed 4 years ago

JohnsonGao commented 5 years ago

Hi Florian, Here is a problem about CSCore.DLL Blocking

Visual Studio - Call Stack - Info here:

CSCore.dll!CSCore.SoundIn.WasapiCapture.CaptureProc(object param = {System.Threading.AutoResetEvent}) Line 270 C#

int eventWaitHandleIndex = WaitHandle.WaitAny(eventWaitHandleArray, actualLatency, false);

I found it was always blocked here when I use WasapiCapture to capture microphone stream. It prevents my application from normally exits, keeping suspended state in memory and unable to quit. How to resolve this problem ? Thank you!

filoe commented 5 years ago

The specified timeout should prevent the thread from blocking. What is the value of actualLatency?

JohnsonGao commented 5 years ago

No setting for SoundIn Object when creation, should be the default value = 100, right ?

    _soundIn = new WasapiCapture() { Device = _MMDevice };
    _soundIn.Initialize();
filoe commented 5 years ago

Do you dispose then _soundIn instance when closing the application?

JohnsonGao commented 5 years ago

Yes, I think so, before exits application, I disposed every objects including this one: public void Dispose() { ... ... if (_soundIn != null) { _soundIn.Dispose(); _soundIn = null; } ... ... }

JohnsonGao commented 5 years ago

Thank you very much, you remind me a problem here: I created the soundIn object several times before every time to use, but when do every creation without Dispose the previous one(same name), at last only one object to be disposed when application exits, maybe there are a series soundIn objects in memory already. And maybe right the un-disposed SoundIn objects prevent the thread from exits. Changed codes as follows and it works now: if (_soundIn != null ) {_soundIn .Dispose(); _soundIn = null;} _soundIn = new WasapiCapture() { Device = _MMDevice }; _soundIn.Initialize();

Thank you very much!

filoe commented 5 years ago

Yes, please make sure to dispose all objects in order to release the threads. It is not possible to run the internal threads as background threads (see https://docs.microsoft.com/en-us/dotnet/api/system.threading.thread.isbackground?view=netframework-4.8), since it can cause strange and unintented behaviour.

JohnsonGao commented 5 years ago

Another question is that I found the sound is not clear when use WasapiloopbackCapture to cap speaker sounds in CSCore Recorder. Did you meet the same situation? Noisy.

filoe commented 5 years ago

No, never met that situation. Maybe you could show me your setup?

JohnsonGao commented 5 years ago

I did not change codes, so the params setup should still keep your sample's setting. I just used the sample of Recorder in CSCore Samples to test. I got noisy loopback recording results. I doubt whether or not some wrong settings exist in my test machine? So meanwhile in the same OS of win7, I used NAudio sample to do the same job and got clear results. Same OS, same recording operations using Wasapiloopback capture, got different audio effects.

Ambusy commented 4 years ago

This "noisy" recording, is it the same problem I reported oct 2018? every n milliseconds a bit of the sound is missing? as if bufferlength returned is less than the actual wav in the buffer, or as if the buffer was truncated? I tried the recorder sample again today with a fresh download in Visual studio 2019 on windows 7 pro and the problem still exists. I was lucky to have a backup of CsCore.dll from 2014, and with a reference to that dll (and removing the project from the CsCore.sln!) everything works . But I remain with an old dll version.

filoe commented 4 years ago

Does it make any difference whether you use eventSync or not?

Ambusy commented 4 years ago

I tried the RECORDER sample. As there is no simple entry in WasapiLoopbackCapture to pass eventSync as true, I hard code true in CsCore's WasapiLoopbackCapture:

public WasapiLoopbackCapture() : base(true, AudioClientShareMode.Shared) { } and keep calling this as:

_soundIn = new WasapiLoopbackCapture();

This results in no wav file: the soundInSource.DataAvailable is never executed.

Update:

With original WasapiLoopbackCapture and call as folllows: var defaultFormat = WaveFormatFromBlob(SelectedDevice.PropertyStore[ new PropertyKey(new Guid(0xf19f064d, 0x82c, 0x4e27, 0xbc, 0x73, 0x68, 0x82, 0xa1, 0xbb, 0x8e, 0x4c), 0)].BlobValue);

_soundIn = new WasapiLoopbackCapture(100, defaultFormat, System.Threading.ThreadPriority.AboveNormal, true); gives the same result.

second update: Recorder with eventSync true does not use CPU, with false about 2%

If someone could explain how one has to use eventSync, I would try it to find the solution. I don't know where to look.

filoe commented 4 years ago

I'm sorry, forgot about that. I'll try to take a look at it. I've already tried to compare any version of WasapiCapture from 2014 and the current version. Was hard to find a difference at first look. If you can find any major differences, it would be a great help. Also it was hard for me to reproduce the issue.

JohnsonGao commented 4 years ago

I almost agree to Ambusy 's assumption, the buffer missing some data, not machting the bufferlength returned. As I resample using ffmpeg, I use CSCore wasapiloopback capture as audio source, sample rate from 48000 to 44100, I found the result very noisy as CSCore RECORDER, but when I change target sample rate from 44100 to 22050, then better effect appears, double clearer than previous; then I go on to change target sample rate from 22050 to 11025, the result got very clear now (but still has a bit data loss makes discontinious). So I doubt the DataAvailable event did not spit out enough audio data in the byte array as 48000? low speed results in that? Can I guess so ? Is there time control issues lead to this?

Ambusy commented 4 years ago

I have a version of 20.02.2015. except for comments and spaces here and there the difference is: `in WasapiCaputure

I changed the SleepDuration back to the shorter period, and it seems to work. I'll get back to you within days, to verify the other 5 recorder programs that I have (3 yours, 2 mine). Thanks for the indications.

Ambusy commented 4 years ago

Hi Florian, The problem is solved in all recorders I have tested. The line int sleepDuration = actualLatency; in function CaptureProc should be modified. In the 2014 version it was actualLatency/8; I tried to lower that number down, and found that in my environment (win7pro, Vs 2019 community) if it reads: int sleepDuration = actualLatency/2; everything works fine.

As I have no experience at all about how to intervene in someone elses project in Github, please will you change that line? Thanks, Martin

filoe commented 4 years ago

Thanks again!