UWP: BluetoothDevice.FromBluetoothAddressAsync throws 0x80070002 exception on non-discoverable & unpaired BT device - c#

I'm trying to pair from a Universal Windows C# app to a Bluetooth - Serial converter, without user interaction.
Development is in Visual Studio 2015 under Windows 10 Pro, but app is intended to run in any Windows 10 based device with a Bluetooth adapter.
For security reasons, BT-serial converter isn't discoverable and is protected by a pin, so I'm not able to perform any enumeration procedure to detect and pair it.
My application only knows BT address (MAC) and PIN's device (Also it knows friendly Bluetooth name, but I never used it).
Previously I'd been able to perform this task under Windows Mobile 6 Pocket PC, using Windows Mobile SDK and C++, but unfortunately code isn't portable to Universal Windows Platform.
Playing with MS samples for Universal Windows(https://github.com/Microsoft/Windows-universal-samples) I achieved to write a code that achieves to pair device, creating from strings some objects that in source sample are derived from enumeration process.
But it only works if device is visible. This is the code:
using System;
using Windows.UI.Xaml.Controls;
using Windows.Networking;
using Windows.Devices.Enumeration;
using Windows.Devices.Bluetooth;
// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409
namespace UWPBTTest
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
DoPairing();
}
async public void DoPairing()
{
UInt64 targetMAC = 32217180653; //target MAC in decimal, this number corresponds to my device (00:07:80:4b:29:ed)
BluetoothDevice btDev = await BluetoothDevice.FromBluetoothAddressAsync(targetMAC); //We create target BT device object, here app throws 0x80070002 exception
DeviceInformation infDev = btDev.DeviceInformation; //We need this aux object to perform pairing
DevicePairingKinds ceremoniesSelected = DevicePairingKinds.ConfirmOnly | DevicePairingKinds.ProvidePin; //Only confirm pairing, we'll provide PIN from app
DevicePairingProtectionLevel protectionLevel = Windows.Devices.Enumeration.DevicePairingProtectionLevel.Encryption; //Encrypted connection
DeviceInformationCustomPairing customPairing = infDev.Pairing.Custom; //Our app takes control of pairing, not OS
customPairing.PairingRequested += PairingRequestedHandler; //Our pairing request handler
DevicePairingResult result = await customPairing.PairAsync(ceremoniesSelected, protectionLevel); //launc pairing
customPairing.PairingRequested -= PairingRequestedHandler;
if ((result.Status == DevicePairingResultStatus.Paired) || (result.Status == DevicePairingResultStatus.AlreadyPaired))
{
//success, now we are able to open a socket
}
else
{
//pairing failed
}
}
//Adapted from https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/DeviceEnumerationAndPairing , scenario 9
private async void PairingRequestedHandler(
DeviceInformationCustomPairing sender,
DevicePairingRequestedEventArgs args)
{
switch (args.PairingKind)
{
case DevicePairingKinds.ConfirmOnly:
// Windows itself will pop the confirmation dialog as part of "consent" if this is running on Desktop or Mobile
// If this is an App for 'Windows IoT Core' where there is no Windows Consent UX, you may want to provide your own confirmation.
args.Accept();
break;
case DevicePairingKinds.ProvidePin:
// As function must be asyn, we simulate a delay of 1 second on GetPinAsync
var collectPinDeferral = args.GetDeferral();
string pin = "1234"; //BT converter pin, currently is "1234" for testing purposes
args.Accept(pin);
collectPinDeferral.Complete();
break;
}
}
}
}
This prototype app uses a blank form, as all data are hardcoded.
Also in Package.appxmanifest -> Capabilities, I checked all fields to discard any permission lack.
Currently this code only can perform pairing operation if BT-serial converter is visible.
If BT device isn't visible, BluetoothDevice.FromBluetoothAddressAsync throws an exception (Resource not found: 0x80070002), instead of creating the BluetoothDevice object.
Is as if Windows "needed" to know something of BT device in order to perform operation, I suspect that when I call FromBluetoothAddressAsync, OS internally lists all devices in system (this includes detected BT devices in range) looking for and item with given address.
I've been looking for other methods to perform mac-based pairing against hidden bt devices, but without success (maybe some type of "pre-pairing"? I didn't find anything)
Thanks.

Related

using an Audio Endpoint other than 'DefaultAudioEndpoint' in C#

