Skip to main content

AudioService

Struct AudioService 

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

The main service that orchestrates real-time audio loopback between an input and output device.

AudioService manages the full lifecycle of the audio processing pipeline:

  • Device management — holds references to the active CPAL input/output devices through an AudioHandlerTrait implementation and supports hot-swapping either device without a full restart.
  • Resampling — on start_loopback the input and output sample rates are compared and a ResamplePolicy is selected automatically:
    • input == output → no resampling, zero overhead.
    • input > output → downsample before the DSP chain.
    • input < output → upsample after the DSP chain.
  • DSP chain — every sample passes through gain, tone stack, and master volume processors in order. Additional processors can be inserted into start_loopback’s run_dsp closure.
  • Thread lifecycle — the loopback runs on a dedicated background thread with a lock-free ring buffer between the CPAL callbacks and the worker; the thread is cleanly shut down via stop_loopback.

Implementations§

Source§

impl AudioService

Auto-generated by derive_getters::Getters.

Source

pub fn audio_handler(&self) -> &Arc<dyn AudioHandlerTrait>

Get field audio_handler from instance of AudioService.

Source

pub fn loopback_thread(&self) -> &Option<JoinHandle<()>>

Get field loopback_thread from instance of AudioService.

Source

pub fn is_active(&self) -> &bool

Get field is_active from instance of AudioService.

Source

pub fn channels(&self) -> &Vec<Channel>

Get field channels from instance of AudioService.

Source

pub fn current_channel_id(&self) -> &u32

Get field current_channel_id from instance of AudioService.

Source

pub fn master_volume(&self) -> &Arc<AtomicF32>

Get field master_volume from instance of AudioService.

Source

pub fn next_channel_id(&self) -> &u32

Get field next_channel_id from instance of AudioService.

Source

pub fn spectrum_tap(&self) -> &Arc<SpectrumTap>

Get field spectrum_tap from instance of AudioService.

Source§

impl AudioService

Source

pub fn dsp_chain_sample_rate(&self) -> u32

Returns the sample rate at which the DSP chain effectively runs.

With current resampling policy, DSP executes at the lower of input/output rates.

Source

pub fn new( input_device: Device, output_device: Device, input_config: StreamConfig, output_config: StreamConfig, ) -> Self

Creates a new AudioService using the provided CPAL input/output devices and stream config.

An AudioHandler is constructed internally from the given parameters.

§Arguments
  • input_device - The CPAL device to capture audio from.
  • output_device - The CPAL device to send processed audio to.
  • input_config - The [StreamConfig] used for the input stream.
  • output_config - The [StreamConfig] used for the output stream.
Source

pub fn new_with_handler(handler: Arc<dyn AudioHandlerTrait>) -> Self

Creates an AudioService with a custom handler.

This constructor is primarily intended for unit and integration testing, where a mock AudioHandlerTrait implementation can be injected in place of a real AudioHandler.

§Arguments
Source

pub fn start_loopback(&mut self)

Starts the audio loopback on a dedicated background thread.

On startup the service:

  1. Reads the input and output sample rates from the active AudioHandlerTrait.
  2. Selects a ResamplePolicy based on those rates (logged at info level).
  3. Builds a pair of lock-free ring buffers sized to the larger of the two rates.
  4. Asks the handler to open the input and output CPAL streams.
  5. Spawns a worker thread that:
    • Pops samples from the input buffer.
    • Routes them through the ResamplePolicy which interleaves run_dsp at the correct point (before or after resampling).
    • Pushes results into the output buffer.
    • On shutdown, flushes any remaining resampler tail before exiting.

If the loopback is already active this method is a no-op.

Source

pub fn stop_loopback(&mut self)

Stops the audio loopback and joins the background thread.

Unparks the loopback thread, signals the inner worker to shut down, and waits for both threads to finish. If the loopback is not currently active this method is a no-op.

Source

