Skip to content

Commit

Permalink
* Fix a potential failure during device discovery.
Browse files Browse the repository at this point in the history
* Improve error handling. Print more details in case of an unexpected error.
  • Loading branch information
PolarGoose committed Sep 10, 2024
1 parent 9a084d6 commit 65e1a73
Show file tree
Hide file tree
Showing 14 changed files with 67 additions and 28 deletions.
3 changes: 2 additions & 1 deletion src/Bluetooth/Devices/BluetoothLeDevice.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using BluetoothDevicePairing.Utils;
using System;

namespace BluetoothDevicePairing.Bluetooth.Devices;
Expand All @@ -21,7 +22,7 @@ public static BluetoothLeDevice FromMac(DeviceMacAddress mac)
{
var device = Windows.Devices.Bluetooth.BluetoothLEDevice.FromBluetoothAddressAsync(mac.RawAddress).GetAwaiter().GetResult();
return device == null
? throw new Exception($"Can't create a BluetoothLE device from the provided mac address '{mac}'. Device with this mac address doesn't exist")
? throw new AppException($"Can't create a BluetoothLE device from the provided mac address '{mac}'. Device with this mac address doesn't exist")
: new BluetoothLeDevice(device);
}
}
23 changes: 18 additions & 5 deletions src/Bluetooth/Devices/DeviceDiscoverer.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
using BluetoothDevicePairing.Bluetooth.Devices.Utils;
using BluetoothDevicePairing.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using static Vanara.PInvoke.Ole32.PROPERTYKEY.System;
using static Vanara.PInvoke.User32;

namespace BluetoothDevicePairing.Bluetooth.Devices;

Expand All @@ -14,7 +17,7 @@ public DiscoveryTime(int timeInSeconds)
{
if (timeInSeconds is < 1 or > 30)
{
throw new Exception($"discovery time should be in range [1; 30] but was {timeInSeconds}");
throw new AppException($"discovery time should be in range [1; 30] but was {timeInSeconds}");
}

Seconds = timeInSeconds;
Expand All @@ -41,13 +44,23 @@ private static List<Device> Discover(AsqFilter filter, DiscoveryTime time)
watcher.Start();
Thread.Sleep(time.Seconds * 1000);
var devices = watcher.Stop();
return devices.Select(CreateDevice).ToList();
return devices.Select(CreateDevice).OfType<Device>().ToList();
}

private static Device CreateDevice(Windows.Devices.Enumeration.DeviceInformation info)
{
return new DeviceInfoId(info).DeviceType == DeviceType.Bluetooth
? BluetoothDevice.FromDeviceInfo(info)
: BluetoothLeDevice.FromDeviceInfo(info);
try
{
// This can throw the following exception:
// System.ArgumentException: The parameter is incorrect. The provided device ID is not a valid BluetoothDevice object.
return new DeviceInfoId(info).DeviceType == DeviceType.Bluetooth
? BluetoothDevice.FromDeviceInfo(info)
: BluetoothLeDevice.FromDeviceInfo(info);
}
catch (Exception ex)
{
Console.WriteLine($"Warning: failed to get information from the discovered device [{info.Name}; {info.Id}]. Error message: {ex.Message}");
return null;
}
}
}
3 changes: 2 additions & 1 deletion src/Bluetooth/Devices/DeviceInfoId.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Text.RegularExpressions;
using BluetoothDevicePairing.Bluetooth.Adapters;
using BluetoothDevicePairing.Utils;

namespace BluetoothDevicePairing.Bluetooth.Devices;

Expand All @@ -15,7 +16,7 @@ public DeviceInfoId(Windows.Devices.Enumeration.DeviceInformation info)
var match = Regex.Match(info.Id, @"(^\w+)#(?<Type>Bluetooth|BluetoothLE)(?<AdapterMac>(..:){5}(..))-(?<DeviceMac>(..:){5}(..))$");
if (!match.Success)
{
throw new Exception($"Failed to parse DeviceInformation.Id '{info.Id}'");
throw new AppException($"Failed to parse DeviceInformation.Id '{info.Id}'");
}

DeviceType = match.Groups["Type"].Value == "Bluetooth" ? DeviceType.Bluetooth : DeviceType.BluetoothLE;
Expand Down
9 changes: 5 additions & 4 deletions src/Bluetooth/Devices/DevicePairer.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using BluetoothDevicePairing.Utils;
using System;
using System.Linq;

