pub struct AudioClient { /* private fields */ }
Expand description
Struct wrapping an IAudioClient.
Implementations§
Source§impl AudioClient
impl AudioClient
Sourcepub fn new_application_loopback_client(
process_id: u32,
include_tree: bool,
) -> Result<Self, WasapiError>
pub fn new_application_loopback_client( process_id: u32, include_tree: bool, ) -> Result<Self, WasapiError>
Creates a loopback capture AudioClient for a specific process.
include_tree
is equivalent to PROCESS_LOOPBACK_MODE.
If true, the loopback capture client will capture audio from the target process and all its child processes,
if false only audio from the target process is captured.
On versions of Windows prior to Windows 10, the thread calling this function must called in a COM Single-Threaded Apartment (STA).
Additionally when calling AudioClient::initialize_client on the client returned by this method, the caller must use Direction::Capture, and ShareMode::Shared. Finally calls to AudioClient::get_device_period do not work, however the period passed by the caller to AudioClient::initialize_client is irrelevant.
§Non-functional methods
In process loopback mode, the functionality of the AudioClient is limited. The following methods either do not work, or return incorrect results:
get_mixformat
just returnsNot implemented
.is_supported
just returnsNot implemented
even if the format and mode work.is_supported_exclusive_with_quirks
just returnsUnable to find a supported format
.get_device_period
just returnsNot implemented
.calculate_aligned_period_near
just returnsNot implemented
even for values that would later work.get_buffer_size
returns huge values like 3131961357 but no error.get_current_padding
just returnsNot implemented
.get_available_space_in_frames
just returnsClient has not been initialised
even if it has.get_audiorenderclient
just returnsNo such interface supported
.get_audiosessioncontrol
just returnsNo such interface supported
.get_audioclock
just returnsNo such interface supported
.get_sharemode
always returnsNone
when it should returnShared
after initialisation.
§Example
use wasapi::{WaveFormat, SampleType, AudioClient, Direction, StreamMode, initialize_mta};
let desired_format = WaveFormat::new(32, 32, &SampleType::Float, 44100, 2, None);
let buffer_duration_hns = 200_000; // 20ms in hundreds of nanoseconds
let autoconvert = true;
let include_tree = false;
let process_id = std::process::id();
initialize_mta().ok().unwrap(); // Don't do this on a UI thread
let mut audio_client = AudioClient::new_application_loopback_client(process_id, include_tree).unwrap();
let mode = StreamMode::EventsShared { autoconvert, buffer_duration_hns };
audio_client.initialize_client(
&desired_format,
&Direction::Capture,
&mode
).unwrap();
Sourcepub fn get_mixformat(&self) -> Result<WaveFormat, WasapiError>
pub fn get_mixformat(&self) -> Result<WaveFormat, WasapiError>
Get MixFormat of the device. This is the format the device uses in shared mode and should always be accepted.
Sourcepub fn is_supported(
&self,
wave_fmt: &WaveFormat,
sharemode: &ShareMode,
) -> Result<Option<WaveFormat>, WasapiError>
pub fn is_supported( &self, wave_fmt: &WaveFormat, sharemode: &ShareMode, ) -> Result<Option<WaveFormat>, WasapiError>
Check if a format is supported. If it’s directly supported, this returns Ok(None). If not, but a similar format is, then the nearest matching supported format is returned as Ok(Some(WaveFormat)).
NOTE: For exclusive mode, this function may not always give the right result for 1- and 2-channel formats. From the Microsoft documentation:
For exclusive-mode formats, the method queries the device driver. Some device drivers will report that they support a 1-channel or 2-channel PCM format if the format is specified by a stand-alone WAVEFORMATEX structure, but will reject the same format if it is specified by a WAVEFORMATEXTENSIBLE structure. To obtain reliable results from these drivers, exclusive-mode applications should call IsFormatSupported twice for each 1-channel or 2-channel PCM format. One call should use a stand-alone WAVEFORMATEX structure to specify the format, and the other call should use a WAVEFORMATEXTENSIBLE structure to specify the same format.
If the first call fails, use WaveFormat::to_waveformatex to get a copy of the WaveFormat in the simpler WAVEFORMATEX representation. Then call this function again with the new WafeFormat structure. If the driver then reports that the format is supported, use the original WaveFormat structure when calling AudioClient::initialize_client.
See also the helper function is_supported_exclusive_with_quirks.
Sourcepub fn is_supported_exclusive_with_quirks(
&self,
wave_fmt: &WaveFormat,
) -> Result<WaveFormat, WasapiError>
pub fn is_supported_exclusive_with_quirks( &self, wave_fmt: &WaveFormat, ) -> Result<WaveFormat, WasapiError>
A helper function for checking if a format is supported.
It calls is_supported
several times with different options
in order to find a format that the device accepts.
The alternatives it tries are:
- The format as given.
- If one or two channels, try with the format as WAVEFORMATEX.
- Try with different channel masks:
- If channels <= 8: Recommended mask(s) from ksmedia.h.
- If channels <= 18: Simple mask.
- Zero mask.
If an accepted format is found, this is returned. An error means no accepted format was found.
Sourcepub fn get_device_period(&self) -> Result<(i64, i64), WasapiError>
pub fn get_device_period(&self) -> Result<(i64, i64), WasapiError>
Get default and minimum periods in 100-nanosecond units
pub fn get_periods(&self) -> Result<(i64, i64), WasapiError>
get_device_period
insteadSourcepub fn calculate_aligned_period_near(
&self,
desired_period: i64,
align_bytes: Option<u32>,
wave_fmt: &WaveFormat,
) -> Result<i64, WasapiError>
pub fn calculate_aligned_period_near( &self, desired_period: i64, align_bytes: Option<u32>, wave_fmt: &WaveFormat, ) -> Result<i64, WasapiError>
Helper function for calculating a period size in 100-nanosecond units that is near a desired value, and always larger than the minimum value supported by the device. The returned value leads to a device buffer size that is aligned both to the frame size of the format, and the optional align_bytes value. This parameter is used for devices that require the buffer size to be a multiple of a certain number of bytes. Give None, Some(0) or Some(1) if the device has no special requirements for the alignment. For example, all devices following the Intel High Definition Audio specification require buffer sizes in multiples of 128 bytes.
See also the playnoise_exclusive
example.
Sourcepub fn initialize_client(
&mut self,
wavefmt: &WaveFormat,
direction: &Direction,
stream_mode: &StreamMode,
) -> Result<(), WasapiError>
pub fn initialize_client( &mut self, wavefmt: &WaveFormat, direction: &Direction, stream_mode: &StreamMode, ) -> Result<(), WasapiError>
Initialize an AudioClient for the given direction, sharemode, timing mode and format. This method wraps IAudioClient::Initialize().
§Sharing mode
In WASAPI, sharing mode determines how multiple audio applications interact with the same audio endpoint. There are two primary sharing modes: Shared and Exclusive.
§Shared Mode (ShareMode::Shared)
- Multiple applications can simultaneously access the audio device.
- The system’s audio engine mixes the audio streams from all applications.
- The application has no control over the sample rate and format used by the device.
- The audio engine can perform automatic sample rate and format conversion, meaning that almost any format can be accepted.
§Exclusive Mode (ShareMode::Exclusive)
- Only one application can access the audio device at a time.
- This mode provides lower latency but requires the device to support the exact audio format requested.
- The application can control the sample rate and format used by the device.
§Timing mode
Event-driven mode and polling mode are two different ways of handling audio buffer updates.
§Event-Driven Mode (TimingMode::Events)
- In this mode, the application registers an event handle using AudioClient::set_get_eventhandle().
- The system signals this event whenever a new buffer of audio data is ready to be processed (either for rendering or capture).
- The application’s audio processing thread waits on this event (Handle::wait_for_event()).
- When the event is signaled, the thread wakes up to processes the available data, and then goes back to waiting.
- This mode is generally more efficient because the application only wakes up when there’s work to do.
- It’s suitable for real-time audio applications where low latency is important.
- This mode is not supported by all devices in exclusive mode (but all devices are supported in shared mode).
- In exclusive mode, devices using the standard Windows USB audio driver can have issues with stuttering sound on playback.
§Polling Mode (TimingMode::Polling)
- In this mode, the application periodically calls AudioClient::get_current_padding() (for capture) or AudioClient::get_available_space_in_frames() (for playback) to check how much data is available or required.
- The thread processes the data, and then goes to sleep, for example by calling std::thread::sleep().
- This mode is less efficient and is more prone to glitches when running at low latency.
- In exclusive mode, it supports more devices, and does not have the stuttering issue with USB audio devices.
Sourcepub fn set_get_eventhandle(&self) -> Result<Handle, WasapiError>
pub fn set_get_eventhandle(&self) -> Result<Handle, WasapiError>
Create and return an event handle for an AudioClient. This is required when using an AudioClient initialized for event driven mode, TimingMode::Events.
Sourcepub fn get_buffer_size(&self) -> Result<u32, WasapiError>
pub fn get_buffer_size(&self) -> Result<u32, WasapiError>
Get buffer size in frames, see IAudioClient::GetBufferSize.
pub fn get_bufferframecount(&self) -> Result<u32, WasapiError>
get_buffer_size
insteadSourcepub fn get_current_padding(&self) -> Result<u32, WasapiError>
pub fn get_current_padding(&self) -> Result<u32, WasapiError>
Get current padding in frames. This represents the number of frames currently in the buffer, for both capture and render devices. The exact meaning depends on how the AudioClient was initialized, see IAudioClient::GetCurrentPadding.
Sourcepub fn get_available_space_in_frames(&self) -> Result<u32, WasapiError>
pub fn get_available_space_in_frames(&self) -> Result<u32, WasapiError>
Get buffer size minus padding in frames. Use this to find out how much free space is available in the buffer.
Sourcepub fn start_stream(&self) -> Result<(), WasapiError>
pub fn start_stream(&self) -> Result<(), WasapiError>
Start the stream on an [IAudioClient]
Sourcepub fn stop_stream(&self) -> Result<(), WasapiError>
pub fn stop_stream(&self) -> Result<(), WasapiError>
Stop the stream on an [IAudioClient]
Sourcepub fn reset_stream(&self) -> Result<(), WasapiError>
pub fn reset_stream(&self) -> Result<(), WasapiError>
Reset the stream on an [IAudioClient]
Sourcepub fn get_audiorenderclient(&self) -> Result<AudioRenderClient, WasapiError>
pub fn get_audiorenderclient(&self) -> Result<AudioRenderClient, WasapiError>
Get a rendering (playback) client
Sourcepub fn get_audiocaptureclient(&self) -> Result<AudioCaptureClient, WasapiError>
pub fn get_audiocaptureclient(&self) -> Result<AudioCaptureClient, WasapiError>
Get a capture client
Sourcepub fn get_audiosessioncontrol(
&self,
) -> Result<AudioSessionControl, WasapiError>
pub fn get_audiosessioncontrol( &self, ) -> Result<AudioSessionControl, WasapiError>
Get the AudioSessionControl
Sourcepub fn get_audioclock(&self) -> Result<AudioClock, WasapiError>
pub fn get_audioclock(&self) -> Result<AudioClock, WasapiError>
Get the AudioClock
Sourcepub fn get_direction(&self) -> Direction
pub fn get_direction(&self) -> Direction
Get the direction for this AudioClient
Get the sharemode for this AudioClient. The sharemode is decided when the client is initialized.
Sourcepub fn get_timing_mode(&self) -> Option<TimingMode>
pub fn get_timing_mode(&self) -> Option<TimingMode>
Get the timing mode for this AudioClient. The mode is decided when the client is initialized.
Sourcepub fn get_aec_control(
&self,
) -> Result<AcousticEchoCancellationControl, WasapiError>
pub fn get_aec_control( &self, ) -> Result<AcousticEchoCancellationControl, WasapiError>
Get the Acoustic Echo Cancellation Control. If it succeeds, the capture endpoint supports control of the loopback reference endpoint for AEC.
Sourcepub fn get_audio_effects_manager(
&self,
) -> Result<AudioEffectsManager, WasapiError>
pub fn get_audio_effects_manager( &self, ) -> Result<AudioEffectsManager, WasapiError>
Get the Audio Effects Manager.
Sourcepub fn set_audio_stream_category(
&self,
category: AUDIO_STREAM_CATEGORY,
) -> Result<(), WasapiError>
pub fn set_audio_stream_category( &self, category: AUDIO_STREAM_CATEGORY, ) -> Result<(), WasapiError>
Set the category of an audio stream.
Sourcepub fn is_aec_supported(&self) -> Result<bool, WasapiError>
pub fn is_aec_supported(&self) -> Result<bool, WasapiError>
Check if the Acoustic Echo Cancellation (AEC) is supported.