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 |