studio.rs

crates/veilvoice-gui/src/studio.rs

veilvoice-gui · 2406 lines · read the source here · or on GitHub

The Recording Studio and the Recording Browser.

Two tabs, one vault

The Studio records; the Browser is what is in the vault afterwards. They are one module because they are one vault, and a vault opened in two places is two chances to get the unlocking wrong.

Roadmap item 130: this is also where veiling as it runs happens

Live scramble was a tab of its own, and it did not need to be. The Studio has always recorded through the same veilvoice_audio::LiveSession that tab ran, with the same engine and the same routing, so the two screens were one act performed in two rooms: pick the devices over there, come here, press record.

Two sessions was the part that was actually wrong. Veiling on one tab and recording on the other opened the same microphone twice, and on the platforms that allow that at all the second stream gets a copy of the input nobody asked for. Studio::start_session is the only starter now, and a test reads this crate's source and fails if a second one appears.

The voice half of the tab is drawn by the window rather than here, because the device lists and the engine settings belong to the window. What lives in this module is the session those controls drive, and everything about the vault.

The voice half works with the vault shut. Veiling a call has never needed a recording vault, and making somebody set one up before they could disguise their voice on a call would be a worse program than the one that had two tabs.

The vault needs both passphrases, and asks for both here

veilvoice_crypto::studio::StudioKey is derived from the app lock and the at-rest passphrase, and from neither alone. That is the whole point of it: a laptop stolen while VeilVoice is unlocked opens nothing, because the at-rest passphrase was never typed.

So this tab asks for both, every time, rather than reaching into whatever the rest of the application happens to be holding. That is a deliberate inconvenience:

  • The app-lock secret is only kept for the session when Sealing::AppLock(crate::security::Sealing::AppLock) is chosen. Reading it when it happens to be there, and prompting when it is not, would make the vault's strength depend on an unrelated setting, and nobody would know which they had.
  • Prompting for both, always, is the only version of this whose security is the same on every run.

Neither passphrase is stored. Both typing buffers are wiped the moment the key is derived, and the derived key lives in page-locked memory for as long as the vault is open. Locking the window closes the vault.

What is recorded is what comes out, unless it was asked to be otherwise

The Studio records through veilvoice_audio::LiveSession::start_recording, which is the same path the command line uses, so the samples that reach the recorder are the veiled ones. That is the default and it is what Keep::Veiled means.

Roadmap item 131 adds the other two. The microphone can be kept as well, or instead, and the reasoning for allowing it at all is on Keep: refusing would not stop somebody who needs the real recording, it would move them to a phone on the table, which is a plaintext file on a device with none of this. What matters is that it is asked for rather than arrived at.

So it is a choice made before the button, never remembered between runs, reset when the window locks, and stated in the same words the plaintext path uses. The default is the safe one, and every path that has not been asked for the microphone passes None where it would go.

Each recording is assembled inside a veilvoice_crypto::Secret and handed straight to the vault to be sealed. Neither is ever a plain file, not even briefly: an unveiled take is a recording of a real voice, and it is sealed exactly as strongly as a veiled one.

In plain words

Record here, and what you record is kept locked up. Opening the cupboard needs both of your passwords at once, every time, which is what makes it worth having.

What gets recorded is the disguised voice. You can ask for your real one as well, or instead, and the screen tells you what that means before you start: anybody who can open the cupboard can then hear who was talking.

WHAT THIS FILE CONTAINS

2406 lines defining 64 functions (36 public), 12 types and 0 constants. Everything below is read out of the source, so it cannot disagree with the code.

