Skip to content
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

macOS Support #6

Closed
Plutoberth opened this issue Aug 9, 2020 · 25 comments
Closed

macOS Support #6

Plutoberth opened this issue Aug 9, 2020 · 25 comments
Labels
enhancement New feature or request help wanted Extra attention is needed

Comments

@Plutoberth
Copy link
Owner

Plutoberth commented Aug 9, 2020

Please react to this issue if you want macOS support

@Plutoberth Plutoberth added the enhancement New feature or request label Aug 9, 2020
@Plutoberth Plutoberth changed the title OSX Support macOS Support Aug 15, 2020
@Plutoberth Plutoberth added the help wanted Extra attention is needed label Aug 15, 2020
@semvis123
Copy link
Contributor

Working on it 👍
(i don't have much experience in c++ but I will try to make it work)

@Plutoberth
Copy link
Owner Author

Working on it 👍
(i don't have much experience in c++ but I will try to make it work)

Awesome! I'm here if you have any questions about the code.

@semvis123
Copy link
Contributor

progress update - got the application compiling to .app with the demo ui, so I still need to make the ui implementation. The bluetooth connection seems a bit more challenging, see https://stackoverflow.com/a/59413196/9729726, looks like I can't easily send data using sockets. Any ideas?

@Plutoberth
Copy link
Owner Author

progress update - got the application compiling to .app with the demo ui, so I still need to make the ui implementation. The bluetooth connection seems a bit more challenging, see https://stackoverflow.com/a/59413196/9729726, looks like I can't easily send data using sockets. Any ideas?

My friend @Mr-M33533K5 worked on this for a bit, and IIRC he reached the conclusion that it's possible.

See:

https://developer.apple.com/library/archive/documentation/DeviceDrivers/Conceptual/Bluetooth/BT_Develop_BT_Apps/BT_Develop_BT_Apps.html

https://developer.apple.com/documentation/iobluetooth/iobluetoothrfcommchannel

https://developer.apple.com/documentation/iobluetooth

@semvis123
Copy link
Contributor

semvis123 commented Oct 27, 2020

progress update - I got the gui working I guess, can't really test it because it crashes on the bluetoothconnector, so the only thing to do is to make the bluetooth connector

@semvis123
Copy link
Contributor

semvis123 commented Oct 27, 2020

progress update there is some working bluetooth yay
image

@Plutoberth
Copy link
Owner Author

progress update there is some working bluetooth yay
image

Awesome! Should probably be pretty easy from here unless Apple's RFCOMM support is borked.

@semvis123
Copy link
Contributor

semvis123 commented Oct 28, 2020

image

I am not done yet, but need your help, on the bluetooth connector :) Please check out my pull request. You can build the project using the command `make` in the macOS directory in client

@Plutoberth
Copy link
Owner Author

image I am not done yet, but need your help, on the bluetooth connector :) Please check out my pull request. You can build the project using the command `make` in the macOS directory in client

I can't build the project because I don't have a Mac, and AFAIK setting up a mac VM is a pain. I do have some comments over the PR, but I'm pre-occupied with another task ATM so it might take me a week or so before I can dedicate some time for it.

@Miigon
Copy link

Miigon commented Nov 1, 2020

@semvis123
I've built your code on 10.14.6 and can successfully detect my WH-1000XM3.

When I click "connect", the following error message occurred: (It failed when calling openRFCOMMChannelSync().)

2020-11-02 01:49:14.884 sonyheadphonesclient[6904:148304] [establishKernelConnection] Received an error from IOServiceOpen() - 0xe00002c7.  NULLing out io_service_t.

IOServiceOpen() failed with error code 0xe00002c7, which according to apple documents, is kIOReturnUnsupported.
I am not familiar with macOS and the inner working of it, but it seems like this is an error regarding calling from user space to kernel space.

I am not entirely sure what happened, but in your code you set delegate to nil when opening a RFCOMM channel, but according to the document https://developer.apple.com/documentation/iobluetooth/iobluetoothdevice/1431606-openrfcommchannelsync?language=objc :

delegate
the object that will play the role of delegate for the channel. A channel delegate is the object the rfcomm uses as target for data and events. The developer will implement only the the methods he/she is interested in. A list of the possible methods is at the end of the file "IOBluetoothRFCOMMChannel.h" in the definition of the protocol IOBluetoothRFCOMMChannelDelegate.

It doesn't seem like using nil as delegate should really work.

	// create new channel
	IOBluetoothRFCOMMChannel *channel = [[IOBluetoothRFCOMMChannel alloc] init];
	if ([device openRFCOMMChannelSync: &channel withChannelID:1 delegate: nil] == kIOReturnSuccess) {
		const int connectResult = kIOReturnSuccess;
		printf("%d", connectResult);
		this->_connected = true;
	}

@semvis123
Copy link
Contributor

Hmmm, it should work though, I saw it in an old file, where it uses nil as delegate: source. I guess it's because the channel id is probably incorrect. But I don't know for sure. Note: saw most people use self for delegate but that didn't compile.

@Miigon
Copy link

Miigon commented Nov 2, 2020

@semvis123
I don't think channel id is likely the case though. IOServiceOpen is used when a user-space app wants to talk to a kernel-space service (in our case, the IOBluetoothDevice). And kIOReturnUnsupported is the default return value when a IOService method that is not implemented is called.

