@bun-win32/mmdevapi
v2.0.1
Published
Zero-dependency, zero-overhead Win32 MMDEVAPI bindings for Bun (FFI) on Windows.
Maintainers
Readme
@bun-win32/mmdevapi
Zero-dependency, zero-overhead Win32 Mmdevapi bindings for Bun on Windows.
Overview
@bun-win32/mmdevapi exposes the mmdevapi.dll exports using Bun's FFI. It provides a single class, Mmdevapi, which lazily binds native symbols on first use. You can optionally preload a subset or all symbols up-front via Preload().
The bindings are strongly typed for a smooth DX in TypeScript.
Features
- Bun-first ergonomics on Windows 10/11.
- Direct FFI to
mmdevapi.dll(MMDevice / Core Audio endpoint enumeration and WASAPI activation). - In-source docs in
structs/Mmdevapi.tswith links to Microsoft Docs. - Lazy binding on first call; optional eager preload (
Mmdevapi.Preload()). - No wrapper overhead; calls map 1:1 to native APIs.
- Strongly-typed Win32 aliases (see
types/Mmdevapi.ts).
Requirements
- Bun runtime
- Windows 10 or later
Installation
bun add @bun-win32/mmdevapiQuick Start
import { ptr } from 'bun:ffi';
import Mmdevapi, { CLSID_MMDeviceEnumerator, IID_IMMDeviceEnumerator } from '@bun-win32/mmdevapi';
function guidBytes(guid: string): Buffer {
const [, d1, d2, d3, d4High, d4Low] = /^([0-9a-f]{8})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{12})$/i.exec(guid)!;
const buffer = Buffer.alloc(16);
buffer.writeUInt32LE(parseInt(d1, 16), 0);
buffer.writeUInt16LE(parseInt(d2, 16), 4);
buffer.writeUInt16LE(parseInt(d3, 16), 6);
const data4 = `${d4High}${d4Low}`;
for (let i = 0; i < 8; i += 1) buffer[8 + i] = parseInt(data4.slice(i * 2, i * 2 + 2), 16);
return buffer;
}
// Resolve the MMDevice class factory without CoCreateInstance.
const clsid = guidBytes(CLSID_MMDeviceEnumerator);
const iidFactory = guidBytes('00000001-0000-0000-c000-000000000046'); // IID_IClassFactory
const factoryOut = Buffer.alloc(8);
const hr = Mmdevapi.DllGetClassObject(ptr(clsid), ptr(iidFactory), ptr(factoryOut));
console.log('DllGetClassObject →', `0x${(hr >>> 0).toString(16).padStart(8, '0')}`);
console.log('IClassFactory * →', `0x${factoryOut.readBigUInt64LE(0).toString(16).padStart(16, '0')}`);
// Preload for hot paths (optional):
Mmdevapi.Preload(['DllGetClassObject', 'ActivateAudioInterfaceAsync']);[!NOTE] AI agents: see
AI.mdfor the package binding contract and source-navigation guidance. It explains how to use the package without scanning the entire implementation.
Examples
Run the included examples:
bun run example:audio-device-radar
bun run example:mmdevapi-factory-probeNotes
- Either rely on lazy binding or call
Mmdevapi.Preload(). - Windows only. Bun runtime required.
- SAL types & naming: nullability is in the type —
Optional<T>(formally optional, SAL_*opt_) andNullable<T>(plain[in]/[out]the docs say can be NULL), the null sentinel derived fromT(nullfor pointersLP*/P*,0nfor handles/by-value addresses); direction is in the parameter name —_out(_Out_),_in_out(_Inout_),_In_bare. SeeAI.mdand the repoAGENTS.md.
