0

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

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

我编写的程序可以正常执行任务 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");
    }
}

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

4

2 回答 2

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);
    }

这对我来说似乎很好用

于 2013-03-20T11:09:26.633 回答
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 中。

于 2012-06-20T09:55:56.340 回答