NAudioを使用していくつかのタスクを実行しています。
- 「StereoMix」ソースラインを見つけます
- 存在するラインコントロールを有効にして、「StereoMix」ソースラインのミュートを解除します
- 存在するラインコントロールを無効にして、同じ入力デバイス上の他のすべてのソースラインをミュートします
私が書いたプログラムはタスク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のバグですか?