diff --git a/README.md b/README.md index bb9e7c1d..73047713 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ A collection of working examples showing how to use Deepgram SDKs with popular p | [290](examples/290-aws-lambda-python-transcription/) | AWS Lambda Serverless Audio Transcription | Python | AWS Lambda | | [300](examples/300-spring-boot-live-transcription-java/) | Spring Boot Real-Time Transcription with Deepgram | Java | Spring Boot | | [310](examples/310-crewai-voice-agents-python/) | CrewAI Voice-Enabled Multi-Agent System with Deepgram | Python | CrewAI | -| [340](examples/340-tauri-live-transcription-rust-ts/) | Tauri Desktop Live Transcription | Python | Tauri | +| [340](examples/340-tauri-live-transcription-rust-ts/) | Tauri Desktop Live Transcription | Rust | Tauri | | [350](examples/350-asterisk-freeswitch-deepgram-stt-python/) | Asterisk / FreeSWITCH PBX to Deepgram Streaming STT | Python | Asterisk/FreeSWITCH | | [360](examples/360-kotlin-android-live-transcription/) | Kotlin Android Live Transcription | Kotlin | Jetpack Compose | | [370](examples/370-swift-ios-live-transcription/) | Swift iOS Live Transcription | Swift | SwiftUI | diff --git a/examples/340-tauri-live-transcription-rust-ts/.gitignore b/examples/340-tauri-live-transcription-rust-ts/.gitignore new file mode 100644 index 00000000..a9c8dc83 --- /dev/null +++ b/examples/340-tauri-live-transcription-rust-ts/.gitignore @@ -0,0 +1,5 @@ +.env +src/dist/ +src/node_modules/ +src/src-tauri/gen/ +src/src-tauri/target/ diff --git a/examples/340-tauri-live-transcription-rust-ts/README.md b/examples/340-tauri-live-transcription-rust-ts/README.md index 3d049603..5aadb8cc 100644 --- a/examples/340-tauri-live-transcription-rust-ts/README.md +++ b/examples/340-tauri-live-transcription-rust-ts/README.md @@ -1,57 +1,115 @@ -# Tauri Desktop Live Transcription +# Tauri desktop live transcription -A cross-platform desktop app built with Tauri v2 that captures microphone audio, streams it to Deepgram via WebSocket for real-time transcription, and displays live captions. Tauri's Rust backend handles the Deepgram connection using the official Rust SDK, while the TypeScript frontend captures audio and renders the UI. +Build a Tauri 2 desktop application that transcribes a running application, +all system audio, or a microphone with Deepgram Nova-3. PocketStation captures +audio in Rust on macOS, Windows, and Linux. The TypeScript frontend selects the +source and displays interim and final transcripts with speaker labels. -## What you'll build - -A Tauri desktop application with a Rust backend that connects to Deepgram's live STT WebSocket using the Deepgram Rust SDK and a TypeScript frontend that captures microphone audio at 16 kHz, streams it to the backend via Tauri commands, and displays rolling live captions with interim and final results. +The application does not open a microphone unless you select **Default +microphone**. ## Prerequisites -- [Rust](https://www.rust-lang.org/tools/install) 1.70+ -- [Node.js](https://nodejs.org/) 18+ -- System WebView (WebKitGTK on Linux, WebView2 on Windows, WebKit on macOS) — see [Tauri prerequisites](https://v2.tauri.app/start/prerequisites/) -- Deepgram account — [get a free API key](https://console.deepgram.com/) - -## Environment variables +- The current stable [Rust toolchain](https://www.rust-lang.org/tools/install) +- [Node.js](https://nodejs.org/) 18 or later +- The [Tauri 2 prerequisites](https://v2.tauri.app/start/prerequisites/) for your operating system +- A [Deepgram API key](https://console.deepgram.com/) -| Variable | Where to find it | -|----------|-----------------| -| `DEEPGRAM_API_KEY` | [Deepgram console](https://console.deepgram.com/) | +## Run the application -## Install and run +Set your Deepgram API key in the shell that will start Tauri: ```bash -cp .env.example .env -# Add your DEEPGRAM_API_KEY to .env +export DEEPGRAM_API_KEY="your_api_key" +``` + +Install the frontend packages and start Tauri: +```bash cd src -npm install -npm run tauri dev +pnpm install +pnpm tauri dev ``` -## Key parameters +Choose one source in the application: + +- **Running application** captures the application name or identifier you + enter, such as `Zoom`. +- **All system audio** captures the complete desktop mix. +- **Default microphone** asks for microphone access and captures the current + default input device. + +Start the application you want to capture before clicking **Start**. If more +than one application matches the value you entered, PocketStation reports the +ambiguity instead of choosing one silently. -| Parameter | Value | Description | -|-----------|-------|-------------| -| `model` | `nova-3` | Deepgram's latest and most accurate STT model | -| `encoding` | `linear16` | 16-bit PCM audio from the microphone | -| `sample_rate` | `16000` | 16 kHz — good balance of quality and bandwidth | -| `interim_results` | `true` | Show partial transcripts as the user speaks | -| `smart_format` | `true` | Auto-capitalisation, numbers, and punctuation | -| `utterance_end_ms` | `1500` | Detect end of speech after 1.5 s of silence | +Use **Pause** to stop sending audio to Deepgram while keeping the selected +native source open. **Resume** continues with new audio; audio produced while +paused is intentionally not transcribed. + +## Permissions + +macOS asks separately for microphone access and for Screen & System Audio +Recording. Grant only the permission required by the source you selected, then +restart the example if macOS requests it. + +Windows uses native process-loopback or system-loopback capture. Linux uses +PipeWire and may display a desktop portal depending on the compositor. + +## How audio reaches Deepgram + +```text +selected native source + ↓ +PocketStation 10 ms frames at 48 kHz + ↓ +mono downmix and linear16 conversion in a PocketStation Connector + ↓ +Deepgram streaming transcription + ↓ +interim and final transcript events in Tauri +``` -## How it works +Audio stays in the Rust process. Only source selections and transcript events +cross Tauri IPC. PocketStation continues native capture while the Deepgram +worker sends frames over the network, and it reports delivery failure if the +network worker cannot keep up. + +The Deepgram request uses these settings: + +| Setting | Value | +|---|---| +| Model | `nova-3` | +| Encoding | `linear16` | +| Sample rate | `48000` | +| Channels | `1` | +| Frame duration | `10 ms` | +| Interim results | Enabled | +| Speaker diarization | Enabled | +| Smart formatting | Enabled | +| Utterance end | `1500 ms` | + +## Verify the example + +Run the source checks: + +```bash +DEEPGRAM_API_KEY=test python tests/test_example.py +``` + +Build both halves of the application: + +```bash +cd src +pnpm build +cargo test --manifest-path src-tauri/Cargo.toml --locked +``` -1. The Tauri app starts with a Rust backend and a web-based frontend rendered in the system WebView -2. When you click **Start**, the TypeScript frontend requests microphone access via `getUserMedia` at 16 kHz -3. A `ScriptProcessorNode` captures raw PCM audio and converts float32 samples to signed 16-bit linear PCM -4. Audio chunks are sent to the Rust backend via Tauri's `invoke("send_audio", ...)` IPC -5. The Rust backend connects to Deepgram's live STT WebSocket using the official `deepgram` Rust crate with `transcription().stream_request_with_options(...).handle()` -6. A `tokio::select!` loop multiplexes audio forwarding and transcript receiving on the same `WebsocketHandle` -7. Transcript events (interim and final) are emitted back to the frontend via Tauri's event system (`app.emit("transcript", ...)`) -8. The frontend renders rolling captions with final text in white and interim text in grey +For the real service check, run the application with a valid Deepgram API key, +play speech in the selected source, and confirm that interim and final text +appears before stopping the session. ## Starter templates -[deepgram-starters](https://github.com/orgs/deepgram-starters/repositories) +See the [Deepgram starter repositories](https://github.com/orgs/deepgram-starters/repositories) +for additional application templates. diff --git a/examples/340-tauri-live-transcription-rust-ts/src/index.html b/examples/340-tauri-live-transcription-rust-ts/src/index.html index a3b3b272..571a9da6 100644 --- a/examples/340-tauri-live-transcription-rust-ts/src/index.html +++ b/examples/340-tauri-live-transcription-rust-ts/src/index.html @@ -60,6 +60,29 @@ align-items: center; } + #source-controls { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 12px; + width: 100%; + max-width: 640px; + margin-bottom: 20px; + } + + label { display: grid; gap: 6px; font-size: 13px; } + + select, input { + width: 100%; + background: rgba(255, 255, 255, 0.08); + border: 1px solid rgba(255, 255, 255, 0.18); + border-radius: 8px; + color: #fff; + padding: 10px 12px; + font: inherit; + } + + [hidden] { display: none !important; } + button { background: rgba(255, 255, 255, 0.1); border: 1px solid rgba(255, 255, 255, 0.2); @@ -98,7 +121,22 @@ -

Tauri + Rust + Deepgram Nova-3

+

PocketStation + Tauri + Rust + Deepgram Nova-3

+ +
+ + +
Click Start to begin transcription...
@@ -106,7 +144,9 @@

Deepgram Live Transcription

