@mcesystems/usbmuxd-instance-manager
v1.0.85
Published
Multi-instance manager for usbmuxd-win-mce - manages multiple usbmuxd processes with batch device allocation
Downloads
1,366
Maintainers
Readme
usbmuxd Instance Manager
Multi-instance manager for usbmuxd-win-mce
Automatically manages multiple usbmuxd instances with intelligent batch device allocation to prevent freezing when handling many iOS devices simultaneously.
Features
- Automatic Device Detection: Uses
usb-device-listenerto detect iOS device connections - Batch Allocation: Groups devices (default: 4 per instance) for optimal resource usage
- Dynamic Scaling: Spawns new instances as needed, terminates when empty
- Isolated Failures: One instance crash doesn't affect others
- Zero Configuration: Works out-of-the-box with sensible defaults
Architecture
┌──────────────────────────────────────────────────────────────┐
│ Windows Host │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ usbmuxd-instance-manager (Node.js) │ │
│ │ ┌──────────────────────────────────────────────────┐ │ │
│ │ │ usb-device-listener │ │ │
│ │ │ Detects iOS devices (VID: 0x05AC) │ │ │
│ │ └──────────────┬───────────────────────────────────┘ │ │
│ │ │ │ │
│ │ ┌──────────────▼───────────────────────────────────┐ │ │
│ │ │ InstanceManager │ │ │
│ │ │ - Batch allocation (4 devices per instance) │ │ │
│ │ │ - Port assignment (27015, 27016, 27017...) │ │ │
│ │ │ - Spawns via WSL2 │ │ │
│ │ └──────────────┬───────────────────────────────────┘ │ │
│ └─────────────────┼──────────────────────────────────────┘ │
│ │ wsl -d usbmuxd-alpine usbmuxd ... │
│ ┌─────────────────▼──────────────────────────────────────┐ │
│ │ WSL2 - Alpine Linux (26MB) │ │
│ │ ┌──────────────────┐ ┌──────────────────┐ │ │
│ │ │ usbmuxd instance │ │ usbmuxd instance │ │ │
│ │ │ Port: 27015 │ │ Port: 27016 │ ... │ │
│ │ │ Devices 1-4 │ │ Devices 5-8 │ │ │
│ │ └──────────────────┘ └──────────────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘Installation
# From workspace root
pnpm install
# Build the package
pnpm --filter @mcesystems/usbmuxd-instance-manager buildUsage
CLI
# Run with defaults
pnpm --filter @mcesystems/usbmuxd-instance-manager dev
# Or after building
node dist/cli.js
# With custom options
node dist/cli.js --batchSize 6 --basePort 27020Programmatic API
import { UsbmuxdService } from '@mcesystems/usbmuxd-instance-manager';
const service = new UsbmuxdService({
batchSize: 4,
basePort: 27015,
maxInstances: 20,
usbmuxdPath: 'usbmuxd', // Path inside WSL2
wslDistribution: 'usbmuxd-alpine', // Alpine WSL2 distro
verboseLogging: true,
});
// Start monitoring
service.start();
// Get device port mapping
const port = service.getDevicePort('00008030-001234567890402E');
console.log(`Device is on port ${port}`);
// Get statistics
const stats = service.getStats();
console.log(`Managing ${stats.deviceCount} devices across ${stats.instanceCount} instances`);
// Stop when done
await service.stop();Configuration
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| batchSize | number | 4 | Devices per instance |
| basePort | number | 27015 | Starting TCP port |
| maxInstances | number | 20 | Maximum instances |
| usbmuxdPath | string | usbmuxd | Path to usbmuxd inside WSL2 |
| wslDistribution | string | usbmuxd-alpine | Alpine WSL2 distribution name |
| verboseLogging | boolean | true | Enable verbose output |
| appleVendorId | string | '05AC' | Apple vendor ID (hex) |
Lockdown sync
The manager automatically syncs lockdown (pairing) files between the native Apple/iTunes lockdown directory and Alpine so devices that were already paired on Windows can be used without pairing again in WSL.
The lockdown directory is resolved per platform:
- Windows:
C:\ProgramData\Apple\Lockdown(same directory used by iTunes / Apple Mobile Device) - macOS:
/var/db/lockdown - Linux:
/var/lib/lockdown
Sync behavior:
- To Alpine: When a device is assigned, that device's plist (
{UDID}.plist) andSystemConfiguration.plistare copied from the Apple lockdown directory to Alpine/var/lib/lockdown. - From Alpine: When the service stops, plists for all devices that were assigned this session (plus
SystemConfiguration.plistif present) are copied from Alpine back to the Apple lockdown directory so they are available for the next run.
Alpine permissions: /var/lib/lockdown is often root-owned. The sync tries a normal copy first; if that fails (e.g. permission denied), it retries with sudo cp. Ensure the WSL user has passwordless sudo for these commands, or that the Alpine image has /var/lib/lockdown writable by the default user. If both fail, a warning is logged and device assignment continues (pairing can still be done manually).
CLI Options
Usage: usbmuxd-instance-manager [OPTIONS]
Options:
--batchSize <n> Number of devices per instance (default: 4)
--basePort <port> Base TCP port for first instance (default: 27015)
--maxInstances <n> Maximum number of instances (default: 20)
--usbmuxdPath <path> Path to usbmuxd executable (WSL: default usbmuxd)
--wslDistribution <n> WSL distribution name (default: alpine-usbmuxd-build)
--verbose <true|false> Enable verbose logging (default: true)
--appleVid <vid> Apple Vendor ID in hex (default: 05AC)
-h, --help Show this help messageEvents
The InstanceManager and UsbmuxdService emit events for monitoring:
service.manager.on('instance-started', (instance) => {
console.log(`Instance ${instance.id} started on port ${instance.port}`);
});
service.manager.on('instance-stopped', (instance) => {
console.log(`Instance ${instance.id} stopped`);
});Example Scenario
12 Devices Connected
Instance 1 (port 27015): iPhone-1, iPhone-2, iPhone-3, iPhone-4
Instance 2 (port 27016): iPhone-5, iPhone-6, iPhone-7, iPhone-8
Instance 3 (port 27017): iPhone-9, iPhone-10, iPhone-11, iPhone-12Device Disconnects
When iPhone-3 disconnects:
- Instance 1 now has 3 devices
- Next device connects → assigned to Instance 1 (has capacity)
When all devices disconnect from Instance 2:
- Instance 2 automatically terminates
- Frees resources
Flow: Working with usbipd and WSL
On Windows, the same physical USB device can be used by either Windows (e.g. iTunes, Apple Mobile Device) or WSL (usbmuxd), not both. usbipd-win is what moves the device between the two.
Device ownership
| State | Who has the device | iTunes / Windows | usbmuxd (WSL) | |-------|--------------------|------------------|---------------| | Not shared | Windows | ✓ | ✗ | | Bound + attached to WSL | WSL | ✗ | ✓ | | Bound but detached | Neither (held by usbipd) | ✗ | ✗ |
Giving the device to usbmuxd (instance manager)
- WSL must be running (e.g. the manager starts it, or run
wsl -d alpine-usbmuxd-build -- echo ok). - Bind the device (take it from Windows):
usbipd bind --busid <BUSID> --force - Attach to WSL:
usbipd attach --wsl=<distro> --busid=<BUSID>
The instance manager does steps 2–3 automatically when it sees an iOS device. You can also use the script:
# From packages/usbmuxd-instance-manager
.\scripts\attach-device.ps1Giving the device back to Windows (e.g. for iTunes)
- Detach from WSL (stops forwarding to Linux):
usbipd detach --busid <BUSID>
Or detach all:usbipd detach -a - Unbind so Windows gets the device back:
usbipd unbind --busid <BUSID>
Until you unbind, the device stays "Shared (forced)" and Windows/iTunes will not see it.
Useful usbipd commands
$usbipd = "C:\Program Files\usbipd-win\usbipd.exe"
# List devices and their state (Shared / Not shared, Attached / Not attached)
& $usbipd list
# Detach from WSL (device still bound to usbipd)
& $usbipd detach --busid 2-5
& $usbipd detach -a
# Unbind so Windows can use the device again (e.g. iTunes)
& $usbipd unbind --busid 2-5Quick reference
- Use device with usbmuxd-instance-manager → bind + attach (manager or script does this when you connect a device).
- Use device with iTunes on Windows → detach then unbind for that bus ID; then iTunes will see it.
Requirements
Runtime
- Node.js: 18+
- Windows: 10/11 with WSL2
- Alpine WSL2 image: usbmuxd-alpine distribution imported
- USB/IP: usbipd-win for USB device forwarding to WSL2
Build
- pnpm: Workspace package manager
- TypeScript: 5.9+
- esbuild: For bundling
Development
# Install dependencies
pnpm install
# Run in dev mode (with auto-reload)
pnpm --filter @mcesystems/usbmuxd-instance-manager dev
# Build
pnpm --filter @mcesystems/usbmuxd-instance-manager build
# Type check
pnpm --filter @mcesystems/usbmuxd-instance-manager check:types
# Clean
pnpm --filter @mcesystems/usbmuxd-instance-manager cleanTroubleshooting
Service Won't Start
- Check usbmuxd path: Ensure
usbmuxdPathpoints to valid executable - Check permissions: Run as Administrator if needed
- Check ports: Ensure ports 27015+ are not in use
Devices Not Detected
- Check USB drivers: iOS devices need WinUSB driver (install via Zadig)
- Check VID: Ensure
appleVendorIdis correct ('05AC' for Apple) - Check logs: Run with verbose logging enabled
Instance Crashes
- Check usbmuxd logs: Look at instance output in console
- Check USB driver: Device might need driver reinstall
- Restart service: Service will spawn new instance for remaining devices
Seeing running usbmuxd
To verify that usbmuxd is running inside the WSL distribution, run ps -ef in that distro (use the same distribution name as in your config, e.g. alpine-usbmuxd-build):
PS C:\WINDOWS\system32> wsl -d alpine-usbmuxd-build -e ps -ef
PID USER TIME COMMAND
1 root 0:00 {init(alpine-usb} /init
4 root 0:00 {init} plan9 --control-socket 6 --log-level 4 --server-fd 7 --pipe-fd 9 --log-truncate
7 root 0:00 {SessionLeader} /init
8 root 0:00 {Relay(9)} /init
9 root 0:00 /bin/sh
36 root 0:00 {Relay(37)} /init
37 root 0:00 /bin/sh
38 root 0:00 usbmuxd -f -v -S 0.0.0.0:27015 --pidfile NONE
43 root 0:00 {SessionLeader} /init
44 root 0:00 {Relay(45)} /init
45 root 0:00 ps -efThe usbmuxd daemon appears as PID 38 (or similar) with arguments like usbmuxd -f -v -S 0.0.0.0:27015 --pidfile NONE.
Performance
Resource Usage (20 devices, 5 instances)
- CPU: 15-20%
- Memory: ~400MB total (~80MB per instance)
- Startup Time: ~500ms per instance
vs. Single Instance (iTunes-style)
| Metric | Single Instance | Multi-Instance (5x) | |--------|----------------|---------------------| | CPU | 25-40% | 15-20% | | Memory | 800MB | 400MB | | Freezing | Frequent | None | | Crash Impact | All devices | 4 devices max |
License
UNLICENSED - Private/Proprietary
This package is separate from the GPL-licensed usbmuxd-win-mce fork and remains proprietary.
See Also
- usbmuxd-win-mce - The usbmuxd fork for Windows
- usb-device-listener - USB device detection library
