Rename project, crates, and binaries to open-360-link
This commit is contained in:
28 files changed
+219
-207
No files matched your search
Generated
+54
-54
@@ -1829,60 +1829,6 @@ dependencies = [
|
|||||||
"hashbrown 0.17.1",
|
"hashbrown 0.17.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "insta360-link-cli"
|
|
||||||
version = "0.0.0"
|
|
||||||
dependencies = [
|
|
||||||
"clap",
|
|
||||||
"insta360-link-protocol",
|
|
||||||
"serde",
|
|
||||||
"serde_json",
|
|
||||||
"tracing",
|
|
||||||
"tracing-subscriber",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "insta360-link-gui"
|
|
||||||
version = "0.0.0"
|
|
||||||
dependencies = [
|
|
||||||
"eframe",
|
|
||||||
"egui",
|
|
||||||
"image",
|
|
||||||
"insta360-link-protocol",
|
|
||||||
"serde",
|
|
||||||
"serde_json",
|
|
||||||
"tracing",
|
|
||||||
"tracing-subscriber",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "insta360-link-protocol"
|
|
||||||
version = "0.0.0"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 2.13.2",
|
|
||||||
"libc",
|
|
||||||
"nusb",
|
|
||||||
"serde",
|
|
||||||
"serde_json",
|
|
||||||
"thiserror 2.0.21",
|
|
||||||
"tracing",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "insta360-link-server"
|
|
||||||
version = "0.0.0"
|
|
||||||
dependencies = [
|
|
||||||
"axum",
|
|
||||||
"clap",
|
|
||||||
"insta360-link-protocol",
|
|
||||||
"serde",
|
|
||||||
"serde_json",
|
|
||||||
"tokio",
|
|
||||||
"tower-http",
|
|
||||||
"tracing",
|
|
||||||
"tracing-subscriber",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "io-kit-sys"
|
name = "io-kit-sys"
|
||||||
version = "0.4.1"
|
version = "0.4.1"
|
||||||
@@ -2623,6 +2569,60 @@ version = "1.70.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
|
checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "open-360-link-cli"
|
||||||
|
version = "0.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"clap",
|
||||||
|
"open-360-link-protocol",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"tracing",
|
||||||
|
"tracing-subscriber",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "open-360-link-gui"
|
||||||
|
version = "0.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"eframe",
|
||||||
|
"egui",
|
||||||
|
"image",
|
||||||
|
"open-360-link-protocol",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"tracing",
|
||||||
|
"tracing-subscriber",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "open-360-link-protocol"
|
||||||
|
version = "0.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.13.2",
|
||||||
|
"libc",
|
||||||
|
"nusb",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"thiserror 2.0.21",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "open-360-link-server"
|
||||||
|
version = "0.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"axum",
|
||||||
|
"clap",
|
||||||
|
"open-360-link-protocol",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"tokio",
|
||||||
|
"tower-http",
|
||||||
|
"tracing",
|
||||||
|
"tracing-subscriber",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "orbclient"
|
name = "orbclient"
|
||||||
version = "0.3.55"
|
version = "0.3.55"
|
||||||
|
|||||||
+5
-5
@@ -1,10 +1,10 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
members = [
|
members = [
|
||||||
"crates/insta360-link-protocol",
|
"crates/open-360-link-protocol",
|
||||||
"crates/insta360-link-cli",
|
"crates/open-360-link-cli",
|
||||||
"crates/insta360-link-gui",
|
"crates/open-360-link-gui",
|
||||||
"crates/insta360-link-server",
|
"crates/open-360-link-server",
|
||||||
]
|
]
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
@@ -12,7 +12,7 @@ version = "0.0.0"
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
authors = ["Lucas Oskorep <lucas.oskorep@gmail.com>"]
|
authors = ["Lucas Oskorep <lucas.oskorep@gmail.com>"]
|
||||||
repository = "https://github.com/lucasoskorep/insta360-link-controller"
|
repository = "https://github.com/lucasoskorep/open-360-link"
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
thiserror = "2.0"
|
thiserror = "2.0"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Insta360 Link Open Controller
|
# Open 360 Link
|
||||||
|
|
||||||
A pure-Rust, cross-platform (**Linux**, **Windows**, **macOS**) hardware controller suite for the **Insta360 Link**, **Insta360 Link 2**, **Insta360 Link 2C**, and **Insta360 Link 2 Pro (PUC3)** 4K AI webcams.
|
A pure-Rust, cross-platform (**Linux**, **Windows**, **macOS**) hardware controller suite for the **Insta360 Link**, **Insta360 Link 2**, **Insta360 Link 2C**, and **Insta360 Link 2 Pro (PUC3)** 4K AI webcams.
|
||||||
|
|
||||||
@@ -12,10 +12,10 @@ Built by reverse-engineering the proprietary USB & UVC Extension Unit (`XU1` and
|
|||||||
|
|
||||||
| Crate / Binary | Description |
|
| Crate / Binary | Description |
|
||||||
| :--- | :--- |
|
| :--- | :--- |
|
||||||
| **`insta360-link-protocol`** | Core Rust library implementing USB device discovery, UVC VideoControl descriptor parsing, standard UVC `CT_*`/`PU_*` controls, proprietary `XU1`/`XU2` codecs, `NusbTransport` (pure-Rust USB via `nusb`), and a stateful `MockCameraTransport` simulator. |
|
| **`open-360-link-protocol`** | Core Rust library implementing USB device discovery, UVC VideoControl descriptor parsing, standard UVC `CT_*`/`PU_*` controls, proprietary `XU1`/`XU2` codecs, `NusbTransport` (pure-Rust USB via `nusb`), and a stateful `MockCameraTransport` simulator. |
|
||||||
| **`insta360-link-ctl`** (`insta360-link-cli`) | Command-line tool for scripting PTZ movement, presets, video modes (`Normal`, `AutoTracking`, `WhiteBoard`, `OverheadShot`, `DeskView`, `AutoFraming`, `SmartWhiteBoard`), exposure/ISO, white balance, audio beamforming modes, filters, and extended hardware switches. |
|
| **`open-360-link-ctl`** (`open-360-link-cli`) | Command-line tool for scripting PTZ movement, presets, video modes (`Normal`, `AutoTracking`, `WhiteBoard`, `OverheadShot`, `DeskView`, `AutoFraming`, `SmartWhiteBoard`), exposure/ISO, white balance, audio beamforming modes, filters, and extended hardware switches. |
|
||||||
| **`insta360-link-server`** | Asynchronous HTTP REST & WebSocket daemon (`axum` + `tokio`) for remote control, Stream Deck / OBS integration, and real-time state synchronization. |
|
| **`open-360-link-server`** | Asynchronous HTTP REST & WebSocket daemon (`axum` + `tokio`) for remote control, Stream Deck / OBS integration, and real-time state synchronization. |
|
||||||
| **`insta360-link-gui`** | Native cross-platform desktop GUI (`egui` / `eframe`) featuring a virtual gimbal PTZ joystick, preset slots, AI mode switcher, image adjustment sliders, audio & filter controls, and built-in simulated camera mode. |
|
| **`open-360-link-gui`** | Native cross-platform desktop GUI (`egui` / `eframe`) featuring a virtual gimbal PTZ joystick, AI mode switcher, image adjustment sliders, audio & filter controls, and live camera preview/recording. |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -61,9 +61,9 @@ cargo build --release
|
|||||||
```
|
```
|
||||||
|
|
||||||
The compiled binaries will be placed in `target/release/`:
|
The compiled binaries will be placed in `target/release/`:
|
||||||
- `target/release/insta360-link-ctl`
|
- `target/release/open-360-link-ctl`
|
||||||
- `target/release/insta360-link-server`
|
- `target/release/open-360-link-server`
|
||||||
- `target/release/insta360-link-gui`
|
- `target/release/open-360-link-gui`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -71,12 +71,12 @@ The compiled binaries will be placed in `target/release/`:
|
|||||||
|
|
||||||
### Linux (`V4L2` & `uvcvideo`)
|
### Linux (`V4L2` & `uvcvideo`)
|
||||||
|
|
||||||
On Linux, `insta360-link-protocol` communicates directly with the primary V4L2 video capture node (`/dev/video*`) using `UVCIOC_CTRL_QUERY` for proprietary Insta360 Extension Unit (`XU1`/`XU2`) commands and standard V4L2 `VIDIOC_G_CTRL`/`VIDIOC_S_CTRL` ioctls for Processing Unit / Camera Terminal controls, while reading USB descriptors from sysfs. Because `systemd-logind` automatically grants the active desktop user session access to `/dev/video*`, **no custom `udev` rules or `sudo` privileges are required**.
|
On Linux, `open-360-link-protocol` communicates directly with the primary V4L2 video capture node (`/dev/video*`) using `UVCIOC_CTRL_QUERY` for proprietary Insta360 Extension Unit (`XU1`/`XU2`) commands and standard V4L2 `VIDIOC_G_CTRL`/`VIDIOC_S_CTRL` ioctls for Processing Unit / Camera Terminal controls, while reading USB descriptors from sysfs. Because `systemd-logind` automatically grants the active desktop user session access to `/dev/video*`, **no custom `udev` rules or `sudo` privileges are required**.
|
||||||
|
|
||||||
#### Arch Linux (AUR)
|
#### Arch Linux & Arch Linux ARM (AUR)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
yay -S insta360-link-controller-bin
|
yay -S open-360-link-bin
|
||||||
```
|
```
|
||||||
|
|
||||||
### macOS
|
### macOS
|
||||||
@@ -87,74 +87,73 @@ On macOS, `nusb` uses `IOKit` to send UVC class-specific control requests direct
|
|||||||
|
|
||||||
## Usage Examples
|
## Usage Examples
|
||||||
|
|
||||||
### 1. Command-Line Interface (`insta360-link-ctl`)
|
### 1. Command-Line Interface (`open-360-link-ctl`)
|
||||||
|
|
||||||
> **Tip**: Pass `--mock` (and optionally `--mock-model link2`, `link2c`, or `link`) to test any command against the simulated camera without physical hardware attached.
|
> **Tip**: Pass `--mock link2` (`link`, `link2`, or `link2c`) to test any command against the simulated camera without physical hardware attached.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# List connected Insta360 Link cameras and discovered UVC unit IDs
|
# List connected Insta360 Link cameras and discovered UVC unit IDs
|
||||||
cargo run -p insta360-link-cli -- list
|
cargo run -p open-360-link-cli -- list
|
||||||
|
|
||||||
# Show complete camera status, firmware version, PTZ angles, and active features
|
# Show complete camera status, firmware version, PTZ angles, and active features
|
||||||
cargo run -p insta360-link-cli -- status
|
cargo run -p open-360-link-cli -- info
|
||||||
|
|
||||||
# Move gimbal to absolute pan/tilt angles (in degrees) and set zoom (100 = 1.0x, 200 = 2.0x)
|
# Move gimbal to absolute pan/tilt angles and set zoom (100 = 1.0x, 200 = 2.0x)
|
||||||
cargo run -p insta360-link-cli -- ptz --pan 15.0 --tilt -10.0 --zoom 150
|
cargo run -p open-360-link-cli -- ptz set-abs --pan 54000 --tilt -36000
|
||||||
|
cargo run -p open-360-link-cli -- ptz zoom 150
|
||||||
|
|
||||||
# Center / home the gimbal
|
# Center / home the gimbal
|
||||||
cargo run -p insta360-link-cli -- home
|
cargo run -p open-360-link-cli -- ptz reset
|
||||||
|
|
||||||
# Save and recall gimbal preset slots (0..5)
|
# Switch AI Video Mode (normal, auto-tracking, whiteboard, overhead, deskview, auto-framing, smart-whiteboard)
|
||||||
cargo run -p insta360-link-cli -- preset save 0
|
cargo run -p open-360-link-cli -- mode set auto-tracking
|
||||||
cargo run -p insta360-link-cli -- preset recall 0
|
cargo run -p open-360-link-cli -- tracking speed fast
|
||||||
|
|
||||||
# Switch AI Video Mode (normal, tracking, whiteboard, overhead, deskview, auto-framing, smart-whiteboard)
|
|
||||||
cargo run -p insta360-link-cli -- mode tracking
|
|
||||||
cargo run -p insta360-link-cli -- tracking --speed fast --composition half-body
|
|
||||||
|
|
||||||
# Configure image settings (brightness, contrast, saturation, sharpness, white balance, HDR)
|
# Configure image settings (brightness, contrast, saturation, sharpness, white balance, HDR)
|
||||||
cargo run -p insta360-link-cli -- image --brightness 60 --contrast 55 --hdr on --wb-kelvin 5600
|
cargo run -p open-360-link-cli -- image brightness 60
|
||||||
|
cargo run -p open-360-link-cli -- image hdr true
|
||||||
|
|
||||||
# Configure microphone beamforming mode (voice-focus, noise-suppression, music-balance, original, sound-wall)
|
# Configure microphone beamforming mode (voice-focus, noise-reduction, music-mode, original, sound-wall)
|
||||||
cargo run -p insta360-link-cli -- audio --mode voice-focus --denoise on
|
cargo run -p open-360-link-cli -- audio mode voice-focus
|
||||||
|
cargo run -p open-360-link-cli -- audio denoise true
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. HTTP & WebSocket Server (`insta360-link-server`)
|
### 2. HTTP & WebSocket Server (`open-360-link-server`)
|
||||||
|
|
||||||
Start the daemon on `127.0.0.1:8360` (use `--mock` if no physical camera is connected):
|
Start the daemon on `127.0.0.1:9360` (use `--mock link2` if no physical camera is connected):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cargo run -p insta360-link-server -- --bind 127.0.0.1:8360 --mock
|
cargo run -p open-360-link-server -- --bind 127.0.0.1:9360 --mock link2
|
||||||
```
|
```
|
||||||
|
|
||||||
Example REST API calls:
|
Example REST API calls:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# List discovered cameras
|
# List discovered cameras
|
||||||
curl http://127.0.0.1:8360/api/cameras
|
curl http://127.0.0.1:9360/api/cameras
|
||||||
|
|
||||||
# Fetch full camera state snapshot
|
# Fetch full camera state snapshot
|
||||||
curl http://127.0.0.1:8360/api/state
|
curl http://127.0.0.1:9360/api/state
|
||||||
|
|
||||||
# Set PTZ pan, tilt, or zoom
|
# Set PTZ pan, tilt, or zoom
|
||||||
curl -X POST http://127.0.0.1:8360/api/ptz \
|
curl -X POST http://127.0.0.1:9360/api/ptz \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-d '{"pan_deg": 20.0, "tilt_deg": -5.0, "zoom": 180}'
|
-d '{"pan_deg": 20.0, "tilt_deg": -5.0, "zoom": 180}'
|
||||||
|
|
||||||
# Switch video mode
|
# Switch video mode
|
||||||
curl -X POST http://127.0.0.1:8360/api/mode \
|
curl -X POST http://127.0.0.1:9360/api/mode \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-d '{"mode": "DeskView"}'
|
-d '{"mode": "DeskView"}'
|
||||||
```
|
```
|
||||||
|
|
||||||
Connect to `ws://127.0.0.1:8360/ws` over WebSockets to receive real-time JSON state broadcasts and send low-latency PTZ/control commands.
|
Connect to `ws://127.0.0.1:9360/ws` over WebSockets to receive real-time JSON state broadcasts and send low-latency PTZ/control commands.
|
||||||
|
|
||||||
### 3. Desktop GUI (`insta360-link-gui`)
|
### 3. Desktop GUI (`open-360-link-gui`)
|
||||||
|
|
||||||
Launch the native cross-platform GUI (automatically connects to a physical Insta360 Link camera if found, or falls back to the interactive simulator):
|
Launch the native cross-platform GUI (automatically connects to a physical Insta360 Link camera if found):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cargo run -p insta360-link-gui
|
cargo run -p open-360-link-gui
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
[Desktop Entry]
|
|
||||||
Version=1.0
|
|
||||||
Type=Application
|
|
||||||
Name=Insta360 Link Controller
|
|
||||||
GenericName=Webcam Controller
|
|
||||||
Comment=Hardware PTZ, AI tracking, image settings, and live preview controller for Insta360 Link webcams
|
|
||||||
Exec=insta360-link-gui
|
|
||||||
TryExec=insta360-link-gui
|
|
||||||
Icon=insta360-link-controller
|
|
||||||
Terminal=false
|
|
||||||
Categories=AudioVideo;Video;
|
|
||||||
Keywords=insta360;link;webcam;camera;ptz;gimbal;uvc;video;tracking;
|
|
||||||
StartupNotify=true
|
|
||||||
StartupWMClass=insta360-link-controller
|
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
[Desktop Entry]
|
||||||
|
Version=1.0
|
||||||
|
Type=Application
|
||||||
|
Name=Open 360 Link
|
||||||
|
GenericName=Webcam Controller
|
||||||
|
Comment=Open-source hardware PTZ, AI tracking, image settings, and live preview controller for Insta360 Link webcams
|
||||||
|
Exec=open-360-link-gui
|
||||||
|
TryExec=open-360-link-gui
|
||||||
|
Icon=open-360-link
|
||||||
|
Terminal=false
|
||||||
|
Categories=AudioVideo;Video;
|
||||||
|
Keywords=open-360-link;insta360;link;webcam;camera;ptz;gimbal;uvc;video;tracking;
|
||||||
|
StartupNotify=true
|
||||||
|
StartupWMClass=open-360-link
|
||||||
File renamed without changes.
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
@@ -1,16 +1,16 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "insta360-link-cli"
|
name = "open-360-link-cli"
|
||||||
version.workspace = true
|
version.workspace = true
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
description = "Cross-platform CLI controller for Insta360 Link, Link 2, and Link 2C cameras"
|
description = "Open 360 Link: Cross-platform CLI controller for Insta360 Link, Link 2, and Link 2C cameras"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "insta360-link-ctl"
|
name = "open-360-link-ctl"
|
||||||
path = "src/main.rs"
|
path = "src/main.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
insta360-link-protocol = { path = "../insta360-link-protocol" }
|
open-360-link-protocol = { path = "../open-360-link-protocol" }
|
||||||
clap.workspace = true
|
clap.workspace = true
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
serde_json.workspace = true
|
serde_json.workspace = true
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
use clap::{ArgAction, Parser, Subcommand, ValueEnum};
|
use clap::{ArgAction, Parser, Subcommand, ValueEnum};
|
||||||
use insta360_link_protocol::{
|
use open_360_link_protocol::{
|
||||||
list_connected_cameras, AudioCaptureMode, CameraModel, CompositionStyle, DeviceInfo,
|
list_connected_cameras, AudioCaptureMode, CameraModel, CompositionStyle, DeviceInfo,
|
||||||
DeviceStatus, DiscoveredCamera, ExtendFunction, FilterMode, ForbiddenAreaInfo, Gesture,
|
DeviceStatus, DiscoveredCamera, ExtendFunction, FilterMode, ForbiddenAreaInfo, Gesture,
|
||||||
GestureFunction, HostPtzInfo, ImageOperation, Insta360CameraController, MockCameraTransport,
|
GestureFunction, HostPtzInfo, ImageOperation, Insta360CameraController, MockCameraTransport,
|
||||||
@@ -11,9 +11,9 @@ use std::process::ExitCode;
|
|||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
#[command(
|
#[command(
|
||||||
name = "insta360-link-ctl",
|
name = "open-360-link-ctl",
|
||||||
version,
|
version,
|
||||||
about = "Cross-platform CLI controller for Insta360 Link, Link 2, and Link 2C cameras"
|
about = "Open 360 Link: Cross-platform CLI controller for Insta360 Link, Link 2, and Link 2C cameras"
|
||||||
)]
|
)]
|
||||||
pub struct Cli {
|
pub struct Cli {
|
||||||
/// Run against an in-memory simulated camera model instead of physical USB
|
/// Run against an in-memory simulated camera model instead of physical USB
|
||||||
@@ -1,16 +1,16 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "insta360-link-gui"
|
name = "open-360-link-gui"
|
||||||
version.workspace = true
|
version.workspace = true
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
description = "Cross-platform pure-Rust desktop GUI controller for Insta360 Link, Link 2, and Link 2C"
|
description = "Open 360 Link: Cross-platform pure-Rust desktop GUI controller for Insta360 Link, Link 2, and Link 2C"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "insta360-link-gui"
|
name = "open-360-link-gui"
|
||||||
path = "src/main.rs"
|
path = "src/main.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
insta360-link-protocol = { path = "../insta360-link-protocol" }
|
open-360-link-protocol = { path = "../open-360-link-protocol" }
|
||||||
eframe.workspace = true
|
eframe.workspace = true
|
||||||
egui.workspace = true
|
egui.workspace = true
|
||||||
image = { version = "0.25", default-features = false, features = ["png"] }
|
image = { version = "0.25", default-features = false, features = ["png"] }
|
||||||
@@ -7,7 +7,7 @@ mod video_engine;
|
|||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
use eframe::egui::{self, Align2, Color32, FontId, Margin, Pos2, Rect, RichText, Rounding, Stroke, Vec2};
|
use eframe::egui::{self, Align2, Color32, FontId, Margin, Pos2, Rect, RichText, Rounding, Stroke, Vec2};
|
||||||
use insta360_link_protocol::{
|
use open_360_link_protocol::{
|
||||||
list_connected_cameras, CameraModel, DiscoveredCamera, Insta360CameraController,
|
list_connected_cameras, CameraModel, DiscoveredCamera, Insta360CameraController,
|
||||||
MockCameraTransport, NusbTransport, PowerLineFrequency, VideoMode, VideoModeAuxData,
|
MockCameraTransport, NusbTransport, PowerLineFrequency, VideoMode, VideoModeAuxData,
|
||||||
};
|
};
|
||||||
@@ -181,41 +181,41 @@ impl Insta360App {
|
|||||||
if let Ok(ext) = self.controller.get_extend_function_status() {
|
if let Ok(ext) = self.controller.get_extend_function_status() {
|
||||||
for (func, en) in ext {
|
for (func, en) in ext {
|
||||||
match func {
|
match func {
|
||||||
insta360_link_protocol::ExtendFunction::AiZoom => {
|
open_360_link_protocol::ExtendFunction::AiZoom => {
|
||||||
self.state.ai_zoom_enabled = en
|
self.state.ai_zoom_enabled = en
|
||||||
}
|
}
|
||||||
insta360_link_protocol::ExtendFunction::AllGestures => {
|
open_360_link_protocol::ExtendFunction::AllGestures => {
|
||||||
self.state.enable_all_gestures = en
|
self.state.enable_all_gestures = en
|
||||||
}
|
}
|
||||||
insta360_link_protocol::ExtendFunction::AutoTracking => {
|
open_360_link_protocol::ExtendFunction::AutoTracking => {
|
||||||
self.state.enable_auto_tracking = en
|
self.state.enable_auto_tracking = en
|
||||||
}
|
}
|
||||||
insta360_link_protocol::ExtendFunction::SingleTapTracking => {
|
open_360_link_protocol::ExtendFunction::SingleTapTracking => {
|
||||||
self.state.enable_single_tap_tracking = en
|
self.state.enable_single_tap_tracking = en
|
||||||
}
|
}
|
||||||
insta360_link_protocol::ExtendFunction::Hdr => self.state.hdr_enabled = en,
|
open_360_link_protocol::ExtendFunction::Hdr => self.state.hdr_enabled = en,
|
||||||
insta360_link_protocol::ExtendFunction::HorizontalMirror => {
|
open_360_link_protocol::ExtendFunction::HorizontalMirror => {
|
||||||
self.state.horizontal_mirror = en
|
self.state.horizontal_mirror = en
|
||||||
}
|
}
|
||||||
insta360_link_protocol::ExtendFunction::VerticalMirror => {
|
open_360_link_protocol::ExtendFunction::VerticalMirror => {
|
||||||
self.state.vertical_mirror = en
|
self.state.vertical_mirror = en
|
||||||
}
|
}
|
||||||
insta360_link_protocol::ExtendFunction::VerticalMode => {
|
open_360_link_protocol::ExtendFunction::VerticalMode => {
|
||||||
self.state.vertical_resolution_mode = en
|
self.state.vertical_resolution_mode = en
|
||||||
}
|
}
|
||||||
insta360_link_protocol::ExtendFunction::ForcedVertical => {
|
open_360_link_protocol::ExtendFunction::ForcedVertical => {
|
||||||
self.state.forced_vertical_lock = en
|
self.state.forced_vertical_lock = en
|
||||||
}
|
}
|
||||||
insta360_link_protocol::ExtendFunction::LowResolution => {
|
open_360_link_protocol::ExtendFunction::LowResolution => {
|
||||||
self.state.low_resolution_mode = en
|
self.state.low_resolution_mode = en
|
||||||
}
|
}
|
||||||
insta360_link_protocol::ExtendFunction::SmartAdjustment => {
|
open_360_link_protocol::ExtendFunction::SmartAdjustment => {
|
||||||
self.state.smart_adjustment = en
|
self.state.smart_adjustment = en
|
||||||
}
|
}
|
||||||
insta360_link_protocol::ExtendFunction::StartupParams => {
|
open_360_link_protocol::ExtendFunction::StartupParams => {
|
||||||
self.state.startup_params_enabled = en
|
self.state.startup_params_enabled = en
|
||||||
}
|
}
|
||||||
insta360_link_protocol::ExtendFunction::UltimatePrivacyMode => {
|
open_360_link_protocol::ExtendFunction::UltimatePrivacyMode => {
|
||||||
self.state.ultimate_privacy = en
|
self.state.ultimate_privacy = en
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
@@ -231,11 +231,11 @@ impl Insta360App {
|
|||||||
if let Ok(gestures) = self.controller.get_gesture_status() {
|
if let Ok(gestures) = self.controller.get_gesture_status() {
|
||||||
for (g, en) in gestures {
|
for (g, en) in gestures {
|
||||||
match g {
|
match g {
|
||||||
insta360_link_protocol::Gesture::Ok => self.state.use_gesture_ok = en,
|
open_360_link_protocol::Gesture::Ok => self.state.use_gesture_ok = en,
|
||||||
insta360_link_protocol::Gesture::Palm => self.state.use_gesture_palm = en,
|
open_360_link_protocol::Gesture::Palm => self.state.use_gesture_palm = en,
|
||||||
insta360_link_protocol::Gesture::LShape => self.state.use_gesture_l = en,
|
open_360_link_protocol::Gesture::LShape => self.state.use_gesture_l = en,
|
||||||
insta360_link_protocol::Gesture::VShape => self.state.use_gesture_v = en,
|
open_360_link_protocol::Gesture::VShape => self.state.use_gesture_v = en,
|
||||||
insta360_link_protocol::Gesture::Rock => self.state.use_gesture_rock = en,
|
open_360_link_protocol::Gesture::Rock => self.state.use_gesture_rock = en,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -325,15 +325,15 @@ impl Insta360App {
|
|||||||
.controller
|
.controller
|
||||||
.set_all_gestures_enabled(self.state.enable_all_gestures);
|
.set_all_gestures_enabled(self.state.enable_all_gestures);
|
||||||
let _ = self.controller.set_gesture_enabled(
|
let _ = self.controller.set_gesture_enabled(
|
||||||
insta360_link_protocol::Gesture::Palm,
|
open_360_link_protocol::Gesture::Palm,
|
||||||
self.state.use_gesture_palm,
|
self.state.use_gesture_palm,
|
||||||
);
|
);
|
||||||
let _ = self.controller.set_gesture_enabled(
|
let _ = self.controller.set_gesture_enabled(
|
||||||
insta360_link_protocol::Gesture::VShape,
|
open_360_link_protocol::Gesture::VShape,
|
||||||
self.state.use_gesture_v,
|
self.state.use_gesture_v,
|
||||||
);
|
);
|
||||||
let _ = self.controller.set_gesture_enabled(
|
let _ = self.controller.set_gesture_enabled(
|
||||||
insta360_link_protocol::Gesture::LShape,
|
open_360_link_protocol::Gesture::LShape,
|
||||||
self.state.use_gesture_l,
|
self.state.use_gesture_l,
|
||||||
);
|
);
|
||||||
let _ = self
|
let _ = self
|
||||||
@@ -412,14 +412,14 @@ impl Insta360App {
|
|||||||
)
|
)
|
||||||
.show(ctx, |ui| {
|
.show(ctx, |ui| {
|
||||||
ui.horizontal_centered(|ui| {
|
ui.horizontal_centered(|ui| {
|
||||||
// Left: Green Insta360 camera icon + "Insta360 Link Controller" title
|
// Left: Green camera icon + "Open 360 Link" title
|
||||||
ui.label(
|
ui.label(
|
||||||
RichText::new("📷")
|
RichText::new("📷")
|
||||||
.color(theme.brand_green)
|
.color(theme.brand_green)
|
||||||
.size(17.0_f32),
|
.size(17.0_f32),
|
||||||
);
|
);
|
||||||
ui.label(
|
ui.label(
|
||||||
RichText::new("Insta360 Link Controller")
|
RichText::new("Open 360 Link")
|
||||||
.strong()
|
.strong()
|
||||||
.size(14.5_f32)
|
.size(14.5_f32)
|
||||||
.color(theme.text01),
|
.color(theme.text01),
|
||||||
@@ -1257,7 +1257,7 @@ impl Insta360App {
|
|||||||
.changed()
|
.changed()
|
||||||
{
|
{
|
||||||
let _ = self.controller.set_gesture_enabled(
|
let _ = self.controller.set_gesture_enabled(
|
||||||
insta360_link_protocol::Gesture::Palm,
|
open_360_link_protocol::Gesture::Palm,
|
||||||
self.state.use_gesture_palm,
|
self.state.use_gesture_palm,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1267,7 +1267,7 @@ impl Insta360App {
|
|||||||
.changed()
|
.changed()
|
||||||
{
|
{
|
||||||
let _ = self.controller.set_gesture_enabled(
|
let _ = self.controller.set_gesture_enabled(
|
||||||
insta360_link_protocol::Gesture::VShape,
|
open_360_link_protocol::Gesture::VShape,
|
||||||
self.state.use_gesture_v,
|
self.state.use_gesture_v,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1277,7 +1277,7 @@ impl Insta360App {
|
|||||||
.changed()
|
.changed()
|
||||||
{
|
{
|
||||||
let _ = self.controller.set_gesture_enabled(
|
let _ = self.controller.set_gesture_enabled(
|
||||||
insta360_link_protocol::Gesture::LShape,
|
open_360_link_protocol::Gesture::LShape,
|
||||||
self.state.use_gesture_l,
|
self.state.use_gesture_l,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1455,13 +1455,13 @@ impl Insta360App {
|
|||||||
ui.label("Tracking Speed:");
|
ui.label("Tracking Speed:");
|
||||||
egui::ComboBox::from_id_salt("tb_track_speed")
|
egui::ComboBox::from_id_salt("tb_track_speed")
|
||||||
.selected_text(match self.state.track_speed {
|
.selected_text(match self.state.track_speed {
|
||||||
insta360_link_protocol::TrackSpeed::Fast => {
|
open_360_link_protocol::TrackSpeed::Fast => {
|
||||||
"Quick"
|
"Quick"
|
||||||
}
|
}
|
||||||
insta360_link_protocol::TrackSpeed::Normal => {
|
open_360_link_protocol::TrackSpeed::Normal => {
|
||||||
"Ordinary"
|
"Ordinary"
|
||||||
}
|
}
|
||||||
insta360_link_protocol::TrackSpeed::Slow => {
|
open_360_link_protocol::TrackSpeed::Slow => {
|
||||||
"Slow"
|
"Slow"
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -1469,37 +1469,37 @@ impl Insta360App {
|
|||||||
if ui
|
if ui
|
||||||
.selectable_value(
|
.selectable_value(
|
||||||
&mut self.state.track_speed,
|
&mut self.state.track_speed,
|
||||||
insta360_link_protocol::TrackSpeed::Fast,
|
open_360_link_protocol::TrackSpeed::Fast,
|
||||||
"Quick",
|
"Quick",
|
||||||
)
|
)
|
||||||
.clicked()
|
.clicked()
|
||||||
{
|
{
|
||||||
let _ = self.controller.set_track_speed(
|
let _ = self.controller.set_track_speed(
|
||||||
insta360_link_protocol::TrackSpeed::Fast,
|
open_360_link_protocol::TrackSpeed::Fast,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if ui
|
if ui
|
||||||
.selectable_value(
|
.selectable_value(
|
||||||
&mut self.state.track_speed,
|
&mut self.state.track_speed,
|
||||||
insta360_link_protocol::TrackSpeed::Normal,
|
open_360_link_protocol::TrackSpeed::Normal,
|
||||||
"Ordinary",
|
"Ordinary",
|
||||||
)
|
)
|
||||||
.clicked()
|
.clicked()
|
||||||
{
|
{
|
||||||
let _ = self.controller.set_track_speed(
|
let _ = self.controller.set_track_speed(
|
||||||
insta360_link_protocol::TrackSpeed::Normal,
|
open_360_link_protocol::TrackSpeed::Normal,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if ui
|
if ui
|
||||||
.selectable_value(
|
.selectable_value(
|
||||||
&mut self.state.track_speed,
|
&mut self.state.track_speed,
|
||||||
insta360_link_protocol::TrackSpeed::Slow,
|
open_360_link_protocol::TrackSpeed::Slow,
|
||||||
"Slow",
|
"Slow",
|
||||||
)
|
)
|
||||||
.clicked()
|
.clicked()
|
||||||
{
|
{
|
||||||
let _ = self.controller.set_track_speed(
|
let _ = self.controller.set_track_speed(
|
||||||
insta360_link_protocol::TrackSpeed::Slow,
|
open_360_link_protocol::TrackSpeed::Slow,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -2307,9 +2307,9 @@ impl eframe::App for Insta360App {
|
|||||||
let z_read = self.controller.get_zoom().unwrap_or(0);
|
let z_read = self.controller.get_zoom().unwrap_or(0);
|
||||||
let _ = self.controller.set_zoom(100);
|
let _ = self.controller.set_zoom(100);
|
||||||
|
|
||||||
let _ = self.controller.set_track_speed(insta360_link_protocol::TrackSpeed::Fast);
|
let _ = self.controller.set_track_speed(open_360_link_protocol::TrackSpeed::Fast);
|
||||||
let ts_fast = self.controller.get_track_speed().ok();
|
let ts_fast = self.controller.get_track_speed().ok();
|
||||||
let _ = self.controller.set_track_speed(insta360_link_protocol::TrackSpeed::Normal);
|
let _ = self.controller.set_track_speed(open_360_link_protocol::TrackSpeed::Normal);
|
||||||
let ts_norm = self.controller.get_track_speed().ok();
|
let ts_norm = self.controller.get_track_speed().ok();
|
||||||
|
|
||||||
let _ = self.controller.set_auto_exposure(true);
|
let _ = self.controller.set_auto_exposure(true);
|
||||||
@@ -2370,7 +2370,7 @@ impl eframe::App for Insta360App {
|
|||||||
let _ = self.controller.set_all_gestures_enabled(true);
|
let _ = self.controller.set_all_gestures_enabled(true);
|
||||||
let _ = self
|
let _ = self
|
||||||
.controller
|
.controller
|
||||||
.set_gesture_enabled(insta360_link_protocol::Gesture::Palm, true);
|
.set_gesture_enabled(open_360_link_protocol::Gesture::Palm, true);
|
||||||
let gest = self.controller.get_gesture_status().ok();
|
let gest = self.controller.get_gesture_status().ok();
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
@@ -2569,16 +2569,16 @@ fn main() -> eframe::Result<()> {
|
|||||||
// Matching webcam.qml: width: 1440, height: 714, minimumWidth: 1120, minimumHeight: 536
|
// Matching webcam.qml: width: 1440, height: 714, minimumWidth: 1120, minimumHeight: 536
|
||||||
let native_options = eframe::NativeOptions {
|
let native_options = eframe::NativeOptions {
|
||||||
viewport: egui::ViewportBuilder::default()
|
viewport: egui::ViewportBuilder::default()
|
||||||
.with_app_id("insta360-link-controller")
|
.with_app_id("open-360-link")
|
||||||
.with_icon(build_app_icon())
|
.with_icon(build_app_icon())
|
||||||
.with_inner_size([1440.0_f32, 714.0_f32])
|
.with_inner_size([1440.0_f32, 714.0_f32])
|
||||||
.with_min_inner_size([1120.0_f32, 536.0_f32])
|
.with_min_inner_size([1120.0_f32, 536.0_f32])
|
||||||
.with_title("Insta360 Link Controller"),
|
.with_title("Open 360 Link"),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
eframe::run_native(
|
eframe::run_native(
|
||||||
"Insta360 Link Controller",
|
"Open 360 Link",
|
||||||
native_options,
|
native_options,
|
||||||
Box::new(|cc| Ok(Box::new(Insta360App::new(cc)))),
|
Box::new(|cc| Ok(Box::new(Insta360App::new(cc)))),
|
||||||
)
|
)
|
||||||
+1
-1
@@ -2,7 +2,7 @@ use egui::{
|
|||||||
Align, Align2, Color32, Context, FontId, Grid, Layout, Pos2, Rect, RichText, Rounding,
|
Align, Align2, Color32, Context, FontId, Grid, Layout, Pos2, Rect, RichText, Rounding,
|
||||||
ScrollArea, Sense, Stroke, TextEdit, Ui, Vec2,
|
ScrollArea, Sense, Stroke, TextEdit, Ui, Vec2,
|
||||||
};
|
};
|
||||||
use insta360_link_protocol::{
|
use open_360_link_protocol::{
|
||||||
AudioCaptureMode, CameraModel, CompositionStyle, ExposureCurve, FilterMode, HostPtzInfo,
|
AudioCaptureMode, CameraModel, CompositionStyle, ExposureCurve, FilterMode, HostPtzInfo,
|
||||||
ImageOperation, Insta360CameraController, PowerLineFrequency, TrackSpeed, UvcControlTransport,
|
ImageOperation, Insta360CameraController, PowerLineFrequency, TrackSpeed, UvcControlTransport,
|
||||||
Gesture,
|
Gesture,
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
use egui::{ColorImage, Pos2, TextureHandle};
|
use egui::{ColorImage, Pos2, TextureHandle};
|
||||||
pub use insta360_link_protocol::*;
|
pub use open_360_link_protocol::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
@@ -285,7 +285,7 @@ pub struct CameraAppState {
|
|||||||
pub last_saved_settings: Option<PersistedAppSettings>,
|
pub last_saved_settings: Option<PersistedAppSettings>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// User settings persisted across sessions in `~/.config/insta360-link-controller/settings.json`.
|
/// User settings persisted across sessions in `~/.config/open-360-link/settings.json`.
|
||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct PersistedAppSettings {
|
pub struct PersistedAppSettings {
|
||||||
pub format_preset: VideoFormatPreset,
|
pub format_preset: VideoFormatPreset,
|
||||||
@@ -325,12 +325,10 @@ pub struct PersistedAppSettings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl PersistedAppSettings {
|
impl PersistedAppSettings {
|
||||||
pub fn config_path() -> PathBuf {
|
fn base_config_dir() -> PathBuf {
|
||||||
if let Ok(xdg) = std::env::var("XDG_CONFIG_HOME") {
|
if let Ok(xdg) = std::env::var("XDG_CONFIG_HOME") {
|
||||||
if !xdg.trim().is_empty() {
|
if !xdg.trim().is_empty() {
|
||||||
return PathBuf::from(xdg)
|
return PathBuf::from(xdg);
|
||||||
.join("insta360-link-controller")
|
|
||||||
.join("settings.json");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let home = std::env::var("HOME")
|
let home = std::env::var("HOME")
|
||||||
@@ -338,14 +336,29 @@ impl PersistedAppSettings {
|
|||||||
.map(PathBuf::from)
|
.map(PathBuf::from)
|
||||||
.unwrap_or_else(|_| PathBuf::from("."));
|
.unwrap_or_else(|_| PathBuf::from("."));
|
||||||
home.join(".config")
|
home.join(".config")
|
||||||
.join("insta360-link-controller")
|
}
|
||||||
|
|
||||||
|
pub fn config_path() -> PathBuf {
|
||||||
|
Self::base_config_dir()
|
||||||
|
.join("open-360-link")
|
||||||
.join("settings.json")
|
.join("settings.json")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load() -> Option<Self> {
|
pub fn load() -> Option<Self> {
|
||||||
let path = Self::config_path();
|
let path = Self::config_path();
|
||||||
let data = std::fs::read_to_string(path).ok()?;
|
if let Ok(data) = std::fs::read_to_string(&path) {
|
||||||
serde_json::from_str(&data).ok()
|
if let Ok(parsed) = serde_json::from_str(&data) {
|
||||||
|
return Some(parsed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Automatic migration from legacy `~/.config/insta360-link-controller/settings.json`
|
||||||
|
let legacy = Self::base_config_dir()
|
||||||
|
.join("insta360-link-controller")
|
||||||
|
.join("settings.json");
|
||||||
|
let data = std::fs::read_to_string(legacy).ok()?;
|
||||||
|
let parsed: Self = serde_json::from_str(&data).ok()?;
|
||||||
|
parsed.save();
|
||||||
|
Some(parsed)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn save(&self) {
|
pub fn save(&self) {
|
||||||
File renamed without changes.
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
use insta360_link_protocol::{
|
use open_360_link_protocol::{
|
||||||
ct_selectors, pu_selectors, xu1_selectors, xu2_selectors, CameraModel, DiscoveredCamera,
|
ct_selectors, pu_selectors, xu1_selectors, xu2_selectors, CameraModel, DiscoveredCamera,
|
||||||
MockCameraTransport, NusbTransport, TransportError, UvcControlPacketHeader,
|
MockCameraTransport, NusbTransport, TransportError, UvcControlPacketHeader,
|
||||||
UvcControlTransport, UvcRequest, UvcUnitIds,
|
UvcControlTransport, UvcRequest, UvcUnitIds,
|
||||||
+1
-1
@@ -3,7 +3,7 @@ use crate::state::{
|
|||||||
SHUTTER_DENOM_LIST,
|
SHUTTER_DENOM_LIST,
|
||||||
};
|
};
|
||||||
use egui::{Color32, ColorImage, Context, TextureHandle, TextureOptions};
|
use egui::{Color32, ColorImage, Context, TextureHandle, TextureOptions};
|
||||||
use insta360_link_protocol::{TrackSpeed, UvcRect, VideoMode};
|
use open_360_link_protocol::{TrackSpeed, UvcRect, VideoMode};
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::process::{Child, ChildStdin, Command, Stdio};
|
use std::process::{Child, ChildStdin, Command, Stdio};
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "insta360-link-protocol"
|
name = "open-360-link-protocol"
|
||||||
version.workspace = true
|
version.workspace = true
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
description = "Pure-Rust cross-platform UVC & Extension Unit protocol library for Insta360 Link, Link 2, and Link 2C webcams"
|
description = "Open 360 Link: Pure-Rust cross-platform UVC & Extension Unit protocol library for Insta360 Link, Link 2, and Link 2C webcams"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
thiserror.workspace = true
|
thiserror.workspace = true
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
use insta360_link_protocol::*;
|
use open_360_link_protocol::*;
|
||||||
|
|
||||||
/// Builds a synthetic USB Configuration Descriptor containing:
|
/// Builds a synthetic USB Configuration Descriptor containing:
|
||||||
/// - Standard Interface Descriptor for UVC VideoControl (`bInterfaceNumber = 2`, `CC_VIDEO = 0x0e`, `SC_VIDEOCONTROL = 0x01`)
|
/// - Standard Interface Descriptor for UVC VideoControl (`bInterfaceNumber = 2`, `CC_VIDEO = 0x0e`, `SC_VIDEOCONTROL = 0x01`)
|
||||||
@@ -1,16 +1,16 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "insta360-link-server"
|
name = "open-360-link-server"
|
||||||
version.workspace = true
|
version.workspace = true
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
description = "Cross-platform HTTP REST & WebSocket remote control server for Insta360 Link cameras"
|
description = "Open 360 Link: Cross-platform HTTP REST & WebSocket remote control server for Insta360 Link cameras"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "insta360-link-server"
|
name = "open-360-link-server"
|
||||||
path = "src/main.rs"
|
path = "src/main.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
insta360-link-protocol = { path = "../insta360-link-protocol" }
|
open-360-link-protocol = { path = "../open-360-link-protocol" }
|
||||||
clap.workspace = true
|
clap.workspace = true
|
||||||
tokio.workspace = true
|
tokio.workspace = true
|
||||||
axum.workspace = true
|
axum.workspace = true
|
||||||
@@ -7,7 +7,7 @@ use axum::{
|
|||||||
routing::{get, post},
|
routing::{get, post},
|
||||||
Json, Router,
|
Json, Router,
|
||||||
};
|
};
|
||||||
use insta360_link_protocol::{
|
use open_360_link_protocol::{
|
||||||
list_connected_cameras, AudioCaptureMode, CameraModel, CompositionStyle, DeviceCapabilities,
|
list_connected_cameras, AudioCaptureMode, CameraModel, CompositionStyle, DeviceCapabilities,
|
||||||
DeviceInfo, DiscoveredCamera, ExtendFunction, FilterMode, ForbiddenAreaInfo, Gesture,
|
DeviceInfo, DiscoveredCamera, ExtendFunction, FilterMode, ForbiddenAreaInfo, Gesture,
|
||||||
GestureFunction, HostPtzInfo, Insta360CameraController, MockCameraTransport, NusbTransport,
|
GestureFunction, HostPtzInfo, Insta360CameraController, MockCameraTransport, NusbTransport,
|
||||||
@@ -1,16 +1,16 @@
|
|||||||
use clap::{Parser, ValueEnum};
|
use clap::{Parser, ValueEnum};
|
||||||
use insta360_link_protocol::{
|
use open_360_link_protocol::{
|
||||||
CameraModel, Insta360CameraController, NusbTransport, UvcControlTransport,
|
CameraModel, Insta360CameraController, NusbTransport, UvcControlTransport,
|
||||||
};
|
};
|
||||||
use insta360_link_server::{build_router, new_mock_state, AppState, ServerTransport};
|
use open_360_link_server::{build_router, new_mock_state, AppState, ServerTransport};
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
#[command(
|
#[command(
|
||||||
name = "insta360-link-server",
|
name = "open-360-link-server",
|
||||||
version,
|
version,
|
||||||
about = "Cross-platform HTTP REST & WebSocket remote control server for Insta360 Link cameras"
|
about = "Open 360 Link: Cross-platform HTTP REST & WebSocket remote control server for Insta360 Link cameras"
|
||||||
)]
|
)]
|
||||||
struct Cli {
|
struct Cli {
|
||||||
/// Bind address for HTTP and WebSocket server
|
/// Bind address for HTTP and WebSocket server
|
||||||
@@ -47,7 +47,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
tracing_subscriber::fmt()
|
tracing_subscriber::fmt()
|
||||||
.with_env_filter(
|
.with_env_filter(
|
||||||
tracing_subscriber::EnvFilter::try_from_default_env()
|
tracing_subscriber::EnvFilter::try_from_default_env()
|
||||||
.unwrap_or_else(|_| "insta360_link_server=info,tower_http=info".into()),
|
.unwrap_or_else(|_| "open_360_link_server=info,tower_http=info".into()),
|
||||||
)
|
)
|
||||||
.init();
|
.init();
|
||||||
|
|
||||||
+2
-2
@@ -1,11 +1,11 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
|
|
||||||
use insta360_link_protocol::{
|
use open_360_link_protocol::{
|
||||||
AudioCaptureMode, CameraModel, CompositionStyle, ExtendFunction, FilterMode, Gesture,
|
AudioCaptureMode, CameraModel, CompositionStyle, ExtendFunction, FilterMode, Gesture,
|
||||||
GestureFunction, TrackSpeed, VideoMode,
|
GestureFunction, TrackSpeed, VideoMode,
|
||||||
};
|
};
|
||||||
use insta360_link_server::{
|
use open_360_link_server::{
|
||||||
build_router, new_mock_state, AudioRequest, CameraStateSnapshot, ImageRequest, ModeRequest,
|
build_router, new_mock_state, AudioRequest, CameraStateSnapshot, ImageRequest, ModeRequest,
|
||||||
PresetRequest, PtzRequest, SystemRequest, TrackingRequest,
|
PresetRequest, PtzRequest, SystemRequest, TrackingRequest,
|
||||||
};
|
};
|
||||||
@@ -2,20 +2,20 @@
|
|||||||
rust = "stable"
|
rust = "stable"
|
||||||
|
|
||||||
[tasks.default]
|
[tasks.default]
|
||||||
description = "Build and launch the Insta360 Link Controller desktop GUI"
|
description = "Build and launch the Open 360 Link desktop GUI"
|
||||||
depends = ["gui"]
|
depends = ["gui"]
|
||||||
|
|
||||||
[tasks.gui]
|
[tasks.gui]
|
||||||
description = "Build and launch the Insta360 Link Controller desktop GUI"
|
description = "Build and launch the Open 360 Link desktop GUI"
|
||||||
run = "cargo run --release -p insta360-link-gui"
|
run = "cargo run --release -p open-360-link-gui"
|
||||||
|
|
||||||
[tasks.cli]
|
[tasks.cli]
|
||||||
description = "Run the insta360-link-ctl CLI (e.g. mise run cli -- info)"
|
description = "Run the open-360-link-ctl CLI (e.g. mise run cli -- info)"
|
||||||
run = "cargo run --release -p insta360-link-cli --"
|
run = "cargo run --release -p open-360-link-cli --"
|
||||||
|
|
||||||
[tasks.server]
|
[tasks.server]
|
||||||
description = "Start the HTTP & WebSocket remote control server on 127.0.0.1:8360"
|
description = "Start the HTTP & WebSocket remote control server on 127.0.0.1:8360"
|
||||||
run = "cargo run --release -p insta360-link-server --"
|
run = "cargo run --release -p open-360-link-server --"
|
||||||
|
|
||||||
[tasks.build]
|
[tasks.build]
|
||||||
description = "Build all workspace crates in release mode"
|
description = "Build all workspace crates in release mode"
|
||||||
@@ -27,7 +27,7 @@ run = "cargo test --workspace"
|
|||||||
|
|
||||||
[tasks.self-test]
|
[tasks.self-test]
|
||||||
description = "Run the automated live hardware GUI verification sequence"
|
description = "Run the automated live hardware GUI verification sequence"
|
||||||
run = "INSTA360_GUI_SELF_TEST=1 cargo run --release -p insta360-link-gui"
|
run = "INSTA360_GUI_SELF_TEST=1 cargo run --release -p open-360-link-gui"
|
||||||
|
|
||||||
[tasks.package-release]
|
[tasks.package-release]
|
||||||
description = "Build and package release binaries for a target (usage: mise run package-release [target] [version])"
|
description = "Build and package release binaries for a target (usage: mise run package-release [target] [version])"
|
||||||
@@ -67,15 +67,15 @@ case "$TARGET" in
|
|||||||
*) ASSET_SUFFIX="$TARGET"; EXT="tar.gz" ;;
|
*) ASSET_SUFFIX="$TARGET"; EXT="tar.gz" ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
STAGE_NAME="insta360-link-controller-v${VERSION}-${ASSET_SUFFIX}"
|
STAGE_NAME="open-360-link-v${VERSION}-${ASSET_SUFFIX}"
|
||||||
STAGE_DIR="dist/${STAGE_NAME}"
|
STAGE_DIR="dist/${STAGE_NAME}"
|
||||||
rm -rf "$STAGE_DIR"
|
rm -rf "$STAGE_DIR"
|
||||||
mkdir -p "$STAGE_DIR"
|
mkdir -p "$STAGE_DIR"
|
||||||
|
|
||||||
if [ "$EXT" = "zip" ]; then
|
if [ "$EXT" = "zip" ]; then
|
||||||
cp "target/${TARGET}/release/insta360-link-gui.exe" "$STAGE_DIR/"
|
cp "target/${TARGET}/release/open-360-link-gui.exe" "$STAGE_DIR/"
|
||||||
cp "target/${TARGET}/release/insta360-link-ctl.exe" "$STAGE_DIR/"
|
cp "target/${TARGET}/release/open-360-link-ctl.exe" "$STAGE_DIR/"
|
||||||
cp "target/${TARGET}/release/insta360-link-server.exe" "$STAGE_DIR/"
|
cp "target/${TARGET}/release/open-360-link-server.exe" "$STAGE_DIR/"
|
||||||
cp README.md "$STAGE_DIR/"
|
cp README.md "$STAGE_DIR/"
|
||||||
python3 -c '
|
python3 -c '
|
||||||
import pathlib, sys, zipfile
|
import pathlib, sys, zipfile
|
||||||
@@ -88,9 +88,9 @@ with zipfile.ZipFile(out_zip, "w", zipfile.ZIP_DEFLATED) as zf:
|
|||||||
' "$STAGE_DIR" "dist/${STAGE_NAME}.zip"
|
' "$STAGE_DIR" "dist/${STAGE_NAME}.zip"
|
||||||
echo "Packaged dist/${STAGE_NAME}.zip"
|
echo "Packaged dist/${STAGE_NAME}.zip"
|
||||||
else
|
else
|
||||||
cp "target/${TARGET}/release/insta360-link-gui" "$STAGE_DIR/"
|
cp "target/${TARGET}/release/open-360-link-gui" "$STAGE_DIR/"
|
||||||
cp "target/${TARGET}/release/insta360-link-ctl" "$STAGE_DIR/"
|
cp "target/${TARGET}/release/open-360-link-ctl" "$STAGE_DIR/"
|
||||||
cp "target/${TARGET}/release/insta360-link-server" "$STAGE_DIR/"
|
cp "target/${TARGET}/release/open-360-link-server" "$STAGE_DIR/"
|
||||||
cp README.md "$STAGE_DIR/"
|
cp README.md "$STAGE_DIR/"
|
||||||
cp -r assets "$STAGE_DIR/"
|
cp -r assets "$STAGE_DIR/"
|
||||||
tar -C dist -czf "dist/${STAGE_NAME}.tar.gz" "$STAGE_NAME"
|
tar -C dist -czf "dist/${STAGE_NAME}.tar.gz" "$STAGE_NAME"
|
||||||
@@ -107,7 +107,7 @@ set -euo pipefail
|
|||||||
VER="${1:-0.1.0}"
|
VER="${1:-0.1.0}"
|
||||||
VER="${VER#v}"
|
VER="${VER#v}"
|
||||||
env -u GITHUB_TOKEN -u GH_TOKEN -u GITHUB_AUTH_TOKEN gh workflow run release.yml \
|
env -u GITHUB_TOKEN -u GH_TOKEN -u GITHUB_AUTH_TOKEN gh workflow run release.yml \
|
||||||
--repo lucasoskorep/insta360-link-controller \
|
--repo lucasoskorep/open-360-link \
|
||||||
--ref master \
|
--ref master \
|
||||||
-f version="$VER"
|
-f version="$VER"
|
||||||
echo "Triggered release workflow on master for v${VER}"
|
echo "Triggered release workflow on master for v${VER}"
|
||||||
|
|||||||
Reference in new issue
Block a user