825160ee46
Chronological port of every Tauri release commit (v0.11.4 -> v0.15.2)
into the Electron rebuild, plus Discord-style audio handling that goes
beyond the Tauri original.
Highlights:
- All 17 Tauri release commits ported (audio fixes, custom notification
sound, Discord-style chat UX, profile banner, changelog page,
Discord-parity call UX, screen-share echo + re-watch UX, audio-loop
fix).
- Native napi-rs audio-loopback addon with WASAPI process-loopback:
* EXCLUDE_TARGET_PROCESS_TREE for full-screen shares -> peers
never hear themselves echoed back through the capture.
* INCLUDE_TARGET_PROCESS_TREE for window shares -> only the
picked window's audio is captured, not the whole OS mixer
(Discord parity).
* HWND -> PID resolution via Win32 GetWindowThreadProcessId.
- Discord-style screen-source picker (thumbnail grid, screens vs
apps tabs, live-refreshing thumbnails).
- Hash routing fix for packaged builds (file:// can't resolve
BrowserRouter paths).
- Tauri sources removed (apps/desktop/src-tauri).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
79 lines
2.7 KiB
TypeScript
79 lines
2.7 KiB
TypeScript
// Frontend wrapper for the main-process screen-source enumerator.
|
|
// Pre-migration this called into a Rust command that captured JPEG
|
|
// thumbnails via xcap; Electron's desktopCapturer returns thumbnails
|
|
// inline as data URLs so there's no binary/base64 dual-path to juggle.
|
|
//
|
|
// The return shape here matches the ipc-types `ScreenSource` contract.
|
|
|
|
import { isTauriRuntime } from './globalShortcut';
|
|
|
|
export type ScreenSourceKind = 'screen' | 'window';
|
|
|
|
export interface ScreenSource {
|
|
/** Chromium desktopCapturer id; feed unchanged to getUserMedia's
|
|
* chromeMediaSourceId constraint when capturing this source. */
|
|
id: string;
|
|
name: string;
|
|
kind: ScreenSourceKind;
|
|
/** Thumbnail as a ready-to-use data URL (image/png). Null when
|
|
* desktopCapturer returned an empty buffer. */
|
|
thumbnailDataUrl: string | null;
|
|
/** App icon as a data URL for window sources; null for screens. */
|
|
iconDataUrl: string | null;
|
|
displayId: number | null;
|
|
}
|
|
|
|
export async function listScreenSources(): Promise<ScreenSource[]> {
|
|
if (!isTauriRuntime()) return [];
|
|
try {
|
|
return await window.electronAPI.getScreenSources();
|
|
} catch (err: unknown) {
|
|
console.warn('getScreenSources failed', err);
|
|
return [];
|
|
}
|
|
}
|
|
|
|
// Single-source high-res refresh. Re-queries desktopCapturer at 640x360
|
|
// so a detail view looks crisp without paying the full enumeration cost
|
|
// more than once per hover-debounce.
|
|
export async function captureScreenSourceThumbnail(
|
|
sourceId: string,
|
|
): Promise<string | null> {
|
|
if (!isTauriRuntime()) return null;
|
|
try {
|
|
return await window.electronAPI.getScreenThumbnail(sourceId);
|
|
} catch (err: unknown) {
|
|
console.warn('getScreenThumbnail failed', { sourceId, err });
|
|
return null;
|
|
}
|
|
}
|
|
|
|
// Legacy name retained for call-sites that expected a Blob. desktopCapturer
|
|
// already gives us a data URL — callers that need a Blob can fetch() the
|
|
// URL. This helper keeps the old signature so nothing breaks during the
|
|
// migration.
|
|
export async function captureScreenSourceThumbnailBytes(
|
|
sourceId: string,
|
|
): Promise<Blob | null> {
|
|
const url = await captureScreenSourceThumbnail(sourceId);
|
|
if (!url) return null;
|
|
try {
|
|
const res = await fetch(url);
|
|
return await res.blob();
|
|
} catch (err: unknown) {
|
|
console.warn('thumbnail fetch failed', { sourceId, err });
|
|
return null;
|
|
}
|
|
}
|
|
|
|
// Legacy single-shot API — now just delegates to listScreenSources.
|
|
export async function enumerateScreenSources(): Promise<ScreenSource[]> {
|
|
return listScreenSources();
|
|
}
|
|
|
|
// Picker tiles bind `src={thumbnailDataUrl(src)}`; we already receive a
|
|
// data URL so this is just a pass-through for API compatibility.
|
|
export function thumbnailDataUrl(src: ScreenSource): string | null {
|
|
return src.thumbnailDataUrl;
|
|
}
|