media_view_playback_progress.cpp 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  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 "media/view/media_view_playback_progress.h"
  8. #include "media/audio/media_audio.h"
  9. #include "styles/style_media_view.h"
  10. namespace Media {
  11. namespace View {
  12. namespace {
  13. constexpr auto kPlaybackAnimationDurationMs = crl::time(200);
  14. } // namespace
  15. PlaybackProgress::PlaybackProgress()
  16. : _valueAnimation([=](crl::time now) {
  17. return valueAnimationCallback(now);
  18. })
  19. , _availableTillAnimation([=](crl::time now) {
  20. return availableTillAnimationCallback(now);
  21. }) {
  22. }
  23. void PlaybackProgress::updateState(
  24. const Player::TrackState &state,
  25. float64 loadedTillPercent) {
  26. _playing = !Player::IsStopped(state.state);
  27. const auto length = state.length;
  28. const auto position = Player::IsStoppedAtEnd(state.state)
  29. ? state.length
  30. : Player::IsStoppedOrStopping(state.state)
  31. ? 0
  32. : state.position;
  33. const auto receivedTill = (length && state.receivedTill > position)
  34. ? state.receivedTill
  35. : -1;
  36. const auto loadedTill = (loadedTillPercent != 0.)
  37. ? int64(std::floor(loadedTillPercent * length))
  38. : -1;
  39. const auto availableTill = (length && loadedTill > position)
  40. ? std::max(receivedTill, loadedTill)
  41. : receivedTill;
  42. const auto wasInLoadingState = _inLoadingState;
  43. if (wasInLoadingState) {
  44. _inLoadingState = false;
  45. if (_inLoadingStateChanged) {
  46. _inLoadingStateChanged(false);
  47. }
  48. }
  49. const auto progress = (position > length)
  50. ? 1.
  51. : length
  52. ? std::clamp(float64(position) / length, 0., 1.)
  53. : 0.;
  54. const auto availableTillProgress = (availableTill > position)
  55. ? std::clamp(float64(availableTill) / length, 0., 1.)
  56. : -1.;
  57. const auto animatedPosition = position + (state.frequency * kPlaybackAnimationDurationMs / 1000);
  58. const auto animatedProgress = length ? qMax(float64(animatedPosition) / length, 0.) : 0.;
  59. if (length != _length || position != _position || wasInLoadingState) {
  60. const auto animated = length
  61. && _length
  62. && (animatedProgress > value())
  63. && (position > _position)
  64. && (position < _position + state.frequency);
  65. if (animated) {
  66. setValue(animatedProgress, animated);
  67. } else {
  68. setValue(progress, animated);
  69. }
  70. _position = position;
  71. _length = length;
  72. }
  73. if (availableTill != _availableTill) {
  74. setAvailableTill(availableTillProgress);
  75. _availableTill = availableTill;
  76. }
  77. }
  78. void PlaybackProgress::updateLoadingState(float64 progress) {
  79. if (!_inLoadingState) {
  80. _inLoadingState = true;
  81. if (_inLoadingStateChanged) {
  82. _inLoadingStateChanged(true);
  83. }
  84. }
  85. auto animated = (progress > value());
  86. setValue(progress, animated);
  87. }
  88. float64 PlaybackProgress::value() const {
  89. return qMin(a_value.current(), 1.);
  90. }
  91. void PlaybackProgress::setValue(float64 value, bool animated) {
  92. if (animated) {
  93. valueAnimationCallback(crl::now());
  94. a_value.start(value);
  95. _valueAnimation.start();
  96. } else {
  97. a_value = anim::value(value, value);
  98. _valueAnimation.stop();
  99. }
  100. emitUpdatedValue();
  101. }
  102. void PlaybackProgress::setAvailableTill(float64 value) {
  103. const auto current = a_availableTill.current();
  104. if (value > current && current > 0.) {
  105. availableTillAnimationCallback(crl::now());
  106. a_availableTill.start(value);
  107. _availableTillAnimation.start();
  108. } else if (value > a_value.current()) {
  109. a_availableTill = anim::value(a_value.current(), value);
  110. _availableTillAnimation.start();
  111. } else {
  112. a_availableTill = anim::value(-1., -1.);
  113. _availableTillAnimation.stop();
  114. }
  115. emitUpdatedValue();
  116. }
  117. bool PlaybackProgress::valueAnimationCallback(float64 now) {
  118. const auto time = (now - _valueAnimation.started());
  119. const auto dt = anim::Disabled()
  120. ? 1.
  121. : (time / kPlaybackAnimationDurationMs);
  122. if (dt >= 1.) {
  123. a_value.finish();
  124. } else {
  125. a_value.update(dt, anim::linear);
  126. }
  127. emitUpdatedValue();
  128. return (dt < 1.);
  129. }
  130. bool PlaybackProgress::availableTillAnimationCallback(float64 now) {
  131. const auto time = now - _availableTillAnimation.started();
  132. const auto dt = anim::Disabled()
  133. ? 1.
  134. : (time / kPlaybackAnimationDurationMs);
  135. if (dt >= 1.) {
  136. a_availableTill.finish();
  137. } else {
  138. a_availableTill.update(dt, anim::linear);
  139. }
  140. emitUpdatedValue();
  141. return (dt < 1.);
  142. }
  143. void PlaybackProgress::emitUpdatedValue() {
  144. if (_valueChanged) {
  145. const auto value = a_value.current();
  146. const auto availableTill = a_availableTill.current();
  147. _valueChanged(value, std::max(value, availableTill));
  148. }
  149. }
  150. } // namespace View
  151. } // namespace Media