You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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监听设备插拔/默认值变更事件,适合对响应速度要求高的场景。

核心实现思路

  1. 用RegisterDeviceNotification注册设备变更通知
  2. 通过SetWinEventHook捕获系统设备事件
  3. 解析事件类型,判断是否是音视频设备变更,触发自定义函数

简化版示例代码(监听音频设备变更)

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:16:25