How scrcpy Handles Audio-Only Recording Modes: A Deep Dive into the Server Architecture
scrcpy handles audio-only recording by treating audio and video as independent streams, creating only the audio socket and pipeline when video is disabled via --no-video.
scrcpy (Screen Copy) is an open-source tool for displaying and controlling Android devices from a desktop. When users need to capture only audio without video overhead, scrcpy's audio-only recording mode activates a specialized pipeline that bypasses video processing entirely while maintaining full audio capture capabilities.
How scrcpy Configures Audio-Only Mode at Startup
The server-side Java code determines which streams to initialize based on boolean flags parsed from the command line. When video is disabled, the architecture deliberately skips video socket creation while preserving the complete audio pathway.
Parsing Command-Line Options in Options.java
The Options class parses the --no-video and --audio flags to set internal boolean states. In server/src/main/java/com/genymobile/scrcpy/Options.java (lines 95-98), the getVideo() and getAudio() methods return these flags, which downstream components use to conditionally initialize streams.
Conditional Socket Creation in DesktopConnection.java
The DesktopConnection.open() method in server/src/main/java/com/genymobile/scrcpy/device/DesktopConnection.java (lines 56-75) accepts separate boolean parameters for video and audio. When video is false, the method omits the video socket creation but still initializes the Unix-domain socket for audio. This ensures that only the requested stream types establish communication channels with the client.
The Audio Pipeline Architecture for Recording
Once the connection layer establishes the audio socket, the server constructs a dedicated processing pipeline that operates independently of any video components.
Server.java Orchestration Logic
In server/src/main/java/com/genymobile/scrcpy/Server.java (lines 118-136), the scrcpy() method contains an if (audio) { … } block that executes regardless of the video flag's state. This block instantiates three core components:
- AudioCapture: Abstracts the audio source (playback capture or direct audio injection)
- AudioEncoder (or
AudioRawRecorderfor raw PCM): Processes captured samples - Streamer: Manages packet transmission to the client socket
AudioCapture and AudioEncoder Components
The AudioCapture interface implementations handle device-specific audio acquisition. For encoding, AudioEncoder.java (lines 18-33) in server/src/main/java/com/genymobile/scrcpy/audio/ reads samples from the capture, encodes them using the default OPUS codec, and prepares them for streaming.
For raw PCM recording without encoding, AudioRawRecorder.java (lines 27-33) bypasses the encoder and forwards raw audio samples directly to the streamer.
Streamer.java Packet Transmission
The Streamer class in server/src/main/java/com/genymobile/scrcpy/device/Streamer.java (lines 38-45) handles the wire protocol. It first writes an audio header via writeAudioHeader(), then continuously transmits encoded packets using writePacket(). This operates exclusively over the audio socket established earlier, ensuring no video data is transmitted during audio-only recording.
Handling Audio Recording Failures and Fallbacks
When audio capture is unavailable (such as on Android versions below 11 or unsupported audio sources), the server signals the client to disable the audio stream gracefully.
In AudioRawRecorder.java (lines 30-32) and AudioEncoder.java (lines 209-211), exception handlers invoke streamer.writeDisableStream(false). The false parameter indicates stream code 0 (audio), instructing the client to continue operating without audio rather than terminating the session. This allows video-only or recording sessions to proceed even when audio capture fails.
Practical Examples for Audio-Only Recording
Recording Audio-Only to a File
To capture only audio and save it to a file:
scrcpy --no-video --audio --record audio-only.mp4
--no-videosetsOptions.video = false, preventing video socket creation.--audioensuresOptions.audio = true(enabled by default).- The client receives only audio packets and writes them to
audio-only.mp4.
Programmatic Server Configuration
To configure audio-only mode programmatically in the server:
Options opts = new Options(); // defaults: video = true, audio = true
opts.setVideo(false); // disable video
opts.setAudio(true); // keep audio enabled
Server.scrcpy(opts); // executes only the audio pipeline
This executes the if (audio) { … } branch in Server.java (lines 118-136), creating AudioCapture, AudioEncoder, and Streamer instances bound exclusively to the audio file descriptor.
Handling Disabled Audio Streams
When audio capture fails, the server sends a disable signal:
streamer.writeDisableStream(false); // code 0 = audio stream disabled
This is invoked in AudioRawRecorder.java (lines 30-32) and AudioEncoder.java (lines 209-211) when exceptions occur during initialization or capture.
Key Source Files in scrcpy's Audio-Only Implementation
| File | Path | Role in Audio-Only Mode |
|---|---|---|
| Options.java | server/src/main/java/com/genymobile/scrcpy/Options.java |
Parses --no-video and --audio flags (lines 95-98) |
| DesktopConnection.java | server/src/main/java/com/genymobile/scrcpy/device/DesktopConnection.java |
Conditionally opens only the audio socket when video is disabled (lines 56-75) |
| Server.java | server/src/main/java/com/genymobile/scrcpy/Server.java |
Orchestrates audio pipeline creation independent of video state (lines 118-136) |
| AudioEncoder.java | server/src/main/java/com/genymobile/scrcpy/audio/AudioEncoder.java |
Encodes captured audio to OPUS and handles failure fallbacks (lines 18-33, 209-211) |
| AudioRawRecorder.java | server/src/main/java/com/genymobile/scrcpy/audio/AudioRawRecorder.java |
Records raw PCM audio without encoding (lines 27-33, 30-32) |
| Streamer.java | server/src/main/java/com/genymobile/scrcpy/device/Streamer.java |
Writes audio headers and packets to the client socket (lines 38-45) |
Summary
- scrcpy treats audio and video as independent streams, allowing audio-only recording by simply omitting video socket creation when
--no-videois specified. - The audio pipeline remains fully functional regardless of video state, utilizing
AudioCapture,AudioEncoder(orAudioRawRecorder), andStreamercomponents inServer.java. - Socket creation is conditional in
DesktopConnection.java, where passingvideo=falseprevents the video Unix-domain socket from opening while preserving the audio channel. - Graceful degradation occurs when audio capture fails: the server sends a disable-stream packet (code 0) via
Streamer.writeDisableStream(), allowing the session to continue without audio rather than crashing.
Frequently Asked Questions
How do I start an audio-only recording session with scrcpy?
Use the --no-video flag combined with --audio (which is enabled by default) and specify an output file with --record. For example: scrcpy --no-video --audio --record audio-only.mp4. This configuration sets Options.video = false in the server, causing DesktopConnection.open() to skip video socket creation while fully initializing the audio pipeline in Server.java.
What happens if my Android device doesn't support audio capture?
If the device runs Android 10 or older, or if the specified audio source is unavailable, the audio component catches the initialization exception and calls streamer.writeDisableStream(false) (where false indicates the audio stream). This sends a disable-stream packet with code 0 to the client, signaling that audio is unavailable while allowing the session to continue with video or recording functionality intact.
Can I record raw PCM audio instead of encoded audio with scrcpy?
Yes, scrcpy supports raw PCM recording through the AudioRawRecorder class located in server/src/main/java/com/genymobile/scrcpy/audio/AudioRawRecorder.java. When configured for raw output, this component bypasses the OPUS encoder and forwards captured audio samples directly to the Streamer, preserving the original PCM format without compression.
Where does scrcpy handle the audio stream when video is disabled?
The audio stream handling occurs in server/src/main/java/com/genymobile/scrcpy/Server.java within the scrcpy() method (lines 118-136). Inside this method, an if (audio) { … } block executes independently of the video flag, creating an AudioCapture instance, an AudioEncoder (or AudioRawRecorder), and a Streamer that writes to the audio socket established in DesktopConnection.java.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →