Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to record audio with WasapiLoopbackCapture when no voice is coming out from speaker in c#?

The below is my sample code to record audio coming from a speaker. It is working fine. But it is recording audio only when some audio is coming out from speaker. If there is no audio then it is not recording. Actually i am doing screen recording with system's voice. The length of audio recorded by wasapiloop is mismatching with screen recording length because wasapiloop is recording audio only when there is sound from speaker.

WasapiCapture waveLoop = new WasapiLoopbackCapture();
waveLoop.Initialize();
waveLoop.DataAvailable += waveLoop_DataAvailable;
waveLoop.Stopped += waveLoop_Stopped;
waveLoop.Start();

I have seen one similar stack over flow question but i did not understand it fully.

CSCore loopback recording when muted

Any help is greatly appreciated.

like image 833
chindirala sampath kumar Avatar asked Sep 15 '18 14:09

chindirala sampath kumar


1 Answers

By design WASAPI loopback capture only produces data when there is actual playback - you already figured this out. If your goal is to produce continuous data stream you are responsible to generate silence audio bytes for the gaps between data generated by loopback capture. Loopback capture data comes with time stamps and discontinuity flags, so you can apply simple math and identify number of zero/silence bytes to add.

UPDATE. Having checked NAudio code (esp. here) I see a problem for accurate math for silence byte calculation in DataAvailable event: NAudio ignores DataDiscontinuity also known as AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY flag reported by loopback capture.

Loopback capture will produce audio packets of specific duration (e.g. 10 ms long) when there is playback data on the endpoint. These packets are exposed to you to be read via WasapiLoopbackCapture interface. There is no buffering and as long as data you read is continuous, GetBuffer call does not raise the DataDiscontinuity flag. That is, you have the flag with your first packet and then until you see it next time you treat the data as continuous.

When playback stops and loopback capture stops producing data, there is no new data from GetBuffer. However you know the size/duration of the packet and in absence of data your timer needs to substitute this missing data with silence bytes (it is also a good idea to take care of partially filled last packet in a sequence with respective size of silence packet). You will be injecting the silence bytes until GetBuffer call succeeds and gets you new data available. You will have DataDiscontinuity flag there to indicate a new data sequence.

From that point you are supposed to stop doing silence and use read captured data again. Also since you know there is no buffering involved, it would be a good idea to use the discontinuity packet to update your timing records: when you have the packet you can assume that its last byte corresponds to moment in time when GetBuffer succeeded. From there you can derive the number of silence bytes to fill for perfect continuity of your combined stream.

So the idea is to take DataDiscontinuity flag from NAudio so that it does not get lost, add a timer for timely silence byte generation and get everything together with checking continuity, adding silence bytes in timer callback and combining everything into continuous feed.

like image 81
Roman R. Avatar answered Oct 27 '22 06:10

Roman R.