Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 5 additions & 10 deletions apps/desktop/src-tauri/src/target_select_overlay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -268,16 +268,11 @@ impl WindowFocusManager {
let cap_main = CapWindowId::Main.get(app);
let cap_settings = CapWindowId::Settings.get(app);

let has_cap_main = cap_main
.as_ref()
.and_then(|v| Some(v.is_minimized().ok()? || !v.is_visible().ok()?))
.unwrap_or(true);
let has_cap_settings = cap_settings
.and_then(|v| Some(v.is_minimized().ok()? || !v.is_visible().ok()?))
.unwrap_or(true);

// Close the overlay if the cap main and settings are not available.
if has_cap_main && has_cap_settings {
let main_window_available = cap_main.is_some();
let settings_window_available = cap_settings.is_some();

// Close the overlay if both cap windows are gone.
if !main_window_available && !settings_window_available {
window.hide().ok();
break;
}
Expand Down
56 changes: 53 additions & 3 deletions apps/desktop/src-tauri/src/tray.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use crate::windows::ShowCapWindow;
use crate::{RecordingStarted, RecordingStopped, RequestOpenSettings, recording};
use crate::{
RecordingStarted, RecordingStopped, RequestOpenRecordingPicker, RequestOpenSettings, recording,
recording_settings::RecordingTargetMode, windows::ShowCapWindow,
};

use std::sync::{
Arc,
Expand All @@ -18,6 +20,9 @@ use tauri_specta::Event;

pub enum TrayItem {
OpenCap,
RecordDisplay,
RecordWindow,
RecordArea,
PreviousRecordings,
PreviousScreenshots,
OpenSettings,
Expand All @@ -29,6 +34,9 @@ impl From<TrayItem> for MenuId {
fn from(value: TrayItem) -> Self {
match value {
TrayItem::OpenCap => "open_cap",
TrayItem::RecordDisplay => "record_display",
TrayItem::RecordWindow => "record_window",
TrayItem::RecordArea => "record_area",
TrayItem::PreviousRecordings => "previous_recordings",
TrayItem::PreviousScreenshots => "previous_screenshots",
TrayItem::OpenSettings => "open_settings",
Expand All @@ -45,6 +53,9 @@ impl TryFrom<MenuId> for TrayItem {
fn try_from(value: MenuId) -> Result<Self, Self::Error> {
match value.0.as_str() {
"open_cap" => Ok(TrayItem::OpenCap),
"record_display" => Ok(TrayItem::RecordDisplay),
"record_window" => Ok(TrayItem::RecordWindow),
"record_area" => Ok(TrayItem::RecordArea),
"previous_recordings" => Ok(TrayItem::PreviousRecordings),
"previous_screenshots" => Ok(TrayItem::PreviousScreenshots),
"open_settings" => Ok(TrayItem::OpenSettings),
Expand All @@ -59,7 +70,28 @@ pub fn create_tray(app: &AppHandle) -> tauri::Result<()> {
let menu = Menu::with_items(
app,
&[
&MenuItem::with_id(app, TrayItem::OpenCap, "New Recording", true, None::<&str>)?,
&MenuItem::with_id(
app,
TrayItem::OpenCap,
"Open Main Window",
true,
None::<&str>,
)?,
&MenuItem::with_id(
app,
TrayItem::RecordDisplay,
"Record Display",
true,
None::<&str>,
)?,
&MenuItem::with_id(
app,
TrayItem::RecordWindow,
"Record Window",
true,
None::<&str>,
)?,
&MenuItem::with_id(app, TrayItem::RecordArea, "Record Area", true, None::<&str>)?,
&PredefinedMenuItem::separator(app)?,
// &MenuItem::with_id(
// app,
Expand Down Expand Up @@ -109,6 +141,24 @@ pub fn create_tray(app: &AppHandle) -> tauri::Result<()> {
.await;
});
}
Ok(TrayItem::RecordDisplay) => {
let _ = RequestOpenRecordingPicker {
target_mode: Some(RecordingTargetMode::Display),
}
.emit(&app_handle);
}
Ok(TrayItem::RecordWindow) => {
let _ = RequestOpenRecordingPicker {
target_mode: Some(RecordingTargetMode::Window),
}
.emit(&app_handle);
}
Ok(TrayItem::RecordArea) => {
let _ = RequestOpenRecordingPicker {
target_mode: Some(RecordingTargetMode::Area),
}
.emit(&app_handle);
}
Ok(TrayItem::PreviousRecordings) => {
let _ = RequestOpenSettings {
page: "recordings".to_string(),
Expand Down
4 changes: 3 additions & 1 deletion apps/desktop/src-tauri/src/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,8 @@ impl ShowCapWindow {
}

if let Some(window) = self.id(app).get(app) {
window.show().ok();
window.unminimize().ok();
window.set_focus().ok();
return Ok(window);
}
Expand Down Expand Up @@ -636,7 +638,7 @@ impl ShowCapWindow {
.maximized(false)
.resizable(false)
.fullscreen(false)
.shadow(true)
.shadow(!cfg!(windows))
.always_on_top(true)
.transparent(true)
.visible_on_all_workspaces(true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { cx } from "cva";
import {
type Component,
type ComponentProps,
createEffect,
createSignal,
onMount,
Show,
} from "solid-js";
import { trackEvent } from "~/utils/analytics";
Expand Down Expand Up @@ -83,12 +83,10 @@ export function MicrophoneSelectBase(props: {
const audioLevel = () =>
(1 - Math.max((dbs() ?? 0) + DB_SCALE, 0) / DB_SCALE) ** 0.5;

// Initialize audio input if needed - only once when component mounts
onMount(() => {
createEffect(() => {
if (!props.value || !permissionGranted() || isInitialized()) return;

setIsInitialized(true);
// Ensure the selected microphone is activated so levels flow in
void handleMicrophoneChange({ name: props.value });
});

Expand Down
16 changes: 13 additions & 3 deletions apps/desktop/src/routes/(window-chrome)/new-main/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ import {
type CaptureWindowWithThumbnail,
commands,
type DeviceOrModelID,
type RecordingTargetMode,
type ScreenCaptureTarget,
} from "~/utils/tauri";
import IconLucideAppWindowMac from "~icons/lucide/app-window-mac";
Expand Down Expand Up @@ -434,10 +435,13 @@ function Page() {
createUpdateCheck();

onMount(async () => {
const targetMode = (window as any).__CAP__.initialTargetMode;
const { __CAP__ } = window as typeof window & {
__CAP__?: { initialTargetMode?: RecordingTargetMode | null };
};
const targetMode = __CAP__?.initialTargetMode ?? null;
setOptions({ targetMode });
if (rawOptions.targetMode) commands.openTargetSelectOverlays(null);
else commands.closeTargetSelectOverlays();
if (targetMode) await commands.openTargetSelectOverlays(null);
else await commands.closeTargetSelectOverlays();

const currentWindow = getCurrentWindow();

Expand Down Expand Up @@ -616,6 +620,12 @@ function Page() {
const setCamera = createCameraMutation();

onMount(() => {
if (rawOptions.micName) {
setMicInput
.mutateAsync(rawOptions.micName)
.catch((error) => console.error("Failed to set mic input:", error));
}

if (rawOptions.cameraID && "ModelID" in rawOptions.cameraID)
setCamera.mutate({ ModelID: rawOptions.cameraID.ModelID });
else if (rawOptions.cameraID && "DeviceID" in rawOptions.cameraID)
Expand Down
52 changes: 29 additions & 23 deletions apps/desktop/src/routes/editor/Player.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -382,52 +382,58 @@ function PreviewCanvas() {
<Show when={latestFrame()}>
{(currentFrame) => {
const padding = 4;
const frameWidth = () => currentFrame().width;
const frameHeight = () => currentFrame().data.height;

const containerAspect = () => {
if (containerBounds.width && containerBounds.height) {
return (
(containerBounds.width - padding * 2) /
(containerBounds.height - padding * 2)
);
}
const availableWidth = () =>
Math.max((containerBounds.width ?? 0) - padding * 2, 0);
const availableHeight = () =>
Math.max((containerBounds.height ?? 0) - padding * 2, 0);

return 1;
const containerAspect = () => {
const width = availableWidth();
const height = availableHeight();
if (width === 0 || height === 0) return 1;
return width / height;
};

const frameAspect = () =>
currentFrame().width / currentFrame().data.height;
const frameAspect = () => {
const width = frameWidth();
const height = frameHeight();
if (width === 0 || height === 0) return containerAspect();
return width / height;
};

const size = () => {
let width: number;
let height: number;
if (frameAspect() < containerAspect()) {
const height = (containerBounds.height ?? 0) - padding * 1;

return {
width: height * frameAspect(),
height,
};
height = availableHeight();
width = height * frameAspect();
} else {
width = availableWidth();
height = width / frameAspect();
}

const width = (containerBounds.width ?? 0) - padding * 2;

return {
width,
height: width / frameAspect(),
width: Math.min(width, frameWidth()),
height: Math.min(height, frameHeight()),
};
};

return (
<div class="flex overflow-hidden absolute inset-0 justify-center items-center h-full">
<canvas
style={{
width: `${size().width - padding * 2}px`,
width: `${size().width}px`,
height: `${size().height}px`,
...gridStyle,
}}
class="rounded"
ref={canvasRef}
id="canvas"
width={currentFrame().width}
height={currentFrame().data.height}
width={frameWidth()}
height={frameHeight()}
/>
</div>
);
Expand Down
11 changes: 9 additions & 2 deletions crates/recording/src/sources/screen_capture/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,14 @@ impl output_pipeline::AudioSource for SystemAudioSource {
}

fn stop(&mut self) -> impl Future<Output = anyhow::Result<()>> {
let res = self.capturer.pause().map_err(Into::into);
async { res }
let res = self.capturer.pause();

async move {
if let Err(err) = res {
warn!("system audio capturer pause failed: {err}");
}

Ok(())
}
}
}
12 changes: 10 additions & 2 deletions crates/recording/src/studio_recording.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use std::{
time::{Duration, Instant, SystemTime, UNIX_EPOCH},
};
use tokio::sync::watch;
use tracing::{Instrument, debug, error_span, info, trace};
use tracing::{Instrument, debug, error_span, info, trace, warn};

#[allow(clippy::large_enum_variant)]
enum ActorState {
Expand Down Expand Up @@ -311,12 +311,20 @@ impl Pipeline {
cursor.actor.stop();
}

let system_audio = match system_audio.transpose() {
Ok(value) => value,
Err(err) => {
warn!("system audio pipeline failed during stop: {err:#}");
None
}
};

Ok(FinishedPipeline {
start_time: self.start_time,
screen: screen.context("screen")?,
microphone: microphone.transpose().context("microphone")?,
camera: camera.transpose().context("camera")?,
system_audio: system_audio.transpose().context("system_audio")?,
system_audio,
cursor: self.cursor,
})
}
Expand Down
Loading