The types it owns.

  • enum Phase line 126 · What the Studio is doing.
  • enum Who line 141 · Who is speaking into a session.
  • struct Setup line 161 · What a live session was started with.
  • enum Running line 179 · The session the Studio has open, and there is at most one.
  • struct RoomGuest line 192 · One guest in a room: the name their take is filed under, and the microphone they speak into.
  • enum Whose line 260 · Whose voice one recording of a take is.
  • struct GuestTake line 297 · What is being kept for one guest while a room take runs.
  • enum Reading line 319 · What a running session last reported about itself.
  • struct Studio line 333 · The Studio and the Browser.
  • enum Keep line 2114 · Which side of the engine a take keeps.
  • enum Render line 2182 · What a take is to be turned into.
  • enum Act line 2250 · Something a browser row asked for.

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.

  • RoomGuest::called line 206 · What to call this guest in slot slot, filling in a blank name.
  • Studio::is_open line 438 · Whether the vault is open.
  • Studio::is_veiling line 458 · Whether the veiled voice is going out.
  • Studio::wants_a_room line 463 · Whether the form is set to a room.
  • Studio::want_a_room line 473 · Switch the form between one microphone and a room.
  • Studio::room_guests line 481 · Who is in the room, in the order they were added.
  • Studio::room_guest_mut line 486 · One guest, to be edited by the controls that draw them.
  • Studio::add_guest line 494 · Add a guest, up to veilvoice_audio::MAX_GUESTS.
  • Studio::remove_guest line 501 · Take a guest out of the room.
  • Studio::guest_levels line 511 · The smoothed bars for the room, one pair per guest.
  • Studio::levels line 522 · The smoothed levels, for the monitor strip and for this tab.
  • Studio::trouble line 532 · What the audio path last reported about itself, and whether it is new.
  • Studio::intruders line 539 · The programs that took the microphone while this take has been running.
  • Studio::note_microphone_holders line 554 · Record which programs are holding the microphone right now.
  • Studio::tick line 571 · Read the session's counters, once a frame, and move the levels on.
    reaches catch_a_fault, is_recording, stop_veiling, finish_take, counted_interruptions, store_take, take_name, length
  • Studio::start_veiling line 712 · Start veiling, keeping nothing.
    reaches start_session, sharing_a_microphone
  • Studio::start_room line 733 · Roadmap item 147.
    reaches start_session, sharing_a_microphone
  • Studio::close line 762 · Shut the vault and forget the key.
    reaches stop_veiling, finish_take, is_recording, counted_interruptions, store_take, take_name, length
  • Studio::tab line 1522 · The take half of the Recording Studio tab.
    reaches is_previewing, keep_form, length, phase, say, shut_panel, start_take, stop_take, take_form, is_recording, unlock, start_session
  • Studio::browser line 1653 · The Recording Browser tab.
    reaches apply, counted, decoy_panel, export, length, made_on, say, shut_panel, size, play, refresh, make_decoys
  • Keep::wants_veiled line 2126 · Whether the veiled voice is kept.
  • Keep::wants_plain line 2134 · Whether the real voice is kept.
  • Keep::label line 2139 · What this is called where it is chosen.
  • Keep::cost line 2153 · What it costs, in the words the plaintext path uses.

WHAT CALLS WHAT

