IAudioClient::Initialize 方法 (audioclient.h)

Initialize 方法初始化音频流。

语法

HRESULT Initialize(
  [in] AUDCLNT_SHAREMODE  ShareMode,
  [in] DWORD              StreamFlags,
  [in] REFERENCE_TIME     hnsBufferDuration,
  [in] REFERENCE_TIME     hnsPeriodicity,
  [in] const WAVEFORMATEX *pFormat,
  [in] LPCGUID            AudioSessionGuid
);

参数

[in] ShareMode

连接的共享模式。 通过此参数,客户端告知音频引擎它是否要与其他客户端共享音频终结点设备。 客户端应将此参数设置为以下 AUDCLNT_SHAREMODE 枚举值之一:

AUDCLNT_SHAREMODE_EXCLUSIVE

AUDCLNT_SHAREMODE_SHARED

[in] StreamFlags

用于控制流的创建的标志。 客户端应将此参数设置为 0 或一个或多个 AUDCLNT_STREAMFLAGS_XXX常量AUDCLNT_SESSIONFLAGS_XXX常量的按位 OR。

[in] hnsBufferDuration

缓冲区容量作为时间值。 此参数 的类型REFERENCE_TIME ,以 100 纳秒为单位表示。 此参数包含调用方请求的缓冲区大小,音频应用程序将与音频引擎 (共享的缓冲区大小) 或终结点设备 (独占模式) 。 如果调用成功,方法将分配一个至少如此大的缓冲区。 有关 REFERENCE_TIME的详细信息,请参阅 Windows SDK 文档。 有关缓冲要求的详细信息,请参阅备注。

[in] hnsPeriodicity

设备周期。 此参数只能在独占模式下为非零。 在共享模式下,始终将此参数设置为 0。 在独占模式下,此参数指定音频终结点设备连续访问缓冲区的请求计划周期。 如果请求的设备周期超出了由设备的最小周期和系统的最大时间段设置的范围,则该方法将时间段固定到该范围。 如果此参数为 0,则 方法将设备周期设置为其默认值。 若要获取默认设备周期,请调用 IAudioClient::GetDevicePeriod 方法。 如果设置了AUDCLNT_STREAMFLAGS_EVENTCALLBACK流标志,并且AUDCLNT_SHAREMODE_EXCLUSIVE设置为 ShareMode,则 hnsPeriodicity 必须为非零且等于 hnsBufferDuration

[in] pFormat

指向格式描述符的指针。 此参数必须指向 WAVEFORMATEX (或 WAVEFORMATEXTENSIBLE) 类型的有效格式描述符。 有关详细信息,请参阅“备注”。

[in] AudioSessionGuid

指向会话 GUID 的指针。 此参数指向标识流所属的音频会话的 GUID 值。 如果 GUID 标识之前已打开的会话,则 方法会将流添加到该会话。 如果 GUID 未标识现有会话,则 方法将打开一个新会话,并将流添加到该会话。 流在其生存期内保持为同一会话的成员。 将此参数设置为 NULL 等效于将指针传递到GUID_NULL值。

返回值

如果该方法成功,则它会返回 S_OK。 如果失败,可能的返回代码包括但不限于下表中显示的值。

返回代码 说明
AUDCLNT_E_ALREADY_INITIALIZED
IAudioClient 对象已初始化。
AUDCLNT_E_WRONG_ENDPOINT_TYPE
已设置AUDCLNT_STREAMFLAGS_LOOPBACK标志,但终结点设备是捕获设备,而不是呈现设备。
AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED
注意 适用于 Windows 7 及更高版本。
 
请求的缓冲区大小未对齐。 如果指定的调用方AUDCLNT_SHAREMODE_EXCLUSIVE和AUDCLNT_STREAMFLAGS_EVENTCALLBACK标志,则可以为呈现器或捕获设备返回此代码。 调用方必须使用对齐的缓冲区大小再次调用 Initialize 。 有关详细信息,请参阅“备注”。
AUDCLNT_E_BUFFER_SIZE_ERROR
注意 适用于 Windows 7 及更高版本。
 
