我正在使用NAudio完成一些任务:
我编写的程序可以执行任务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中的一个错误吗?
答案 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);
}
这似乎对我很好