Skip to content

Commit fb2b056

Browse files
committed
Use audio serial as a fallback for K4W and 1473 models that do not provide a useful camera serial (thanks @olzhas).
Fixes #360 and resolves #393. Signed-off-by: Benn Snyder <[email protected]>
1 parent 88aba0a commit fb2b056

File tree

2 files changed

+122
-71
lines changed

2 files changed

+122
-71
lines changed

include/libfreenect.h

+4-4
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,10 @@ typedef enum {
6464
/// A struct used in enumeration to give access to serial numbers, so you can
6565
/// open a particular device by serial rather than depending on index. This
6666
/// is most useful if you have more than one Kinect.
67-
struct freenect_device_attributes;
68-
struct freenect_device_attributes {
69-
struct freenect_device_attributes *next; /**< Next device in the linked list */
70-
const char* camera_serial; /**< Serial number of this device's camera subdevice */
67+
struct freenect_device_attributes
68+
{
69+
struct freenect_device_attributes *next; // Next device in the linked list
70+
const char* camera_serial; // Serial number of camera or audio subdevice
7171
};
7272

7373
/// Enumeration of available resolutions.

src/usb_libusb10.c

+118-67
Original file line numberDiff line numberDiff line change
@@ -60,58 +60,149 @@ FN_INTERNAL int fnusb_num_devices(fnusb_ctx *ctx)
6060
return nr;
6161
}
6262

63+
// Returns 1 if `pid` identifies K4W audio, 0 otherwise
64+
FN_INTERNAL int fnusb_is_pid_k4w_audio(int pid)
65+
{
66+
return (pid == PID_K4W_AUDIO || pid == PID_K4W_AUDIO_ALT_1 || pid == PID_K4W_AUDIO_ALT_2);
67+
}
68+
69+
FN_INTERNAL libusb_device * fnusb_find_connected_audio_device(libusb_device * camera, libusb_device ** deviceList, int cnt)
70+
{
71+
if (cnt <= 0) return NULL;
72+
73+
int cameraBusNo = libusb_get_bus_number(camera);
74+
if (cameraBusNo < 0) return NULL;
75+
libusb_device * cameraParent = libusb_get_parent(camera);
76+
77+
int i = 0;
78+
for (i = 0; i < cnt; i++)
79+
{
80+
struct libusb_device_descriptor desc;
81+
int res = libusb_get_device_descriptor (deviceList[i], &desc);
82+
if (res < 0)
83+
{
84+
continue;
85+
}
86+
87+
if (desc.idVendor == VID_MICROSOFT)
88+
{
89+
// make sure its some type of Kinect audio device
90+
if ((desc.idProduct == PID_NUI_AUDIO || fnusb_is_pid_k4w_audio(desc.idProduct)))
91+
{
92+
int audioBusNo = libusb_get_bus_number(deviceList[i]);
93+
if (audioBusNo == cameraBusNo)
94+
{
95+
// we have a match!
96+
// let's double check
97+
libusb_device * audioParent = libusb_get_parent(deviceList[i]);
98+
if (cameraParent == audioParent)
99+
{
100+
return deviceList[i];
101+
}
102+
}
103+
}
104+
}
105+
}
106+
107+
return NULL;
108+
}
109+
63110
FN_INTERNAL int fnusb_list_device_attributes(fnusb_ctx *ctx, struct freenect_device_attributes** attribute_list)
64111
{
112+
// todo: figure out how to log without freenect_context
113+
65114
*attribute_list = NULL; // initialize some return value in case the user is careless.
66-
libusb_device **devs;
67-
//pointer to pointer of device, used to retrieve a list of devices
115+
libusb_device **devs; // pointer to pointer of device, used to retrieve a list of devices
68116
ssize_t count = libusb_get_device_list (ctx->ctx, &devs);
69117
if (count < 0)
118+
{
70119
return -1;
120+
}
71121

72-
struct freenect_device_attributes** camera_prev_next = attribute_list;
122+
struct freenect_device_attributes** next_attr = attribute_list;
73123

74124
// Pass over the list. For each camera seen, if we already have a camera
75125
// for the newest_camera device, allocate a new one and append it to the list,
76-
// incrementing num_devs. Likewise for each audio device.
77-
struct libusb_device_descriptor desc;
126+
// incrementing num_cams.
78127
int num_cams = 0;
79128
int i;
80-
for (i = 0; i < count; i++) {
81-
int r = libusb_get_device_descriptor (devs[i], &desc);
82-
if (r < 0)
129+
for (i = 0; i < count; i++)
130+
{
131+
libusb_device* camera_device = devs[i];
132+
133+
struct libusb_device_descriptor desc;
134+
int res = libusb_get_device_descriptor (camera_device, &desc);
135+
if (res < 0)
136+
{
83137
continue;
84-
if (desc.idVendor == VID_MICROSOFT && (desc.idProduct == PID_NUI_CAMERA || desc.idProduct == PID_K4W_CAMERA)) {
138+
}
139+
140+
if (desc.idVendor == VID_MICROSOFT && (desc.idProduct == PID_NUI_CAMERA || desc.idProduct == PID_K4W_CAMERA))
141+
{
85142
// Verify that a serial number exists to query. If not, don't touch the device.
86-
if (desc.iSerialNumber == 0) {
143+
if (desc.iSerialNumber == 0)
144+
{
87145
continue;
88146
}
89147

90-
// Open device.
91-
int res;
92-
libusb_device_handle *this_device;
93-
res = libusb_open(devs[i], &this_device);
94-
unsigned char string_desc[256]; // String descriptors are at most 256 bytes.
95-
if (res != 0) {
148+
libusb_device_handle *camera_handle;
149+
res = libusb_open(camera_device, &camera_handle);
150+
if (res != 0)
151+
{
96152
continue;
97153
}
98154

99155
// Read string descriptor referring to serial number.
100-
res = libusb_get_string_descriptor_ascii(this_device, desc.iSerialNumber, string_desc, 256);
101-
libusb_close(this_device);
102-
if (res < 0) {
156+
unsigned char serial[256]; // String descriptors are at most 256 bytes.
157+
res = libusb_get_string_descriptor_ascii(camera_handle, desc.iSerialNumber, serial, 256);
158+
libusb_close(camera_handle);
159+
if (res < 0)
160+
{
103161
continue;
104162
}
105163

164+
// K4W and 1473 don't provide a camera serial; use audio serial instead.
165+
const char* const K4W_1473_SERIAL = "0000000000000000";
166+
if (strncmp((const char*)serial, K4W_1473_SERIAL, 16) != 0)
167+
{
168+
libusb_device* audio_device = fnusb_find_connected_audio_device(camera_device, devs, count);
169+
170+
if (audio_device != NULL)
171+
{
172+
struct libusb_device_descriptor audio_desc;
173+
res = libusb_get_device_descriptor(audio_device, &audio_desc);
174+
if (res != 0)
175+
{
176+
//FN_ERROR("Failed to get audio serial descriptors of K4W or 1473 device: %d\n", res);
177+
}
178+
else
179+
{
180+
libusb_device_handle * audio_handle = NULL;
181+
res = libusb_open(audio_device, &audio_handle);
182+
if (res != 0)
183+
{
184+
//FN_ERROR("Failed to open audio device for serial of K4W or 1473 device: %d\n", res);
185+
}
186+
else
187+
{
188+
res = libusb_get_string_descriptor_ascii(audio_handle, audio_desc.iSerialNumber, serial, 256);
189+
libusb_close(audio_handle);
190+
if (res != 0)
191+
{
192+
//FN_ERROR("Failed to get audio serial of K4W or 1473 device: %d\n", res);
193+
}
194+
}
195+
}
196+
}
197+
}
198+
106199
// Add item to linked list.
107-
struct freenect_device_attributes* new_dev_attrs = (struct freenect_device_attributes*)malloc(sizeof(struct freenect_device_attributes));
108-
memset(new_dev_attrs, 0, sizeof(*new_dev_attrs));
109-
110-
*camera_prev_next = new_dev_attrs;
111-
// Copy string with serial number
112-
new_dev_attrs->camera_serial = strdup((char*)string_desc);
113-
camera_prev_next = &(new_dev_attrs->next);
114-
// Increment number of cameras found
200+
struct freenect_device_attributes* current_attr = (struct freenect_device_attributes*)malloc(sizeof(struct freenect_device_attributes));
201+
memset(current_attr, 0, sizeof(*current_attr));
202+
203+
current_attr->camera_serial = strdup((char*)serial);
204+
*next_attr = current_attr;
205+
next_attr = &(current_attr->next);
115206
num_cams++;
116207
}
117208
}
@@ -161,46 +252,6 @@ FN_INTERNAL int fnusb_process_events_timeout(fnusb_ctx *ctx, struct timeval* tim
161252
return libusb_handle_events_timeout(ctx->ctx, timeout);
162253
}
163254

164-
// Returns 1 if `pid` identifies K4W audio, 0 otherwise
165-
FN_INTERNAL int fnusb_is_pid_k4w_audio(int pid)
166-
{
167-
return (pid == PID_K4W_AUDIO || pid == PID_K4W_AUDIO_ALT_1 || pid == PID_K4W_AUDIO_ALT_2);
168-
}
169-
170-
FN_INTERNAL libusb_device * fnusb_find_connected_audio_device(libusb_device * camera, libusb_device ** deviceList, int cnt){
171-
172-
int cameraBusNo = libusb_get_bus_number(camera);
173-
libusb_device * cameraParent = libusb_get_parent(camera);
174-
175-
if( cameraBusNo < 0 ) return NULL;
176-
if( cnt <= 0 ) return NULL;
177-
178-
int i = 0;
179-
struct libusb_device_descriptor desc;
180-
181-
for (i = 0; i < cnt; i++) {
182-
int r = libusb_get_device_descriptor (deviceList[i], &desc);
183-
if (r < 0) continue;
184-
if (desc.idVendor != VID_MICROSOFT) continue;
185-
186-
//make sure its some type of Kinect audio device
187-
if( (desc.idProduct == PID_NUI_AUDIO || fnusb_is_pid_k4w_audio(desc.idProduct) ) ){
188-
189-
int audioBusNo = libusb_get_bus_number(deviceList[i]);
190-
if( audioBusNo == cameraBusNo ){
191-
//we have a match!
192-
//lets double check
193-
libusb_device * audioParent = libusb_get_parent(deviceList[i]);
194-
if( cameraParent == audioParent ){
195-
return deviceList[i];
196-
}
197-
}
198-
}
199-
}
200-
201-
return NULL;
202-
}
203-
204255
FN_INTERNAL int fnusb_open_subdevices(freenect_device *dev, int index)
205256
{
206257
freenect_context *ctx = dev->parent;

0 commit comments

Comments
 (0)