Struct AudioClient

Source
pub struct AudioClient { /* private fields */ }
Expand description

Struct wrapping an IAudioClient.

Implementations§

Source§

impl AudioClient

Source

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 returns Not implemented.
  • is_supported just returns Not implemented even if the format and mode work.
  • is_supported_exclusive_with_quirks just returns Unable to find a supported format.
  • get_device_period just returns Not implemented.
  • calculate_aligned_period_near just returns Not implemented even for values that would later work.
  • get_buffer_size returns huge values like 3131961357 but no error.
  • get_current_padding just returns Not implemented.
  • get_available_space_in_frames just returns Client has not been initialised even if it has.
  • get_audiorenderclient just returns No such interface supported.
  • get_audiosessioncontrol just returns No such interface supported.
  • get_audioclock just returns No such interface supported.
  • get_sharemode always returns None when it should return Shared 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();
Source

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.

Source

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.

Source

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.

Source

pub fn get_device_period(&self) -> Result<(i64, i64), WasapiError>

Get default and minimum periods in 100-nanosecond units

Source

pub fn get_periods(&self) -> Result<(i64, i64), WasapiError>

👎Deprecated since 0.17.0: please use the new function name get_device_period instead
Source

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.

Source

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.
Source

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.

Source

pub fn get_buffer_size(&self) -> Result<u32, WasapiError>

Get buffer size in frames, see IAudioClient::GetBufferSize.

Source

pub fn get_bufferframecount(&self) -> Result<u32, WasapiError>

👎Deprecated since 0.17.0: please use the new function name get_buffer_size instead
Source

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.

Source

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.

Source

pub fn start_stream(&self) -> Result<(), WasapiError>

Start the stream on an [IAudioClient]

Source

pub fn stop_stream(&self) -> Result<(), WasapiError>

Stop the stream on an [IAudioClient]

Source

pub fn reset_stream(&self) -> Result<(), WasapiError>

Reset the stream on an [IAudioClient]

Source

pub fn get_audiorenderclient(&self) -> Result<AudioRenderClient, WasapiError>

Get a rendering (playback) client

Source

pub fn get_audiocaptureclient(&self) -> Result<AudioCaptureClient, WasapiError>

Get a capture client

Source

pub fn get_audiosessioncontrol( &self, ) -> Result<AudioSessionControl, WasapiError>

Source

pub fn get_audioclock(&self) -> Result<AudioClock, WasapiError>

Get the AudioClock

Source

pub fn get_direction(&self) -> Direction

Get the direction for this AudioClient

Source

pub fn get_sharemode(&self) -> Option<ShareMode>

Get the sharemode for this AudioClient. The sharemode is decided when the client is initialized.

Source

pub fn get_timing_mode(&self) -> Option<TimingMode>

Get the timing mode for this AudioClient. The mode is decided when the client is initialized.

Source

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.

Source

pub fn get_audio_effects_manager( &self, ) -> Result<AudioEffectsManager, WasapiError>

Get the Audio Effects Manager.

Source

pub fn set_audio_stream_category( &self, category: AUDIO_STREAM_CATEGORY, ) -> Result<(), WasapiError>

Set the category of an audio stream.

Source

pub fn is_aec_supported(&self) -> Result<bool, WasapiError>

Check if the Acoustic Echo Cancellation (AEC) is supported.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.