指示独占模式客户端请求的缓冲区持续时间值超出范围。 请求的拉取模式持续时间值不得大于 5000 毫秒;对于推送模式,持续时间值不得大于 2 秒。
AUDCLNT_E_CPUUSAGE_EXCEEDED
指示进程传递持续时间超过了最大 CPU 使用率。 音频引擎通过保持进程传递持续时间超过最大 CPU 使用率的次数来跟踪 CPU 使用率。 最大 CPU 使用率按引擎周期的百分比计算。 百分比值是系统 CPU 限制值 (在 10% 和 90% ) 范围内。 如果未找到此值,则使用默认值 40% 来计算最大 CPU 使用率。
AUDCLNT_E_DEVICE_INVALIDATED
音频终结点设备已拔出,或者音频硬件或关联的硬件资源已重新配置、禁用、删除或以其他方式不可用。
AUDCLNT_E_DEVICE_IN_USE
终结点设备已在使用中。 设备正在独占模式下使用,或者设备正在共享模式下使用,并且调用方要求在独占模式下使用设备。
AUDCLNT_E_ENDPOINT_CREATE_FAILED
方法未能为呈现器或捕获设备创建音频终结点。 如果音频终结点设备已拔下,或者音频硬件或关联的硬件资源已重新配置、禁用、删除或不可用,则可能会出现这种情况。
AUDCLNT_E_INVALID_DEVICE_PERIOD
注意 适用于 Windows 7 及更高版本。
 
指示独占模式客户端请求的设备周期大于 5000 毫秒。
AUDCLNT_E_UNSUPPORTED_FORMAT
音频引擎 (共享模式) 或音频终结点设备 (独占模式) 不支持指定格式。
AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED
调用方正在请求使用终结点设备的独占模式,但用户已禁用设备的独占模式使用。
AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL
已设置AUDCLNT_STREAMFLAGS_EVENTCALLBACK标志,但参数 hnsBufferDurationhnsPeriodicity 不相等。
AUDCLNT_E_SERVICE_NOT_RUNNING
Windows 音频服务未运行。
E_POINTER
参数 pFormatNULL
E_INVALIDARG
参数 pFormat 指向格式说明无效;或已设置AUDCLNT_STREAMFLAGS_LOOPBACK标志,但 ShareMode 不等于 AUDCLNT_SHAREMODE_SHARED;或 AUDCLNT_STREAMFLAGS_CROSSPROCESS 标志已设置,但 ShareMode 等于 AUDCLNT_SHAREMODE_EXCLUSIVE。

先前调用 SetClientProperties 时,音频/呈现流的类别无效。

E_OUTOFMEMORY
内存不足。

备注

在音频终结点设备上激活 IAudioClient 接口后,客户端必须成功调用 Initialize 一次,并且只能调用一次,以初始化客户端和设备之间的音频流。 客户端可以直接 (独占模式) 连接到音频硬件,也可以通过音频引擎 (共享模式) 间接连接。 在 Initialize 调用中,客户端指定流的音频数据格式、缓冲区大小和音频会话。

注意 在 Windows 8 中,首次使用 IAudioClient 访问音频设备应在 STA 线程上。 来自 MTA 线程的调用可能会导致未定义的行为。
 
仅当音频设备已在共享模式下运行或设备当前未使用时,尝试创建共享模式流才能成功。 如果设备已在独占模式下运行,则尝试创建共享模式流失败。

