data_streaming.cpp 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. /*
  2. This file is part of Telegram Desktop,
  3. the official desktop application for the Telegram messaging service.
  4. For license and copyright information please follow this link:
  5. https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
  6. */
  7. #include "data/data_streaming.h"
  8. #include "data/data_photo.h"
  9. #include "data/data_document.h"
  10. #include "data/data_session.h"
  11. #include "data/data_file_origin.h"
  12. #include "media/streaming/media_streaming_loader.h"
  13. #include "media/streaming/media_streaming_reader.h"
  14. #include "media/streaming/media_streaming_document.h"
  15. namespace Data {
  16. namespace {
  17. constexpr auto kKeepAliveTimeout = 5 * crl::time(1000);
  18. template <typename Object, typename Data>
  19. bool PruneDestroyedAndSet(
  20. base::flat_map<
  21. not_null<Data*>,
  22. std::weak_ptr<Object>> &objects,
  23. not_null<Data*> data,
  24. const std::shared_ptr<Object> &object) {
  25. auto result = false;
  26. for (auto i = begin(objects); i != end(objects);) {
  27. if (i->first == data) {
  28. (i++)->second = object;
  29. result = true;
  30. } else if (i->second.lock() != nullptr) {
  31. ++i;
  32. } else {
  33. i = objects.erase(i);
  34. }
  35. }
  36. return result;
  37. }
  38. [[nodiscard]] auto LookupOtherQualities(
  39. DocumentData *original,
  40. not_null<DocumentData*> quality,
  41. HistoryItem *context)
  42. -> std::vector<Media::Streaming::QualityDescriptor> {
  43. if (!original || !context) {
  44. return {};
  45. }
  46. auto qualities = original->resolveQualities(context);
  47. if (qualities.empty()) {
  48. return {};
  49. }
  50. auto result = std::vector<Media::Streaming::QualityDescriptor>();
  51. result.reserve(qualities.size());
  52. for (const auto &video : qualities) {
  53. if (video != quality) {
  54. if (const auto height = video->resolveVideoQuality()) {
  55. result.push_back({
  56. .sizeInBytes = uint32(video->size),
  57. .height = uint32(height),
  58. });
  59. }
  60. }
  61. }
  62. return result;
  63. }
  64. [[nodiscard]] auto LookupOtherQualities(
  65. DocumentData *original,
  66. not_null<PhotoData*> quality,
  67. HistoryItem *context)
  68. -> std::vector<Media::Streaming::QualityDescriptor> {
  69. Expects(!original);
  70. return {};
  71. }
  72. } // namespace
  73. Streaming::Streaming(not_null<Session*> owner)
  74. : _owner(owner)
  75. , _keptAliveTimer([=] { clearKeptAlive(); }) {
  76. }
  77. Streaming::~Streaming() = default;
  78. template <typename Data>
  79. [[nodiscard]] std::shared_ptr<Streaming::Reader> Streaming::sharedReader(
  80. base::flat_map<not_null<Data*>, std::weak_ptr<Reader>> &readers,
  81. not_null<Data*> data,
  82. FileOrigin origin,
  83. bool forceRemoteLoader) {
  84. const auto i = readers.find(data);
  85. if (i != end(readers)) {
  86. if (auto result = i->second.lock()) {
  87. if (!forceRemoteLoader || result->isRemoteLoader()) {
  88. return result;
  89. }
  90. }
  91. }
  92. auto loader = data->createStreamingLoader(origin, forceRemoteLoader);
  93. if (!loader) {
  94. return nullptr;
  95. }
  96. auto result = std::make_shared<Reader>(
  97. std::move(loader),
  98. &_owner->cacheBigFile());
  99. if (!PruneDestroyedAndSet(readers, data, result)) {
  100. readers.emplace_or_assign(data, result);
  101. }
  102. return result;
  103. }
  104. template <typename Data>
  105. [[nodiscard]] std::shared_ptr<Streaming::Document> Streaming::sharedDocument(
  106. base::flat_map<not_null<Data*>, std::weak_ptr<Document>> &documents,
  107. base::flat_map<not_null<Data*>, std::weak_ptr<Reader>> &readers,
  108. not_null<Data*> data,
  109. DocumentData *original,
  110. HistoryItem *context,
  111. FileOrigin origin) {
  112. auto otherQualities = LookupOtherQualities(original, data, context);
  113. const auto i = documents.find(data);
  114. if (i != end(documents)) {
  115. if (auto result = i->second.lock()) {
  116. if (!otherQualities.empty()) {
  117. result->setOtherQualities(std::move(otherQualities));
  118. }
  119. return result;
  120. }
  121. }
  122. auto reader = sharedReader(readers, data, origin);
  123. if (!reader) {
  124. return nullptr;
  125. }
  126. auto result = std::make_shared<Document>(
  127. data,
  128. std::move(reader),
  129. std::move(otherQualities));
  130. if (!PruneDestroyedAndSet(documents, data, result)) {
  131. documents.emplace_or_assign(data, result);
  132. }
  133. return result;
  134. }
  135. template <typename Data>
  136. void Streaming::keepAlive(
  137. base::flat_map<not_null<Data*>, std::weak_ptr<Document>> &documents,
  138. not_null<Data*> data) {
  139. const auto i = documents.find(data);
  140. if (i == end(documents)) {
  141. return;
  142. }
  143. auto shared = i->second.lock();
  144. if (!shared) {
  145. return;
  146. }
  147. const auto till = crl::now() + kKeepAliveTimeout;
  148. const auto j = _keptAlive.find(shared);
  149. if (j != end(_keptAlive)) {
  150. j->second = till;
  151. } else {
  152. _keptAlive.emplace(std::move(shared), till);
  153. }
  154. if (!_keptAliveTimer.isActive()) {
  155. _keptAliveTimer.callOnce(kKeepAliveTimeout);
  156. }
  157. }
  158. std::shared_ptr<Streaming::Reader> Streaming::sharedReader(
  159. not_null<DocumentData*> document,
  160. FileOrigin origin,
  161. bool forceRemoteLoader) {
  162. return sharedReader(_fileReaders, document, origin, forceRemoteLoader);
  163. }
  164. std::shared_ptr<Streaming::Document> Streaming::sharedDocument(
  165. not_null<DocumentData*> document,
  166. FileOrigin origin) {
  167. return sharedDocument(
  168. _fileDocuments,
  169. _fileReaders,
  170. document,
  171. nullptr,
  172. nullptr,
  173. origin);
  174. }
  175. std::shared_ptr<Streaming::Document> Streaming::sharedDocument(
  176. not_null<DocumentData*> quality,
  177. not_null<DocumentData*> original,
  178. HistoryItem *context,
  179. FileOrigin origin) {
  180. return sharedDocument(
  181. _fileDocuments,
  182. _fileReaders,
  183. quality,
  184. original,
  185. context,
  186. origin);
  187. }
  188. std::shared_ptr<Streaming::Reader> Streaming::sharedReader(
  189. not_null<PhotoData*> photo,
  190. FileOrigin origin,
  191. bool forceRemoteLoader) {
  192. return sharedReader(_photoReaders, photo, origin, forceRemoteLoader);
  193. }
  194. std::shared_ptr<Streaming::Document> Streaming::sharedDocument(
  195. not_null<PhotoData*> photo,
  196. FileOrigin origin) {
  197. return sharedDocument(
  198. _photoDocuments,
  199. _photoReaders,
  200. photo,
  201. nullptr,
  202. nullptr,
  203. origin);
  204. }
  205. void Streaming::keepAlive(not_null<DocumentData*> document) {
  206. keepAlive(_fileDocuments, document);
  207. }
  208. void Streaming::keepAlive(not_null<PhotoData*> photo) {
  209. keepAlive(_photoDocuments, photo);
  210. }
  211. void Streaming::clearKeptAlive() {
  212. const auto now = crl::now();
  213. auto min = std::numeric_limits<crl::time>::max();
  214. for (auto i = begin(_keptAlive); i != end(_keptAlive);) {
  215. const auto wait = (i->second - now);
  216. if (wait <= 0) {
  217. i = _keptAlive.erase(i);
  218. } else {
  219. ++i;
  220. if (min > wait) {
  221. min = wait;
  222. }
  223. }
  224. }
  225. if (!_keptAlive.empty()) {
  226. _keptAliveTimer.callOnce(min);
  227. }
  228. }
  229. } // namespace Data