Skip to content

Repository files navigation

iCast

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.

Features

  • 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.

Requirements

  • 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

Install

  1. Download this repository (Code > Download ZIP, or git clone) and put it in a folder you will keep, for example C:\Apps\icast-windows.
  2. 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.txt into it,
  • creates an iCast shortcut on the Desktop and in the Start menu. The shortcut runs pythonw -m icast from 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).

Setup with an agent

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

Usage

  1. 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.
  2. First start only: Windows Defender Firewall asks whether Python may use the network. Tick Private networks and click Allow.
  3. Make sure Windows treats your Wi-Fi as a private network: Settings > Network & internet > Wi-Fi > your network > Network profile type > Private.
  4. 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...).
  5. 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.

Window controls

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.

Mirroring only (control off, the default)

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

With control on

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.

Keyboard shortcuts (both modes)

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.

Right-click menu

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.

USB control (optional)

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).

  1. 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.

  2. 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.

  3. 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.ipa in your Downloads folder. iCast tries GitHub's asset API first and can retry via the direct link for the same release. iCast removes .dSYM debug 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.

  4. 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).

  5. Trust the developer profile. On the iPhone go to Settings > General > VPN & Device Management, tap your Apple ID under "Developer App" and tap Trust.

  6. Check everything. Run

    control.bat doctor

    and fix whatever it reports until all checks pass.

  7. 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.

Helper commands

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.

Troubleshooting

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.exe and 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.ipa again with Sideloadly.
  • "Untrusted Developer" on the phone: trust the profile in Settings > General > VPN & Device Management.
  • Logs are in %LOCALAPPDATA%\iCast\*.log: icast.log for the app and wda_runner.log / wda_forward.log for the WebDriverAgent processes.

Limitations

  • 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": 1440 in %LOCALAPPDATA%\iCast\settings.json and start it again. If the iPhone stops connecting, change it back to 1080.
  • 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.

Settings

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.

How it works

  • Discovery. The app advertises _airplay._tcp and _raop._tcp services 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-setup and pair-verify with Ed25519 signatures and an X25519 key exchange.
  • FairPlay. fp-setup runs 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 during SETUP.
  • 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).

Development

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

Project layout

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

Credits

License

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.

Disclaimer

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.

Contributors

Languages