NAudio - 无法设置线路控制静音值

时间:2012-06-20 00:17:24

标签: c# naudio

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

  1. 找到“Stereo Mix”源代码行
  2. 通过启用任何线控制来取消静音“立体声混音”源线
  3. 通过禁用任何线控制来使同一输入设备上的所有其他源线静音
  4. 我编写的程序可以执行任务1,但任务2和3失败。

    具体来说,这段代码会导致抛出ArgumentException:

    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:

    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类,我看到了这个:

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

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

2 个答案:

答案 0 :(得分:2)

此功能未实现,可能应替换为NotImplementedException。这是我在2002年为NAudio写的第一个代码,当时我刚刚开始学习PInvoke和pinning,如果你看一下NAudio源,你会看到使用该值的代码被注释掉了,大概是因为它我最初尝试时会引起某种内存异常。

/// <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中。

答案 1 :(得分:2)

我也有这个问题。除了Mark Heaths的回复,我调整了BooleanMixerControl的属性Value来检索正确的值:

/// <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
    {
        int structSize = Marshal.SizeOf(boolDetails);

        mixerControlDetails.paDetails = Marshal.AllocHGlobal(structSize * nChannels);
        for (int channel = 0; channel < nChannels; channel++)
        {
            boolDetails.fValue = value ? 1 : 0;
            long pointer = mixerControlDetails.paDetails.ToInt64() + (structSize * channel);
            Marshal.StructureToPtr(boolDetails, (IntPtr)pointer, false);
        }
        MmException.Try(MixerInterop.mixerSetControlDetails(mixerHandle, ref mixerControlDetails, MixerFlags.Value | mixerHandleType), "mixerSetControlDetails");
        Marshal.FreeHGlobal(mixerControlDetails.paDetails);
    }

这似乎对我很好