Skip to content

Commit

Permalink
Add audio passthrough error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
micahmo committed Apr 14, 2023
1 parent f06ab03 commit 5db0fff
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 21 deletions.
96 changes: 75 additions & 21 deletions SoundBoard/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1576,35 +1576,89 @@ private void HandleInputOutputChange()

if (GlobalSettings.GetInputDeviceGuids().Any())
{
Guid inputDeviceId = GlobalSettings.GetInputDeviceGuids().First();

foreach (var outputDeviceId in GlobalSettings.GetOutputDeviceGuids())
{
// Create the input
Guid inputDeviceId = GlobalSettings.GetInputDeviceGuids().First();
MMDevice inputDevice = Utilities.GetDevice(inputDeviceId, DataFlow.Capture);
WasapiCapture inputCapture = new WasapiCapture(inputDevice);
inputCapture.RecordingStopped += HandleRecordingStopped;
_inputCaptures.Add(inputCapture);

// Create the buffer
BufferedWaveProvider bufferedWaveProvider = new BufferedWaveProvider(inputDevice.AudioClient.MixFormat)
try
{
DiscardOnBufferOverflow = true
};
_bufferedWaveProviders.Add(bufferedWaveProvider);
// Create the input
MMDevice inputDevice = Utilities.GetDevice(inputDeviceId, DataFlow.Capture);
WasapiCapture inputCapture = new WasapiCapture(inputDevice);
inputCapture.RecordingStopped += HandleRecordingStopped;
_inputCaptures.Add(inputCapture);

// Create the buffer
BufferedWaveProvider bufferedWaveProvider = new BufferedWaveProvider(inputDevice.AudioClient.MixFormat)
{
DiscardOnBufferOverflow = true
};
_bufferedWaveProviders.Add(bufferedWaveProvider);

inputCapture.DataAvailable += (_, args) =>
{
bufferedWaveProvider.AddSamples(args.Buffer, 0, args.BytesRecorded);
};

inputCapture.DataAvailable += (_, args) =>
// Create the outputs
WasapiOut output = new WasapiOut(Utilities.GetDevice(outputDeviceId, DataFlow.Render), AudioClientShareMode.Shared, true, GlobalSettings.AudioPassthroughLatency);
_outputCaptures.Add(output);

output.Init(bufferedWaveProvider);
output.Play();

inputCapture.StartRecording();
}
catch (Exception ex)
{
bufferedWaveProvider.AddSamples(args.Buffer, 0, args.BytesRecorded);
};
HandleRecordingStopped(this, new StoppedEventArgs());

// Create the outputs
WasapiOut output = new WasapiOut(Utilities.GetDevice(outputDeviceId, DataFlow.Render), AudioClientShareMode.Shared, true, GlobalSettings.AudioPassthroughLatency);
_outputCaptures.Add(output);
Dispatcher.Invoke(async () =>
{
// Try to get the friendly input/output device names.
string inputDeviceName = Properties.Resources.UNKNOWN;
string outputDeviceName = Properties.Resources.UNKNOWN;
try
{
inputDeviceName = Utilities.GetDevice(inputDeviceId, DataFlow.Capture).FriendlyName;
}
catch {}
try
{
outputDeviceName = Utilities.GetDevice(outputDeviceId, DataFlow.Render).FriendlyName;
}
catch {}

string error = string.Format(Properties.Resources.AudioPassthroughError, inputDeviceName, outputDeviceName);

if (ex is COMException comException)
{
if (comException.ErrorCode == -2004287478)
{
// This is a specific error we know about which means the output device is being held exclusively.
error += $"{Environment.NewLine}{Environment.NewLine}{Properties.Resources.AudioPassthroughOutputExclusiveError}";
}

error += $"{Environment.NewLine}{Environment.NewLine}{string.Format(Properties.Resources.ComErrorCode, comException.ErrorCode)}";
}

output.Init(bufferedWaveProvider);
output.Play();
string fullError = $"{error}{Environment.NewLine}{Environment.NewLine}{ex}";

inputCapture.StartRecording();
var res = await this.ShowMessageAsync(Properties.Resources.Error, error,
MessageDialogStyle.AffirmativeAndNegative, new MetroDialogSettings
{
AffirmativeButtonText = Properties.Resources.CopyDetails,
NegativeButtonText = Properties.Resources.OK
});

if (res == MessageDialogResult.Affirmative)
{
Clipboard.SetText(fullError);
}
});

return;
}
}
}
}
Expand Down
36 changes: 36 additions & 0 deletions SoundBoard/Properties/Resources.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions SoundBoard/Properties/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -380,4 +380,16 @@ Global Hotkey: {1}</value>
<data name="ChangeDefaultButtonGrid" xml:space="preserve">
<value>Change Default Button Grid</value>
</data>
<data name="UNKNOWN" xml:space="preserve">
<value>UNKNOWN</value>
</data>
<data name="AudioPassthroughError" xml:space="preserve">
<value>There was an error opening the input ({0}) or output ({1}) audio device for audio passthrough.</value>
</data>
<data name="ComErrorCode" xml:space="preserve">
<value>Error code: 0x{0:X}</value>
</data>
<data name="AudioPassthroughOutputExclusiveError" xml:space="preserve">
<value>The output audio device is being used exclusively by another application.</value>
</data>
</root>

0 comments on commit 5db0fff

Please sign in to comment.