pub fn set_master_volume(&self, master_volume: f32)

Sets the master volume value.

The master volume value is atomically updated and will be read by the audio processing thread on the next sample cycle.

§Arguments
  • master_volume - The new master volume value. Must be positive (> 0.0).
§Panics

Panics if master_volume is negative or zero.

Source

pub fn set_input_device(&mut self, input: Device, input_config: StreamConfig)

Switches the audio input device without interrupting playback longer than necessary.

Constructs a new AudioHandler that pairs the given input device with the existing output device and stream config, then delegates to set_audio_handler.

§Arguments
  • input - The new CPAL input device to capture audio from.
Source

pub fn set_output_device(&mut self, output: Device, output_config: StreamConfig)

Switches the audio output device without interrupting playback longer than necessary.

Constructs a new AudioHandler that pairs the existing input device with the given output device and stream config, then delegates to set_audio_handler.

§Arguments
  • output - The new CPAL output device to send processed audio to.
Source

pub fn toggle_loopback(&mut self, is_on: bool)

Toggles the audio loopback on or off.

  • If is_on is true and the loopback is not active, start_loopback is called.
  • If is_on is false and the loopback is active, stop_loopback is called.
  • If the requested state already matches the current state, this method is a no-op.
Source

pub fn add_channel(&mut self, channel_name: String) -> u32

Adds a new channel to the channel list and return the new channel.

New channels are initialized with default values and the current_channel_id is updated to the new channel’s id.

§Arguments
  • channel_name - The name of the new channel (30 characters max).
Source

pub fn channels_mut(&mut self) -> &mut Vec<Channel>

Returns a mutable reference to the channel list, allowing channels to be modified or reordered.

Source

pub fn remove_channel(&mut self, channel_id: u32)

Removes the channel with the given id from the channel list and sets current_channel_id to 0 (default channel).

§Arguments
  • channel_id - The id of the channel to remove. Cannot be 0 (default channel).
Source

pub fn set_current_channel_id(&mut self, new_current_channel_id: u32)

Sets the current channel id, restarting the loopback if it was active to ensure the new channel’s parameters are applied.

§Arguments
  • new_current_channel_id - The id of the channel to set as current. Must exist in the channel list.
Source

pub fn buffer_size_frames(&self) -> u32

Returns the current buffer size in frames.

If the handler uses BufferSize::Default, returns 256 as a practical fallback.

Source

pub fn set_buffer_size_frames(&mut self, frames: u32) -> Result<(), String>

Updates the buffer size for both input and output streams.

Rebuilds the audio handler with a BufferSize::Fixed(frames) config and restarts the loopback if it was active.

§Arguments
  • frames - The desired buffer size in frames.
Source

pub fn apply_amp_config(&mut self, config: AmpConfigDto)

Applies a persisted amp configuration snapshot to the live service.

Restore behavior summary:

  • channels are recreated from the persisted DTOs,
  • gain, volume, tone stack, and effect-chain state are restored,
  • if the snapshot contains no channels, a default channel is created,
  • if the stored current channel no longer exists, the first restored channel becomes the active channel,
  • next_channel_id is recalculated from the restored set,
  • loopback is toggled according to config.is_active.

Note that the current JSON persistence implementation always loads with is_active = false, so persisted sessions restart with loopback turned off even though this method is capable of applying either state.

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
§

impl<T> Any for T
where T: Any,

§

fn into_any(self: Box<T>) -> Box<dyn Any>

§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

§

fn type_name(&self) -> &'static str

§

impl<T> AnySync for T
where T: Any + Send + Sync,

§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Sync + Send>

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.

§

impl<S> FromSample<S> for S

§

fn from_sample_(s: S) -> S

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
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.

§

impl<T, U> ToSample<U> for T
where U: FromSample<T>,

§

fn to_sample_(self) -> U

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

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

impl<S, T> Duplex<S> for T
where T: FromSample<S> + ToSample<S>,