This program is an audio visualizer for an rgb keyboard that listens to windows' default audio device. My audio setup is a bit more involved, and I use way more than just the default audio device. For instance, when I play music from Winamp it goes through the device Auxillary 1 (Synchronous Audio Router) instead of Desktop Input (Synchronous Audio Router) which I have set as Default. I'd like to be able change the device that the program listens to for the visualization.
I found in the source where the audio device is declared; Lines 32-36 in CSCoreAudioInput.cs:
public void Initialize()
{
MMDevice captureDevice = MMDeviceEnumerator.DefaultAudioEndpoint(DataFlow.Render, Role.Console);
WaveFormat deviceFormat = captureDevice.DeviceFormat;
_audioEndpointVolume = AudioEndpointVolume.FromDevice(captureDevice);
}
The way that I understand it from the documentation, the section MMDeviceEnumerator.DefaultAudioEndpoint(DataFlow.Render, Role.Console) is where Windows gives the application my default IMMEndpoint "Desktop Input."
How would I go about changing DefaultAudioEndpoint?
Further Reading shows a few ways to get an IMMDevice, with DefaultAudioEnpoint being one of them. It seems to me that I'd have to enumerate the devices, and then separate out Auxillary 1 (Synchronous Audio Router) using PKEY_Device_FriendlyName. That's a bit much for me, as I have little to no C# experience. Is there an easier way to go about choosing a different endpoint? Am I on the right track? or am I missing the mark completely?
Also, what is the difference between MMDevice and IMMDevice? The source only seems to use MMDevice while all the Microsoft documentation references IMMDevice.
Thanks.
I DID IT!
I've found why the program uses MMDevice rather than IMMDevice. The developer has chosen to use the CSCore Library rather than Windows' own Core Audio API.
From continued reading of the CSCore MMDeviceEnumerator Documentation, it looks like I'll have to make a separate program that outputs all endpoints and their respective Endpoint ID Strings. Then I can substitute the DefaultAudioEndpoint method with the GetDevice(String id) method, where String id is the ID of whichever Endpoint I chose from the separate program.
To find the the Endpoint I wanted, I wrote this short program to find all the info I wanted:
static void Main(string[] args)
{
MMDeviceEnumerator enumerator = new MMDeviceEnumerator();
MMDeviceCollection collection = enumerator.EnumAudioEndpoints(DataFlow.Render,DeviceState.Active);
Console.WriteLine($"\nNumber of active Devices: {collection.GetCount()}");
int i = 0;
foreach (MMDevice device in collection){
Console.WriteLine($"\n{i} Friendly name: {device.FriendlyName}");
Console.WriteLine($"Endpoint ID: {device.DeviceID}");
i++;
}
Console.ReadKey();
}
This showed me that the Endpoint I wanted was item number 3 (2 in an array) on my list, and instead of using GetDevice(String id) I used ItemAt(int deviceIndex).
MMDeviceEnumerator enumerator = new MMDeviceEnumerator();
MMDeviceCollection collection = enumerator.EnumAudioEndpoints(DataFlow.Render,DeviceState.Active);
MMDevice captureDevice = collection.ItemAt(2);
However in this case, the program was not using captureDevice to bring in the audio data. These were the magic lines:
_capture = new WasapiLoopbackCapture(100, new WaveFormat(deviceFormat.SampleRate, deviceFormat.BitsPerSample, i));
_capture.Initialize();
I found that WasapiLoopbackCapture uses Windows' default device unless changed, and the code was using DefaultAudioEndpoint to get the properties of the default device. So I added
_capture.Device = captureDevice;
//before
_capture.Initialize();
And now the program properly pulls the audio data off of my non-default audio endpoint.
I had been asked to solve a similar type of problem this week. Although there are a few librarys to do this I was specifically asked to do this for "non ish" programmers so I developed this in PowerShell.
Powershell default audio device changer - Github
Maybe you can alter it to your needs.

Detect barcode scanner with PointOfService on Windows 10

I would like to use a barcode scanner with Windows 10 (Build 15063) via the Windows.Devices.PointOfService namespace. The scanner is a Datalogic Quickscan QD2430 and I tried with all RS-232 and Keyboard mode.
I used the official sample application https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/BarcodeScanner with no luck. It can detect a device but it's definitely the in-built webcam (HP laptop).
I tried to modify the source, the DeviceHelpers's GetFirstDeviceAsync function https://github.com/Microsoft/Windows-universal-samples/blob/master/SharedContent/cs/DeviceHelpers.cs.
The DeviceInformation.FindAllAsync also returns only the camera's info as result.
string selector = BarcodeScanner.GetDeviceSelector(PosConnectionTypes.All);
DeviceInformation.FindAllAsync(selector);
It returns nothing.
DeviceInformation.FindAllAsync(DeviceClass.ImageScanner);
It returns every connected and I think the previously connected but currently offline devices too. I tried to filter the scanner by name. There was a lot filterd result too, but the convertAsync function returned null for all excepts one, it thrown an Exception "A device attached to the system is not functioning. (Exception from HRESULT: 0x8007001F)".
DeviceInformationCollection infos = await DeviceInformation.FindAllAsync(DeviceClass.All);
foreach(DeviceInformation info in infos)
{
if (info.Name.ToUpper().Contains("BARCODE"))
{
T scanner = await convertAsync(info.Id);
if (scanner != null)
{
return scanner;
}
}
}
Datalogic Quickscan QD2430 is not in the list of devices supported by Windows.Devices.PointOfService.
Ask Datalogic to provide a device driver that supports Windows.Devices.PointOfService, or change the scanner to the one described in the supported list.
Alternatively, create your own device driver according to the Point of Service (POS) of Windows Driver Kit.

