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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With