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 Phaseline 126 · What the Studio is doing.enum Wholine 141 · Who is speaking into a session.struct Setupline 161 · What a live session was started with.enum Runningline 179 · The session the Studio has open, and there is at most one.struct RoomGuestline 192 · One guest in a room: the name their take is filed under, and the microphone they speak into.enum Whoseline 260 · Whose voice one recording of a take is.struct GuestTakeline 297 · What is being kept for one guest while a room take runs.enum Readingline 319 · What a running session last reported about itself.struct Studioline 333 · The Studio and the Browser.enum Keepline 2114 · Which side of the engine a take keeps.enum Renderline 2182 · What a take is to be turned into.enum Actline 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::calledline 206 · What to call this guest in slot slot, filling in a blank name.Studio::is_openline 438 · Whether the vault is open.Studio::is_veilingline 458 · Whether the veiled voice is going out.Studio::wants_a_roomline 463 · Whether the form is set to a room.Studio::want_a_roomline 473 · Switch the form between one microphone and a room.Studio::room_guestsline 481 · Who is in the room, in the order they were added.Studio::room_guest_mutline 486 · One guest, to be edited by the controls that draw them.Studio::add_guestline 494 · Add a guest, up to veilvoice_audio::MAX_GUESTS.Studio::remove_guestline 501 · Take a guest out of the room.Studio::guest_levelsline 511 · The smoothed bars for the room, one pair per guest.Studio::levelsline 522 · The smoothed levels, for the monitor strip and for this tab.Studio::troubleline 532 · What the audio path last reported about itself, and whether it is new.Studio::intrudersline 539 · The programs that took the microphone while this take has been running.Studio::note_microphone_holdersline 554 · Record which programs are holding the microphone right now.Studio::tickline 571 · Read the session's counters, once a frame, and move the levels on.
reachescatch_a_fault,is_recording,stop_veiling,finish_take,counted_interruptions,store_take,take_name,lengthStudio::start_veilingline 712 · Start veiling, keeping nothing.
reachesstart_session,sharing_a_microphoneStudio::start_roomline 733 · Roadmap item 147.
reachesstart_session,sharing_a_microphoneStudio::closeline 762 · Shut the vault and forget the key.
reachesstop_veiling,finish_take,is_recording,counted_interruptions,store_take,take_name,lengthStudio::tabline 1522 · The take half of the Recording Studio tab.
reachesis_previewing,keep_form,length,phase,say,shut_panel,start_take,stop_take,take_form,is_recording,unlock,start_sessionStudio::browserline 1653 · The Recording Browser tab.
reachesapply,counted,decoy_panel,export,length,made_on,say,shut_panel,size,play,refresh,make_decoysKeep::wants_veiledline 2126 · Whether the veiled voice is kept.Keep::wants_plainline 2134 · Whether the real voice is kept.Keep::labelline 2139 · What this is called where it is chosen.Keep::costline 2153 · What it costs, in the words the plaintext path uses.
WHAT CALLS WHAT
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
| Item | Line | Documentation |
|---|---|---|
into_secret fn | 104 | Move a typed passphrase into page-locked storage and wipe the buffer. |
default_dir pub fn | 120 | Where the vaults live: beside the lock file, in this platform's config directory. |
Phase enum | 126 | What the Studio is doing. |
Who enum | 141 | Who is speaking into a session. |
Setup struct | 161 | What a live session was started with. |
Running enum | 179 | The session the Studio has open, and there is at most one. |
RoomGuest pub struct | 192 | One guest in a room: the name their take is filed under, and the microphone they speak into. |
RoomGuest::called pub fn | 206 | What to call this guest in slot slot, filling in a blank name. |
sharing_a_microphone pub fn | 230 | Which guests are sharing a microphone, and the sentence to say about it. |
Whose pub enum | 260 | Whose voice one recording of a take is. |
take_name pub fn | 276 | What one recording of a take is called in the vault. |
GuestTake struct | 297 | What is being kept for one guest while a room take runs. |
Reading pub enum | 319 | What a running session last reported about itself. |
Studio pub struct | 333 | The Studio and the Browser. |
Studio::is_open pub fn | 438 | Whether the vault is open. |
Studio::is_recording pub fn | 450 | Whether a take is being kept. |
Studio::is_veiling pub fn | 458 | Whether the veiled voice is going out. |
Studio::wants_a_room pub fn | 463 | Whether the form is set to a room. |
Studio::want_a_room pub fn | 473 | Switch the form between one microphone and a room. |
Studio::room_guests pub fn | 481 | Who is in the room, in the order they were added. |
Studio::room_guest_mut pub fn | 486 | One guest, to be edited by the controls that draw them. |
Studio::add_guest pub fn | 494 | Add a guest, up to veilvoice_audio::MAX_GUESTS. |
Studio::remove_guest pub fn | 501 | Take a guest out of the room. |
Studio::guest_levels pub fn | 511 | The smoothed bars for the room, one pair per guest. |
Studio::is_previewing pub fn | 517 | Whether what is going out is a preview to this machine's own output rather than to the chosen one. |
Studio::levels pub fn | 522 | The smoothed levels, for the monitor strip and for this tab. |
Studio::trouble pub fn | 532 | What the audio path last reported about itself, and whether it is new. |
Studio::intruders pub fn | 539 | The programs that took the microphone while this take has been running. |
Studio::note_microphone_holders pub fn | 554 | Record which programs are holding the microphone right now. |
Studio::tick pub fn | 571 | Read the session's counters, once a frame, and move the levels on. |
Studio::catch_a_fault fn | 663 | Roadmap item 145. |
Studio::phase fn | 699 | What phase the take half of the tab is in. |
Studio::start_veiling pub fn | 712 | Start veiling, keeping nothing. |
Studio::start_room pub fn | 733 | Roadmap item 147. |
Studio::stop_veiling pub fn | 744 | Stop the audio. |
Studio::close pub fn | 762 | Shut the vault and forget the key. |
Studio::unlock fn | 791 | Derive the key from both entries and open the vault. |
Studio::measure fn | 856 | Read the folder the vaults are in: how much room is free, and how many vaults are already there. |
Studio::make_decoys fn | 869 | Make count decoys beside the open vault. |
Studio::start_take fn | 913 | Start recording into the vault's holding area. |
Studio::start_session fn | 939 | Start, or restart, the live session setup describes. |
Studio::stop_take fn | 1103 | Stop keeping, seal what was captured, and carry on veiling. |
Studio::finish_take fn | 1115 | Stop recording and seal what was captured into the vault. |
Studio::store_take fn | 1232 | Seal one recorder's audio into the vault under name. |
Studio::play fn | 1301 | Play a take, straight out of the vault and out of locked memory. |
Studio::export fn | 1347 | Turn a take into a page, a video, or both, in into. |
Studio::write_page fn | 1457 | The player page, its subtitles, and the drawing they sit in. |
Studio::refresh fn | 1500 | Re-read the listing from the vault. |
Studio::tab pub fn | 1522 | The take half of the Recording Studio tab. |
Studio::browser pub fn | 1653 | The Recording Browser tab. |
Studio::decoy_panel fn | 1881 | The decoy panel, under the listing. |
Studio::shut_panel fn | 1900 | The panel shown while the vault is shut, in both tabs. |
Studio::take_form fn | 1960 | The name field for the next take. |
Studio::keep_form fn | 1991 | Which side of the engine to keep, asked before anything starts. |
Studio::say fn | 2021 | Show the last message, if there is one. |
Studio::apply fn | 2032 | Carry out a row action. |
Keep pub enum | 2114 | Which side of the engine a take keeps. |
Keep::wants_veiled pub fn | 2126 | Whether the veiled voice is kept. |
Keep::wants_plain pub fn | 2134 | Whether the real voice is kept. |
Keep::label pub fn | 2139 | What this is called where it is chosen. |
Keep::cost pub fn | 2153 | What it costs, in the words the plaintext path uses. |
Render pub enum | 2182 | What a take is to be turned into. |
Render::wants_page fn | 2192 | |
Render::wants_video fn | 2196 | |
wav_shape fn | 2207 | The sample rate and frame count a canonical WAV header states. |
plan_for fn | 2231 | A one-speaker plan spanning a take. |
Act enum | 2250 | Something a browser row asked for. |
counted_interruptions pub fn | 2269 | "one interruption" or "three interruptions". |
counted_decoys pub fn | 2278 | "One decoy" or "four decoys", so the interface does not say "1 decoys". |
counted pub fn | 2287 | "One recording" or "four recordings", so the interface does not say "1 recordings". |
made_on pub fn | 2300 | A Unix time as a date somebody reads. |
pcm16 fn | 2324 | Sixteen-bit PCM from a WAV, as the waveform drawer wants it. |
safe_stem fn | 2339 | A file name built from what somebody called a recording. |
run_ffmpeg fn | 2362 | Run ffmpeg to put the audio in a video with a black picture. |
length pub fn | 2389 | A length in seconds, as m:ss, for somewhere a person reads. |
size pub fn | 2395 | A size in bytes, rounded to something a person can compare. |