devices.rs

crates/veilvoice-audio/src/devices.rs

veilvoice-audio · 257 lines · read the source here · or on GitHub

Enumerating audio devices, and guessing which of them are virtual cables.

What this is for

Live scrambling is only useful if the veiled voice can be routed into something else -- a call, a stream, a recorder. The way that is done on every desktop platform is a virtual audio cable: a driver that presents a playback device on one side and a microphone on the other, so anything that can select a microphone can receive VeilVoice's output.

So the list this module produces is not merely a list. Picking the wrong output device is the single most common way for live mode to appear broken while working perfectly, and the whole reason DeviceInfo::is_virtual_cable exists is to put the right entry in front of the user.

The detection is name matching, and that is a limitation, not an oversight

There is no portable way to ask an audio device whether it is virtual. CPAL does not expose it because the underlying APIs largely do not either. So VIRTUAL_CABLE_HINTS matches on name fragments, which means:

  • a cable this list has never heard of is reported as an ordinary device;
  • a real device whose name happens to contain "loopback" or "virtual" is flagged when it should not be.

Both are wrong in the harmless direction: the flag reorders and annotates a list, it never restricts what the user may choose. A heuristic that hides options would be a different and worse thing than one that highlights them, and this is deliberately the second.

The alternative -- showing an unsorted list of identically named endpoints and letting the user find the right one -- was tried and is worse.

Enumeration can fail, and does

Device lists come from the OS and are not stable: a device can disappear between being listed and being opened, a host may have no devices at all, and on Linux a machine with no sound server is entirely normal. Every function here returns a crate::Error rather than panicking or quietly returning an empty list, because an empty list and a failed query mean very different things to somebody trying to work out why they cannot be heard.

In plain words

This asks your computer which microphones and speakers it has, and works out which of them are virtual cables.

A virtual cable is a small piece of software that pretends to be a speaker on one side and a microphone on the other. It is how a veiled voice gets into a call: VeilVoice plays into the cable, and the calling program picks the cable as its microphone and never knows the difference.

Working out which device is a cable is done by recognising the names the common ones use, so it is a good guess rather than a certainty. Nothing depends on the guess being right: it decides which device is suggested, never which ones you are allowed to choose.

WHAT THIS FILE CONTAINS

257 lines defining 6 functions (4 public), 2 types and 1 constant. Everything below is read out of the source, so it cannot disagree with the code.

The types it owns.

  • enum Direction line 64 · Which direction a device carries audio.
  • struct DeviceInfo line 73 · A device the user can choose.

What happens when it runs. These are the ways in: public, and nothing else in this file calls them, so they are what an outside caller reaches first.

  • find_virtual_cable line 154 · Find the first output device that looks like a virtual audio cable.
    reaches list, looks_virtual, name_of_opt
  • name_of line 164 · The name of an opened device, or a placeholder when the OS will not say.
    reaches name_of_opt
  • open line 169 · Look up a device by exact name, or the host default when name is None.
    reaches name_of_opt

WHAT CALLS WHAT

looks_virtual line 106 name_of_opt line 116 list line 121 find_virtual_cable line 154 name_of line 164 open line 169 entry: a way in: public, and nothing in this file calls it api: public, and also used inside this file helper: private to this file dashed: a call that goes back up, or across a wrapped rank The functions this file defines, and the calls between them. An edge means the callee's name appears, called, inside the caller's body. This is a syntactic reading, not a type-resolved one.

The functions this file defines, and the calls between them. An edge means the callee's name appears, called, inside the caller's body. This is a syntactic reading, not a type-resolved one.

The same graph as Mermaid source
%%{init: {"theme":"base","themeVariables":{"background":"#1a1b26","primaryColor":"#1f2335","primaryTextColor":"#c0caf5","primaryBorderColor":"#7aa2f7","secondaryColor":"#16161e","tertiaryColor":"#16161e","lineColor":"#737aa2","textColor":"#c0caf5","mainBkg":"#1f2335","nodeBorder":"#7aa2f7","clusterBkg":"#16161e","clusterBorder":"#2f3549","fontFamily":"ui-monospace, SFMono-Regular, Consolas, monospace","fontSize":"14px"}}}%%
flowchart TD
    n_looks_virtual["looks_virtual<br/>line 106"]
    n_name_of_opt["name_of_opt<br/>line 116"]
    n_list["list<br/>line 121"]
    n_find_virtual_cable(["find_virtual_cable<br/>line 154"])
    n_name_of(["name_of<br/>line 164"])
    n_open(["open<br/>line 169"])
    n_find_virtual_cable --> n_list
    n_list --> n_looks_virtual
    n_list --> n_name_of_opt
    n_name_of --> n_name_of_opt
    n_open --> n_name_of_opt
    click n_looks_virtual href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-audio/src/devices.rs#L106" "open the source"
    click n_name_of_opt href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-audio/src/devices.rs#L116" "open the source"
    click n_list href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-audio/src/devices.rs#L121" "open the source"
    click n_find_virtual_cable href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-audio/src/devices.rs#L154" "open the source"
    click n_name_of href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-audio/src/devices.rs#L164" "open the source"
    click n_open href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-audio/src/devices.rs#L169" "open the source"
    classDef entry fill:#1f2335,stroke:#7aa2f7,color:#c0caf5
    class n_find_virtual_cable,n_name_of,n_open entry
    classDef api fill:#1f2335,stroke:#7dcfff,color:#c0caf5
    class n_list api
    classDef helper fill:#1f2335,stroke:#bb9af7,color:#c0caf5
    class n_looks_virtual,n_name_of_opt helper

This site loads no third-party script, so it cannot run Mermaid; the diagram above is the same nodes and edges drawn by the generator instead. GitHub renders the source below directly.

ITEMS

ItemLineDocumentation
Direction pub enum64Which direction a device carries audio.
DeviceInfo pub struct73A device the user can choose.
VIRTUAL_CABLE_HINTS const89Name fragments used by the common virtual audio cables.
looks_virtual fn106Whether a device's name suggests it is a virtual cable rather than real hardware.
name_of_opt fn116A device's name as the platform reports it, or None when it will not say.
list pub fn121List the devices available in one direction.
find_virtual_cable pub fn154Find the first output device that looks like a virtual audio cable.
name_of pub fn164The name of an opened device, or a placeholder when the OS will not say.
open pub fn169Look up a device by exact name, or the host default when name is None.