joelpurra / uvcc

USB Video Class (UVC) device configurator. Used for webcams, camcorders, etcetera. Command line interface for automation.
https://joelpurra.com/projects/uvcc/
GNU General Public License v3.0
98 stars 5 forks source link

TypeError: Cannot read properties of undefined (reading 'descriptor') #23

Open wookayin opened 2 years ago

wookayin commented 2 years ago

Version:

❯❯❯ uvcc --version         
v5.0.2
❯❯❯ node --version
v17.3.0

(Note: M1 mac, arm64)

Error:

$ uvcc controls

WrappedError: Could create uvc-control object: {} ("TypeError: Cannot read properties of undefined (reading 'descriptor')")
    at CameraFactory.createWrappedError (file:///opt/homebrew/lib/node_modules/uvcc/dist/camera-factory.js:90:30)
    at CameraFactory.get (file:///opt/homebrew/lib/node_modules/uvcc/dist/camera-factory.js:74:43)
    at CommandManager.execute (file:///opt/homebrew/lib/node_modules/uvcc/dist/command-manager.js:73:47)
    at async mainAsync (file:///opt/homebrew/lib/node_modules/uvcc/dist/index.js:73:9) {
  innerError: TypeError: Cannot read properties of undefined (reading 'descriptor')
      at getInterfaceDescriptors (/opt/homebrew/lib/node_modules/uvcc/node_modules/uvc-control/index.js:375:26)
      at UVCControl.init (/opt/homebrew/lib/node_modules/uvcc/node_modules/uvc-control/index.js:85:25)
      at new UVCControl (/opt/homebrew/lib/node_modules/uvcc/node_modules/uvc-control/index.js:22:10)
      at CameraFactory.get (file:///opt/homebrew/lib/node_modules/uvcc/dist/camera-factory.js:54:28)
      at CommandManager.execute (file:///opt/homebrew/lib/node_modules/uvcc/dist/command-manager.js:73:47)
      at async mainAsync (file:///opt/homebrew/lib/node_modules/uvcc/dist/index.js:73:9)
wookayin commented 2 years ago

This is because in uvc-control/index.js

362 function getInterfaceDescriptors(device) {
363   // find the VC interface                                   
364   // VC Interface Descriptor is a concatenation of all the descriptors that are used to fully describe
365   // the video function, i.e., all Unit Descriptors (UDs) and Terminal Descriptors (TDs)              
366   const vcInterface = device.interfaces.filter(interface => {                                         
367   ┊ const {                                                                                           
368   ┊ ┊ descriptor                                                                                      
369   ┊ } = interface                                                                                     
370   ┊ return descriptor.bInterfaceClass === CC.VIDEO &&                                                 
371   ┊ ┊ descriptor.bInterfaceSubClass === SC.VIDEOCONTROL              
372   })[0]                                                              

vcInterface is null (there is no such interface whose class is VIDEO). Why, even though there is a valid USB camera connected?

joelpurra commented 2 years ago

@wookayin: haven't seen that error before, and can't reproduce it. As I can't reproduce the issue (be it because of system configuration, hardware configuration, or something else) I suggest that you debug locally.

One improvement would be to check for a null vcInterface and throw a nicer error, but it's not going to fix the problem. If you find that switching the USB configuration helps, that can be part of the error message.

wookayin commented 2 years ago

Hello @joelpurra, thanks for your reply.

I have exactly the same configuration as where it worked previously, before v5.0.2 release (though it was buggy, #22). I use Logitech BRIO 4K and 930e.

I do see the webcam device in chrome://usb-internals/ --- while doing this troubleshoothing, I can use the webcam in other programs without any issues.

The webcam device (vendor 0x046D, product 0x0891) has three interfaces:

The configuration descriptor looks as follows (which I cannot easily understand):

image

I also tried to print out all the vendorId, productId, interface class code for all the interfaces when searching for vcInterface, but I do get the same vendorId and productId for all the devices. The device.deviceDescriptor are always the same javascript Object (which doesn't seem right). This could also be a potentially related bug (which happens in a configuration that works fine)?

  const vcInterface = device.interfaces.filter(interface => {
    const {
      descriptor, device
    } = interface
+   console.log(device.deviceDescriptor.idVendor, device.deviceDescriptor.idProduct, descriptor.bInterfaceClass);
    return descriptor.bInterfaceClass === CC.VIDEO &&
      descriptor.bInterfaceSubClass === SC.VIDEOCONTROL
  })[0]
joelpurra commented 2 years ago

@wookayin: the interfaces you see, for one of your cameras, look correct. This is the interface node-uvc-control is looking for:

Interface 1: Class Code = 14 (Video) / Subclass Code: 1

You also have at least one more camera connected though.

There are bugs in your debugging code.

You say that this setup worked well before, and that the only thing that differs is the uvcc versions. Then the easiest is of course to rollback to the older version.

If you want to dig deeper, here are some debugging suggestions.

Does any combination of that work?

Note that the biggest changes to uvcc the past months have been due to breaking changes and bugs in node-usb. You are already looking at code from node-uvc-control, but please keep in mind that they are from the forked version specifically for uvcc. There are many more stylistic issued and bugs in node-uvc-control that I don't want to spend time fixing. Only minimum effort at this time.

eparadis commented 2 years ago

I've read this thread and I'm not sure I'll be able to contribute much, but I'd like to report I also see this bug.

$ uvcc --version
v5.0.2
$ node --version
v17.0.1

This is on an Intel Mac Mini (2018). The camera I have attached is a Logitech C615.

$ sudo uvcc devices
[
  {
    "name": "HD Webcam C615",
    "vendor": 1133,
    "product": 2092,
    "address": 30
  }
]
# note: it hangs here. I must use CTRL-C to exit

Error using uvcc controls:

$ uvcc controls
WrappedError: Could create uvc-control object: {} ("TypeError: Cannot read properties of undefined (reading 'descriptor')")
    at CameraFactory.createWrappedError (file:///usr/local/lib/node_modules/uvcc/dist/camera-factory.js:90:30)
    at CameraFactory.get (file:///usr/local/lib/node_modules/uvcc/dist/camera-factory.js:74:43)
    at CommandManager.execute (file:///usr/local/lib/node_modules/uvcc/dist/command-manager.js:73:47)
    at async mainAsync (file:///usr/local/lib/node_modules/uvcc/dist/index.js:73:9) {
  innerError: TypeError: Cannot read properties of undefined (reading 'descriptor')
      at getInterfaceDescriptors (/usr/local/lib/node_modules/uvcc/node_modules/uvc-control/index.js:375:26)
      at UVCControl.init (/usr/local/lib/node_modules/uvcc/node_modules/uvc-control/index.js:85:25)
      at new UVCControl (/usr/local/lib/node_modules/uvcc/node_modules/uvc-control/index.js:22:10)
      at CameraFactory.get (file:///usr/local/lib/node_modules/uvcc/dist/camera-factory.js:54:28)
      at CommandManager.execute (file:///usr/local/lib/node_modules/uvcc/dist/command-manager.js:73:47)
      at async mainAsync (file:///usr/local/lib/node_modules/uvcc/dist/index.js:73:9)

Perhaps this data point will help someone else.

joelpurra commented 2 years ago

@wookayin, @eparadis: which version of macOS are you using? Have seen reports of issues with macOS 12 in other projects.

The current approach where the USB device is accessed directly, implemented by for example node-uvc-control and libuvc, might not work anymore. Windows has similar problems, but not for merely adjusting UVC controls. It seems Apple changed how USB webcams are accessed; perhaps there are system configuration workarounds. Am, as mentioned, not using macOS 12 (neither Intel nor ARM version) myself so am not able to work on this issue.

mcuee commented 2 years ago

Workaround which may not be easy to implement (using a codeless DriverKit Extension).