recorder.cpp
Go to the documentation of this file.
1 // License: Apache 2.0. See LICENSE file in root directory.
2 // Copyright(c) 2015 Intel Corporation. All Rights Reserved.
3 
4 #include "recorder.h"
5 #include <fstream>
6 #include "sql.h"
7 #include <algorithm>
8 #include "types.h"
9 #include <iostream>
10 
11 using namespace std;
12 using namespace sql;
13 
14 const char* CONFIG_TABLE = "rs_config";
15 const char* CONFIG_QUERY = "SELECT value FROM rs_config WHERE section = ? AND key = ?";
16 const char* CONFIG_CREATE = "CREATE TABLE rs_config(section NUMBER, key TEXT, value TEXT)";
17 const char* CONFIG_INSERT = "INSERT OR REPLACE INTO rs_config(section, key, value) VALUES(?, ?, ?)";
18 const char* API_VERSION_KEY = "api_version";
19 const char* CREATED_AT_KEY = "created_at";
20 
21 const char* SECTIONS_TABLE = "rs_sections";
22 const char* SECTIONS_SELECT_MAX_ID = "SELECT max(key) from rs_sections";
23 const char* SECTIONS_CREATE = "CREATE TABLE rs_sections(key NUMBER PRIMARY KEY, name TEXT)";
24 const char* SECTIONS_INSERT = "INSERT INTO rs_sections(key, name) VALUES (?, ?)";
25 const char* SECTIONS_COUNT_BY_NAME = "SELECT COUNT(*) FROM rs_sections WHERE name = ?";
26 const char* SECTIONS_COUNT_ALL = "SELECT COUNT(*) FROM rs_sections";
27 const char* SECTIONS_FIND_BY_NAME = "SELECT key FROM rs_sections WHERE name = ?";
28 
29 const char* CALLS_CREATE = "CREATE TABLE rs_calls(section NUMBER, type NUMBER, timestamp NUMBER, entity_id NUMBER, txt TEXT, param1 NUMBER, param2 NUMBER, param3 NUMBER, param4 NUMBER, param5 NUMBER, param6 NUMBER, had_errors NUMBER, param7 NUMBER, param8 NUMBER, param9 NUMBER, param10 NUMBER, param11 NUMBER, param12 NUMBER)";
30 const char* CALLS_INSERT = "INSERT INTO rs_calls(section, type, timestamp, entity_id, txt, param1, param2, param3, param4, param5, param6, had_errors, param7, param8, param9, param10, param11, param12) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?, ?, ?, ?, ?, ?,?)";
31 const char* CALLS_SELECT_ALL = "SELECT * FROM rs_calls WHERE section = ?";
32 
33 const char* DEVICE_INFO_CREATE = "CREATE TABLE rs_device_info(section NUMBER, type NUMBER, id TEXT, uid TEXT, pid NUMBER, vid NUMBER, mi NUMBER)";
34 const char* DEVICE_INFO_SELECT_ALL = "SELECT * FROM rs_device_info WHERE section = ?";
35 const char* DEVICE_INFO_INSERT = "INSERT INTO rs_device_info(section, type, id, uid, pid, vid, mi) VALUES(?, ?, ?, ?, ?, ?, ?)";
36 
37 const char* BLOBS_CREATE = "CREATE TABLE rs_blobs(section NUMBER, data BLOB)";
38 const char* BLOBS_INSERT = "INSERT INTO rs_blobs(section, data) VALUES(?, ?)";
39 const char* BLOBS_SELECT_ALL = "SELECT * FROM rs_blobs WHERE section = ?";
40 
41 const char* PROFILES_CREATE = "CREATE TABLE rs_profile(section NUMBER, width NUMBER, height NUMBER, fps NUMBER, fourcc NUMBER)";
42 const char* PROFILES_INSERT = "INSERT INTO rs_profile(section, width, height, fps, fourcc) VALUES(?, ? ,? ,? ,?)";
43 const char* PROFILES_SELECT_ALL = "SELECT * FROM rs_profile WHERE section = ?";
44 
45 namespace librealsense
46 {
47  namespace platform
48  {
50  {
51  public:
52  playback_backend_exception(const std::string& msg, call_type t, int entity_id) noexcept
53  : backend_exception(generate_message(msg, t, entity_id), RS2_EXCEPTION_TYPE_BACKEND)
54  {}
55  private:
56  std::string generate_message(const std::string& msg, call_type t, int entity_id) const
57  {
58  std::stringstream s;
59  s << msg << " call type: " << int(t) << " entity " << entity_id;
60  return s.str();
61  }
62  };
63 
64  enum class device_type
65  {
66  uvc,
67  usb,
68  hid,
69  hid_sensor,
70  hid_input
71  };
72 
74  {
75  union {
76  uint32_t block;
77  uint8_t bytes[4];
78  } xu;
79  union {
80  uint32_t block;
81  uint8_t bytes[4];
82  } yu;
83  xu.block = x;
84  yu.block = y;
85  auto diff_sum = 0;
86  for (auto i = 0; i < 4; i++)
87  {
88  auto dist = abs(xu.bytes[i] - yu.bytes[i]);
89  diff_sum += dist * dist;
90  }
91  return diff_sum;
92  }
93 
94  vector<uint8_t> compression_algorithm::decode(const vector<uint8_t>& input) const
95  {
96  vector<uint8_t> results;
97  for (size_t i = 0; i < input.size() - 5; i += 5)
98  {
99  union {
100  uint32_t block;
101  uint8_t bytes[4];
102  } curr_block;
103 
104  curr_block.block = *reinterpret_cast<const uint32_t*>(input.data() + i);
105  auto len = input[i + 4];
106  for (auto j = 0; j < len * 4; j++)
107  {
108  results.push_back(curr_block.bytes[j % 4]);
109  }
110  }
111  return results;
112  }
113 
114  vector<uint8_t> compression_algorithm::encode(uint8_t* data, size_t size) const
115  {
116  vector<uint8_t> results;
117  union {
118  uint32_t block;
119  uint8_t bytes[4];
120  } curr_block;
121  curr_block.block = *reinterpret_cast<const uint32_t*>(data);
122  uint8_t length = 0;
123  for (size_t i = 0; i < size; i += 4)
124  {
125  auto block = *reinterpret_cast<const uint32_t*>(data + i);
126  if (dist(block, curr_block.block) < min_dist && length < max_length)
127  {
128  length++;
129  }
130  else
131  {
132  for (auto j = 0; j < 4; j++)
133  results.push_back(curr_block.bytes[j]);
134  results.push_back(length);
135  curr_block.block = block;
136  length = 1;
137  }
138  }
139  if (length)
140  {
141  for (auto j = 0; j < 4; j++)
142  results.push_back(curr_block.bytes[j]);
143  results.push_back(length);
144  }
145  return results;
146  }
147 
148  recording::recording(std::shared_ptr<time_service> ts, std::shared_ptr<playback_device_watcher> watcher)
149  :_ts(ts), _watcher(watcher)
150  {
151  }
152 
154  {
155  call* next;
156  do
157  {
158  backend_device_group old, curr;
160  load_device_changed_data(old, curr, k);
161  _watcher->raise_callback(old, curr);
162  next = pick_next_call();
163  } while (next && next->type == call_type::device_watcher_event);
164  }
165 
167  {
168  return _curr_time;
169  }
170 
171  void recording::save(const char* filename, const char* section, bool append) const
172  {
173  connection c(filename);
174  LOG_WARNING("Saving recording to file, don't close the application");
175 
176  if (!c.table_exists(CONFIG_TABLE))
177  {
184  }
185 
186  auto section_id = 0;
187 
188  if (!append)
189  {
190  {
191  statement check_section_unique(c, SECTIONS_COUNT_BY_NAME);
192  check_section_unique.bind(1, section);
193  auto result = check_section_unique();
194  if (result[0].get_int() > 0)
195  {
196  throw runtime_error(to_string() << "Append record - can't save over existing section in file " << filename << "!");
197  }
198  }
199 
200  {
201  statement max_section_id(c, SECTIONS_COUNT_ALL);
202  auto result = max_section_id();
203  section_id = result[0].get_int() + 1;
204  }
205 
206  {
207  statement create_section(c, SECTIONS_INSERT);
208  create_section.bind(1, section_id);
209  create_section.bind(2, section);
210  create_section();
211  }
212  }
213  else
214  {
215  {
216  statement check_section_exists(c, SECTIONS_COUNT_BY_NAME);
217  check_section_exists.bind(1, section);
218  auto result = check_section_exists();
219  if (result[0].get_int() == 0)
220  {
221  throw runtime_error(to_string() << "Append record - Could not find section " << section << " in file " << filename << "!");
222  }
223  }
224  {
225  statement find_section_id(c, SECTIONS_FIND_BY_NAME);
226  find_section_id.bind(1, section);
227  auto result = find_section_id();
228  section_id = result[0].get_int();
229  }
230  }
231 
232  if (!append)
233  {
234  {
235  statement insert(c, CONFIG_INSERT);
236  insert.bind(1, section_id);
237  insert.bind(2, API_VERSION_KEY);
238  insert.bind(3, RS2_API_VERSION_STR);
239  insert();
240  }
241 
242  {
243  statement insert(c, CONFIG_INSERT);
244  insert.bind(1, section_id);
245  insert.bind(2, CREATED_AT_KEY);
246  auto datetime = datetime_string();
247  insert.bind(3, datetime.c_str());
248  insert();
249  }
250  }
251 
252  c.transaction([&]()
253  {
254  for (auto&& cl : calls)
255  {
256  statement insert(c, CALLS_INSERT);
257  insert.bind(1, section_id);
258  insert.bind(2, static_cast<int>(cl.type));
259  insert.bind(3, cl.timestamp);
260  insert.bind(4, cl.entity_id);
261  insert.bind(5, cl.inline_string.c_str());
262  insert.bind(6, cl.param1);
263  insert.bind(7, cl.param2);
264  insert.bind(8, cl.param3);
265  insert.bind(9, cl.param4);
266  insert.bind(10, cl.param5);
267  insert.bind(11, cl.param6);
268  insert.bind(12, cl.had_error ? 1 : 0);
269  insert.bind(13, cl.param7);
270  insert.bind(14, cl.param8);
271  insert.bind(15, cl.param9);
272  insert.bind(16, cl.param10);
273  insert.bind(17, cl.param11);
274  insert.bind(18, cl.param12);
275 
276  insert();
277  }
278 
279  for (auto&& uvc_info : uvc_device_infos)
280  {
281  statement insert(c, DEVICE_INFO_INSERT);
282  insert.bind(1, section_id);
283  insert.bind(2, (int)device_type::uvc);
284  insert.bind(3, "");
285  insert.bind(4, uvc_info.unique_id.c_str());
286  insert.bind(5, (int)uvc_info.pid);
287  insert.bind(6, (int)uvc_info.vid);
288  insert.bind(7, (int)uvc_info.mi);
289  insert();
290  }
291 
292  for (auto&& usb_info : usb_device_infos)
293  {
294  statement insert(c, DEVICE_INFO_INSERT);
295  insert.bind(1, section_id);
296  insert.bind(2, (int)device_type::usb);
297  string id(usb_info.id.begin(), usb_info.id.end());
298  insert.bind(3, id.c_str());
299  insert.bind(4, usb_info.unique_id.c_str());
300  insert.bind(5, (int)usb_info.pid);
301  insert.bind(6, (int)usb_info.vid);
302  insert.bind(7, (int)usb_info.mi);
303  insert();
304  }
305 
306  for (auto&& hid_info : hid_device_infos)
307  {
308  statement insert(c, DEVICE_INFO_INSERT);
309  insert.bind(1, section_id);
310  insert.bind(2, (int)device_type::hid);
311  insert.bind(3, hid_info.id.c_str());
312  insert.bind(4, hid_info.unique_id.c_str());
313 
314  stringstream ss_vid(hid_info.vid);
315  stringstream ss_pid(hid_info.pid);
316  uint32_t vid, pid;
317  ss_vid >> hex >> vid;
318  ss_pid >> hex >> pid;
319 
320  insert.bind(5, (int)pid);
321  insert.bind(6, (int)vid);
322  insert.bind(7, hid_info.device_path.c_str());
323  insert();
324  }
325 
326  for (auto&& hid_info : hid_sensors)
327  {
328  statement insert(c, DEVICE_INFO_INSERT);
329  insert.bind(1, section_id);
330  insert.bind(2, (int)device_type::hid_sensor);
331  insert.bind(3, hid_info.name.c_str());
332  insert.bind(4, "");
333  insert();
334  }
335 
336  for (auto&& hid_info : hid_sensor_inputs)
337  {
338  statement insert(c, DEVICE_INFO_INSERT);
339  insert.bind(1, section_id);
340  insert.bind(2, (int)device_type::hid_input);
341  insert.bind(3, hid_info.name.c_str());
342  insert.bind(4, "");
343  insert();
344  }
345 
346  for (auto&& profile : this->stream_profiles)
347  {
348  statement insert(c, PROFILES_INSERT);
349  insert.bind(1, section_id);
350  insert.bind(2, (int)profile.width);
351  insert.bind(3, (int)profile.height);
352  insert.bind(4, (int)profile.fps);
353  insert.bind(5, (int)profile.format);
354  insert();
355  }
356 
357  for (auto&& blob : blobs)
358  {
359  statement insert(c, BLOBS_INSERT);
360  insert.bind(1, section_id);
361  insert.bind(2, blob);
362  insert();
363  }
364  });
365  }
366 
367  static bool is_heighr_or_equel_to_min_version(std::string api_version, std::string min_api_version)
368  {
369  const int ver_size = 3;
370  int section_version[ver_size] = { -1, -1, -1 };
371  int min_version[ver_size] = { -1 ,-1 , -1 };
372  std::sscanf(api_version.c_str(), "%d.%d.%d", &section_version[0], &section_version[1], &section_version[2]);
373  std::sscanf(min_api_version.c_str(), "%d.%d.%d", &min_version[0], &min_version[1], &min_version[2]);
374  for (int i = 0; i < ver_size; i++)
375  {
376  if(min_version[i] < 0)
377  throw runtime_error(to_string() << "Minimum provided version is in wrong format, expexted format: 0.0.0, actual string: " << min_api_version);
378  if (section_version[i] == min_version[i]) continue;
379  if (section_version[i] > min_version[i]) continue;
380  if (section_version[i] < min_version[i]) return false;
381  }
382  return true;
383  }
384 
385  shared_ptr<recording> recording::load(const char* filename, const char* section, std::shared_ptr<playback_device_watcher> watcher, std::string min_api_version)
386  {
387  if (!file_exists(filename))
388  {
389  throw runtime_error("Recording file not found!");
390  }
391 
392  auto result = make_shared<recording>(nullptr, watcher);
393 
394  connection c(filename);
395 
396  if (!c.table_exists(CONFIG_TABLE))
397  {
398  throw runtime_error("Invalid recording, missing config section!");
399  }
400 
401  int section_id = 0;
402 
403  {
404  statement check_section_exists(c, SECTIONS_COUNT_BY_NAME);
405  check_section_exists.bind(1, section);
406  auto result = check_section_exists();
407  if (result[0].get_int() == 0)
408  {
409  throw runtime_error(to_string() << "Could not find section " << section << "!");
410  }
411  }
412  {
413  statement find_section_id(c, SECTIONS_FIND_BY_NAME);
414  find_section_id.bind(1, section);
415  auto result = find_section_id();
416  section_id = result[0].get_int();
417  }
418 
419  {
420  statement select_api_version(c, CONFIG_QUERY);
421  select_api_version.bind(1, section_id);
422  select_api_version.bind(2, API_VERSION_KEY);
423  auto api_version = select_api_version()[0].get_string();
424  if(is_heighr_or_equel_to_min_version(api_version, min_api_version) == false)
425  throw runtime_error(to_string() << "File version is lower than the minimum required version that was defind by the test, file version: " <<
426  api_version << " min version: " << min_api_version);
427  LOG_WARNING("Loaded recording from API version " << api_version);
428  }
429 
430  statement select_calls(c, CALLS_SELECT_ALL);
431  select_calls.bind(1, section_id);
432 
433  result->calls.push_back(call());
434 
435  for (auto&& row : select_calls)
436  {
437  call cl;
438  cl.type = static_cast<call_type>(row[1].get_int());
439  cl.timestamp = row[2].get_double();
440  cl.entity_id = row[3].get_int();
441  cl.inline_string = row[4].get_string();
442  cl.param1 = row[5].get_int();
443  cl.param2 = row[6].get_int();
444  cl.param3 = row[7].get_int();
445  cl.param4 = row[8].get_int();
446  cl.param5 = row[9].get_int();
447  cl.param6 = row[10].get_int();
448  cl.had_error = row[11].get_int() > 0;
449  cl.param7 = row[12].get_int();
450  cl.param8 = row[13].get_int();
451  cl.param9 = row[14].get_int();
452  cl.param10 = row[15].get_int();
453  cl.param11 = row[16].get_int();
454  cl.param12 = row[17].get_int();
455 
456 
457  result->calls.push_back(cl);
458  result->_curr_time = cl.timestamp;
459  }
460 
461  statement select_devices(c, DEVICE_INFO_SELECT_ALL);
462  select_devices.bind(1, section_id);
463  for (auto&& row : select_devices)
464  {
465  if (row[1].get_int() == (int)device_type::usb)
466  {
468  info.id = row[2].get_string();
469  info.unique_id = row[3].get_string();
470  info.pid = row[4].get_int();
471  info.vid = row[5].get_int();
472  info.mi = row[6].get_int();
473  result->usb_device_infos.push_back(info);
474  }
475  else if (row[1].get_int() == (int)device_type::uvc)
476  {
478  info.unique_id = row[3].get_string();
479  info.pid = row[4].get_int();
480  info.vid = row[5].get_int();
481  info.mi = row[6].get_int();
482  result->uvc_device_infos.push_back(info);
483  }
484  else if (row[1].get_int() == (int)device_type::hid)
485  {
487  info.id = row[2].get_string();
488  info.unique_id = row[3].get_string();
489  info.pid = to_string() << row[4].get_int();
490  info.vid = to_string() << row[5].get_int();
491  info.device_path = row[6].get_string();
492 
493  result->hid_device_infos.push_back(info);
494  }
495  else if (row[1].get_int() == (int)device_type::hid_sensor)
496  {
498  info.name = row[2].get_string();
499 
500  result->hid_sensors.push_back(info);
501  }
502  else if (row[1].get_int() == (int)device_type::hid_input)
503  {
505  info.name = row[2].get_string();
506  info.index = row[4].get_int();
507 
508  result->hid_sensor_inputs.push_back(info);
509  }
510  }
511 
512  statement select_profiles(c, PROFILES_SELECT_ALL);
513  select_profiles.bind(1, section_id);
514  for (auto&& row : select_profiles)
515  {
517  p.width = row[1].get_int();
518  p.height = row[2].get_int();
519  p.fps = row[3].get_int();
520  p.format = row[4].get_int();
521  result->stream_profiles.push_back(p);
522  }
523 
524  statement select_blobs(c, BLOBS_SELECT_ALL);
525  select_blobs.bind(1, section_id);
526 
527  for (auto&& row : select_blobs)
528  {
529  result->blobs.push_back(row[1].get_blob());
530  }
531 
532  return result;
533  }
534 
535  int recording::save_blob(const void* ptr, size_t size)
536  {
537  lock_guard<recursive_mutex> lock(_mutex);
538  vector<uint8_t> holder;
539  holder.resize(size);
540  librealsense::copy(holder.data(), ptr, size);
541  auto id = static_cast<int>(blobs.size());
542  blobs.push_back(holder);
543  return id;
544  }
545 
547  {
548  return _ts->get_time();
549  }
550 
551  call& recording::find_call(call_type t, int entity_id, std::function<bool(const call& c)> history_match_validation)
552  {
553  lock_guard<recursive_mutex> lock(_mutex);
554 
555 
556  for (size_t i = 1; i <= calls.size(); i++)
557  {
558  const auto idx = (_cursors[entity_id] + i) % static_cast<int>(calls.size());
559  if (calls[idx].type == t && calls[idx].entity_id == entity_id)
560  {
561  if (calls[idx].had_error)
562  {
563  throw runtime_error(calls[idx].inline_string);
564  }
565  _curr_time = calls[idx].timestamp;
566 
567  if (!history_match_validation(calls[idx]))
568  {
569  throw playback_backend_exception("Recording history mismatch!", t, entity_id);
570  }
571 
572  _cursors[entity_id] = _cycles[entity_id] = idx;
573 
574  auto next = pick_next_call();
576  {
578  }
579  return calls[idx];
580  }
581  }
582  throw runtime_error("The recording is missing the part you are trying to playback!");
583  }
584 
586  {
587  lock_guard<recursive_mutex> lock(_mutex);
588  const auto idx = (_cycles[id] + 1) % static_cast<int>(calls.size());
589  return &calls[idx];
590  }
591 
593  {
594 
595  lock_guard<recursive_mutex> lock(_mutex);
596  auto&& next = pick_next_call();
597  if (next && next->type == call_type::device_watcher_event)
598  {
600  }
601 
602  for (size_t i = 1; i <= calls.size(); i++)
603  {
604  const auto idx = (_cycles[id] + i);
605  if (idx >= calls.size())
606  {
607  _cycles[id] = _cursors[id];
608  return nullptr;
609  }
610 
611  if (calls[idx].type == t && calls[idx].entity_id == id)
612  {
613  _cycles[id] = idx;
614  _curr_time = calls[idx].timestamp;
615  return &calls[idx];
616  }
617  if (calls[idx].type != t && calls[idx].entity_id == id)
618  {
619  _cycles[id] = _cursors[id];
620  return nullptr;
621  }
622  }
623  return nullptr;
624  }
625 
627  {
628  _owner->try_record([=](recording* rec1, lookup_key key1)
629  {
630  _source_watcher->start([=](backend_device_group old, backend_device_group curr)
631  {
632  _owner->try_record([=](recording* rec1, lookup_key key1)
633  {
634  rec1->save_device_changed_data(old, curr, key1);
635  callback(old, curr);
636 
637  }, _entity_id, call_type::device_watcher_event);
638  });
639 
640  }, _entity_id, call_type::device_watcher_start);
641  }
642 
644  {
645  _owner->try_record([&](recording* rec1, lookup_key key1)
646  {
647  _source_watcher->stop();
648 
649  }, _entity_id, call_type::device_watcher_stop);
650  }
651 
652 
654  {
655  _owner->try_record([this, callback, profile](recording* rec, lookup_key k)
656  {
657  _source->probe_and_commit(profile, [this, callback](stream_profile p, frame_object f, std::function<void()> continuation)
658  {
659  _owner->try_record([this, callback, p, &f, continuation](recording* rec1, lookup_key key1)
660  {
661  auto&& c = rec1->add_call(key1);
662  c.param1 = rec1->save_blob(&p, sizeof(p));
663 
664  if (_owner->get_mode() == RS2_RECORDING_MODE_BEST_QUALITY)
665  {
666  c.param2 = rec1->save_blob(f.pixels, static_cast<int>(f.frame_size));
667  c.param4 = static_cast<int>(f.frame_size);
668  c.param3 = 1;
669  }
670  else if (_owner->get_mode() == RS2_RECORDING_MODE_BLANK_FRAMES)
671  {
672  c.param2 = -1;
673  c.param4 = static_cast<int>(f.frame_size);
674  c.param3 = 0;
675  }
676  else
677  {
678  auto compressed = _compression->encode((uint8_t*)f.pixels, f.frame_size);
679  c.param2 = rec1->save_blob(compressed.data(), static_cast<int>(compressed.size()));
680  c.param4 = static_cast<int>(compressed.size());
681  c.param3 = 2;
682  }
683 
684  c.param5 = rec1->save_blob(f.metadata, static_cast<int>(f.metadata_size));
685  c.param6 = static_cast<int>(f.metadata_size);
686  callback(p, f, continuation);
687  }, _entity_id, call_type::uvc_frame);
688  });
689 
690  vector<stream_profile> ps{ profile };
691  rec->save_stream_profiles(ps, k);
692 
693  }, _entity_id, call_type::uvc_probe_commit);
694  }
695 
696  void record_uvc_device::stream_on(std::function<void(const notification& n)> error_handler)
697  {
698  _owner->try_record([&](recording* rec, lookup_key k)
699  {
700  _source->stream_on();
701  rec->add_call(k);
702  }, _entity_id, call_type::uvc_play);
703  }
704 
706  {
707  _owner->try_record([&](recording* rec, lookup_key k)
708  {
709  _source->start_callbacks();
710  rec->add_call(k);
711  }, _entity_id, call_type::uvc_start_callbacks);
712  }
713 
715  {
716  _owner->try_record([&](recording* rec, lookup_key k)
717  {
718  _source->stop_callbacks();
719  rec->add_call(k);
720  }, _entity_id, call_type::uvc_stop_callbacks);
721  }
722 
724  {
725  _owner->try_record([&](recording* rec, lookup_key k)
726  {
727  _source->close(profile);
728  vector<stream_profile> ps{ profile };
729  rec->save_stream_profiles(ps, k);
730  }, _entity_id, call_type::uvc_close);
731  }
732 
734  {
735  _owner->try_record([&](recording* rec, lookup_key k)
736  {
737  _source->set_power_state(state);
738 
739  auto&& c = rec->add_call(k);
740  c.param1 = state;
741  }, _entity_id, call_type::uvc_set_power_state);
742  }
743 
745  {
746  return _owner->try_record([&](recording* rec, lookup_key k)
747  {
748  auto res = _source->get_power_state();
749 
750  auto&& c = rec->add_call(k);
751  c.param1 = res;
752 
753  return res;
754  }, _entity_id, call_type::uvc_get_power_state);
755  }
756 
758  {
759  _owner->try_record([&](recording* rec, lookup_key k)
760  {
761  _source->init_xu(xu);
762  rec->add_call(k);
763  }, _entity_id, call_type::uvc_init_xu);
764  }
765 
766  bool record_uvc_device::set_xu(const extension_unit& xu, uint8_t ctrl, const uint8_t* data, int len)
767  {
768  return _owner->try_record([&](recording* rec, lookup_key k)
769  {
770  auto sts = _source->set_xu(xu, ctrl, data, len);
771 
772  auto&& c = rec->add_call(k);
773  c.param1 = ctrl;
774  c.param2 = rec->save_blob(data, len);
775  c.param3 = sts;
776 
777  return sts;
778  }, _entity_id, call_type::uvc_set_xu);
779  }
780 
781  bool record_uvc_device::get_xu(const extension_unit& xu, uint8_t ctrl, uint8_t* data, int len) const
782  {
783  return _owner->try_record([&](recording* rec, lookup_key k)
784  {
785  auto sts = _source->get_xu(xu, ctrl, data, len);
786 
787  auto&& c = rec->add_call(k);
788  c.param1 = ctrl;
789  c.param2 = rec->save_blob(data, len);
790  c.param3 = sts;
791 
792  return sts;
793  }, _entity_id, call_type::uvc_get_xu);
794  }
795 
797  {
798  return _owner->try_record([&](recording* rec, lookup_key k)
799  {
800  auto res = _source->get_xu_range(xu, ctrl, len);
801 
802  auto&& c = rec->add_call(k);
803  c.param1 = ctrl;
804  c.param2 = rec->save_blob(res.def.data(), res.def.size());
805  c.param3 = rec->save_blob(res.min.data(), res.min.size());
806  c.param4 = rec->save_blob(res.max.data(), res.max.size());
807  c.param5 = rec->save_blob(res.step.data(), res.step.size());
808 
809  return res;
810  }, _entity_id, call_type::uvc_get_xu_range);
811  }
812 
814  {
815  return _owner->try_record([&](recording* rec, lookup_key k)
816  {
817  auto sts = _source->get_pu(opt, value);
818 
819  auto&& c = rec->add_call(k);
820  c.param1 = opt;
821  c.param2 = value;
822  c.param3 = sts;
823 
824  return sts;
825  }, _entity_id, call_type::uvc_get_pu);
826  }
827 
829  {
830  return _owner->try_record([&](recording* rec, lookup_key k)
831  {
832  auto sts = _source->set_pu(opt, value);
833 
834  auto&& c = rec->add_call(k);
835  c.param1 = opt;
836  c.param2 = value;
837  c.param3 = sts;
838 
839  return sts;
840  }, _entity_id, call_type::uvc_set_pu);
841  }
842 
844  {
845  return _owner->try_record([&](recording* rec, lookup_key k)
846  {
847  auto res = _source->get_pu_range(opt);
848 
849  auto&& c = rec->add_call(k);
850  c.param1 = opt;
851  c.param2 = rec->save_blob(res.min.data(), res.min.size());
852  c.param3 = rec->save_blob(res.max.data(), res.max.size());
853  c.param4 = rec->save_blob(res.step.data(), res.step.size());
854  c.param5 = rec->save_blob(res.def.data(), res.def.size());
855 
856  return res;
857  }, _entity_id, call_type::uvc_get_pu_range);
858  }
859 
860  vector<stream_profile> record_uvc_device::get_profiles() const
861  {
862  return _owner->try_record([&](recording* rec, lookup_key k)
863  {
864  auto devices = _source->get_profiles();
865  rec->save_stream_profiles(devices, k);
866  return devices;
867  }, _entity_id, call_type::uvc_stream_profiles);
868  }
869 
871  {
872  _owner->try_record([&](recording* rec, lookup_key k)
873  {
874  _source->lock();
875  rec->add_call(k);
876  }, _entity_id, call_type::uvc_lock);
877  }
878 
880  {
881  _owner->try_record([&](recording* rec, lookup_key k)
882  {
883  _source->unlock();
884  rec->add_call(k);
885  }, _entity_id, call_type::uvc_unlock);
886  }
887 
888  void record_hid_device::register_profiles(const std::vector<hid_profile>& hid_profiles)
889  {
890  _owner->try_record([&](recording* rec, lookup_key k)
891  {
892  _source->register_profiles(hid_profiles);
893  auto&& c = rec->add_call(k);
894  c.param1 = rec->save_blob(hid_profiles.data(), hid_profiles.size() * sizeof(hid_profile));
895  }, _entity_id, call_type::hid_register_profiles);
896  }
897 
898  void record_hid_device::open(const std::vector<hid_profile>& hid_profiles)
899  {
900  _owner->try_record([&](recording* rec, lookup_key k)
901  {
902  _source->open(hid_profiles);
903  auto&& c =rec->add_call(k);
904  c.param1 = rec->save_blob(hid_profiles.data(), hid_profiles.size() * sizeof(hid_profile));
905  }, _entity_id, call_type::hid_open);
906  }
907 
909  {
910  _owner->try_record([&](recording* rec, lookup_key k)
911  {
912  _source->close();
913  rec->add_call(k);
914  }, _entity_id, call_type::hid_close);
915  }
916 
918  {
919  _owner->try_record([&](recording* rec, lookup_key k)
920  {
921  _source->stop_capture();
922  rec->add_call(k);
923  }, _entity_id, call_type::hid_stop_capture);
924  }
925 
927  {
928  _owner->try_record([this, callback](recording* rec, lookup_key k)
929  {
930  _source->start_capture([this, callback](const sensor_data& sd)
931  {
932  _owner->try_record([this, callback, &sd](recording* rec1, lookup_key key1)
933  {
934  auto&& c = rec1->add_call(key1);
935  c.param1 = rec1->save_blob(sd.fo.pixels, sd.fo.frame_size);
936  c.param2 = rec1->save_blob(sd.fo.metadata, sd.fo.metadata_size);
937 
938 
939  c.inline_string = sd.sensor.name;
940 
941  callback(sd);
942  }, _entity_id, call_type::hid_frame);
943  });
944 
945  }, _entity_id, call_type::hid_start_capture);
946  }
947 
948  vector<hid_sensor> record_hid_device::get_sensors()
949  {
950  return _owner->try_record([&](recording* rec, lookup_key k)
951  {
952  auto res = _source->get_sensors();
953  rec->save_hid_sensors(res, k);
954  return res;
955  }, _entity_id, call_type::hid_get_sensors);
956  }
957 
958  std::vector<uint8_t> record_hid_device::get_custom_report_data(const std::string& custom_sensor_name,
959  const std::string& report_name,
960  custom_sensor_report_field report_field)
961  {
962  return _owner->try_record([&](recording* rec, lookup_key k)
963  {
964  auto result = _source->get_custom_report_data(custom_sensor_name, report_name, report_field);
965 
966  auto&& c = rec->add_call(k);
967  c.param1 = rec->save_blob((void*)result.data(), result.size());
968  c.param2 = rec->save_blob(custom_sensor_name.c_str(), custom_sensor_name.size() + 1);
969  c.param3 = rec->save_blob(report_name.c_str(), report_name.size() + 1);
970  c.param4 = report_field;
971 
972  return result;
974  }
975 
977  {
978  return _owner->try_record([&](recording* rec, lookup_key k)
979  {
980  auto result = _source->get_device_location();
981 
982  auto&& c = rec->add_call(k);
984 
985  return result;
986  }, _entity_id, call_type::uvc_get_location);
987  }
988 
990  {
991  return _owner->try_record([&](recording* rec, lookup_key k)
992  {
993  auto result = _source->get_usb_specification();
994 
995  auto&& c = rec->add_call(k);
996  c.param1 = result;
997 
998  return result;
999  }, _entity_id, call_type::uvc_get_usb_specification);
1000  }
1001 
1002  vector<uint8_t> record_usb_device::send_receive(const vector<uint8_t>& data, int timeout_ms, bool require_response)
1003  {
1004  return _owner->try_record([&](recording* rec, lookup_key k)
1005  {
1006  auto result = _source->send_receive(data, timeout_ms, require_response);
1007 
1008  auto&& c = rec->add_call(k);
1009  c.param1 = rec->save_blob((void*)data.data(), static_cast<int>(data.size()));
1010  c.param2 = rec->save_blob((void*)result.data(), static_cast<int>(result.size()));
1011  c.param3 = timeout_ms;
1012  c.param4 = require_response;
1013 
1014  return result;
1015  }, _entity_id, call_type::send_command);
1016  }
1017 
1018 
1020  {
1021  return try_record([&](recording* rec, lookup_key k)
1022  {
1023  auto dev = _source->create_hid_device(info);
1024 
1025  auto id = _entity_count.fetch_add(1);
1026  auto&& c = rec->add_call(k);
1027  c.param1 = id;
1028 
1029  return make_shared<record_hid_device>(dev, id, this);
1031  }
1032 
1033  vector<hid_device_info> record_backend::query_hid_devices() const
1034  {
1035  return try_record([&](recording* rec, lookup_key k)
1036  {
1037  auto devices = _source->query_hid_devices();
1038  rec->save_device_info_list(devices, k);
1039  return devices;
1041  }
1042 
1044  {
1045  return try_record([&](recording* rec, lookup_key k)
1046  {
1047  auto dev = _source->create_uvc_device(info);
1048 
1049  auto id = _entity_count.fetch_add(1);
1050  auto&& c = rec->add_call(k);
1051  c.param1 = id;
1052 
1053  return make_shared<record_uvc_device>(dev, _compression, id, this);
1055  }
1056 
1057  vector<uvc_device_info> record_backend::query_uvc_devices() const
1058  {
1059  return try_record([&](recording* rec, lookup_key k)
1060  {
1061  auto devices = _source->query_uvc_devices();
1062  rec->save_device_info_list(devices, k);
1063  return devices;
1065  }
1066 
1067  shared_ptr<command_transfer> record_backend::create_usb_device(usb_device_info info) const
1068  {
1069  return try_record([&](recording* rec, lookup_key k)
1070  {
1071  auto dev = _source->create_usb_device(info);
1072 
1073  auto id = _entity_count.fetch_add(1);
1074  auto&& c = rec->add_call(k);
1075  c.param1 = id;
1076 
1077  return make_shared<record_usb_device>(dev, id, this);
1079  }
1080 
1081  vector<usb_device_info> record_backend::query_usb_devices() const
1082  {
1083  return try_record([&](recording* rec, lookup_key k)
1084  {
1085  auto devices = _source->query_usb_devices();
1086  rec->save_device_info_list(devices, k);
1087  return devices;
1089  }
1090 
1091  std::shared_ptr<time_service> record_backend::create_time_service() const
1092  {
1093  return _source->create_time_service();
1094  }
1095 
1096  std::shared_ptr<device_watcher> record_backend::create_device_watcher() const
1097  {
1098  return std::make_shared<record_device_watcher>(this, _source->create_device_watcher(), 0);
1099  }
1100 
1102  const char* filename, const char* section,
1104  : _source(source), _rec(std::make_shared<platform::recording>(create_time_service())), _entity_count(1),
1105  _filename(filename),
1106  _section(section), _compression(make_shared<compression_algorithm>()), _mode(mode)
1107  {}
1108 
1110  {
1111  try
1112  {
1113  write_to_file();
1114  }
1115  catch (const runtime_error& e)
1116  {
1117  std::cerr << "Recording failed: " << e.what() << std::endl;
1118  }
1119  catch (...)
1120  {
1121  std::cerr << "Recording failed: - unresolved error" << std::endl;
1122  }
1123  }
1124 
1126  {
1127  auto&& c = _rec->find_call(call_type::create_hid_device, 0);
1128 
1129  return make_shared<playback_hid_device>(_rec, c.param1);
1130  }
1131 
1132  vector<hid_device_info> playback_backend::query_hid_devices() const
1133  {
1134  return _rec->load_hid_device_info_list();
1135  }
1136 
1138  {
1139  auto&& c = _rec->find_call(call_type::create_uvc_device, 0);
1140 
1141  return make_shared<playback_uvc_device>(_rec, c.param1);
1142  }
1143 
1144  vector<uvc_device_info> playback_backend::query_uvc_devices() const
1145  {
1146  return _rec->load_uvc_device_info_list();
1147  }
1148 
1149  shared_ptr<command_transfer> playback_backend::create_usb_device(usb_device_info info) const
1150  {
1151  auto&& c = _rec->find_call(call_type::create_usb_device, 0);
1152 
1153  return make_shared<playback_usb_device>(_rec, c.param1);
1154  }
1155 
1156  vector<usb_device_info> playback_backend::query_usb_devices() const
1157  {
1158  return _rec->load_usb_device_info_list();
1159  }
1160 
1161  std::shared_ptr<time_service> playback_backend::create_time_service() const
1162  {
1163  return make_shared<recording_time_service>(*_rec);
1164  }
1165 
1166  std::shared_ptr<device_watcher> playback_backend::create_device_watcher() const
1167  {
1168  return _device_watcher;
1169  }
1170 
1171  playback_backend::playback_backend(const char* filename, const char* section, std::string min_api_version)
1172  : _device_watcher(new playback_device_watcher(0)),
1173  _rec(platform::recording::load(filename, section, _device_watcher, min_api_version))
1174  {
1175  LOG_DEBUG("Starting section " << section);
1176  }
1177 
1179  {
1180  assert(_alive);
1181  _alive = false;
1182  _callback_thread.join();
1183  }
1184 
1186  {
1187  _rec->save(_filename.c_str(), _section.c_str(), false);
1188  //LOG(INFO) << "Finished writing " << _rec->size() << " calls...";
1189  }
1190 
1192  : _entity_id(id), _alive(false), _dispatcher(10)
1193  {}
1194 
1196  {
1197  stop();
1198  }
1199 
1201  {
1202  std::lock_guard<std::recursive_mutex> lock(_mutex);
1203  stop();
1204  _dispatcher.start();
1205  _callback = callback;
1206  _alive = true;
1207  }
1208 
1210  {
1211  std::lock_guard<std::recursive_mutex> lock(_mutex);
1212  if (_alive)
1213  {
1214  _alive = false;
1215  _dispatcher.stop();
1216  }
1217  }
1218 
1220  {
1222  _callback(old, curr);
1223  });
1224  }
1225 
1227  {
1228  lock_guard<mutex> lock(_callback_mutex);
1229 
1230  auto it = std::remove_if(begin(_callbacks), end(_callbacks),
1231  [&profile](const pair<stream_profile, frame_callback>& pair)
1232  {
1233  return pair.first == profile;
1234  });
1235 
1236  _callbacks.erase(it, end(_callbacks));
1237  _commitments.push_back({ profile, callback });
1238  }
1239 
1240  void playback_uvc_device::stream_on(std::function<void(const notification& n)> error_handler)
1241  {
1242  lock_guard<mutex> lock(_callback_mutex);
1243 
1244  auto&& c = _rec->find_call(call_type::uvc_play, _entity_id);
1245 
1246  for (auto&& pair : _commitments)
1247  _callbacks.push_back(pair);
1248  _commitments.clear();
1249  }
1250 
1252  {
1253  _rec->find_call(call_type::uvc_start_callbacks, _entity_id);
1254  }
1255 
1257  {
1258  _rec->find_call(call_type::uvc_stop_callbacks, _entity_id);
1259  }
1260 
1262  {
1263  auto stored = _rec->load_stream_profiles(_entity_id, call_type::uvc_close);
1264  vector<stream_profile> input{ profile };
1265  if (input != stored)
1266  throw playback_backend_exception("Recording history mismatch!", call_type::uvc_close, _entity_id);
1267 
1268  lock_guard<mutex> lock(_callback_mutex);
1269  auto it = std::remove_if(begin(_callbacks), end(_callbacks),
1270  [&profile](const pair<stream_profile, frame_callback>& pair)
1271  {
1272  return pair.first == profile;
1273  });
1274  _callbacks.erase(it, end(_callbacks));
1275  }
1276 
1278  {
1279  auto&& c = _rec->find_call(call_type::uvc_set_power_state, _entity_id, [&](const call& call_found)
1280  {
1281  return call_found.param1 == state;
1282  });
1283  }
1284 
1286  {
1287  auto&& c = _rec->find_call(call_type::uvc_get_power_state, _entity_id);
1288  return static_cast<power_state>(c.param1);
1289  }
1290 
1292  {
1293  _rec->find_call(call_type::uvc_init_xu, _entity_id);
1294  }
1295 
1297  {
1298  auto&& c = _rec->find_call(call_type::uvc_set_xu, _entity_id, [&](const call& call_found)
1299  {
1300  return call_found.param1 == ctrl;
1301  });
1302 
1303  auto stored_data = _rec->load_blob(c.param2);
1304  vector<uint8_t> in_data(data, data + len);
1305  if (stored_data != in_data)
1306  {
1307  throw playback_backend_exception("Recording history mismatch!", call_type::uvc_set_xu, _entity_id);
1308  }
1309  return (c.param3 != 0);
1310  }
1311 
1313  {
1314  auto&& c = _rec->find_call(call_type::uvc_get_xu, _entity_id);
1315  if (c.param1 != ctrl)
1316  throw playback_backend_exception("Recording history mismatch!", call_type::uvc_get_xu, _entity_id);
1317  auto stored_data = _rec->load_blob(c.param2);
1318  if (stored_data.size() != len)
1319  throw playback_backend_exception("Recording history mismatch!", call_type::uvc_get_xu, _entity_id);
1320  librealsense::copy(data, stored_data.data(), len);
1321  return (c.param3 != 0);
1322  }
1323 
1325  {
1327  auto&& c = _rec->find_call(call_type::uvc_get_xu_range, _entity_id, [&](const call& call_found)
1328  {
1329  return call_found.param1 == ctrl;
1330  });
1331 
1332  res.def = _rec->load_blob(c.param2);
1333  res.min = _rec->load_blob(c.param3);
1334  res.max = _rec->load_blob(c.param4);
1335  res.step = _rec->load_blob(c.param5);
1336 
1337  return res;
1338  }
1339 
1341  {
1342  auto&& c = _rec->find_call(call_type::uvc_get_pu, _entity_id, [&](const call& call_found)
1343  {
1344  return call_found.param1 == opt;
1345  });
1346  value = c.param2;
1347  return (c.param3 != 0);
1348  }
1349 
1351  {
1352  auto&& c = _rec->find_call(call_type::uvc_set_pu, _entity_id, [&](const call& call_found)
1353  {
1354  return call_found.param1 == opt && call_found.param2 == value;
1355  });
1356  return (c.param3 != 0);
1357  }
1358 
1360  {
1361 
1362  auto&& c = _rec->find_call(call_type::uvc_get_pu_range, _entity_id, [&](const call& call_found)
1363  {
1364  return call_found.param1 == opt;
1365  });
1366 
1367  control_range res(_rec->load_blob(c.param2), _rec->load_blob(c.param3), _rec->load_blob(c.param4), _rec->load_blob(c.param5));
1368 
1369  return res;
1370  }
1371 
1372  vector<stream_profile> playback_uvc_device::get_profiles() const
1373  {
1374  return _rec->load_stream_profiles(_entity_id, call_type::uvc_stream_profiles);
1375  }
1376 
1378  {
1379  _rec->find_call(call_type::uvc_lock, _entity_id);
1380  }
1381 
1383  {
1384  _rec->find_call(call_type::uvc_unlock, _entity_id);
1385  }
1386 
1388  {
1389  auto&& c = _rec->find_call(call_type::uvc_get_location, _entity_id);
1390  return c.inline_string;
1391  }
1392 
1394  {
1395  auto&& c = _rec->find_call(call_type::uvc_get_usb_specification, _entity_id);
1396  return static_cast<usb_spec>(c.param1);
1397  }
1398 
1399  playback_uvc_device::playback_uvc_device(shared_ptr<recording> rec, int id)
1400  : _rec(rec), _entity_id(id), _alive(true)
1401  {
1402  _callback_thread = std::thread([this]() { callback_thread(); });
1403  }
1404 
1405  void playback_hid_device::register_profiles(const std::vector<hid_profile>& hid_profiles)
1406  {
1407  auto stored = _rec->find_call(call_type::hid_register_profiles, _entity_id);
1408  auto stored_iios = _rec->load_blob(stored.param1);
1409  // TODO: Verify sensor_iio
1410  }
1411 
1412  void playback_hid_device::open(const std::vector<hid_profile>& hid_profiles)
1413  {
1414  auto stored = _rec->find_call(call_type::hid_open, _entity_id);
1415  auto stored_iios = _rec->load_blob(stored.param1);
1416  // TODO: Verify sensor_iio
1417  }
1418 
1420  {
1421  _rec->find_call(call_type::hid_close, _entity_id);
1422 
1423  lock_guard<mutex> lock(_callback_mutex);
1424  if (_alive)
1425  {
1426  _alive = false;
1427  _callback_thread.join();
1428  }
1429  }
1430 
1432  {
1434 
1435  lock_guard<mutex> lock(_callback_mutex);
1436  _alive = false;
1437  _callback_thread.join();
1438  }
1439 
1441  {
1442  lock_guard<mutex> lock(_callback_mutex);
1443 
1444  _callback = callback;
1445  _alive = true;
1446 
1447  _callback_thread = std::thread([this]() { callback_thread(); });
1448  }
1449 
1451  {
1452  return _rec->load_hid_sensors2_list(_entity_id);
1453  }
1454 
1455  std::vector<uint8_t> playback_hid_device::get_custom_report_data(const std::string& custom_sensor_name,
1456  const std::string& report_name,
1457  custom_sensor_report_field report_field)
1458  {
1459  auto&& c = _rec->find_call(call_type::hid_get_custom_report_data, _entity_id, [&](const call& call_found)
1460  {
1461  return custom_sensor_name == std::string((const char*)_rec->load_blob(call_found.param2).data()) &&
1462  report_name == std::string((const char*)_rec->load_blob(call_found.param3).data()) &&
1463  report_field == call_found.param4;
1464  });
1465 
1466  return _rec->load_blob(c.param1);
1467  }
1468 
1470  {
1471  while (_alive)
1472  {
1473  auto c_ptr = _rec->cycle_calls(call_type::hid_frame, _entity_id);
1474  if (c_ptr)
1475  {
1476  auto sd_data = _rec->load_blob(c_ptr->param1);
1477  auto sensor_name = c_ptr->inline_string;
1478 
1479  sensor_data sd;
1480  sd.fo.pixels = (void*)sd_data.data();
1481  sd.fo.frame_size = sd_data.size();
1482 
1483  auto metadata = _rec->load_blob(c_ptr->param2);
1484  sd.fo.metadata = (void*)metadata.data();
1485  sd.fo.metadata_size = static_cast<uint8_t>(metadata.size());
1486 
1487  sd.sensor.name = sensor_name;
1488 
1489  _callback(sd);
1490  }
1491  this_thread::sleep_for(chrono::milliseconds(1));
1492  }
1493  }
1494 
1496  {
1497 
1498  }
1499 
1500  playback_hid_device::playback_hid_device(shared_ptr<recording> rec, int id)
1501  : _rec(rec), _entity_id(id),
1502  _alive(false)
1503  {
1504 
1505  }
1506 
1507  vector<uint8_t> playback_usb_device::send_receive(const vector<uint8_t>& data, int timeout_ms, bool require_response)
1508  {
1509  auto&& c = _rec->find_call(call_type::send_command, _entity_id, [&](const call& call_found)
1510  {
1511  return call_found.param3 == timeout_ms && (call_found.param4 > 0) == require_response && _rec->load_blob(call_found.param1) == data;
1512  });
1513 
1514  return _rec->load_blob(c.param2);
1515  }
1516 
1517 
1518 
1520  {
1521  auto profile_blob = _rec->load_blob(frame->param1);
1522 
1523  stream_profile p;
1524  librealsense::copy(&p, profile_blob.data(), sizeof(p));
1525 
1526  return p;
1527  }
1528 
1529 
1531  {
1532  int next_timeout_ms = 0;
1533  double prev_frame_ts = 0;
1534 
1535  while (_alive)
1536  {
1537  auto c_ptr = _rec->pick_next_call(_entity_id);
1538 
1539  if (c_ptr && c_ptr->type == call_type::uvc_frame)
1540  {
1541  lock_guard<mutex> lock(_callback_mutex);
1542  for (auto&& pair : _callbacks)
1543  {
1544  if(get_profile(c_ptr) == pair.first)
1545  {
1546  auto c_ptr = _rec->cycle_calls(call_type::uvc_frame, _entity_id);
1547 
1548  if (c_ptr)
1549  {
1550  auto p = get_profile(c_ptr);
1551  if(p == pair.first)
1552  {
1553  vector<uint8_t> frame_blob;
1554  vector<uint8_t> metadata_blob;
1555 
1556  if (prev_frame_ts > 0 &&
1557  c_ptr->timestamp > prev_frame_ts &&
1558  c_ptr->timestamp - prev_frame_ts <= 300)
1559  {
1560  prev_frame_ts = c_ptr->timestamp - prev_frame_ts;
1561  }
1562 
1563  prev_frame_ts = c_ptr->timestamp;
1564 
1565  if (c_ptr->param3 == 0) // frame was not saved
1566  {
1567  frame_blob = vector<uint8_t>(c_ptr->param4, 0);
1568  }
1569  else if (c_ptr->param3 == 1)// frame was saved
1570  {
1571  frame_blob = _rec->load_blob(c_ptr->param2);
1572  }
1573  else
1574  {
1575  frame_blob = _compression.decode(_rec->load_blob(c_ptr->param2));
1576  }
1577 
1578  metadata_blob = _rec->load_blob(c_ptr->param5);
1579  frame_object fo{ frame_blob.size(),
1580  static_cast<uint8_t>(metadata_blob.size()), // Metadata is limited to 0xff bytes by design
1581  frame_blob.data(),metadata_blob.data() };
1582 
1583 
1584  pair.second(p, fo, []() {});
1585 
1586  break;
1587  }
1588  }
1589  else
1590  {
1591  LOG_WARNING("Could not Cycle frames!");
1592  }
1593 
1594  }
1595 
1596  }
1597  }
1598  else
1599  {
1600  _rec->cycle_calls(call_type::uvc_frame, _entity_id);
1601  }
1602  // work around - Let the other threads of playback uvc devices pull their frames
1603  this_thread::sleep_for(std::chrono::milliseconds(next_timeout_ms));
1604  }
1605  }
1606 
1607  }
1608 }
1609 
static const textual_icon lock
Definition: model-views.h:218
bool set_xu(const extension_unit &xu, uint8_t ctrl, const uint8_t *data, int len) override
Definition: recorder.cpp:1296
const char * DEVICE_INFO_INSERT
Definition: recorder.cpp:35
GLuint GLuint end
const char * CONFIG_CREATE
Definition: recorder.cpp:16
GLint y
GLenum GLenum GLsizei void * row
void init_xu(const extension_unit &xu) override
Definition: recorder.cpp:757
const char * SECTIONS_INSERT
Definition: recorder.cpp:24
GLuint64EXT GLuint GLuint GLenum GLenum GLuint GLuint GLenum GLuint GLuint key1
Definition: glext.h:10696
bool set_xu(const extension_unit &xu, uint8_t ctrl, const uint8_t *data, int len) override
Definition: recorder.cpp:766
std::vector< uint8_t > max
Definition: backend.h:88
rs2_option
Defines general configuration controls. These can generally be mapped to camera UVC controls...
Definition: rs_option.h:22
GLdouble s
const char * DEVICE_INFO_CREATE
Definition: recorder.cpp:33
GLfloat GLfloat p
Definition: glext.h:12687
std::vector< hid_sensor_input > hid_sensor_inputs
Definition: recorder.h:309
void init_xu(const extension_unit &xu) override
Definition: recorder.cpp:1291
std::vector< usb_device_info > query_usb_devices() const override
Definition: recorder.cpp:1081
std::string get_device_location() const override
Definition: recorder.cpp:976
rs2_recording_mode
Definition: rs_internal.h:32
void probe_and_commit(stream_profile profile, frame_callback callback, int buffers) override
Definition: recorder.cpp:1226
#define LOG_WARNING(...)
Definition: src/types.h:241
std::map< size_t, size_t > _cursors
Definition: recorder.h:315
void stream_on(std::function< void(const notification &n)> error_handler=[](const notification &n){}) override
Definition: recorder.cpp:1240
GLfloat value
std::vector< stream_profile > get_profiles() const override
Definition: recorder.cpp:1372
std::vector< call > calls
Definition: recorder.h:302
std::shared_ptr< recording > _rec
Definition: recorder.h:581
std::vector< uint8_t > get_custom_report_data(const std::string &custom_sensor_name, const std::string &report_name, custom_sensor_report_field report_field) override
Definition: recorder.cpp:958
std::shared_ptr< recording > _rec
Definition: recorder.h:477
usb_spec get_usb_specification() const override
Definition: recorder.cpp:989
std::shared_ptr< device_watcher > create_device_watcher() const override
Definition: recorder.cpp:1096
void stream_on(std::function< void(const notification &n)> error_handler=[](const notification &n){}) override
Definition: recorder.cpp:696
std::vector< uint8_t > send_receive(const std::vector< uint8_t > &data, int timeout_ms, bool require_response) override
Definition: recorder.cpp:1507
void start(device_changed_callback callback) override
Definition: recorder.cpp:1200
const char * BLOBS_INSERT
Definition: recorder.cpp:38
const char * SECTIONS_COUNT_BY_NAME
Definition: recorder.cpp:25
const char * SECTIONS_COUNT_ALL
Definition: recorder.cpp:26
GLsizei const GLchar *const * string
void close(stream_profile profile) override
Definition: recorder.cpp:1261
bool get_xu(const extension_unit &xu, uint8_t ctrl, uint8_t *data, int len) const override
Definition: recorder.cpp:781
std::string get_string(int column=0) const
Definition: sql.cpp:121
static bool is_heighr_or_equel_to_min_version(std::string api_version, std::string min_api_version)
Definition: recorder.cpp:367
std::vector< hid_device_info > query_hid_devices() const override
Definition: recorder.cpp:1033
GLdouble n
Definition: glext.h:1966
unsigned char uint8_t
Definition: stdint.h:78
const char * PROFILES_SELECT_ALL
Definition: recorder.cpp:43
call & find_call(call_type t, int entity_id, std::function< bool(const call &c)> history_match_validation=[](const call &c){return true;})
Definition: recorder.cpp:551
e
Definition: rmse.py:177
int save_blob(const void *ptr, size_t size)
Definition: recorder.cpp:535
void open(const std::vector< hid_profile > &hid_profiles) override
Definition: recorder.cpp:898
const char * SECTIONS_SELECT_MAX_ID
Definition: recorder.cpp:22
std::shared_ptr< time_service > _ts
Definition: recorder.h:313
static std::shared_ptr< recording > load(const char *filename, const char *section, std::shared_ptr< playback_device_watcher > watcher=nullptr, std::string min_api_version="")
Definition: recorder.cpp:385
void probe_and_commit(stream_profile profile, frame_callback callback, int buffers) override
Definition: recorder.cpp:653
GLenum GLuint id
std::shared_ptr< playback_device_watcher > _watcher
Definition: recorder.h:310
void set_power_state(power_state state) override
Definition: recorder.cpp:733
std::recursive_mutex _mutex
Definition: recorder.h:312
bool table_exists(const char *name) const
Definition: sql.cpp:69
GLdouble t
GLenum GLsizei len
Definition: glext.h:3285
def info(name, value, persistent=False)
Definition: test.py:301
not_this_one begin(...)
const char * SECTIONS_FIND_BY_NAME
Definition: recorder.cpp:27
const char * API_VERSION_KEY
Definition: recorder.cpp:18
GLdouble f
GLenum mode
call & add_call(lookup_key key)
Definition: recorder.h:147
static float min_dist
Definition: rs-kinfu.cpp:17
void raise_callback(backend_device_group old, backend_device_group curr)
Definition: recorder.cpp:1219
GLsizeiptr size
record_backend(std::shared_ptr< backend > source, const char *filename, const char *section, rs2_recording_mode mode)
Definition: recorder.cpp:1101
std::string get_device_location() const override
Definition: recorder.cpp:1387
const GLubyte * c
Definition: glext.h:12690
const char * CONFIG_INSERT
Definition: recorder.cpp:17
std::shared_ptr< recording > _rec
Definition: recorder.h:605
bool get_xu(const extension_unit &xu, uint8_t ctrl, uint8_t *data, int len) const override
Definition: recorder.cpp:1312
void close(stream_profile profile) override
Definition: recorder.cpp:723
void bind(int param, int value) const
Definition: sql.cpp:136
std::vector< hid_sensor > hid_sensors
Definition: recorder.h:308
GLdouble x
std::function< void(backend_device_group old, backend_device_group curr)> device_changed_callback
Definition: backend.h:574
std::shared_ptr< command_transfer > create_usb_device(usb_device_info info) const override
Definition: recorder.cpp:1067
unsigned int uint32_t
Definition: stdint.h:80
bool file_exists(const char *filename)
Definition: types.cpp:81
devices
Definition: test-fg.py:9
void start_capture(hid_callback callback) override
Definition: recorder.cpp:1440
void start_capture(hid_callback callback) override
Definition: recorder.cpp:926
const char * CONFIG_QUERY
Definition: recorder.cpp:15
void transaction(std::function< void()> transaction) const
Definition: sql.cpp:77
std::vector< stream_profile > get_profiles() const override
Definition: recorder.cpp:860
control_range get_xu_range(const extension_unit &xu, uint8_t ctrl, int len) const override
Definition: recorder.cpp:796
playback_backend_exception(const std::string &msg, call_type t, int entity_id) noexcept
Definition: recorder.cpp:52
std::string datetime_string()
Definition: src/types.h:1516
std::shared_ptr< time_service > create_time_service() const override
Definition: recorder.cpp:1091
std::vector< uint8_t > send_receive(const std::vector< uint8_t > &data, int timeout_ms, bool require_response) override
Definition: recorder.cpp:1002
void load_device_changed_data(backend_device_group &old, backend_device_group &curr, lookup_key k)
Definition: recorder.h:253
std::vector< hid_sensor > get_sensors() override
Definition: recorder.cpp:948
def callback(frame)
Definition: t265_stereo.py:91
void start(device_changed_callback callback) override
Definition: recorder.cpp:626
void register_profiles(const std::vector< hid_profile > &hid_profiles) override
Definition: recorder.cpp:1405
GLint j
std::shared_ptr< time_service > create_time_service() const override
Definition: recorder.cpp:1161
playback_backend(const char *filename, const char *section, std::string min_api_version)
Definition: recorder.cpp:1171
const char * CALLS_INSERT
Definition: recorder.cpp:30
void set_power_state(power_state state) override
Definition: recorder.cpp:1277
playback_uvc_device(std::shared_ptr< recording > rec, int id)
Definition: recorder.cpp:1399
const char * BLOBS_SELECT_ALL
Definition: recorder.cpp:39
const char * BLOBS_CREATE
Definition: recorder.cpp:37
const GLuint * buffers
std::map< size_t, size_t > _cycles
Definition: recorder.h:316
std::vector< hid_sensor > get_sensors() override
Definition: recorder.cpp:1450
std::vector< std::shared_ptr< stream_profile_interface >> stream_profiles
Definition: streaming.h:165
std::vector< uvc_device_info > query_uvc_devices() const override
Definition: recorder.cpp:1144
Definition: sql.cpp:11
std::shared_ptr< hid_device > create_hid_device(hid_device_info info) const override
Definition: recorder.cpp:1125
playback_hid_device(std::shared_ptr< recording > rec, int id)
Definition: recorder.cpp:1500
std::shared_ptr< command_transfer > create_usb_device(usb_device_info info) const override
Definition: recorder.cpp:1149
const char * PROFILES_CREATE
Definition: recorder.cpp:41
std::function< void(stream_profile, frame_object, std::function< void()>)> frame_callback
Definition: backend.h:177
void execute(const char *command) const
Definition: sql.cpp:60
const char * SECTIONS_TABLE
Definition: recorder.cpp:21
void next(auto_any_t cur, type2type< T, C > *)
Definition: foreach.hpp:757
stream_profile get_profile(call *frame) const
Definition: recorder.cpp:1519
power_state get_power_state() const override
Definition: recorder.cpp:744
control_range get_xu_range(const extension_unit &xu, uint8_t ctrl, int len) const override
Definition: recorder.cpp:1324
::realsense_legacy_msgs::metadata_< std::allocator< void > > metadata
static auto it
GLenum GLenum GLenum input
Definition: glext.h:10805
GLenum type
const char * CALLS_CREATE
Definition: recorder.cpp:29
const char * CALLS_SELECT_ALL
Definition: recorder.cpp:31
std::shared_ptr< device_watcher > create_device_watcher() const override
Definition: recorder.cpp:1166
void save_device_changed_data(backend_device_group old, backend_device_group curr, lookup_key k)
Definition: recorder.h:181
std::vector< std::vector< uint8_t > > blobs
Definition: recorder.h:303
#define RS2_API_VERSION_STR
Definition: rs.h:43
bool get_pu(rs2_option opt, int32_t &value) const override
Definition: recorder.cpp:1340
std::vector< uint8_t > def
Definition: backend.h:90
std::shared_ptr< uvc_device > create_uvc_device(uvc_device_info info) const override
Definition: recorder.cpp:1043
std::ostream & cerr()
std::vector< uvc_device_info > query_uvc_devices() const override
Definition: recorder.cpp:1057
GLsizei GLsizei GLchar * source
control_range get_pu_range(rs2_option opt) const override
Definition: recorder.cpp:1359
power_state get_power_state() const override
Definition: recorder.cpp:1285
std::vector< uint8_t > min
Definition: backend.h:87
std::vector< hid_device_info > hid_device_infos
Definition: recorder.h:307
std::vector< uvc_device_info > uvc_device_infos
Definition: recorder.h:304
std::shared_ptr< uvc_device > create_uvc_device(uvc_device_info info) const override
Definition: recorder.cpp:1137
control_range get_pu_range(rs2_option opt) const override
Definition: recorder.cpp:843
const char * DEVICE_INFO_SELECT_ALL
Definition: recorder.cpp:34
void save_device_info_list(std::vector< uvc_device_info > list, lookup_key k)
Definition: recorder.h:216
int i
GLenum GLuint GLenum GLsizei length
GLuint res
Definition: glext.h:8856
const char * PROFILES_INSERT
Definition: recorder.cpp:42
void register_profiles(const std::vector< hid_profile > &hid_profiles) override
Definition: recorder.cpp:888
signed int int32_t
Definition: stdint.h:77
std::function< void(const sensor_data &)> hid_callback
Definition: backend.h:327
#define LOG_DEBUG(...)
Definition: src/types.h:239
rs2_format format
const char * CREATED_AT_KEY
Definition: recorder.cpp:19
bool set_pu(rs2_option opt, int32_t value) override
Definition: recorder.cpp:828
std::vector< hid_device_info > query_hid_devices() const override
Definition: recorder.cpp:1132
std::vector< uint8_t > step
Definition: backend.h:89
std::vector< uint8_t > get_custom_report_data(const std::string &custom_sensor_name, const std::string &report_name, custom_sensor_report_field report_field) override
Definition: recorder.cpp:1455
std::shared_ptr< recording > _rec
Definition: recorder.h:538
double rs2_time_t
Definition: rs_types.h:300
GLboolean * data
void save_stream_profiles(std::vector< stream_profile > list, lookup_key key)
Definition: recorder.h:231
bool get_pu(rs2_option opt, int32_t &value) const override
Definition: recorder.cpp:813
usb_spec get_usb_specification() const override
Definition: recorder.cpp:1393
const char * SECTIONS_CREATE
Definition: recorder.cpp:23
std::shared_ptr< hid_device > create_hid_device(hid_device_info info) const override
Definition: recorder.cpp:1019
GLuint64EXT * result
Definition: glext.h:10921
void save(const char *filename, const char *section, bool append=false) const
Definition: recorder.cpp:171
void save_hid_sensors(std::vector< hid_sensor > list, lookup_key key)
Definition: recorder.h:236
std::vector< usb_device_info > usb_device_infos
Definition: recorder.h:305
std::vector< usb_device_info > query_usb_devices() const override
Definition: recorder.cpp:1156
Definition: parser.hpp:150
const char * CONFIG_TABLE
Definition: recorder.cpp:14
bool set_pu(rs2_option opt, int32_t value) override
Definition: recorder.cpp:1350
void copy(void *dst, void const *src, size_t size)
Definition: types.cpp:836
std::string generate_message(const std::string &msg, call_type t, int entity_id) const
Definition: recorder.cpp:56
void open(const std::vector< hid_profile > &hid_profiles) override
Definition: recorder.cpp:1412
call * cycle_calls(call_type call_type, int id)
Definition: recorder.cpp:592
std::string to_string(T value)


librealsense2
Author(s): Sergey Dorodnicov , Doron Hirshberg , Mark Horn , Reagan Lopez , Itay Carpis
autogenerated on Mon May 3 2021 02:47:39