silent_sink_suspender.cc 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. // Copyright 2016 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "media/base/silent_sink_suspender.h"
  5. #include "base/bind.h"
  6. #include "base/task/single_thread_task_runner.h"
  7. #include "base/threading/thread_task_runner_handle.h"
  8. namespace media {
  9. SilentSinkSuspender::SilentSinkSuspender(
  10. AudioRendererSink::RenderCallback* callback,
  11. base::TimeDelta silence_timeout,
  12. const AudioParameters& params,
  13. scoped_refptr<AudioRendererSink> sink,
  14. scoped_refptr<base::SingleThreadTaskRunner> worker)
  15. : callback_(callback),
  16. params_(params),
  17. sink_(std::move(sink)),
  18. task_runner_(base::ThreadTaskRunnerHandle::Get()),
  19. silence_timeout_(silence_timeout),
  20. fake_sink_(std::move(worker), params_),
  21. sink_transition_callback_(
  22. base::BindRepeating(&SilentSinkSuspender::TransitionSinks,
  23. base::Unretained(this))) {
  24. DCHECK(params_.IsValid());
  25. DCHECK(sink_);
  26. DCHECK(callback_);
  27. DCHECK(task_runner_->BelongsToCurrentThread());
  28. }
  29. SilentSinkSuspender::~SilentSinkSuspender() {
  30. DCHECK(task_runner_->BelongsToCurrentThread());
  31. fake_sink_.Stop();
  32. }
  33. int SilentSinkSuspender::Render(base::TimeDelta delay,
  34. base::TimeTicks delay_timestamp,
  35. int prior_frames_skipped,
  36. AudioBus* dest) {
  37. // Lock required since AudioRendererSink::Pause() is not synchronous, we need
  38. // to discard these calls during the transition to the fake sink.
  39. base::AutoLock al(transition_lock_);
  40. if (is_using_fake_sink_ && dest) {
  41. // Audio should be silent at this point, if not, it will be handled once the
  42. // transition to the fake sink is complete.
  43. dest->Zero();
  44. return dest->frames();
  45. }
  46. // When we're using the |fake_sink_| a null destination will be sent; we store
  47. // the audio data for a future transition out of silence.
  48. if (!dest) {
  49. DCHECK(is_using_fake_sink_);
  50. DCHECK_EQ(prior_frames_skipped, 0);
  51. // |delay_timestamp| contains the value cached at
  52. // |latest_output_delay_timestamp_|
  53. // so we simulate the real sink output, promoting |delay_timestamp| with
  54. // |elapsed_time|.
  55. DCHECK_EQ(delay_timestamp, latest_output_delay_timestamp_);
  56. base::TimeDelta elapsed_time =
  57. base::TimeTicks::Now() - fake_sink_transition_time_;
  58. delay_timestamp += elapsed_time;
  59. // If we have no buffers or a transition is pending, one or more extra
  60. // Render() calls have occurred in before TransitionSinks() can run, so we
  61. // store this data for the eventual transition.
  62. if (buffers_after_silence_.empty() || is_transition_pending_)
  63. buffers_after_silence_.push_back(AudioBus::Create(params_));
  64. dest = buffers_after_silence_.back().get();
  65. } else if (!buffers_after_silence_.empty()) {
  66. // Drain any non-silent transitional buffers before queuing more audio data.
  67. // Note: These do not skew clocks derived from frame count since we don't
  68. // issue Render() to the client when returning these buffers.
  69. DCHECK(!is_using_fake_sink_);
  70. buffers_after_silence_.front()->CopyTo(dest);
  71. buffers_after_silence_.pop_front();
  72. return dest->frames();
  73. }
  74. // Pass-through to client and request rendering.
  75. callback_->Render(delay, delay_timestamp, prior_frames_skipped, dest);
  76. // Check for silence or real audio data and transition if necessary.
  77. if (!dest->AreFramesZero() || !detect_silence_) {
  78. first_silence_time_ = base::TimeTicks();
  79. if (is_using_fake_sink_) {
  80. is_transition_pending_ = true;
  81. task_runner_->PostTask(
  82. FROM_HERE,
  83. base::BindOnce(sink_transition_callback_.callback(), false));
  84. return dest->frames();
  85. }
  86. } else if (!is_using_fake_sink_) {
  87. const base::TimeTicks now = base::TimeTicks::Now();
  88. if (first_silence_time_.is_null())
  89. first_silence_time_ = now;
  90. if (now - first_silence_time_ > silence_timeout_) {
  91. is_transition_pending_ = true;
  92. latest_output_delay_ = delay;
  93. latest_output_delay_timestamp_ = delay_timestamp;
  94. fake_sink_transition_time_ = now;
  95. task_runner_->PostTask(
  96. FROM_HERE,
  97. base::BindOnce(sink_transition_callback_.callback(), true));
  98. }
  99. }
  100. return dest->frames();
  101. }
  102. void SilentSinkSuspender::OnRenderError() {
  103. callback_->OnRenderError();
  104. }
  105. void SilentSinkSuspender::OnPaused() {
  106. DCHECK(task_runner_->BelongsToCurrentThread());
  107. // This is a no-op if the sink isn't running, but must be executed without the
  108. // |transition_lock_| being held to avoid possible deadlock.
  109. fake_sink_.Stop();
  110. base::AutoLock al(transition_lock_);
  111. // Nothing to do if we haven't touched the sink.
  112. if (!is_using_fake_sink_ && !is_transition_pending_) {
  113. first_silence_time_ = base::TimeTicks();
  114. return;
  115. }
  116. // If we've moved over to the fake sink, we just need to stop it and cancel
  117. // any pending transitions.
  118. is_using_fake_sink_ = false;
  119. is_transition_pending_ = false;
  120. first_silence_time_ = base::TimeTicks();
  121. sink_transition_callback_.Reset(base::BindRepeating(
  122. &SilentSinkSuspender::TransitionSinks, base::Unretained(this)));
  123. }
  124. void SilentSinkSuspender::SetDetectSilence(bool detect_silence) {
  125. DCHECK(task_runner_->BelongsToCurrentThread());
  126. bool should_transition_to_real_sink = false;
  127. {
  128. base::AutoLock lock(transition_lock_);
  129. detect_silence_ = detect_silence;
  130. should_transition_to_real_sink = !detect_silence_ && is_using_fake_sink_;
  131. // If we haven't started the transition abort it.
  132. if (is_transition_pending_) {
  133. is_transition_pending_ = false;
  134. sink_transition_callback_.Reset(base::BindRepeating(
  135. &SilentSinkSuspender::TransitionSinks, base::Unretained(this)));
  136. }
  137. }
  138. if (should_transition_to_real_sink)
  139. TransitionSinks(/*use_fake_sink=*/false);
  140. }
  141. bool SilentSinkSuspender::IsUsingFakeSinkForTesting() {
  142. base::AutoLock al(transition_lock_);
  143. return is_using_fake_sink_;
  144. }
  145. void SilentSinkSuspender::TransitionSinks(bool use_fake_sink) {
  146. DCHECK(task_runner_->BelongsToCurrentThread());
  147. // Ignore duplicate requests which can occur if the transition takes too long
  148. // and multiple Render() events occur.
  149. {
  150. base::AutoLock al(transition_lock_);
  151. if (use_fake_sink == is_using_fake_sink_)
  152. return;
  153. }
  154. if (use_fake_sink) {
  155. sink_->Pause();
  156. // |sink_| may still be executing Render() at this point or even sometime
  157. // after this point, so we must acquire the lock to make sure we don't have
  158. // concurrent Render() execution. Once |is_using_fake_sink_| is set to true,
  159. // calls from |sink_| will be dropped.
  160. {
  161. base::AutoLock al(transition_lock_);
  162. is_transition_pending_ = false;
  163. is_using_fake_sink_ = true;
  164. }
  165. fake_sink_.Start(base::BindRepeating(
  166. [](SilentSinkSuspender* suspender, base::TimeDelta frozen_delay,
  167. base::TimeTicks frozen_delay_timestamp, base::TimeTicks ideal_time,
  168. base::TimeTicks now) {
  169. // TODO: Seems that the code in Render() might benefit from the two
  170. // new timestamps being provided by FakeAudioWorker, in that it's call
  171. // to base::TimeTicks::Now() can be eliminated (use |now| instead),
  172. // along with its custom delay timestamp calculations.
  173. suspender->Render(frozen_delay, frozen_delay_timestamp, 0, nullptr);
  174. },
  175. this, latest_output_delay_, latest_output_delay_timestamp_));
  176. } else {
  177. fake_sink_.Stop();
  178. // Despite the fake sink having a synchronous Stop(), if this transition
  179. // occurs too soon after pausing the real sink, we may have pending Render()
  180. // calls from before the transition to the fake sink. As such, we need to
  181. // hold the lock here to avoid any races.
  182. {
  183. base::AutoLock al(transition_lock_);
  184. is_transition_pending_ = false;
  185. is_using_fake_sink_ = false;
  186. }
  187. sink_->Play();
  188. }
  189. }
  190. } // namespace media