When device format is using 48k-sampling and content format is using 44.1k-sampling, playback problems occur. We observed the following sequence of events.
[WasapiOut::PlayThread]
1. audio buffer is filled at first
2. enter while loop and sleep for a while
3. try to fill buffer again, sometimes 'numFramesAvailable' is only '1'
[WasapiOut::FillBuffer]
4. when argument 'frameCount'='1' and 'playbackProvider' is SRC Dmo (i.e. device format is 48k while content is 44.1k), 'playbackState' will be stopped
5. no sound gets played, or you only hear a click
Step 4 is caused since:
[ResamplerDmoStream::Read]
int inputBytesRequired = (int)OutputToInputPosition(count - outputBytesProvided);
=>
[ResamplerDmoStream::OutputToInputPosition]
long inputPosition = (long)(outputPosition / ratio);
=>
inputPosition is 0 since double to integer truncation
Thus, the idea is only use FillBuffer when available frame count is 'bigger' so that inputPosition does not result in double-to-integer truncation value of 0.
We propose an easy fix by changing WasapiOut.cs, line 138, so that (numFramesAvailable > 10), instead of (numFramesAvailable > 0).
138: if (numFramesAvailable > 10)
139: {
140: FillBuffer(playbackProvider, numFramesAvailable);
141: }
Ten frames are safe and will not cause data loss. Of course, modifying behavior with 'OutputToInputPosition' is another way.
[WasapiOut::PlayThread]
1. audio buffer is filled at first
2. enter while loop and sleep for a while
3. try to fill buffer again, sometimes 'numFramesAvailable' is only '1'
[WasapiOut::FillBuffer]
4. when argument 'frameCount'='1' and 'playbackProvider' is SRC Dmo (i.e. device format is 48k while content is 44.1k), 'playbackState' will be stopped
5. no sound gets played, or you only hear a click
Step 4 is caused since:
[ResamplerDmoStream::Read]
int inputBytesRequired = (int)OutputToInputPosition(count - outputBytesProvided);
=>
[ResamplerDmoStream::OutputToInputPosition]
long inputPosition = (long)(outputPosition / ratio);
=>
inputPosition is 0 since double to integer truncation
Thus, the idea is only use FillBuffer when available frame count is 'bigger' so that inputPosition does not result in double-to-integer truncation value of 0.
We propose an easy fix by changing WasapiOut.cs, line 138, so that (numFramesAvailable > 10), instead of (numFramesAvailable > 0).
138: if (numFramesAvailable > 10)
139: {
140: FillBuffer(playbackProvider, numFramesAvailable);
141: }
Ten frames are safe and will not cause data loss. Of course, modifying behavior with 'OutputToInputPosition' is another way.