6581 Useful Things

October 9, 2006

Minimizing audio capture latency in DirectShow

Filed under: DirectShow — sid6581 @ 8:21 pm

If you have used DirectShow for audio capture, you have probably noticed that audio that is being previewed by an audio renderer in your graph can significantly lag the audio capture source. This is especially obvious if you are capturing and previewing both audio and video, where this lag will make your preview look like a badly dubbed movie.

The cause of the lag can be hard to track down if you don’t know where to look. It turns out that the reason is that the audio capture source in DirectShow defaults to using 500ms buffers. In other words, the capture source has to capture 500ms worth of audio before it can pass the buffer downstream. Since the audio renderer can’t render any audio until it gets the buffer from the source, there will be at least a 500ms latency between any audio being captured and any audio being played.

So what can we do about it? There’s actually a fairly easy way to ask the capture source to use a smaller buffer: The IAMBufferNegotiation interface. You have to get this interface from the audio capture pin on your capture filter, not the filter itself. Using it is very simple, but you need to be careful when calculating the buffer size to take into account the current audio capture rate, the number of channels, and the number of bits in a sample.

Below is a quick example. Call this function with your audio capture pin and your desired latency in milliseconds (try 50ms), and your latency problems should hopefully be taken care of.

HRESULT SetAudioLatency(IPin *AudioCapturePin, int BufferSizeMilliSeconds)
{
   assert(AudioCapturePin);
   assert(BufferSizeMilliSeconds > 0); 

   // Get the interfaces we need.
   CComQIPtr<IAMStreamConfig> streamconfig(AudioCapturePin);
   if (!streamconfig)
      return E_NOINTERFACE; 

   CComQIPtr<IAMBufferNegotiation> bufneg(AudioCapturePin);
   if (!bufneg)
      return E_NOINTERFACE; 

   // Get the current audio capture properties.
   CMediaType mt;
   HRESULT hr = streamconfig->GetFormat(&mt);
   if (FAILED(hr))
      return hr; 

   assert(*mt->FormatType() == FORMAT_WaveFormatEx);
   assert(mt->FormatLength() >= sizeof(WAVEFORMATEX));
   WAVEFORMATEX *wf = (WAVEFORMATEX *)MediaType->Format(); 

   // Set the desired buffer size.
   ALLOCATOR_PROPERTIES props;
   props.cBuffers = -1;
   props.cbBuffer = wf->nAvgBytesPerSec * BufferSizeMilliSeconds/1000;
   props.cbAlign = -1;
   props.cbPrefix = -1;
   return bufneg->SuggestAllocatorProperties(&props);
}
About these ads

8 Comments »

  1. Hello,

    I am having difficulty compiling this example using Visual Studio 2005. As soon as I include any header that declares CComQIPtr, I get error “C1189: Need to include strsafe.h after tchar.h”. I would appreciate if you can provide exact headers included in your example. Thanks in advance.

    Regards,
    Vinay Agarwal

    Comment by Vinay Agarwal — March 15, 2007 @ 7:54 pm

  2. Any sugestion?
    I’m in the same situatuion , my include directory have this order:

    C:\Archivos de programa\Microsoft Visual Studio 8\VC\atlmfc\include
    C:\Archivos de programa\Microsoft Visual Studio 8\VC\include
    $(VCInstallDir)include
    C:\Archivos de programa\Microsoft DirectX 9.0 SDK (February 2005)\Include
    C:\Archivos de programa\Microsoft DirectX 9.0 SDK (February 2005)\Extras\DirectShow\Include
    C:\Archivos de programa\Microsoft DirectX 9.0 SDK (February 2005)\Extras\DirectShow\Samples\C++\DirectShow\BaseClasses
    $(VCInstallDir)PlatformSDK\include
    $(FrameworkSDKDir)include

    ************** In my computer ************
    in C:\Archivos de programa\Microsoft DirectX 9.0 SDK (February 2005)\Include

    and

    in C:\Archivos de programa\Microsoft Visual Studio 8\VC\include

    *******************************************

    first :
    C:\Archivos de programa\Microsoft Visual Studio 8\VC\include

    second :
    C:\Archivos de programa\Microsoft DirectX 9.0 SDK (February 2005)\Include

    Comment by charlie — June 14, 2007 @ 9:10 am

  3. Try including atlbase.h before you include any DirectShow header files. If that doesn’t work, try including tchar.h before you include anything else. Without knowing which header files you include, and in which order, I’m not sure what else to try.

    Comment by sid6581 — June 16, 2007 @ 9:24 pm

  4. I am using the DirectShowLib.Net for a tv viewer application (C#). So I’m using preview for watching the video and I couldn’t figure out the reason of the audio latency. Your post solved the issue. Thanks!

    Comment by Gerwin — March 22, 2008 @ 8:56 am

  5. [...] ? >Can you refer me to a relevant sample with IAMBufferNegotiation usage? Here you go: http://sid6581.wordpress.com/2006/10…in-directshow/ — Be seeing [...]

    Pingback by Synchronized preview of Composite and Line in | keyongtech — January 18, 2009 @ 10:42 am

  6. Thank you! I`ll try that :)

    Comment by Angel G — February 10, 2009 @ 3:29 am

  7. I assume by “MediaType” you meant “mt”? Also thanks for the code, seems to work great!

    Comment by roger — August 20, 2012 @ 6:37 pm


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

The Silver is the New Black Theme. Blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: