使用Media Foundation为多个流设置卷

时间:2012-11-18 04:47:37

标签: windows visual-c++ audio ms-media-foundation

我正在为一个应用程序提供音频代码,该应用程序将同时播放多个音频流。我对所有不同的选项感到有点困惑,有些具体的事情我不太明白。

我正在使用IAudioClient调用来获取和设置卷。这是获取多个流的卷的最佳方法吗?

看来我必须调用IAudioClient :: Initialize。此功能需要WAVEFORMATEX结构。是否有除音量设置中使用的通道数以外的参数?此外,似乎Initialize只能使用一次,并且音量设置和读取会多次发生。我应该保存对IAudioClient的引用并每次都使用它,还是每次获取或设置卷时都可以释放它?

如何区分在同一设备(端点)上播放的两个流?

这是设置音量的代码(通常检查以确保每次调用成功消除以节省空间):

hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&DeviceEnumerator));
hr = DeviceEnumerator->GetDevice((wchar_t *)currentPlaybackDevice.id, &pPlaybackDevice);
hr = pPlaybackDevice->Activate(__uuidof(IAudioClient), CLSCTX_INPROC_SERVER, NULL, reinterpret_cast<void **>(&pPlaybackClient));
hr = pPlaybackClient->Initialize(AUDCLNT_SHAREMODE_SHARED, 0, 0, 0, &pWaveFormat, 0);
hr = pPlaybackClient->GetService(__uuidof(IAudioStreamVolume), (void **)&pStreamVolume);
hr = pStreamVolume->GetChannelCount(&channels);
for(UINT32 i = 0; i < channels; i++)
     chanVolumes[i] = playbackLevel;
hr = pStreamVolume->SetAllVolumes(channels, chanVolumes);

1 个答案:

答案 0 :(得分:0)

频道数与音量无关。 T调整获取接口IAudioStreamVolumeIChannelAudioVolume所需的音量。见MSDN writes

  

IAudioStreamVolume接口使客户端能够控制和   监听音频流中所有频道的音量级别。   客户端获取对IAudioStreamVolume接口的引用   通过使用调用IAudioClient :: GetService方法的流对象   参数riid设置为REFIID IID_IAudioStreamVolume。

以下是适合您的代码段。它以更大的音量播放合成的正弦波几秒钟,然后继续更新音量以保持静音播放。

#define _USE_MATH_DEFINES
#include <math.h>
#include <mmdeviceapi.h>
#include <audioclient.h>

#define _A  ATLASSERT
#define __C ATLENSURE_SUCCEEDED
#define __D ATLENSURE_THROW

int _tmain(int argc, _TCHAR* argv[])
{
    __C(CoInitialize(NULL));
    CComPtr<IMMDeviceEnumerator> pMmDeviceEnumerator;
    __C(pMmDeviceEnumerator.CoCreateInstance(__uuidof(MMDeviceEnumerator)));
    CComPtr<IMMDevice> pMmDevice;
    __C(pMmDeviceEnumerator->GetDefaultAudioEndpoint(eRender, eMultimedia, &pMmDevice));
    CComPtr<IAudioClient> pAudioClient;
    __C(pMmDevice->Activate(__uuidof(IAudioClient), CLSCTX_ALL, NULL, (VOID**) &pAudioClient));
    CComHeapPtr<WAVEFORMATEX> pWaveFormatEx;
    __C(pAudioClient->GetMixFormat(&pWaveFormatEx));
    static const REFERENCE_TIME g_nBufferTime = 60 * 1000 * 10000i64; // 1 minute
    __C(pAudioClient->Initialize(AUDCLNT_SHAREMODE_SHARED, 0, g_nBufferTime, 0, pWaveFormatEx, NULL));
    #pragma region Data
    CComPtr<IAudioRenderClient> pAudioRenderClient;
    __C(pAudioClient->GetService(__uuidof(IAudioRenderClient), (VOID**) &pAudioRenderClient));
    UINT32 nSampleCount = (UINT32) (g_nBufferTime / (1000 * 10000i64) * pWaveFormatEx->nSamplesPerSec) / 2;
    _A(pWaveFormatEx->wFormatTag == WAVE_FORMAT_EXTENSIBLE);
    const WAVEFORMATEXTENSIBLE* pWaveFormatExtensible = (const WAVEFORMATEXTENSIBLE*) (const WAVEFORMATEX*) pWaveFormatEx;
    _A(pWaveFormatExtensible->SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT);
    // ASSU: Mixing format is IEEE Float PCM
    BYTE* pnData = NULL;
    __C(pAudioRenderClient->GetBuffer(nSampleCount, &pnData));
    FLOAT* pfFloatData = (FLOAT*) pnData;
    for(UINT32 nSampleIndex = 0; nSampleIndex < nSampleCount; nSampleIndex++)
        for(WORD nChannelIndex = 0; nChannelIndex < pWaveFormatEx->nChannels; nChannelIndex++)
            pfFloatData[nSampleIndex * pWaveFormatEx->nChannels + nChannelIndex] = sin(1000.0f * nSampleIndex / pWaveFormatEx->nSamplesPerSec * 2 * M_PI);
    __C(pAudioRenderClient->ReleaseBuffer(nSampleCount, 0));
    #pragma endregion
    CComPtr<ISimpleAudioVolume> pSimpleAudioVolume;
    __C(pAudioClient->GetService(__uuidof(ISimpleAudioVolume), (VOID**) &pSimpleAudioVolume));
    __C(pSimpleAudioVolume->SetMasterVolume(0.50f, NULL));
    _tprintf(_T("Playing Loud\n"));
    __C(pAudioClient->Start());
    Sleep(5 * 1000);
    _tprintf(_T("Playing Quiet\n"));
    __C(pSimpleAudioVolume->SetMasterVolume(0.10f, NULL));
    Sleep(15 * 1000);
    // NOTE: We don't care for termination crash
    return 0;
}