So AddVoiceData
is being called every time new samples become available from Steam? If this is the case, then the reason for the crackling and pops would be due to short gaps of time between AddVoiceData
calls when the FMOD::Sound
has finished playing and there are no more samples to play, so it outputs silence. This is could loosely be described as “buffer starvation”, and the way to avoid it is to do three things:
- Rather than playing a new
FMOD::Sound
every time samples become available, useAddVoiceData
to write your samples to an intermediate ring buffer, then in yourUpdate
loop read from the buffer and add it to yourFMOD::Sound
usingSound::lock
/Sound::unlock
. This will ensure samples are being given to theFMOD::Sound
without any gaps. - Introduce some latency to give yourself a little more time for samples to become available. You can do this by waiting for the write position of your buffer to reach some value before starting to read from it and filling your
FMOD::Sound
. - Keep track of the distance between your read and write positions, and when the distance is greater than your target latency, use
Channel::setFrequency
to speed-up the sample rate of yourFMOD::Channel
to get theFMOD::Sound
to consume samples faster. Likewise when the distance is less than your target latency, reduce the sample rate of yourFMOD::Channel
until you get back to your target latency. This will account for any irregularities in the rate at which samples arrive fromAddVoiceData
, and will ensure you never run out of samples to play. If you speed up or slow down too quickly however you will get pitch distortions, so only make very small changes to the sample rate.
I recently wrote an example which applies this approach to hook into a Video’s audio source in Unity and get it playing through FMOD- it is the same concept and should help demonstrate how to avoid buffer starvation.