IntelRealSense / librealsense

Intel® RealSense™ SDK
https://www.intelrealsense.com/
Apache License 2.0
7.55k stars 4.81k forks source link

How to get librealsense to recognise D415 on unrooted Android #13003

Closed psygn0me closed 3 months ago

psygn0me commented 3 months ago

Hi,

I am trying to repurpose an old mobile Android device running Android 7.1.1 (SDK API 21) by connecting it to an Intel RealSense D415. I was not able to build the librealsense.aar (Gradle was giving Java related errors), but I was successfully able to compile the latest arm64-v8a version of librealsense.so via the Android cmake toolchain (Release build, RS2_USE_ANDROID_BACKEND flags) in the Android wrapper folder.

I am aware that I would need the aar to get USB permission from Android to use the D415 however I am using a custom libusb library that is able to request and access USB devices on Android from only C code (without having a JNI bridge where Java Activities call C code). For my intents and purposes I rather not go this route as this would make my code less portable to other platforms.

Using this custom libusb library returns a file descriptor (fd) which indicates that I was able to detect and gain permission to the D415 USB device. How can I pass this fd to librealsense to let it know it has access to the device? I imported all the necessary header files from the include/ folder however I was not able to find a function that would recognize the device based on a valid fd that was enumerated and opened by another library in the same application. For example after receiving an fd, calling:

rs2::context ctx; int num = ctx.query_devices().size();

Returns 0 (No devices found).

Am I missing a call similar to Java RsContext(init)? What is the C function equivalent?

Please if anyone can shed some light on this matter it would be greatly appreciated. Until then, I will keep scouring the source code. Thanks.

MartyG-RealSense commented 3 months ago

Hi @psygn0me If you are installing librealsense only for this old phone in particular and do not want to use AAR to obtain USB permissions then you could consider using the current RealSense Android wrapper's predecessor, as this old wrapper obtained access permissions via rooting the device instead.

https://dev.intelrealsense.com/docs/android-for-rooted-devices

psygn0me commented 3 months ago

Hi @MartyG-RealSense,

The device has a locked bootloader so I can't root it unfortunately.

From the link you posted, it states:

Disclaimer: There is a limitation in access to the camera from a native code due to Android USB permissions policy. Therefore, building Intel® RealSense™ SDK 2.0 for Android devices will run only on rooted devices.

Just curious, how is this permission policy different from the one obtained on an unrooted Android device using Java Activity classes? As mentioned earlier I am using a custom libusb library that can request and open USB connections on Android without Java Activities. Is this different?

Digging a bit into the USB backend, there is a 'usbhost.h' file that I can import into my project and call the function with the fd I obtained earlier:

struct usb_device* dev = usb_device_new("D415", fd);

With this device handle, I can query for vendor id, product id, name, etc. But I just don't know how to propagate this info up the chain to the frontend. How can I hook into the context so that it can detect the device and start the streams? I feel like there is a callback I'm missing or maybe I have to derive a class.

So far I tried: auto h = std::make_shared < librealsense::platform::usb_device_usbhost > (dev);

librealsense::platform::device_watcher_usbhost::instance()->notify();

Am I going about this the right way?

Thanks for your time.

MartyG-RealSense commented 3 months ago

My Android wrapper knowledge is limited and so I do not have advice that I can provide about the Android USB permissions policy or usbhost.h, unfortunately. The only RealSense support case to previously mention usbhost.h is one at https://github.com/IntelRealSense/librealsense/issues/5681#issuecomment-635387986 where a RealSense user used it to query the Android version.

In general though, access permissions should not be needed if a program is run in sudo admin powers mode. My understanding is that Android does not have sudo permissions, but the link below suggests that sudo power on Android can be obtained by installing a terminal emulator called Termux onto the device.

https://www.quora.com/How-can-I-run-an-app-with-sudo-without-rooting-in-Android

psygn0me commented 3 months ago

Hi @MartyG-RealSense,

I managed to figure out why I wasn't able to get my unrootable Android device to interface with librealsense. No reason not to use the existing aar object to request USB permission, but for my unlikely use case of handling the permission myself, the solution was simply to change the add and remove methods in "enumerator-usbhost.cpp" from JNI C to just plain C code, thereby bypassing any Java code. Calling, for example:

usb_enumerator::add_usb_device(dev_name, fd);

Would add the device of type usb_device to the global _devices array and get the rs2::context to find the device. Pretty sure I can also start a stream but I need to create a window first to visualize the data, which I'll do later...

Maybe this is better off in another discussion but the D415 is showing as Usb Type 2.1, I am not using the official cable but I tried a few others to no avail. I'll try a few things before I buy yet another usb cable, like updating the firmware (currently 5.11.1.100).

Anyways thanks for your help, this can be closed now.

MartyG-RealSense commented 3 months ago

It's great to hear that you achieved a solution. Thanks very much for the update and for sharing the solution. As you suggested, I will close this case. Thanks again!