New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
BluetoothEndPoint does not contain a constructor that takes 2 arguments #75
Comments
In the current release the BluetoothEndPoint is not emphasised as the BluetoothClient.Connect(address, service) provides a simpler approach for cross platform use. I'm looking at reintroducing BluetoothEndPoint as a supported alternative but will have to assess how it will be implemented on platform APIs which are not Socket oriented. |
What I am missing from |
Specifying a port number may be useful, especially for reconnecting to a previously used device but using the service uuid will ensure you're using the correct port for an exposed service. If you can't connect using the Headset profile it may be because the device is already connected or that it uses the Handsfree profile instead. |
Ok, so using the guid exposed by the device on In my case I am able to connect to the device with This is my code:
I am trying to use the RFCOMM service in order to get the battery information from the device (Headset with Bluetooth 4.1) by sending AT commands, similar to what they do in the following python code: https://github.com/TheWeirdDev/Bluetooth_Headset_Battery_Level/blob/master/bluetooth_battery.py |
I have logged the bluetooth communications between and Android device (that can get the battery value from the headset) and the headset. I have opened with WIreShark and it seems that AT commands that inform about the battery are not sent trough RFCOMM protocol, they are sent trough HFP protocol. How can I use the HFP protocol to send/get AT commands with this library? |
Handsfree Profile runs over an RFComm connection. All of it's control commands/responses are text based AT commands. To connect to a handsfree device you open an RFComm socket to the BluetoothService.Handsfree service uuid. There is a set of required commands which the handsfree device will send to the phone (Audio Gateway) and you must respond to before you can get indicator values. Both Handsfree and Headset are RFComm based but Handsfree has a lot more functionality and has been updated more recently. You may find however that if the handsfree device is connected and active on the Android device you can't open another connection as the handsfree device may only support a single device at once. |
Thanks @peterfoot for your support! I have extracted the bluetooth log from my Android phone (which is able to get the battery level) to be sure that the headset is using HFP to send AT command with the battery information (AT+IPHONEACCEV), this is one of the packets extracted from the log (with wireshark):
And this is the code I am using to get this AT commands from the headset in my Windows C# application using the 32feet (InTheHand.Net.Bluetooth) library. To do so I try to connect to the headset using
When executing the code it gives the following error in
With |
The headset is definitely paired to the PC? You could try checking the BluetoothDeviceInfo InstalledServices array for the Handsfree uuid but this only returns services which Windows knows about and so on older versions of Windows this won't include Handsfree. Secondly the command you are using is an Apple specific extension to the Handsfree service so while it will work on many newer devices it's not universally supported. Also you should not simply connect and send this command - there is an expected sequence of commands and responses when the handsfree device and audio gateway (your PC in this case) go through when first connected. This allows both sides to negotiate supported features. Then not only can you get indicator values but also receive notifications when these change. You'll have to refer to the HFP spec which has a flowchart describing this. |
I am testing on Windows 10 and the Headset is definitely paired and connected before executing my code (i do not know if this is the right way to proceed, as the headset is already connected and I connect again from my code, anyway I tried also to disconnect it from Windows and then execute my code, but I get the same results) I tried to connect using each one of the 5 InstalledServices I can get from device:
The only one that is connecting is the first one: But still I cannot get any commands from the device when I execute:
The execution gets stuck in
The IPHONEACCEV command is sent from the headset to de Android smartphone. Yes you are right that I need to send some AT commands before in order configure the communciation, but I least I expected to receive any command once I connect to the Headset, but as you can see in my code, the I also tried to send an AT command ("\r\nAT + BRSF = 20\r\n") to the headset just after connecting and before the |
Check the IsConnected property of the BluetoothDeviceInfo returned from your picker. If Windows is connected to the Handsfree you won't also be able to connect to the service. There isn't a documented API to get the battery level in this case but clearly the value is there as Windows 10 surfaces it through the Settings > Devices page. |
Yes, Thanks! |
Ok, I have made some progress (thanks to you :) ) If I call The only thing here is that when I call this |
They sometimes support multiple devices but it's unlikely to support multiple connections from the same device. If you need to take a snapshot you could disable the service, connect and retrieve the battery and then disconnect and re-enable the windows service. I'm trying to find if there is another API which will expose the handsfree battery when it is connected to Windows... |
So the process now is as follows:
The only issue I am facing now is that when i reconnect the headset to windows with |
Hello to everybody, If the code is executed without audio (the headset is paired but in standby), then i can use correctly HFP on pc withpout problem. At this point is possible according to your opinion know if:
Thanks |
Hi Guys, I know I am late but I tried and it is indeed possible to get the battery level using only UWP and WinRT APIs in C# Thanks guys, a lot of your comments helped me to understand how the communication happens. |
Thanks Spartan for the info, but a lot of time ago i have discovered a similar way. But the code that you have posted need a little bit modification in order to work with the JBL400BT headphone, is necessary responde to the AT commands setting new value in order to have as final sequential the IPHONEACCEV value. |
Hey @sturla78 you're right, method could be different for JBL, but I haven't tested it. In my case both Sony and Firebolt headphones worked with just sending an "OK" to whatever was incoming until I got the IPHONEACCEV |
I am trying to get battery level from headset too, glad i've found this thread. I tried both 32feet api and approach based on @SpartanX1 code with winrt apis, both have requirement that device must be disconnected prior to establishing socket connection. Ok, but we send/read AT commands, at the same time in Windows Settings, headset becomes "connected" and battery level also gets displayed there! So windows surely does something else: our manual socket connection does not prevent it from reading battery level. Maybe it shares existing socket? I tried looking at BluetoothClient and StreamSocket and don't see any way to modify socket options (if there are any at all). Also there's a closed source app called "bluetoothgoodies" that claims to "just work"... i am even thinking that any sniffer will do (driver level?) since reading battery state is a read-only operation. is there any simple way to tap into windows bluetooth stack? or maybe even usb... |
I also have a similar problem. Is there any official example code for your reference? It has been bothering me for several days, thank you |
@Rast1234 May be Windows uses cached data? I did not try to wait while battery information changed. If you turn off all services:
It does not matter to which service to connect. UPD: |
App from |
@steam3d that's exactly why i think it could be possible to work with the socket at a lower level, but no idea how. idk about caching, but windows UI sometimes shows out-of-date battery level after my device is disconnected so yeah, maybe it has an internal cache |
@Rast1234 Or Windows use HID device to collect battery information. Windows is mapped Bluetooth headphones also as a HID device that I suppose control the headphone buttons. HID device can provide battery information or at least event when battery is low. https://www.bluetooth.com/specifications/specs/human-interface-device-profile-1-1-1/
We connect to RFcomm service, that lays on top of L2CAP. https://www.bluetooth.com/specifications/specs/human-interface-device-profile-1-1-1/
So Window can just operate of data on L2CAP layer and because of it does not have any trouble to get Battery information even if socket is busy. Anyway I tried to find HID device to get more info but without success |
Well I made lot of test what I figure out:
|
Hi, |
If Windows is connected to the Handsfree service then you won't be able to open a socket - and vice-versa - Windows won't get battery updates if you've disconnected and connected to the service yourself. If only the Windows cached value was accessible we'd be able to read this without interfering with the connection. |
@peterfoot Do you have any idea where Windows can storage cached value? I checked everything from devices properties to regedit.exe. Maybe I something miss |
Hi there. I have a problem with the subject of this thread. Guess someone could help me. I want to get the battery level of Bluetooth headphones via Handsfree service. I have two devices for tests: AirPods and Logitech G735. Windows can get battery level only for Airpods. And MacOS only for Logitech. This is strange to me but also we know that we can get battery levels for both devices. So I'm using this code but getting only one AT Command in response AT+BRSF=671 for AirPods and AT+BRSF=147 for Logitech. What am I doing wrong? I really appreciate any help you can provide. private static async Task<byte> GetBatteryLevelAsync(Headphones headphones)
{
return await Task.Run(() =>
{
using (var bluetoothClient = new BluetoothClient())
{
var device = bluetoothClient.PairedDevices.FirstOrDefault(d => d.DeviceName == headphones.Name);
if (device != null)
{
device.SetServiceState(BluetoothService.Handsfree, false);
bluetoothClient.Connect(device.DeviceAddress, BluetoothService.Handsfree);
var stream = bluetoothClient.GetStream();
if (stream != null && stream.CanRead && stream.CanWrite)
{
while (true)
{
if (!stream.DataAvailable)
{
break;
}
byte[] responseBytes = new byte[1024];
int bytesRead = stream.Read(responseBytes, 0, responseBytes.Length);
string response = Encoding.ASCII.GetString(responseBytes, 0, bytesRead);
byte[] commandBytes = Encoding.ASCII.GetBytes(response);
stream.Write(commandBytes, 0, commandBytes.Length);
}
}
if (bluetoothClient.Connected)
{
bluetoothClient.Close();
}
device.SetServiceState(BluetoothService.Handsfree, true);
}
}
return Task.FromResult((byte)1);
});
} |
@m1adow What did you mean windows can get? Your code does nothing or what? What does the output console say? |
I mean that in the Windows Settings app in the Bluetooth & Devices section, I can see headphones and their battery level. |
@m1adow I suppose mac can't get battery because it is Fake AirPods. |
@steam3d Hello again! I successfully managed to get the battery from the code thanks to you. But for some reason between checking data availability from the stream, I need to add a small delay. If I run code without delay then in Output I will get "false". Is there a workaround to avoid this? while (true)
{
await Task.Delay(50); // how to avoid waiting for data?
Debug.WriteLine(stream.DataAvailable);
if (!stream.DataAvailable)
{
break;
}
byte[] buffer = new byte[1024];
int bytesRead = await stream.ReadAsync(buffer);
string receivedData = Encoding.ASCII.GetString(buffer, 0, bytesRead);
recievedResponse.Append(receivedData);
Debug.WriteLine(receivedData);
await stream.WriteAsync(responseBytes);
} |
@m1adow Check Microsoft Rfcomm example on their GitHub. You do not need use while(true). https://github.com/microsoft/Windows-universal-samples/tree/main/Samples/BluetoothRfcommChat You also need to know that enable and disable SetServiceState is incredible complicated task for windows. Windows will destroy audio endpoint and then create a new one (include a lot of GUID and other data), some app that use headset could stuck. |
On version 4.0.4 when I code the following line in a Visual Studio 2017 .NET Framework 4.6.1 Windows Forms application:
BluetoothEndPoint blep = new BluetoothEndPoint(BluetoothAddress.Parse("001122334455"), BluetoothService.SerialPort);
I get the error "BluetoothEndPoint does not contain a constructor that takes 2 arguments"
As per the documentation BluetoothEndPoint has constructor that takes 2 or 3 arguments.
Note: I am using 4.0.4 version because 4.0.5 nuget package fails to install as per #74
Thanks!
The text was updated successfully, but these errors were encountered: