| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/base/silent_sink_suspender.h" | 5 #include "media/base/silent_sink_suspender.h" |
| 6 | 6 |
| 7 #include "base/single_thread_task_runner.h" | 7 #include "base/single_thread_task_runner.h" |
| 8 #include "base/threading/thread_task_runner_handle.h" | 8 #include "base/threading/thread_task_runner_handle.h" |
| 9 | 9 |
| 10 namespace media { | 10 namespace media { |
| (...skipping 17 matching lines...) Expand all Loading... |
| 28 DCHECK(sink_); | 28 DCHECK(sink_); |
| 29 DCHECK(callback_); | 29 DCHECK(callback_); |
| 30 DCHECK(task_runner_->BelongsToCurrentThread()); | 30 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 31 } | 31 } |
| 32 | 32 |
| 33 SilentSinkSuspender::~SilentSinkSuspender() { | 33 SilentSinkSuspender::~SilentSinkSuspender() { |
| 34 DCHECK(task_runner_->BelongsToCurrentThread()); | 34 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 35 fake_sink_.Stop(); | 35 fake_sink_.Stop(); |
| 36 } | 36 } |
| 37 | 37 |
| 38 int SilentSinkSuspender::Render(base::TimeDelta delay, | 38 int SilentSinkSuspender::Render(AudioBus* dest, |
| 39 base::TimeTicks delay_timestamp, | 39 uint32_t frames_delayed, |
| 40 int prior_frames_skipped, | 40 uint32_t frames_skipped) { |
| 41 AudioBus* dest) { | |
| 42 // Lock required since AudioRendererSink::Pause() is not synchronous, we need | 41 // Lock required since AudioRendererSink::Pause() is not synchronous, we need |
| 43 // to discard these calls during the transition to the fake sink. | 42 // to discard these calls during the transition to the fake sink. |
| 44 base::AutoLock al(transition_lock_); | 43 base::AutoLock al(transition_lock_); |
| 45 if (is_using_fake_sink_ && dest) { | 44 if (is_using_fake_sink_ && dest) { |
| 46 // Audio should be silent at this point, if not, it will be handled once the | 45 // Audio should be silent at this point, if not, it will be handled once the |
| 47 // transition to the fake sink is complete. | 46 // transition to the fake sink is complete. |
| 48 dest->Zero(); | 47 dest->Zero(); |
| 49 return dest->frames(); | 48 return dest->frames(); |
| 50 } | 49 } |
| 51 | 50 |
| 52 // When we're using the |fake_sink_| a null destination will be sent; we store | 51 // When we're using the |fake_sink_| a null destination will be sent; we store |
| 53 // the audio data for a future transition out of silence. | 52 // the audio data for a future transition out of silence. |
| 54 if (!dest) { | 53 if (!dest) { |
| 55 DCHECK(is_using_fake_sink_); | 54 DCHECK(is_using_fake_sink_); |
| 56 DCHECK_EQ(delay, base::TimeDelta()); | 55 DCHECK_EQ(frames_delayed, 0u); |
| 57 DCHECK_EQ(prior_frames_skipped, 0); | 56 DCHECK_EQ(frames_skipped, 0u); |
| 58 | 57 |
| 59 // If we have no buffers or a transition is pending, one or more extra | 58 // 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 | 59 // Render() calls have occurred in before TransitionSinks() can run, so we |
| 61 // store this data for the eventual transition. | 60 // store this data for the eventual transition. |
| 62 if (buffers_after_silence_.empty() || is_transition_pending_) | 61 if (buffers_after_silence_.empty() || is_transition_pending_) |
| 63 buffers_after_silence_.push_back(AudioBus::Create(params_)); | 62 buffers_after_silence_.push_back(AudioBus::Create(params_)); |
| 64 dest = buffers_after_silence_.back().get(); | 63 dest = buffers_after_silence_.back().get(); |
| 65 } else if (!buffers_after_silence_.empty()) { | 64 } else if (!buffers_after_silence_.empty()) { |
| 66 // Drain any non-silent transitional buffers before queuing more audio data. | 65 // 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 | 66 // Note: These do not skew clocks derived from frame count since we don't |
| 68 // issue Render() to the client when returning these buffers. | 67 // issue Render() to the client when returning these buffers. |
| 69 DCHECK(!is_using_fake_sink_); | 68 DCHECK(!is_using_fake_sink_); |
| 70 buffers_after_silence_.front()->CopyTo(dest); | 69 buffers_after_silence_.front()->CopyTo(dest); |
| 71 buffers_after_silence_.pop_front(); | 70 buffers_after_silence_.pop_front(); |
| 72 return dest->frames(); | 71 return dest->frames(); |
| 73 } | 72 } |
| 74 | 73 |
| 75 // Pass-through to client and request rendering. | 74 // Pass-through to client and request rendering. |
| 76 callback_->Render(delay, delay_timestamp, prior_frames_skipped, dest); | 75 callback_->Render(dest, frames_delayed, frames_skipped); |
| 77 | 76 |
| 78 // Check for silence or real audio data and transition if necessary. | 77 // Check for silence or real audio data and transition if necessary. |
| 79 if (!dest->AreFramesZero()) { | 78 if (!dest->AreFramesZero()) { |
| 80 first_silence_time_ = base::TimeTicks(); | 79 first_silence_time_ = base::TimeTicks(); |
| 81 if (is_using_fake_sink_) { | 80 if (is_using_fake_sink_) { |
| 82 is_transition_pending_ = true; | 81 is_transition_pending_ = true; |
| 83 task_runner_->PostTask( | 82 task_runner_->PostTask( |
| 84 FROM_HERE, base::Bind(sink_transition_callback_.callback(), false)); | 83 FROM_HERE, base::Bind(sink_transition_callback_.callback(), false)); |
| 85 return dest->frames(); | 84 return dest->frames(); |
| 86 } | 85 } |
| (...skipping 30 matching lines...) Expand all Loading... |
| 117 // after this point, so we must acquire the lock to make sure we don't have | 116 // after this point, so we must acquire the lock to make sure we don't have |
| 118 // concurrent Render() execution. Once |is_using_fake_sink_| is set to true, | 117 // concurrent Render() execution. Once |is_using_fake_sink_| is set to true, |
| 119 // calls from |sink_| will be dropped. | 118 // calls from |sink_| will be dropped. |
| 120 { | 119 { |
| 121 base::AutoLock al(transition_lock_); | 120 base::AutoLock al(transition_lock_); |
| 122 is_transition_pending_ = false; | 121 is_transition_pending_ = false; |
| 123 is_using_fake_sink_ = true; | 122 is_using_fake_sink_ = true; |
| 124 } | 123 } |
| 125 fake_sink_.Start( | 124 fake_sink_.Start( |
| 126 base::Bind(base::IgnoreResult(&SilentSinkSuspender::Render), | 125 base::Bind(base::IgnoreResult(&SilentSinkSuspender::Render), |
| 127 base::Unretained(this), base::TimeDelta(), | 126 base::Unretained(this), nullptr, 0, 0)); |
| 128 base::TimeTicks::Now(), 0, nullptr)); | |
| 129 } else { | 127 } else { |
| 130 fake_sink_.Stop(); | 128 fake_sink_.Stop(); |
| 131 | 129 |
| 132 // Despite the fake sink having a synchronous Stop(), if this transition | 130 // Despite the fake sink having a synchronous Stop(), if this transition |
| 133 // occurs too soon after pausing the real sink, we may have pending Render() | 131 // occurs too soon after pausing the real sink, we may have pending Render() |
| 134 // calls from before the transition to the fake sink. As such, we need to | 132 // calls from before the transition to the fake sink. As such, we need to |
| 135 // hold the lock here to avoid any races. | 133 // hold the lock here to avoid any races. |
| 136 { | 134 { |
| 137 base::AutoLock al(transition_lock_); | 135 base::AutoLock al(transition_lock_); |
| 138 is_transition_pending_ = false; | 136 is_transition_pending_ = false; |
| 139 is_using_fake_sink_ = false; | 137 is_using_fake_sink_ = false; |
| 140 } | 138 } |
| 141 sink_->Play(); | 139 sink_->Play(); |
| 142 } | 140 } |
| 143 } | 141 } |
| 144 | 142 |
| 145 } // namespace content | 143 } // namespace content |
| OLD | NEW |