Expand All @@ -11,14 +12,14 @@ public static void PairDevice(Device device, string pinCode)

if (device.ConnectionStatus == ConnectionStatus.Connected)
{
throw new Exception("Device is already connected, no need to pair");
throw new AppException("Device is already connected, no need to pair");
}

if (device.ConnectionStatus == ConnectionStatus.Paired)
{
if (!device.AssociatedAudioDevices.Any())
{
throw new Exception("Device is already paired");
throw new AppException("Device is already paired");
}

Console.WriteLine("Device is already paired. Connecting associated audio devices");
Expand Down Expand Up @@ -53,7 +54,7 @@ private static void Pair(Windows.Devices.Enumeration.DeviceInformationPairing pa
.GetAwaiter().GetResult().Status;
if (res != Windows.Devices.Enumeration.DevicePairingResultStatus.Paired)
{
throw new Exception($"Failed to pair device. Status = {res}");
throw new AppException($"Failed to pair device. Status = {res}");
}
}

Expand Down Expand Up @@ -82,7 +83,7 @@ private static void PairingRequestedHandler(Windows.Devices.Enumeration.DevicePa

default:
Console.WriteLine($"Unexpected pairing type: {args.PairingKind}");
throw new Exception();
throw new AppException();
}
}
}
5 changes: 3 additions & 2 deletions src/Bluetooth/Devices/DeviceUnPairer.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using BluetoothDevicePairing.Utils;
using System;

namespace BluetoothDevicePairing.Bluetooth.Devices;
Expand All @@ -10,13 +11,13 @@ public static void UnpairDevice(Device device)

if (device.ConnectionStatus == ConnectionStatus.NotPaired)
{
throw new Exception("Device is not paired");
throw new AppException("Device is not paired");
}

var res = device.PairingInfo.UnpairAsync().GetAwaiter().GetResult().Status;
if (res != Windows.Devices.Enumeration.DeviceUnpairingResultStatus.Unpaired)
{
throw new Exception($"Failed to unpair the device. Status = {res}");
throw new AppException($"Failed to unpair the device. Status = {res}");
}

Console.WriteLine("Device has been successfully unpaired");
Expand Down
3 changes: 2 additions & 1 deletion src/Bluetooth/MacAddress.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using BluetoothDevicePairing.Utils;
using System;
using System.Linq;
using System.Text.RegularExpressions;
Expand All @@ -14,7 +15,7 @@ protected MacAddress(string mac)
var match = Regex.Match(mac, @"^(..:){5}(..)$");
if (!match.Success)
{
throw new Exception($"MacAddress address '{mac}' is not a valid mac address");
throw new AppException($"MacAddress address '{mac}' is not a valid mac address");
}
Address = mac;
RawAddress = Convert.ToUInt64(Address.Replace(":", ""), 16);
Expand Down
12 changes: 6 additions & 6 deletions src/BluetoothDevicePairing.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,21 @@
<Copyright>Console utility to discover and pair Bluetooth and Bluetooth Low Energy devices.</Copyright>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="CommandLineParser" Version="2.9.1"/>
<PackageReference Include="CommandLineParser" Version="2.9.1" />
<PackageReference Include="Costura.Fody" Version="5.7.0">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Fody" Version="6.8.0">
<PackageReference Include="Fody" Version="6.8.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Windows.SDK.Contracts" Version="10.0.22621.3233"/>
<PackageReference Include="Microsoft.Windows.SDK.Contracts" Version="10.0.26100.1" />
<PackageReference Include="PolySharp" Version="1.14.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="System.Net.Http" Version="4.3.4"/>
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.1"/>
<PackageReference Include="Vanara.PInvoke.CoreAudio" Version="4.0.1"/>
<PackageReference Include="System.Net.Http" Version="4.3.4" />
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />
<PackageReference Include="Vanara.PInvoke.CoreAudio" Version="4.0.3" />
</ItemGroup>
</Project>
3 changes: 2 additions & 1 deletion src/Commands/DisconnectBluetoothAudioDeviceByName.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using BluetoothDevicePairing.Bluetooth.Devices;
using BluetoothDevicePairing.Commands.Utils;
using BluetoothDevicePairing.Utils;
using CommandLine;
using System;

