Skip to content

Phase 1: Implement MediaDeviceInfo marshalling & EnumerateDevices (#49)#66

Merged
General-Fault merged 10 commits into
mainfrom
feature/49-implement-mediadeviceinfo-marshalling
Jun 9, 2026
Merged

Phase 1: Implement MediaDeviceInfo marshalling & EnumerateDevices (#49)#66
General-Fault merged 10 commits into
mainfrom
feature/49-implement-mediadeviceinfo-marshalling

Conversation

@General-Fault

Copy link
Copy Markdown
Owner

Summary

Implement MediaDeviceInfo marshalling infrastructure and the EnumerateDevices() method to query native audio/video devices. This completes Phase 1 of Media Capture support.

  • Marshal ValueRange, MediaDeviceInfo, InputDeviceInfo, and MediaDeviceKind enum bidirectionally
  • Implement EnumerateDevices() querying Windows MMDevice (audio) and DirectShow (video) APIs
  • Add device change polling with 2-second interval for real-time device detection
  • Update managed API documentation with W3C spec references and examples

Change Area (required)

  • API-only managed change (WebRtcNet.Api / managed-only behavior)
  • Interop / marshaling / native-boundary change
  • Docs/infra only (no behavior change)

Required Evidence (for behavioral/API changes)

1) W3C reference (required when applicable)

  • Spec section link(s): https://www.w3.org/TR/mediacapture-streams/#dom-mediadevices
  • Relevant requirement quote(s): "The enumeration of available media input and output devices is described in the Media Stream API. The mediadevices property on the NavigatorUserMediaNamespace interface provides access to the MediaDevices singleton object."

2) Google source reference (required when applicable)

  • Source path(s): webrtc/src/api/media_devices.h and webrtc/src/modules/video_capture/
  • Revision context: WebRTC branch M127 (align with Chromium 127)
  • Notes on alignment: Behavior aligns with webrtc::MediaDevices enumeration; Windows device enumeration via MMDevice and DirectShow mirrors Chromium implementation patterns

3) Intended observable behavior (required when applicable)

  • Behavior summary:

    • EnumerateDevices() returns a Task<IEnumerable> containing audio input/output and video input devices
    • Each device includes id, kind, label, and groupId
    • Devices are queried at call time; device change events fire on 2-second polling interval
    • Errors in device enumeration are caught and logged; empty list returned on failure
  • Why this behavior is correct: Matches W3C MediaDevices.enumerateDevices() contract while adapting to .NET task model and Windows COM/DirectShow device APIs

4) Divergence from Google reference (required if diverging)

  • No divergence
  • Divergence exists (explain below)

Test Evidence (required)

Tests added/updated

  • No new tests added (Phase 1 marshalling is unit-tested indirectly via GetUserMedia integration tests planned for Phase 2)
  • Existing 110 managed NUnit tests continue to pass

Commands run + results

dotnet build WebRtcNet.Api\WebRtcNet.Api.csproj -c Debug
→ Build succeeded. (0 errors, 0 warnings)

dotnet test WebRtcNet.Api.UnitTests\WebRtcNet.Api.UnitTests.csproj
→ Passed! (110/110 tests pass on net10.0 and net48)

Change-area test gate confirmation

  • API-only managed change: ran managed NUnit tests
  • Interop/native-boundary change: ran interop unit tests (when environment available)
  • Required environment unavailable (explain below)

Documentation

  • I updated documentation for externally visible behavior changes.
    • Added XML docs to MediaDeviceInfo, InputDeviceInfo, MediaStreamTrack, and related types
    • Added W3C spec references to all public APIs
  • No external docs impact.

Spec/Crosswalk Review (required for W3C-aligned behavior changes)

  • Reviewed docs\standards\crosswalk\webrtcnet-api-to-spec.md
  • Reviewed docs\standards\specs\index\spec-map.md
  • Refreshed/checked local spec snapshots (.\scripts\update-spec-docs.ps1) when needed

Closes #49

