Skip to content
9 changes: 6 additions & 3 deletions apps/desktop/src-tauri/src/deeplink_actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ use std::path::{Path, PathBuf};
use tauri::{AppHandle, Manager, Url};
use tracing::trace;

use crate::{App, ArcLock, recording::StartRecordingInputs, windows::ShowCapWindow};
use crate::{
App, ArcLock, apply_camera_input, apply_mic_input, recording::StartRecordingInputs,
windows::ShowCapWindow,
};

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
Expand Down Expand Up @@ -116,8 +119,8 @@ impl DeepLinkAction {
} => {
let state = app.state::<ArcLock<App>>();

crate::set_camera_input(app.clone(), state.clone(), camera).await?;
crate::set_mic_input(state.clone(), mic_label).await?;
apply_camera_input(app.clone(), state.clone(), camera).await?;
apply_mic_input(state.clone(), mic_label).await?;

let capture_target: ScreenCaptureTarget = match capture_mode {
CaptureMode::Screen(name) => cap_recording::screen_capture::list_displays()
Expand Down
19 changes: 17 additions & 2 deletions apps/desktop/src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,13 @@ impl App {
#[specta::specta]
#[instrument(skip(state))]
async fn set_mic_input(state: MutableState<'_, App>, label: Option<String>) -> Result<(), String> {
apply_mic_input(state, label).await
}

pub(crate) async fn apply_mic_input(
state: MutableState<'_, App>,
label: Option<String>,
) -> Result<(), String> {
let (mic_feed, studio_handle, current_label) = {
let app = state.read().await;
let handle = match app.current_recording() {
Expand Down Expand Up @@ -414,6 +421,14 @@ async fn set_camera_input(
app_handle: AppHandle,
state: MutableState<'_, App>,
id: Option<DeviceOrModelID>,
) -> Result<(), String> {
apply_camera_input(app_handle, state, id).await
}

pub(crate) async fn apply_camera_input(
app_handle: AppHandle,
state: MutableState<'_, App>,
id: Option<DeviceOrModelID>,
) -> Result<(), String> {
let app = state.read().await;
let camera_feed = app.camera_feed.clone();
Expand Down Expand Up @@ -2543,8 +2558,8 @@ pub async fn run(recording_logging_handle: LoggingHandle, logs_dir: PathBuf) {
.flatten()
.unwrap_or_default();

let _ = set_mic_input(app.state(), settings.mic_name).await;
let _ = set_camera_input(app.clone(), app.state(), settings.camera_id).await;
let _ = apply_mic_input(app.state(), settings.mic_name).await;
let _ = apply_camera_input(app.clone(), app.state(), settings.camera_id).await;

let _ = start_recording(app.clone(), app.state(), {
recording::StartRecordingInputs {
Expand Down
41 changes: 41 additions & 0 deletions apps/desktop/src-tauri/src/recording.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ use crate::{
App, CurrentRecordingChanged, MutableState, NewStudioRecordingAdded, RecordingState,
RecordingStopped, VideoUploadInfo,
api::PresignedS3PutRequestMethod,
apply_camera_input, apply_mic_input,
audio::AppSounds,
auth::AuthStore,
create_screenshot,
Expand All @@ -55,6 +56,7 @@ use crate::{
},
open_external_link,
presets::PresetsStore,
recording_settings::RecordingSettingsStore,
thumbnails::*,
upload::{
InstantMultipartUpload, build_video_meta, compress_image, create_or_get_video, upload_video,
Expand Down Expand Up @@ -349,6 +351,43 @@ pub enum RecordingAction {
UpgradeRequired,
}

async fn restore_inputs_from_store_if_missing(app: &AppHandle, state: &MutableState<'_, App>) {
let guard = state.read().await;
let recording_active = !matches!(guard.recording_state, RecordingState::None);
let needs_mic = guard.selected_mic_label.is_none();
let needs_camera = guard.selected_camera_id.is_none();
drop(guard);

if recording_active || (!needs_mic && !needs_camera) {
return;
}

let settings = match RecordingSettingsStore::get(app) {
Ok(Some(settings)) => settings,
Ok(None) => return,
Err(err) => {
warn!(%err, "Failed to load recording settings while restoring inputs");
return;
}
};

if needs_mic {
if let Some(mic) = settings.mic_name.clone() {
if let Err(err) = apply_mic_input(app.state(), Some(mic)).await {
warn!(%err, "Failed to restore microphone input");
}
}
}

if needs_camera {
if let Some(camera) = settings.camera_id.clone() {
if let Err(err) = apply_camera_input(app.clone(), app.state(), Some(camera)).await {
warn!(%err, "Failed to restore camera input");
}
}
}
}

#[tauri::command]
#[specta::specta]
#[tracing::instrument(name = "recording", skip_all)]
Expand All @@ -357,6 +396,8 @@ pub async fn start_recording(
state_mtx: MutableState<'_, App>,
inputs: StartRecordingInputs,
) -> Result<RecordingAction, String> {
restore_inputs_from_store_if_missing(&app, &state_mtx).await;

if !matches!(state_mtx.read().await.recording_state, RecordingState::None) {
return Err("Recording already in progress".to_string());
}
Expand Down
48 changes: 46 additions & 2 deletions apps/desktop/src-tauri/src/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ use tokio::sync::RwLock;
use tracing::{debug, error, instrument, warn};

use crate::{
App, ArcLock, RequestScreenCapturePrewarm, fake_window,
App, ArcLock, RequestScreenCapturePrewarm, apply_camera_input, apply_mic_input, fake_window,
general_settings::{self, AppTheme, GeneralSettingsStore},
permissions,
recording_settings::RecordingTargetMode,
recording_settings::{RecordingSettingsStore, RecordingTargetMode},
target_select_overlay::WindowFocusManager,
window_exclusion::WindowExclusion,
};
Expand Down Expand Up @@ -282,6 +282,8 @@ impl ShowCapWindow {
crate::platform::set_window_level(window.as_ref().window(), 50);
}

restore_recording_inputs_if_idle(app);

#[cfg(target_os = "macos")]
{
let app_handle = app.clone();
Expand Down Expand Up @@ -797,6 +799,48 @@ impl ShowCapWindow {
}
}

fn restore_recording_inputs_if_idle(app: &AppHandle<Wry>) {
let settings = match RecordingSettingsStore::get(app) {
Ok(Some(settings)) => settings,
Ok(None) => return,
Err(err) => {
warn!(%err, "Failed to load recording settings while restoring inputs");
return;
}
};

let mic_name = settings.mic_name.clone();
let camera_id = settings.camera_id.clone();

if mic_name.is_none() && camera_id.is_none() {
return;
}

let app_handle = app.clone();
let state = app_handle.state::<ArcLock<App>>();
let app_state = state.inner().clone();

tauri::async_runtime::spawn(async move {
if app_state.read().await.is_recording_active_or_pending() {
return;
}

if let Some(mic) = mic_name {
if let Err(err) = apply_mic_input(app_handle.state(), Some(mic)).await {
warn!(%err, "Failed to restore microphone input");
}
}

if let Some(camera) = camera_id {
if let Err(err) =
apply_camera_input(app_handle.clone(), app_handle.state(), Some(camera)).await
{
warn!(%err, "Failed to restore camera input");
}
}
});
}

#[cfg(target_os = "macos")]
fn add_traffic_lights(window: &WebviewWindow<Wry>, controls_inset: Option<LogicalPosition<f64>>) {
use crate::platform::delegates;
Expand Down
Loading
Loading