Unity Windows应用:如何检测默认音视频设备变更?
检测Windows默认音视频设备变更的Unity实现方案
嘿,这个需求我之前做直播工具类项目时刚好踩过坑,下面给你分享两种可行的实现思路,从快速上手到进阶优化都有:
一、简单易用:定时轮询检测(适合快速验证)
这种方式逻辑直白,不需要复杂的原生API调用,核心就是定期抓取当前默认设备的唯一标识,和之前保存的对比,不一致就触发你的目标函数。
1. 麦克风检测示例代码
using UnityEngine; using System.Collections; using System.Runtime.InteropServices; public class AudioDeviceMonitor : MonoBehaviour { // 调用Windows API获取默认音频设备信息 [DllImport("winmm.dll", CharSet = CharSet.Auto)] private static extern uint waveInGetDevCaps(uint uDeviceID, ref WAVEINCAPS pwic, uint cbwic); [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] private struct WAVEINCAPS { public ushort wMid; public ushort wPid; public uint vDriverVersion; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string szPname; public uint dwFormats; public ushort wChannels; public ushort wReserved1; } private string currentDefaultMicID; void Start() { // 初始化时记录当前默认麦克风标识 currentDefaultMicID = GetDefaultMicrophoneID(); // 启动协程,每2秒检查一次(可根据需求调整间隔) StartCoroutine(CheckDeviceChangeCoroutine(2f)); } IEnumerator CheckDeviceChangeCoroutine(float checkInterval) { while (true) { yield return new WaitForSeconds(checkInterval); string newMicID = GetDefaultMicrophoneID(); if (newMicID != currentDefaultMicID) { Debug.Log("默认麦克风已变更!"); // 调用你的自定义处理函数 OnDefaultMicrophoneChanged(); currentDefaultMicID = newMicID; } } } private string GetDefaultMicrophoneID() { WAVEINCAPS caps = new WAVEINCAPS(); waveInGetDevCaps(0, ref caps, (uint)Marshal.SizeOf(caps)); // 用设备名称作为标识,也可以结合wMid+wPid生成更唯一的ID return caps.szPname; } // 你需要触发的自定义函数 private void OnDefaultMicrophoneChanged() { // 这里写设备变更后的逻辑:比如重新初始化麦克风、提示用户等 Debug.Log("执行自定义麦克风变更逻辑"); } }
2. 摄像头检测示例代码
摄像头可以直接借助Unity自带的WebCamTexture类获取系统默认设备信息:
using UnityEngine; using System.Collections; public class CameraDeviceMonitor : MonoBehaviour { private string currentDefaultCamID; void Start() { currentDefaultCamID = GetDefaultCameraID(); StartCoroutine(CheckCameraChangeCoroutine(2f)); } IEnumerator CheckCameraChangeCoroutine(float checkInterval) { while (true) { yield return new WaitForSeconds(checkInterval); string newCamID = GetDefaultCameraID(); if (newCamID != currentDefaultCamID) { Debug.Log("默认摄像头已变更!"); OnDefaultCameraChanged(); currentDefaultCamID = newCamID; } } } private string GetDefaultCameraID() { if (WebCamTexture.devices.Length == 0) return string.Empty; // Unity中WebCamTexture.devices[0]就是系统默认摄像头 WebCamDevice defaultCam = WebCamTexture.devices[0]; return defaultCam.name; } private void OnDefaultCameraChanged() { // 自定义摄像头变更逻辑:比如重新创建WebCamTexture、刷新预览画面等 Debug.Log("执行摄像头变更后的逻辑"); } }
二、进阶方案:实时监听系统设备变更事件
如果需要零延迟的响应(不想等轮询间隔),可以调用Windows原生API监听设备插拔/默认值变更事件,适合对响应速度要求高的场景。
核心实现思路
- 用
RegisterDeviceNotification注册设备变更通知 - 通过
SetWinEventHook捕获系统设备事件 - 解析事件类型,判断是否是音视频设备变更,触发自定义函数
简化版示例代码(监听音频设备变更)
using UnityEngine; using System; using System.Runtime.InteropServices; public class RealTimeDeviceMonitor : MonoBehaviour { [DllImport("user32.dll")] private static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc, WinEventDelegate lpfnWinEventProc, uint idProcess, uint idThread, uint dwFlags); [DllImport("user32.dll")] private static extern bool UnhookWinEvent(IntPtr hWinEventHook); private delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime); private IntPtr eventHook; private WinEventDelegate eventDelegate; private const uint EVENT_SYSTEM_SOUND = 0x0001; private const uint WINEVENT_OUTOFCONTEXT = 0x0000; void OnEnable() { eventDelegate = new WinEventDelegate(WinEventProc); // 监听系统声音相关事件,间接捕获音频设备变更 eventHook = SetWinEventHook(EVENT_SYSTEM_SOUND, EVENT_SYSTEM_SOUND, IntPtr.Zero, eventDelegate, 0, 0, WINEVENT_OUTOFCONTEXT); } void OnDisable() { if (eventHook != IntPtr.Zero) { UnhookWinEvent(eventHook); } } private void WinEventProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime) { Debug.Log("检测到音频设备可能变更,开始验证..."); // 复用之前的设备ID对比逻辑,触发自定义函数 CheckAndTriggerAudioDeviceChange(); } private void CheckAndTriggerAudioDeviceChange() { // 这里可以直接调用之前的GetDefaultMicrophoneID和对比逻辑 // 省略重复代码,逻辑和轮询方式一致 } }
注意事项
- 轮询间隔建议设为1-3秒,平衡性能和响应速度
- 实时监听方式要在
OnEnable/OnDisable中正确注册/注销钩子,避免内存泄漏 - 测试时记得手动切换Windows默认设备,确认逻辑生效
- 打包时确保脚本被正确包含在Build中,Windows平台API调用不会被剥离
内容的提问来源于stack exchange,提问作者MBS
相关产品推荐
相关产品推荐

