Skip to content

vhost_user_media: Add lens facing control, worker POLLHUP handling, and shmem_unmap fix - #3121

Open
changyeon-jo wants to merge 4 commits into
google:mainfrom
changyeon-jo:cvd_fleet_camera_options
Open

vhost_user_media: Add lens facing control, worker POLLHUP handling, and shmem_unmap fix#3121
changyeon-jo wants to merge 4 commits into
google:mainfrom
changyeon-jo:cvd_fleet_camera_options

Conversation

@changyeon-jo

@changyeon-jo changyeon-jo commented Aug 30, 2026

Copy link
Copy Markdown

Summary

This PR contains standalone fixes and enhancements for vhost_user_media drivers:

  1. Baseline Formatting (Commit 1):

    • Runs cargo fmt on the baseline v4l2_stream_proxy crate so subsequent functional changes remain strictly scoped and free of cosmetic noise.
  2. Lens Facing Control & CLI Tests (Commit 2):

    • Adds LensFacing enum (FRONT, BACK, EXTERNAL) and --lens-facing CLI option to v4l2_stream_proxy, aligning it with emulated_camera_mplane and emulated_camera_splane.
    • Implements V4L2 CID_LENS_FACING control in query_ext_ctrl, g_ctrl, and g_ext_ctrls returning the configured lens facing to allow the guest Camera HAL to query camera orientation.
    • Adds unit tests:
      • test_lens_facing_from_str: parsing valid orientations and rejecting invalid ones.
      • test_cmdline_args_default_lens_facing: verifies default is EXTERNAL.
      • test_cmdline_args_custom_lens_facing: verifies --lens-facing BACK override.
      • test_ctrl_name_is_nul_padded & test_ctrl_name_truncates_and_stays_nul_terminated: verifies control name formatting.
  3. Shmem Unmap Length Calculation (Commit 3):

    • Fixes shmem_unmap message length calculation in vhu_media/src/lib.rs to unmap the entire allocated region (end - shm_offset + 1) instead of 1 byte.
  4. POLLHUP Handling in Worker Loop (Commit 4):

    • Handles POLLHUP alongside POLLIN in v4l2_stream_proxy/src/worker.rs when polling the video stream FIFO. When a FIFO writer disconnects and the buffer is drained, Linux poll() reports only POLLHUP (without POLLIN). Handling POLLHUP triggers read(), consuming remaining bytes and receiving Ok(0) (EOF) to cleanly transition to WorkerState::Unopened rather than spinning in a 100% CPU poll busy-loop.

(Note: Multi-instance fleet configuration support has been moved to a separate follow-up PR as suggested in review).

Testing

  • cargo fmt --check in vhost_user_media/v4l2_stream_proxy (Passed)
  • cargo test in vhost_user_media/v4l2_stream_proxy (Passed, 5/5 unit tests)
  • cargo test in vhost_user_media/vhu_media (Passed)

@changyeon-jo
changyeon-jo force-pushed the cvd_fleet_camera_options branch 5 times, most recently from d99eda1 to 32236db Compare September 1, 2026 17:14
Add LensFacing enum and --lens-facing CLI option to v4l2_stream_proxy,
aligning it with emulated_camera_mplane and emulated_camera_splane.
Implement V4L2 CID_LENS_FACING control in query_ext_ctrl, g_ctrl, and
g_ext_ctrls returning the configured lens facing.
Add unit tests for CLI argument parsing, lens facing string conversion,
and control name padding.
The previous calculation passed len: 1 to shmem_unmap. Update it to
unmap the entire allocated range (end - shm_offset + 1).
When a FIFO writer disconnects and the buffer is drained, Linux poll()
reports only POLLHUP (without POLLIN). Handling POLLHUP ensures read()
is invoked, which consumes any remaining bytes and returns Ok(0) (EOF).
This cleanly transitions the worker to WorkerState::Unopened rather than
spinning in a 100% CPU poll busy-loop.
@changyeon-jo
changyeon-jo force-pushed the cvd_fleet_camera_options branch 2 times, most recently from f947e43 to 0025092 Compare September 1, 2026 17:50

@bridadan bridadan left a comment

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.

Thanks for the fixes! I think the final commit adding multi-instance support could be its own PR, the commits proceeding it are nice standalone fixes that I'd like to see merged.

flag += ":input_height=" +
std::to_string(v4l2_stream_proxy.input_height());
flag += ":input_fps=" + v4l2_stream_proxy.input_fps();
if (!v4l2_stream_proxy.input_path().empty()) {

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.

The validation that's done here drops invalid values silently. That's not the desired behavior as all of these options are required by the vhost user v4l2_stream_proxy binary (there are no defaults).

There's already some of this validation being done on CLI arguments here: http://github.com/google/android-cuttlefish/blob/3bd35b0f831649e30e8b22e13557047b4ddf3258/base/cvd/cuttlefish/host/libs/config/media.cpp#L87-L113

@ser-io if configuration is specified in JSON files instead of CLI arguments, are they still validated by the code I linked to above? This is the flow I have in my head, is that accurate?

flowchart TD
    A[JSON Config] -->|Serialzied to CLI args| B
    D[Terminal] -->|CLI args provided by user| B
    B[CLI Arg String] --> C[Split and validated by host/libs/config/media.cpp]
Loading

If so, then I'd recommend all the validation should be done in host/libs/config/media.cpp.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

As suggested, I've spun off the fleet/config changes into follow-up PR #3136 and addressed this there:

Removed silent dropping in cf_media_configs.cpp: The if guards have been removed so all fields are serialized unconditionally into the --media flag.
Centralized validation in host/libs/config/media.cpp: Added explicit CF_EXPECT non-empty checks for input_path and input_fps (alongside the existing input_width > 0 and input_height > 0 checks).

Comment on lines +1359 to +1370
@@ -1360,7 +1360,14 @@ Result<CuttlefishConfig> InitializeCuttlefishConfiguration(
CF_EXPECT_EQ(media_configs_bindings.size(), 1,
"Expected a single binding?");
auto media_configs = media_configs_bindings[0]->GetConfigs();
instance.set_media_configs(media_configs);
std::vector<CuttlefishConfig::MediaConfig> instance_media_configs;
for (const auto& config : media_configs) {
if (!config.instance_index.has_value() ||
config.instance_index.value() == instance_index) {
instance_media_configs.push_back(config);
}
}
instance.set_media_configs(instance_media_configs);

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.

Is there a fundamental limitation right now only allowing us to have a single VM use a media config? It seems like it might come from how were using the injector.getMultibindings<...> flow (all the other configs that use it also seem to limit it to 1 binding).

Might be a better question for @ser-io

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

This change is moved to 5262fa5

@changyeon-jo
changyeon-jo force-pushed the cvd_fleet_camera_options branch from 0025092 to 1da0933 Compare September 3, 2026 21:45
@changyeon-jo changyeon-jo changed the title Support v4l2_stream_proxy options and fleet launching with media devices vhost_user_media: Add lens facing control, worker POLLHUP handling, and shmem_unmap fix Sep 3, 2026
@changyeon-jo

Copy link
Copy Markdown
Author

Thanks @bridadan! I've updated this PR to only contain the 4 standalone driver and vhost-user fixes. I'll open a separate follow-up PR for the multi-instance fleet configuration and validation changes.

@changyeon-jo

Copy link
Copy Markdown
Author

Thanks for the fixes! I think the final commit adding multi-instance support could be its own PR, the commits proceeding it are nice standalone fixes that I'd like to see merged.

#3136 is created. :)

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