0

NAudioを使用していくつかのタスクを実行しています。

  1. 「StereoMix」ソースラインを見つけます
  2. 存在するラインコントロールを有効にして、「StereoMix」ソースラインのミュートを解除します
  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

この機能は実装されていないため、おそらく。に置き換える必要がありNotImplementedExceptionます。これは、2002年にPInvokeとピン留めについて学び始めたばかりのときに、NAudio用に作成した最初のコードの1つでした。また、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 に答える
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 に答える