# How scrcpy Handles Audio-Only Recording Modes: A Deep Dive into the Server Architecture

> Explore how scrcpy's server architecture enables audio-only recording. Learn how scrcpy creates independent audio streams when video is disabled with --no-video for efficient recording.

- Repository: [Genymobile/scrcpy](https://github.com/Genymobile/scrcpy)
- Tags: deep-dive
- Published: 2026-02-25

---

**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`](https://github.com/Genymobile/scrcpy/blob/main/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`](https://github.com/Genymobile/scrcpy/blob/main/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`](https://github.com/Genymobile/scrcpy/blob/main/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:

1. **AudioCapture**: Abstracts the audio source (playback capture or direct audio injection)
2. **AudioEncoder** (or `AudioRawRecorder` for raw PCM): Processes captured samples
3. **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`](https://github.com/Genymobile/scrcpy/blob/main/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`](https://github.com/Genymobile/scrcpy/blob/main/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`](https://github.com/Genymobile/scrcpy/blob/main/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`](https://github.com/Genymobile/scrcpy/blob/main/AudioRawRecorder.java) (lines 30-32) and [`AudioEncoder.java`](https://github.com/Genymobile/scrcpy/blob/main/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:

```bash
scrcpy --no-video --audio --record audio-only.mp4

```

- `--no-video` sets `Options.video = false`, preventing video socket creation.
- `--audio` ensures `Options.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:

```java
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`](https://github.com/Genymobile/scrcpy/blob/main/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:

```java
streamer.writeDisableStream(false); // code 0 = audio stream disabled

```

This is invoked in [`AudioRawRecorder.java`](https://github.com/Genymobile/scrcpy/blob/main/AudioRawRecorder.java) (lines 30-32) and [`AudioEncoder.java`](https://github.com/Genymobile/scrcpy/blob/main/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`](https://github.com/Genymobile/scrcpy/blob/main/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`](https://github.com/Genymobile/scrcpy/blob/main/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`](https://github.com/Genymobile/scrcpy/blob/main/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`](https://github.com/Genymobile/scrcpy/blob/main/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`](https://github.com/Genymobile/scrcpy/blob/main/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`](https://github.com/Genymobile/scrcpy/blob/main/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-video` is specified.
- **The audio pipeline remains fully functional** regardless of video state, utilizing `AudioCapture`, `AudioEncoder` (or `AudioRawRecorder`), and `Streamer` components in [`Server.java`](https://github.com/Genymobile/scrcpy/blob/main/Server.java).
- **Socket creation is conditional** in [`DesktopConnection.java`](https://github.com/Genymobile/scrcpy/blob/main/DesktopConnection.java), where passing `video=false` prevents 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`](https://github.com/Genymobile/scrcpy/blob/main/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`](https://github.com/Genymobile/scrcpy/blob/main/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`](https://github.com/Genymobile/scrcpy/blob/main/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`](https://github.com/Genymobile/scrcpy/blob/main/DesktopConnection.java).