+ + disconnected
diff --git a/examples/340-tauri-live-transcription-rust-ts/src/package.json b/examples/340-tauri-live-transcription-rust-ts/src/package.json index 2cc7b1db..f465a89d 100644 --- a/examples/340-tauri-live-transcription-rust-ts/src/package.json +++ b/examples/340-tauri-live-transcription-rust-ts/src/package.json @@ -10,10 +10,10 @@ "tauri": "tauri" }, "dependencies": { - "@tauri-apps/api": "2.2.0" + "@tauri-apps/api": "2.11.1" }, "devDependencies": { - "@tauri-apps/cli": "2.2.0", + "@tauri-apps/cli": "2.11.4", "typescript": "5.7.3", "vite": "6.4.2" } diff --git a/examples/340-tauri-live-transcription-rust-ts/src/pnpm-lock.yaml b/examples/340-tauri-live-transcription-rust-ts/src/pnpm-lock.yaml index bdc43537..7704fa96 100644 --- a/examples/340-tauri-live-transcription-rust-ts/src/pnpm-lock.yaml +++ b/examples/340-tauri-live-transcription-rust-ts/src/pnpm-lock.yaml @@ -9,12 +9,12 @@ importers: .: dependencies: '@tauri-apps/api': - specifier: 2.2.0 - version: 2.2.0 + specifier: 2.11.1 + version: 2.11.1 devDependencies: '@tauri-apps/cli': - specifier: 2.2.0 - version: 2.2.0 + specifier: 2.11.4 + version: 2.11.4 typescript: specifier: 5.7.3 version: 5.7.3 @@ -318,75 +318,82 @@ packages: cpu: [x64] os: [win32] - '@tauri-apps/api@2.2.0': - resolution: {integrity: sha512-R8epOeZl1eJEl603aUMIGb4RXlhPjpgxbGVEaqY+0G5JG9vzV/clNlzTeqc+NLYXVqXcn8mb4c5b9pJIUDEyAg==} + '@tauri-apps/api@2.11.1': + resolution: {integrity: sha512-M2FPuYND2m+wh5hfW9ZpSdxMPdEJovPBWwoHJmwUpysTYNHaOkVFN419m/K0LIgjb/7KU2vBgsUepJWugQCvAA==} - '@tauri-apps/cli-darwin-arm64@2.2.0': - resolution: {integrity: sha512-Paxq9JUj1uxV/CDr8hNnr88GcjXLmmX1yBcclQldeUoAoSgsXN1eLLS4e0CHXIzYATmcsSbcl6Zgquo4wW4e9w==} + '@tauri-apps/cli-darwin-arm64@2.11.4': + resolution: {integrity: sha512-1ryOF3ZhpZ/nemHV5zVwBQBz9jDGKmKPvWPADOhc83ig0P4bMc2iER4NbC6r9sjeIZ6RVQ4g3RZIYvezhcl4TQ==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@tauri-apps/cli-darwin-x64@2.2.0': - resolution: {integrity: sha512-BpIQxYQmg+vyS4Z4hxnAcrR95Kn2cnQbkA37NZDW0x7nnx+IFTNremU0cxATJQ3vk1PPVi3PQgrnAX5HE5aXKA==} + '@tauri-apps/cli-darwin-x64@2.11.4': + resolution: {integrity: sha512-uFsGQAAfuyz1k/yGLmkWfkBlgKAqZfxqlHmLWx81QU27RJWfmbNHCIq8T8w1e+VClleIuZUjpHWfoE4E3DLo3A==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@tauri-apps/cli-linux-arm-gnueabihf@2.2.0': - resolution: {integrity: sha512-JDYwiELRKKOStSA2QKpGiOZL4si+9ZZcwYCh7DRxnk0csM42vIv0bgcG+ucK5A/gltyDyavZgHNToxFGXaLKXA==} + '@tauri-apps/cli-linux-arm-gnueabihf@2.11.4': + resolution: {integrity: sha512-IaHZn5CdBL21oUmjiVOS1ctw6Ip1O0pjp70FwOWmYz1myWe0SY96ZIj2FYf7pT0m8bI2h/hrs5ZbEXXh44/MkQ==} engines: {node: '>= 10'} cpu: [arm] os: [linux] - '@tauri-apps/cli-linux-arm64-gnu@2.2.0': - resolution: {integrity: sha512-ITpT44YDMrg3l0ZQMTeFjj+mRzjCZAGyD3GuJ414aL5X1GWO2CHMdAHYQT9gYtH2OHlixaWq9nRJXDL7W9998w==} + '@tauri-apps/cli-linux-arm64-gnu@2.11.4': + resolution: {integrity: sha512-N41/ukTRVe6XSuUTESuFdGeOW2i7k62tK+6gHK5Kd5/q5RPvvi19GaWAVPPb9u95HSGmTChSolBfzynUsssFaA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] libc: [glibc] - '@tauri-apps/cli-linux-arm64-musl@2.2.0': - resolution: {integrity: sha512-sj/NR2O99XeatAh4UgM4MltNipoi4A8ZbMhTb1/FaGEvs/ZVrushIX69hFIyxcHu8Nbe/OkZb5b+N80A/V30jA==} + '@tauri-apps/cli-linux-arm64-musl@2.11.4': + resolution: {integrity: sha512-v277UnT/fB64xAfSroL5N3Km3tLmvATWqJJw/wRI+g6o+HkeD0slyE7gOhNs1MbjE41R7bQOTxMVoL3aomUJmw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] libc: [musl] - '@tauri-apps/cli-linux-x64-gnu@2.2.0': - resolution: {integrity: sha512-mwX7EzQLKbHZ/VzSksiOLS0uqJUVDqY58cqCj2puiGaPVgCE7bxbKcO6P3PmqYX9P8XWR2K8t922k7K44dScqA==} + '@tauri-apps/cli-linux-riscv64-gnu@2.11.4': + resolution: {integrity: sha512-qqgNkQ2u1yZHxjhxsZaxUtRDW8dIqIYm33rx/mzwQv0SfY9x1B+iraj8vWeFiXjjSVVhEMepXSOts1TqPzvXNQ==} + engines: {node: '>= 10'} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@tauri-apps/cli-linux-x64-gnu@2.11.4': + resolution: {integrity: sha512-2VRNWl84FOH0m2giiDkO2h0QXlcMJeX+zJDpI5kDIQAx6s+geF3v48F4DXfJez4GS/FdoDGnPnw1C2iYGbQ7bQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] libc: [glibc] - '@tauri-apps/cli-linux-x64-musl@2.2.0': - resolution: {integrity: sha512-9C8lVjVJPEjMZaOQdKA5SZV1NpjLP690Y9GodRMum5cIDE3T1AVrp9w6vjrsciQN42agTsO8UaREppF6OjxYnA==} + '@tauri-apps/cli-linux-x64-musl@2.11.4': + resolution: {integrity: sha512-o9GyhYor/nc7xarmwDE3ka2szuW3uuZzXjHWh64Q8YX5AtSgxdQkFWzrY4O8KiGtVNvFBI14H3Q49Qj5TOIP/A==} engines: {node: '>= 10'} cpu: [x64] os: [linux] libc: [musl] - '@tauri-apps/cli-win32-arm64-msvc@2.2.0': - resolution: {integrity: sha512-lbXYsLlvyanx1S/VSiylc6fMsDh1wnBpBid4VxscSfSPyyIOPC/p9uJvcEFWR5Caaet6vUwyJ3iKUaT5yqfsUA==} + '@tauri-apps/cli-win32-arm64-msvc@2.11.4': + resolution: {integrity: sha512-ld5Ehb598m0VkYyylRPNeCFsBe/km0jxis6KgMpl3IGY6I/i1RwQXO05I1AsXUXO2WC6AvB/Lw4qTf/asiuEiQ==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@tauri-apps/cli-win32-ia32-msvc@2.2.0': - resolution: {integrity: sha512-nlQ2iRFJTuZw5YelO2HNIsrkcZdqlt7HxdMkHJtCQkFReclpSupjbn6CrupIXHYO8NO6LcoDXiteOYhdWh0fJg==} + '@tauri-apps/cli-win32-ia32-msvc@2.11.4': + resolution: {integrity: sha512-12Hxi0XX/H5VFxO/bGgHkFWhml9VMgEOu9CidjeCeTNQ1l6fpUlbiGgSP7CLI3PFtW9/FfbeHieZ+kyWK5H7CA==} engines: {node: '>= 10'} cpu: [ia32] os: [win32] - '@tauri-apps/cli-win32-x64-msvc@2.2.0': - resolution: {integrity: sha512-MupuZwaJqJv3YsNCGD0H/98S+7106E6HChGoobuPmN87eCniSL/mSsOaa0cVmxdIAwVcSi0fuDzDBRMt8wOhHw==} + '@tauri-apps/cli-win32-x64-msvc@2.11.4': + resolution: {integrity: sha512-+vDiqBIU5dMISg/wNvX3sF+ZHfgJGJ5T0AcO+EHNXV9GGAG+P5fzodlDXD3QdKCRgZxMoCm5PPvj3BqLNjBthw==} engines: {node: '>= 10'} cpu: [x64] os: [win32] - '@tauri-apps/cli@2.2.0': - resolution: {integrity: sha512-8sA4LBU4kA73SZcL/mLjXvrpJjDqLFLQymg39FDlf3SVWyzbQxCyHBrokCLhUXLenG4qWVCl91oAImC/s47vzA==} + '@tauri-apps/cli@2.11.4': + resolution: {integrity: sha512-R8xGtMpwyetawSqm9kYOuMmEqkhUbvcUy8n0aNXIxollKBLESUu5f4Fx+64hgASYm1H+jSWq6jCW6zqTnH6hqQ==} engines: {node: '>= 10'} hasBin: true @@ -641,50 +648,54 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.60.1': optional: true - '@tauri-apps/api@2.2.0': {} + '@tauri-apps/api@2.11.1': {} + + '@tauri-apps/cli-darwin-arm64@2.11.4': + optional: true - '@tauri-apps/cli-darwin-arm64@2.2.0': + '@tauri-apps/cli-darwin-x64@2.11.4': optional: true - '@tauri-apps/cli-darwin-x64@2.2.0': + '@tauri-apps/cli-linux-arm-gnueabihf@2.11.4': optional: true - '@tauri-apps/cli-linux-arm-gnueabihf@2.2.0': + '@tauri-apps/cli-linux-arm64-gnu@2.11.4': optional: true - '@tauri-apps/cli-linux-arm64-gnu@2.2.0': + '@tauri-apps/cli-linux-arm64-musl@2.11.4': optional: true - '@tauri-apps/cli-linux-arm64-musl@2.2.0': + '@tauri-apps/cli-linux-riscv64-gnu@2.11.4': optional: true - '@tauri-apps/cli-linux-x64-gnu@2.2.0': + '@tauri-apps/cli-linux-x64-gnu@2.11.4': optional: true - '@tauri-apps/cli-linux-x64-musl@2.2.0': + '@tauri-apps/cli-linux-x64-musl@2.11.4': optional: true - '@tauri-apps/cli-win32-arm64-msvc@2.2.0': + '@tauri-apps/cli-win32-arm64-msvc@2.11.4': optional: true - '@tauri-apps/cli-win32-ia32-msvc@2.2.0': + '@tauri-apps/cli-win32-ia32-msvc@2.11.4': optional: true - '@tauri-apps/cli-win32-x64-msvc@2.2.0': + '@tauri-apps/cli-win32-x64-msvc@2.11.4': optional: true - '@tauri-apps/cli@2.2.0': + '@tauri-apps/cli@2.11.4': optionalDependencies: - '@tauri-apps/cli-darwin-arm64': 2.2.0 - '@tauri-apps/cli-darwin-x64': 2.2.0 - '@tauri-apps/cli-linux-arm-gnueabihf': 2.2.0 - '@tauri-apps/cli-linux-arm64-gnu': 2.2.0 - '@tauri-apps/cli-linux-arm64-musl': 2.2.0 - '@tauri-apps/cli-linux-x64-gnu': 2.2.0 - '@tauri-apps/cli-linux-x64-musl': 2.2.0 - '@tauri-apps/cli-win32-arm64-msvc': 2.2.0 - '@tauri-apps/cli-win32-ia32-msvc': 2.2.0 - '@tauri-apps/cli-win32-x64-msvc': 2.2.0 + '@tauri-apps/cli-darwin-arm64': 2.11.4 + '@tauri-apps/cli-darwin-x64': 2.11.4 + '@tauri-apps/cli-linux-arm-gnueabihf': 2.11.4 + '@tauri-apps/cli-linux-arm64-gnu': 2.11.4 + '@tauri-apps/cli-linux-arm64-musl': 2.11.4 + '@tauri-apps/cli-linux-riscv64-gnu': 2.11.4 + '@tauri-apps/cli-linux-x64-gnu': 2.11.4 + '@tauri-apps/cli-linux-x64-musl': 2.11.4 + '@tauri-apps/cli-win32-arm64-msvc': 2.11.4 + '@tauri-apps/cli-win32-ia32-msvc': 2.11.4 + '@tauri-apps/cli-win32-x64-msvc': 2.11.4 '@types/estree@1.0.8': {} diff --git a/examples/340-tauri-live-transcription-rust-ts/src/src-tauri/Cargo.lock b/examples/340-tauri-live-transcription-rust-ts/src/src-tauri/Cargo.lock index 7df7af2b..7137cdea 100644 --- a/examples/340-tauri-live-transcription-rust-ts/src/src-tauri/Cargo.lock +++ b/examples/340-tauri-live-transcription-rust-ts/src/src-tauri/Cargo.lock @@ -32,6 +32,28 @@ dependencies = [ "alloc-no-stdlib", ] +[[package]] +name = "alsa" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812947049edcd670a82cd5c73c3661d2e58468577ba8489de58e1a73c04cbd5d" +dependencies = [ + "alsa-sys", + "bitflags 2.11.0", + "cfg-if", + "libc", +] + +[[package]] +name = "alsa-sys" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad7569085a265dd3f607ebecce7458eaab2132a84393534c95b18dcbc3f31e04" +dependencies = [ + "libc", + "pkg-config", +] + [[package]] name = "android_system_properties" version = "0.1.5" @@ -41,6 +63,22 @@ dependencies = [ "libc", ] +[[package]] +name = "annotate-snippets" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "710e8eae58854cdc1790fcb56cca04d712a17be849eeb81da2a724bf4bae2bc4" +dependencies = [ + "anstyle", + "unicode-width", +] + +[[package]] +name = "anstyle" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" + [[package]] name = "anyhow" version = "1.0.102" @@ -78,7 +116,7 @@ dependencies = [ "glib-sys", "gobject-sys", "libc", - "system-deps", + "system-deps 6.2.2", ] [[package]] @@ -127,6 +165,25 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "bindgen" +version = "0.72.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" +dependencies = [ + "annotate-snippets", + "bitflags 2.11.0", + "cexpr", + "clang-sys", + "itertools", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.117", +] + [[package]] name = "bit-set" version = "0.8.0" @@ -245,7 +302,7 @@ checksum = "685c9fa8e590b8b3d678873528d83411db17242a73fccaed827770ea0fedda51" dependencies = [ "glib-sys", "libc", - "system-deps", + "system-deps 6.2.2", ] [[package]] @@ -308,6 +365,15 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom 7.1.3", +] + [[package]] name = "cfb" version = "0.7.3" @@ -326,7 +392,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" dependencies = [ "smallvec", - "target-lexicon", + "target-lexicon 0.12.16", +] + +[[package]] +name = "cfg-expr" +version = "0.20.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe4ece8474b5f766c63426647e7b4b316b67431ade1036a8313cee24a03ae917" +dependencies = [ + "smallvec", + "target-lexicon 0.13.5", ] [[package]] @@ -353,6 +429,17 @@ dependencies = [ "windows-link 0.2.1", ] +[[package]] +name = "clang-sys" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "157a8ba7b480713b56f4c09fd13fc3e0a22a5dfab8097ba61cbc5feef950788a" +dependencies = [ + "glob", + "libc", + "libloading 0.8.9", +] + [[package]] name = "cmake" version = "0.1.58" @@ -372,12 +459,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "convert_case" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" - [[package]] name = "cookie" version = "0.18.1" @@ -388,6 +469,12 @@ dependencies = [ "version_check", ] +[[package]] +name = "cookie-factory" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9885fa71e26b8ab7855e2ec7cae6e9b380edff76cd052e07c683a0319d51b3a2" + [[package]] name = "core-foundation" version = "0.10.1" @@ -428,6 +515,50 @@ dependencies = [ "libc", ] +[[package]] +name = "coreaudio-rs" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5d7dca3ebcf65a035582c9ad4385371a9d9ee6537474d2a278f4e1e475bb58" +dependencies = [ + "bitflags 2.11.0", + "libc", + "objc2-audio-toolbox", + "objc2-core-audio", + "objc2-core-audio-types", + "objc2-core-foundation", +] + +[[package]] +name = "cpal" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f02e8d0327b42d3e2e4ab2119af397344eb9fc54a34bf0ddeaa1277af8681f1" +dependencies = [ + "alsa", + "block2", + "coreaudio-rs", + "dasp_sample", + "jni 0.22.4", + "js-sys", + "libc", + "mach2", + "ndk", + "ndk-context", + "num-derive", + "num-traits", + "objc2", + "objc2-audio-toolbox", + "objc2-avf-audio", + "objc2-core-audio", + "objc2-core-audio-types", + "objc2-core-foundation", + "objc2-foundation", + "web-sys", + "windows 0.62.2", + "windows-core 0.62.2", +] + [[package]] name = "cpufeatures" version = "0.2.17" @@ -471,23 +602,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "cssparser" -version = "0.29.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93d03419cb5950ccfd3daf3ff1c7a36ace64609a1a8746d493df1ca0afde0fa" -dependencies = [ - "cssparser-macros", - "dtoa-short", - "itoa", - "matches", - "phf 0.10.1", - "proc-macro2", - "quote", - "smallvec", - "syn 1.0.109", -] - [[package]] name = "cssparser" version = "0.36.0" @@ -497,7 +611,7 @@ dependencies = [ "cssparser-macros", "dtoa-short", "itoa", - "phf 0.13.1", + "phf", "smallvec", ] @@ -513,14 +627,20 @@ dependencies = [ [[package]] name = "ctor" -version = "0.2.9" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" +checksum = "352d39c2f7bef1d6ad73db6f5160efcaed66d94ef8c6c573a8410c00bf909a98" dependencies = [ - "quote", - "syn 2.0.117", + "ctor-proc-macro", + "dtor", ] +[[package]] +name = "ctor-proc-macro" +version = "0.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52560adf09603e58c9a7ee1fe1dcb95a16927b17c127f0ac02d6e768a0e25bc1" + [[package]] name = "darling" version = "0.23.0" @@ -555,17 +675,34 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "dasp_sample" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c87e182de0887fd5361989c677c4e8f5000cd9491d6d563161a8f3a5519fc7f" + [[package]] name = "data-encoding" version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" +[[package]] +name = "dbus" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ab69f03cc8c4340c9c8e315114e1658e6775a9b16a04357973aa21cec22b32e" +dependencies = [ + "libc", + "libdbus-sys", + "windows-sys 0.61.2", +] + [[package]] name = "deepgram" -version = "0.9.2" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b4b3ba8223aa3a88fad716198d988ff87b50b564b99ba1933afac2f9f08d829" +checksum = "12466522a157634afeed95a738f129f5f0fc2e1af855d9550921eeec1182e1a1" dependencies = [ "anyhow", "bytes", @@ -593,7 +730,7 @@ name = "deepgram-tauri-live-transcription" version = "0.1.0" dependencies = [ "deepgram", - "dotenvy", + "pocketstation", "serde", "serde_json", "tauri", @@ -611,19 +748,6 @@ dependencies = [ "serde_core", ] -[[package]] -name = "derive_more" -version = "0.99.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f" -dependencies = [ - "convert_case", - "proc-macro2", - "quote", - "rustc_version", - "syn 2.0.117", -] - [[package]] name = "derive_more" version = "2.1.1" @@ -673,7 +797,7 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -729,20 +853,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "521e380c0c8afb8d9a1e83a1822ee03556fc3e3e7dbc1fd30be14e37f9cb3f89" dependencies = [ "bit-set", - "cssparser 0.36.0", + "cssparser", "foldhash 0.2.0", - "html5ever 0.38.0", + "html5ever", "precomputed-hash", - "selectors 0.36.1", - "tendril 0.5.0", + "selectors", + "tendril", ] -[[package]] -name = "dotenvy" -version = "0.15.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" - [[package]] name = "dpi" version = "0.1.2" @@ -767,6 +885,21 @@ dependencies = [ "dtoa", ] +[[package]] +name = "dtor" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1057d6c64987086ff8ed0fd3fbf377a6b7d205cc7715868cd401705f715cbe4" +dependencies = [ + "dtor-proc-macro", +] + +[[package]] +name = "dtor-proc-macro" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f678cf4a922c215c63e0de95eb1ff08a958a81d47e485cf9da1e27bf6305cfa5" + [[package]] name = "dunce" version = "1.0.5" @@ -779,6 +912,12 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" +[[package]] +name = "either" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "252afb9ae5eaa683babdc6a068b3f5726eb19e05070c731f9b2a23a7c3e8ed34" + [[package]] name = "embed-resource" version = "3.0.8" @@ -823,7 +962,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -927,16 +1066,6 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" -[[package]] -name = "futf" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" -dependencies = [ - "mac", - "new_debug_unreachable", -] - [[package]] name = "futures" version = "0.3.32" @@ -1025,15 +1154,6 @@ dependencies = [ "slab", ] -[[package]] -name = "fxhash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" -dependencies = [ - "byteorder", -] - [[package]] name = "gdk" version = "0.18.2" @@ -1072,7 +1192,7 @@ dependencies = [ "glib-sys", "gobject-sys", "libc", - "system-deps", + "system-deps 6.2.2", ] [[package]] @@ -1089,7 +1209,7 @@ dependencies = [ "libc", "pango-sys", "pkg-config", - "system-deps", + "system-deps 6.2.2", ] [[package]] @@ -1103,7 +1223,7 @@ dependencies = [ "gobject-sys", "libc", "pkg-config", - "system-deps", + "system-deps 6.2.2", ] [[package]] @@ -1129,7 +1249,7 @@ dependencies = [ "gdk-sys", "glib-sys", "libc", - "system-deps", + "system-deps 6.2.2", "x11", ] @@ -1143,17 +1263,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - [[package]] name = "getrandom" version = "0.2.17" @@ -1163,7 +1272,7 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "wasi 0.11.1+wasi-snapshot-preview1", + "wasi", "wasm-bindgen", ] @@ -1222,7 +1331,7 @@ dependencies = [ "glib-sys", "gobject-sys", "libc", - "system-deps", + "system-deps 6.2.2", "winapi", ] @@ -1270,7 +1379,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "063ce2eb6a8d0ea93d2bf8ba1957e78dbab6be1c2220dd3daca57d5a9d869898" dependencies = [ "libc", - "system-deps", + "system-deps 6.2.2", ] [[package]] @@ -1287,7 +1396,7 @@ checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44" dependencies = [ "glib-sys", "libc", - "system-deps", + "system-deps 6.2.2", ] [[package]] @@ -1326,7 +1435,7 @@ dependencies = [ "gobject-sys", "libc", "pango-sys", - "system-deps", + "system-deps 6.2.2", ] [[package]] @@ -1382,16 +1491,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] -name = "html5ever" -version = "0.29.1" +name = "hound" +version = "3.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b7410cae13cbc75623c98ac4cbfd1f0bedddf3227afc24f370cf0f50a44a11c" -dependencies = [ - "log", - "mac", - "markup5ever 0.14.1", - "match_token", -] +checksum = "62adaabb884c94955b19907d60019f4e145d091c75345379e70d1ee696f7854f" [[package]] name = "html5ever" @@ -1400,7 +1503,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1054432bae2f14e0061e33d23402fbaa67a921d319d56adc6bcf887ddad1cbc2" dependencies = [ "log", - "markup5ever 0.38.0", + "markup5ever", ] [[package]] @@ -1513,7 +1616,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core 0.62.2", + "windows-core 0.61.2", ] [[package]] @@ -1532,7 +1635,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e795dff5605e0f04bff85ca41b51a96b83e80b281e96231bcaaf1ac35103371" dependencies = [ "byteorder", - "png", + "png 0.17.16", ] [[package]] @@ -1698,6 +1801,15 @@ dependencies = [ "serde", ] +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.18" @@ -1724,7 +1836,7 @@ dependencies = [ "glib-sys", "gobject-sys", "libc", - "system-deps", + "system-deps 6.2.2", ] [[package]] @@ -1743,6 +1855,36 @@ dependencies = [ "windows-sys 0.45.0", ] +[[package]] +name = "jni" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498" +dependencies = [ + "cfg-if", + "combine", + "jni-macros", + "jni-sys 0.4.1", + "log", + "simd_cesu8", + "thiserror 2.0.18", + "walkdir", + "windows-link 0.2.1", +] + +[[package]] +name = "jni-macros" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "simd_cesu8", + "syn 2.0.117", +] + [[package]] name = "jni-sys" version = "0.3.1" @@ -1826,18 +1968,6 @@ dependencies = [ "unicode-segmentation", ] -[[package]] -name = "kuchikiki" -version = "0.8.8-speedreader" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02cb977175687f33fa4afa0c95c112b987ea1443e5a51c8f8ff27dc618270cc2" -dependencies = [ - "cssparser 0.29.6", - "html5ever 0.29.1", - "indexmap 2.13.1", - "selectors 0.24.0", -] - [[package]] name = "leb128fmt" version = "0.1.0" @@ -1864,7 +1994,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e9ec52138abedcc58dc17a7c6c0c00a2bdb4f3427c7f63fa97fd0d859155caf" dependencies = [ "gtk-sys", - "libloading", + "libloading 0.7.4", "once_cell", ] @@ -1874,6 +2004,15 @@ version = "0.2.184" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48f5d2a454e16a5ea0f4ced81bd44e4cfc7bd3a507b61887c99fd3538b28e4af" +[[package]] +name = "libdbus-sys" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "328c4789d42200f1eeec05bd86c9c13c7f091d2ba9a6ea35acdf51f31bc0f043" +dependencies = [ + "pkg-config", +] + [[package]] name = "libloading" version = "0.7.4" @@ -1884,6 +2023,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "libloading" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" +dependencies = [ + "cfg-if", + "windows-link 0.2.1", +] + [[package]] name = "libredox" version = "0.1.15" @@ -1893,6 +2042,39 @@ dependencies = [ "libc", ] +[[package]] +name = "libspa" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "882f7427e7989dcc9d388b7f05c4630390a1d7696f9ffa469cd4a7a48f0b4c40" +dependencies = [ + "bitflags 2.11.0", + "cc", + "cookie-factory", + "libc", + "libspa-sys", + "nom 8.0.0", + "rustix", + "system-deps 7.0.8", +] + +[[package]] +name = "libspa-sys" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b6e17bdaf63ed0d5e4144022624032b41fd9733112e8c74ac26fc9bf1291924" +dependencies = [ + "bindgen", + "cc", + "system-deps 7.0.8", +] + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + [[package]] name = "litemap" version = "0.8.2" @@ -1921,24 +2103,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" [[package]] -name = "mac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" - -[[package]] -name = "markup5ever" -version = "0.14.1" +name = "mach2" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7a7213d12e1864c0f002f52c2923d4556935a43dec5e71355c2760e0f6e7a18" -dependencies = [ - "log", - "phf 0.11.3", - "phf_codegen 0.11.3", - "string_cache 0.8.9", - "string_cache_codegen 0.5.4", - "tendril 0.4.3", -] +checksum = "dae608c151f68243f2b000364e1f7b186d9c29845f7d2d85bd31b9ad77ad552b" [[package]] name = "markup5ever" @@ -1947,27 +2115,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8983d30f2915feeaaab2d6babdd6bc7e9ed1a00b66b5e6d74df19aa9c0e91862" dependencies = [ "log", - "tendril 0.5.0", + "tendril", "web_atoms", ] -[[package]] -name = "match_token" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "matches" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" - [[package]] name = "memchr" version = "2.8.0" @@ -1989,6 +2140,12 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" version = "0.8.9" @@ -2006,15 +2163,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" dependencies = [ "libc", - "wasi 0.11.1+wasi-snapshot-preview1", + "wasi", "windows-sys 0.61.2", ] [[package]] name = "muda" -version = "0.17.2" +version = "0.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c9fec5a4e89860383d778d10563a605838f8f0b2f9303868937e5ff32e86177" +checksum = "1dd04e60bc0b07438a6771710ee1698f98f6ebbc7f89b61264af1563b8aeb878" dependencies = [ "crossbeam-channel", "dpi", @@ -2025,10 +2182,10 @@ dependencies = [ "objc2-core-foundation", "objc2-foundation", "once_cell", - "png", + "png 0.18.1", "serde", "thiserror 2.0.18", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -2068,10 +2225,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" [[package]] -name = "nodrop" -version = "0.1.14" +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "nom" +version = "8.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" +checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405" +dependencies = [ + "memchr", +] [[package]] name = "num-conv" @@ -2079,6 +2249,26 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967" +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "num-integer" +version = "0.1.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ce2d95d4b3734dc35aa2f45e1aa22cd416814592a4f9d9205e11affd5b8e10b" +dependencies = [ + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -2133,6 +2323,76 @@ dependencies = [ "objc2-foundation", ] +[[package]] +name = "objc2-audio-toolbox" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6948501a91121d6399b79abaa33a8aa4ea7857fe019f341b8c23ad6e81b79b08" +dependencies = [ + "bitflags 2.11.0", + "libc", + "objc2", + "objc2-core-audio", + "objc2-core-audio-types", + "objc2-core-foundation", + "objc2-foundation", +] + +[[package]] +name = "objc2-avf-audio" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13a380031deed8e99db00065c45937da434ca987c034e13b87e4441f9e4090be" +dependencies = [ + "bitflags 2.11.0", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-cloud-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ad74d880bb43877038da939b7427bba67e9dd42004a18b809ba7d87cee241c" +dependencies = [ + "bitflags 2.11.0", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-audio" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1eebcea8b0dbff5f7c8504f3107c68fc061a3eb44932051c8cf8a68d969c3b2" +dependencies = [ + "dispatch2", + "objc2", + "objc2-core-audio-types", + "objc2-core-foundation", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-audio-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a89f2ec274a0cf4a32642b2991e8b351a404d290da87bb6a9a9d8632490bd1c" +dependencies = [ + "bitflags 2.11.0", + "objc2", +] + +[[package]] +name = "objc2-core-data" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b402a653efbb5e82ce4df10683b6b28027616a2715e90009947d50b8dd298fa" +dependencies = [ + "objc2", + "objc2-foundation", +] + [[package]] name = "objc2-core-foundation" version = "0.3.2" @@ -2140,7 +2400,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" dependencies = [ "bitflags 2.11.0", + "block2", "dispatch2", + "libc", "objc2", ] @@ -2157,6 +2419,38 @@ dependencies = [ "objc2-io-surface", ] +[[package]] +name = "objc2-core-image" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d563b38d2b97209f8e861173de434bd0214cf020e3423a52624cd1d989f006" +dependencies = [ + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-location" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca347214e24bc973fc025fd0d36ebb179ff30536ed1f80252706db19ee452009" +dependencies = [ + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-text" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde0dfb48d25d2b4862161a4d5fcc0e3c24367869ad306b0c9ec0073bfed92d" +dependencies = [ + "bitflags 2.11.0", + "objc2", + "objc2-core-foundation", + "objc2-core-graphics", +] + [[package]] name = "objc2-encode" version = "4.1.0" @@ -2180,6 +2474,7 @@ checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" dependencies = [ "bitflags 2.11.0", "block2", + "libc", "objc2", "objc2-core-foundation", ] @@ -2214,8 +2509,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22" dependencies = [ "bitflags 2.11.0", + "block2", "objc2", + "objc2-cloud-kit", + "objc2-core-data", "objc2-core-foundation", + "objc2-core-graphics", + "objc2-core-image", + "objc2-core-location", + "objc2-core-text", + "objc2-foundation", + "objc2-quartz-core", + "objc2-user-notifications", +] + +[[package]] +name = "objc2-user-notifications" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9df9128cbbfef73cda168416ccf7f837b62737d748333bfe9ab71c245d76613e" +dependencies = [ + "objc2", "objc2-foundation", ] @@ -2273,7 +2587,7 @@ dependencies = [ "glib-sys", "gobject-sys", "libc", - "system-deps", + "system-deps 6.2.2", ] [[package]] @@ -2305,105 +2619,25 @@ version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" -[[package]] -name = "phf" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" -dependencies = [ - "phf_shared 0.8.0", -] - -[[package]] -name = "phf" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" -dependencies = [ - "phf_macros 0.10.0", - "phf_shared 0.10.0", - "proc-macro-hack", -] - -[[package]] -name = "phf" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" -dependencies = [ - "phf_macros 0.11.3", - "phf_shared 0.11.3", -] - [[package]] name = "phf" version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" dependencies = [ - "phf_macros 0.13.1", - "phf_shared 0.13.1", + "phf_macros", + "phf_shared", "serde", ] -[[package]] -name = "phf_codegen" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815" -dependencies = [ - "phf_generator 0.8.0", - "phf_shared 0.8.0", -] - -[[package]] -name = "phf_codegen" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" -dependencies = [ - "phf_generator 0.11.3", - "phf_shared 0.11.3", -] - [[package]] name = "phf_codegen" version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49aa7f9d80421bca176ca8dbfebe668cc7a2684708594ec9f3c0db0805d5d6e1" dependencies = [ - "phf_generator 0.13.1", - "phf_shared 0.13.1", -] - -[[package]] -name = "phf_generator" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" -dependencies = [ - "phf_shared 0.8.0", - "rand 0.7.3", -] - -[[package]] -name = "phf_generator" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" -dependencies = [ - "phf_shared 0.10.0", - "rand 0.8.5", -] - -[[package]] -name = "phf_generator" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" -dependencies = [ - "phf_shared 0.11.3", - "rand 0.8.5", + "phf_generator", + "phf_shared", ] [[package]] @@ -2413,34 +2647,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737" dependencies = [ "fastrand", - "phf_shared 0.13.1", -] - -[[package]] -name = "phf_macros" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58fdf3184dd560f160dd73922bea2d5cd6e8f064bf4b13110abd81b03697b4e0" -dependencies = [ - "phf_generator 0.10.0", - "phf_shared 0.10.0", - "proc-macro-hack", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "phf_macros" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" -dependencies = [ - "phf_generator 0.11.3", - "phf_shared 0.11.3", - "proc-macro2", - "quote", - "syn 2.0.117", + "phf_shared", ] [[package]] @@ -2449,47 +2656,20 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef" dependencies = [ - "phf_generator 0.13.1", - "phf_shared 0.13.1", + "phf_generator", + "phf_shared", "proc-macro2", "quote", "syn 2.0.117", ] -[[package]] -name = "phf_shared" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" -dependencies = [ - "siphasher 0.3.11", -] - -[[package]] -name = "phf_shared" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" -dependencies = [ - "siphasher 0.3.11", -] - -[[package]] -name = "phf_shared" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" -dependencies = [ - "siphasher 1.0.2", -] - [[package]] name = "phf_shared" version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" dependencies = [ - "siphasher 1.0.2", + "siphasher", ] [[package]] @@ -2518,6 +2698,31 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" +[[package]] +name = "pipewire" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bde71084c4e25959d68f1ea54daa75e5ecdb338e5caf0b5510143b79baa32d5c" +dependencies = [ + "bitflags 2.11.0", + "libc", + "libspa", + "libspa-sys", + "pipewire-sys", + "rustix", +] + +[[package]] +name = "pipewire-sys" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce653f53e63e5b93853218092ee9a8906a5d082c92f3f1db26316955dd63ce0" +dependencies = [ + "bindgen", + "libspa-sys", + "system-deps 7.0.8", +] + [[package]] name = "pkg-config" version = "0.3.32" @@ -2550,6 +2755,41 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "png" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61" +dependencies = [ + "bitflags 2.11.0", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "pocketstation" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eeb23694072ba182d17175e966fe75c67a18632de517e7d78d6197af3d23a127" +dependencies = [ + "cc", + "cpal", + "hound", + "libc", + "libloading 0.8.9", + "pipewire", + "rtrb", + "serde", + "serde_json", + "thiserror 1.0.69", + "tokio", + "wasapi", + "windows 0.58.0", + "windows-core 0.58.0", +] + [[package]] name = "potential_utf" version = "0.1.5" @@ -2643,12 +2883,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "proc-macro-hack" -version = "0.5.20+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" - [[package]] name = "proc-macro2" version = "1.0.106" @@ -2697,7 +2931,7 @@ dependencies = [ "bytes", "getrandom 0.3.4", "lru-slab", - "rand 0.9.2", + "rand", "ring", "rustc-hash", "rustls", @@ -2720,7 +2954,7 @@ dependencies = [ "once_cell", "socket2", "tracing", - "windows-sys 0.60.2", + "windows-sys 0.59.0", ] [[package]] @@ -2744,59 +2978,14 @@ version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom 0.1.16", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc", - "rand_pcg", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] - [[package]] name = "rand" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ - "rand_chacha 0.9.0", - "rand_core 0.9.5", -] - -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core 0.6.4", + "rand_chacha", + "rand_core", ] [[package]] @@ -2806,52 +2995,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core 0.9.5", -] - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom 0.2.17", -] - -[[package]] -name = "rand_core" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" -dependencies = [ - "getrandom 0.3.4", -] - -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core 0.5.1", + "rand_core", ] [[package]] -name = "rand_pcg" -version = "0.2.1" +name = "rand_core" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" dependencies = [ - "rand_core 0.5.1", + "getrandom 0.3.4", ] [[package]] @@ -2984,6 +3137,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rtrb" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fae8ee26b0371a29a77d2b2d6b3ae13aa81def6f9bf1b1b92a32d279a5e709b7" + [[package]] name = "rustc-hash" version = "2.1.2" @@ -2999,6 +3158,19 @@ dependencies = [ "semver", ] +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags 2.11.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.59.0", +] + [[package]] name = "rustls" version = "0.23.37" @@ -3043,7 +3215,7 @@ checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784" dependencies = [ "core-foundation", "core-foundation-sys", - "jni", + "jni 0.21.1", "log", "once_cell", "rustls", @@ -3053,7 +3225,7 @@ dependencies = [ "security-framework", "security-framework-sys", "webpki-root-certs", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -3184,24 +3356,6 @@ dependencies = [ "libc", ] -[[package]] -name = "selectors" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c37578180969d00692904465fb7f6b3d50b9a2b952b87c23d0e2e5cb5013416" -dependencies = [ - "bitflags 1.3.2", - "cssparser 0.29.6", - "derive_more 0.99.20", - "fxhash", - "log", - "phf 0.8.0", - "phf_codegen 0.8.0", - "precomputed-hash", - "servo_arc 0.2.0", - "smallvec", -] - [[package]] name = "selectors" version = "0.36.1" @@ -3209,15 +3363,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c5d9c0c92a92d33f08817311cf3f2c29a3538a8240e94a6a3c622ce652d7e00c" dependencies = [ "bitflags 2.11.0", - "cssparser 0.36.0", - "derive_more 2.1.1", + "cssparser", + "derive_more", "log", "new_debug_unreachable", - "phf 0.13.1", - "phf_codegen 0.13.1", + "phf", + "phf_codegen", "precomputed-hash", "rustc-hash", - "servo_arc 0.4.3", + "servo_arc", "smallvec", ] @@ -3391,16 +3545,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "servo_arc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52aa42f8fdf0fed91e5ce7f23d8138441002fa31dca008acf47e6fd4721f741" -dependencies = [ - "nodrop", - "stable_deref_trait", -] - [[package]] name = "servo_arc" version = "0.4.3" @@ -3468,10 +3612,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" [[package]] -name = "siphasher" -version = "0.3.11" +name = "simd_cesu8" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11031e251abf8611c80f460e19dbdeb54a66db918e49c65a7065b46ac7aec520" +dependencies = [ + "rustc_version", + "simdutf8", +] + +[[package]] +name = "simdutf8" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" [[package]] name = "siphasher" @@ -3546,7 +3700,7 @@ dependencies = [ "glib-sys", "gobject-sys", "libc", - "system-deps", + "system-deps 6.2.2", ] [[package]] @@ -3555,19 +3709,6 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" -[[package]] -name = "string_cache" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f" -dependencies = [ - "new_debug_unreachable", - "parking_lot", - "phf_shared 0.11.3", - "precomputed-hash", - "serde", -] - [[package]] name = "string_cache" version = "0.9.0" @@ -3576,30 +3717,18 @@ checksum = "a18596f8c785a729f2819c0f6a7eae6ebeebdfffbfe4214ae6b087f690e31901" dependencies = [ "new_debug_unreachable", "parking_lot", - "phf_shared 0.13.1", + "phf_shared", "precomputed-hash", ] -[[package]] -name = "string_cache_codegen" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c711928715f1fe0fe509c53b43e993a9a557babc2d0a3567d0a3006f1ac931a0" -dependencies = [ - "phf_generator 0.11.3", - "phf_shared 0.11.3", - "proc-macro2", - "quote", -] - [[package]] name = "string_cache_codegen" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "585635e46db231059f76c5849798146164652513eb9e8ab2685939dd90f29b69" dependencies = [ - "phf_generator 0.13.1", - "phf_shared 0.13.1", + "phf_generator", + "phf_shared", "proc-macro2", "quote", ] @@ -3634,7 +3763,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", - "quote", "unicode-ident", ] @@ -3675,46 +3803,61 @@ version = "6.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" dependencies = [ - "cfg-expr", + "cfg-expr 0.15.8", "heck 0.5.0", "pkg-config", "toml 0.8.2", "version-compare", ] +[[package]] +name = "system-deps" +version = "7.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "396a35feb67335377e0251fcbc1092fc85c484bd4e3a7a54319399da127796e7" +dependencies = [ + "cfg-expr 0.20.9", + "heck 0.5.0", + "pkg-config", + "toml 1.1.2+spec-1.1.0", + "version-compare", +] + [[package]] name = "tao" -version = "0.34.8" +version = "0.35.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9103edf55f2da3c82aea4c7fab7c4241032bfeea0e71fa557d98e00e7ce7cc20" +checksum = "d1c93047acf68669466a34690ac58cca7010bd1b201e1ec86f1fd0a75d3dd4a9" dependencies = [ "bitflags 2.11.0", "block2", "core-foundation", "core-graphics", "crossbeam-channel", + "dbus", "dispatch2", "dlopen2", "dpi", "gdkwayland-sys", "gdkx11-sys", "gtk", - "jni", + "jni 0.21.1", "libc", "log", "ndk", - "ndk-context", "ndk-sys", "objc2", "objc2-app-kit", "objc2-foundation", + "objc2-ui-kit", "once_cell", "parking_lot", + "percent-encoding", "raw-window-handle", "tao-macros", "unicode-segmentation", "url", - "windows", + "windows 0.61.3", "windows-core 0.61.2", "windows-version", "x11-dl", @@ -3737,11 +3880,17 @@ version = "0.12.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" +[[package]] +name = "target-lexicon" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca" + [[package]] name = "tauri" -version = "2.10.3" +version = "2.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da77cc00fb9028caf5b5d4650f75e31f1ef3693459dfca7f7e506d1ecef0ba2d" +checksum = "667b20e2726d572dea2de7370da16e188eb06008faf9a92fab7cdc46791190b5" dependencies = [ "anyhow", "bytes", @@ -3754,7 +3903,7 @@ dependencies = [ "gtk", "heck 0.5.0", "http", - "jni", + "jni 0.21.1", "libc", "log", "mime", @@ -3785,14 +3934,14 @@ dependencies = [ "webkit2gtk", "webview2-com", "window-vibrancy", - "windows", + "windows 0.61.3", ] [[package]] name = "tauri-build" -version = "2.5.6" +version = "2.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bbc990d1dbf57a8e1c7fa2327f2a614d8b757805603c1b9ba5c81bade09fd4d" +checksum = "bc9ce40b16101cb6ea63d3e221567affd1c3a9205f95d7bc574941a10636b632" dependencies = [ "anyhow", "cargo_toml", @@ -3806,22 +3955,21 @@ dependencies = [ "serde_json", "tauri-utils", "tauri-winres", - "toml 0.9.12+spec-1.1.0", "walkdir", ] [[package]] name = "tauri-codegen" -version = "2.5.5" +version = "2.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4a24476afd977c5d5d169f72425868613d82747916dd29e0a357c84c4bd6d29" +checksum = "08279169ff42f8fc45a1dbc9dcae888893ba95288142e5880c59b93a26d2cfc5" dependencies = [ "base64 0.22.1", "brotli", "ico", "json-patch", "plist", - "png", + "png 0.17.16", "proc-macro2", "quote", "semver", @@ -3839,9 +3987,9 @@ dependencies = [ [[package]] name = "tauri-macros" -version = "2.5.5" +version = "2.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d39b349a98dadaffebb73f0a40dcd1f23c999211e5a2e744403db384d0c33de7" +checksum = "e8b394794f399a421811d06966343e7933fcae92d59f5180b9388d1174497a45" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -3853,15 +4001,15 @@ dependencies = [ [[package]] name = "tauri-runtime" -version = "2.10.1" +version = "2.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2826d79a3297ed08cd6ea7f412644ef58e32969504bc4fbd8d7dbeabc4445ea2" +checksum = "b0b4bc95aed361b0019067d189a1174a603d460d0f6c72606512d59fc9c12ec8" dependencies = [ "cookie", "dpi", "gtk", "http", - "jni", + "jni 0.21.1", "objc2", "objc2-ui-kit", "objc2-web-kit", @@ -3873,18 +4021,18 @@ dependencies = [ "url", "webkit2gtk", "webview2-com", - "windows", + "windows 0.61.3", ] [[package]] name = "tauri-runtime-wry" -version = "2.10.1" +version = "2.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e11ea2e6f801d275fdd890d6c9603736012742a1c33b96d0db788c9cdebf7f9e" +checksum = "4e6fac707727b7a2f48e4ded90976324267371073edbb415ffb73bb0458d203f" dependencies = [ "gtk", "http", - "jni", + "jni 0.21.1", "log", "objc2", "objc2-app-kit", @@ -3898,30 +4046,30 @@ dependencies = [ "url", "webkit2gtk", "webview2-com", - "windows", + "windows 0.61.3", "wry", ] [[package]] name = "tauri-utils" -version = "2.8.3" +version = "2.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "219a1f983a2af3653f75b5747f76733b0da7ff03069c7a41901a5eb3ace4557d" +checksum = "3e176a18e67764923c4f1ce66f25ae4abe5f688384d5eb1a0fa6c77f3d90f887" dependencies = [ "anyhow", "brotli", "cargo_metadata", "ctor", + "dom_query", "dunce", "glob", - "html5ever 0.29.1", "http", "infer", "json-patch", - "kuchikiki", "log", "memchr", - "phf 0.11.3", + "phf", + "plist", "proc-macro2", "quote", "regex", @@ -3933,7 +4081,7 @@ dependencies = [ "serde_with", "swift-rs", "thiserror 2.0.18", - "toml 0.9.12+spec-1.1.0", + "toml 1.1.2+spec-1.1.0", "url", "urlpattern", "uuid", @@ -3951,17 +4099,6 @@ dependencies = [ "toml 0.9.12+spec-1.1.0", ] -[[package]] -name = "tendril" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" -dependencies = [ - "futf", - "mac", - "utf-8", -] - [[package]] name = "tendril" version = "0.5.0" @@ -4173,6 +4310,21 @@ dependencies = [ "winnow 0.7.15", ] +[[package]] +name = "toml" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee" +dependencies = [ + "indexmap 2.13.1", + "serde_core", + "serde_spanned 1.1.1", + "toml_datetime 1.1.1+spec-1.1.0", + "toml_parser", + "toml_writer", + "winnow 1.0.1", +] + [[package]] name = "toml_datetime" version = "0.6.3" @@ -4329,9 +4481,9 @@ dependencies = [ [[package]] name = "tray-icon" -version = "0.21.3" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e85aa143ceb072062fc4d6356c1b520a51d636e7bc8e77ec94be3608e5e80c" +checksum = "045979e3f037cd18ad1cb2a419dfda133c5c29c9f3453370079f2255d46c257e" dependencies = [ "crossbeam-channel", "dirs", @@ -4343,10 +4495,10 @@ dependencies = [ "objc2-core-graphics", "objc2-foundation", "once_cell", - "png", + "png 0.18.1", "serde", "thiserror 2.0.18", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -4366,7 +4518,7 @@ dependencies = [ "http", "httparse", "log", - "rand 0.9.2", + "rand", "rustls", "rustls-pki-types", "sha1", @@ -4439,6 +4591,12 @@ version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c" +[[package]] +name = "unicode-width" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" + [[package]] name = "unicode-xid" version = "0.2.6" @@ -4552,10 +4710,17 @@ dependencies = [ ] [[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" +name = "wasapi" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" +checksum = "80c3aa5d6b0e7acc3ea10cb19c334df0c8d825060f14a30d9e3b03385e6e5175" +dependencies = [ + "log", + "num-integer", + "thiserror 2.0.18", + "windows 0.62.2", + "windows-core 0.62.2", +] [[package]] name = "wasi" @@ -4709,10 +4874,10 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57a9779e9f04d2ac1ce317aee707aa2f6b773afba7b931222bff6983843b1576" dependencies = [ - "phf 0.13.1", - "phf_codegen 0.13.1", - "string_cache 0.9.0", - "string_cache_codegen 0.6.1", + "phf", + "phf_codegen", + "string_cache", + "string_cache_codegen", ] [[package]] @@ -4756,7 +4921,7 @@ dependencies = [ "libc", "pkg-config", "soup3-sys", - "system-deps", + "system-deps 6.2.2", ] [[package]] @@ -4794,10 +4959,10 @@ checksum = "7130243a7a5b33c54a444e54842e6a9e133de08b5ad7b5861cd8ed9a6a5bc96a" dependencies = [ "webview2-com-macros", "webview2-com-sys", - "windows", + "windows 0.61.3", "windows-core 0.61.2", - "windows-implement", - "windows-interface", + "windows-implement 0.60.2", + "windows-interface 0.59.3", ] [[package]] @@ -4818,7 +4983,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "381336cfffd772377d291702245447a5251a2ffa5bad679c99e61bc48bacbf9c" dependencies = [ "thiserror 2.0.18", - "windows", + "windows 0.61.3", "windows-core 0.61.2", ] @@ -4844,7 +5009,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -4868,17 +5033,39 @@ dependencies = [ "windows-version", ] +[[package]] +name = "windows" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" +dependencies = [ + "windows-core 0.58.0", + "windows-targets 0.52.6", +] + [[package]] name = "windows" version = "0.61.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" dependencies = [ - "windows-collections", + "windows-collections 0.2.0", "windows-core 0.61.2", - "windows-future", + "windows-future 0.2.1", "windows-link 0.1.3", - "windows-numerics", + "windows-numerics 0.2.0", +] + +[[package]] +name = "windows" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580" +dependencies = [ + "windows-collections 0.3.2", + "windows-core 0.62.2", + "windows-future 0.3.2", + "windows-numerics 0.3.1", ] [[package]] @@ -4890,14 +5077,36 @@ dependencies = [ "windows-core 0.61.2", ] +[[package]] +name = "windows-collections" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610" +dependencies = [ + "windows-core 0.62.2", +] + +[[package]] +name = "windows-core" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" +dependencies = [ + "windows-implement 0.58.0", + "windows-interface 0.58.0", + "windows-result 0.2.0", + "windows-strings 0.1.0", + "windows-targets 0.52.6", +] + [[package]] name = "windows-core" version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" dependencies = [ - "windows-implement", - "windows-interface", + "windows-implement 0.60.2", + "windows-interface 0.59.3", "windows-link 0.1.3", "windows-result 0.3.4", "windows-strings 0.4.2", @@ -4909,8 +5118,8 @@ version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ - "windows-implement", - "windows-interface", + "windows-implement 0.60.2", + "windows-interface 0.59.3", "windows-link 0.2.1", "windows-result 0.4.1", "windows-strings 0.5.1", @@ -4924,7 +5133,29 @@ checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" dependencies = [ "windows-core 0.61.2", "windows-link 0.1.3", - "windows-threading", + "windows-threading 0.1.0", +] + +[[package]] +name = "windows-future" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb" +dependencies = [ + "windows-core 0.62.2", + "windows-link 0.2.1", + "windows-threading 0.2.1", +] + +[[package]] +name = "windows-implement" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", ] [[package]] @@ -4938,6 +5169,17 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "windows-interface" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "windows-interface" version = "0.59.3" @@ -4971,6 +5213,25 @@ dependencies = [ "windows-link 0.1.3", ] +[[package]] +name = "windows-numerics" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26" +dependencies = [ + "windows-core 0.62.2", + "windows-link 0.2.1", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-result" version = "0.3.4" @@ -4989,6 +5250,16 @@ dependencies = [ "windows-link 0.2.1", ] +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result 0.2.0", + "windows-targets 0.52.6", +] + [[package]] name = "windows-strings" version = "0.4.2" @@ -5034,15 +5305,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows-sys" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" -dependencies = [ - "windows-targets 0.53.5", -] - [[package]] name = "windows-sys" version = "0.61.2" @@ -5076,7 +5338,7 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", + "windows_i686_gnullvm", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", @@ -5084,29 +5346,21 @@ dependencies = [ ] [[package]] -name = "windows-targets" -version = "0.53.5" +name = "windows-threading" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" dependencies = [ - "windows-link 0.2.1", - "windows_aarch64_gnullvm 0.53.1", - "windows_aarch64_msvc 0.53.1", - "windows_i686_gnu 0.53.1", - "windows_i686_gnullvm 0.53.1", - "windows_i686_msvc 0.53.1", - "windows_x86_64_gnu 0.53.1", - "windows_x86_64_gnullvm 0.53.1", - "windows_x86_64_msvc 0.53.1", + "windows-link 0.1.3", ] [[package]] name = "windows-threading" -version = "0.1.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" +checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37" dependencies = [ - "windows-link 0.1.3", + "windows-link 0.2.1", ] [[package]] @@ -5130,12 +5384,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" - [[package]] name = "windows_aarch64_msvc" version = "0.42.2" @@ -5148,12 +5396,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" - [[package]] name = "windows_i686_gnu" version = "0.42.2" @@ -5166,24 +5408,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" -[[package]] -name = "windows_i686_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" - [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" - [[package]] name = "windows_i686_msvc" version = "0.42.2" @@ -5196,12 +5426,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_i686_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" - [[package]] name = "windows_x86_64_gnu" version = "0.42.2" @@ -5214,12 +5438,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" - [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" @@ -5232,12 +5450,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" - [[package]] name = "windows_x86_64_msvc" version = "0.42.2" @@ -5250,12 +5462,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" -[[package]] -name = "windows_x86_64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" - [[package]] name = "winnow" version = "0.5.40" @@ -5386,9 +5592,9 @@ checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" [[package]] name = "wry" -version = "0.54.4" +version = "0.55.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5a8135d8676225e5744de000d4dff5a082501bf7db6a1c1495034f8c314edbc" +checksum = "186f9871daa55fd9c016578b810d149de58367113db7fb72b462d2323ce19514" dependencies = [ "base64 0.22.1", "block2", @@ -5402,7 +5608,7 @@ dependencies = [ "gtk", "http", "javascriptcore-rs", - "jni", + "jni 0.21.1", "libc", "ndk", "objc2", @@ -5422,7 +5628,7 @@ dependencies = [ "webkit2gtk", "webkit2gtk-sys", "webview2-com", - "windows", + "windows 0.61.3", "windows-core 0.61.2", "windows-version", "x11-dl", diff --git a/examples/340-tauri-live-transcription-rust-ts/src/src-tauri/Cargo.toml b/examples/340-tauri-live-transcription-rust-ts/src/src-tauri/Cargo.toml index d9fa963b..ec6abe63 100644 --- a/examples/340-tauri-live-transcription-rust-ts/src/src-tauri/Cargo.toml +++ b/examples/340-tauri-live-transcription-rust-ts/src/src-tauri/Cargo.toml @@ -4,12 +4,20 @@ version = "0.1.0" edition = "2021" [dependencies] -deepgram = "=0.9.2" -dotenvy = "=0.15.7" +deepgram = { version = "=0.10.1", default-features = false, features = ["listen"] } serde = { version = "=1.0.228", features = ["derive"] } serde_json = "=1.0.149" -tauri = { version = "=2.10.3", features = [] } +tauri = { version = "=2.11.5", features = [] } tokio = { version = "=1.51.0", features = ["full"] } [build-dependencies] -tauri-build = { version = "=2.5.6", features = [] } +tauri-build = { version = "=2.6.3", features = [] } + +[target.'cfg(target_os = "macos")'.dependencies] +pocketstation = { version = "=1.1.10", default-features = false, features = ["coreaudio-capture"] } + +[target.'cfg(target_os = "windows")'.dependencies] +pocketstation = { version = "=1.1.10", default-features = false, features = ["wasapi-capture"] } + +[target.'cfg(target_os = "linux")'.dependencies] +pocketstation = { version = "=1.1.10", default-features = false, features = ["pipewire-capture"] } diff --git a/examples/340-tauri-live-transcription-rust-ts/src/src-tauri/Info.plist b/examples/340-tauri-live-transcription-rust-ts/src/src-tauri/Info.plist new file mode 100644 index 00000000..5ff5d9a4 --- /dev/null +++ b/examples/340-tauri-live-transcription-rust-ts/src/src-tauri/Info.plist @@ -0,0 +1,10 @@ + + + + + NSMicrophoneUsageDescription + Capture microphone audio for live transcription. + NSScreenCaptureUsageDescription + Capture application or system audio for live transcription. + + diff --git a/examples/340-tauri-live-transcription-rust-ts/src/src-tauri/icons/icon.ico b/examples/340-tauri-live-transcription-rust-ts/src/src-tauri/icons/icon.ico new file mode 100644 index 00000000..9790e7ab Binary files /dev/null and b/examples/340-tauri-live-transcription-rust-ts/src/src-tauri/icons/icon.ico differ diff --git a/examples/340-tauri-live-transcription-rust-ts/src/src-tauri/icons/icon.png b/examples/340-tauri-live-transcription-rust-ts/src/src-tauri/icons/icon.png new file mode 100644 index 00000000..0808302c Binary files /dev/null and b/examples/340-tauri-live-transcription-rust-ts/src/src-tauri/icons/icon.png differ diff --git a/examples/340-tauri-live-transcription-rust-ts/src/src-tauri/icons/icon.svg b/examples/340-tauri-live-transcription-rust-ts/src/src-tauri/icons/icon.svg new file mode 100644 index 00000000..a571bd1c --- /dev/null +++ b/examples/340-tauri-live-transcription-rust-ts/src/src-tauri/icons/icon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/examples/340-tauri-live-transcription-rust-ts/src/src-tauri/src/main.rs b/examples/340-tauri-live-transcription-rust-ts/src/src-tauri/src/main.rs index 446f9f8d..fe7a0675 100644 --- a/examples/340-tauri-live-transcription-rust-ts/src/src-tauri/src/main.rs +++ b/examples/340-tauri-live-transcription-rust-ts/src/src-tauri/src/main.rs @@ -3,28 +3,191 @@ use deepgram::common::options::{Encoding, Model, Options}; use deepgram::common::stream_response::StreamResponse; use deepgram::Deepgram; +use pocketstation::connector::{ + Connector, ConnectorError, ConnectorErrorCode, ConnectorErrorStage, ConnectorRetryability, +}; +use pocketstation::{AudioFrameDuration, Session, SessionEventKind, SessionEventReceive, Source}; +use serde::Deserialize; use std::env; +use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; +use std::time::Duration; use tauri::{AppHandle, Emitter, State}; -use tokio::sync::{mpsc, Mutex}; +use tokio::sync::{mpsc, oneshot, Mutex}; struct AppState { - // Channel for sending audio bytes to the Deepgram worker task. - // None when no transcription session is active. - audio_tx: Arc>>>>, + active: Mutex>, +} + +struct ActiveTranscription { + stop: Arc, + paused: Arc, +} + +#[derive(Clone, Deserialize)] +#[serde(rename_all = "snake_case")] +enum CaptureSource { + Application, + SystemAudio, + Microphone, +} + +#[derive(Clone, Deserialize)] +struct CaptureRequest { + source: CaptureSource, + application: Option, +} + +impl CaptureRequest { + fn source(&self) -> Result { + match self.source { + CaptureSource::Application => { + let application = self + .application + .as_deref() + .map(str::trim) + .filter(|value| !value.is_empty()) + .ok_or_else(|| "Enter a running application name or identifier".to_string())?; + Ok(Source::application(application)) + } + CaptureSource::SystemAudio => Ok(Source::system_audio()), + CaptureSource::Microphone => Ok(Source::microphone_default()), + } + } + + fn label(&self) -> &'static str { + match self.source { + CaptureSource::Application => "application", + CaptureSource::SystemAudio => "system audio", + CaptureSource::Microphone => "microphone", + } + } +} + +fn pcm16_mono(samples: &[f32], channels: u8) -> Result, &'static str> { + let channels = usize::from(channels); + if channels == 0 { + return Err("PocketStation returned an invalid channel layout"); + } + + let frames = samples.chunks_exact(channels); + if !frames.remainder().is_empty() { + return Err("PocketStation returned an invalid channel layout"); + } + + let mut output = Vec::with_capacity(samples.len() / channels * 2); + for frame in frames { + let sample = frame.iter().copied().sum::() / channels as f32; + let sample = sample.clamp(-1.0, 1.0); + let value = if sample < 0.0 { + (sample * 32_768.0) as i16 + } else { + (sample * 32_767.0) as i16 + }; + output.extend_from_slice(&value.to_le_bytes()); + } + Ok(output) +} + +fn delivery_error(message: impl Into) -> ConnectorError { + ConnectorError::new( + ConnectorErrorCode::new("deepgram.audio_queue_unavailable") + .expect("the example error code is valid"), + ConnectorErrorStage::Delivery, + ConnectorRetryability::Retryable, + message, + ) + .expect("the example error message is valid") +} + +fn run_capture( + app: AppHandle, + request: CaptureRequest, + audio_tx: mpsc::Sender>, + stop: Arc, + paused: Arc, +) -> Result<(), String> { + let session = Session::builder() + .audio_frame_duration(AudioFrameDuration::Ms10) + .build(); + let destination = session + .destination( + Connector::from_audio_fn(move |frame| { + if paused.load(Ordering::Acquire) { + return Ok(()); + } + if frame.sample_rate_hz() != 48_000 { + return Err(delivery_error(format!( + "Deepgram expects 48000 Hz audio; PocketStation returned {} Hz", + frame.sample_rate_hz() + ))); + } + let data = pcm16_mono(frame.samples(), frame.channels()).map_err(delivery_error)?; + audio_tx + .try_send(data) + .map_err(|error| delivery_error(error.to_string())) + }) + .map_err(|error| error.to_string())?, + ) + .map_err(|error| error.to_string())?; + session + .capture(request.source()?) + .map_err(|error| error.to_string())? + .send(destination) + .map_err(|error| error.to_string())?; + + let mut running = session.start().map_err(|error| error.to_string())?; + let _ = app.emit("capture-status", format!("capturing {}", request.label())); + let mut runtime_error = None; + while !stop.load(Ordering::Acquire) { + if let SessionEventReceive::Event(event) = running.try_recv_event() { + match event.kind() { + SessionEventKind::Source(_) + | SessionEventKind::Endpoint(_) + | SessionEventKind::Rollback(_) + | SessionEventKind::Finalization(_) => { + runtime_error = Some(format!( + "PocketStation reported {kind:?}", + kind = event.kind() + )); + break; + } + SessionEventKind::Lifecycle(_) | SessionEventKind::Terminal(_) => {} + } + } + std::thread::sleep(Duration::from_millis(20)); + } + + if let Some(error) = runtime_error { + let outcome = running.cancel(); + if outcome.is_success() { + Err(error) + } else { + Err(format!( + "{error}; PocketStation cancellation failed: {outcome:?}" + )) + } + } else { + let outcome = running.stop(); + if !outcome.is_success() { + Err(format!("PocketStation did not stop cleanly: {outcome:?}")) + } else { + Ok(()) + } + } } -// Runs the Deepgram WebSocket session: forwards audio from the mpsc channel -// to Deepgram and emits transcript events back to the Tauri frontend. async fn run_session( app: AppHandle, api_key: String, - mut audio_rx: mpsc::Receiver>, + request: CaptureRequest, + stop: Arc, + paused: Arc, ) { let dg = match Deepgram::new(&api_key) { - Ok(d) => d, - Err(e) => { - let _ = app.emit("dg-error", e.to_string()); + Ok(deepgram) => deepgram, + Err(error) => { + let _ = app.emit("dg-error", error.to_string()); return; } }; @@ -33,14 +196,15 @@ async fn run_session( .model(Model::Nova3) .smart_format(true) .punctuate(true) - .tag(["deepgram-examples"]) // <- THIS tags usage for Deepgram console tracking + .diarize(true) + .tag(["deepgram-examples"]) .build(); let mut handle = match dg .transcription() .stream_request_with_options(options) .encoding(Encoding::Linear16) - .sample_rate(16000) + .sample_rate(48000) .channels(1) .interim_results(true) .utterance_end_ms(1500) @@ -48,31 +212,54 @@ async fn run_session( .handle() .await { - Ok(h) => h, - Err(e) => { - let _ = app.emit("dg-error", e.to_string()); + Ok(handle) => handle, + Err(error) => { + let _ = app.emit("dg-error", error.to_string()); return; } }; + let (audio_tx, mut audio_rx) = mpsc::channel::>(32); + let (capture_done_tx, mut capture_done_rx) = oneshot::channel(); + let capture_app = app.clone(); + let capture_stop = Arc::clone(&stop); + let capture_paused = Arc::clone(&paused); + tokio::task::spawn_blocking(move || { + let result = run_capture(capture_app, request, audio_tx, capture_stop, capture_paused); + let _ = capture_done_tx.send(result); + }); + let _ = app.emit("dg-status", "connected"); + let mut capture_finished = false; - // Single loop that multiplexes audio sending and response receiving. - // tokio::select! lets us await both the audio channel and the Deepgram - // WebSocket concurrently without needing to split the handle. loop { tokio::select! { biased; + capture = &mut capture_done_rx => { + capture_finished = true; + match capture { + Ok(Ok(())) => { + let _ = handle.close_stream().await; + } + Ok(Err(error)) => { + let _ = app.emit("dg-error", error); + } + Err(error) => { + let _ = app.emit("dg-error", error.to_string()); + } + } + break; + } + audio = audio_rx.recv() => { match audio { Some(data) => { - if let Err(e) = handle.send_data(data).await { - let _ = app.emit("dg-error", e.to_string()); + if let Err(error) = handle.send_data(data).await { + let _ = app.emit("dg-error", error.to_string()); break; } } - // Frontend closed the channel — finalize None => { let _ = handle.close_stream().await; break; @@ -80,24 +267,24 @@ async fn run_session( } } - resp = handle.receive() => { - match resp { + response = handle.receive() => { + match response { Some(Ok(StreamResponse::TranscriptResponse { channel, is_final, speech_final, .. })) => { - // channel.alternatives[0].transcript holds the text - if let Some(alt) = channel.alternatives.first() { - if !alt.transcript.is_empty() { + if let Some(alternative) = channel.alternatives.first() { + if !alternative.transcript.is_empty() { let _ = app.emit( "transcript", serde_json::json!({ - "text": alt.transcript, + "text": alternative.transcript, "is_final": is_final, "speech_final": speech_final, - "confidence": alt.confidence, + "confidence": alternative.confidence, + "speaker": alternative.words.first().and_then(|word| word.speaker), }), ); } @@ -111,8 +298,8 @@ async fn run_session( let _ = app.emit("utterance-end", ""); } Some(Ok(_)) => {} - Some(Err(e)) => { - let _ = app.emit("dg-error", e.to_string()); + Some(Err(error)) => { + let _ = app.emit("dg-error", error.to_string()); break; } None => { @@ -124,6 +311,12 @@ async fn run_session( } } + stop.store(true, Ordering::Release); + if !capture_finished { + if let Ok(Err(error)) = capture_done_rx.await { + let _ = app.emit("dg-error", error); + } + } let _ = app.emit("dg-status", "disconnected"); } @@ -131,65 +324,77 @@ async fn run_session( async fn start_transcription( app: AppHandle, state: State<'_, AppState>, + request: CaptureRequest, ) -> Result<(), String> { - let api_key = env::var("DEEPGRAM_API_KEY") - .map_err(|_| "DEEPGRAM_API_KEY not set".to_string())?; + let api_key = + env::var("DEEPGRAM_API_KEY").map_err(|_| "DEEPGRAM_API_KEY is not set".to_string())?; - // Stop any existing session first + let stop = Arc::new(AtomicBool::new(false)); + let paused = Arc::new(AtomicBool::new(false)); { - let mut tx_guard = state.audio_tx.lock().await; - tx_guard.take(); - } - - // Buffered channel — frontend sends audio chunks here; the worker - // forwards them to Deepgram's WebSocket. - let (audio_tx, audio_rx) = mpsc::channel::>(512); - - { - let mut tx_guard = state.audio_tx.lock().await; - *tx_guard = Some(audio_tx); + let mut active = state.active.lock().await; + if let Some(previous) = active.replace(ActiveTranscription { + stop: Arc::clone(&stop), + paused: Arc::clone(&paused), + }) { + previous.stop.store(true, Ordering::Release); + } } - tokio::spawn(run_session(app, api_key, audio_rx)); - + tokio::spawn(run_session(app, api_key, request, stop, paused)); Ok(()) } #[tauri::command] -async fn send_audio( - state: State<'_, AppState>, - audio: Vec, -) -> Result<(), String> { - let tx_guard = state.audio_tx.lock().await; - if let Some(tx) = tx_guard.as_ref() { - tx.send(audio).await.map_err(|e| e.to_string())?; +async fn stop_transcription(state: State<'_, AppState>) -> Result<(), String> { + if let Some(active) = state.active.lock().await.take() { + active.stop.store(true, Ordering::Release); } Ok(()) } #[tauri::command] -async fn stop_transcription( - state: State<'_, AppState>, -) -> Result<(), String> { - let mut tx_guard = state.audio_tx.lock().await; - // Dropping the sender closes the channel, which signals the worker - // to finalize and disconnect from Deepgram. - tx_guard.take(); +async fn set_transcription_paused(state: State<'_, AppState>, paused: bool) -> Result<(), String> { + let active = state.active.lock().await; + let transcription = active + .as_ref() + .ok_or_else(|| "No transcription is running".to_string())?; + transcription.paused.store(paused, Ordering::Release); Ok(()) } fn main() { - dotenvy::dotenv().ok(); - tauri::Builder::default() .manage(AppState { - audio_tx: Arc::new(Mutex::new(None)), + active: Mutex::new(None), }) .invoke_handler(tauri::generate_handler![ start_transcription, - send_audio, stop_transcription, + set_transcription_paused, ]) .run(tauri::generate_context!()) - .expect("error while running tauri application"); + .expect("error while running Tauri application"); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn given_stereo_samples_when_converted_then_pcm_is_downmixed_and_clamped() { + assert_eq!( + pcm16_mono(&[-2.0, -2.0, 0.0, 0.0, 2.0, 2.0], 2), + Ok(vec![0, 128, 0, 0, 255, 127]) + ); + } + + #[test] + fn given_blank_application_when_selected_then_configuration_is_rejected() { + let request = CaptureRequest { + source: CaptureSource::Application, + application: Some(" ".to_string()), + }; + assert!(request.source().is_err()); + } } diff --git a/examples/340-tauri-live-transcription-rust-ts/src/src/main.ts b/examples/340-tauri-live-transcription-rust-ts/src/src/main.ts index ba55be80..8100a4e9 100644 --- a/examples/340-tauri-live-transcription-rust-ts/src/src/main.ts +++ b/examples/340-tauri-live-transcription-rust-ts/src/src/main.ts @@ -4,118 +4,155 @@ import { listen } from "@tauri-apps/api/event"; const transcriptEl = document.getElementById("transcript")!; const btnStart = document.getElementById("btn-start") as HTMLButtonElement; const btnStop = document.getElementById("btn-stop") as HTMLButtonElement; +const btnPause = document.getElementById("btn-pause") as HTMLButtonElement; +const btnCopy = document.getElementById("btn-copy") as HTMLButtonElement; const statusEl = document.getElementById("status")!; +const sourceEl = document.getElementById("capture-source") as HTMLSelectElement; +const applicationRow = document.getElementById("application-row")!; +const applicationEl = document.getElementById("application") as HTMLInputElement; const MAX_LINES = 6; const finalLines: string[] = []; let currentInterim = ""; - -let mediaStream: MediaStream | null = null; -let audioContext: AudioContext | null = null; -let processorNode: ScriptProcessorNode | null = null; - -function renderTranscript() { - const visible = finalLines.slice(-MAX_LINES); - let html = visible.map((l) => `${l}`).join("
"); - if (currentInterim) { - html += `
${currentInterim}`; +let paused = false; + +function appendLine(text: string, className?: string) { + const line = document.createElement("span"); + line.textContent = text; + if (className) line.className = className; + if (transcriptEl.childNodes.length > 0) { + transcriptEl.append(document.createElement("br")); } - transcriptEl.innerHTML = html || "Listening..."; + transcriptEl.append(line); } -// Capture microphone at 16 kHz, convert float32 to linear16 PCM, -// and forward each chunk to the Rust backend via Tauri command. -async function startAudioCapture() { - mediaStream = await navigator.mediaDevices.getUserMedia({ audio: true }); - - // 16 kHz matches the Deepgram encoding config exactly - audioContext = new AudioContext({ sampleRate: 16000 }); - const source = audioContext.createMediaStreamSource(mediaStream); - - // ScriptProcessorNode is deprecated but universally supported in - // WebView contexts. AudioWorklet is the modern alternative but adds - // file complexity not warranted for this example. - processorNode = audioContext.createScriptProcessor(4096, 1, 1); - - processorNode.onaudioprocess = (event: AudioProcessingEvent) => { - const float32 = event.inputBuffer.getChannelData(0); - - // Convert float32 [-1, 1] → signed 16-bit PCM - const int16 = new Int16Array(float32.length); - for (let i = 0; i < float32.length; i++) { - const s = Math.max(-1, Math.min(1, float32[i])); - int16[i] = s < 0 ? s * 0x8000 : s * 0x7fff; - } +function renderTranscript() { + transcriptEl.replaceChildren(); + for (const line of finalLines.slice(-MAX_LINES)) appendLine(line); + if (currentInterim) appendLine(currentInterim, "interim"); + if (transcriptEl.childNodes.length === 0) transcriptEl.textContent = "Listening..."; +} - invoke("send_audio", { audio: Array.from(new Uint8Array(int16.buffer)) }); - }; +function updateApplicationInput() { + const capturesApplication = sourceEl.value === "application"; + applicationRow.hidden = !capturesApplication; + applicationEl.required = capturesApplication; +} - source.connect(processorNode); - processorNode.connect(audioContext.destination); +function resetControls() { + btnStart.disabled = false; + btnStop.disabled = true; + btnPause.disabled = true; + btnPause.textContent = "Pause"; + btnPause.classList.remove("active"); + paused = false; + btnStart.classList.remove("active"); + btnStop.classList.remove("active"); + sourceEl.disabled = false; + applicationEl.disabled = false; } -function stopAudioCapture() { - if (processorNode) { - processorNode.disconnect(); - processorNode = null; - } - if (audioContext) { - audioContext.close(); - audioContext = null; - } - if (mediaStream) { - mediaStream.getTracks().forEach((t) => t.stop()); - mediaStream = null; - } +function displayText(text: string, speaker: number | null) { + return speaker === null ? text : `Speaker ${speaker + 1}: ${text}`; } +sourceEl.addEventListener("change", updateApplicationInput); +updateApplicationInput(); + btnStart.addEventListener("click", async () => { + if (sourceEl.value === "application" && !applicationEl.value.trim()) { + applicationEl.focus(); + applicationEl.reportValidity(); + return; + } + btnStart.disabled = true; btnStop.disabled = false; + btnPause.disabled = false; btnStart.classList.add("active"); - btnStop.classList.remove("active"); - + sourceEl.disabled = true; + applicationEl.disabled = true; finalLines.length = 0; currentInterim = ""; transcriptEl.textContent = "Connecting..."; - await invoke("start_transcription"); - await startAudioCapture(); + try { + await invoke("start_transcription", { + request: { + source: sourceEl.value, + application: applicationEl.value.trim() || null, + }, + }); + } catch (error) { + statusEl.textContent = `error: ${String(error)}`; + statusEl.className = "status error"; + resetControls(); + } }); btnStop.addEventListener("click", async () => { btnStop.disabled = true; - btnStart.disabled = false; - btnStop.classList.remove("active"); - btnStart.classList.remove("active"); - - stopAudioCapture(); + btnPause.disabled = true; await invoke("stop_transcription"); + resetControls(); statusEl.textContent = "disconnected"; statusEl.className = "status"; }); -listen<{ text: string; is_final: boolean; speech_final: boolean; confidence: number }>( +btnPause.addEventListener("click", async () => { + const nextPaused = !paused; + try { + await invoke("set_transcription_paused", { paused: nextPaused }); + paused = nextPaused; + btnPause.textContent = paused ? "Resume" : "Pause"; + btnPause.classList.toggle("active", paused); + statusEl.textContent = paused ? "paused" : "connected"; + statusEl.className = paused ? "status" : "status connected"; + } catch (error) { + statusEl.textContent = `error: ${String(error)}`; + statusEl.className = "status error"; + } +}); + +btnCopy.addEventListener("click", async () => { + const transcript = finalLines.join("\n"); + if (transcript) await navigator.clipboard.writeText(transcript); +}); + +listen<{ + text: string; + is_final: boolean; + speech_final: boolean; + confidence: number; + speaker: number | null; +}>( "transcript", (event) => { if (event.payload.is_final) { - finalLines.push(event.payload.text); + finalLines.push(displayText(event.payload.text, event.payload.speaker)); currentInterim = ""; } else { - currentInterim = event.payload.text; + currentInterim = displayText(event.payload.text, event.payload.speaker); } renderTranscript(); - } + }, ); +listen("capture-status", (event) => { + statusEl.textContent = event.payload; + statusEl.className = "status connected"; +}); + listen("dg-status", (event) => { statusEl.textContent = event.payload; statusEl.className = `status ${event.payload}`; + if (event.payload === "disconnected") resetControls(); }); listen("dg-error", (event) => { statusEl.textContent = `error: ${event.payload}`; statusEl.className = "status error"; + resetControls(); }); listen("utterance-end", () => { diff --git a/examples/340-tauri-live-transcription-rust-ts/tests/test_example.py b/examples/340-tauri-live-transcription-rust-ts/tests/test_example.py index b3586076..56f8e3da 100644 --- a/examples/340-tauri-live-transcription-rust-ts/tests/test_example.py +++ b/examples/340-tauri-live-transcription-rust-ts/tests/test_example.py @@ -1,32 +1,25 @@ """Test the Tauri desktop live transcription example. -The Tauri desktop app requires a full build toolchain (Rust, system WebView, -and a display). This test verifies the example's correctness by inspecting -source files directly — the Rust backend, Tauri configuration, and TypeScript -frontend — without building or running the app. +These tests inspect the Rust backend, Tauri configuration, and TypeScript +frontend without starting a desktop window. Run the application for the real +Deepgram and native capture check described in the README. """ +import json import os import sys -import json from pathlib import Path -# ── Credential check ──────────────────────────────────────────────────────── -# Exit code convention across all examples in this repo: -# 0 = all tests passed -# 1 = real test failure (code bug, assertion error, unexpected API response) -# 2 = missing credentials (expected in CI until secrets are configured) env_example = Path(__file__).parent.parent / ".env.example" required = [ line.split("=")[0].strip() for line in env_example.read_text().splitlines() if line and not line.startswith("#") and "=" in line and line[0].isupper() ] -missing = [k for k in required if not os.environ.get(k)] +missing = [key for key in required if not os.environ.get(key)] if missing: print(f"MISSING_CREDENTIALS: {','.join(missing)}", file=sys.stderr) sys.exit(2) -# ──────────────────────────────────────────────────────────────────────────── ROOT = Path(__file__).parent.parent @@ -38,116 +31,96 @@ def test_file_structure(): "README.md", "src/src-tauri/src/main.rs", "src/src-tauri/Cargo.toml", + "src/src-tauri/Info.plist", + "src/src-tauri/icons/icon.ico", "src/src-tauri/tauri.conf.json", "src/src/main.ts", "src/index.html", "src/package.json", ] - for f in required_files: - full = ROOT / f - assert full.exists(), f"Missing required file: {f}" - print("File structure check passed") + for relative_path in required_files: + assert (ROOT / relative_path).exists(), f"Missing required file: {relative_path}" -def test_rust_source_uses_deepgram_sdk(): - """Verify the Rust source uses the Deepgram SDK correctly.""" +def test_rust_owns_capture_and_deepgram(): + """Verify Rust owns native capture and the Deepgram connection.""" main_rs = (ROOT / "src" / "src-tauri" / "src" / "main.rs").read_text() - assert "deepgram::Deepgram" in main_rs or "use deepgram" in main_rs, \ - "main.rs does not import the Deepgram SDK" - assert "deepgram-examples" in main_rs, \ - "main.rs missing required tag 'deepgram-examples'" - assert "Model::Nova3" in main_rs, \ - "main.rs should use Nova3 model" - assert "DEEPGRAM_API_KEY" in main_rs, \ - "main.rs should read DEEPGRAM_API_KEY from environment" - assert "send_audio" in main_rs, \ - "main.rs should expose send_audio Tauri command" - assert "start_transcription" in main_rs, \ - "main.rs should expose start_transcription Tauri command" - - print("Rust source validation passed") - - -def test_cargo_toml_pins_deepgram(): - """Verify Cargo.toml declares the deepgram crate dependency.""" + assert "deepgram::Deepgram" in main_rs or "use deepgram" in main_rs + assert "deepgram-examples" in main_rs + assert "Model::Nova3" in main_rs + assert ".diarize(true)" in main_rs + assert "DEEPGRAM_API_KEY" in main_rs + assert "start_transcription" in main_rs + assert "set_transcription_paused" in main_rs + assert "pocketstation" in main_rs + assert "Source::application" in main_rs + assert "Source::system_audio" in main_rs + assert "Source::microphone_default" in main_rs + assert "Connector::from_audio_fn" in main_rs + + +def test_cargo_dependencies_are_pinned(): + """Verify the example uses released Deepgram and PocketStation crates.""" cargo_toml = (ROOT / "src" / "src-tauri" / "Cargo.toml").read_text() - assert "deepgram" in cargo_toml, \ - "Cargo.toml must declare the deepgram crate as a dependency" - assert "0.9.2" in cargo_toml, \ - "Cargo.toml should pin deepgram at version 0.9.2" - assert "tauri" in cargo_toml, \ - "Cargo.toml must declare the tauri crate as a dependency" - - print("Cargo.toml declares deepgram and tauri dependencies") - + assert 'deepgram = { version = "=0.10.1"' in cargo_toml + assert 'features = ["listen"]' in cargo_toml + assert 'tauri = { version = "=2.11.5"' in cargo_toml + assert cargo_toml.count('pocketstation = { version = "=1.1.10"') == 3 + assert 'features = ["coreaudio-capture"]' in cargo_toml + assert 'features = ["wasapi-capture"]' in cargo_toml + assert 'features = ["pipewire-capture"]' in cargo_toml + assert "tauri" in cargo_toml -def test_tauri_conf_settings(): - """Verify tauri.conf.json has the expected app configuration.""" - conf_path = ROOT / "src" / "src-tauri" / "tauri.conf.json" - conf = json.loads(conf_path.read_text()) +def test_tauri_configuration(): + """Verify the desktop window and application identity.""" + conf = json.loads((ROOT / "src" / "src-tauri" / "tauri.conf.json").read_text()) product_name = conf.get("productName", "") - assert "deepgram" in product_name.lower() or "transcription" in product_name.lower(), \ - f"tauri.conf.json productName should reference Deepgram or Transcription, got: {product_name}" - - # App identifier should follow reverse-domain convention identifier = conf.get("identifier", "") - assert "deepgram" in identifier.lower(), \ - f"tauri.conf.json identifier should include 'deepgram', got: {identifier}" - - # Must define at least one window windows = conf.get("app", {}).get("windows", []) - assert len(windows) > 0, \ - "tauri.conf.json must define at least one window" - - assert windows[0].get("width", 0) > 0, "Window width must be positive" - assert windows[0].get("height", 0) > 0, "Window height must be positive" - print(f"tauri.conf.json settings valid:") - print(f" productName: {product_name}") - print(f" identifier: {identifier}") - print(f" window: {windows[0].get('width')}x{windows[0].get('height')}") + assert "deepgram" in product_name.lower() or "transcription" in product_name.lower() + assert "deepgram" in identifier.lower() + assert windows + assert windows[0].get("width", 0) > 0 + assert windows[0].get("height", 0) > 0 -def test_typescript_frontend_uses_tauri_invoke(): - """Verify the TypeScript frontend calls the Rust backend via Tauri's invoke().""" +def test_frontend_selects_native_capture(): + """Verify the frontend requests one explicit native source.""" main_ts = (ROOT / "src" / "src" / "main.ts").read_text() + index_html = (ROOT / "src" / "index.html").read_text() - assert 'from "@tauri-apps/api/core"' in main_ts or \ - 'from "@tauri-apps/api"' in main_ts, \ - "main.ts must import from @tauri-apps/api" - assert "invoke" in main_ts, \ - "main.ts must call invoke() to communicate with the Rust backend" - assert "start_transcription" in main_ts, \ - "main.ts must invoke start_transcription Tauri command" - assert "send_audio" in main_ts, \ - "main.ts must invoke send_audio Tauri command" - assert "stop_transcription" in main_ts, \ - "main.ts must invoke stop_transcription Tauri command" + assert 'from "@tauri-apps/api/core"' in main_ts + assert "start_transcription" in main_ts + assert "stop_transcription" in main_ts + assert "set_transcription_paused" in main_ts + assert "getUserMedia" not in main_ts + assert "send_audio" not in main_ts + assert "capture-source" in main_ts + assert 'value="application"' in index_html + assert 'value="system_audio"' in index_html + assert 'value="microphone"' in index_html + assert 'id="application"' in index_html + assert 'id="btn-copy"' in index_html + assert 'id="btn-pause"' in index_html - print("TypeScript frontend correctly uses Tauri invoke() for backend communication") - - -def test_typescript_frontend_audio_capture(): - """Verify the TypeScript frontend captures microphone audio for Deepgram.""" - main_ts = (ROOT / "src" / "src" / "main.ts").read_text() - assert "getUserMedia" in main_ts, \ - "main.ts must use getUserMedia to capture microphone audio" - # 16000 Hz matches the Deepgram linear16 encoding config in main.rs - assert "16000" in main_ts, \ - "main.ts should configure audio at 16000 Hz to match Deepgram encoding" +def test_macos_permission_descriptions(): + """Verify packaged macOS builds explain both permission requests.""" + info_plist = (ROOT / "src" / "src-tauri" / "Info.plist").read_text() - print("TypeScript frontend captures microphone audio at 16 kHz for Deepgram") + assert "NSMicrophoneUsageDescription" in info_plist + assert "NSScreenCaptureUsageDescription" in info_plist if __name__ == "__main__": test_file_structure() - test_rust_source_uses_deepgram_sdk() - test_cargo_toml_pins_deepgram() - test_tauri_conf_settings() - test_typescript_frontend_uses_tauri_invoke() - test_typescript_frontend_audio_capture() - print("\nAll tests passed") + test_rust_owns_capture_and_deepgram() + test_cargo_dependencies_are_pinned() + test_tauri_configuration() + test_frontend_selects_native_capture() + test_macos_permission_descriptions() + print("All tests passed")