duvc-ctl 2.0.0
USB Video Class Camera Control Library
Loading...
Searching...
No Matches
api.cpp
Go to the documentation of this file.
1
11#include "duvc-ctl/c/api.h"
12
13// Include all necessary C++ headers
18#include "duvc-ctl/core/types.h"
22#ifdef _WIN32
24#endif
25
26#include <algorithm>
27#include <atomic>
28#include <cstring>
29#include <memory>
30#include <mutex>
31#include <string>
32#include <unordered_map>
33#include <vector>
34
35// Version information
36#ifndef DUVC_ABI_VERSION
37#define DUVC_ABI_VERSION ((1 << 16) | (0 << 8) | 0) // 1.0.0
38#endif
39
40#ifndef DUVC_ABI_VERSION_STRING
41#define DUVC_ABI_VERSION_STRING "1.0.0"
42#endif
43
44#ifdef DeviceCapabilities
45#undef DeviceCapabilities
46#endif
47
48// Global state management
49namespace {
50
52std::atomic<bool> g_initialized{false};
53
55std::mutex g_library_mutex;
56
58thread_local std::string g_last_error_details;
59
61duvc_log_callback g_log_callback = nullptr;
62void *g_log_callback_user_data = nullptr;
63std::mutex g_log_mutex;
64
66duvc_device_change_callback g_device_change_callback = nullptr;
67void *g_device_change_user_data = nullptr;
68std::mutex g_device_change_mutex;
69
71std::vector<std::unique_ptr<duvc::Device>> g_device_storage;
72std::mutex g_device_storage_mutex;
73
75std::unordered_map<duvc_connection_t *, std::unique_ptr<duvc::Camera>>
76 g_connections;
77std::mutex g_connection_mutex;
78
80std::vector<std::unique_ptr<duvc::DeviceCapabilities>> g_capabilities_storage;
81std::mutex g_capabilities_mutex;
82
91duvc_result_t copy_string_to_buffer(const std::string &cpp_str, char *buffer,
92 size_t buffer_size, size_t *required_size) {
93 size_t needed = cpp_str.length() + 1;
94 if (required_size)
95 *required_size = needed;
96
97 if (!buffer || buffer_size < needed) {
99 }
100
101 std::memcpy(buffer, cpp_str.c_str(), needed);
102 return DUVC_SUCCESS;
103}
104
108duvc_result_t copy_wstring_to_buffer(const std::wstring &wide_str, char *buffer,
109 size_t buffer_size,
110 size_t *required_size) {
111 try {
112 std::string utf8_str = duvc::to_utf8(wide_str);
113 return copy_string_to_buffer(utf8_str, buffer, buffer_size, required_size);
114 } catch (const std::exception &e) {
115 g_last_error_details = std::string("String conversion failed: ") + e.what();
116 if (required_size)
117 *required_size = 0;
119 }
120}
121
125duvc_result_t convert_error_code(duvc::ErrorCode code) {
126 switch (code) {
128 return DUVC_SUCCESS;
145 default:
147 }
148}
149
153template <typename T>
154duvc_result_t handle_cpp_result(const duvc::Result<T> &result) {
155 if (result.is_ok()) {
156 g_last_error_details.clear();
157 return DUVC_SUCCESS;
158 }
159
160 const auto &error = result.error();
161 g_last_error_details = error.description();
162 return convert_error_code(error.code());
163}
164
168void cpp_log_callback_wrapper(duvc::LogLevel level,
169 const std::string &message) {
170 std::lock_guard<std::mutex> lock(g_log_mutex);
171 if (g_log_callback) {
172 duvc_log_level_t c_level =
173 static_cast<duvc_log_level_t>(static_cast<int>(level));
174 try {
175 g_log_callback(c_level, message.c_str(), g_log_callback_user_data);
176 } catch (...) {
177 // Ignore exceptions from user callback
178 }
179 }
180}
181
182// --- C <-> C++ Type Conversion Helpers ---
183
184duvc::CamProp convert_cam_prop(duvc_cam_prop_t prop) {
185 return static_cast<duvc::CamProp>(prop);
186}
187
188duvc::VidProp convert_vid_prop(duvc_vid_prop_t prop) {
189 return static_cast<duvc::VidProp>(prop);
190}
191
192duvc::CamMode convert_cam_mode_from_c(duvc_cam_mode_t mode) {
193 return static_cast<duvc::CamMode>(mode);
194}
195
196duvc_cam_mode_t convert_cam_mode_to_c(duvc::CamMode mode) {
197 return static_cast<duvc_cam_mode_t>(mode);
198}
199
201convert_prop_setting_from_c(const duvc_prop_setting_t &setting) {
202 duvc::PropSetting cpp_setting;
203 cpp_setting.value = setting.value;
204 cpp_setting.mode = convert_cam_mode_from_c(setting.mode);
205 return cpp_setting;
206}
207
209convert_prop_setting_to_c(const duvc::PropSetting &setting) {
210 duvc_prop_setting_t c_setting;
211 c_setting.value = setting.value;
212 c_setting.mode = convert_cam_mode_to_c(setting.mode);
213 return c_setting;
214}
215
216duvc_prop_range_t convert_prop_range_to_c(const duvc::PropRange &range) {
217 duvc_prop_range_t c_range;
218 c_range.min = range.min;
219 c_range.max = range.max;
220 c_range.step = range.step;
221 c_range.default_val = range.default_val;
222 c_range.default_mode = convert_cam_mode_to_c(range.default_mode);
223 return c_range;
224}
225
226} // anonymous namespace
227
228extern "C" {
229
230/* ========================================================================
231 * Version and ABI Management
232 * ======================================================================== */
233
234uint32_t duvc_get_version(void) { return DUVC_ABI_VERSION; }
235
237
238int duvc_check_abi_compatibility(uint32_t compiled_version) {
239 uint32_t runtime_version = duvc_get_version();
240
241 // Extract major, minor versions
242 uint32_t compiled_major = (compiled_version >> 16) & 0xFF;
243 uint32_t runtime_major = (runtime_version >> 16) & 0xFF;
244
245 // Major versions must match exactly for ABI compatibility
246 if (compiled_major != runtime_major) {
247 return 0;
248 }
249
250 // Runtime minor version must be >= compiled minor version
251 uint32_t compiled_minor = (compiled_version >> 8) & 0xFF;
252 uint32_t runtime_minor = (runtime_version >> 8) & 0xFF;
253
254 return (runtime_minor >= compiled_minor) ? 1 : 0;
255}
256
257/* ========================================================================
258 * Library Lifecycle
259 * ======================================================================== */
260
262 std::lock_guard<std::mutex> lock(g_library_mutex);
263
264 if (g_initialized.load()) {
265 return DUVC_SUCCESS; // Already initialized
266 }
267
268 try {
269 // Clear any previous error state
270 g_last_error_details.clear();
271
272 // Initialize logging with default level
274
275 // Clear storage containers
276 g_device_storage.clear();
277 g_connections.clear();
278 g_capabilities_storage.clear();
279
280 g_initialized.store(true);
281 duvc::log_info("duvc-ctl C API initialized successfully");
282 return DUVC_SUCCESS;
283
284 } catch (const std::exception &e) {
285 g_last_error_details = std::string("Initialization failed: ") + e.what();
287 } catch (...) {
288 g_last_error_details = "Initialization failed: unknown error";
290 }
291}
292
293void duvc_shutdown(void) {
294 std::lock_guard<std::mutex> lock(g_library_mutex);
295 if (!g_initialized.load()) {
296 return; // Already shutdown
297 }
298
299 try {
300 // Unregister device monitor to stop background threads
302
303 // Clear all connections
304 {
305 std::lock_guard<std::mutex> conn_lock(g_connection_mutex);
306 g_connections.clear();
307 }
308
309 // Clear device storage
310 {
311 std::lock_guard<std::mutex> dev_lock(g_device_storage_mutex);
312 g_device_storage.clear();
313 }
314
315 // Clear capabilities storage
316 {
317 std::lock_guard<std::mutex> caps_lock(g_capabilities_mutex);
318 g_capabilities_storage.clear();
319 }
320
321 // Clear callbacks
322 {
323 std::lock_guard<std::mutex> log_lock(g_log_mutex);
324 g_log_callback = nullptr;
325 g_log_callback_user_data = nullptr;
326 }
327
328 g_initialized.store(false);
329
330 } catch (...) {
331 // Ignore exceptions during shutdown
332 }
333}
334
335int duvc_is_initialized(void) { return g_initialized.load() ? 1 : 0; }
336
337/* ========================================================================
338 * String Conversions
339 * ======================================================================== */
340
342 switch (code) {
343 case DUVC_SUCCESS:
344 return "Success";
346 return "Not Implemented";
348 return "Invalid Argument";
350 return "Device Not Found";
352 return "Device Busy";
354 return "Property Not Supported";
356 return "Invalid Value";
358 return "Permission Denied";
360 return "System Error";
362 return "Connection Failed";
364 return "Timeout";
366 return "Buffer Too Small";
367 default:
368 return "Unknown Error";
369 }
370}
371
373 // This can leverage the internal C++ version if available and linked
374 return duvc::to_string(static_cast<duvc::CamProp>(prop));
375}
376
378 return duvc::to_string(static_cast<duvc::VidProp>(prop));
379}
380
382 return duvc::to_string(static_cast<duvc::CamMode>(mode));
383}
384
386 switch (level) {
387 case DUVC_LOG_DEBUG:
388 return "Debug";
389 case DUVC_LOG_INFO:
390 return "Info";
391 case DUVC_LOG_WARNING:
392 return "Warning";
393 case DUVC_LOG_ERROR:
394 return "Error";
396 return "Critical";
397 default:
398 return "Unknown";
399 }
400}
401
402/* ========================================================================
403 * Logging System
404 * ======================================================================== */
405
407 void *user_data) {
408 if (!g_initialized.load()) {
409 g_last_error_details = "Library not initialized";
411 }
412
413 try {
414 std::lock_guard<std::mutex> lock(g_log_mutex);
415 g_log_callback = callback;
416 g_log_callback_user_data = user_data;
417
418 if (callback) {
419 duvc::set_log_callback(cpp_log_callback_wrapper);
420 } else {
421 duvc::set_log_callback(nullptr);
422 }
423
424 return DUVC_SUCCESS;
425 } catch (const std::exception &e) {
426 g_last_error_details =
427 std::string("Failed to set log callback: ") + e.what();
429 }
430}
431
433 if (!g_initialized.load()) {
434 g_last_error_details = "Library not initialized";
436 }
437
438 try {
439 duvc::LogLevel cpp_level =
440 static_cast<duvc::LogLevel>(static_cast<int>(level));
441 duvc::set_log_level(cpp_level);
442 return DUVC_SUCCESS;
443 } catch (const std::exception &e) {
444 g_last_error_details = std::string("Failed to set log level: ") + e.what();
446 }
447}
448
450 if (!level)
452 if (!g_initialized.load()) {
453 g_last_error_details = "Library not initialized";
455 }
456
457 try {
459 *level = static_cast<duvc_log_level_t>(static_cast<int>(cpp_level));
460 return DUVC_SUCCESS;
461 } catch (const std::exception &e) {
462 g_last_error_details = std::string("Failed to get log level: ") + e.what();
464 }
465}
466
468 if (!message)
470 if (!g_initialized.load()) {
471 // Cannot set error message if not initialized
473 }
474
475 try {
476 duvc::LogLevel cpp_level =
477 static_cast<duvc::LogLevel>(static_cast<int>(level));
478 duvc::log_message(cpp_level, std::string(message));
479 return DUVC_SUCCESS;
480 } catch (const std::exception &) {
481 // Don't update error details to avoid recursion
483 }
484}
485
486duvc_result_t duvc_log_debug(const char *message) {
487 return duvc_log_message(DUVC_LOG_DEBUG, message);
488}
489
490duvc_result_t duvc_log_info(const char *message) {
491 return duvc_log_message(DUVC_LOG_INFO, message);
492}
493
494duvc_result_t duvc_log_warning(const char *message) {
495 return duvc_log_message(DUVC_LOG_WARNING, message);
496}
497
498duvc_result_t duvc_log_error(const char *message) {
499 return duvc_log_message(DUVC_LOG_ERROR, message);
500}
501
502duvc_result_t duvc_log_critical(const char *message) {
503 return duvc_log_message(DUVC_LOG_CRITICAL, message);
504}
505
506/* ========================================================================
507 * Device Management
508 * ======================================================================== */
509
511 if (!devices || !count)
513 if (!g_initialized.load()) {
514 g_last_error_details = "Library not initialized";
516 }
517
518 try {
519 std::lock_guard<std::mutex> lock(g_device_storage_mutex);
520
521 // Clear previous device storage
522 g_device_storage.clear();
523
524 // Get devices from C++ core
525 auto device_list = duvc::list_devices();
526
527 // Allocate C device array
528 duvc_device_t **c_devices = static_cast<duvc_device_t **>(
529 std::malloc(device_list.size() * sizeof(duvc_device_t *)));
530 if (!c_devices && !device_list.empty()) {
531 g_last_error_details = "Failed to allocate memory for device list";
533 }
534
535 // Store devices and create C pointers
536 for (size_t i = 0; i < device_list.size(); ++i) {
537 auto stored_device =
538 std::make_unique<duvc::Device>(std::move(device_list[i]));
539 c_devices[i] = reinterpret_cast<duvc_device_t *>(stored_device.get());
540 g_device_storage.push_back(std::move(stored_device));
541 }
542
543 *devices = c_devices;
544 *count = device_list.size();
545 return DUVC_SUCCESS;
546
547 } catch (const std::exception &e) {
548 g_last_error_details = std::string("Failed to list devices: ") + e.what();
550 } catch (...) {
551 g_last_error_details = "Unknown error while listing devices";
553 }
554}
555
556duvc_result_t duvc_find_device_by_path(const char *device_path_utf8,
557 duvc_device_t **device) {
558 if (!device_path_utf8 || !device)
560 if (!g_initialized.load()) {
561 g_last_error_details = "Library not initialized";
563 }
564
565 try {
566 // Convert UTF-8 to wide string
567 std::wstring device_path = duvc::to_wstring(std::string(device_path_utf8));
568
569 // Find device by path
570 duvc::Device found_device = duvc::find_device_by_path(device_path);
571
572 // Store device and return pointer
573 std::lock_guard<std::mutex> lock(g_device_storage_mutex);
574 auto stored_device = std::make_unique<duvc::Device>(std::move(found_device));
575 *device = reinterpret_cast<duvc_device_t *>(stored_device.get());
576 g_device_storage.push_back(std::move(stored_device));
577
578 return DUVC_SUCCESS;
579
580 } catch (const std::exception &e) {
581 g_last_error_details =
582 std::string("Failed to find device by path: ") + e.what();
584 } catch (...) {
585 g_last_error_details = "Unknown error while finding device by path";
587 }
588}
589
590void duvc_free_device_list(duvc_device_t **devices, size_t count) {
591 (void)count; // Unused parameter
592
593 if (devices) {
594 std::free(devices);
595 }
596
597 // Note: Individual devices are managed by g_device_storage
598}
599
601 int *connected) {
602 if (!device || !connected)
604 if (!g_initialized.load()) {
605 g_last_error_details = "Library not initialized";
607 }
608
609 try {
610 const duvc::Device *cpp_device =
611 reinterpret_cast<const duvc::Device *>(device);
612 bool is_connected = duvc::is_device_connected(*cpp_device);
613 *connected = is_connected ? 1 : 0;
614 return DUVC_SUCCESS;
615
616 } catch (const std::exception &e) {
617 g_last_error_details =
618 std::string("Failed to check device connection: ") + e.what();
620 } catch (...) {
621 g_last_error_details = "Unknown error while checking device connection";
623 }
624}
625
627 size_t buffer_size, size_t *required) {
628 if (!device)
630 if (!g_initialized.load()) {
631 g_last_error_details = "Library not initialized";
633 }
634
635 try {
636 const duvc::Device *cpp_device =
637 reinterpret_cast<const duvc::Device *>(device);
638 return copy_wstring_to_buffer(cpp_device->name, buffer, buffer_size,
639 required);
640 } catch (const std::exception &e) {
641 g_last_error_details =
642 std::string("Failed to get device name: ") + e.what();
644 }
645}
646
648 size_t buffer_size, size_t *required) {
649 if (!device)
651 if (!g_initialized.load()) {
652 g_last_error_details = "Library not initialized";
654 }
655
656 try {
657 const duvc::Device *cpp_device =
658 reinterpret_cast<const duvc::Device *>(device);
659 return copy_wstring_to_buffer(cpp_device->path, buffer, buffer_size,
660 required);
661 } catch (const std::exception &e) {
662 g_last_error_details =
663 std::string("Failed to get device path: ") + e.what();
665 }
666}
667
669 size_t buffer_size, size_t *required) {
670 if (!device)
672 if (!g_initialized.load()) {
673 g_last_error_details = "Library not initialized";
675 }
676
677 try {
678 const duvc::Device *cpp_device =
679 reinterpret_cast<const duvc::Device *>(device);
680 // Use path as device ID if available, otherwise use name
681 const std::wstring &id_str =
682 cpp_device->path.empty() ? cpp_device->name : cpp_device->path;
683 return copy_wstring_to_buffer(id_str, buffer, buffer_size, required);
684 } catch (const std::exception &e) {
685 g_last_error_details = std::string("Failed to get device ID: ") + e.what();
687 }
688}
689
691 if (!device || !valid)
693 if (!g_initialized.load()) {
694 g_last_error_details = "Library not initialized";
696 }
697
698 try {
699 const duvc::Device *cpp_device =
700 reinterpret_cast<const duvc::Device *>(device);
701 *valid = cpp_device->is_valid() ? 1 : 0;
702 return DUVC_SUCCESS;
703 } catch (const std::exception &e) {
704 g_last_error_details =
705 std::string("Failed to check device validity: ") + e.what();
707 }
708}
709
710/* ========================================================================
711 * Device Change Monitoring
712 * ======================================================================== */
713
716 void *user_data) {
717 if (!g_initialized.load()) {
718 g_last_error_details = "Library not initialized";
720 }
721
722 try {
723 std::lock_guard<std::mutex> lock(g_device_change_mutex);
724
725 g_device_change_callback = callback;
726 g_device_change_user_data = user_data;
727
728 // Register with the underlying system
730 [=](bool added, const std::wstring &device_path) {
731 std::lock_guard<std::mutex> cb_lock(g_device_change_mutex);
732 if (g_device_change_callback) {
733 try {
734 std::string utf8_path = duvc::to_utf8(device_path);
735 g_device_change_callback(added ? 1 : 0, utf8_path.c_str(),
736 g_device_change_user_data);
737 } catch (...) {
738 // Ignore exceptions from user callback
739 }
740 }
741 });
742
743 return DUVC_SUCCESS;
744
745 } catch (const std::exception &e) {
746 g_last_error_details =
747 std::string("Failed to register device change callback: ") + e.what();
749 }
750}
751
753 if (!g_initialized.load()) {
754 return;
755 }
756
757 try {
758 std::lock_guard<std::mutex> lock(g_device_change_mutex);
759
760 // Unregister with the underlying system
762
763 g_device_change_callback = nullptr;
764 g_device_change_user_data = nullptr;
765
766 } catch (...) {
767 // Ignore exceptions during cleanup
768 }
769}
770
771/* ========================================================================
772 * Camera Connections
773 * ======================================================================== */
774
776 duvc_connection_t **conn) {
777 if (!conn || device_index < 0)
779 if (!g_initialized.load()) {
780 g_last_error_details = "Library not initialized";
782 }
783
784 try {
785 auto cam_result = duvc::open_camera(device_index);
786 if (!cam_result.is_ok()) {
787 return handle_cpp_result(cam_result);
788 }
789
790 std::lock_guard<std::mutex> conn_lock(g_connection_mutex);
791 auto camera_ptr =
792 std::make_unique<duvc::Camera>(std::move(cam_result).value());
793 duvc_connection_t *handle =
794 reinterpret_cast<duvc_connection_t *>(camera_ptr.get());
795 g_connections[handle] = std::move(camera_ptr);
796 *conn = handle;
797
798 return DUVC_SUCCESS;
799 } catch (const std::exception &e) {
800 g_last_error_details =
801 std::string("Failed to open camera by index: ") + e.what();
803 }
804}
805
807 duvc_connection_t **conn) {
808 if (!device || !conn)
810 if (!g_initialized.load()) {
811 g_last_error_details = "Library not initialized";
813 }
814
815 try {
816 const duvc::Device *cpp_device =
817 reinterpret_cast<const duvc::Device *>(device);
818 auto cam_result = duvc::open_camera(*cpp_device);
819 if (!cam_result.is_ok()) {
820 return handle_cpp_result(cam_result);
821 }
822
823 std::lock_guard<std::mutex> lock(g_connection_mutex);
824 auto camera_ptr =
825 std::make_unique<duvc::Camera>(std::move(cam_result).value());
826 duvc_connection_t *handle =
827 reinterpret_cast<duvc_connection_t *>(camera_ptr.get());
828 g_connections[handle] = std::move(camera_ptr);
829 *conn = handle;
830
831 return DUVC_SUCCESS;
832 } catch (const std::exception &e) {
833 g_last_error_details = std::string("Failed to open camera: ") + e.what();
835 }
836}
837
839 if (!conn || !g_initialized.load()) {
840 return;
841 }
842
843 try {
844 std::lock_guard<std::mutex> lock(g_connection_mutex);
845 auto it = g_connections.find(conn);
846 if (it != g_connections.end()) {
847 g_connections.erase(it);
848 }
849 } catch (...) {
850 // Ignore exceptions during cleanup
851 }
852}
853
855 if (!conn || !g_initialized.load()) {
856 return 0;
857 }
858
859 try {
860 std::lock_guard<std::mutex> lock(g_connection_mutex);
861 auto it = g_connections.find(const_cast<duvc_connection_t *>(conn));
862 if (it == g_connections.end()) {
863 return 0;
864 }
865 return it->second->is_valid() ? 1 : 0;
866 } catch (...) {
867 return 0;
868 }
869}
870
871/* ========================================================================
872 * Property Access - Single Properties
873 * ======================================================================== */
874
876 duvc_cam_prop_t prop,
877 duvc_prop_setting_t *setting) {
878 if (!conn || !setting)
880 if (!g_initialized.load()) {
881 g_last_error_details = "Library not initialized";
883 }
884
885 try {
886 std::lock_guard<std::mutex> lock(g_connection_mutex);
887 auto it = g_connections.find(conn);
888 if (it == g_connections.end()) {
889 g_last_error_details = "Invalid connection handle";
891 }
892
893 auto result = it->second->get(convert_cam_prop(prop));
894 if (!result.is_ok()) {
895 return handle_cpp_result(result);
896 }
897
898 *setting = convert_prop_setting_to_c(result.value());
899 return DUVC_SUCCESS;
900 } catch (const std::exception &e) {
901 g_last_error_details =
902 std::string("Failed to get camera property: ") + e.what();
904 }
905}
906
908 duvc_cam_prop_t prop,
909 const duvc_prop_setting_t *setting) {
910 if (!conn || !setting)
912 if (!g_initialized.load()) {
913 g_last_error_details = "Library not initialized";
915 }
916
917 try {
918 std::lock_guard<std::mutex> lock(g_connection_mutex);
919 auto it = g_connections.find(conn);
920 if (it == g_connections.end()) {
921 g_last_error_details = "Invalid connection handle";
923 }
924
925 duvc::PropSetting cpp_setting = convert_prop_setting_from_c(*setting);
926 auto result = it->second->set(convert_cam_prop(prop), cpp_setting);
927 return handle_cpp_result(result);
928 } catch (const std::exception &e) {
929 g_last_error_details =
930 std::string("Failed to set camera property: ") + e.what();
932 }
933}
934
936 duvc_cam_prop_t prop,
937 duvc_prop_range_t *range) {
938 if (!conn || !range)
940 if (!g_initialized.load()) {
941 g_last_error_details = "Library not initialized";
943 }
944
945 try {
946 std::lock_guard<std::mutex> lock(g_connection_mutex);
947 auto it = g_connections.find(conn);
948 if (it == g_connections.end()) {
949 g_last_error_details = "Invalid connection handle";
951 }
952
953 auto result = it->second->get_range(convert_cam_prop(prop));
954 if (!result.is_ok()) {
955 return handle_cpp_result(result);
956 }
957
958 *range = convert_prop_range_to_c(result.value());
959 return DUVC_SUCCESS;
960 } catch (const std::exception &e) {
961 g_last_error_details =
962 std::string("Failed to get camera property range: ") + e.what();
964 }
965}
966
968 duvc_vid_prop_t prop,
969 duvc_prop_setting_t *setting) {
970 if (!conn || !setting)
972 if (!g_initialized.load()) {
973 g_last_error_details = "Library not initialized";
975 }
976
977 try {
978 std::lock_guard<std::mutex> lock(g_connection_mutex);
979 auto it = g_connections.find(conn);
980 if (it == g_connections.end()) {
981 g_last_error_details = "Invalid connection handle";
983 }
984
985 auto result = it->second->get(convert_vid_prop(prop));
986 if (!result.is_ok()) {
987 return handle_cpp_result(result);
988 }
989
990 *setting = convert_prop_setting_to_c(result.value());
991 return DUVC_SUCCESS;
992 } catch (const std::exception &e) {
993 g_last_error_details =
994 std::string("Failed to get video property: ") + e.what();
996 }
997}
998
1000 duvc_vid_prop_t prop,
1001 const duvc_prop_setting_t *setting) {
1002 if (!conn || !setting)
1004 if (!g_initialized.load()) {
1005 g_last_error_details = "Library not initialized";
1007 }
1008
1009 try {
1010 std::lock_guard<std::mutex> lock(g_connection_mutex);
1011 auto it = g_connections.find(conn);
1012 if (it == g_connections.end()) {
1013 g_last_error_details = "Invalid connection handle";
1015 }
1016
1017 duvc::PropSetting cpp_setting = convert_prop_setting_from_c(*setting);
1018 auto result = it->second->set(convert_vid_prop(prop), cpp_setting);
1019 return handle_cpp_result(result);
1020 } catch (const std::exception &e) {
1021 g_last_error_details =
1022 std::string("Failed to set video property: ") + e.what();
1024 }
1025}
1026
1028 duvc_vid_prop_t prop,
1029 duvc_prop_range_t *range) {
1030 if (!conn || !range)
1032 if (!g_initialized.load()) {
1033 g_last_error_details = "Library not initialized";
1035 }
1036
1037 try {
1038 std::lock_guard<std::mutex> lock(g_connection_mutex);
1039 auto it = g_connections.find(conn);
1040 if (it == g_connections.end()) {
1041 g_last_error_details = "Invalid connection handle";
1043 }
1044
1045 auto result = it->second->get_range(convert_vid_prop(prop));
1046 if (!result.is_ok()) {
1047 return handle_cpp_result(result);
1048 }
1049
1050 *range = convert_prop_range_to_c(result.value());
1051 return DUVC_SUCCESS;
1052 } catch (const std::exception &e) {
1053 g_last_error_details =
1054 std::string("Failed to get video property range: ") + e.what();
1056 }
1057}
1058
1059/* ========================================================================
1060 * Property Access - Multiple Properties
1061 * ======================================================================== */
1062
1064 const duvc_cam_prop_t *props,
1065 duvc_prop_setting_t *settings,
1066 size_t count) {
1067 if (!conn || !props || !settings || count == 0)
1069 if (!g_initialized.load()) {
1070 g_last_error_details = "Library not initialized";
1072 }
1073
1074 try {
1075 std::lock_guard<std::mutex> lock(g_connection_mutex);
1076 auto it = g_connections.find(conn);
1077 if (it == g_connections.end()) {
1078 g_last_error_details = "Invalid connection handle";
1080 }
1081
1082 duvc::Camera *camera = it->second.get();
1083 for (size_t i = 0; i < count; ++i) {
1084 auto result = camera->get(convert_cam_prop(props[i]));
1085 if (!result.is_ok()) {
1086 g_last_error_details =
1087 "Failed to get camera property at index " + std::to_string(i);
1088 return handle_cpp_result(result);
1089 }
1090 settings[i] = convert_prop_setting_to_c(result.value());
1091 }
1092
1093 return DUVC_SUCCESS;
1094 } catch (const std::exception &e) {
1095 g_last_error_details =
1096 std::string("Failed to get multiple camera properties: ") + e.what();
1098 }
1099}
1100
1102 duvc_connection_t *conn, const duvc_cam_prop_t *props,
1103 const duvc_prop_setting_t *settings, size_t count) {
1104 if (!conn || !props || !settings || count == 0)
1106 if (!g_initialized.load()) {
1107 g_last_error_details = "Library not initialized";
1109 }
1110
1111 try {
1112 std::lock_guard<std::mutex> lock(g_connection_mutex);
1113 auto it = g_connections.find(conn);
1114 if (it == g_connections.end()) {
1115 g_last_error_details = "Invalid connection handle";
1117 }
1118
1119 duvc::Camera *camera = it->second.get();
1120 for (size_t i = 0; i < count; ++i) {
1121 duvc::PropSetting cpp_setting = convert_prop_setting_from_c(settings[i]);
1122 auto result = camera->set(convert_cam_prop(props[i]), cpp_setting);
1123 if (!result.is_ok()) {
1124 g_last_error_details =
1125 "Failed to set camera property at index " + std::to_string(i);
1126 return handle_cpp_result(result);
1127 }
1128 }
1129
1130 return DUVC_SUCCESS;
1131 } catch (const std::exception &e) {
1132 g_last_error_details =
1133 std::string("Failed to set multiple camera properties: ") + e.what();
1135 }
1136}
1137
1139 const duvc_vid_prop_t *props,
1140 duvc_prop_setting_t *settings,
1141 size_t count) {
1142 if (!conn || !props || !settings || count == 0)
1144 if (!g_initialized.load()) {
1145 g_last_error_details = "Library not initialized";
1147 }
1148
1149 try {
1150 std::lock_guard<std::mutex> lock(g_connection_mutex);
1151 auto it = g_connections.find(conn);
1152 if (it == g_connections.end()) {
1153 g_last_error_details = "Invalid connection handle";
1155 }
1156
1157 duvc::Camera *camera = it->second.get();
1158 for (size_t i = 0; i < count; ++i) {
1159 auto result = camera->get(convert_vid_prop(props[i]));
1160 if (!result.is_ok()) {
1161 g_last_error_details =
1162 "Failed to get video property at index " + std::to_string(i);
1163 return handle_cpp_result(result);
1164 }
1165 settings[i] = convert_prop_setting_to_c(result.value());
1166 }
1167
1168 return DUVC_SUCCESS;
1169 } catch (const std::exception &e) {
1170 g_last_error_details =
1171 std::string("Failed to get multiple video properties: ") + e.what();
1173 }
1174}
1175
1177 duvc_connection_t *conn, const duvc_vid_prop_t *props,
1178 const duvc_prop_setting_t *settings, size_t count) {
1179 if (!conn || !props || !settings || count == 0)
1181 if (!g_initialized.load()) {
1182 g_last_error_details = "Library not initialized";
1184 }
1185
1186 try {
1187 std::lock_guard<std::mutex> lock(g_connection_mutex);
1188 auto it = g_connections.find(conn);
1189 if (it == g_connections.end()) {
1190 g_last_error_details = "Invalid connection handle";
1192 }
1193
1194 duvc::Camera *camera = it->second.get();
1195 for (size_t i = 0; i < count; ++i) {
1196 duvc::PropSetting cpp_setting = convert_prop_setting_from_c(settings[i]);
1197 auto result = camera->set(convert_vid_prop(props[i]), cpp_setting);
1198 if (!result.is_ok()) {
1199 g_last_error_details =
1200 "Failed to set video property at index " + std::to_string(i);
1201 return handle_cpp_result(result);
1202 }
1203 }
1204
1205 return DUVC_SUCCESS;
1206 } catch (const std::exception &e) {
1207 g_last_error_details =
1208 std::string("Failed to set multiple video properties: ") + e.what();
1210 }
1211}
1212
1213/* ========================================================================
1214 * Quick API - Direct Device Access
1215 * ======================================================================== */
1216
1218 duvc_cam_prop_t prop,
1219 duvc_prop_setting_t *setting) {
1220 if (!device || !setting)
1222 if (!g_initialized.load()) {
1223 g_last_error_details = "Library not initialized";
1225 }
1226
1227 try {
1228 const duvc::Device *cpp_device =
1229 reinterpret_cast<const duvc::Device *>(device);
1230 auto cam_result = duvc::open_camera(*cpp_device);
1231 if (!cam_result.is_ok()) {
1232 return handle_cpp_result(cam_result);
1233 }
1234
1235 auto camera = std::move(cam_result).value();
1236 auto result = camera.get(convert_cam_prop(prop));
1237 if (!result.is_ok()) {
1238 return handle_cpp_result(result);
1239 }
1240
1241 *setting = convert_prop_setting_to_c(result.value());
1242 return DUVC_SUCCESS;
1243 } catch (const std::exception &e) {
1244 g_last_error_details =
1245 std::string("Failed to quick get camera property: ") + e.what();
1247 }
1248}
1249
1252 duvc_cam_prop_t prop,
1253 const duvc_prop_setting_t *setting) {
1254 if (!device || !setting)
1256 if (!g_initialized.load()) {
1257 g_last_error_details = "Library not initialized";
1259 }
1260
1261 try {
1262 const duvc::Device *cpp_device =
1263 reinterpret_cast<const duvc::Device *>(device);
1264 auto cam_result = duvc::open_camera(*cpp_device);
1265 if (!cam_result.is_ok()) {
1266 return handle_cpp_result(cam_result);
1267 }
1268
1269 auto camera = std::move(cam_result).value();
1270 duvc::PropSetting cpp_setting = convert_prop_setting_from_c(*setting);
1271 auto result = camera.set(convert_cam_prop(prop), cpp_setting);
1272 return handle_cpp_result(result);
1273 } catch (const std::exception &e) {
1274 g_last_error_details =
1275 std::string("Failed to quick set camera property: ") + e.what();
1277 }
1278}
1279
1281 duvc_cam_prop_t prop,
1282 duvc_prop_range_t *range) {
1283 if (!device || !range)
1285 if (!g_initialized.load()) {
1286 g_last_error_details = "Library not initialized";
1288 }
1289
1290 try {
1291 const duvc::Device *cpp_device =
1292 reinterpret_cast<const duvc::Device *>(device);
1293 auto cam_result = duvc::open_camera(*cpp_device);
1294 if (!cam_result.is_ok()) {
1295 return handle_cpp_result(cam_result);
1296 }
1297
1298 auto camera = std::move(cam_result).value();
1299 auto result = camera.get_range(convert_cam_prop(prop));
1300 if (!result.is_ok()) {
1301 return handle_cpp_result(result);
1302 }
1303
1304 *range = convert_prop_range_to_c(result.value());
1305 return DUVC_SUCCESS;
1306 } catch (const std::exception &e) {
1307 g_last_error_details =
1308 std::string("Failed to quick get camera property range: ") + e.what();
1310 }
1311}
1312
1314 duvc_vid_prop_t prop,
1315 duvc_prop_setting_t *setting) {
1316 if (!device || !setting)
1318 if (!g_initialized.load()) {
1319 g_last_error_details = "Library not initialized";
1321 }
1322
1323 try {
1324 const duvc::Device *cpp_device =
1325 reinterpret_cast<const duvc::Device *>(device);
1326 auto cam_result = duvc::open_camera(*cpp_device);
1327 if (!cam_result.is_ok()) {
1328 return handle_cpp_result(cam_result);
1329 }
1330
1331 auto camera = std::move(cam_result).value();
1332 auto result = camera.get(convert_vid_prop(prop));
1333 if (!result.is_ok()) {
1334 return handle_cpp_result(result);
1335 }
1336
1337 *setting = convert_prop_setting_to_c(result.value());
1338 return DUVC_SUCCESS;
1339 } catch (const std::exception &e) {
1340 g_last_error_details =
1341 std::string("Failed to quick get video property: ") + e.what();
1343 }
1344}
1345
1348 const duvc_prop_setting_t *setting) {
1349 if (!device || !setting)
1351 if (!g_initialized.load()) {
1352 g_last_error_details = "Library not initialized";
1354 }
1355
1356 try {
1357 const duvc::Device *cpp_device =
1358 reinterpret_cast<const duvc::Device *>(device);
1359 auto cam_result = duvc::open_camera(*cpp_device);
1360 if (!cam_result.is_ok()) {
1361 return handle_cpp_result(cam_result);
1362 }
1363
1364 auto camera = std::move(cam_result).value();
1365 duvc::PropSetting cpp_setting = convert_prop_setting_from_c(*setting);
1366 auto result = camera.set(convert_vid_prop(prop), cpp_setting);
1367 return handle_cpp_result(result);
1368 } catch (const std::exception &e) {
1369 g_last_error_details =
1370 std::string("Failed to quick set video property: ") + e.what();
1372 }
1373}
1374
1376 duvc_vid_prop_t prop,
1377 duvc_prop_range_t *range) {
1378 if (!device || !range)
1380 if (!g_initialized.load()) {
1381 g_last_error_details = "Library not initialized";
1383 }
1384
1385 try {
1386 const duvc::Device *cpp_device =
1387 reinterpret_cast<const duvc::Device *>(device);
1388 auto cam_result = duvc::open_camera(*cpp_device);
1389 if (!cam_result.is_ok()) {
1390 return handle_cpp_result(cam_result);
1391 }
1392
1393 auto camera = std::move(cam_result).value();
1394 auto result = camera.get_range(convert_vid_prop(prop));
1395 if (!result.is_ok()) {
1396 return handle_cpp_result(result);
1397 }
1398
1399 *range = convert_prop_range_to_c(result.value());
1400 return DUVC_SUCCESS;
1401 } catch (const std::exception &e) {
1402 g_last_error_details =
1403 std::string("Failed to quick get video property range: ") + e.what();
1405 }
1406}
1407
1408/* ========================================================================
1409 * Device Capability Snapshots
1410 * ======================================================================== */
1411
1414 if (!device || !caps)
1416 if (!g_initialized.load()) {
1417 g_last_error_details = "Library not initialized";
1419 }
1420
1421 try {
1422 const duvc::Device *cpp_device =
1423 reinterpret_cast<const duvc::Device *>(device);
1424 auto result = duvc::get_device_capabilities(*cpp_device);
1425 if (!result.is_ok()) {
1426 return handle_cpp_result(result);
1427 }
1428
1429 std::lock_guard lock(g_capabilities_mutex);
1430 auto stored_caps =
1431 std::make_unique<duvc::DeviceCapabilities>(std::move(result.value()));
1433 reinterpret_cast<duvc_device_capabilities_t *>(stored_caps.get());
1434 g_capabilities_storage.push_back(std::move(stored_caps));
1435 *caps = handle;
1436
1437 return DUVC_SUCCESS;
1438 } catch (const std::exception &e) {
1439 g_last_error_details =
1440 std::string("Failed to get device capabilities: ") + e.what();
1442 }
1443}
1444
1448 if (device_index < 0 || !caps)
1450 if (!g_initialized.load()) {
1451 g_last_error_details = "Library not initialized";
1453 }
1454
1455 try {
1456 auto result = duvc::get_device_capabilities(device_index);
1457 if (!result.is_ok()) {
1458 return handle_cpp_result(result);
1459 }
1460
1461 std::lock_guard lock(g_capabilities_mutex);
1462 auto stored_caps =
1463 std::make_unique<duvc::DeviceCapabilities>(std::move(result.value()));
1465 reinterpret_cast<duvc_device_capabilities_t *>(stored_caps.get());
1466 g_capabilities_storage.push_back(std::move(stored_caps));
1467 *caps = handle;
1468
1469 return DUVC_SUCCESS;
1470 } catch (const std::exception &e) {
1471 g_last_error_details =
1472 std::string("Failed to get device capabilities by index: ") + e.what();
1474 }
1475}
1476
1478 if (!caps || !g_initialized.load()) {
1479 return;
1480 }
1481
1482 try {
1483 std::lock_guard lock(g_capabilities_mutex);
1484 auto it = std::find_if(
1485 g_capabilities_storage.begin(), g_capabilities_storage.end(),
1486 [caps](const std::unique_ptr<duvc::DeviceCapabilities> &ptr) {
1487 return reinterpret_cast<duvc_device_capabilities_t *>(ptr.get()) ==
1488 caps;
1489 });
1490
1491 if (it != g_capabilities_storage.end()) {
1492 g_capabilities_storage.erase(it);
1493 }
1494 } catch (...) {
1495 // Ignore exceptions during cleanup
1496 }
1497}
1498
1501 if (!caps)
1503 if (!g_initialized.load()) {
1504 g_last_error_details = "Library not initialized";
1506 }
1507
1508 try {
1509 std::lock_guard lock(g_capabilities_mutex);
1510 duvc::DeviceCapabilities *cpp_caps =
1511 reinterpret_cast<duvc::DeviceCapabilities *>(caps);
1512 auto result = cpp_caps->refresh();
1513 return handle_cpp_result(result);
1514 } catch (const std::exception &e) {
1515 g_last_error_details =
1516 std::string("Failed to refresh device capabilities: ") + e.what();
1518 }
1519}
1520
1521/* ========================================================================
1522 * Capability Queries
1523 * ======================================================================== */
1524
1526 duvc_cam_prop_t prop,
1527 duvc_prop_range_t *range,
1528 duvc_prop_setting_t *current) {
1529 if (!caps)
1531 if (!g_initialized.load()) {
1532 g_last_error_details = "Library not initialized";
1534 }
1535
1536 try {
1537 const duvc::DeviceCapabilities *cpp_caps =
1538 reinterpret_cast<const duvc::DeviceCapabilities *>(caps);
1539 const auto &capability =
1540 cpp_caps->get_camera_capability(convert_cam_prop(prop));
1541
1542 if (!capability.supported) {
1543 g_last_error_details = "Camera property not supported";
1545 }
1546
1547 if (range) {
1548 *range = convert_prop_range_to_c(capability.range);
1549 }
1550
1551 if (current) {
1552 *current = convert_prop_setting_to_c(capability.current);
1553 }
1554
1555 return DUVC_SUCCESS;
1556 } catch (const std::exception &e) {
1557 g_last_error_details =
1558 std::string("Failed to get camera capability: ") + e.what();
1560 }
1561}
1562
1564 duvc_vid_prop_t prop,
1565 duvc_prop_range_t *range,
1566 duvc_prop_setting_t *current) {
1567 if (!caps)
1569 if (!g_initialized.load()) {
1570 g_last_error_details = "Library not initialized";
1572 }
1573
1574 try {
1575 const duvc::DeviceCapabilities *cpp_caps =
1576 reinterpret_cast<const duvc::DeviceCapabilities *>(caps);
1577 const auto &capability =
1578 cpp_caps->get_video_capability(convert_vid_prop(prop));
1579
1580 if (!capability.supported) {
1581 g_last_error_details = "Video property not supported";
1583 }
1584
1585 if (range) {
1586 *range = convert_prop_range_to_c(capability.range);
1587 }
1588
1589 if (current) {
1590 *current = convert_prop_setting_to_c(capability.current);
1591 }
1592
1593 return DUVC_SUCCESS;
1594 } catch (const std::exception &e) {
1595 g_last_error_details =
1596 std::string("Failed to get video capability: ") + e.what();
1598 }
1599}
1600
1603 duvc_cam_prop_t prop, int *supported) {
1604 if (!caps || !supported)
1606 if (!g_initialized.load()) {
1607 g_last_error_details = "Library not initialized";
1609 }
1610
1611 try {
1612 const duvc::DeviceCapabilities *cpp_caps =
1613 reinterpret_cast<const duvc::DeviceCapabilities *>(caps);
1614 *supported =
1615 cpp_caps->supports_camera_property(convert_cam_prop(prop)) ? 1 : 0;
1616 return DUVC_SUCCESS;
1617 } catch (const std::exception &e) {
1618 g_last_error_details =
1619 std::string("Failed to check camera property support: ") + e.what();
1621 }
1622}
1623
1626 duvc_vid_prop_t prop, int *supported) {
1627 if (!caps || !supported)
1629 if (!g_initialized.load()) {
1630 g_last_error_details = "Library not initialized";
1632 }
1633
1634 try {
1635 const duvc::DeviceCapabilities *cpp_caps =
1636 reinterpret_cast<const duvc::DeviceCapabilities *>(caps);
1637 *supported =
1638 cpp_caps->supports_video_property(convert_vid_prop(prop)) ? 1 : 0;
1639 return DUVC_SUCCESS;
1640 } catch (const std::exception &e) {
1641 g_last_error_details =
1642 std::string("Failed to check video property support: ") + e.what();
1644 }
1645}
1646
1649 duvc_cam_prop_t *props, size_t max_count,
1650 size_t *actual_count) {
1651 if (!caps || !actual_count)
1653 if (!g_initialized.load()) {
1654 g_last_error_details = "Library not initialized";
1656 }
1657
1658 try {
1659 const duvc::DeviceCapabilities *cpp_caps =
1660 reinterpret_cast<const duvc::DeviceCapabilities *>(caps);
1661 auto supported_props = cpp_caps->supported_camera_properties();
1662
1663 *actual_count = supported_props.size();
1664
1665 if (!props || max_count < supported_props.size()) {
1667 }
1668
1669 for (size_t i = 0; i < supported_props.size(); ++i) {
1670 props[i] =
1671 static_cast<duvc_cam_prop_t>(static_cast<int>(supported_props[i]));
1672 }
1673
1674 return DUVC_SUCCESS;
1675 } catch (const std::exception &e) {
1676 g_last_error_details =
1677 std::string("Failed to get supported camera properties: ") + e.what();
1679 }
1680}
1681
1684 duvc_vid_prop_t *props, size_t max_count,
1685 size_t *actual_count) {
1686 if (!caps || !actual_count)
1688 if (!g_initialized.load()) {
1689 g_last_error_details = "Library not initialized";
1691 }
1692
1693 try {
1694 const duvc::DeviceCapabilities *cpp_caps =
1695 reinterpret_cast<const duvc::DeviceCapabilities *>(caps);
1696 auto supported_props = cpp_caps->supported_video_properties();
1697
1698 *actual_count = supported_props.size();
1699
1700 if (!props || max_count < supported_props.size()) {
1702 }
1703
1704 for (size_t i = 0; i < supported_props.size(); ++i) {
1705 props[i] =
1706 static_cast<duvc_vid_prop_t>(static_cast<int>(supported_props[i]));
1707 }
1708
1709 return DUVC_SUCCESS;
1710 } catch (const std::exception &e) {
1711 g_last_error_details =
1712 std::string("Failed to get supported video properties: ") + e.what();
1714 }
1715}
1716
1719 int *accessible) {
1720 if (!caps || !accessible)
1722 if (!g_initialized.load()) {
1723 g_last_error_details = "Library not initialized";
1725 }
1726
1727 try {
1728 const duvc::DeviceCapabilities *cpp_caps =
1729 reinterpret_cast<const duvc::DeviceCapabilities *>(caps);
1730 *accessible = cpp_caps->is_device_accessible() ? 1 : 0;
1731 return DUVC_SUCCESS;
1732 } catch (const std::exception &e) {
1733 g_last_error_details =
1734 std::string("Failed to check device accessibility: ") + e.what();
1736 }
1737}
1738
1739/* ========================================================================
1740 * Property Range Utilities
1741 * ======================================================================== */
1742
1744 int32_t value, int *valid) {
1745 if (!range || !valid) {
1747 }
1748
1749 try {
1750 // Check if value is within min/max bounds
1751 if (value < range->min || value > range->max) {
1752 *valid = 0;
1753 return DUVC_SUCCESS;
1754 }
1755
1756 // Check if value aligns with step size
1757 if (range->step > 0) {
1758 int32_t offset = value - range->min;
1759 if (offset % range->step != 0) {
1760 *valid = 0;
1761 return DUVC_SUCCESS;
1762 }
1763 }
1764
1765 *valid = 1;
1766 return DUVC_SUCCESS;
1767 } catch (const std::exception &e) {
1768 g_last_error_details =
1769 std::string("Failed to validate property range: ") + e.what();
1771 }
1772}
1773
1775 int32_t value, int32_t *clamped_value) {
1776 if (!range || !clamped_value) {
1778 }
1779
1780 try {
1781 int32_t clamped = value;
1782
1783 // Clamp to min/max bounds
1784 if (clamped < range->min) {
1785 clamped = range->min;
1786 } else if (clamped > range->max) {
1787 clamped = range->max;
1788 }
1789
1790 // Align to step size if specified
1791 if (range->step > 0) {
1792 int32_t offset = clamped - range->min;
1793 int32_t remainder = offset % range->step;
1794 if (remainder != 0) {
1795 // Round to nearest step
1796 if (remainder < range->step / 2) {
1797 clamped -= remainder;
1798 } else {
1799 clamped += (range->step - remainder);
1800 }
1801
1802 // Ensure we didn't exceed max after rounding
1803 if (clamped > range->max) {
1804 clamped = range->max - (range->max - range->min) % range->step;
1805 }
1806 }
1807 }
1808
1809 *clamped_value = clamped;
1810 return DUVC_SUCCESS;
1811 } catch (const std::exception &e) {
1812 g_last_error_details =
1813 std::string("Failed to clamp property value: ") + e.what();
1815 }
1816}
1817
1819 int *supports_auto) {
1820 if (!range || !supports_auto) {
1822 }
1823
1824 try {
1825 // Check if the default mode is auto - this indicates auto mode support
1826 *supports_auto = (range->default_mode == DUVC_CAM_MODE_AUTO) ? 1 : 0;
1827 return DUVC_SUCCESS;
1828 } catch (const std::exception &e) {
1829 g_last_error_details =
1830 std::string("Failed to check auto mode support: ") + e.what();
1832 }
1833}
1834
1835/* ========================================================================
1836 * Error Handling and Diagnostics
1837 * ======================================================================== */
1838
1839duvc_result_t duvc_get_last_error_details(char *buffer, size_t buffer_size,
1840 size_t *required_size) {
1841 return copy_string_to_buffer(g_last_error_details, buffer, buffer_size,
1842 required_size);
1843}
1844
1845void duvc_clear_last_error(void) { g_last_error_details.clear(); }
1846
1847} // extern "C"
duvc_result_t duvc_get_multiple_video_properties(duvc_connection_t *conn, const duvc_vid_prop_t *props, duvc_prop_setting_t *settings, size_t count)
Get multiple video properties.
Definition api.cpp:1138
duvc_result_t duvc_get_supported_video_properties(const duvc_device_capabilities_t *caps, duvc_vid_prop_t *props, size_t max_count, size_t *actual_count)
Get list of supported video properties.
Definition api.cpp:1683
const char * duvc_cam_prop_to_string(duvc_cam_prop_t prop)
Convert camera property to string.
Definition api.cpp:372
duvc_result_t duvc_set_camera_property(duvc_connection_t *conn, duvc_cam_prop_t prop, const duvc_prop_setting_t *setting)
Set camera property value.
Definition api.cpp:907
duvc_result_t duvc_get_camera_property_range(duvc_connection_t *conn, duvc_cam_prop_t prop, duvc_prop_range_t *range)
Get camera property range.
Definition api.cpp:935
duvc_result_t duvc_get_video_property_range(duvc_connection_t *conn, duvc_vid_prop_t prop, duvc_prop_range_t *range)
Get video property range.
Definition api.cpp:1027
duvc_result_t duvc_get_device_capabilities(const duvc_device_t *device, duvc_device_capabilities_t **caps)
Get device capabilities snapshot.
Definition api.cpp:1412
duvc_result_t duvc_supports_camera_property(const duvc_device_capabilities_t *caps, duvc_cam_prop_t prop, int *supported)
Check if camera property is supported.
Definition api.cpp:1602
duvc_result_t duvc_set_multiple_camera_properties(duvc_connection_t *conn, const duvc_cam_prop_t *props, const duvc_prop_setting_t *settings, size_t count)
Set multiple camera properties.
Definition api.cpp:1101
duvc_result_t duvc_refresh_device_capabilities(duvc_device_capabilities_t *caps)
Refresh capabilities snapshot.
Definition api.cpp:1500
duvc_result_t duvc_is_device_connected(const duvc_device_t *device, int *connected)
Check if device is connected.
Definition api.cpp:600
void duvc_close_camera(duvc_connection_t *conn)
Close camera connection.
Definition api.cpp:838
duvc_result_t duvc_initialize(void)
Initialize library.
Definition api.cpp:261
void duvc_free_device_list(duvc_device_t **devices, size_t count)
Free device list.
Definition api.cpp:590
duvc_result_t duvc_set_log_level(duvc_log_level_t level)
Set minimum log level.
Definition api.cpp:432
duvc_result_t duvc_supports_video_property(const duvc_device_capabilities_t *caps, duvc_vid_prop_t prop, int *supported)
Check if video property is supported.
Definition api.cpp:1625
duvc_result_t duvc_device_is_valid(const duvc_device_t *device, int *valid)
Check if device is valid.
Definition api.cpp:690
duvc_result_t duvc_quick_get_camera_property(const duvc_device_t *device, duvc_cam_prop_t prop, duvc_prop_setting_t *setting)
Quick get camera property (creates temporary connection)
Definition api.cpp:1217
duvc_result_t duvc_get_camera_property(duvc_connection_t *conn, duvc_cam_prop_t prop, duvc_prop_setting_t *setting)
Get camera property value.
Definition api.cpp:875
duvc_result_t duvc_list_devices(duvc_device_t ***devices, size_t *count)
List all connected devices.
Definition api.cpp:510
void duvc_unregister_device_change_callback(void)
Unregister device change callback.
Definition api.cpp:752
const char * duvc_get_version_string(void)
Get library version string.
Definition api.cpp:236
duvc_result_t duvc_get_device_name(const duvc_device_t *device, char *buffer, size_t buffer_size, size_t *required)
Get device name.
Definition api.cpp:626
duvc_result_t duvc_log_error(const char *message)
Log error message.
Definition api.cpp:498
duvc_result_t duvc_quick_get_camera_property_range(const duvc_device_t *device, duvc_cam_prop_t prop, duvc_prop_range_t *range)
Quick get camera property range.
Definition api.cpp:1280
duvc_result_t duvc_set_multiple_video_properties(duvc_connection_t *conn, const duvc_vid_prop_t *props, const duvc_prop_setting_t *settings, size_t count)
Set multiple video properties.
Definition api.cpp:1176
duvc_result_t duvc_get_device_capabilities_by_index(int device_index, duvc_device_capabilities_t **caps)
Get device capabilities by index.
Definition api.cpp:1446
duvc_result_t duvc_log_message(duvc_log_level_t level, const char *message)
Log message at specific level.
Definition api.cpp:467
duvc_result_t duvc_get_device_id(const duvc_device_t *device, char *buffer, size_t buffer_size, size_t *required)
Get device ID.
Definition api.cpp:668
const char * duvc_cam_mode_to_string(duvc_cam_mode_t mode)
Convert camera mode to string.
Definition api.cpp:381
duvc_result_t duvc_log_info(const char *message)
Log info message.
Definition api.cpp:490
duvc_result_t duvc_open_camera(const duvc_device_t *device, duvc_connection_t **conn)
Open camera by device handle.
Definition api.cpp:806
duvc_result_t duvc_capabilities_is_device_accessible(const duvc_device_capabilities_t *caps, int *accessible)
Check if device is accessible.
Definition api.cpp:1718
duvc_result_t duvc_set_log_callback(duvc_log_callback callback, void *user_data)
Set log callback.
Definition api.cpp:406
duvc_result_t duvc_get_supported_camera_properties(const duvc_device_capabilities_t *caps, duvc_cam_prop_t *props, size_t max_count, size_t *actual_count)
Get list of supported camera properties.
Definition api.cpp:1648
duvc_result_t duvc_find_device_by_path(const char *device_path_utf8, duvc_device_t **device)
Find device by unique Windows device path.
Definition api.cpp:556
void duvc_free_device_capabilities(duvc_device_capabilities_t *caps)
Free device capabilities.
Definition api.cpp:1477
duvc_result_t duvc_prop_range_clamp(const duvc_prop_range_t *range, int32_t value, int32_t *clamped_value)
Clamp value to valid range.
Definition api.cpp:1774
duvc_result_t duvc_log_debug(const char *message)
Log debug message.
Definition api.cpp:486
#define DUVC_ABI_VERSION_STRING
Definition api.cpp:41
duvc_result_t duvc_quick_get_video_property_range(const duvc_device_t *device, duvc_vid_prop_t prop, duvc_prop_range_t *range)
Quick get video property range.
Definition api.cpp:1375
duvc_result_t duvc_set_video_property(duvc_connection_t *conn, duvc_vid_prop_t prop, const duvc_prop_setting_t *setting)
Set video property value.
Definition api.cpp:999
int duvc_camera_is_valid(const duvc_connection_t *conn)
Check if camera connection is valid.
Definition api.cpp:854
duvc_result_t duvc_get_multiple_camera_properties(duvc_connection_t *conn, const duvc_cam_prop_t *props, duvc_prop_setting_t *settings, size_t count)
Get multiple camera properties.
Definition api.cpp:1063
duvc_result_t duvc_quick_set_camera_property(const duvc_device_t *device, duvc_cam_prop_t prop, const duvc_prop_setting_t *setting)
Quick set camera property (creates temporary connection)
Definition api.cpp:1251
uint32_t duvc_get_version(void)
Get library version.
Definition api.cpp:234
void duvc_shutdown(void)
Shutdown library.
Definition api.cpp:293
duvc_result_t duvc_prop_capability_supports_auto(const duvc_prop_range_t *range, int *supports_auto)
Check if property supports auto mode.
Definition api.cpp:1818
duvc_result_t duvc_quick_get_video_property(const duvc_device_t *device, duvc_vid_prop_t prop, duvc_prop_setting_t *setting)
Quick get video property.
Definition api.cpp:1313
duvc_result_t duvc_log_warning(const char *message)
Log warning message.
Definition api.cpp:494
duvc_result_t duvc_get_video_capability(const duvc_device_capabilities_t *caps, duvc_vid_prop_t prop, duvc_prop_range_t *range, duvc_prop_setting_t *current)
Get video property capability.
Definition api.cpp:1563
duvc_result_t duvc_quick_set_video_property(const duvc_device_t *device, duvc_vid_prop_t prop, const duvc_prop_setting_t *setting)
Quick set video property.
Definition api.cpp:1347
void duvc_clear_last_error(void)
Clear last error information.
Definition api.cpp:1845
int duvc_check_abi_compatibility(uint32_t compiled_version)
Check ABI compatibility.
Definition api.cpp:238
const char * duvc_vid_prop_to_string(duvc_vid_prop_t prop)
Convert video property to string.
Definition api.cpp:377
duvc_result_t duvc_prop_range_is_valid(const duvc_prop_range_t *range, int32_t value, int *valid)
Check if value is valid for range.
Definition api.cpp:1743
duvc_result_t duvc_log_critical(const char *message)
Log critical message.
Definition api.cpp:502
duvc_result_t duvc_get_last_error_details(char *buffer, size_t buffer_size, size_t *required_size)
Get last error details.
Definition api.cpp:1839
duvc_result_t duvc_get_device_path(const duvc_device_t *device, char *buffer, size_t buffer_size, size_t *required)
Get device path.
Definition api.cpp:647
const char * duvc_error_code_to_string(duvc_result_t code)
Convert error code to string.
Definition api.cpp:341
duvc_result_t duvc_get_log_level(duvc_log_level_t *level)
Get current log level.
Definition api.cpp:449
duvc_result_t duvc_open_camera_by_index(int device_index, duvc_connection_t **conn)
Open camera by device index.
Definition api.cpp:775
duvc_result_t duvc_get_video_property(duvc_connection_t *conn, duvc_vid_prop_t prop, duvc_prop_setting_t *setting)
Get video property value.
Definition api.cpp:967
duvc_result_t duvc_register_device_change_callback(duvc_device_change_callback callback, void *user_data)
Register device change callback.
Definition api.cpp:715
duvc_result_t duvc_get_camera_capability(const duvc_device_capabilities_t *caps, duvc_cam_prop_t prop, duvc_prop_range_t *range, duvc_prop_setting_t *current)
Get camera property capability.
Definition api.cpp:1525
int duvc_is_initialized(void)
Check if library is initialized.
Definition api.cpp:335
const char * duvc_log_level_to_string(duvc_log_level_t level)
Convert log level to string.
Definition api.cpp:385
Complete C ABI for duvc-ctl with comprehensive API coverage.
duvc_result_t
Result codes for duvc operations.
Definition api.h:30
@ DUVC_ERROR_TIMEOUT
Operation timed out.
Definition api.h:42
@ DUVC_ERROR_CONNECTION_FAILED
Failed to establish device connection.
Definition api.h:41
@ DUVC_ERROR_INVALID_ARGUMENT
Invalid function argument provided.
Definition api.h:33
@ DUVC_ERROR_INVALID_VALUE
Property value out of valid range.
Definition api.h:37
@ DUVC_ERROR_NOT_IMPLEMENTED
Feature not implemented on this platform.
Definition api.h:32
@ DUVC_ERROR_DEVICE_BUSY
Device is busy or in use by another process.
Definition api.h:35
@ DUVC_ERROR_PERMISSION_DENIED
Insufficient permissions to access device.
Definition api.h:38
@ DUVC_ERROR_DEVICE_NOT_FOUND
Device not found or disconnected.
Definition api.h:34
@ DUVC_ERROR_BUFFER_TOO_SMALL
Provided buffer is too small for data.
Definition api.h:43
@ DUVC_ERROR_SYSTEM_ERROR
System/platform error occurred.
Definition api.h:40
@ DUVC_ERROR_PROPERTY_NOT_SUPPORTED
Property not supported by device.
Definition api.h:36
@ DUVC_SUCCESS
Operation completed successfully.
Definition api.h:31
duvc_vid_prop_t
Video processing properties.
Definition api.h:78
duvc_cam_prop_t
Camera control properties.
Definition api.h:49
#define DUVC_ABI_VERSION
Definition api.h:21
void(* duvc_log_callback)(duvc_log_level_t level, const char *message, void *user_data)
Log message callback.
Definition api.h:183
#define DUVC_LOG_ERROR(msg)
Definition api.h:1077
struct duvc_connection_t duvc_connection_t
Opaque camera connection handle.
Definition api.h:167
duvc_cam_mode_t
Camera control modes.
Definition api.h:94
@ DUVC_CAM_MODE_AUTO
Automatic control by camera.
Definition api.h:95
#define DUVC_LOG_WARNING(msg)
Definition api.h:1076
struct duvc_device_capabilities_t duvc_device_capabilities_t
Opaque device capabilities handle.
Definition api.h:172
struct duvc_device_t duvc_device_t
Opaque device handle.
Definition api.h:162
#define DUVC_LOG_INFO(msg)
Definition api.h:1075
duvc_log_level_t
Log levels.
Definition api.h:102
#define DUVC_LOG_CRITICAL(msg)
Definition api.h:1078
void(* duvc_device_change_callback)(int added, const char *device_path, void *user_data)
Device hotplug callback.
Definition api.h:192
#define DUVC_LOG_DEBUG(msg)
Definition api.h:1074
RAII camera handle for simplified device management.
Device capability detection and snapshots using Camera API.
RAII camera handle for simplified device management.
Definition camera.h:23
Result< void > set(CamProp prop, const PropSetting &setting)
Set camera property value.
Definition camera.cpp:62
Result< PropSetting > get(CamProp prop)
Get camera property value.
Definition camera.cpp:48
Complete device capability snapshot.
Definition capability.h:35
const PropertyCapability & get_video_capability(VidProp prop) const
Get video property capability.
std::vector< CamProp > supported_camera_properties() const
Get list of supported camera properties.
bool supports_video_property(VidProp prop) const
Check if video property is supported.
Result< void > refresh()
Refresh capability snapshot.
bool supports_camera_property(CamProp prop) const
Check if camera property is supported.
std::vector< VidProp > supported_video_properties() const
Get list of supported video properties.
const PropertyCapability & get_camera_capability(CamProp prop) const
Get camera property capability.
bool is_device_accessible() const
Check if device is connected and accessible.
Definition capability.h:93
Result type that can contain either a value or an error.
Definition result.h:75
bool is_ok() const
Check if result contains a value (success)
Definition result.h:101
const Error & error() const
Get the error (assumes error)
Definition result.h:128
Windows-specific device connection pooling.
Device enumeration and management functions.
HRESULT decoder and diagnostics utilities.
Structured logging interface for duvc-ctl.
void log_info(const std::string &message)
Log info message.
Definition logging.cpp:114
VidProp
Video processing properties (IAMVideoProcAmp interface)
Definition types.h:50
ErrorCode
Error codes for duvc operations.
Definition result.h:19
@ InvalidValue
Property value out of range.
@ InvalidArgument
Invalid function argument.
@ DeviceBusy
Device is busy or in use.
@ PermissionDenied
Insufficient permissions.
@ Success
Operation succeeded.
@ PropertyNotSupported
Property not supported by device.
@ NotImplemented
Feature not implemented on this platform.
@ SystemError
System/platform error.
@ DeviceNotFound
Device not found or disconnected.
Result< DeviceCapabilities > get_device_capabilities(const Device &device)
Create device capability snapshot.
std::vector< Device > list_devices()
Enumerate all available video input devices.
Definition core.cpp:626
void unregister_device_change_callback()
Unregister device change callback.
Definition core.cpp:537
CamMode
Property control mode.
Definition types.h:66
LogLevel
Log levels.
Definition logging.h:16
@ Info
Informational messages.
const wchar_t * to_wstring(CamProp)
Convert camera property enum to wide string.
Definition core.cpp:707
void set_log_callback(LogCallback callback)
Set global log callback.
Definition logging.cpp:73
const char * to_string(CamProp)
Convert camera property enum to string.
Definition core.cpp:678
std::string to_utf8(const std::wstring &wstr)
Converts a wide string (UTF-16 on Windows) to a UTF-8 string.
CamProp
Camera control properties (IAMCameraControl interface)
Definition types.h:18
void log_message(LogLevel level, const std::string &message)
Log a message.
Definition logging.cpp:88
bool is_device_connected(const Device &dev)
Check if a device is currently connected and accessible.
Definition core.cpp:549
void register_device_change_callback(DeviceChangeCallback callback)
Register callback for device hotplug events.
Definition core.cpp:511
Result< Camera > open_camera(int device_index)
Create camera from device index.
Definition camera.cpp:130
void set_log_level(LogLevel level)
Set minimum log level.
Definition logging.cpp:78
Device find_device_by_path(const std::wstring &device_path)
Find device by unique Windows device path.
Definition device.cpp:211
LogLevel get_log_level()
Get current minimum log level.
Definition logging.cpp:83
Result/Error type system for duvc-ctl.
String conversion utilities for enums and types.
Represents a camera device.
Definition types.h:131
std::wstring path
Unique device path/identifier.
Definition types.h:133
std::wstring name
Human-readable device name.
Definition types.h:132
bool is_valid() const
Check if device has valid identifying information.
Definition types.h:186
Property range and default information.
Definition types.h:92
int default_val
Default value.
Definition types.h:96
int min
Minimum supported value.
Definition types.h:93
int step
Step size between valid values.
Definition types.h:95
int max
Maximum supported value.
Definition types.h:94
CamMode default_mode
Default control mode.
Definition types.h:97
Property setting with value and control mode.
Definition types.h:74
int value
Property value.
Definition types.h:75
CamMode mode
Control mode (auto/manual)
Definition types.h:76
Property range information.
Definition api.h:140
int32_t max
Maximum supported value.
Definition api.h:142
duvc_cam_mode_t default_mode
Default control mode.
Definition api.h:145
int32_t step
Step size between valid values.
Definition api.h:143
int32_t min
Minimum supported value.
Definition api.h:141
int32_t default_val
Default value.
Definition api.h:144
Property setting with value and mode.
Definition api.h:132
duvc_cam_mode_t mode
Control mode (auto/manual)
Definition api.h:134
int32_t value
Property value.
Definition api.h:133
Core data types and enumerations for duvc-ctl.