本文介绍了NAudio-无法设置线路控制静音值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用NAudio来完成一些任务:

I'm using NAudio to do a few tasks:

  1. 找到立体声混音"源代码行
  2. 通过启用存在的任何行控件来取消对"Stereo Mix"源行的静音
  3. 通过禁用存在的任何线路控件来使同一输入设备上的所有其他源线路静音

我编写的程序可以执行任务1,但是任务2和3失败.

The program I've written can perform task 1 okay, but tasks 2 and 3 fail.

具体来说,此代码块将引发ArgumentException:

Specifically, this block of code causes the ArgumentException to be thrown:

if( control.IsBoolean ) {

    BooleanMixerControl boolControl = (BooleanMixerControl)control;
    boolControl.Value = isMuted;
    set = true;

    if( boolControl.Value != isMuted )
        throw new ArgumentException("Could not set line muted value.");
}

这是我用来执行这些任务的静态类.它依赖于当前版本的NAudio:

Here is a static class that I use to perform these tasks. It has a dependency on the current version of NAudio:

public static class RecordSourceManager {

    public static Boolean GetMicrophoneMuted(String deviceName) {

        Mixer mixer = GetMixer( deviceName );
        if( mixer == null ) throw new ArgumentException("Specified device \"" + deviceName + "\" does not exist.");

        foreach(MixerLine line in mixer.Destinations) {

            foreach(MixerLine sourceLine in line.Sources) {

                if( sourceLine.ComponentType == MixerLineComponentType.SourceMicrophone ) {

                    return GetLineMuted( sourceLine );
                }
            }
        }

        throw new ArgumentException("Specified device \"" + deviceName + "\" does not contain a microphone device.");
    }

    public static void SetMicrophoneExclusive(String deviceName, Boolean enableMicrophoneExclusivity) {

        Mixer mixer = GetMixer( deviceName );
        if( mixer == null ) throw new ArgumentException("Specified device \"" + deviceName + "\" does not exist.");

        foreach(MixerLine line in mixer.Destinations) {

            foreach(MixerLine sourceLine in line.Sources) {

                if( sourceLine.ComponentType == MixerLineComponentType.SourceMicrophone ) {

                    SetLineMuted( sourceLine, !enableMicrophoneExclusivity );

                } else {

                    SetLineMuted( sourceLine, enableMicrophoneExclusivity );
                }
            }
        }
    }

    public static Boolean GetStereoMixMuted(String deviceName) {

        Mixer mixer = GetMixer( deviceName );
        if( mixer == null ) throw new ArgumentException("Specified device \"" + deviceName + "\" does not exist.");

        foreach(MixerLine line in mixer.Destinations) {

            foreach(MixerLine sourceLine in line.Sources) {

                if( IsStereoMix( sourceLine.Name ) ) {

                    return GetLineMuted( sourceLine );
                }
            }
        }

        throw new ArgumentException("Specified device \"" + deviceName + "\" does not contain a microphone device.");
    }

    public static void SetStereoMixExclusive(String deviceName, Boolean enableStereoMixExclusivity) {

        Mixer mixer = GetMixer( deviceName );
        if( mixer == null ) throw new ArgumentException("Specified device \"" + deviceName + "\" does not exist.");

        MixerLine stereoMix;
        MixerLine parentLine;

        GetStereoMixLine( mixer, out stereoMix, out parentLine );
        if( stereoMix == null ) throw new ArgumentException("Specified device \"" + deviceName + "\" does not contain a Stereo Mix line.");

        foreach(MixerLine source in parentLine.Sources) {

            Boolean ok;

            if( IsStereoMix( source.Name ) ) {

                ok = SetLineMuted( source, !enableStereoMixExclusivity );

            } else {

                ok = SetLineMuted( source, enableStereoMixExclusivity );
            }

            if( !ok ) throw new ArgumentException("Could not set line muted state.");
        }
    }

    private static Mixer GetMixer(String deviceName) {

        foreach(Mixer mixer in Mixer.Mixers) {

            //wtr.WriteLine("Mixer: {0}, Mfg: {1}", mixer.Name, mixer.Manufacturer );
            if( String.Equals( mixer.Name, deviceName, StringComparison.OrdinalIgnoreCase ) ) return mixer;
        }

        return null;
    }

