1 // License: Apache 2.0. See LICENSE file in root directory.
2 // Copyright(c) 2015 Intel Corporation. All Rights Reserved.
3 
4 #include "device.h"
5 #include "sync.h"
6 
7 using namespace rsimpl;
8 
rs_device(std::shared_ptr<rsimpl::uvc::device> device,const rsimpl::static_device_info & info)9 rs_device::rs_device(std::shared_ptr<rsimpl::uvc::device> device, const rsimpl::static_device_info & info) : device(device), config(info), capturing(false),
10     depth(config, RS_STREAM_DEPTH), color(config, RS_STREAM_COLOR), infrared(config, RS_STREAM_INFRARED), infrared2(config, RS_STREAM_INFRARED2),
11     points(depth), rect_color(color), color_to_depth(color, depth), depth_to_color(depth, color), depth_to_rect_color(depth, rect_color), infrared2_to_depth(infrared2,depth), depth_to_infrared2(depth,infrared2)
12 {
13     streams[RS_STREAM_DEPTH    ] = native_streams[RS_STREAM_DEPTH]     = &depth;
14     streams[RS_STREAM_COLOR    ] = native_streams[RS_STREAM_COLOR]     = &color;
15     streams[RS_STREAM_INFRARED ] = native_streams[RS_STREAM_INFRARED]  = &infrared;
16     streams[RS_STREAM_INFRARED2] = native_streams[RS_STREAM_INFRARED2] = &infrared2;
17     streams[RS_STREAM_POINTS]                                          = &points;
18     streams[RS_STREAM_RECTIFIED_COLOR]                                 = &rect_color;
19     streams[RS_STREAM_COLOR_ALIGNED_TO_DEPTH]                          = &color_to_depth;
20     streams[RS_STREAM_DEPTH_ALIGNED_TO_COLOR]                          = &depth_to_color;
21     streams[RS_STREAM_DEPTH_ALIGNED_TO_RECTIFIED_COLOR]                = &depth_to_rect_color;
22     streams[RS_STREAM_INFRARED2_ALIGNED_TO_DEPTH]                      = &infrared2_to_depth;
23     streams[RS_STREAM_DEPTH_ALIGNED_TO_INFRARED2]                      = &depth_to_infrared2;
24 }
25 
~rs_device()26 rs_device::~rs_device()
27 {
28 
29 }
30 
supports_option(rs_option option) const31 bool rs_device::supports_option(rs_option option) const
32 {
33     if(uvc::is_pu_control(option)) return true;
34     for(auto & o : config.info.options) if(o.option == option) return true;
35     return false;
36 }
37 
enable_stream(rs_stream stream,int width,int height,rs_format format,int fps)38 void rs_device::enable_stream(rs_stream stream, int width, int height, rs_format format, int fps)
39 {
40     if(capturing) throw std::runtime_error("streams cannot be reconfigured after having called rs_start_device()");
41     if(config.info.stream_subdevices[stream] == -1) throw std::runtime_error("unsupported stream");
42 
43     config.requests[stream] = {true, width, height, format, fps};
44     for(auto & s : native_streams) s->archive.reset(); // Changing stream configuration invalidates the current stream info
45 }
46 
enable_stream_preset(rs_stream stream,rs_preset preset)47 void rs_device::enable_stream_preset(rs_stream stream, rs_preset preset)
48 {
49     if(capturing) throw std::runtime_error("streams cannot be reconfigured after having called rs_start_device()");
50     if(!config.info.presets[stream][preset].enabled) throw std::runtime_error("unsupported stream");
51 
52     config.requests[stream] = config.info.presets[stream][preset];
53     for(auto & s : native_streams) s->archive.reset(); // Changing stream configuration invalidates the current stream info
54 }
55 
disable_stream(rs_stream stream)56 void rs_device::disable_stream(rs_stream stream)
57 {
58     if(capturing) throw std::runtime_error("streams cannot be reconfigured after having called rs_start_device()");
59     if(config.info.stream_subdevices[stream] == -1) throw std::runtime_error("unsupported stream");
60 
61     config.requests[stream] = {};
62     for(auto & s : native_streams) s->archive.reset(); // Changing stream configuration invalidates the current stream info
63 }
64 
start()65 void rs_device::start()
66 {
67     if(capturing) throw std::runtime_error("cannot restart device without first stopping device");
68 
69     auto selected_modes = config.select_modes();
70     auto archive = std::make_shared<frame_archive>(selected_modes, select_key_stream(selected_modes));
71     auto timestamp_reader = create_frame_timestamp_reader();
72 
73     for(auto & s : native_streams) s->archive.reset(); // Starting capture invalidates the current stream info, if any exists from previous capture
74 
75     // Satisfy stream_requests as necessary for each subdevice, calling set_mode and
76     // dispatching the uvc configuration for a requested stream to the hardware
77     for(auto mode_selection : selected_modes)
78     {
79         // Create a stream buffer for each stream served by this subdevice mode
80         for(auto & stream_mode : mode_selection.get_outputs())
81         {
82             // If this is one of the streams requested by the user, store the buffer so they can access it
83             if(config.requests[stream_mode.first].enabled) native_streams[stream_mode.first]->archive = archive;
84         }
85 
86         // Initialize the subdevice and set it to the selected mode
87         set_subdevice_mode(*device, mode_selection.mode.subdevice, mode_selection.mode.native_dims.x, mode_selection.mode.native_dims.y, mode_selection.mode.pf.fourcc, mode_selection.mode.fps,
88             [mode_selection, archive, timestamp_reader](const void * frame) mutable
89         {
90             // Ignore any frames which appear corrupted or invalid
91             if(!timestamp_reader->validate_frame(mode_selection.mode, frame)) return;
92 
93             // Determine the timestamp for this frame
94             int timestamp = timestamp_reader->get_frame_timestamp(mode_selection.mode, frame);
95 
96             // Obtain buffers for unpacking the frame
97             std::vector<byte *> dest;
98             for(auto & output : mode_selection.get_outputs()) dest.push_back(archive->alloc_frame(output.first, timestamp));
99 
100             // Unpack the frame and commit it to the archive
101             mode_selection.unpack(dest.data(), reinterpret_cast<const byte *>(frame));
102             for(auto & output : mode_selection.get_outputs()) archive->commit_frame(output.first);
103         });
104     }
105 
106     this->archive = archive;
107     on_before_start(selected_modes);
108     start_streaming(*device, config.info.num_libuvc_transfer_buffers);
109     capture_started = std::chrono::high_resolution_clock::now();
110     capturing = true;
111 }
112 
stop()113 void rs_device::stop()
114 {
115     if(!capturing) throw std::runtime_error("cannot stop device without first starting device");
116     stop_streaming(*device);
117     capturing = false;
118 }
119 
wait_all_streams()120 void rs_device::wait_all_streams()
121 {
122     if(!capturing) return;
123     if(!archive) return;
124 
125     archive->wait_for_frames();
126 }
127 
poll_all_streams()128 bool rs_device::poll_all_streams()
129 {
130     if(!capturing) return false;
131     if(!archive) return false;
132     return archive->poll_for_frames();
133 }
134 
get_option_range(rs_option option,double & min,double & max,double & step)135 void rs_device::get_option_range(rs_option option, double & min, double & max, double & step)
136 {
137     if(uvc::is_pu_control(option))
138     {
139         int mn, mx;
140         uvc::get_pu_control_range(get_device(), config.info.stream_subdevices[RS_STREAM_COLOR], option, &mn, &mx);
141         min = mn;
142         max = mx;
143         step = 1;
144         return;
145     }
146 
147     for(auto & o : config.info.options)
148     {
149         if(o.option == option)
150         {
151             min = o.min;
152             max = o.max;
153             step = o.step;
154             return;
155         }
156     }
157 
158     throw std::logic_error("range not specified");
159 }
160