1 /* 2 * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #ifndef MODULES_AUDIO_DEVICE_WIN_CORE_AUDIO_UTILITY_WIN_H_ 12 #define MODULES_AUDIO_DEVICE_WIN_CORE_AUDIO_UTILITY_WIN_H_ 13 14 #include <audioclient.h> 15 #include <audiopolicy.h> 16 #include <avrt.h> 17 #include <comdef.h> 18 #include <mmdeviceapi.h> 19 #include <objbase.h> 20 #include <propidl.h> 21 #include <wrl/client.h> 22 23 #include <string> 24 25 #include "api/units/time_delta.h" 26 #include "modules/audio_device/audio_device_name.h" 27 #include "modules/audio_device/include/audio_device_defines.h" 28 #include "rtc_base/logging.h" 29 #include "rtc_base/string_utils.h" 30 31 #pragma comment(lib, "Avrt.lib") 32 33 namespace webrtc { 34 namespace webrtc_win { 35 36 // Utility class which registers a thread with MMCSS in the constructor and 37 // deregisters MMCSS in the destructor. The task name is given by |task_name|. 38 // The Multimedia Class Scheduler service (MMCSS) enables multimedia 39 // applications to ensure that their time-sensitive processing receives 40 // prioritized access to CPU resources without denying CPU resources to 41 // lower-priority applications. 42 class ScopedMMCSSRegistration { 43 public: PriorityClassToString(DWORD priority_class)44 const char* PriorityClassToString(DWORD priority_class) { 45 switch (priority_class) { 46 case ABOVE_NORMAL_PRIORITY_CLASS: 47 return "ABOVE_NORMAL"; 48 case BELOW_NORMAL_PRIORITY_CLASS: 49 return "BELOW_NORMAL"; 50 case HIGH_PRIORITY_CLASS: 51 return "HIGH"; 52 case IDLE_PRIORITY_CLASS: 53 return "IDLE"; 54 case NORMAL_PRIORITY_CLASS: 55 return "NORMAL"; 56 case REALTIME_PRIORITY_CLASS: 57 return "REALTIME"; 58 default: 59 return "INVALID"; 60 } 61 } 62 PriorityToString(int priority)63 const char* PriorityToString(int priority) { 64 switch (priority) { 65 case THREAD_PRIORITY_ABOVE_NORMAL: 66 return "ABOVE_NORMAL"; 67 case THREAD_PRIORITY_BELOW_NORMAL: 68 return "BELOW_NORMAL"; 69 case THREAD_PRIORITY_HIGHEST: 70 return "HIGHEST"; 71 case THREAD_PRIORITY_IDLE: 72 return "IDLE"; 73 case THREAD_PRIORITY_LOWEST: 74 return "LOWEST"; 75 case THREAD_PRIORITY_NORMAL: 76 return "NORMAL"; 77 case THREAD_PRIORITY_TIME_CRITICAL: 78 return "TIME_CRITICAL"; 79 default: 80 // Can happen in combination with REALTIME_PRIORITY_CLASS. 81 return "INVALID"; 82 } 83 } 84 ScopedMMCSSRegistration(const wchar_t * task_name)85 explicit ScopedMMCSSRegistration(const wchar_t* task_name) { 86 RTC_DLOG(INFO) << "ScopedMMCSSRegistration: " << rtc::ToUtf8(task_name); 87 // Register the calling thread with MMCSS for the supplied |task_name|. 88 DWORD mmcss_task_index = 0; 89 mmcss_handle_ = AvSetMmThreadCharacteristicsW(task_name, &mmcss_task_index); 90 if (mmcss_handle_ == nullptr) { 91 RTC_LOG(LS_ERROR) << "Failed to enable MMCSS on this thread: " 92 << GetLastError(); 93 } else { 94 const DWORD priority_class = GetPriorityClass(GetCurrentProcess()); 95 const int priority = GetThreadPriority(GetCurrentThread()); 96 RTC_DLOG(INFO) << "priority class: " 97 << PriorityClassToString(priority_class) << "(" 98 << priority_class << ")"; 99 RTC_DLOG(INFO) << "priority: " << PriorityToString(priority) << "(" 100 << priority << ")"; 101 } 102 } 103 ~ScopedMMCSSRegistration()104 ~ScopedMMCSSRegistration() { 105 if (Succeeded()) { 106 // Deregister with MMCSS. 107 RTC_DLOG(INFO) << "~ScopedMMCSSRegistration"; 108 AvRevertMmThreadCharacteristics(mmcss_handle_); 109 } 110 } 111 112 ScopedMMCSSRegistration(const ScopedMMCSSRegistration&) = delete; 113 ScopedMMCSSRegistration& operator=(const ScopedMMCSSRegistration&) = delete; 114 Succeeded()115 bool Succeeded() const { return mmcss_handle_ != nullptr; } 116 117 private: 118 HANDLE mmcss_handle_ = nullptr; 119 }; 120 121 // Initializes COM in the constructor (STA or MTA), and uninitializes COM in the 122 // destructor. Taken from base::win::ScopedCOMInitializer. 123 // 124 // WARNING: This should only be used once per thread, ideally scoped to a 125 // similar lifetime as the thread itself. You should not be using this in 126 // random utility functions that make COM calls; instead ensure that these 127 // functions are running on a COM-supporting thread! 128 // See https://msdn.microsoft.com/en-us/library/ms809971.aspx for details. 129 class ScopedCOMInitializer { 130 public: 131 // Enum value provided to initialize the thread as an MTA instead of STA. 132 // There are two types of apartments, Single Threaded Apartments (STAs) 133 // and Multi Threaded Apartments (MTAs). Within a given process there can 134 // be multiple STA’s but there is only one MTA. STA is typically used by 135 // "GUI applications" and MTA by "worker threads" with no UI message loop. 136 enum SelectMTA { kMTA }; 137 138 // Constructor for STA initialization. ScopedCOMInitializer()139 ScopedCOMInitializer() { 140 RTC_DLOG(INFO) << "Single-Threaded Apartment (STA) COM thread"; 141 Initialize(COINIT_APARTMENTTHREADED); 142 } 143 144 // Constructor for MTA initialization. ScopedCOMInitializer(SelectMTA mta)145 explicit ScopedCOMInitializer(SelectMTA mta) { 146 RTC_DLOG(INFO) << "Multi-Threaded Apartment (MTA) COM thread"; 147 Initialize(COINIT_MULTITHREADED); 148 } 149 ~ScopedCOMInitializer()150 ~ScopedCOMInitializer() { 151 if (Succeeded()) { 152 CoUninitialize(); 153 } 154 } 155 156 ScopedCOMInitializer(const ScopedCOMInitializer&) = delete; 157 ScopedCOMInitializer& operator=(const ScopedCOMInitializer&) = delete; 158 Succeeded()159 bool Succeeded() { return SUCCEEDED(hr_); } 160 161 private: Initialize(COINIT init)162 void Initialize(COINIT init) { 163 // Initializes the COM library for use by the calling thread, sets the 164 // thread's concurrency model, and creates a new apartment for the thread 165 // if one is required. CoInitializeEx must be called at least once, and is 166 // usually called only once, for each thread that uses the COM library. 167 hr_ = CoInitializeEx(NULL, init); 168 RTC_CHECK_NE(RPC_E_CHANGED_MODE, hr_) 169 << "Invalid COM thread model change (MTA->STA)"; 170 // Multiple calls to CoInitializeEx by the same thread are allowed as long 171 // as they pass the same concurrency flag, but subsequent valid calls 172 // return S_FALSE. To close the COM library gracefully on a thread, each 173 // successful call to CoInitializeEx, including any call that returns 174 // S_FALSE, must be balanced by a corresponding call to CoUninitialize. 175 if (hr_ == S_OK) { 176 RTC_DLOG(INFO) 177 << "The COM library was initialized successfully on this thread"; 178 } else if (hr_ == S_FALSE) { 179 RTC_DLOG(WARNING) 180 << "The COM library is already initialized on this thread"; 181 } 182 } 183 HRESULT hr_; 184 }; 185 186 // A PROPVARIANT that is automatically initialized and cleared upon respective 187 // construction and destruction of this class. 188 class ScopedPropVariant { 189 public: ScopedPropVariant()190 ScopedPropVariant() { PropVariantInit(&pv_); } 191 ~ScopedPropVariant()192 ~ScopedPropVariant() { Reset(); } 193 194 ScopedPropVariant(const ScopedPropVariant&) = delete; 195 ScopedPropVariant& operator=(const ScopedPropVariant&) = delete; 196 bool operator==(const ScopedPropVariant&) const = delete; 197 bool operator!=(const ScopedPropVariant&) const = delete; 198 199 // Returns a pointer to the underlying PROPVARIANT for use as an out param in 200 // a function call. Receive()201 PROPVARIANT* Receive() { 202 RTC_DCHECK_EQ(pv_.vt, VT_EMPTY); 203 return &pv_; 204 } 205 206 // Clears the instance to prepare it for re-use (e.g., via Receive). Reset()207 void Reset() { 208 if (pv_.vt != VT_EMPTY) { 209 HRESULT result = PropVariantClear(&pv_); 210 RTC_DCHECK_EQ(result, S_OK); 211 } 212 } 213 get()214 const PROPVARIANT& get() const { return pv_; } ptr()215 const PROPVARIANT* ptr() const { return &pv_; } 216 217 private: 218 PROPVARIANT pv_; 219 }; 220 221 // Simple scoped memory releaser class for COM allocated memory. 222 template <typename T> 223 class ScopedCoMem { 224 public: ScopedCoMem()225 ScopedCoMem() : mem_ptr_(nullptr) {} 226 ~ScopedCoMem()227 ~ScopedCoMem() { Reset(nullptr); } 228 229 ScopedCoMem(const ScopedCoMem&) = delete; 230 ScopedCoMem& operator=(const ScopedCoMem&) = delete; 231 232 T** operator&() { // NOLINT 233 RTC_DCHECK(mem_ptr_ == nullptr); // To catch memory leaks. 234 return &mem_ptr_; 235 } 236 237 operator T*() { return mem_ptr_; } 238 239 T* operator->() { 240 RTC_DCHECK(mem_ptr_ != nullptr); 241 return mem_ptr_; 242 } 243 244 const T* operator->() const { 245 RTC_DCHECK(mem_ptr_ != nullptr); 246 return mem_ptr_; 247 } 248 249 explicit operator bool() const { return mem_ptr_; } 250 251 friend bool operator==(const ScopedCoMem& lhs, std::nullptr_t) { 252 return lhs.Get() == nullptr; 253 } 254 255 friend bool operator==(std::nullptr_t, const ScopedCoMem& rhs) { 256 return rhs.Get() == nullptr; 257 } 258 259 friend bool operator!=(const ScopedCoMem& lhs, std::nullptr_t) { 260 return lhs.Get() != nullptr; 261 } 262 263 friend bool operator!=(std::nullptr_t, const ScopedCoMem& rhs) { 264 return rhs.Get() != nullptr; 265 } 266 Reset(T * ptr)267 void Reset(T* ptr) { 268 if (mem_ptr_) 269 CoTaskMemFree(mem_ptr_); 270 mem_ptr_ = ptr; 271 } 272 Get()273 T* Get() const { return mem_ptr_; } 274 275 private: 276 T* mem_ptr_; 277 }; 278 279 // A HANDLE that is automatically initialized and closed upon respective 280 // construction and destruction of this class. 281 class ScopedHandle { 282 public: ScopedHandle()283 ScopedHandle() : handle_(nullptr) {} ScopedHandle(HANDLE h)284 explicit ScopedHandle(HANDLE h) : handle_(nullptr) { Set(h); } 285 ~ScopedHandle()286 ~ScopedHandle() { Close(); } 287 288 ScopedHandle& operator=(const ScopedHandle&) = delete; 289 bool operator==(const ScopedHandle&) const = delete; 290 bool operator!=(const ScopedHandle&) const = delete; 291 292 // Use this instead of comparing to INVALID_HANDLE_VALUE. IsValid()293 bool IsValid() const { return handle_ != nullptr; } 294 Set(HANDLE new_handle)295 void Set(HANDLE new_handle) { 296 Close(); 297 // Windows is inconsistent about invalid handles. 298 // See https://blogs.msdn.microsoft.com/oldnewthing/20040302-00/?p=40443 299 // for details. 300 if (new_handle != INVALID_HANDLE_VALUE) { 301 handle_ = new_handle; 302 } 303 } 304 Get()305 HANDLE Get() const { return handle_; } 306 HANDLE()307 operator HANDLE() const { return handle_; } 308 Close()309 void Close() { 310 if (handle_) { 311 if (!::CloseHandle(handle_)) { 312 RTC_NOTREACHED(); 313 } 314 handle_ = nullptr; 315 } 316 } 317 318 private: 319 HANDLE handle_; 320 }; 321 322 // Utility methods for the Core Audio API on Windows. 323 // Always ensure that Core Audio is supported before using these methods. 324 // Use webrtc_win::core_audio_utility::IsSupported() for this purpose. 325 // Also, all methods must be called on a valid COM thread. This can be done 326 // by using the webrtc_win::ScopedCOMInitializer helper class. 327 // These methods are based on media::CoreAudioUtil in Chrome. 328 namespace core_audio_utility { 329 330 // Helper class which automates casting between WAVEFORMATEX and 331 // WAVEFORMATEXTENSIBLE raw pointers using implicit constructors and 332 // operator overloading. Note that, no memory is allocated by this utility 333 // structure. It only serves as a handle (or a wrapper) of the structure 334 // provided to it at construction. 335 class WaveFormatWrapper { 336 public: WaveFormatWrapper(WAVEFORMATEXTENSIBLE * p)337 WaveFormatWrapper(WAVEFORMATEXTENSIBLE* p) 338 : ptr_(reinterpret_cast<WAVEFORMATEX*>(p)) {} WaveFormatWrapper(WAVEFORMATEX * p)339 WaveFormatWrapper(WAVEFORMATEX* p) : ptr_(p) {} 340 ~WaveFormatWrapper() = default; 341 342 operator WAVEFORMATEX*() const { return ptr_; } 343 WAVEFORMATEX* operator->() const { return ptr_; } get()344 WAVEFORMATEX* get() const { return ptr_; } 345 WAVEFORMATEXTENSIBLE* GetExtensible() const; 346 347 bool IsExtensible() const; 348 bool IsPcm() const; 349 bool IsFloat() const; 350 size_t size() const; 351 352 private: 353 WAVEFORMATEX* ptr_; 354 }; 355 356 // Returns true if Windows Core Audio is supported. 357 // Always verify that this method returns true before using any of the 358 // other methods in this class. 359 bool IsSupported(); 360 361 // Returns true if Multimedia Class Scheduler service (MMCSS) is supported. 362 // The MMCSS enables multimedia applications to ensure that their time-sensitive 363 // processing receives prioritized access to CPU resources without denying CPU 364 // resources to lower-priority applications. 365 bool IsMMCSSSupported(); 366 367 // The MMDevice API lets clients discover the audio endpoint devices in the 368 // system and determine which devices are suitable for the application to use. 369 // Header file Mmdeviceapi.h defines the interfaces in the MMDevice API. 370 371 // Number of active audio devices in the specified data flow direction. 372 // Set |data_flow| to eAll to retrieve the total number of active audio 373 // devices. 374 int NumberOfActiveDevices(EDataFlow data_flow); 375 376 // Returns 1, 2, or 3 depending on what version of IAudioClient the platform 377 // supports. 378 // Example: IAudioClient2 is supported on Windows 8 and higher => 2 is returned. 379 uint32_t GetAudioClientVersion(); 380 381 // Creates an IMMDeviceEnumerator interface which provides methods for 382 // enumerating audio endpoint devices. 383 // TODO(henrika): IMMDeviceEnumerator::RegisterEndpointNotificationCallback. 384 Microsoft::WRL::ComPtr<IMMDeviceEnumerator> CreateDeviceEnumerator(); 385 386 // These functions return the unique device id of the default or 387 // communications input/output device, or an empty string if no such device 388 // exists or if the device has been disabled. 389 std::string GetDefaultInputDeviceID(); 390 std::string GetDefaultOutputDeviceID(); 391 std::string GetCommunicationsInputDeviceID(); 392 std::string GetCommunicationsOutputDeviceID(); 393 394 // Creates an IMMDevice interface corresponding to the unique device id in 395 // |device_id|, or by data-flow direction and role if |device_id| is set to 396 // AudioDeviceName::kDefaultDeviceId. 397 Microsoft::WRL::ComPtr<IMMDevice> CreateDevice(const std::string& device_id, 398 EDataFlow data_flow, 399 ERole role); 400 401 // Returns the unique ID and user-friendly name of a given endpoint device. 402 // Example: "{0.0.1.00000000}.{8db6020f-18e3-4f25-b6f5-7726c9122574}", and 403 // "Microphone (Realtek High Definition Audio)". 404 webrtc::AudioDeviceName GetDeviceName(IMMDevice* device); 405 406 // Gets the user-friendly name of the endpoint device which is represented 407 // by a unique id in |device_id|, or by data-flow direction and role if 408 // |device_id| is set to AudioDeviceName::kDefaultDeviceId. 409 std::string GetFriendlyName(const std::string& device_id, 410 EDataFlow data_flow, 411 ERole role); 412 413 // Query if the audio device is a rendering device or a capture device. 414 EDataFlow GetDataFlow(IMMDevice* device); 415 416 // Enumerates all input devices and adds the names (friendly name and unique 417 // device id) to the list in |device_names|. 418 bool GetInputDeviceNames(webrtc::AudioDeviceNames* device_names); 419 420 // Enumerates all output devices and adds the names (friendly name and unique 421 // device id) to the list in |device_names|. 422 bool GetOutputDeviceNames(webrtc::AudioDeviceNames* device_names); 423 424 // The Windows Audio Session API (WASAPI) enables client applications to 425 // manage the flow of audio data between the application and an audio endpoint 426 // device. Header files Audioclient.h and Audiopolicy.h define the WASAPI 427 // interfaces. 428 429 // Creates an IAudioSessionManager2 interface for the specified |device|. 430 // This interface provides access to e.g. the IAudioSessionEnumerator 431 Microsoft::WRL::ComPtr<IAudioSessionManager2> CreateSessionManager2( 432 IMMDevice* device); 433 434 // Creates an IAudioSessionEnumerator interface for the specified |device|. 435 // The client can use the interface to enumerate audio sessions on the audio 436 // device 437 Microsoft::WRL::ComPtr<IAudioSessionEnumerator> CreateSessionEnumerator( 438 IMMDevice* device); 439 440 // Number of active audio sessions for the given |device|. Expired or inactive 441 // sessions are not included. 442 int NumberOfActiveSessions(IMMDevice* device); 443 444 // Creates an IAudioClient instance for a specific device or the default 445 // device specified by data-flow direction and role. 446 Microsoft::WRL::ComPtr<IAudioClient> CreateClient(const std::string& device_id, 447 EDataFlow data_flow, 448 ERole role); 449 Microsoft::WRL::ComPtr<IAudioClient2> 450 CreateClient2(const std::string& device_id, EDataFlow data_flow, ERole role); 451 Microsoft::WRL::ComPtr<IAudioClient3> 452 CreateClient3(const std::string& device_id, EDataFlow data_flow, ERole role); 453 454 // Sets the AudioCategory_Communications category. Should be called before 455 // GetSharedModeMixFormat() and IsFormatSupported(). The |client| argument must 456 // be an IAudioClient2 or IAudioClient3 interface pointer, hence only supported 457 // on Windows 8 and above. 458 // TODO(henrika): evaluate effect (if any). 459 HRESULT SetClientProperties(IAudioClient2* client); 460 461 // Returns the buffer size limits of the hardware audio engine in 462 // 100-nanosecond units given a specified |format|. Does not require prior 463 // audio stream initialization. The |client| argument must be an IAudioClient2 464 // or IAudioClient3 interface pointer, hence only supported on Windows 8 and 465 // above. 466 // TODO(henrika): always fails with AUDCLNT_E_OFFLOAD_MODE_ONLY. 467 HRESULT GetBufferSizeLimits(IAudioClient2* client, 468 const WAVEFORMATEXTENSIBLE* format, 469 REFERENCE_TIME* min_buffer_duration, 470 REFERENCE_TIME* max_buffer_duration); 471 472 // Get the mix format that the audio engine uses internally for processing 473 // of shared-mode streams. The client can call this method before calling 474 // IAudioClient::Initialize. When creating a shared-mode stream for an audio 475 // endpoint device, the Initialize method always accepts the stream format 476 // obtained by this method. 477 HRESULT GetSharedModeMixFormat(IAudioClient* client, 478 WAVEFORMATEXTENSIBLE* format); 479 480 // Returns true if the specified |client| supports the format in |format| 481 // for the given |share_mode| (shared or exclusive). The client can call this 482 // method before calling IAudioClient::Initialize. 483 bool IsFormatSupported(IAudioClient* client, 484 AUDCLNT_SHAREMODE share_mode, 485 const WAVEFORMATEXTENSIBLE* format); 486 487 // For a shared-mode stream, the audio engine periodically processes the 488 // data in the endpoint buffer at the period obtained in |device_period|. 489 // For an exclusive mode stream, |device_period| corresponds to the minimum 490 // time interval between successive processing by the endpoint device. 491 // This period plus the stream latency between the buffer and endpoint device 492 // represents the minimum possible latency that an audio application can 493 // achieve. The time in |device_period| is expressed in 100-nanosecond units. 494 HRESULT GetDevicePeriod(IAudioClient* client, 495 AUDCLNT_SHAREMODE share_mode, 496 REFERENCE_TIME* device_period); 497 498 // Returns the range of periodicities supported by the engine for the specified 499 // stream |format|. The periodicity of the engine is the rate at which the 500 // engine wakes an event-driven audio client to transfer audio data to or from 501 // the engine. Can be used for low-latency support on some devices. 502 // The |client| argument must be an IAudioClient3 interface pointer, hence only 503 // supported on Windows 10 and above. 504 HRESULT GetSharedModeEnginePeriod(IAudioClient3* client3, 505 const WAVEFORMATEXTENSIBLE* format, 506 uint32_t* default_period_in_frames, 507 uint32_t* fundamental_period_in_frames, 508 uint32_t* min_period_in_frames, 509 uint32_t* max_period_in_frames); 510 511 // Get the preferred audio parameters for the given |client| corresponding to 512 // the stream format that the audio engine uses for its internal processing of 513 // shared-mode streams. The acquired values should only be utilized for shared 514 // mode streamed since there are no preferred settings for an exclusive mode 515 // stream. 516 HRESULT GetPreferredAudioParameters(IAudioClient* client, 517 webrtc::AudioParameters* params); 518 // As above but override the preferred sample rate and use |sample_rate| 519 // instead. Intended mainly for testing purposes and in combination with rate 520 // conversion. 521 HRESULT GetPreferredAudioParameters(IAudioClient* client, 522 webrtc::AudioParameters* params, 523 uint32_t sample_rate); 524 525 // After activating an IAudioClient interface on an audio endpoint device, 526 // the client must initialize it once, and only once, to initialize the audio 527 // stream between the client and the device. In shared mode, the client 528 // connects indirectly through the audio engine which does the mixing. 529 // If a valid event is provided in |event_handle|, the client will be 530 // initialized for event-driven buffer handling. If |event_handle| is set to 531 // nullptr, event-driven buffer handling is not utilized. To achieve the 532 // minimum stream latency between the client application and audio endpoint 533 // device, set |buffer_duration| to 0. A client has the option of requesting a 534 // buffer size that is larger than what is strictly necessary to make timing 535 // glitches rare or nonexistent. Increasing the buffer size does not necessarily 536 // increase the stream latency. Each unit of reference time is 100 nanoseconds. 537 // The |auto_convert_pcm| parameter can be used for testing purposes to ensure 538 // that the sample rate of the client side does not have to match the audio 539 // engine mix format. If |auto_convert_pcm| is set to true, a rate converter 540 // will be inserted to convert between the sample rate in |format| and the 541 // preferred rate given by GetPreferredAudioParameters(). 542 // The output parameter |endpoint_buffer_size| contains the size of the 543 // endpoint buffer and it is expressed as the number of audio frames the 544 // buffer can hold. 545 HRESULT SharedModeInitialize(IAudioClient* client, 546 const WAVEFORMATEXTENSIBLE* format, 547 HANDLE event_handle, 548 REFERENCE_TIME buffer_duration, 549 bool auto_convert_pcm, 550 uint32_t* endpoint_buffer_size); 551 552 // Works as SharedModeInitialize() but adds support for using smaller engine 553 // periods than the default period. 554 // The |client| argument must be an IAudioClient3 interface pointer, hence only 555 // supported on Windows 10 and above. 556 // TODO(henrika): can probably be merged into SharedModeInitialize() to avoid 557 // duplicating code. Keeping as separate method for now until decided if we 558 // need low-latency support. 559 HRESULT SharedModeInitializeLowLatency(IAudioClient3* client, 560 const WAVEFORMATEXTENSIBLE* format, 561 HANDLE event_handle, 562 uint32_t period_in_frames, 563 bool auto_convert_pcm, 564 uint32_t* endpoint_buffer_size); 565 566 // Creates an IAudioRenderClient client for an existing IAudioClient given by 567 // |client|. The IAudioRenderClient interface enables a client to write 568 // output data to a rendering endpoint buffer. The methods in this interface 569 // manage the movement of data packets that contain audio-rendering data. 570 Microsoft::WRL::ComPtr<IAudioRenderClient> CreateRenderClient( 571 IAudioClient* client); 572 573 // Creates an IAudioCaptureClient client for an existing IAudioClient given by 574 // |client|. The IAudioCaptureClient interface enables a client to read 575 // input data from a capture endpoint buffer. The methods in this interface 576 // manage the movement of data packets that contain capture data. 577 Microsoft::WRL::ComPtr<IAudioCaptureClient> CreateCaptureClient( 578 IAudioClient* client); 579 580 // Creates an IAudioClock interface for an existing IAudioClient given by 581 // |client|. The IAudioClock interface enables a client to monitor a stream's 582 // data rate and the current position in the stream. 583 Microsoft::WRL::ComPtr<IAudioClock> CreateAudioClock(IAudioClient* client); 584 585 // Creates an AudioSessionControl interface for an existing IAudioClient given 586 // by |client|. The IAudioControl interface enables a client to configure the 587 // control parameters for an audio session and to monitor events in the session. 588 Microsoft::WRL::ComPtr<IAudioSessionControl> CreateAudioSessionControl( 589 IAudioClient* client); 590 591 // Creates an ISimpleAudioVolume interface for an existing IAudioClient given by 592 // |client|. This interface enables a client to control the master volume level 593 // of an active audio session. 594 Microsoft::WRL::ComPtr<ISimpleAudioVolume> CreateSimpleAudioVolume( 595 IAudioClient* client); 596 597 // Fills up the endpoint rendering buffer with silence for an existing 598 // IAudioClient given by |client| and a corresponding IAudioRenderClient 599 // given by |render_client|. 600 bool FillRenderEndpointBufferWithSilence(IAudioClient* client, 601 IAudioRenderClient* render_client); 602 603 // Prints/logs all fields of the format structure in |format|. 604 // Also supports extended versions (WAVEFORMATEXTENSIBLE). 605 std::string WaveFormatToString(const WaveFormatWrapper format); 606 607 // Converts Windows internal REFERENCE_TIME (100 nanosecond units) into 608 // generic webrtc::TimeDelta which then can be converted to any time unit. 609 webrtc::TimeDelta ReferenceTimeToTimeDelta(REFERENCE_TIME time); 610 611 // Converts size expressed in number of audio frames, |num_frames|, into 612 // milliseconds given a specified |sample_rate|. 613 double FramesToMilliseconds(uint32_t num_frames, uint16_t sample_rate); 614 615 // Converts a COM error into a human-readable string. 616 std::string ErrorToString(const _com_error& error); 617 618 } // namespace core_audio_utility 619 } // namespace webrtc_win 620 } // namespace webrtc 621 622 #endif // MODULES_AUDIO_DEVICE_WIN_CORE_AUDIO_UTILITY_WIN_H_ 623