Playjector API
Game capture and control bridge for communicating with the native C++ Playjector application via TCP sockets
Quick Navigation
Game Capture
Direct communication with native C++ game capture engine
TCP Socket Bridge
Reliable TCP communication with automatic reconnection
Process Management
Automatic spawning and lifecycle management of Playjector process
Quick Start
Get started with the Playjector connector:
import { makePlayjectorConnector } from '@playcastdotio/PlayjectorConnector';
const connector = makePlayjectorConnector(7555, {
callbacks: {
message: (message) => {
console.log('Received from Playjector:', message);
handlePlayjectorMessage(message);
},
ready: () => {
console.log('Playjector connected and ready');
// Start sending commands
},
error: (error) => {
console.error('Playjector error:', error);
},
close: () => {
console.log('Playjector connection closed');
}
},
spawn: {
path: 'C:\\Program Files (x86)\\PlayCast\\PlayJector',
args: ['-default_port', '7555'],
spawnWaitTime: 1000
},
autoReconnect: {
enabled: true,
timeout: 3000
}
});
// Connect to Playjector
await connector.connect();
Connector Configuration
Configure the Playjector connector with callbacks, spawning options, and connection settings.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| port | number | Required | TCP port for communication with Playjector |
| config | PlayjectorConfig | Required | Configuration object with callbacks and options |
Configuration Sections
Callbacks
Event handlers for Playjector communication and lifecycle events.
- message(message) - Handle incoming messages from Playjector
- ready() - Called when connection is established
- refused() - Called when connection is refused
- reset() - Called when connection is reset
- error(message) - Handle connection errors
- close() - Called when connection closes
- playjectorClose(code) - Called when Playjector process exits
- disconnected() - Called when connector disconnects
const config = {
callbacks: {
message: (message) => {
// Validate and process message
if (validators.validatePlaycastMessage(message)) {
handleValidMessage(message);
}
},
ready: () => {
// Connection established, send initialization commands
connector.sendMessage(initializationMessage);
},
error: (errorMsg) => {
// Log error and notify user
logger.error('Playjector error:', errorMsg);
notifyUser('Connection error occurred');
},
playjectorClose: (exitCode) => {
// Handle process exit
if (exitCode !== 0) {
logger.warn('Playjector exited with code:', exitCode);
}
}
}
};
Process Spawning
Configure automatic spawning of the Playjector process.
| Option | Type | Default | Description |
|---|---|---|---|
| path | string | Auto-detected | Path to Playjector executable directory |
| args | string[] | [] | Command line arguments for Playjector |
| spawnWaitTime | number | 500 | Time to wait after spawning process (ms) |
| logging.port | number | undefined | Port for Playjector logging output |
const config = {
spawn: {
path: 'C:\\Program Files (x86)\\PlayCast\\PlayJector',
args: [
'-default_port', '7555',
'-quality', 'high',
'-fps', '60'
],
spawnWaitTime: 1500, // Wait longer for slower systems
logging: {
port: 7556 // Enable logging on separate port
}
}
};
Auto-Reconnect
Configure automatic reconnection behavior when connection is lost.
| Option | Type | Default | Description |
|---|---|---|---|
| enabled | boolean | false | Enable automatic reconnection |
| timeout | number | 3000 | Time between reconnection attempts (ms) |
const config = {
autoReconnect: {
enabled: true,
timeout: 5000 // Wait 5 seconds between attempts
},
maxConnectionAttempts: 10 // Limit total attempts
};
Additional Options
| Option | Type | Default | Description |
|---|---|---|---|
| disableMessageVerification | boolean | false | Skip message validation for performance |
| hostIpOverride | string | '127.0.0.1' | Override connection IP address |
| maxConnectionAttempts | number | -1 (unlimited) | Maximum number of connection attempts |
| logging | boolean | false | Enable detailed logging |
Connection Management
Managing the TCP connection to the Playjector process.
Connection Methods
Establish connection to Playjector. Will spawn process if configured and needed.
Close connection and terminate Playjector process if spawned.
// Connect with error handling
try {
await connector.connect();
console.log('Successfully connected to Playjector');
} catch (error) {
console.error('Failed to connect:', error);
// Handle connection failure
handleConnectionError(error);
}
// Disconnect cleanly
connector.disconnect();
console.log('Disconnected from Playjector');
Connection States and Events
const connector = makePlayjectorConnector(7555, {
callbacks: {
ready: () => {
// Connection established successfully
updateConnectionStatus('connected');
enableGameControls();
},
refused: () => {
// Connection refused (Playjector not listening)
updateConnectionStatus('refused');
showRetryButton();
},
reset: () => {
// Connection was reset unexpectedly
updateConnectionStatus('reset');
attemptReconnection();
},
close: () => {
// Connection closed normally
updateConnectionStatus('closed');
disableGameControls();
},
error: (errorMsg) => {
// Connection error occurred
updateConnectionStatus('error');
showErrorMessage(errorMsg);
}
}
});
Message Handling
Sending and receiving messages through the Playjector bridge.
Sending Messages
import { generators } from '@playcastdotio/Messaging';
// Send gamepad input
const gamepadMessage = generators.gamepad.createButtonEvent({
userId: 'player123',
button: 'A',
pressed: true,
timestamp: Date.now()
});
connector.sendMessage(gamepadMessage);
// Send mouse input
const mouseMessage = generators.mouse.createMoveEvent({
userId: 'player123',
x: 100,
y: 200,
deltaX: 5,
deltaY: -3,
timestamp: Date.now()
});
connector.sendMessage(mouseMessage);
// Send stream quality command
const qualityMessage = generators.stream.createQualityChange({
userId: 'player123',
preset: 'high',
bitrate: 5000000,
timestamp: Date.now()
});
connector.sendMessage(qualityMessage);
Receiving Messages
const connector = makePlayjectorConnector(7555, {
callbacks: {
message: (message) => {
// Messages are automatically validated unless disabled
console.log('Message type:', message.header.target);
console.log('Action:', message.header.action);
// Route message based on type
switch (message.header.target) {
case 'stream':
handleStreamMessage(message);
break;
case 'system':
handleSystemMessage(message);
break;
case 'encoder':
handleEncoderMessage(message);
break;
default:
console.log('Unknown message type:', message.header.target);
}
}
}
});
function handleStreamMessage(message) {
switch (message.header.action) {
case 'qualityChanged':
updateQualityIndicator(message.body.message.quality);
break;
case 'frameRateChanged':
updateFrameRateDisplay(message.body.message.frameRate);
break;
case 'bitrateChanged':
updateBitrateDisplay(message.body.message.bitrate);
break;
}
}
Message Capture and Debugging
const connector = makePlayjectorConnector(7555, {
captureMessages: {
enabled: true,
maximumMessagesToCapture: 1000,
outgoing: [],
incoming: [],
combinedState: [],
onMessageSent: (message) => {
console.log('Sent to Playjector:', message.header.target);
},
onMessageReceived: (message) => {
console.log('Received from Playjector:', message.header.target);
}
}
});
// Access captured messages for debugging
console.log('Outgoing messages:', connector.config.captureMessages.outgoing);
console.log('Incoming messages:', connector.config.captureMessages.incoming);
console.log('All messages:', connector.config.captureMessages.combinedState);
Process Spawning
Automatic management of the Playjector process lifecycle.
Process Discovery
The connector automatically searches for the Playjector executable in standard installation paths:
C:\Program Files (x86)\PlayCast\PlayJector- Custom path specified in configuration
const connector = makePlayjectorConnector(7555, {
spawn: {
// Custom installation path
path: 'D:\\Games\\PlayCast\\PlayJector',
args: [
'-default_port', '7555',
'-quality', 'ultra',
'-fps', '120',
'-resolution', '1920x1080'
],
spawnWaitTime: 2000 // Wait 2 seconds for startup
},
callbacks: {
playjectorClose: (exitCode) => {
if (exitCode === 0) {
console.log('Playjector exited normally');
} else {
console.error('Playjector crashed with code:', exitCode);
// Handle crash recovery
handlePlayjectorCrash(exitCode);
}
}
}
});
Process Arguments
| Argument | Description | Example |
|---|---|---|
| -default_port | TCP port for communication | '-default_port', '7555' |
| -logging_port | Port for logging output | '-logging_port', '7556' |
| -quality | Initial quality preset | '-quality', 'high' |
| -fps | Target frame rate | '-fps', '60' |
| -resolution | Capture resolution | '-resolution', '1920x1080' |
Auto-Reconnect
Robust reconnection handling for network issues and process failures.
Reconnection Scenarios
- Connection Refused - Playjector not running or port busy
- Connection Reset - Network issue or Playjector restart
- Connection Closed - Normal disconnection with reconnect enabled
- Process Exit - Playjector process crashed or was terminated
const connector = makePlayjectorConnector(7555, {
autoReconnect: {
enabled: true,
timeout: 3000 // 3 second delay between attempts
},
maxConnectionAttempts: 5, // Limit attempts to prevent infinite loop
callbacks: {
refused: () => {
console.log('Connection refused, will retry...');
updateConnectionStatus('reconnecting');
},
reset: () => {
console.log('Connection reset, attempting reconnection...');
updateConnectionStatus('reconnecting');
},
close: () => {
if (autoReconnectEnabled) {
console.log('Connection closed, will reconnect...');
updateConnectionStatus('reconnecting');
} else {
updateConnectionStatus('disconnected');
}
},
ready: () => {
console.log('Reconnection successful');
updateConnectionStatus('connected');
resetConnectionAttemptCounter();
}
}
});
Manual Reconnection Control
// Disable auto-reconnect temporarily
connector.config.autoReconnect.enabled = false;
// Manual reconnection with custom logic
async function manualReconnect() {
const maxRetries = 3;
let retryCount = 0;
while (retryCount < maxRetries) {
try {
await connector.connect();
console.log('Manual reconnection successful');
return true;
} catch (error) {
retryCount++;
console.log(`Manual reconnection attempt ${retryCount} failed`);
if (retryCount < maxRetries) {
// Progressive backoff
const delay = Math.pow(2, retryCount) * 1000;
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
console.error('Manual reconnection failed after all attempts');
return false;
}
// Re-enable auto-reconnect
connector.config.autoReconnect.enabled = true;
Error Handling and Troubleshooting
Common issues and solutions when working with the Playjector connector.
Common Errors
Playjector Path Not Found
// Error: "Playjector path does not exist"
// Solution: Specify correct path or install Playjector
const connector = makePlayjectorConnector(7555, {
spawn: {
// Check if path exists before using
path: process.env.PLAYJECTOR_PATH ||
'C:\\Program Files (x86)\\PlayCast\\PlayJector'
},
callbacks: {
error: (errorMsg) => {
if (errorMsg.includes('path does not exist')) {
showPlayjectorInstallationPrompt();
}
}
}
});
Port Already in Use
// Error: "EADDRINUSE" - Port already in use
// Solution: Use different port or kill existing process
const connector = makePlayjectorConnector(7555, {
callbacks: {
refused: () => {
// Try alternative port
tryAlternativePort();
}
}
});
async function tryAlternativePort() {
const alternatePorts = [7556, 7557, 7558];
for (const port of alternatePorts) {
try {
const newConnector = makePlayjectorConnector(port, config);
await newConnector.connect();
console.log(`Connected on alternative port: ${port}`);
return newConnector;
} catch (error) {
continue;
}
}
throw new Error('No available ports found');
}
Message Validation Failures
// Error: "Message from PlayJector failed validation"
// Solution: Enable logging to debug message format
const connector = makePlayjectorConnector(7555, {
logging: true, // Enable detailed logging
disableMessageVerification: false, // Keep validation enabled
callbacks: {
message: (message) => {
try {
// Additional validation
if (typeof message === 'string') {
console.log('Raw message:', message);
message = JSON.parse(message);
}
if (message && message.header && message.body) {
handleValidMessage(message);
} else {
console.warn('Invalid message structure:', message);
}
} catch (error) {
console.error('Message processing error:', error);
}
}
}
});