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 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
46 // Audio should be silent at this point, if not, it will be handled once the | 46 // Audio should be silent at this point, if not, it will be handled once the |
47 // transition to the fake sink is complete. | 47 // transition to the fake sink is complete. |
48 dest->Zero(); | 48 dest->Zero(); |
49 return dest->frames(); | 49 return dest->frames(); |
50 } | 50 } |
51 | 51 |
52 // When we're using the |fake_sink_| a null destination will be sent; we store | 52 // 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. | 53 // the audio data for a future transition out of silence. |
54 if (!dest) { | 54 if (!dest) { |
55 DCHECK(is_using_fake_sink_); | 55 DCHECK(is_using_fake_sink_); |
56 DCHECK_EQ(delay, base::TimeDelta()); | |
57 DCHECK_EQ(prior_frames_skipped, 0); | 56 DCHECK_EQ(prior_frames_skipped, 0); |
| 57 // |delay_timestamp| contains the value cached at |
| 58 // |latest_output_delay_timestamp_| |
| 59 // so we simulate the real sink output, promoting |delay_timestamp| with |
| 60 // |elapsedTime|. |
| 61 DCHECK_EQ(delay_timestamp, latest_output_delay_timestamp_); |
| 62 base::TimeDelta elapsedTime = |
| 63 base::TimeTicks::Now() - fake_sink_transition_time_; |
| 64 delay_timestamp += elapsedTime; |
58 | 65 |
59 // If we have no buffers or a transition is pending, one or more extra | 66 // 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 | 67 // Render() calls have occurred in before TransitionSinks() can run, so we |
61 // store this data for the eventual transition. | 68 // store this data for the eventual transition. |
62 if (buffers_after_silence_.empty() || is_transition_pending_) | 69 if (buffers_after_silence_.empty() || is_transition_pending_) |
63 buffers_after_silence_.push_back(AudioBus::Create(params_)); | 70 buffers_after_silence_.push_back(AudioBus::Create(params_)); |
64 dest = buffers_after_silence_.back().get(); | 71 dest = buffers_after_silence_.back().get(); |
65 } else if (!buffers_after_silence_.empty()) { | 72 } else if (!buffers_after_silence_.empty()) { |
66 // Drain any non-silent transitional buffers before queuing more audio data. | 73 // 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 | 74 // Note: These do not skew clocks derived from frame count since we don't |
(...skipping 15 matching lines...) Expand all Loading... |
83 task_runner_->PostTask( | 90 task_runner_->PostTask( |
84 FROM_HERE, base::Bind(sink_transition_callback_.callback(), false)); | 91 FROM_HERE, base::Bind(sink_transition_callback_.callback(), false)); |
85 return dest->frames(); | 92 return dest->frames(); |
86 } | 93 } |
87 } else if (!is_using_fake_sink_) { | 94 } else if (!is_using_fake_sink_) { |
88 const base::TimeTicks now = base::TimeTicks::Now(); | 95 const base::TimeTicks now = base::TimeTicks::Now(); |
89 if (first_silence_time_.is_null()) | 96 if (first_silence_time_.is_null()) |
90 first_silence_time_ = now; | 97 first_silence_time_ = now; |
91 if (now - first_silence_time_ > silence_timeout_) { | 98 if (now - first_silence_time_ > silence_timeout_) { |
92 is_transition_pending_ = true; | 99 is_transition_pending_ = true; |
| 100 latest_output_delay_ = delay; |
| 101 latest_output_delay_timestamp_ = delay_timestamp; |
| 102 fake_sink_transition_time_ = now; |
93 task_runner_->PostTask( | 103 task_runner_->PostTask( |
94 FROM_HERE, base::Bind(sink_transition_callback_.callback(), true)); | 104 FROM_HERE, base::Bind(sink_transition_callback_.callback(), true)); |
95 } | 105 } |
96 } | 106 } |
97 | 107 |
98 return dest->frames(); | 108 return dest->frames(); |
99 } | 109 } |
100 | 110 |
101 void SilentSinkSuspender::OnRenderError() { | 111 void SilentSinkSuspender::OnRenderError() { |
102 callback_->OnRenderError(); | 112 callback_->OnRenderError(); |
(...skipping 14 matching lines...) Expand all Loading... |
117 // after this point, so we must acquire the lock to make sure we don't have | 127 // 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, | 128 // concurrent Render() execution. Once |is_using_fake_sink_| is set to true, |
119 // calls from |sink_| will be dropped. | 129 // calls from |sink_| will be dropped. |
120 { | 130 { |
121 base::AutoLock al(transition_lock_); | 131 base::AutoLock al(transition_lock_); |
122 is_transition_pending_ = false; | 132 is_transition_pending_ = false; |
123 is_using_fake_sink_ = true; | 133 is_using_fake_sink_ = true; |
124 } | 134 } |
125 fake_sink_.Start( | 135 fake_sink_.Start( |
126 base::Bind(base::IgnoreResult(&SilentSinkSuspender::Render), | 136 base::Bind(base::IgnoreResult(&SilentSinkSuspender::Render), |
127 base::Unretained(this), base::TimeDelta(), | 137 base::Unretained(this), latest_output_delay_, |
128 base::TimeTicks::Now(), 0, nullptr)); | 138 latest_output_delay_timestamp_, 0, nullptr)); |
129 } else { | 139 } else { |
130 fake_sink_.Stop(); | 140 fake_sink_.Stop(); |
131 | 141 |
132 // Despite the fake sink having a synchronous Stop(), if this transition | 142 // 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() | 143 // 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 | 144 // calls from before the transition to the fake sink. As such, we need to |
135 // hold the lock here to avoid any races. | 145 // hold the lock here to avoid any races. |
136 { | 146 { |
137 base::AutoLock al(transition_lock_); | 147 base::AutoLock al(transition_lock_); |
138 is_transition_pending_ = false; | 148 is_transition_pending_ = false; |
139 is_using_fake_sink_ = false; | 149 is_using_fake_sink_ = false; |
140 } | 150 } |
141 sink_->Play(); | 151 sink_->Play(); |
142 } | 152 } |
143 } | 153 } |
144 | 154 |
145 } // namespace content | 155 } // namespace content |
OLD | NEW |