webrtc_device_resolver.cpp 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. // This file is part of Desktop App Toolkit,
  2. // a set of libraries for developing nice desktop applications.
  3. //
  4. // For license and copyright information please follow this link:
  5. // https://github.com/desktop-app/legal/blob/master/LEGAL
  6. //
  7. #include "webrtc/webrtc_device_resolver.h"
  8. #include "webrtc/webrtc_environment.h"
  9. namespace Webrtc {
  10. namespace {
  11. [[nodiscard]] bool IsDefault(const QString &id) {
  12. return id.isEmpty() || id == kDefaultDeviceId;
  13. }
  14. } // namespace
  15. DeviceResolver::DeviceResolver(
  16. not_null<Environment*> environment,
  17. DeviceType type,
  18. rpl::producer<QString> savedId)
  19. : _environment(environment)
  20. , _current{ .type = type }
  21. , _data(_current) {
  22. _data.changes() | rpl::start_with_next([=](DeviceResolvedId id) {
  23. QMutexLocker lock(&_mutex);
  24. _current = id;
  25. }, _lifetime);
  26. std::move(
  27. savedId
  28. ) | rpl::start_with_next([=](QString id) {
  29. QMutexLocker lock(&_mutex);
  30. _savedId = id;
  31. lock.unlock();
  32. trackSavedId();
  33. }, _lifetime);
  34. }
  35. void DeviceResolver::trackSavedId() {
  36. const auto now = _environment->defaultId(_current.type);
  37. if (IsDefault(_savedId)) {
  38. _data = rpl::single(
  39. DeviceChange{ now, now }
  40. ) | rpl::then(
  41. _environment->defaultChanges(_current.type)
  42. ) | rpl::map([=](const DeviceChange &change) {
  43. _lastChangeReason = change.reason;
  44. return DeviceResolvedId{ change.nowId, _current.type, true };
  45. });
  46. return;
  47. }
  48. _data = rpl::single(DevicesChange{
  49. DeviceChange{ now, now },
  50. _environment->devices(_current.type),
  51. }) | rpl::then(
  52. _environment->changes(_current.type)
  53. ) | rpl::map([=](const DevicesChange &change) {
  54. const auto now = _data.current();
  55. const auto i = ranges::find(
  56. change.nowList,
  57. _savedId,
  58. &DeviceInfo::id);
  59. if (i != end(change.nowList) && !i->inactive) {
  60. auto result = DeviceResolvedId{ _savedId, now.type };
  61. if (now != result) {
  62. _lastChangeReason = DeviceChangeReason::Connected;
  63. }
  64. return result;
  65. } else {
  66. _lastChangeReason = (now == DeviceResolvedId{ _savedId })
  67. ? DeviceChangeReason::Disconnected
  68. : change.defaultChange.reason;
  69. const auto &defaultId = change.defaultChange.nowId;
  70. return DeviceResolvedId{ defaultId, now.type, true };
  71. }
  72. });
  73. }
  74. DeviceResolvedId DeviceResolver::current() const {
  75. if (IsDefault(_savedId)) {
  76. _environment->validateDefaultId(_current.type);
  77. } else {
  78. _environment->validateDevices(_current.type);
  79. }
  80. return _data.current();
  81. }
  82. DeviceResolvedId DeviceResolver::threadSafeCurrent() const {
  83. QMutexLocker lock(&_mutex);
  84. auto savedId = _savedId;
  85. auto current = _current;
  86. lock.unlock();
  87. return _environment->threadSafeResolveId(current, savedId);
  88. }
  89. rpl::producer<DeviceResolvedId> DeviceResolver::value() const {
  90. return _data.value();
  91. }
  92. rpl::producer<DeviceResolvedId> DeviceResolver::changes() const {
  93. return _data.changes();
  94. }
  95. DeviceChangeReason DeviceResolver::lastChangeReason() const {
  96. return _lastChangeReason;
  97. }
  98. rpl::producer<QString> DeviceIdOrDefault(
  99. rpl::producer<QString> id) {
  100. return std::move(id) | rpl::map([](const QString &id) {
  101. return !id.isEmpty() ? id : kDefaultDeviceId;
  102. }) | rpl::distinct_until_changed();
  103. }
  104. rpl::producer<QString> DeviceIdValueWithFallback(
  105. rpl::producer<QString> id,
  106. rpl::producer<QString> fallback) {
  107. return rpl::combine(
  108. std::move(id),
  109. std::move(fallback)
  110. ) | rpl::map([](const QString &id, const QString &fallback) {
  111. return !id.isEmpty()
  112. ? id
  113. : !fallback.isEmpty()
  114. ? fallback
  115. : kDefaultDeviceId;
  116. }) | rpl::distinct_until_changed();
  117. }
  118. } // namespace Webrtc