Here's the code of IOService: https://fergofrog.com/code/cbowser/xnu/iokit/IOKit/IOService.h.html
See the return value of callPlatformFunction()

@ result An IOReturn code; kIOReturnSuccess if the function was successfully executed, kIOReturnUnsupported if a service to execute the function could not be found.

So it seems like our app cannot talk to the kernel and bluetooth driver properly at all. (notice the original error message is during establishKernelConnection).

I've saw some apps that use these api and I've seem some complain about their app not working (same error IOServiceOpen() - 0xe00002c7) after upgrading to Sierra.

I would guess that apple changed the kernel in a way that breaks these super old apis? (bluetooth related functionalities is added to OSX back in 2002). Or apple just dropped the support deliberately. I don't know for sure.

Considering that Sony Headphones Connect has an iOS app, which surely uses RFCOMM as well, I'm sure that the kernel still supports it though. I might give Swift a try and see if things are different.

@Plutoberth
Copy link
Owner Author

@Miigon From what I read, RFCOMM is available on iOS only for companies that got approval from Apple (otherwise you only have GATT), and that it's available for everyone on macOS. Docs linked above seem to imply that this is the case. I know very little about macOS though, so take that with a grain of salt.

@semvis123
Copy link
Contributor

Found this on Github, but when it connects to the wh-1000-xm3 it gives an error which indicates that the device isn't an SPP/RFCOMM device. Is this correct or is this something Sierra(and up) related?

@Miigon
Copy link

Miigon commented Nov 3, 2020

@semvis123

Well, it expects the rfcomm device to be the first device that you Mac have connected to. But in my case my 1000xm3 is the second device(I know it from Xcode debugger).

I changed the code so that it will try to connect to my 1000xm3, instead of connecting to my mouse, which is the first device.

// line 75, MacosBT.mm
IOBluetoothDevice *device = [deviceArray objectAtIndex:1]; // objectAtIndex:0  ->  objectAtIndex:1

Another thing I changed is this line:

// line 78, MacosBT.mm  and  line 96, MacosBT.mm
IOBluetoothSDPUUID *sppServiceUUID = [IOBluetoothSDPUUID uuid16: kBluetoothSDPUUID16RFCOMM];
// uuid16: kBluetoothSDPUUID16ServiceClassSerialPort   ->  uuid16: kBluetoothSDPUUID16RFCOMM

The original code is looking for a ServiceClassSerialPort service, which the 1000xm3 doesn't have.
By changing it to look for kBluetoothSDPUUID16RFCOMM, it detects the RFCOMM service of the device successfully. (which means the Mac surely knows the 1000xm3 is a RFCOMM device)

After these changes, the program can run past the two "not SPP/RFCOMM device" checks and can actually get rfcommChannelID(btw, for me it's 0x10)

And guess what? openRFCOMMChannelSync() now actually returns kIOReturnSuccess!

Hello, Bluetooth RFcomm reception demo.
Attempting to connect
We have 4 paired device(s).
device name = WH-1000XM3
Successfully connected

No NULLing, no nothing. it just connects!

I suspect that the channelID is the cause of problem, so I put withChannelID: 0x10 to your code(MacOSBluetoothConnector.mm).

Sure enough, it connects.

screenshot

So a channelID of 0x10 works, but I think it would still be a good idea to use getRFCOMMChannelID() to get the correct channelID dynamically.

@semvis123
Copy link
Contributor

semvis123 commented Nov 3, 2020

Wow that's some good information!
I adjusted my fork and pull request, now it chooses the channelID dynamically, and thus successfully connects.

The next step is to make the opened channel globally accessible, so it can be accessed in the other functions (like disconnect).

Note: the headphones can currently only connect once because it probably doesn't disconnect (if you turn the headphones off and back on it will work again).

@semvis123
Copy link
Contributor

semvis123 commented Nov 4, 2020

Got some work done! The connection works and disconnect works kinda, when the channel is closed it cannot be opened again (currently solved by disconnecting from the device).

Send data and receive data are now also correctly structured, send command doesn't work though ( do I need to use the byte magic file? or is this maybe cause the function doesn't return anything? or another possibility, is this because of the receive function not working?), receive always prints null (string conversion error maybe?).

pull request and fork have been updated

  • working channel
  • correct file structure
  • working send function
  • working receive function
  • reopening channel without disconnecting

@Plutoberth
Copy link
Owner Author

@semvis123, The recv function has to work since the protocol has some synchronization built in, and that requires our side to receive some data. I'll take a look at everything on Monday.

@Miigon
Copy link

Miigon commented Nov 17, 2020

how's everything going buddies?

@semvis123
Copy link
Contributor

semvis123 commented Nov 17, 2020

@Miigon Some progress has been made!
The receive function has still a few problems, and there are some problems rewriting the bleutooth connector to not use an extra (probably unneeded) thread.

Check my pull request for the most up to date information.

@semvis123
Copy link
Contributor

Currently fully working 🎉

@Plutoberth
Copy link
Owner Author

@Miigon Could you test the new version please?

@Miigon
Copy link

Miigon commented Jan 17, 2021

@Plutoberth Sure, I've done testing it. It isn't quite working yet. I've detailed everything in the pull request comment.

@Plutoberth
Copy link
Owner Author

@Miigon thanks!

@Plutoberth
Copy link
Owner Author

Forgot to close this :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

3 participants