Expand All @@ -20,7 +21,7 @@ public static void Execute(DisconnectBluetoothAudioDeviceByNameOptions opts)
opts.DeviceType);
if (devices.Count > 1)
{
throw new Exception($"{devices.Count} devices found, don't know which one to choose");
throw new AppException($"{devices.Count} devices found, don't know which one to choose");
}

AudioDeviceDisconnector.DisconnectBluetoothAudioDevice(devices[0]);
Expand Down
5 changes: 3 additions & 2 deletions src/Commands/PairDeviceByName.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using BluetoothDevicePairing.Bluetooth.Devices;
using BluetoothDevicePairing.Commands.Utils;
using BluetoothDevicePairing.Utils;
using CommandLine;
using System;

Expand Down Expand Up @@ -29,10 +30,10 @@ public static void Execute(PairDeviceByNameOptions opts)
DevicePairer.PairDevice(devices[0], opts.PinCode);
return;
case 2:
throw new Exception(
throw new AppException(
$"2 devices with the name '{opts.DeviceName}' found \n 1 - \"{devices[0]}\" \n 2 - \"{devices[1]}\". Don't know which one to choose.");
default:
throw new Exception(
throw new AppException(
$"{devices.Count} devices with the name '{opts.DeviceName}' found. Don't know which one to choose");
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/Commands/UnPairDeviceByName.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using BluetoothDevicePairing.Bluetooth.Devices;
using BluetoothDevicePairing.Commands.Utils;
using BluetoothDevicePairing.Utils;
using CommandLine;
using System;

Expand All @@ -19,7 +20,7 @@ public static void Execute(UnpairDeviceByNameOptions opts)
opts.DeviceType);
if (devices.Count > 1)
{
throw new Exception($"{devices.Count} devices found, don't know which one to choose");
throw new AppException($"{devices.Count} devices found, don't know which one to choose");
}

DeviceUnPairer.UnpairDevice(devices[0]);
Expand Down
5 changes: 3 additions & 2 deletions src/Commands/Utils/AudioDeviceDisconnector.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using BluetoothDevicePairing.Bluetooth.Devices;
using System.Linq;
using System;
using BluetoothDevicePairing.Utils;

namespace BluetoothDevicePairing.Commands.Utils;

Expand All @@ -12,12 +13,12 @@ public static void DisconnectBluetoothAudioDevice(Device device)

if (device.ConnectionStatus != ConnectionStatus.Connected)
{
throw new Exception($"The device '{device.Name}' is not connected");
throw new AppException($"The device '{device.Name}' is not connected");
}

if (!device.AssociatedAudioDevices.Any())
{
throw new Exception($"The device '{device.Name}' is not an audio device");
throw new AppException($"The device '{device.Name}' is not an audio device");
}

Console.WriteLine($"Disconnecting audio devices associated with '{device.Name}'");
Expand Down
3 changes: 2 additions & 1 deletion src/Commands/Utils/DeviceFinder.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using BluetoothDevicePairing.Bluetooth.Devices;
using BluetoothDevicePairing.Utils;
using System;
using System.Collections.Generic;

Expand All @@ -10,7 +11,7 @@ public static List<Device> FindDevicesByName(List<Device> devices, string name,
{
var res = devices.FindAll(d => d.Name == name && deviceType == d.Id.DeviceType);
return res.Count == 0
? throw new Exception($"Couldn't find any devices with '{name}' name and device type '{deviceType}'")
? throw new AppException($"Couldn't find any devices with '{name}' name and device type '{deviceType}'")
: res;
}

Expand Down
8 changes: 7 additions & 1 deletion src/Program.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using BluetoothDevicePairing.Commands;
using BluetoothDevicePairing.Utils;
using CommandLine;

static void ParseCommandLineAndExecuteActions(string[] args)
Expand Down Expand Up @@ -27,8 +28,13 @@ static void ParseCommandLineAndExecuteActions(string[] args)
ParseCommandLineAndExecuteActions(args);
return 0;
}
catch (Exception ex)
catch (AppException ex)
{
Console.WriteLine($"Failed: {ex.Message}");
return -1;
}
catch (Exception ex)
{
Console.WriteLine($"Unexpected failure: {ex}");
return -1;
}
10 changes: 10 additions & 0 deletions src/Utils/AppException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System;

namespace BluetoothDevicePairing.Utils;

public sealed class AppException: ApplicationException
{
public AppException() { }

public AppException(string message): base(message) { }
}

0 comments on commit 65e1a73

Please sign in to comment.