Skip to content

Integrate virtual_tuner_daemon into the run_cvd - #3348

Open
abinba wants to merge 4 commits into
google:mainfrom
abinba:feat/virtual-tuner-run-cvd
Open

abinba wants to merge 4 commits into
google:mainfrom
abinba:feat/virtual-tuner-run-cvd

Conversation

@abinba

@abinba abinba commented Oct 14, 2026 •

Copy link
Copy Markdown
Collaborator

[continuation of #3175 and #3231]

When the guest audio config declares a virtual_tuner stream, run_cvd
starts virtual_tuner_daemon and passes webRTC --tuner_pcm_socket_path.
Guests without that stream get no socket, no daemon and no new flag.

  • run_cvd creates the PCM listening socket and hands it to the daemon
    with --pcm_server_fd, because webRTC's TunerAudioSource connects once
    at startup.

  • The gRPC control server listens on vsock port 7010 through vhost-user
    vsock, so each instance gets its own socket. With kernel vsock every
    instance would share host port 7010, so the launch fails when
    vhost-user vsock is off.

  • --pcm_channels comes from the stream's channel layout. The daemon
    exits at startup unless it's stereo.

  • The daemon isn't critical: if it exits, the device keeps running
    without tuner audio.

Known limitations:

  • After a snapshot restore the daemon starts untuned, so the tuner is
    silent until the guest tunes again.

  • If the daemon exits, tuner audio stays silent until the device
    restarts, because webRTC doesn't reconnect.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a virtual tuner daemon and server to Cuttlefish, including an audio generator, a PCM stream server, and a gRPC control service, along with their integration into the run_cvd flow and associated unit tests. The review feedback highlights several critical issues, including potential null pointer dereferences when checking if potentially empty SharedFDs are open, a dangerous file deletion risk in test teardown if the temporary directory is empty, and potential uninitialized memory leaks if the audio buffer size is not a multiple of the channel count.

Comment thread base/cvd/cuttlefish/host/commands/virtual_tuner_daemon/main.cpp
@abinba
abinba requested a review from jemoreira October 14, 2026 13:34
return WriteAll(fd, buf.data(), buf.size());
}

bool SendAll(SharedFD sock, std::string_view msg) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider absl::Span instead, perhaps.

@abinba abinba Oct 16, 2026 •

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A Span<const char> would still need the cast and byte count at the call site, so I kept pointer+size to match Fd::Send. Happy to add a typed Span<const T> overload if you prefer.