into_secret line 104 default_dir line 120 sharing_a_microphone line 230 take_name line 276 Studio::is_recording line 450 Studio::is_previewing line 517 Studio::tick line 571 Studio::catch_a_fault line 663 Studio::phase line 699 Studio::start_veiling line 712 Studio::start_room line 733 Studio::stop_veiling line 744 Studio::close line 762 Studio::unlock line 791 Studio::tab line 1522 Studio::browser line 1653 counted_interruptions line 2269 counted_decoys line 2278 counted line 2287 made_on line 2300 length line 2389 size line 2395 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. 22 of 64 functions are drawn; the diagram is bounded at 22 so it stays readable.

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. 22 of 64 functions are drawn; the diagram is bounded at 22 so it stays readable.

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_into_secret["into_secret<br/>line 104"]
    n_default_dir["default_dir<br/>line 120"]
    n_sharing_a_microphone["sharing_a_microphone<br/>line 230"]
    n_take_name["take_name<br/>line 276"]
    n_is_recording["Studio::is_recording<br/>line 450"]
    n_is_previewing["Studio::is_previewing<br/>line 517"]
    n_tick(["Studio::tick<br/>line 571"])
    n_catch_a_fault["Studio::catch_a_fault<br/>line 663"]
    n_phase["Studio::phase<br/>line 699"]
    n_start_veiling(["Studio::start_veiling<br/>line 712"])
    n_start_room(["Studio::start_room<br/>line 733"])
    n_stop_veiling["Studio::stop_veiling<br/>line 744"]
    n_close(["Studio::close<br/>line 762"])
    n_unlock["Studio::unlock<br/>line 791"]
    n_tab(["Studio::tab<br/>line 1522"])
    n_browser(["Studio::browser<br/>line 1653"])
    n_counted_interruptions["counted_interruptions<br/>line 2269"]
    n_counted_decoys["counted_decoys<br/>line 2278"]
    n_counted["counted<br/>line 2287"]
    n_made_on["made_on<br/>line 2300"]
    n_length["length<br/>line 2389"]
    n_size["size<br/>line 2395"]
    n_browser --> n_counted
    n_browser --> n_length
    n_browser --> n_made_on
    n_browser --> n_size
    n_catch_a_fault --> n_is_recording
    n_catch_a_fault --> n_stop_veiling
    n_close --> n_stop_veiling
    n_phase --> n_is_recording
    n_stop_veiling --> n_is_recording
    n_tab --> n_is_previewing
    n_tab --> n_length
    n_tab --> n_phase
    n_tick --> n_catch_a_fault
    n_tick --> n_is_recording
    n_unlock --> n_default_dir
    n_unlock --> n_into_secret
    click n_into_secret href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-gui/src/studio.rs#L104" "open the source"
    click n_default_dir href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-gui/src/studio.rs#L120" "open the source"
    click n_sharing_a_microphone href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-gui/src/studio.rs#L230" "open the source"
    click n_take_name href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-gui/src/studio.rs#L276" "open the source"
    click n_is_recording href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-gui/src/studio.rs#L450" "open the source"
    click n_is_previewing href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-gui/src/studio.rs#L517" "open the source"
    click n_tick href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-gui/src/studio.rs#L571" "open the source"
    click n_catch_a_fault href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-gui/src/studio.rs#L663" "open the source"
    click n_phase href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-gui/src/studio.rs#L699" "open the source"
    click n_start_veiling href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-gui/src/studio.rs#L712" "open the source"
    click n_start_room href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-gui/src/studio.rs#L733" "open the source"
    click n_stop_veiling href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-gui/src/studio.rs#L744" "open the source"
    click n_close href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-gui/src/studio.rs#L762" "open the source"
    click n_unlock href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-gui/src/studio.rs#L791" "open the source"
    click n_tab href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-gui/src/studio.rs#L1522" "open the source"
    click n_browser href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-gui/src/studio.rs#L1653" "open the source"
    click n_counted_interruptions href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-gui/src/studio.rs#L2269" "open the source"
    click n_counted_decoys href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-gui/src/studio.rs#L2278" "open the source"
    click n_counted href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-gui/src/studio.rs#L2287" "open the source"
    click n_made_on href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-gui/src/studio.rs#L2300" "open the source"
    click n_length href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-gui/src/studio.rs#L2389" "open the source"
    click n_size href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-gui/src/studio.rs#L2395" "open the source"
    classDef entry fill:#1f2335,stroke:#7aa2f7,color:#c0caf5
    class n_tick,n_start_veiling,n_start_room,n_close,n_tab,n_browser entry
    classDef api fill:#1f2335,stroke:#7dcfff,color:#c0caf5
    class n_default_dir,n_sharing_a_microphone,n_take_name,n_is_recording,n_is_previewing,n_stop_veiling,n_counted_interruptions,n_counted_decoys,n_counted,n_made_on,n_length,n_size api
    classDef helper fill:#1f2335,stroke:#bb9af7,color:#c0caf5
    class n_into_secret,n_catch_a_fault,n_phase,n_unlock 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
