1

I'm trying to play a wav file(44100sr 16bits 2 channels) from the disk , and I need to process the audio data in the SampleGrabber filter callback ,but it always received 44100 bytes data four times per seconds, I want to change the callback rate to 10 times per seconds(audio sample size:17640 bytes per callback),not four times(44100 bytes per time), How can I make it works as expected?

hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC, IID_IBaseFilter, (void **)&m_pBgmAudioGrabber);
BREAK_IF_FAILED(hr);
        
hr = m_pGraph->AddFilter((IBaseFilter*)m_pBgmAudioGrabber, L"Bgm Audio Mix");
BREAK_IF_FAILED(hr);

hr = InitBgmAudioGrabble();
BREAK_IF_FAILED(hr);

CComPtr<IPin> pAudioMixInputPin;
hr = g_DSHelper.GetPin(m_pBgmAudioGrabber, PINDIR_INPUT, 0, &pAudioMixInputPin);
g_DSHelper.SetAudioFilterBuffer(pAudioMixInputPin);
BREAK_IF_FAILED(hr);

CComPtr<IPin> pAudioMixOutputPin;
hr = g_DSHelper.GetPin(m_pBgmAudioGrabber, PINDIR_OUTPUT, 0, &pAudioMixOutputPin);
g_DSHelper.SetAudioFilterBuffer(pAudioMixOutputPin);

BREAK_IF_FAILED(hr);
        
hr = CoCreateInstance(CLSID_AsyncReader, NULL, CLSCTX_INPROC, IID_IBaseFilter, (void**)&m_pBGMAudioSrcFilter);
RETURN_IF_FAILED(hr, hr);
InfoLog(_T("Create BGM source filter CLSID_AsyncReader OK!"));

hr = CoCreateInstance(CLSID_WavParser, NULL, CLSCTX_INPROC, IID_IBaseFilter, (void**)&m_pWaveParserFilter);
RETURN_IF_FAILED(hr, hr)
InfoLog(_T("Create CLSID_WavParser OK!"));
hr = m_pGraph->AddFilter(m_pWaveParserFilter, L"Wav Parser");
RETURN_IF_FAILED(hr, hr)
InfoLog(_T("AddFilter CLSID_WavParser OK!"));
        
        
CComPtr<IFileSourceFilter> pSourceFilter;
hr = m_pBGMAudioSrcFilter->QueryInterface(IID_IFileSourceFilter, (void**)&pSourceFilter);
RETURN_IF_FAILED(hr, hr)
InfoLog(_T("QueryInterface IID_IFileSourceFilter OK!"));
        
HRESULT hr = pSourceFilter->Load(m_strBkgMusicPath,NULL );
        
RETURN_IF_FAILED(hr, hr)
InfoLog(_T("Load %s OK!"), m_strBkgMusicPath);

hr = m_pGraph->AddFilter(m_pBGMAudioSrcFilter, L"Async Source");
RETURN_IF_FAILED(hr, hr)
InfoLog(_T("AddFilter AsyncSource OK!"));

CComPtr<IPin> pWavParseInputPin;
hr = g_DSHelper.GetPin(m_pWaveParserFilter, PINDIR_INPUT, 0, &pWavParseInputPin);
g_DSHelper.SetAudioFilterBuffer(pWavParseInputPin);

RETURN_IF_FAILED(hr, hr)
        
CComPtr<IPin> pAudioBGMOutputPin;
        
hr = g_DSHelper.GetPin(m_pBGMAudioSrcFilter, PINDIR_OUTPUT, 0, &pAudioBGMOutputPin);
g_DSHelper.SetAudioFilterBuffer(pAudioBGMOutputPin);

RETURN_IF_FAILED(hr, hr)

hr = m_pGraph->ConnectDirect(pAudioBGMOutputPin, pWavParseInputPin, NULL);
RETURN_IF_FAILED(hr, hr)
InfoLog(_T("Connect of pBkgAudioPathOutputPin and pWavParseInputPin OK!"));

CComPtr<IPin> pWavParseOutputPin;
hr = g_DSHelper.GetPin(m_pWaveParserFilter, PINDIR_OUTPUT, 0, &pWavParseOutputPin);
g_DSHelper.SetAudioFilterBuffer(pWavParseOutputPin);
RETURN_IF_FAILED(hr, hr)

hr = m_BgmAudioRenderDevice.Create(m_strAudioRenderDeviceID);
RETURN_IF_FAILED(hr, hr);
        
hr = m_BgmAudioRenderDevice.SetAudioRenderFormat(g_RecordingConfig.AudioSamplePerSecond(), g_RecordingConfig.AudioBitsPerSample(), g_RecordingConfig.AudioChannels());
RETURN_IF_FAILED(hr, hr);
        
hr = m_pGraph->AddFilter(m_BgmAudioRenderDevice.GetBaseFilter(), L"BGM Audio Render");
RETURN_IF_FAILED(hr, hr);

CComPtr<IPin> pBgmRenderPin  = m_BgmAudioRenderDevice.GetInputPin();
hr = m_pGraph->ConnectDirect(pWavParseOutputPin, pAudioMixInputPin,NULL);
RETURN_IF_FAILED(hr, hr)
g_DSHelper.SetAudioFilterBuffer(pBgmRenderPin);
        

hr = m_pGraph->ConnectDirect(pAudioMixOutputPin, pBgmRenderPin,NULL);
RETURN_IF_FAILED(hr, hr)

if (m_pMC)
{
    hr = m_pMC->StopWhenReady();
    BREAK_IF_FAILED(hr)
}
djvg
  • 11,722
  • 5
  • 72
  • 103
tobin
  • 127
  • 2
  • 8

1 Answers1

1

... always received 44100 bytes data four times per seconds, I want to change the callback rate to 10 times per second...

You can't have this. When you set it to stream data in suitable format that fit your needs, it is your task from there to break the stream it pieces suitable for your processing.

When you are playing from file, the source filter is pushing the data at maximal rate and in chunks that make sense for reader, demultiplexer, decoder. You almost never, if ever at all, have flexibility over this process and - as opposed to live audio capture - you cannot request certain data granularity.

Just consume the data at this rate and split it into pieces necessary for your internal preocessing yourself, it is a relatively easy task.

Roman R.
  • 68,205
  • 6
  • 94
  • 158
  • Thank you for your help. Actually, my requirements are to process and play PCM in real time, but the fixed sample size will bring great delay. About 2.5s, I expect to reduce the size optimization delay of each sample, such as playing immediately when switching effect, rather than waiting for 2.5s。Audio data can load from both files and memory. It seems that I can't achieve this with DirectShow? Can I use DirectSound or something? I need to be compatible with Windows XP – tobin May 27 '21 at 02:17
  • Memfile of the Async Sample can do that? I need take 17640 byte PCM data to render every time(process and render 10 times per seconds), so that when I change the audio effect ,I just need to wait 1/10 second to hear the new effect, not 1/4 seconds latency. If DirectShow can't do this ,any other way? I need to be compatible with Windows XP – tobin May 27 '21 at 03:26