【问题标题】:How to Get and Set System Volume in Windows如何在 Windows 中获取和设置系统音量
【发布时间】:2018-11-16 05:39:00
【问题描述】:

我想在键盘点击时使用 unity 和 c# 将操作系统音量设置在某个级别,例如我想将 Windows 音量(不是统一)设置为 70:我该怎么做???

void Update()
{   
    if (Input.GetKeyDown(KeyCode.A))
    {
        //Set Windows Volume 70%      
    }
}

【问题讨论】:

    标签: c# c++ unity3d window


    【解决方案1】:

    这需要一个插件。由于这个问题是针对 Windows 的,您可以使用 IAudioEndpointVolume 构建一个 C++ plugin 然后从 C# 调用它。 This 帖子有一个有效的 C++ 示例,说明如何使用 IAudioEndpointVolume 更改音量,您可以将其用作创建 C++ 插件的基本源。


    我已经开始清理该代码,然后将其转换为 dll 插件并将 DLL 放在 Assets/Plugins 文件夹中。你可以看看如何构建C++插件here

    C++ 代码

    #include "stdafx.h"
    #include <windows.h>
    #include <mmdeviceapi.h>
    #include <endpointvolume.h>
    
    #define DLLExport __declspec(dllexport)
    
    extern "C"
    {
        enum class VolumeUnit {
            Decibel,
            Scalar
        };
    
        //Gets volume
        DLLExport float GetSystemVolume(VolumeUnit vUnit) {
            HRESULT hr;
    
            // -------------------------
            CoInitialize(NULL);
            IMMDeviceEnumerator *deviceEnumerator = NULL;
            hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, __uuidof(IMMDeviceEnumerator), (LPVOID *)&deviceEnumerator);
            IMMDevice *defaultDevice = NULL;
    
            hr = deviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &defaultDevice);
            deviceEnumerator->Release();
            deviceEnumerator = NULL;
    
            IAudioEndpointVolume *endpointVolume = NULL;
            hr = defaultDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL, (LPVOID *)&endpointVolume);
            defaultDevice->Release();
            defaultDevice = NULL;
    
            float currentVolume = 0;
            if (vUnit == VolumeUnit::Decibel) {
                //Current volume in dB
                hr = endpointVolume->GetMasterVolumeLevel(&currentVolume);
            }
    
            else if (vUnit == VolumeUnit::Scalar) {
                //Current volume as a scalar
                hr = endpointVolume->GetMasterVolumeLevelScalar(&currentVolume);
            }
            endpointVolume->Release();
            CoUninitialize();
    
            return currentVolume;
        }
    
        //Sets volume
        DLLExport void SetSystemVolume(double newVolume, VolumeUnit vUnit) {
            HRESULT hr;
    
            // -------------------------
            CoInitialize(NULL);
            IMMDeviceEnumerator *deviceEnumerator = NULL;
            hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, __uuidof(IMMDeviceEnumerator), (LPVOID *)&deviceEnumerator);
            IMMDevice *defaultDevice = NULL;
    
            hr = deviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &defaultDevice);
            deviceEnumerator->Release();
            deviceEnumerator = NULL;
    
            IAudioEndpointVolume *endpointVolume = NULL;
            hr = defaultDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL, (LPVOID *)&endpointVolume);
            defaultDevice->Release();
            defaultDevice = NULL;
    
            if (vUnit == VolumeUnit::Decibel)
                hr = endpointVolume->SetMasterVolumeLevel((float)newVolume, NULL);
    
            else    if (vUnit == VolumeUnit::Scalar)
                hr = endpointVolume->SetMasterVolumeLevelScalar((float)newVolume, NULL);
    
            endpointVolume->Release();
    
            CoUninitialize();
        }
    }
    

    C# 代码

    using System.Runtime.InteropServices;
    using UnityEngine;
    
    public class VolumeManager : MonoBehaviour
    {
        //The Unit to use when getting and setting the volume
        public enum VolumeUnit
        {
            //Perform volume action in decibels</param>
            Decibel,
            //Perform volume action in scalar
            Scalar
        }
    
        /// <summary>
        /// Gets the current volume
        /// </summary>
        /// <param name="vUnit">The unit to report the current volume in</param>
        [DllImport("ChangeVolumeWindows")]
        public static extern float GetSystemVolume(VolumeUnit vUnit);
        /// <summary>
        /// sets the current volume
        /// </summary>
        /// <param name="newVolume">The new volume to set</param>
        /// <param name="vUnit">The unit to set the current volume in</param>
        [DllImport("ChangeVolumeWindows")]
        public static extern void SetSystemVolume(double newVolume, VolumeUnit vUnit);
    
        // Use this for initialization
        void Start()
        {
            //Get volume in Decibel 
            float volumeDecibel = GetSystemVolume(VolumeUnit.Decibel);
            Debug.Log("Volume in Decibel: " + volumeDecibel);
    
            //Get volume in Scalar 
            float volumeScalar = GetSystemVolume(VolumeUnit.Scalar);
            Debug.Log("Volume in Scalar: " + volumeScalar);
    
            //Set volume in Decibel 
            SetSystemVolume(-16f, VolumeUnit.Decibel);
    
            //Set volume in Scalar 
            SetSystemVolume(0.70f, VolumeUnit.Scalar);
        }
    }
    

    GetSystemVolume 函数用于获取当前音量,SetSystemVolume 用于设置。此问题适用于 Windows,但您可以使用其他平台的 API 做类似的事情。

    按下A键时将其设置为70%

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.A))
        {
            //Set Windows Volume 70%  
            SetSystemVolume(0.70f, VolumeUnit.Scalar);
        }
    }
    

    【讨论】:

    • 正是我想要的......谢谢......它运作良好:)
    • @AmmarIsmaeel 好。很高兴我能提供帮助。
    • 很好的答案 - 一切都完美无缺。在我注释掉第一个包含之前,我的 DLL 没有编译: //#include "stdafx.h"
    • 谢谢!只是要注意可能的 DLL 依赖关系。我的一位同事使用 Visual Studio 2015 根据这个答案制作了一个 DLL,但我们发现在一些用户的 Windows 10 机器上,有一个DLLNotFoundException even though the DLL was present。此异常实际上是由于缺少 DLL 依赖项(特别是缺少 Microsoft Visual C++ Redistributable)。在我们的例子中,在 Plugins 文件夹中包含 vcruntime140.dll 和 api-ms-win-crt-runtime-l1-1-0.dll 以及这个 DLL 解决了这个问题。
    • 此外,对于直接使用上述代码的任何人 - 请注意,如果 IMMDeviceEnumerator.GetDefaultAudioEndpoint 失败或没有可用设备,则 defaultDevice 可以是 null,这将导致 Unity 崩溃。具体来说,我在一个用户的机器上遇到了这个问题,由于驱动程序问题,没有有效的声音播放设备。 (请参阅Control Panel -&gt; Sound -&gt; Playback 并禁用所有设备以对此进行测试。)
    【解决方案2】:

    据我所知,您无法做到这一点。这样做没有任何好处,您是否在任何游戏/应用程序中看到过这种情况?

    您可以使用滑块更改 Unity 应用程序的主音量,还可以以相同的方式管理其他音效

    http://docs.unity3d.com/ScriptReference/AudioListener.html
    http://docs.unity3d.com/ScriptReference/AudioListener-volume.html

    例子

    public class AudioControl: MonoBehaviour {
    void SetVolume(Slider slider) {
        AudioListener.volume = slider.Value;
        // probably save this value to a playerpref so it is remembered. 
        }
    }
    

    【讨论】:

    • “想设置 Windows 音量(不是统一)” 这不是系统音量。您正在设置 Unity 的音量。请再次阅读问题。
    • 请再次阅读我的回答,我说“你不能这样做”,并要求他提供一个这样做的例子。这不是一个适用的答案吗?
    • 你可以。你可以这样做。设置系统音量与设置游戏音量不同。 OP明确表示。您的回答没有解决这里的问题
    • @Programmer “你不能”是一个有效的答案。在尝试查看 C# 应用程序如何调整 Windows 系统音量时,我发现了 this,它基本上是 C++ dll 的包装器......并且不能在 Unity 中编译。 Visual Studio 说没问题,但 Unity 找不到 System.Windows
    • @Draco18s 我用 C++ 而不是 C# 搜索类似这样的问题。我了解到,每当您需要访问或控制硬件时,有 90% 的可能性是保证工作的官方 API 仅在 C++ 中可用。其他编程语言有时会使用 C++ API 来实现它,但不是大多数时候。这就是为什么 C# 中的其他解决方案不会显示官方 API,并且通常是很长的代码或不是正确方法的短代码,例如使用按键。
    猜你喜欢
    • 1970-01-01
    • 2011-06-06
    • 2019-12-13
    • 2019-01-08
    • 1970-01-01
    • 1970-01-01
    • 2011-11-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多