Skip to content
CineWindows logoCineWindows
Esc
navigateopen⌘Jpreview
On this page

IPC Protocol

Control CineWindows remotely via JSON-RPC over TCP or stdin

CineWindows implements the mpv JSON IPC protocol over TCP and stdin, enabling external tools and scripts to control playback, query properties, and receive real-time events.

Port 32321 Protocol mpv JSON IPC Encoding UTF-8

Enabling IPC

TCP Server

CLI Mode

Both Simultaneously

Request / Response Format

Messages are newline-delimited JSON (\n). Every request and response carries a request_id for correlation.

{"command":["get_property","time-pos"],"request_id":1}
{"error":"success","request_id":1,"data":42.5}
{"error":"property not found","request_id":1,"data":null}

Command Reference

Command Arguments Description
loadfile url, replace|append Load a media file or URL
playlist-next Next playlist item
playlist-prev Previous playlist item
playlist-play-index index Play item at index
stop Stop playback
quit Quit the application
set property, value Set a property value
get_property name Get a property value
set_property name, value Alias for set
observe_property id, name Subscribe to property changes
observe_property_string id, name Subscribe with string formatting
unobserve_property id Unsubscribe from property changes
cycle name, direction Cycle a property (up or down)
add name, value Add to a property (e.g. volume)
multiply name, value Multiply a property value
seek amount, type Seek (relative, absolute, etc.)
revert_seek Revert to position before last seek
frame_step Step forward one frame
frame_back_step Step backward one frame
screenshot Take a screenshot
screenshot_raw Capture screenshot (returns base64)

Events

Events are pushed automatically to connected TCP clients (or stdout in CLI mode).

{"event":"start-file","request_id":0}
{"event":"property-change","id":1,"request_id":0,"name":"time-pos","data":43.1}
Event Trigger Extra Fields
start-file File loading begins
file-loaded File loading completes
end-file File playback ends reason
seek Seek occurs
playback-restart Playback resumes after seek
pause Pause state changes
shutdown Application shutting down
idle Player enters idle state
property-change Observed property changed id, name, data

Supported Properties

Property Type Description
time-pos number Current position in seconds
duration number Media duration in seconds
percent-pos number Position as percentage
playback-time number Current playback time
volume number Audio volume (0–100)
mute boolean Audio mute state
pause boolean Pause state
speed number Speed multiplier
filename string Current file name
path string Full file path or URL
media-title string Media title metadata
chapter number Current chapter index
chapter-list array Chapter list
track-list array All tracks
vid number Active video track ID
aid number Active audio track ID
sid number Active subtitle track ID
secondary-sid number Secondary subtitle ID
fullscreen boolean Fullscreen state
sub-visibility boolean Subtitle visibility
sub-delay number Subtitle delay
sub-pos number Subtitle position
sub-scale number Subtitle font scale
contrast number Video contrast
brightness number Video brightness
gamma number Video gamma
saturation number Video saturation
hue number Video hue
deinterlace boolean Deinterlace state
deband boolean Deband filter state
video-aspect string Aspect ratio override
panscan number Pan-and-scan range
zoom number Video zoom level
playlist-pos number Playlist index
playlist-count number Playlist size

Examples

import json, socket

def ipc(command):
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect(("127.0.0.1", 32321))
    s.sendall((json.dumps(command) + "\n").encode())
    resp = s.makefile().readline()
    s.close()
    return json.loads(resp)

# Get current position
print(ipc({"command": ["get_property", "time-pos"], "request_id": 1}))

# Toggle pause
print(ipc({"command": ["set", "pause", True], "request_id": 2}))

# Load a file
print(ipc({"command": ["loadfile", "C:\\Movies\\clip.mp4", "replace"], "request_id": 3}))
const net = require("net");

function ipc(command) {
  return new Promise((resolve, reject) => {
    const client = net.createConnection(32321, "127.0.0.1", () => {
      client.write(JSON.stringify(command) + "\n");
    });
    client.on("data", (data) => {
      resolve(JSON.parse(data.toString()));
      client.end();
    });
    client.on("error", reject);
  });
}

(async () => {
  console.log(await ipc({ command: ["get_property", "volume"], request_id: 1 }));
  console.log(await ipc({ command: ["set", "speed", 1.5], request_id: 2 }));
})();
# Get media title
echo '{"command":["get_property","media-title"],"request_id":1}' | nc -q0 127.0.0.1 32321

# Set volume to 80
echo '{"command":["set","volume",80],"request_id":2}' | nc -q0 127.0.0.1 32321

# Seek to 50%
echo '{"command":["seek",50,"absolute-percent"],"request_id":3}' | nc -q0 127.0.0.1 32321

Compatibility Notes

  • TCP binds to 127.0.0.1 only — no remote access
  • Delimiter is \n (newline)
  • Max concurrent clients limited only by OS resources
  • Player interaction is marshaled to Qt’s main thread; I/O runs asynchronously
  • On Windows, --cli calls AllocConsole() if no parent console is attached
  • Property observation uses reference counting: if multiple clients observe the same property, only one mpv observation is registered

Was this page helpful?