Skip to content

Drop NAudio.CoreAudioApi dependency (or wait for upstream ComWrappers support) #23

@hoobio

Description

@hoobio

Problem

Earmark.Audio uses NAudio.CoreAudioApi for Core Audio device + session enumeration and change events:

NAudio's COM interface declarations are classic [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]. Marshalling those depends on System.StubHelpers.InterfaceMarshaler in CoreLib, which the .NET 10 trimmer feature-switches out and prints IL2026: Built-in COM support is not trim compatible. PR #19 confirmed the runtime then throws TypeLoadException on the first MMDeviceEnumerator constructor call. This blocks the trimming follow-up in #21 alongside the own-code migration in #22.

Pairs with #22: even if our own COM declarations are migrated to [GeneratedComInterface], NAudio's classic-COM declarations would still keep System.StubHelpers.InterfaceMarshaler reachable and the trimmer would still strip it.

Proposed Solution

Two paths, in priority order:

  1. Wait for NAudio to support ComWrappers upstream (filed as a tracking issue at NAudio.CoreAudioApi (WASAPI) breaks under PublishTrimmed: classic-COM stripped by .NET trimmer naudio/NAudio#1256, referencing the existing dormant directsound playback breaks with trimming enabled naudio/NAudio#1191 about DirectSound + trimming). NAudio.Wasapi 2.2.1 currently targets netstandard2.0 + UAP10.0.18362, so an upstream migration would have to multi-target net8.0+ to get [GeneratedComInterface]. Slow path, depends on upstream maintainer bandwidth.
  2. Replace the NAudio surface we use with hand-rolled [GeneratedComInterface] declarations. Roughly five COM interfaces plus IID/HResult/PROPVARIANT plumbing (the same pattern Migrate own classic-COM interop to ComWrappers (IPolicyConfigVista, IAudioPolicyConfigFactory) #22 establishes for our existing interop). Once Migrate own classic-COM interop to ComWrappers (IPolicyConfigVista, IAudioPolicyConfigFactory) #22 lands, Earmark.Audio already has the ComWrappers strategy class and the helpers needed to do this in-tree.

Recommendation: start path 1 (cost of one upstream issue), but plan on path 2 for actually unblocking #21 since upstream timing is uncertain.

Alternatives Considered

Additional Context

Checklist

  • I searched existing issues and this hasn't been requested yet

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions