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