androidarraysexternalbulkandroid-usb

USB host bulkTransfer returns valid amount of data but I don't get anything back


I have an external camera that's connected via a USB C dongle to my Android tablet. My goal is to have a constant stream of data from the camera into my phone, showing it to the user and allowing him to record it and save it to the local storage.

I am following the official docs from the following link - https://developer.android.com/guide/topics/connectivity/usb/host#working-d

And I have spent the last couple of hours trying to figure out how things work, mapping the interfaces and endpoints, eventually finding an interface that has an endpoint that when I call bulkTransfer() on, does not return a failed value (-1).

I currently am facing 2 issues:

  1. I have indeed got a valid response from the bulkTransfer() function, but my ByteArray does not fill with relevant information - when trying to print out the values they are all 0's. I though it may be a wrong endpoint as suggested in the official docs, but I have tried all combinations of interfaces and endpoints until I get an indexOutOfBoundException. That combination of interface + endpoint that I used is the only one that produced a valid bulk response. What am I missing?

  2. I am looking for a stream of data that doesn't stop, but it seems like when calling bulkTransfer() it's one a one time oppression, unlike CameraX library for example that I get a constant callback each time a new chunck of data is available.

Here is the code on my main screen -

 LaunchedEffect(key1 = true) {
        val usbManager = context.getSystemService(Context.USB_SERVICE) as UsbManager
        val filter = IntentFilter(ACTION_USB_PERMISSION)
        registerReceiver(context, UsbBroadcastReceiver(), filter, RECEIVER_NOT_EXPORTED)
        val hdCamera = usbManager.deviceList.values.find { device ->
            val name = device.productName ?: return@LaunchedEffect
            name.contains("HD camera")
        } ?: return@LaunchedEffect
        val permissionIntent = PendingIntent.getBroadcast(
            context,
            0, Intent(ACTION_USB_PERMISSION),
            0
        )
        usbManager.requestPermission(hdCamera, permissionIntent)
    }

And here is my BroadcastReceiver -

override fun onReceive(context: Context?, intent: Intent?) {
        if (intent?.action != ACTION_USB_PERMISSION) return
        synchronized(this) {
            val usbManager = context?.getSystemService(Context.USB_SERVICE) as UsbManager
            val device: UsbDevice? = intent.getParcelable(UsbManager.EXTRA_DEVICE)

            val usbInterface = device?.getInterface(0)
            val endpoint = usbInterface?.getEndpoint(1) ?: return@synchronized
            usbManager.openDevice(device)?.apply {
                val array = ByteArray(endpoint.maxPacketSize)
                claimInterface(usbInterface, true)
                val bulkTransfer = bulkTransfer(endpoint, array, array.size, 0)
                Log.d("defaultAppDebuger", "bulk array: $bulkTransfer") //prints a valid number - 512
                array.forEach {
                    Log.d("defaultAppDebuger", "bulk array: $it") //the array values are empty
                }
            }
        }
    }

edit: I have tried to move the BroadcastReceiver code to an async coroutine thinking that the loading of the information is related to the fact that I am in the wrong thread. Still didn't work, I get a valid result from the bulkTransfer and the byteArray is not filled -

fun BroadcastReceiver.goAsync(
    context: CoroutineContext = Dispatchers.IO,
    block: suspend CoroutineScope.() -> Unit
) {
    val pendingResult = goAsync()
    CoroutineScope(SupervisorJob()).launch(context) {
        try {
            block()
        } finally {
            pendingResult.finish()
        }
    }
}

 override fun onReceive(context: Context?, intent: Intent?) = goAsync { .... }

Thanks!


Solution

  • After carefully researching I was not able to get an answer and ditched that mini project that I worked on. I followed this comment on the following thread -

    https://stackoverflow.com/a/68120774/8943516

    That, combined with a 2.5 days of deep researched of both USB Host protocol which was not able to connect to my camera and Camera2API which couldn't recognize my external camera brought me to a dead end.