The client application is the desktop component (Windows, Linux, macOS) written in C. It orchestrates all desktop-side operations: ADB communication, server lifecycle management, video/audio stream processing, display rendering, and control command transmission.
This page documents the client's architecture, source module organization, initialization flow, main event loop, and threading model. Subsystem details are covered in child pages:
| Page | Title | Key modules |
|---|---|---|
| 2.1 | Application Core | main.c, scrcpy.c, options.h |
| 2.2 | ADB and Server Management | adb/, server.c |
| 2.3 | Screen Display and Rendering | screen.c, display.c, opengl.c |
| 2.4 | Input Processing | input_manager.c, keyboard/mouse/gamepad processors |
| 2.5 | Media Processing Pipeline | demuxer.c, decoder.c, audio_player.c |
| 2.6 | Recording System | recorder.c |
| 2.7 | V4L2 Integration | v4l2_sink.c |
| 2.8 | Control Message Protocol | control_msg.c, controller.c, receiver.c |
The client application is structured as a single-process, multi-threaded C application built on top of SDL2 (for windowing, audio, and input) and FFmpeg (for media processing). The architecture follows a modular design with clear separation of concerns.
Client architecture organized into entry, orchestration, and subsystem layers.
Sources: app/src/main.c1-154 app/src/scrcpy.c1-1069 app/src/scrcpy.c48-92 app/src/server.c1-1063
All client source files are listed in app/meson.build1-66 They are organized into subsystems below.
Core orchestration
| File | Role |
|---|---|
src/main.c | Platform entry point, SDL/FFmpeg init, argument dispatch |
src/scrcpy.c | Session orchestration, component wiring, SDL event loop |
src/cli.c | Command-line argument parsing |
src/options.c | scrcpy_options defaults and validation |
src/version.c | Version string constant |
src/events.c | Custom SDL event type registration |
src/icon.c | Application icon data |
src/compat.c | FFmpeg/SDL version compatibility shims |
Server management
| File | Role |
|---|---|
src/server.c | sc_server lifecycle: push JAR, forward ports, launch, accept sockets |
src/adb/adb.c | adb binary invocation helpers |
src/adb/adb_device.c | Device selection logic |
src/adb/adb_parser.c | Parse adb devices output |
src/adb/adb_tunnel.c | Reverse/forward tunnel management |
Media pipeline
| File | Role |
|---|---|
src/demuxer.c | sc_demuxer: framing packets from socket |
src/decoder.c | sc_decoder: libavcodec decoding |
src/audio_player.c | sc_audio_player: SDL audio output |
src/audio_regulator.c | sc_audio_regulator: clock compensation |
src/delay_buffer.c | sc_delay_buffer: optional frame delay queue |
src/frame_buffer.c | sc_frame_buffer: single-slot frame buffer |
src/fps_counter.c | sc_fps_counter: FPS measurement |
src/packet_merger.c | sc_packet_merger: merge split packets |
src/clock.c | sc_clock: media clock tracking |
Display and rendering
| File | Role |
|---|---|
src/screen.c | sc_screen: SDL window, texture rendering |
src/display.c | sc_display: SDL renderer and texture management |
src/opengl.c | OpenGL extension loading |
Input handling
| File | Role |
|---|---|
src/input_manager.c | sc_input_manager: SDL event dispatch to processors |
src/keyboard_sdk.c | sc_keyboard_sdk: Android SDK key injection |
src/mouse_sdk.c | sc_mouse_sdk: Android SDK touch/mouse injection |
src/mouse_capture.c | Mouse pointer capture helpers |
src/hid/hid_keyboard.c | HID keyboard descriptor |
src/hid/hid_mouse.c | HID mouse descriptor |
src/hid/hid_gamepad.c | HID gamepad descriptor |
src/uhid/keyboard_uhid.c | UHID keyboard input processor |
src/uhid/mouse_uhid.c | UHID mouse input processor |
src/uhid/gamepad_uhid.c | UHID gamepad input processor |
src/uhid/uhid_output.c | Serialize UHID control messages |
Control messaging
| File | Role |
|---|---|
src/control_msg.c | sc_control_msg serialization |
src/controller.c | sc_controller: outbound message queue and send thread |
src/receiver.c | sc_receiver: inbound device message handling |
src/device_msg.c | sc_device_msg deserialization |
src/file_pusher.c | sc_file_pusher: ADB push for dropped files |
Recording
| File | Role |
|---|---|
src/recorder.c | sc_recorder: libavformat muxing to MP4/MKV/etc. |
Trait interfaces
| File | Role |
|---|---|
src/trait/frame_source.c | sc_frame_source: fan-out to multiple frame sinks |
src/trait/packet_source.c | sc_packet_source: fan-out to multiple packet sinks |
Utilities
| File | Role |
|---|---|
src/util/net.c | Cross-platform TCP sockets |
src/util/thread.c | sc_thread/sc_mutex/sc_cond wrappers |
src/util/process.c | Cross-platform process spawning |
src/util/intr.c | sc_intr: interruptible blocking |
src/util/log.c | Logging macros |
src/util/strbuf.c / str.c | String building utilities |
src/util/audiobuf.c | Lock-free audio ring buffer |
src/util/average.c | Rolling average for clock compensation |
src/util/acksync.c | Acknowledgement synchronization |
src/util/env.c | Environment variable helpers |
src/util/file.c | File path utilities |
src/util/tick.c | High-resolution tick counter |
src/util/timeout.c | sc_timeout: time-limit thread |
src/util/rand.c | Random token generation |
src/util/term.c | Terminal capability detection |
src/util/memory.c | Memory allocation helpers |
Optional / platform-specific
| File | Condition | Role |
|---|---|---|
src/v4l2_sink.c | Linux + v4l2 option | sc_v4l2_sink: stream to V4L2 device |
src/usb/scrcpy_otg.c | usb option | scrcpy_otg(): OTG mode entry point |
src/usb/screen_otg.c | usb option | sc_screen_otg: OTG SDL window |
src/usb/usb.c | usb option | sc_usb: libusb device management |
src/usb/aoa_hid.c | usb option | sc_aoa: Android Open Accessory HID |
src/usb/keyboard_aoa.c | usb option | AOA keyboard input processor |
src/usb/mouse_aoa.c | usb option | AOA mouse input processor |
src/usb/gamepad_aoa.c | usb option | AOA gamepad input processor |
src/sys/win/process.c | Windows | Win32 process execution |
src/sys/unix/process.c | Unix/macOS | POSIX process execution |
Sources: app/meson.build1-109
The entire client state is encapsulated in a single struct scrcpy defined in app/src/scrcpy.c48-92 This structure contains all major subsystems and is allocated statically within the scrcpy() function.
struct scrcpy defined at app/src/scrcpy.c48-92 contains all subsystems:
Key Structure Members:
| Member | Type | Purpose |
|---|---|---|
server | sc_server | Manages ADB connection and server process |
screen | sc_screen | SDL window and video rendering |
audio_player | sc_audio_player | SDL audio output |
video_demuxer | sc_demuxer | Parses video stream packets |
audio_demuxer | sc_demuxer | Parses audio stream packets |
video_decoder | sc_decoder | FFmpeg video decoder |
audio_decoder | sc_decoder | FFmpeg audio decoder |
recorder | sc_recorder | MP4/MKV file recording |
video_buffer | sc_delay_buffer | Optional video frame buffering |
controller | sc_controller | Sends control messages |
file_pusher | sc_file_pusher | Handles file drag-and-drop |
keyboard_* | union | Keyboard processor (SDK/UHID/AOA) |
mouse_* | union | Mouse processor (SDK/UHID/AOA) |
gamepad_* | union | Gamepad processor (UHID/AOA) |
Sources: app/src/scrcpy.c48-92
The client follows a strict initialization order to ensure dependencies are properly established. The sequence begins in main() and proceeds through scrcpy().
Key Initialization Steps:
Sources: app/src/scrcpy.c380-949 app/src/main.c26-104
The client's main thread runs an event loop that processes SDL events and custom scrcpy events. This loop is the central coordination point for user interactions and system notifications.
Event Types:
| Event | Source | Action |
|---|---|---|
SC_EVENT_DEVICE_DISCONNECTED | Demuxer/Controller | Terminate with disconnection status |
SC_EVENT_DEMUXER_ERROR | Demuxer threads | Terminate with failure |
SC_EVENT_CONTROLLER_ERROR | Controller thread | Terminate with failure |
SC_EVENT_RECORDER_ERROR | Recorder thread | Terminate with failure |
SC_EVENT_AOA_OPEN_ERROR | AOA initialization | Terminate with failure |
SC_EVENT_TIME_LIMIT_REACHED | Timeout thread | Terminate successfully |
SDL_QUIT | User/OS | Terminate successfully |
SC_EVENT_RUN_ON_MAIN_THREAD | Any thread | Execute callback on main thread |
| SDL window/input events | SDL | Forward to sc_screen_handle_event() |
Sources: app/src/scrcpy.c178-218
The client application uses multiple threads to handle concurrent operations. Each major subsystem runs in its own thread to prevent blocking and ensure smooth operation.
Client uses multiple threads for concurrent operations:
Thread Responsibilities:
| Thread | Entry Function | Source File | Purpose |
|---|---|---|---|
| Main | event_loop() | scrcpy.c:178 | SDL events, frame rendering, input |
| Server | run_server() | server.c:941 | ADB operations, server lifecycle |
| Video Demuxer | run_demuxer() | demuxer.c | Parse video socket stream |
| Audio Demuxer | run_demuxer() | demuxer.c | Parse audio socket stream |
| Video Decoder | run_decoder() | decoder.c | FFmpeg video decoding |
| Audio Decoder | run_decoder() | decoder.c | FFmpeg audio decoding |
| Controller | run_controller() | controller.c | Send control messages via socket |
| Controller Receiver | run_receiver() | controller.c | Receive clipboard from device |
| Recorder | run_recorder() | recorder.c | Mux packets to MP4/MKV file |
| File Pusher | run_file_pusher() | file_pusher.c | Push dropped files via ADB |
| Timeout | run_timeout() | timeout.c | Trigger time limit event |
| AOA | run_aoa() | aoa.c | Handle USB AOA HID |
Sources: app/src/scrcpy.c48-92 app/src/scrcpy.c178-218 app/src/server.c941-1063
The client carefully manages component lifecycle with explicit initialization, start, stop, join, and destroy phases. This ensures proper cleanup and prevents resource leaks.
Lifecycle Functions Pattern:
Each component typically provides these functions:
*_init() - Allocate resources, initialize state*_start() - Spawn thread, begin operations*_stop() - Signal thread to stop, interrupt blocking operations*_join() - Wait for thread termination*_destroy() - Free resources, cleanupSources: app/src/scrcpy.c958-1068
Components communicate through well-defined interfaces using the sink/source pattern. This allows flexible pipeline configuration without tight coupling.
Components communicate via sink/source pattern for flexible pipeline composition:
Interface Types:
| Interface | Methods | Purpose |
|---|---|---|
sc_packet_source | add_sink() | Distribute packets to multiple consumers |
sc_packet_sink | open(), close(), push() | Receive packets |
sc_frame_source | add_sink() | Distribute frames to multiple consumers |
sc_frame_sink | open(), close(), push() | Receive frames |
Example Connections (from scrcpy.c):
sc_packet_source_add_sink()sc_packet_source_add_sink()sc_frame_source_add_sink()sc_frame_source_add_sink()Sources: app/src/scrcpy.c597-606 app/src/scrcpy.c625-632 app/src/scrcpy.c834-844
Client configuration is encapsulated in struct scrcpy_options which is populated from command-line arguments and passed throughout the application.
Command-line options flow through parsing to component initialization:
Key Configuration Structures:
struct scrcpy_options (options.h) - Parsed command-line optionsstruct sc_server_params (server.h:21-74) - Server execution parametersstruct sc_screen_params (screen.h) - Window and rendering configurationstruct sc_recorder_params - Recording format and orientationConfiguration fields include:
Sources: app/src/options.h app/src/server.h21-74 app/src/scrcpy.c424-477
The client uses a combination of return codes, callbacks, and SDL events for error propagation. Critical errors trigger immediate shutdown through the event system.
Worker threads report errors to main thread via SDL custom events:
Error Event Types:
SC_EVENT_DEMUXER_ERROR - Video/audio stream errorSC_EVENT_CONTROLLER_ERROR - Control socket errorSC_EVENT_RECORDER_ERROR - Recording failureSC_EVENT_AOA_OPEN_ERROR - USB AOA initialization failureSC_EVENT_SERVER_CONNECTION_FAILED - Cannot connect to serverError Callback Registration:
Each component's on_ended callback is registered at init time and pushes the appropriate SC_EVENT_* into the SDL queue. For example, the video demuxer callback is set up at app/src/scrcpy.c577-581 and its handler at app/src/scrcpy.c273-287 pushes SC_EVENT_DEVICE_DISCONNECTED on clean end-of-stream or SC_EVENT_DEMUXER_ERROR on failure. The main event loop at app/src/scrcpy.c178-218 receives these and returns the appropriate scrcpy_exit_code.
Sources: app/src/scrcpy.c273-287 app/src/scrcpy.c577-581 app/src/scrcpy.c178-218
The client maintains cross-platform compatibility through abstraction layers in the util/ and sys/ directories. Platform-specific code is isolated and selected at compile time.
Platform abstraction isolates OS-specific code:
Abstraction Categories:
| Category | Generic Header | Windows | Unix/Linux |
|---|---|---|---|
| Process Management | util/process.h | sys/win/process.c | sys/unix/process.c |
| Command Execution | - | sys/win/command.c | Uses exec*() |
| Network Sockets | util/net.h | Winsock2 | BSD sockets |
| Threading | util/thread.h | Windows threads | pthreads |
| File System | util/file.h | Windows API | POSIX |
Sources: app/src/util/process.h app/src/sys/win/process.c app/src/sys/unix/process.c
The client relies heavily on SDL2 for cross-platform windowing, input, and audio. SDL is initialized in stages based on required features.
SDL Hints Configuration:
SDL hints configured in sdl_set_hints() at app/src/scrcpy.c105-155:
| Hint | Value | Purpose |
|---|---|---|
SDL_HINT_RENDER_DRIVER | User-specified or default | Select renderer (OpenGL, Direct3D, etc) |
SDL_HINT_APP_NAME | "scrcpy" | Identify app in PulseAudio, etc |
SDL_HINT_RENDER_SCALE_QUALITY | "1" | Enable linear filtering |
SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH | "1" | Click-to-focus also processed as click |
SDL_HINT_TOUCH_MOUSE_EVENTS | "0" | Disable synthetic mouse events |
SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS | "0" | Don't minimize on focus loss |
SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS | "1" | Process gamepad in background |
Sources: app/src/scrcpy.c105-155 app/src/scrcpy.c488-492
The client application serves as the orchestrator for all desktop-side operations in scrcpy. Its key responsibilities include:
The architecture emphasizes modularity, threading for concurrency, and platform abstraction for cross-OS compatibility. All components communicate through well-defined interfaces, allowing flexible configuration and minimal coupling.
Sources: app/src/scrcpy.c1-1069 app/src/main.c1-154 app/src/server.c1-207
Refresh this wiki
This wiki was recently refreshed. Please wait 3 days to refresh again.