Comment thread base/cvd/cuttlefish/host/commands/run_cvd/launch/virtual_tuner_server.h Outdated
namespace cuttlefish {
namespace {

constexpr unsigned int kVirtualTunerVsockPort = 7010;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using a fixed port like this breaks multi-device functionality. Each device needs to select its port from a range by this formula: first_port + instance_num - 1. Look at how the adb host port is chosen in host/commands/assemble_cvd/flags.cc for an example.

These ranges usually cover 100 ports, [7000..7099] and [7100..7199] are available in the vsock address space.

@abinba abinba Oct 16, 2026 •

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In case of the vhost-user-vsock, it turns a guest connection to (CID 2, port P) into a Unix socket connection to a file in that instance's directory: /tmp/vsock-CID-UID/vm.vsock-PORT. Therefore, it worked before.

But I agree that it's better to select the port automatically and then pass it to the guest through bootconfig. Done in the next patch.

Comment thread base/cvd/cuttlefish/host/commands/run_cvd/launch/virtual_tuner_server.cpp Outdated
Comment thread base/cvd/cuttlefish/host/commands/run_cvd/launch/virtual_tuner_server.cpp Outdated
Comment thread base/cvd/cuttlefish/host/commands/run_cvd/launch/virtual_tuner_server.cpp Outdated
Comment thread base/cvd/cuttlefish/host/commands/run_cvd/launch/virtual_tuner_server.cpp Outdated
@abinba
abinba force-pushed the feat/virtual-tuner-run-cvd branch from 008bcdb to 666251d Compare October 16, 2026 12:32
Introduce the audio emulation pipeline for the Cuttlefish Virtual Tuner:
- AudioGenerator: Generates 48 kHz, 16-bit stereo PCM audio frames
  (white noise while tuned/playing, silence while stopped/untuned).
- PcmStreamServer: Multi-client PCM stream server delivering 48 kHz 16-bit
  stereo audio frames over a UNIX domain stream socket to Cuttlefish's
  virtio-snd virtual sound card backend (CrosVM).
- Unit and integration tests covering audio frame synthesis and socket
  streaming.

Test: bazel test //cuttlefish/host/commands/virtual_tuner_daemon:...
Bug: 521329213
TAG=agy
CONV=809829e8-ac68-4c32-b9b7-632f61743e47
Introduce the VirtualTunerServiceImpl gRPC control service and the
virtual_tuner_daemon binary entry point:
- VirtualTunerServiceImpl: Implements Tune and Stop RPCs updating
  TunerState.
- virtual_tuner_daemon: Runs PcmStreamServer alongside the gRPC control
  server. It takes --server_address, --pcm_server_fd and
  --pcm_channels. run_cvd creates the PCM listening socket before
  starting WebRTC, because WebRTC connects to it only once.
  --pcm_channels is the channel count of the guest's virtual_tuner
  audio stream; anything other than 2 is rejected because the generator
  produces stereo. The launcher is expected to validate the guest
  config first, so this check is a backstop.
- Unit tests verifying Tune and Stop RPCs over an in-process gRPC
  channel.

Test: bazel test //cuttlefish/host/commands/virtual_tuner_daemon/...
Bug: b/521329213
TAG=agy
CONV=809829e8-ac68-4c32-b9b7-632f61743e47
Moves AudioChannelsLayout and GetChannelsCount out of webRTC's
audio_settings.h, and ConvertChannelLayout out of webRTC's main.cpp,
into a new library, //cuttlefish/host/libs/audio:channel_layout. That
lets run_cvd turn a guest audio config layout into a channel count
without copying webRTC's mapping. audio_settings.h re-exports the new
header, so the rest of webRTC is unchanged. No behavior change.

Test: bazel test //cuttlefish/host/libs/audio:all //cuttlefish/host/frontend/webrtc:all
Bug: b/521329213
TAG=agy
CONV=e89104c1-07ca-48c1-bafc-c87fbf95b6df
When the guest audio config declares a virtual_tuner stream on any PCM
device, run_cvd now starts virtual_tuner_daemon and passes webRTC the
path of the tuner PCM socket. Guests without a virtual_tuner stream
don't start the daemon.

run_cvd creates the PCM listening socket and hands it to the daemon
with --pcm_server_fd, so the socket exists before webRTC starts:
webRTC's TunerAudioSource connects once, at construction.

The gRPC control server listens on a per-instance vsock port (7000 for
instance 1, 7001 for instance 2, and so on). It goes through vhost-user
vsock when that is enabled and through host AF_VSOCK otherwise.
assemble_cvd assigns the port to every instance, as it does for the
VHAL proxy server, stores it in the instance config and passes it to
the guest as the androidboot.vsock_virtual_tuner_port bootconfig
property.

run_cvd derives --pcm_channels from the stream's channel layout with
the helpers in host/libs/audio, and the daemon exits at startup if that
isn't stereo. The daemon is not a critical process: if it exits, the
device keeps running without tuner audio.

Test: bazel test //cuttlefish/host/commands/run_cvd/launch:all //cuttlefish/host/commands/assemble_cvd:all //cuttlefish/host/libs/config:all //cuttlefish/package:cvd; cvd load on cf_x86_64_auto with a virtual_tuner stream, with vhost-user vsock and with host AF_VSOCK
Bug: b/521329213
TAG=agy
CONV=e89104c1-07ca-48c1-bafc-c87fbf95b6df
@abinba
abinba force-pushed the feat/virtual-tuner-run-cvd branch from 666251d to 5c396d8 Compare October 16, 2026 12:41

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants