Skip to content

broadcastradio: Add Audio Generator and PCM Stream Server for Virtual Tuner - #3175

Open
abinba wants to merge 3 commits into
google:mainfrom
abinba:feat/virtual-tuner-audio
Open

abinba wants to merge 3 commits into
google:mainfrom
abinba:feat/virtual-tuner-audio

Conversation

@abinba

@abinba abinba commented Sep 11, 2026

Copy link
Copy Markdown
Collaborator

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 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
@chihchiachen
chihchiachen requested review from jemoreira and removed request for Databean September 18, 2026 16:48

@jemoreira jemoreira left a comment

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.

Please rebase your branch on top of main instead of creating merge commits.

void StreamClient(ClientSession* session);
void ReapFinishedClients();

TunerState* const tuner_state_;

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.

nit: use TunerState&

if (written > 0) {
cursor += written;
remaining -= static_cast<size_t>(written);
} else if (written < 0 && fd->GetErrno() == EINTR) {

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.

Fd::Send handles EINTR for you, this check is unnecessary.

constexpr auto kMaxSchedulingLag = std::chrono::milliseconds(500);
constexpr int kPrebufferChunks = 2;

bool SendAll(const SharedFD& fd, const void* data, size_t size) {

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.

There is already a SendAll function in common/libs/fs/shared_buf.*, please add an overload that takes void*, size_t instead of std::string_view and have the existing one call the new one to avoid repetition.

While you're at it, please add the flags parameter as well with a default value of MSG_NOSIGNAL to make it more flexible without changing the current behavior.

}

::unlink(socket_path_.c_str());
server_fd_ = SharedFD::SocketLocalServer(

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.

Because of the way cuttlefish spawns processes there is no guarantee that this socket will be created before the client attempts to connect to it. Our way of dealing with this race is to have the parent process run_cvd create the socket and let the child process (this one) inherit it. The actual fd is passed by command line parameter.

There are several examples under host/commands/run_cvd/launch that you can use for guidance.

}

if (server_fd_->IsOpen()) {
server_fd_->Shutdown(SHUT_RDWR);

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.

why Shutdown? Is Close not enough?


LOG(INFO) << "PCM streaming server accepted a client.";
auto session = std::make_unique<ClientSession>();
session->fd = std::move(client_fd);

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.

nit: client_fd is a SharedFD, it's typically copied instead of moved, just like a shared_ptr.

});
}

void PcmStreamServer::StreamClient(ClientSession* session) {

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.

nit: use ClientSession& for the parameter

Comment on lines +193 to +194
std::this_thread::sleep_until(deadline);
if (!is_running_) {

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.

nit: If you use std::condition_variable::wait_until you can notify the variable from the stop routine and not have to wait until this sleep ends.

AudioGenerator generator;
std::vector<int16_t> buffer(kChunkFrames * kChannels);

const auto write_next_chunk = [&] {

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.

please write the type for this lambda since it's not obvious that it returns bool without looking at other source locations.

namespace virtualtuner {
namespace {

bool ReadExactly(const SharedFD& fd, std::span<uint8_t> buffer) {

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.

We already have ReadExact in shared_buf.h

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.

2 participants