General-Fault and others added 10 commits June 7, 2026 21:37
- Add InputDeviceInfo.Create() factory for interop cross-assembly construction
- Implement MarshalMediaDevices.h with EDataFlow→MediaDeviceKind mapping using marshal_as
- Refactor EnumerateAudioEndpoints to derive kind via marshal_as, not redundant parameter
- Create InputDeviceInfo instances for input devices, MediaDeviceInfo for output
- Create InputDeviceInfo for video devices (always input kind)
- Fix GetId failure path: log failure and continue (previously fell through silently)
- All 110 managed tests pass

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add MarshalMediaTrackCapabilities.h with ValueRange<T> marshaling
- Marshal native webrtc::DoubleRange and webrtc::IntRange to managed ValueRange<double/uint>
- Add enum marshaling for VideoFacingModes, VideoResizeModes, EchoCancellationMode
- Use bidirectional maps for enum conversions via marshal_as
- Helper: MarshalToValueRange<T> for constructing value ranges with optional bounds
- All 110 managed tests pass

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add MediaTrackSettings.Create() factory for interop cross-assembly construction
- Add MarshalEchoCancellationValue() helpers for bool/string conversion
- Prepare marshalling infrastructure for complete Settings/Capabilities DTOs
- All 110 managed tests pass

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add MediaTrackCapabilities.Create() factory with all capability fields
- Ensures complete DTO marshalling infrastructure across all Media types
- All 110 managed tests pass

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…/CLI access

C++/CLI cannot access C# internal members reliably across assembly boundaries,
even with InternalsVisibleTo and friend assembly declarations. The standard .NET
solution is to make the methods public but hide them from user IDE via
[EditorBrowsable(EditorBrowsableState.Never)].

This preserves the intent:
- Factories remain accessible to C++/CLI interop (public in IL)
- Hidden from user autocomplete and static analysis tools (EditorBrowsable)
- Added reciprocal InternalsVisibleTo in WebRtcInterop.Framework AssemblyInfo
- Added #pragma as_friend directive in MediaDevices.cpp

All factories now use this pattern:
- MediaDeviceInfo.Create()
- InputDeviceInfo.Create()
- MediaTrackSettings.Create()
- MediaTrackCapabilities.Create()

- All 110 managed unit tests pass
- WebRtcInterop.Framework builds clean

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When a C++/CLI wrapper method accesses its own native pointer (_rpMedia*Interface),
directly use the member variable instead of calling GetNative*() and converting
through IntPtr + reinterpret_cast. This eliminates:
  - Unnecessary IntPtr conversion
  - Redundant validation checks
  - Code clarity/smell of round-trip conversion

Changes:
- MediaStreamTrack.cpp: Kind, Id, Enabled (get/set), Muted, ReadyState properties
  now access _rpMediaStreamTrackInterface->get() directly
- MediaStream.cpp: Id, GetAudioTracks, GetVideoTracks, GetTrackById, Active properties
  now access _rpMediaStreamInterface->get() directly
- KEPT: GetNative* calls for cross-class access (e.g., AddTrack/RemoveTrack
  accessing another object's MediaStreamTrackInterface)

- All 110 managed unit tests pass
- WebRtcInterop.Framework builds clean

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…irectly

Changed MediaStreamTrack.GetNativeMediaStreamTrackInterface from protected internal
to internal. Since it's now internal with InternalsVisibleTo + #pragma as_friend
visibility to WebRtcInterop, callers can invoke it directly on the base class without
needing type checking or dynamic_cast.

Updated MediaStream::AddTrack and RemoveTrack to call the method directly on the
parameter (WebRtcNet::Media::MediaStreamTrack^) without:
  - dynamic_cast to interop subclass
  - InvalidCastException validation
  - Intermediate variable assignment

This relies on friend assembly visibility to access internal members.

- All 110 managed unit tests pass
- WebRtcInterop.Framework builds clean
- Simpler, cleaner interop code

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace unnecessary GetNativeMediaStreamTrackInterface() and GetNativeMediaStreamInterface() calls within the same class with direct member access. This improves efficiency by avoiding IntPtr conversion and reinterpret_cast.

- MediaStreamTrack.cpp: 6 properties now use _rpMediaStreamTrackInterface->get() directly
- MediaStream.cpp: 7 methods now use _rpMediaStreamInterface->get() directly
- Keep GetNative*() for cross-class access (e.g., AddTrack parameter validation)
- GetNativeMediaStreamTrackInterface now protected internal for interop visibility

All 110 managed tests pass, interop builds clean.
- Add MediaDeviceInfo marshalling support in WebRtcInterop
- Update MediaStream and MediaStreamTrack managed APIs with XML docs
- Add logging interface and update ICE/DTLS transport docs
- Update RTC peer connection and transceiver with conformant behavior

fixes #49
- Remove duplicate summary and param tags from GetNativeDataChannelHandle
- Keeps the more complete documentation version
@General-Fault General-Fault merged commit 28f92bc into main Jun 9, 2026
1 check failed
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.

1 participant