如果将流初始化为事件驱动且处于共享模式, 则 ShareMode 设置为 AUDCLNT_SHAREMODE_SHARED,并且设置的其中一个流标志包括AUDCLNT_STREAMFLAGS_EVENTCALLBACK。 对于此类流,关联的应用程序还必须通过调用 IAudioClient::SetEventHandle 来获取句柄。 当需要停用流时,音频引擎可以使用 句柄释放流对象。 在释放流对象之前未能调用 IAudioClient::SetEventHandle 可能会导致在音频引擎等待可用句柄) 超时 (延迟几秒钟。 超时期限到期后,音频引擎会释放流对象。

尝试创建独占模式流是否成功取决于多个因素,包括设备的可用性以及控制设备独占模式操作的用户控制设置。 有关详细信息,请参阅 独占模式流

IAudioClient 对象仅支持与音频引擎或音频硬件的一个连接。 此连接在 IAudioClient 对象的生存期内持续。

客户端应仅在调用 Initialize调用以下方法:

以下方法不要求先调用 Initialize 激活 IAudioClient 接口后,可以随时调用这些方法。

在调用 Initialize 以设置共享模式或独占模式连接之前,客户端可以调用 IAudioClient::IsFormatSupported 方法来发现音频引擎或音频终结点设备是否支持该模式下的特定格式。 在打开共享模式连接之前,客户端可以通过调用 IAudioClient::GetMixFormat 方法获取音频引擎的混合格式。

客户端与音频引擎之间共享的终结点缓冲区必须足够大,以防止客户端和音频引擎在处理传递之间的音频流中发生故障。 对于呈现终结点,客户端线程定期将数据写入缓冲区,音频引擎线程定期从缓冲区读取数据。 对于捕获终结点,引擎线程定期写入缓冲区,客户端线程定期从缓冲区读取数据。 在任一情况下,如果客户端线程和引擎线程的周期不相等,缓冲区必须足够大,以容纳两个时间段中的较长时间,而不会发生故障。

客户端通过 hnsBufferDuration 参数指定缓冲区大小。 客户端负责请求足够大的缓冲区,以确保在对缓冲区执行的定期处理传递之间不会发生故障。 同样, Initialize 方法可确保缓冲区永远不会小于所需的最小缓冲区大小,以确保引擎线程对缓冲区执行的定期处理传递之间不会出现故障。 如果客户端请求的缓冲区大小小于音频引擎的最小所需缓冲区大小,该方法会将缓冲区大小设置为此最小缓冲区大小,而不是客户端请求的缓冲区大小。

如果客户端通过 hnsBufferDuration 参数请求缓冲区大小 (,) 不是音频帧的整数数,该方法会将请求的缓冲区大小舍入到下一个整数数的帧数。

Initialize 调用之后,客户端应调用 IAudioClient::GetBufferSize 方法以获取终结点缓冲区的精确大小。 在每次处理过程中,客户端将需要实际缓冲区大小来计算要传入或传出缓冲区的数据量。 客户端调用 IAudioClient::GetCurrentPadding 方法来确定缓冲区中当前有多少数据可供处理。

若要在客户端应用程序与音频终结点设备之间实现最小流延迟,客户端线程应在与音频引擎线程相同的时间段运行。 引擎线程的周期是固定的,不能由客户端控制。 使客户端的周期小于引擎的周期会不必要地增加客户端线程在处理器上的负载,而不会改善延迟或减小缓冲区大小。 若要确定引擎线程的周期,客户端可以调用 IAudioClient::GetDevicePeriod 方法。 若要将缓冲区设置为引擎线程所需的最小大小,客户端应调用 Initialize ,并将 hnsBufferDuration 参数设置为 0。 在 Initialize 调用之后,客户端可以通过调用 IAudioClient::GetBufferSize 来获取生成的缓冲区的大小。

客户端可以选择请求的缓冲区大小大于使计时故障很少或不存在的绝对必要大小。 增加缓冲区大小不一定会增加流延迟。 对于呈现流,通过缓冲区的延迟完全取决于客户端的写入指针和引擎的读取指针之间的分离。 对于捕获流,通过缓冲区的延迟完全取决于引擎的写入指针和客户端的读取指针之间的分离。

环回标志 (AUDCLNT_STREAMFLAGS_LOOPBACK) 启用音频环回。 客户端只能在具有共享模式流的呈现终结点上启用音频环回。 音频环回主要用于支持 AEC) (回声消除。

AEC 客户端需要呈现终结点以及从音频引擎捕获输出流的功能。 引擎的输出流是音频设备通过扬声器播放的全局混合。 如果启用了音频环回,客户端可以通过调用 IAudioClient::GetService 方法来打开全局音频混合的捕获缓冲区,以获取呈现流对象上的 IAudioCaptureClient 接口。 如果未启用音频环回,则在呈现流上打开捕获缓冲区的尝试将失败。 捕获缓冲区中的环回数据采用设备格式,客户端可以通过查询设备的 PKEY_AudioEngine_DeviceFormat 属性来获取该格式。

在 Windows 10 之前的 Windows 版本中,使用事件驱动的缓冲 (AUDCLNT_STREAMFLAGS_EVENTCALLBACK) 初始化流并启用环回 (AUDCLNT_STREAMFLAGS_LOOPBACK) 时,拉取模式捕获客户端不会收到任何事件。 如果使用此配置打开流, 则 Initialize 调用会成功,但不会引发相关事件,以便在每次缓冲区准备好进行处理时通知捕获客户端。 若要解决此问题,请在事件驱动模式下初始化呈现流。 每次客户端收到呈现流的事件时,它都必须向捕获客户端发出信号,以运行从捕获终结点缓冲区读取下一组样本的捕获线程。 从Windows 10现在为处于活动状态的已启用环回的流设置相关的事件句柄。

请注意,必须在共享模式下打开所有流,因为独占模式流无法在环回模式下运行。 有关音频环回的详细信息,请参阅 环回录制

AUDCLNT_STREAMFLAGS_EVENTCALLBACK标志指示客户端对音频缓冲区的处理将由事件驱动。 WASAPI 支持事件驱动的缓冲,以实现共享模式流和独占模式流的低延迟处理。

Windows Vista 的初始版本支持事件驱动的缓冲 (即,AUDCLNT_STREAMFLAGS_EVENTCALLBACK标志) 仅用于呈现流。

在 Windows Vista 的初始版本中,对于捕获流,仅在共享模式下支持AUDCLNT_STREAMFLAGS_EVENTCALLBACK标志。 设置此标志对独占模式捕获流没有影响。 也就是说,尽管应用程序通过 Initialize 调用以独占模式指定此标志,但应用程序不会接收捕获音频流通常需要的任何事件。 在 Windows Vista Service Pack 1 版本中,此标志在共享模式和独占模式下正常运行;应用程序可以设置此标志,为捕获流启用事件缓冲。 有关捕获音频流的详细信息,请参阅 捕获流

若要启用事件驱动缓冲,客户端必须向系统提供事件句柄。 在 Initialize 调用之后,在调用 IAudioClient::Start 方法以启动流之前,客户端必须调用 IAudioClient::SetEventHandle 方法来设置事件句柄。 流运行时,系统会定期向事件发出信号,以向客户端指示音频数据可供处理。 在处理阶段之间,客户端线程通过调用 WaitForSingleObject 等同步函数来等待事件句柄。 有关同步函数的详细信息,请参阅 Windows SDK 文档。

对于使用事件驱动缓冲的共享模式流,调用方必须将 hnsPeriodicityhnsBufferDuration 设置为 0。 Initialize 方法根据音频引擎的计划周期确定要分配的缓冲区的大小。 尽管客户端的缓冲区处理线程由事件驱动,但如前所述,基本缓冲区管理进程是不变的。 每次线程唤醒时,它都应调用 IAudioClient::GetCurrentPadding ,以确定要写入呈现缓冲区或从捕获缓冲区读取的数据量。 与 Initialize 方法为使用事件驱动缓冲的独占模式流分配的两个缓冲区不同,共享模式流需要单个缓冲区。

对于使用事件驱动缓冲的独占模式流,调用方必须为 hnsPeriodicityhnsBufferDuration 指定非零值,并且这两个参数的值必须相等。 Initialize 方法为流分配两个缓冲区。 每个缓冲区的持续时间等于 hnsBufferDuration 参数的值。 在对呈现流进行 Initialize 调用之后,调用方应在启动流之前填充两个缓冲区中的第一个缓冲区。 对于捕获流,缓冲区最初为空,调用方应假定每个缓冲区保持为空,直到该缓冲区的事件收到信号。 在流运行时,系统交替向客户端发送一个或另一个缓冲区-这种形式的双重缓冲称为“ping-ponging”。 每次客户端从系统接收缓冲区 (系统通过向事件) 发出信号来指示缓冲区时,客户端必须处理整个缓冲区。 例如,如果客户端从 IAudioRenderClient::GetBuffer 方法请求与缓冲区大小不匹配的数据包大小,该方法将失败。 不需要调用 IAudioClient::GetCurrentPadding 方法,因为数据包大小必须始终等于缓冲区大小。 与前面讨论的缓冲模式不同,事件驱动的独占模式流的延迟直接取决于缓冲区大小。

音频会话中所述,包含呈现流的会话的默认行为是,其音量和静音设置在应用程序重启后保持不变。 AUDCLNT_STREAMFLAGS_NOPERSIST标志替代默认行为,并使设置不具有持久性。 此标志对包含捕获流的会话没有影响 , 这些会话的设置永远不会持久。 此外,包含环回流的会话 (使用AUDCLNT_STREAMFLAGS_LOOPBACK标志) 初始化的流的设置不是永久性的。

只有连接到呈现终结点设备的会话才能具有永久性卷和静音设置。 要添加到会话中的第一个流确定会话的设置是否是永久性的。 因此,如果在初始化第一个流期间设置了AUDCLNT_STREAMFLAGS_NOPERSIST或AUDCLNT_STREAMFLAGS_LOOPBACK标志,则会话的设置不是永久性的。 否则,它们是永久性的。 它们的持久性不受其他流影响,这些流随后可能会在会话对象的生存期内添加或删除。

在对 Initialize 的调用成功初始化 IAudioClient 接口实例后,用于初始化同一接口实例的后续 Initialize 调用将失败,并E_ALREADY_INITIALIZED返回错误代码。

如果初始调用 Initialize 失败,后续 的 Initialize 调用可能会失败,并且即使接口尚未初始化,也会E_ALREADY_INITIALIZED返回错误代码。 如果发生这种情况,请释放 IAudioClient 接口并从 MMDevice API 获取新的 IAudioClient 接口,然后再再次调用 Initialize

有关调用 Initialize 方法的代码示例,请参阅以下主题:

从 Windows 7 开始, Initialize 可以返回呈现或捕获设备的AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED。 这表示由 hnsBufferDuration 参数中的调用方指定的缓冲区大小未对齐。 仅当调用方请求独占模式流 (AUDCLNT_SHAREMODE_EXCLUSIVE) 和事件驱动的缓冲 (AUDCLNT_STREAMFLAGS_EVENTCALLBACK) 时,才会返回此错误代码。

如果 Initialize 返回AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED,则调用方必须再次调用 Initialize 并指定对齐的缓冲区大小。 请使用以下步骤:

  1. 调用 IAudioClient::GetBufferSize 并接收下一个最高对齐的缓冲区大小 (帧) 。
  2. 调用 IAudioClient::Release 以释放在返回AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED的上一次调用中使用的音频客户端。
  3. 以 100 纳秒为单位计算对齐的缓冲区大小, (hns) 。 缓冲区大小为 (REFERENCE_TIME)((10000.0 * 1000 / WAVEFORMATEX.nSamplesPerSecond * nFrames) + 0.5)。 在此公式中, nFramesGetBufferSize 检索的缓冲区大小。
  4. 调用参数 iid 设置为 REFIID 的 IMMDevice::Activate 方法IID_IAudioClient创建新的音频客户端。
  5. 在创建的音频客户端上再次调用 Initialize ,并指定新的缓冲区大小和周期。

从Windows 10开始,硬件卸载的音频流必须是事件驱动的。 这意味着,如果调用 IAudioClient2::SetClientProperties 并将 AudioClientPropertiesbIsOffload 参数设置为 TRUE,则必须将 StreamFlags 参数中的 AUDCLNT_STREAMFLAGS_EVENTCALLBACK 标志指定为 IAudioClient::Initialize

示例

以下示例代码演示如何响应 AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED 返回代码。

#define REFTIMES_PER_SEC  10000000

HRESULT CreateAudioClient(IMMDevice* pDevice, IAudioClient** ppAudioClient)
{
    if (!pDevice)
    {
        return E_INVALIDARG;
    }

    if (!ppAudioClient)
    {
        return E_POINTER;
    }

    HRESULT hr = S_OK;
    
    WAVEFORMATEX *pwfx = NULL;

    REFERENCE_TIME hnsRequestedDuration = REFTIMES_PER_SEC;

    UINT32 nFrames = 0;

    IAudioClient *pAudioClient = NULL;

    // Get the audio client.
    CHECK_HR( hr = pDevice->Activate(
        __uuidof(IAudioClient), 
        CLSCTX_ALL,
        NULL, 
        (void**)&pAudioClient));

    // Get the device format.
    CHECK_HR( hr = pAudioClient->GetMixFormat(&pwfx));

    // Open the stream and associate it with an audio session.
    hr = pAudioClient->Initialize( 
        AUDCLNT_SHAREMODE_EXCLUSIVE,
        AUDCLNT_STREAMFLAGS_EVENTCALLBACK, 
        hnsRequestedDuration, 
        hnsRequestedDuration, 
        pwfx, 
        NULL);

    // If the requested buffer size is not aligned...
    if (hr == AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED)
    {	
        // Get the next aligned frame.
        CHECK_HR( hr = pAudioClient->GetBufferSize(&nFrames));
        
        hnsRequestedDuration = (REFERENCE_TIME)
        ((10000.0 * 1000 / pwfx->nSamplesPerSec * nFrames) + 0.5);

        // Release the previous allocations.
        SAFE_RELEASE(pAudioClient);
        CoTaskMemFree(pwfx);
        
        // Create a new audio client.
        CHECK_HR( hr = pDevice->Activate(
            __uuidof(IAudioClient), 
            CLSCTX_ALL,
            NULL, 
            (void**)&pAudioClient));
    
        // Get the device format.
        CHECK_HR( hr = pAudioClient->GetMixFormat(&pwfx));
        
        // Open the stream and associate it with an audio session.
        CHECK_HR( hr = pAudioClient->Initialize( 
            AUDCLNT_SHAREMODE_EXCLUSIVE,
            AUDCLNT_STREAMFLAGS_EVENTCALLBACK, 
            hnsRequestedDuration, 
            hnsRequestedDuration, 
            pwfx, 
            NULL));
    }
    else
    {
        CHECK_HR (hr);
    }
    
    // Return to the caller.
    *(ppAudioClient) = pAudioClient;
    (*ppAudioClient)->AddRef();

done:

    // Clean up.
    CoTaskMemFree(pwfx);
    SAFE_RELEASE(pAudioClient);
    return hr;
}

要求

   
目标平台 Windows
标头 audioclient.h

另请参阅

IAudioCaptureClient 接口

IAudioClient 接口

IAudioClient::GetBufferSize

IAudioClient::GetCurrentPadding

IAudioClient::GetDevicePeriod

IAudioClient::GetMixFormat

IAudioClient::GetService

IAudioClient::SetEventHandle

IAudioClient::Start

IAudioRenderClient::GetBuffer