Finding paired Bluetooth device if its in range using 32Feet

I'm trying to make a simple application that will show the nearby Bluetooth devices (this one works fine)
Also I'm trying to find if the specific Bluetooth device (I have its MAC & Its already paired in windows) is in range. It's an android phone and by default its set to Invisible to nearby devices, But that wouldn't be a problem since it's already paired in windows, right?
Am using this code:
BluetoothClient BTClient = new BluetoothClient();
BluetoothDeviceInfo[] BTDeviceInfo = BTClient.DiscoverDevices();
which is working find for finding "Visible Devices", It will also show me Paired device weather its In-Range or Not!
How i can check if that paired devices is in-range? Without going to setting and make it "Visible" will be much better
It might be too late, but you can use BTClient.DiscoverDevicesInRange();
and look for your device in that list.
Another method would be to try reading the services in the device using its bluetooth address, you will get an exception if it isn't in range.
private static Boolean IsInRange(BluetoothDeviceInfo device)
{
Guid fakeUuid = new Guid("{F13F471D-47CB-41d6-9609-BAD0690BF891}");
try
{
ServiceRecord[] records = device.GetServiceRecords(fakeUuid);
return true;
}
catch(SocketException ex)
{
if (ex.ErrorCode == 10040) return true;
return false;
}
}

USB device not valid in MonoLibUsb

I'm trying to open a USB device handle in MonoLibUsb (on Linux), but every time I open it I get IsInvalid == true on the device handle.
The USB device is definitely compatible with LibUsb as I've connected it to my Windows PC and can successfully use LibUsbDotNet to talk to it. If I try to use LibUsbDotNet in Mono the application hangs when trying to open it, so I figured LibUsbDotNet is for Windows and MonoLibUsb is for Mono (the name kind of gives it away). However, even MonoLibUsb fails to properly use the device.
So why is the device handle returned invalid?
Code
private void UsbInit() {
var sessionHandle = new MonoUsbSessionHandle();
var profileList = new MonoUsbProfileList();
profileList.Refresh(sessionHandle);
List<MonoUsbProfile> usbList = profileList.GetList().FindAll(MyVidPidPredicate);
foreach(MonoUsbProfile profile in usbList) {
var deviceHandle = profile.OpenDeviceHandle();
if (deviceHandle.IsInvalid) {
Console.WriteLine(string.Format("IsInvalid: {0} - {1}", MonoUsbSessionHandle.LastErrorCode, MonoUsbSessionHandle.LastErrorString));
}
}
}
private bool MyVidPidPredicate(MonoUsbProfile profile) {
if (profile.DeviceDescriptor.VendorID == 0xabcd && profile.DeviceDescriptor.ProductID == 0x1234)
return true;
return false;
}
Output
IsInvalid: Success -
This line in the documentation is very easy to overlook:
The user must have appropriate access permissions to the usb device before it can be used with linux.
If I'm starting the application as root (or through sudo) the device handle becomes valid.

How to use Core Audio API Master Volume Control with a friendly name?

I am using this code provided here.
http://www.codeproject.com/Articles/18520/Vista-Core-Audio-API-Master-Volume-Control
I am trying to control the volume of my application and 1 additional process that my application starts. Is there a way to use this code above as per application instead of master?
Here is the code in the form
MMDeviceEnumerator DevEnum = new MMDeviceEnumerator();
device = DevEnum.GetDefaultAudioEndpoint(EDataFlow.eRender, ERole.eMultimedia);
beiVolumControl.EditValue = (int)(device.AudioEndpointVolume.MasterVolumeLevelScalar * 100);
By comments listed there is a way to pick the device using a friendly name but I don't see any examples listed anywhere.
Here is the code used when my volume slider changes
//change the Volume
void ritbVolumeControl_EditValueChanged(object sender, EventArgs e)
{
TrackBarControl trackBar = sender as TrackBarControl;
//only use in vista or above.
if (useAlternateSound == false)
{
device.AudioEndpointVolume.MasterVolumeLevelScalar = ((float)trackBar.Value / 100.0f);
}
else
{
//probably using xp or lower.
}
// MessageBox.Show(trackBar.Value.ToString());
}
The End Goal is to Control my Application and one other process's volume if it's possible without controlling the master volume of all applications. So I can mute them and still use skype voice chat for an example. Am I going about this the wrong way?
Thanks.

Categories

Resources