    private static void GetStereoMixLine(Mixer device, out MixerLine stereoMix, out MixerLine parentLine) {

        foreach(MixerLine line in device.Destinations) {

            foreach(MixerLine source in line.Sources) {

                if( IsStereoMix( source.Name ) ) {

                    stereoMix  = source;
                    parentLine = line;
                    return;
                }
            }

        }

        stereoMix  = null;
        parentLine = null;
    }

    private static Boolean IsStereoMix(String sourceName) {

        String[] names = new String[] {
            "Stereo Mix",
            "What U Hear",
            "What \"U\" Hear",
            "What-U-Hear",
            "Playback Redirect",
            "Wave Out",
            "Wave Out Mix",
            "Wave-Out Mix"
        };

        foreach(String name in names) {

            if( String.Equals( sourceName, name, StringComparison.OrdinalIgnoreCase ) ) return true;
        }

        return false;
    }

    private static Boolean SetLineMuted(MixerLine line, Boolean isMuted) {

        Boolean set = false;

        foreach(MixerControl control in line.Controls) {

            // Can't test if control's name == "Mute" because sometimes it's "Mic Volume" (even though it's boolean). Same goes for GetLineMuted.
            if( control.IsBoolean ) {

                BooleanMixerControl boolControl = (BooleanMixerControl)control;
                boolControl.Value = isMuted;
                set = true;

                if( boolControl.Value != isMuted )
                    throw new ArgumentException("Could not set line muted value.");
            }

        }

        return set;
    }

    private static Boolean GetLineMuted(MixerLine line) {

        foreach(MixerControl control in line.Controls) {

            if( control.IsBoolean ) {

                BooleanMixerControl boolControl = (BooleanMixerControl)control;
                return boolControl.Value;
            }
        }

        return false;
    }
}

我以为我要看一下NAudio的BooleanMixerControl类,我看到了:

I thought I'd take a look at NAudio's BooleanMixerControl class, and I see this:

public bool Value {
    get {
        base.GetControlDetails();
        return (this.boolDetails.fValue == 1);
    }
    set {
        MmException.Try(MixerInterop.mixerSetControlDetails(base.mixerHandle, ref this.mixerControlDetails, base.mixerHandleType), "mixerSetControlDetails");
    }
}

有趣的是,似乎似乎忽略了属性设置器的value参数,因此mixerSetControlDetails调用不会做任何有用的工作.这是NAudio中的错误吗?

Interestingly it seems the value argument to the property setter is being ignored, the mixerSetControlDetails call therefore won't do any useful work. Is this a bug in NAudio?

推荐答案

此功能尚未实现,可能应替换为NotImplementedException.这是我2002年刚开始学习PInvoke和固定时为NAudio编写的第一批代码,如果您查看NAudio源码,您会发现使用该值的代码被注释掉了,大概是因为最初尝试时导致某种内存异常.

This feature is not implemented, and probably should be replaced with a NotImplementedException. It was amongst the first code I ever wrote for NAudio back in 2002 when I was just beginning to learn about PInvoke and pinning, and if you look at the NAudio source you will see the code that uses the value is commented out, presumably because it caused some kind of memory exception when I originally tried it.

/// <summary>
/// The current value of the control
/// </summary>
public bool Value 
{
    get 
    {
        GetControlDetails(); // make sure we have the latest value
        return (boolDetails.fValue == 1);
    }
    set 
    {
        //GetControlDetails();
        //MixerInterop.MIXERCONTROLDETAILS_BOOLEAN boolDetails = (MixerInterop.MIXERCONTROLDETAILS_BOOLEAN) Marshal.PtrToStructure(mixerControlDetails.paDetails,typeof(MixerInterop.MIXERCONTROLDETAILS_BOOLEAN));
        //boolDetails.fValue = (value) ? 1 : 0;
        // TODO: pin the memory
        MmException.Try(MixerInterop.mixerSetControlDetails(mixerHandle, ref mixerControlDetails, MixerFlags.Value | mixerHandleType), "mixerSetControlDetails");
    }
}   

它从未得到修复的原因是,我自己不需要使用它,但是如果有人想提供一个修复程序,我很高兴将其包含在NAudio中.

The reason it has never been fixed is that I've never needed to use it myself, but if someone wants to contribute a fix I'd be glad to include it in NAudio.

这篇关于NAudio-无法设置线路控制静音值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-27 15:01