Commit 75789dc7 authored by henrika's avatar henrika Committed by Commit Bot

Improves media::CoreAudioUtil::GetPreferredAudioParameters.

This CL is an attempt to reduce risk of crashes in GetPreferredAudioParameters
which lately has added support for IAudioClient3.

Adds version check and an improved usage of ComPtr::As.

Bug: 898789
Change-Id: I3e8e58543cfd5d4d5029aa90668119acb411a867
Reviewed-on: https://chromium-review.googlesource.com/c/1312949Reviewed-by: default avatarOskar Sundbom <ossu@chromium.org>
Commit-Queue: Henrik Andreasson <henrika@chromium.org>
Cr-Commit-Position: refs/heads/master@{#605318}
parent 4a3be25d
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include "base/win/scoped_handle.h" #include "base/win/scoped_handle.h"
#include "base/win/scoped_propvariant.h" #include "base/win/scoped_propvariant.h"
#include "base/win/scoped_variant.h" #include "base/win/scoped_variant.h"
#include "base/win/windows_version.h"
#include "media/audio/audio_device_description.h" #include "media/audio/audio_device_description.h"
#include "media/base/media_switches.h" #include "media/base/media_switches.h"
...@@ -183,6 +184,10 @@ ChannelConfig ChannelLayoutToChannelConfig(ChannelLayout layout) { ...@@ -183,6 +184,10 @@ ChannelConfig ChannelLayoutToChannelConfig(ChannelLayout layout) {
} }
} }
bool IAudioClient3IsSupported() {
return CoreAudioUtil::GetIAudioClientVersion() >= 3;
}
std::string GetDeviceID(IMMDevice* device) { std::string GetDeviceID(IMMDevice* device) {
ScopedCoMem<WCHAR> device_id_com; ScopedCoMem<WCHAR> device_id_com;
std::string device_id; std::string device_id;
...@@ -367,6 +372,21 @@ ComPtr<IAudioClient> CreateClientInternal(IMMDevice* audio_device, ...@@ -367,6 +372,21 @@ ComPtr<IAudioClient> CreateClientInternal(IMMDevice* audio_device,
return audio_client; return audio_client;
} }
// Creates and activates an IAudioClient3 COM object given the selected
// endpoint device.
ComPtr<IAudioClient3> CreateClientInternal3(IMMDevice* audio_device,
const UMALogCallback& uma_log_cb) {
if (!audio_device)
return ComPtr<IAudioClient3>();
ComPtr<IAudioClient3> audio_client;
HRESULT hr = audio_device->Activate(
__uuidof(IAudioClient3), CLSCTX_INPROC_SERVER, NULL, &audio_client);
DVLOG_IF(1, FAILED(hr)) << "IMMDevice::Activate: " << std::hex << hr;
uma_log_cb.Run(UmaLogStep::CREATE_CLIENT, hr);
return audio_client;
}
HRESULT GetPreferredAudioParametersInternal(IAudioClient* client, HRESULT GetPreferredAudioParametersInternal(IAudioClient* client,
bool is_output_device, bool is_output_device,
AudioParameters* params, AudioParameters* params,
...@@ -378,19 +398,25 @@ HRESULT GetPreferredAudioParametersInternal(IAudioClient* client, ...@@ -378,19 +398,25 @@ HRESULT GetPreferredAudioParametersInternal(IAudioClient* client,
return hr; return hr;
// Preferred sample rate. // Preferred sample rate.
int sample_rate = mix_format.Format.nSamplesPerSec; const int sample_rate = mix_format.Format.nSamplesPerSec;
int min_frames_per_buffer = 0; int min_frames_per_buffer = 0;
int max_frames_per_buffer = 0; int max_frames_per_buffer = 0;
int frames_per_buffer; int frames_per_buffer = 0;
const bool supports_iac3 = IAudioClient3IsSupported();
if (supports_iac3) {
// Try to obtain an IAudioClient3 interface from the IAudioClient object.
// Use ComPtr::As for doing QueryInterface calls on COM objects.
ComPtr<IAudioClient> audio_client(client);
ComPtr<IAudioClient3> audio_client_3; ComPtr<IAudioClient3> audio_client_3;
hr = client->QueryInterface(audio_client_3.GetAddressOf()); hr = audio_client.As(&audio_client_3);
if (SUCCEEDED(hr)) { if (SUCCEEDED(hr)) {
UINT32 default_period_frames; UINT32 default_period_frames = 0;
UINT32 fundamental_period_frames; UINT32 fundamental_period_frames = 0;
UINT32 min_period_frames; UINT32 min_period_frames = 0;
UINT32 max_period_frames; UINT32 max_period_frames = 0;
hr = audio_client_3->GetSharedModeEnginePeriod( hr = audio_client_3->GetSharedModeEnginePeriod(
&(mix_format.Format), &default_period_frames, &(mix_format.Format), &default_period_frames,
&fundamental_period_frames, &min_period_frames, &max_period_frames); &fundamental_period_frames, &min_period_frames, &max_period_frames);
...@@ -401,11 +427,14 @@ HRESULT GetPreferredAudioParametersInternal(IAudioClient* client, ...@@ -401,11 +427,14 @@ HRESULT GetPreferredAudioParametersInternal(IAudioClient* client,
max_frames_per_buffer = max_period_frames; max_frames_per_buffer = max_period_frames;
frames_per_buffer = default_period_frames; frames_per_buffer = default_period_frames;
} }
DVLOG(1) << "IAudioClient3 => min_period_frames: " << min_period_frames;
DVLOG(1) << "IAudioClient3 => frames_per_buffer: " << frames_per_buffer;
}
} }
// If we don't have access to IAudioClient3 or if the call to // If we don't have access to IAudioClient3 or if the call to
// GetSharedModeEnginePeriod() fails we fall back to GetDevicePeriod(). // GetSharedModeEnginePeriod() fails we fall back to GetDevicePeriod().
if (FAILED(hr)) { if (!supports_iac3 || FAILED(hr)) {
REFERENCE_TIME default_period = 0; REFERENCE_TIME default_period = 0;
hr = CoreAudioUtil::GetDevicePeriod(client, AUDCLNT_SHAREMODE_SHARED, hr = CoreAudioUtil::GetDevicePeriod(client, AUDCLNT_SHAREMODE_SHARED,
&default_period); &default_period);
...@@ -416,11 +445,11 @@ HRESULT GetPreferredAudioParametersInternal(IAudioClient* client, ...@@ -416,11 +445,11 @@ HRESULT GetPreferredAudioParametersInternal(IAudioClient* client,
// We are using the native device period to derive the smallest possible // We are using the native device period to derive the smallest possible
// buffer size in shared mode. Note that the actual endpoint buffer will be // buffer size in shared mode. Note that the actual endpoint buffer will be
// larger than this size but it will be possible to fill it up in two calls. // larger than this size but it will be possible to fill it up in two calls.
// TODO(henrika): ensure that this scheme works for capturing as well.
frames_per_buffer = static_cast<int>( frames_per_buffer = static_cast<int>(
sample_rate * CoreAudioUtil::ReferenceTimeToTimeDelta(default_period) sample_rate * CoreAudioUtil::ReferenceTimeToTimeDelta(default_period)
.InSecondsF() + .InSecondsF() +
0.5); 0.5);
DVLOG(1) << "IAudioClient => frames_per_buffer: " << frames_per_buffer;
} }
ChannelLayout channel_layout = GetChannelLayout(mix_format); ChannelLayout channel_layout = GetChannelLayout(mix_format);
...@@ -484,6 +513,19 @@ base::TimeDelta CoreAudioUtil::ReferenceTimeToTimeDelta(REFERENCE_TIME time) { ...@@ -484,6 +513,19 @@ base::TimeDelta CoreAudioUtil::ReferenceTimeToTimeDelta(REFERENCE_TIME time) {
return base::TimeDelta::FromMicroseconds(0.1 * time + 0.5); return base::TimeDelta::FromMicroseconds(0.1 * time + 0.5);
} }
uint32_t CoreAudioUtil::GetIAudioClientVersion() {
if (base::win::GetVersion() >= base::win::VERSION_WIN10) {
// Minimum supported client: Windows 10.
// Minimum supported server: Windows Server 2016
return 3;
} else if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
// Minimum supported client: Windows 8.
// Minimum supported server: Windows Server 2012.
return 2;
}
return 1;
}
AUDCLNT_SHAREMODE CoreAudioUtil::GetShareMode() { AUDCLNT_SHAREMODE CoreAudioUtil::GetShareMode() {
const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
if (cmd_line->HasSwitch(switches::kEnableExclusiveAudio)) if (cmd_line->HasSwitch(switches::kEnableExclusiveAudio))
...@@ -702,14 +744,20 @@ ComPtr<IAudioClient> CoreAudioUtil::CreateClient(const std::string& device_id, ...@@ -702,14 +744,20 @@ ComPtr<IAudioClient> CoreAudioUtil::CreateClient(const std::string& device_id,
EDataFlow data_flow, EDataFlow data_flow,
ERole role) { ERole role) {
ComPtr<IMMDevice> device(CreateDevice(device_id, data_flow, role)); ComPtr<IMMDevice> device(CreateDevice(device_id, data_flow, role));
return CreateClientInternal(device.Get(), return CreateClientInternal(device.Get(),
base::BindRepeating(&LogUMAEmptyCb)); base::BindRepeating(&LogUMAEmptyCb));
} }
ComPtr<IAudioClient3> CoreAudioUtil::CreateClient3(const std::string& device_id,
EDataFlow data_flow,
ERole role) {
ComPtr<IMMDevice> device(CreateDevice(device_id, data_flow, role));
return CreateClientInternal3(device.Get(),
base::BindRepeating(&LogUMAEmptyCb));
}
HRESULT CoreAudioUtil::GetSharedModeMixFormat( HRESULT CoreAudioUtil::GetSharedModeMixFormat(
IAudioClient* client, WAVEFORMATPCMEX* format) { IAudioClient* client, WAVEFORMATPCMEX* format) {
VLOG(1) << __FUNCTION__;
ScopedCoMem<WAVEFORMATPCMEX> format_pcmex; ScopedCoMem<WAVEFORMATPCMEX> format_pcmex;
HRESULT hr = client->GetMixFormat( HRESULT hr = client->GetMixFormat(
reinterpret_cast<WAVEFORMATEX**>(&format_pcmex)); reinterpret_cast<WAVEFORMATEX**>(&format_pcmex));
...@@ -814,7 +862,6 @@ HRESULT CoreAudioUtil::GetDevicePeriod(IAudioClient* client, ...@@ -814,7 +862,6 @@ HRESULT CoreAudioUtil::GetDevicePeriod(IAudioClient* client,
HRESULT CoreAudioUtil::GetPreferredAudioParameters(const std::string& device_id, HRESULT CoreAudioUtil::GetPreferredAudioParameters(const std::string& device_id,
bool is_output_device, bool is_output_device,
AudioParameters* params) { AudioParameters* params) {
DVLOG(1) << __FUNCTION__;
UMALogCallback uma_log_cb( UMALogCallback uma_log_cb(
is_output_device ? base::BindRepeating(&LogUMAPreferredOutputParams) is_output_device ? base::BindRepeating(&LogUMAPreferredOutputParams)
: base::BindRepeating(&LogUMAEmptyCb)); : base::BindRepeating(&LogUMAEmptyCb));
...@@ -883,16 +930,21 @@ HRESULT CoreAudioUtil::SharedModeInitialize(IAudioClient* client, ...@@ -883,16 +930,21 @@ HRESULT CoreAudioUtil::SharedModeInitialize(IAudioClient* client,
stream_flags |= AUDCLNT_STREAMFLAGS_EVENTCALLBACK; stream_flags |= AUDCLNT_STREAMFLAGS_EVENTCALLBACK;
DVLOG(2) << "stream_flags: 0x" << std::hex << stream_flags; DVLOG(2) << "stream_flags: 0x" << std::hex << stream_flags;
const bool supports_iac3 = IAudioClient3IsSupported();
HRESULT hr; HRESULT hr;
if (requested_buffer_size > 0) { if (supports_iac3 && requested_buffer_size > 0) {
// Try to obtain an IAudioClient3 interface from the IAudioClient object.
// Use ComPtr::As for doing QueryInterface calls on COM objects.
ComPtr<IAudioClient> audio_client(client);
ComPtr<IAudioClient3> audio_client_3; ComPtr<IAudioClient3> audio_client_3;
hr = client->QueryInterface(audio_client_3.GetAddressOf()); hr = audio_client.As(&audio_client_3);
if (FAILED(hr)) { if (FAILED(hr)) {
DVLOG(1) << "Failed to QueryInterface on IAudioClient3 with explicit " DVLOG(1) << "Failed to obtain IAudioClient3 interface: " << std::hex
"buffer size: " << hr;
<< std::hex << hr;
return hr; return hr;
} }
// Initialize a low-latency client using IAudioClient3.
hr = audio_client_3->InitializeSharedAudioStream( hr = audio_client_3->InitializeSharedAudioStream(
stream_flags, requested_buffer_size, &(format->Format), session_guid); stream_flags, requested_buffer_size, &(format->Format), session_guid);
if (FAILED(hr)) { if (FAILED(hr)) {
......
...@@ -47,6 +47,10 @@ class MEDIA_EXPORT CoreAudioUtil { ...@@ -47,6 +47,10 @@ class MEDIA_EXPORT CoreAudioUtil {
// Example: double s = RefererenceTimeToTimeDelta(t).InMillisecondsF(); // Example: double s = RefererenceTimeToTimeDelta(t).InMillisecondsF();
static base::TimeDelta ReferenceTimeToTimeDelta(REFERENCE_TIME time); static base::TimeDelta ReferenceTimeToTimeDelta(REFERENCE_TIME time);
// Returns 1, 2, or 3 corresponding to the highest version of IAudioClient
// the platform supports.
static uint32_t GetIAudioClientVersion();
// Returns AUDCLNT_SHAREMODE_EXCLUSIVE if --enable-exclusive-mode is used // Returns AUDCLNT_SHAREMODE_EXCLUSIVE if --enable-exclusive-mode is used
// as command-line flag and AUDCLNT_SHAREMODE_SHARED otherwise (default). // as command-line flag and AUDCLNT_SHAREMODE_SHARED otherwise (default).
static AUDCLNT_SHAREMODE GetShareMode(); static AUDCLNT_SHAREMODE GetShareMode();
...@@ -113,10 +117,12 @@ class MEDIA_EXPORT CoreAudioUtil { ...@@ -113,10 +117,12 @@ class MEDIA_EXPORT CoreAudioUtil {
// manage the flow of audio data between the application and an audio endpoint // manage the flow of audio data between the application and an audio endpoint
// device. // device.
// Create an IAudioClient instance for a specific device _or_ the default // Create an IAudioClient instance for a specific device or the default
// device if AudioDeviceDescription::IsDefaultDevice(device_id). // device if AudioDeviceDescription::IsDefaultDevice(device_id).
static Microsoft::WRL::ComPtr<IAudioClient> static Microsoft::WRL::ComPtr<IAudioClient>
CreateClient(const std::string& device_id, EDataFlow data_flow, ERole role); CreateClient(const std::string& device_id, EDataFlow data_flow, ERole role);
static Microsoft::WRL::ComPtr<IAudioClient3>
CreateClient3(const std::string& device_id, EDataFlow data_flow, ERole role);
// Get the mix format that the audio engine uses internally for processing // Get the mix format that the audio engine uses internally for processing
// of shared-mode streams. This format is not necessarily a format that the // of shared-mode streams. This format is not necessarily a format that the
...@@ -190,8 +196,6 @@ class MEDIA_EXPORT CoreAudioUtil { ...@@ -190,8 +196,6 @@ class MEDIA_EXPORT CoreAudioUtil {
uint32_t* endpoint_buffer_size, uint32_t* endpoint_buffer_size,
const GUID* session_guid); const GUID* session_guid);
// TODO(henrika): add ExclusiveModeInitialize(...)
// Create an IAudioRenderClient client for an existing IAudioClient given by // Create an IAudioRenderClient client for an existing IAudioClient given by
// |client|. The IAudioRenderClient interface enables a client to write // |client|. The IAudioRenderClient interface enables a client to write
// output data to a rendering endpoint buffer. // output data to a rendering endpoint buffer.
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <stdint.h> #include <stdint.h>
#include "base/macros.h" #include "base/macros.h"
#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "base/synchronization/waitable_event.h" #include "base/synchronization/waitable_event.h"
#include "base/test/metrics/histogram_tester.h" #include "base/test/metrics/histogram_tester.h"
...@@ -43,6 +44,12 @@ class CoreAudioUtilWinTest : public ::testing::Test { ...@@ -43,6 +44,12 @@ class CoreAudioUtilWinTest : public ::testing::Test {
ScopedCOMInitializer com_init_; ScopedCOMInitializer com_init_;
}; };
TEST_F(CoreAudioUtilWinTest, GetIAudioClientVersion) {
uint32_t client_version = CoreAudioUtil::GetIAudioClientVersion();
EXPECT_GE(client_version, 1u);
EXPECT_LE(client_version, 3u);
}
TEST_F(CoreAudioUtilWinTest, NumberOfActiveDevices) { TEST_F(CoreAudioUtilWinTest, NumberOfActiveDevices) {
ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable()); ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
...@@ -79,7 +86,7 @@ TEST_F(CoreAudioUtilWinTest, CreateDefaultDevice) { ...@@ -79,7 +86,7 @@ TEST_F(CoreAudioUtilWinTest, CreateDefaultDevice) {
// Create default devices for all flow/role combinations above. // Create default devices for all flow/role combinations above.
ComPtr<IMMDevice> audio_device; ComPtr<IMMDevice> audio_device;
for (size_t i = 0; i < arraysize(data); ++i) { for (size_t i = 0; i < base::size(data); ++i) {
audio_device = CoreAudioUtil::CreateDevice( audio_device = CoreAudioUtil::CreateDevice(
AudioDeviceDescription::kDefaultDeviceId, data[i].flow, data[i].role); AudioDeviceDescription::kDefaultDeviceId, data[i].flow, data[i].role);
EXPECT_TRUE(audio_device.Get()); EXPECT_TRUE(audio_device.Get());
...@@ -132,7 +139,7 @@ TEST_F(CoreAudioUtilWinTest, GetDefaultDeviceName) { ...@@ -132,7 +139,7 @@ TEST_F(CoreAudioUtilWinTest, GetDefaultDeviceName) {
// Get name and ID of default devices for all flow/role combinations above. // Get name and ID of default devices for all flow/role combinations above.
ComPtr<IMMDevice> audio_device; ComPtr<IMMDevice> audio_device;
AudioDeviceName device_name; AudioDeviceName device_name;
for (size_t i = 0; i < arraysize(data); ++i) { for (size_t i = 0; i < base::size(data); ++i) {
audio_device = CoreAudioUtil::CreateDevice( audio_device = CoreAudioUtil::CreateDevice(
AudioDeviceDescription::kDefaultDeviceId, data[i].flow, data[i].role); AudioDeviceDescription::kDefaultDeviceId, data[i].flow, data[i].role);
EXPECT_TRUE(SUCCEEDED( EXPECT_TRUE(SUCCEEDED(
...@@ -152,7 +159,7 @@ TEST_F(CoreAudioUtilWinTest, GetAudioControllerID) { ...@@ -152,7 +159,7 @@ TEST_F(CoreAudioUtilWinTest, GetAudioControllerID) {
// Enumerate all active input and output devices and fetch the ID of // Enumerate all active input and output devices and fetch the ID of
// the associated device. // the associated device.
EDataFlow flows[] = { eRender , eCapture }; EDataFlow flows[] = { eRender , eCapture };
for (size_t i = 0; i < arraysize(flows); ++i) { for (size_t i = 0; i < base::size(flows); ++i) {
ComPtr<IMMDeviceCollection> collection; ComPtr<IMMDeviceCollection> collection;
ASSERT_TRUE(SUCCEEDED(enumerator->EnumAudioEndpoints( ASSERT_TRUE(SUCCEEDED(enumerator->EnumAudioEndpoints(
flows[i], DEVICE_STATE_ACTIVE, collection.GetAddressOf()))); flows[i], DEVICE_STATE_ACTIVE, collection.GetAddressOf())));
...@@ -199,10 +206,35 @@ TEST_F(CoreAudioUtilWinTest, CreateClient) { ...@@ -199,10 +206,35 @@ TEST_F(CoreAudioUtilWinTest, CreateClient) {
EDataFlow data[] = {eRender, eCapture}; EDataFlow data[] = {eRender, eCapture};
for (size_t i = 0; i < arraysize(data); ++i) { for (size_t i = 0; i < base::size(data); ++i) {
ComPtr<IAudioClient> client = CoreAudioUtil::CreateClient(
AudioDeviceDescription::kDefaultDeviceId, data[i], eConsole);
EXPECT_TRUE(client.Get());
}
}
TEST_F(CoreAudioUtilWinTest, CreateClient3) {
ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable() &&
CoreAudioUtil::GetIAudioClientVersion() >= 3);
EDataFlow data[] = {eRender, eCapture};
for (size_t i = 0; i < base::size(data); ++i) {
ComPtr<IAudioClient3> client3 = CoreAudioUtil::CreateClient3(
AudioDeviceDescription::kDefaultDeviceId, data[i], eConsole);
EXPECT_TRUE(client3.Get());
}
// Use ComPtr notation to achieve the same thing as above. ComPtr::As wraps
// QueryInterface calls on existing COM objects. In this case we use an
// existing IAudioClient to obtain the IAudioClient3 interface.
for (size_t i = 0; i < base::size(data); ++i) {
ComPtr<IAudioClient> client = CoreAudioUtil::CreateClient( ComPtr<IAudioClient> client = CoreAudioUtil::CreateClient(
AudioDeviceDescription::kDefaultDeviceId, data[i], eConsole); AudioDeviceDescription::kDefaultDeviceId, data[i], eConsole);
EXPECT_TRUE(client.Get()); EXPECT_TRUE(client.Get());
ComPtr<IAudioClient3> client3;
EXPECT_TRUE(SUCCEEDED(client.As(&client3)));
EXPECT_TRUE(client3.Get());
} }
} }
...@@ -257,7 +289,7 @@ TEST_F(CoreAudioUtilWinTest, GetDevicePeriod) { ...@@ -257,7 +289,7 @@ TEST_F(CoreAudioUtilWinTest, GetDevicePeriod) {
// Verify that the device periods are valid for the default render and // Verify that the device periods are valid for the default render and
// capture devices. // capture devices.
for (size_t i = 0; i < arraysize(data); ++i) { for (size_t i = 0; i < base::size(data); ++i) {
ComPtr<IAudioClient> client; ComPtr<IAudioClient> client;
REFERENCE_TIME shared_time_period = 0; REFERENCE_TIME shared_time_period = 0;
REFERENCE_TIME exclusive_time_period = 0; REFERENCE_TIME exclusive_time_period = 0;
...@@ -281,7 +313,7 @@ TEST_F(CoreAudioUtilWinTest, GetPreferredAudioParameters) { ...@@ -281,7 +313,7 @@ TEST_F(CoreAudioUtilWinTest, GetPreferredAudioParameters) {
// Verify that the preferred audio parameters are OK for the default render // Verify that the preferred audio parameters are OK for the default render
// and capture devices. // and capture devices.
for (size_t i = 0; i < arraysize(data); ++i) { for (size_t i = 0; i < base::size(data); ++i) {
AudioParameters params; AudioParameters params;
EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetPreferredAudioParameters( EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetPreferredAudioParameters(
AudioDeviceDescription::kDefaultDeviceId, data[i] == eRender, AudioDeviceDescription::kDefaultDeviceId, data[i] == eRender,
...@@ -365,7 +397,7 @@ TEST_F(CoreAudioUtilWinTest, CreateRenderAndCaptureClients) { ...@@ -365,7 +397,7 @@ TEST_F(CoreAudioUtilWinTest, CreateRenderAndCaptureClients) {
WAVEFORMATPCMEX format; WAVEFORMATPCMEX format;
uint32_t endpoint_buffer_size = 0; uint32_t endpoint_buffer_size = 0;
for (size_t i = 0; i < arraysize(data); ++i) { for (size_t i = 0; i < base::size(data); ++i) {
ComPtr<IAudioClient> client; ComPtr<IAudioClient> client;
ComPtr<IAudioRenderClient> render_client; ComPtr<IAudioRenderClient> render_client;
ComPtr<IAudioCaptureClient> capture_client; ComPtr<IAudioCaptureClient> capture_client;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment