English · Tiếng Việt · 简体中文
Mirror and control your iPhone on Windows.
Maintained by phh235.
iCast is an iPhone mirror for Windows 10 and 11. It turns your PC into an AirPlay receiver so you can mirror your iPhone screen and play its audio over Wi-Fi. Start screen mirroring from Control Center to see your iPhone in a floating window on your PC. AirPlay mirroring works without installing an app on your iPhone.
To control your iPhone from Windows with a mouse and keyboard, set up WebDriverAgent over USB.
- Wireless AirPlay mirroring with sound. The iPhone sees the PC as an AirPlay receiver under Control Center > Screen Mirroring. No app on the phone, no cable.
- iPhone-shaped window. Frameless, rounded, always on top by default, resizable, and it remembers its position.
- Rotation. When the iPhone turns to landscape, the window turns with it.
- Screenshots. Save the current frame as a PNG in one click.
- Optional mouse and keyboard control over USB. Tap, long press, swipe, scroll, type, Home, App Switcher and volume, all through WebDriverAgent.
- Windows 10 or Windows 11
- Python 3.11 or newer (check "Add python.exe to PATH" during setup)
- The iPhone and the PC on the same Wi-Fi network
For the optional USB control you also need:
- a USB cable for the iPhone
- iTunes from apple.com (it installs Apple's USB driver service; Sideloadly needs the apple.com version rather than the Microsoft Store apps)
- an Apple ID; a free one is enough
- Download this repository (Code > Download ZIP, or
git clone) and put it in a folder you will keep, for exampleC:\Apps\icast-windows. - Double-click
install.bat.
install.bat:
- checks that Python 3.11+ is available,
- creates a private virtual environment in
%LOCALAPPDATA%\iCast\venv, - installs the dependencies from
requirements-control.txtinto it, - creates an iCast shortcut on the Desktop and in the Start menu. The shortcut
runs
pythonw -m icastfrom the repository folder, so no console window opens.
For a smaller fresh installation with mirroring and audio, run install.bat --mirror-only.
You can add USB control later by running install.bat again.
If you move the folder later, run install.bat again so the shortcuts point to the new
location. run.bat starts the app without a shortcut, and control.bat runs the USB
control helper (see below).
Paste this prompt into an agent with terminal access to your Windows PC. Change the mode
to mirror-and-usb if you also want mouse and keyboard control.
Set up iCast on this Windows PC in mirror-only mode.
Get the source from https://github.com/phh235/icast-windows. Reuse a local copy if present.
Otherwise choose a permanent folder under my user profile, such as %USERPROFILE%\Projects,
and run this command there.
git clone https://github.com/phh235/icast-windows.git
If Git is unavailable, download and extract the source ZIP.
https://github.com/phh235/icast-windows/archive/refs/heads/main.zip
Open the downloaded project folder, read README.md, and run the following steps from there.
1. Check that Python 3.11+ is available as python.exe on PATH. If needed, install it from
an official source, refresh PATH, and verify the version. Reuse an existing iCast setup
where possible and preserve my settings.
2. Run the matching installer command. Redirecting input from NUL lets the installer
exit without waiting for a keypress.
cmd.exe /d /c "install.bat --mirror-only < NUL"
cmd.exe /d /c "install.bat < NUL"
Check the exit code, then run -m pip check with %LOCALAPPDATA%\iCast\venv\Scripts\python.exe.
3. Start iCast with .\run.bat and check that it is listening using the window or the
current startup entries in %LOCALAPPDATA%\iCast\icast.log. Ask me to approve private
network access if Windows prompts and select the receiver in iPhone Screen Mirroring.
4. For mirror-and-usb, set up the missing USB prerequisites using the links in this README.
Ask me to approve any Windows elevation prompt. Run .\control.bat doctor and address
the first failed check. If WDA needs to be installed or renewed, run
.\control.bat get-wda and give me the exact IPA path. Hand off the steps that need me:
connecting or unlocking the iPhone, tapping Trust, signing in and signing the IPA in
Sideloadly, or enabling Developer Mode. Use .\control.bat reveal-dev-mode if needed.
After I confirm, rerun doctor. Once mirroring is active, turn on USB control with Ctrl+U
and check that the button turns green.
5. Complete every step you can from the terminal. When you need my action, tell me exactly
what to do, wait for confirmation, then resume. Report what was installed, what you
verified, and any remaining blocker.
Enter Apple Account credentials, verification codes and the iPhone passcode directly in Sideloadly or on the device. USB setup details
- Start iCast. An iPhone-shaped window appears with the text
"Waiting for iPhone". The footer shows the PC's addresses:
PC: <ips> - iPhone and PC must be on the same Wi-Fi. - First start only: Windows Defender Firewall asks whether Python may use the network. Tick Private networks and click Allow.
- Make sure Windows treats your Wi-Fi as a private network: Settings > Network & internet > Wi-Fi > your network > Network profile type > Private.
- On the iPhone, open Control Center > Screen Mirroring and choose the name of this PC (by default the computer name; you can change it with right-click > Rename PC...).
- The window shows "Connecting..." and then the iPhone screen.
Only one copy of the app runs at a time: starting it again just brings the existing window to the front.
Move the mouse over the window to show the top bar. From left to right it has:
- a label with the device name, the frame rate and the control status,
- Control (hand pointer icon): turns USB control on or off. White when off, pulsing orange while starting, green when ready, red after an error,
- Home (circle),
- Pin: keep the window always on top,
- Minimize,
- Close.
| Action | What it does |
|---|---|
| Left-drag anywhere | Move the window |
| Double-click | Switch between big and normal size |
| Ctrl + mouse wheel | Resize |
| Ctrl + Plus / Ctrl + Minus | Resize |
| Right-click | Open the menu |
These apply once control is ready (green Control button) and the iPhone screen is shown. While the window shows a placeholder instead of the iPhone screen, dragging still moves the window.
| Action on the phone area | What the iPhone gets |
|---|---|
| Click | Tap. It is sent about 0.2 s after the click, in case a second click makes it a double tap |
| Press and hold for 0.5 s or longer without moving | Long press |
| Drag | Swipe. It is sent when you release the button and lasts as long as your drag did (clamped to 0.06 - 1.5 s) |
| Double-click | Double tap (both taps are sent together, so apps see a real double tap) |
| Mouse wheel | Scroll. Wheel steps are collected for about 120 ms and sent as one scroll |
| Typing | Text input. Characters are buffered for about 80 ms; Backspace and Enter work |
| Drag the top bar, or Alt + drag anywhere | Move the window |
| Ctrl + mouse wheel | Resize |
Every tap or long press shows a short fading ripple where it landed; a swipe shows a fading line from its start to its end.
| Shortcut | Action |
|---|---|
| Ctrl + H | Home |
| Ctrl + J | App Switcher on iPhones with a Home button |
| Ctrl + Up / Ctrl + Down | iPhone volume up / down |
| Ctrl + M | Mute / unmute the sound on the PC |
| Ctrl + T | Toggle Always on Top |
| Ctrl + Q | Quit iCast |
| Ctrl + U | Turn USB control on / off |
| Ctrl + V | Paste Windows clipboard text into the focused iPhone field while USB control is ready |
| F11 / Esc | Toggle full screen / return to the windowed view |
| Ctrl + 1 | Toggle Actual Pixels (1:1) |
| Ctrl + Shift + C | Copy the current frame at its original resolution |
| Ctrl + Plus / Ctrl + Minus | Resize the window |
Home, App Switcher and iPhone volume act on the phone while control is ready. Ctrl + J double-presses Home on iPhones with a Home button. On Face ID models, iCast shows an AssistiveTouch hint because a WDA swipe can scroll the current app. On those models, open App Switcher from AssistiveTouch or with the iPhone's bottom-edge gesture.
Ctrl + mouse wheel resizes in proportion to how far the wheel turns (about 6% per notch), so smooth scrolling with a touchpad resizes smoothly too.
| Item | Action |
|---|---|
| Control iPhone (USB) | Turn control on or off (checkable) |
| Home | Go to the Home Screen |
| App Switcher | Double-press Home on iPhones with a Home button |
| Volume Up / Volume Down | Change the iPhone volume |
| Always on Top | Keep the window above other windows |
| Sound | Play the iPhone sound on the PC |
| Size | Small, Medium or Large |
| Full Screen / Exit Full Screen | Fit the iPhone view to the current display and keep its aspect ratio |
| Actual Pixels (1:1) | Show one source pixel per display pixel when the original frame fits |
| Resolution | Choose the requested resolution |
| Frame Rate | Choose 30, 60 or experimental 120 FPS |
| Save Screenshot | Save the current frame to Pictures\iCast |
| Copy Screenshot | Copy the original frame to the Windows clipboard |
| Stream Info... | Show received resolution, display size and displayed FPS |
| Rename PC... | Change the name the iPhone shows under Screen Mirroring |
| Open Settings Folder | Open the folder containing settings.json |
| Connection Diagnostics... | Show AirPlay status and run the optional USB checks |
| Open Log | Open %LOCALAPPDATA%\iCast\icast.log |
| Quit | Exit the app |
If the controller reports an error, the app shows it in a non-blocking message box titled "iPhone control" with the full text, and the status also appears in the top bar label.
AirPlay only carries picture and sound. To send taps and keystrokes back, iCast
talks to WebDriverAgent (WDA), Appium's
open-source automation server built on Apple's XCUITest, which runs as a small app on the
phone. iCast starts it over USB with
pymobiledevice3. No Mac is needed, and on
iOS 17.4 or later (and on iOS 16 or earlier) no administrator rights either. iOS 17.0 - 17.3
can only be controlled with administrator rights: update the iPhone, or run
pymobiledevice3 remote tunneld as administrator before you turn control on.
The commands below run in a terminal (Command Prompt or PowerShell) opened in the repository
folder. control.bat runs the helper with the app's own Python environment, so nothing has
to be activated (it is the same as python -m icast.control ... inside that
environment).
-
Connect the iPhone. Install iTunes from apple.com, connect the iPhone with a cable, unlock it and tap Trust when it asks about this computer.
-
Turn on Developer Mode. Run
control.bat reveal-dev-mode
This makes the Developer Mode switch appear on the phone (it also appears by itself once WebDriverAgent is installed in step 4). Then on the iPhone go to Settings > Privacy & Security > Developer Mode, turn it on and confirm. The phone restarts; after the restart, unlock it and confirm Turn On once more.
-
Get WebDriverAgent. Run
control.bat get-wda
It downloads a pinned Appium WebDriverAgent release, checks the download against its official SHA-256 digest, and saves
WebDriverAgentRunner.ipain yourDownloadsfolder. iCast tries GitHub's asset API first and can retry via the direct link for the same release. iCast removes.dSYMdebug bundles because Sideloadly may try to sign their DWARF binaries. The IPA keeps the XCTest runner and frameworks, so you can give it to Sideloadly without editing it. -
Install it on the iPhone. Open Sideloadly, select the iPhone and
WebDriverAgentRunner.ipa, enter your Apple ID and start. Sideloadly signs the app with your Apple ID and installs it. ZIP validation checks the package structure and integrity. Signing still depends on a compatible WDA build, Sideloadly, and Apple's signing requirements. With a free Apple ID the signature is valid for 7 days: after that, install it again with Sideloadly (paid developer accounts last a year). -
Trust the developer profile. On the iPhone go to Settings > General > VPN & Device Management, tap your Apple ID under "Developer App" and tap Trust.
-
Check everything. Run
control.bat doctor
and fix whatever it reports until all checks pass.
-
Turn control on. Start mirroring the iPhone connected by USB. In the iCast window press Ctrl + U, click the hand button in the top bar, or right-click > Control iPhone (USB). The button pulses orange while WDA starts (the first time also downloads and mounts the Developer Disk Image, which can take a minute) and turns green when it is ready.
iCast starts the supported WDA runner with its listener bound to the iPhone's loopback address and opens a PC loopback forward over USB. It checks that the USB iPhone is the one sending the mirror before enabling input. Switching or stopping the mirror ends control. Keep the cable connected while you use control.
control.bat COMMAND (or python -m icast.control COMMAND; add --help to any
command for its options):
| Command | What it does |
|---|---|
doctor |
Check everything USB control needs (--ip ADDRESS also checks WDA over Wi-Fi) |
reveal-dev-mode |
Make the Developer Mode switch appear in the iPhone's Settings |
get-wda |
Download WebDriverAgent as WebDriverAgentRunner.ipa (--out PATH to save it elsewhere) |
start |
Start WebDriverAgent over USB without the app and keep it running until Ctrl+C |
tap X Y |
Tap at X, Y (in points) on a running WDA |
home |
Go to the Home Screen |
type TEXT |
Type TEXT into the focused field (\n = Return, \b = Backspace) |
tap, home and type default to http://127.0.0.1:8100. When you start WDA with
iCast's start command, pass its printed loopback URL with --url.
The PC does not appear under Screen Mirroring
- The Wi-Fi network must be Private in Windows (see Usage).
- Python must be allowed through the firewall on private networks: Start > "Allow an app
through Windows Firewall" > find
pythonw.exe/python.exeand tick Private. - The iPhone and the PC must be on the same network and subnet. Guest networks and routers with "client isolation" / "AP isolation" block devices from seeing each other. A VPN on either device can do the same.
- Restart the app; it announces itself again with mDNS when it starts.
"Could not decrypt the video"
Stop Screen Mirroring on the iPhone and connect again. If it keeps happening, open the log (right-click > Open Log) and attach it to an issue.
"iPhone is locked"
Unlock the iPhone; mirroring continues on its own.
No sound
Check that Sound is ticked in the right-click menu (or press Ctrl + M) and that Windows plays to the right output device. The iPhone's own volume buttons also control the level.
Control does not start or stops working
- Run
control.bat doctor(see USB control) and fix what it reports. The error box titled "iPhone control" shows the same message. - A free Apple ID signature expires after 7 days: if WDA suddenly fails to launch, install
WebDriverAgentRunner.ipaagain with Sideloadly. - "Untrusted Developer" on the phone: trust the profile in Settings > General > VPN & Device Management.
- Logs are in
%LOCALAPPDATA%\iCast\*.log:icast.logfor the app andwda_runner.log/wda_forward.logfor the WebDriverAgent processes.
- Protected content is not mirrored. Apps that use DRM (Netflix, Apple TV and similar) show a black screen. The iPhone decides this, not the receiver.
- Resolution. The iPhone is asked for a stream 1080 pixels high by default. To try a
sharper picture, quit the app, set
"height": 1440in%LOCALAPPDATA%\iCast\settings.jsonand start it again. If the iPhone stops connecting, change it back to1080. - Control latency. Every action is an HTTP request to WebDriverAgent, so expect about 100-200 ms before the iPhone reacts. A single click waits about 0.2 s more, to tell it from a double-click.
- No live drag. Swipes are sent when you release the mouse button, so you cannot drag an item and watch it follow the pointer, or draw.
- Control needs setup. It requires a cable, Developer Mode and a sideloaded WDA that has to be re-signed every 7 days with a free Apple ID.
Right-click and use Resolution (720p, 1080p or 1440p) and Frame Rate (30, 60 or experimental 120 FPS) to set them independently. Reconnect Screen Mirroring to send the new request. Stream Info... shows the received resolution and displayed FPS, which depend on the video the iPhone sends.
Actual Pixels (1:1) uses physical display pixels, including at fractional Windows scaling. Stream Info reports fit view if the original frame is too large for the display.
%LOCALAPPDATA%\iCast\settings.json is created on the first start. Useful keys:
| Key | Default | Meaning |
|---|---|---|
name |
computer name | Name shown on the iPhone under Screen Mirroring |
width, height |
1920, 1080 |
Stream size requested from the iPhone (the height decides the resolution) |
fps |
60 |
Frame rate requested from the iPhone |
audio |
true |
Play the iPhone sound on the PC |
always_on_top |
true |
Keep the window above other windows |
The file also stores the window position and the receiver's identity (a random MAC address and an Ed25519 key). Delete the file to reset everything. The iPhone will then see a new receiver.
- Discovery. The app advertises
_airplay._tcpand_raop._tcpservices over mDNS (python-zeroconf) with the TXT records of an Apple TV, so the iPhone lists the PC under Screen Mirroring. - Control connection. An asyncio RTSP server on TCP port 7000 handles
GET /info, then AirPlay legacy pairing:pair-setupandpair-verifywith Ed25519 signatures and an X25519 key exchange. - FairPlay.
fp-setupruns the FairPlay SAP handshake. A pure-Python port of the open-source playfair code unwraps the 16-byte AES session key that the iPhone sends FairPlay-encrypted duringSETUP. - Video. The mirroring stream is H.264 over TCP, encrypted with AES-128-CTR. The key is derived from the FairPlay key and the pair-verify shared secret. PyAV (FFmpeg) decodes it on a background thread and scales frames to the window's size in device pixels.
- Audio. AAC-ELD over RTP/UDP, encrypted with AES-CBC, decoded with PyAV and played with sounddevice.
- Window. PySide6 (Qt) draws a frameless, translucent, rounded window with the frame, placeholders and controls.
- Control. pymobiledevice3 finds the iPhone through usbmux, checks Developer Mode, mounts the Developer Disk Image, launches WebDriverAgent as an XCUITest (on iOS 17+ through a userspace tunnel) and forwards a local port to WDA's port 8100. Mouse and keyboard input becomes WDA HTTP calls (taps, swipes, text, buttons).
Use the app's environment (%LOCALAPPDATA%\iCast\venv\Scripts\python.exe) or any
Python 3.11+ with requirements.txt installed. Use requirements-control.txt for
the optional pymobiledevice3 command checks. The simulator also uses NumPy.
Run everything from the repository folder.
rem FairPlay known-answer tests (21 recorded sessions)
python tests/test_fairplay.py
rem WebDriverAgent control and IPA packaging tests
python tests/test_wda.py
rem AirPlay shutdown, video sessions, and settings tests
python tests/test_lifecycle.py
rem Full AirPlay session without an iPhone or a network:
rem the receiver listens on 127.0.0.1:7100 only and does not announce itself
python -m icast --local
rem in a second window: a simulated iPhone that pairs, does FairPlay and streams
rem an encrypted H.264 test pattern and an AAC tone (arguments: host port seconds)
python tools/fake_iphone.py 127.0.0.1 7100--local also skips the single-instance check and uses a separate settings file, so it can
run next to a normal copy of the app. Other options:
| Option | Meaning |
|---|---|
--port N |
RTSP port (default 7000, or 7100 with --local) |
--control |
Turn on USB control when the first mirror begins |
--grab DIR |
Save a PNG of the window every 2 seconds |
--quit-after N |
Exit after N seconds |
tools/gen_fairplay.py regenerates icast/fairplay/_tables.py and _garble.py from
the playfair C sources shipped with UxPlay:
python tools/gen_fairplay.py path\to\UxPlay\lib| Path | Contents |
|---|---|
icast/airplay.py |
RTSP server, session setup, Receiver |
icast/pairing.py |
Legacy pair-setup / pair-verify |
icast/fairplay/ |
Pure-Python FairPlay SAP (playfair port) |
icast/video.py |
Mirror stream decryption and H.264 decoding |
icast/audio.py |
RTP audio decryption, decoding and playback |
icast/discovery.py |
mDNS advertisement |
icast/config.py |
Settings and receiver identity |
icast/ui.py |
The iPhone-shaped window |
icast/control/ |
WebDriverAgent client and USB bring-up |
tests/ |
FairPlay and WDA tests |
tools/ |
Simulated iPhone, FairPlay table generator |
- UxPlay, RPiPlay and shairplay, and the authors of the playfair FairPlay code they ship. The protocol handling here was checked against UxPlay.
- pymobiledevice3 for talking to the iPhone over USB.
- Appium WebDriverAgent for input on the iPhone.
- PyAV and FFmpeg for decoding.
- PySide6 (Qt for Python) for the window.
- python-zeroconf for mDNS.
- The FairPlay test vectors come from openairplay/airplay2-receiver and omarroth/doubletake.
GPL-3.0. The icast/fairplay/ module is a port of the GPL-3.0 playfair
code (see licenses/playfair-LICENSE.md), so the whole
application is distributed under the GPL-3.0. See NOTICE for copyright and
modification notices for this version.
This project is not affiliated with, endorsed by, or sponsored by Apple Inc. AirPlay, iPhone, FairPlay and iOS are trademarks of Apple Inc., registered in the U.S. and other countries. Use it only with devices and content you are allowed to mirror.