流式处理音频呈现器

(SAR) 流式音频呈现器是用于呈现音频的媒体接收器。 SAR 的每个实例都呈现一个音频流。 若要呈现多个流,请使用 SAR 的多个实例。

若要创建 SAR,请调用以下函数之一:

如果要播放受保护的内容,则需要返回激活对象的第二个函数,因为激活对象必须序列化到受保护的进程。 对于清晰的内容,可以使用任一函数。

SAR 可以接收 PCM 或 IEEE 浮点格式的未压缩音频。 如果播放速率快于 1×,SAR 会自动调整音调。

配置音频呈现器

SAR 支持多个配置属性。 设置这些属性的机制取决于调用哪个函数来创建 SAR。 如果使用 MFCreateAudioRenderer 函数,请执行以下操作:

  1. 通过调用 MFCreateAttributes 创建新的属性存储。
  2. 将属性添加到属性存储。
  3. 将属性存储传递到 pAudioAttributes 参数中的 MFCreateAudioRenderer 函数。

如果使用 MFCreateAudioRendererActivate 函数,该函数将返回指向 ppActivate 参数中的 IMFAttributes 接口的指针。 使用此指针添加属性。

有关配置属性的列表,请参阅 音频呈现器属性

选择音频终结点设备

音频终结点设备是呈现或捕获音频的硬件设备。 示例包括扬声器、耳机、麦克风和 CD 播放器。 SAR 始终使用音频呈现设备。 可通过两种方式选择设备。

第一种方法是使用 IMMDeviceEnumerator 接口枚举系统上的音频呈现设备。 此接口记录在核心音频 API 文档中。

  1. 创建设备枚举器对象。
  2. 使用设备枚举器枚举音频呈现设备。 每个设备都由指向 IMMDevice 接口的指针表示。
  3. 根据设备属性或用户选择选择设备。
  4. 调用 IMMDevice::GetId 获取设备标识符。
  5. 将设备标识符设置为 MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ID 属性的值。

可以按音频设备 的角色指定音频设备,而不是枚举设备。 音频角色标识一般使用类别。 例如, 主机 角色是为游戏和系统通知定义的,而 多媒体 角色是为音乐和电影定义的。 每个角色分配有一个音频呈现设备,用户可以更改这些分配。 如果指定设备角色,SAR 将使用为该角色分配的任何音频设备。 若要指定设备角色,请设置 MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ROLE 属性。

本节中列出的两个属性互斥。 如果未设置其中任一项,SAR 将使用分配给 eConsole 角色的音频设备。

以下代码枚举音频呈现设备,并将列表中的第一个设备分配给 SAR。 此示例使用 MFCreateAudioRenderer 函数创建 SAR。

#include <mmdeviceapi.h>

HRESULT hr = S_OK;

IMMDeviceEnumerator *pEnum = NULL;      // Audio device enumerator.
IMMDeviceCollection *pDevices = NULL;   // Audio device collection.
IMMDevice *pDevice = NULL;              // An audio device.
IMFAttributes *pAttributes = NULL;      // Attribute store.
IMFMediaSink *pSink = NULL;             // Streaming audio renderer (SAR)

LPWSTR wstrID = NULL;                   // Device ID.

// Create the device enumerator.
hr = CoCreateInstance(
    __uuidof(MMDeviceEnumerator), 
    NULL,
    CLSCTX_ALL, 
    __uuidof(IMMDeviceEnumerator), 
    (void**)&pEnum
    );

// Enumerate the rendering devices.
if (SUCCEEDED(hr))
{
    hr = pEnum->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &pDevices);
}

// Get ID of the first device in the list.
if (SUCCEEDED(hr))
{
    hr = pDevices->Item(0, &pDevice);
}

if (SUCCEEDED(hr))
{
    hr = pDevice->GetId(&wstrID);
}

// Create an attribute store and set the device ID attribute.
if (SUCCEEDED(hr))
{
    hr = MFCreateAttributes(&pAttributes, 2);
}

if (SUCCEEDED(hr))
{
    hr = pAttributes->SetString(
        MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ID, 
        wstrID
        );
}

// Create the audio renderer.
if (SUCCEEDED(hr))
{
    hr = MFCreateAudioRenderer(pAttributes, &pSink);    
}

SAFE_RELEASE(pEnum);
SAFE_RELEASE(pDevices);
SAFE_RELEASE(pDevice); 
SAFE_RELEASE(pAttributes);
CoTaskMemFree(wstrID);

若要为 SAR 创建激活对象,请将调用 IMMDevice::GetId 后显示的代码更改为以下内容:

IMFActivate *pActivate = NULL;          // Activation object.

if (SUCCEEDED(hr))
{
    hr = MFCreateAudioRendererActivate(&pActivate);    
}

if (SUCCEEDED(hr))
{
    hr = pActivate->SetString(
        MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ID, 
        wstrID
        );
}

SAFE_RELEASE(pActivate);

选择音频会话

音频会话是应用程序可以共同管理的一组相关音频流。 应用程序可以控制每个会话的音量级别和静音状态。 会话由 GUID 标识。 若要指定 SAR 的音频会话,请使用 MF_AUDIO_RENDERER_ATTRIBUTE_SESSION_ID 属性。 如果未设置此属性,则 SAR 会加入该进程的默认会话(由 GUID_NULL 标识)。

默认情况下,音频会话特定于进程,这意味着它仅包含来自调用进程的流。 若要加入跨进程会话,请使用值 MF_AUDIO_RENDERER_ATTRIBUTE_FLAGS_CROSSPROCESS 设置 MF_AUDIO_RENDERER_ATTRIBUTE_FLAGS 属性。

创建 SAR 后,使用 IMFAudioPolicy 接口将会话加入到一组会话,所有这些会话都由控制面板中的同一个音量控件控制。 还可以使用此接口来设置显示在音量控件中的显示名称和图标。

控制卷级别

若要控制 SAR 音频会话中所有流的主音量级别,请使用 IMFSimpleAudioVolume 接口。 若要控制单个流的音量,或控制流中单个通道的音量,请使用 IMFAudioStreamVolume 接口。 这两个接口都是通过调用 IMFGetService::GetService 获取的。 可以直接在 SAR 上调用 GetService ,也可以在媒体会话上调用它。 音量级别表示为衰减值。 对于每个通道,衰减级别是主音量和通道音量的乘积。

音频/视频播放