into_secret fn104Move a typed passphrase into page-locked storage and wipe the buffer.
default_dir pub fn120Where the vaults live: beside the lock file, in this platform's config directory.
Phase enum126What the Studio is doing.
Who enum141Who is speaking into a session.
Setup struct161What a live session was started with.
Running enum179The session the Studio has open, and there is at most one.
RoomGuest pub struct192One guest in a room: the name their take is filed under, and the microphone they speak into.
RoomGuest::called pub fn206What to call this guest in slot slot, filling in a blank name.
sharing_a_microphone pub fn230Which guests are sharing a microphone, and the sentence to say about it.
Whose pub enum260Whose voice one recording of a take is.
take_name pub fn276What one recording of a take is called in the vault.
GuestTake struct297What is being kept for one guest while a room take runs.
Reading pub enum319What a running session last reported about itself.
Studio pub struct333The Studio and the Browser.
Studio::is_open pub fn438Whether the vault is open.
Studio::is_recording pub fn450Whether a take is being kept.
Studio::is_veiling pub fn458Whether the veiled voice is going out.
Studio::wants_a_room pub fn463Whether the form is set to a room.
Studio::want_a_room pub fn473Switch the form between one microphone and a room.
Studio::room_guests pub fn481Who is in the room, in the order they were added.
Studio::room_guest_mut pub fn486One guest, to be edited by the controls that draw them.
Studio::add_guest pub fn494Add a guest, up to veilvoice_audio::MAX_GUESTS.
Studio::remove_guest pub fn501Take a guest out of the room.
Studio::guest_levels pub fn511The smoothed bars for the room, one pair per guest.
Studio::is_previewing pub fn517Whether what is going out is a preview to this machine's own output rather than to the chosen one.
Studio::levels pub fn522The smoothed levels, for the monitor strip and for this tab.
Studio::trouble pub fn532What the audio path last reported about itself, and whether it is new.
Studio::intruders pub fn539The programs that took the microphone while this take has been running.
Studio::note_microphone_holders pub fn554Record which programs are holding the microphone right now.
Studio::tick pub fn571Read the session's counters, once a frame, and move the levels on.
Studio::catch_a_fault fn663Roadmap item 145.
Studio::phase fn699What phase the take half of the tab is in.
Studio::start_veiling pub fn712Start veiling, keeping nothing.
Studio::start_room pub fn733Roadmap item 147.
Studio::stop_veiling pub fn744Stop the audio.
Studio::close pub fn762Shut the vault and forget the key.
Studio::unlock fn791Derive the key from both entries and open the vault.
Studio::measure fn856Read the folder the vaults are in: how much room is free, and how many vaults are already there.
Studio::make_decoys fn869Make count decoys beside the open vault.
Studio::start_take fn913Start recording into the vault's holding area.
Studio::start_session fn939Start, or restart, the live session setup describes.
Studio::stop_take fn1103Stop keeping, seal what was captured, and carry on veiling.
Studio::finish_take fn1115Stop recording and seal what was captured into the vault.
Studio::store_take fn1232Seal one recorder's audio into the vault under name.
Studio::play fn1301Play a take, straight out of the vault and out of locked memory.
Studio::export fn1347Turn a take into a page, a video, or both, in into.
Studio::write_page fn1457The player page, its subtitles, and the drawing they sit in.
Studio::refresh fn1500Re-read the listing from the vault.
Studio::tab pub fn1522The take half of the Recording Studio tab.
Studio::browser pub fn1653The Recording Browser tab.
Studio::decoy_panel fn1881The decoy panel, under the listing.
Studio::shut_panel fn1900The panel shown while the vault is shut, in both tabs.
Studio::take_form fn1960The name field for the next take.
Studio::keep_form fn1991Which side of the engine to keep, asked before anything starts.
Studio::say fn2021Show the last message, if there is one.
Studio::apply fn2032Carry out a row action.
Keep pub enum2114Which side of the engine a take keeps.
Keep::wants_veiled pub fn2126Whether the veiled voice is kept.
Keep::wants_plain pub fn2134Whether the real voice is kept.
Keep::label pub fn2139What this is called where it is chosen.
Keep::cost pub fn2153What it costs, in the words the plaintext path uses.
Render pub enum2182What a take is to be turned into.
Render::wants_page fn2192
Render::wants_video fn2196
wav_shape fn2207The sample rate and frame count a canonical WAV header states.
plan_for fn2231A one-speaker plan spanning a take.
Act enum2250Something a browser row asked for.
counted_interruptions pub fn2269"one interruption" or "three interruptions".
counted_decoys pub fn2278"One decoy" or "four decoys", so the interface does not say "1 decoys".
counted pub fn2287"One recording" or "four recordings", so the interface does not say "1 recordings".
made_on pub fn2300A Unix time as a date somebody reads.
pcm16 fn2324Sixteen-bit PCM from a WAV, as the waveform drawer wants it.
safe_stem fn2339A file name built from what somebody called a recording.
run_ffmpeg fn2362Run ffmpeg to put the audio in a video with a black picture.
length pub fn2389A length in seconds, as m:ss, for somewhere a person reads.
size pub fn2395A size in bytes, rounded to something a person can compare.