0

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

我正在使用 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);
4

1 回答 1

0

通道数与音量无关。T调节音量需要获取接口IAudioStreamVolumeIChannelAudioVolume。见MSDN 写道

IAudioStreamVolume 接口使客户端能够控制和监视音频流中所有通道的音量级别。客户端通过调用 IAudioClient::GetService 方法获取对流对象上 IAudioStreamVolume 接口的引用,并将参数 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;
}
于 2012-11-18T09:07:52.210 回答