OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/audio/pulse/pulse_output.h" | 5 #include "media/audio/pulse/pulse_output.h" |
6 | 6 |
7 #include <pulse/pulseaudio.h> | 7 #include <pulse/pulseaudio.h> |
8 | 8 |
9 #include "base/single_thread_task_runner.h" | 9 #include "base/single_thread_task_runner.h" |
10 #include "media/audio/audio_manager_base.h" | 10 #include "media/audio/audio_manager_base.h" |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
42 const std::string& device_id, | 42 const std::string& device_id, |
43 AudioManagerBase* manager) | 43 AudioManagerBase* manager) |
44 : params_(params), | 44 : params_(params), |
45 device_id_(device_id), | 45 device_id_(device_id), |
46 manager_(manager), | 46 manager_(manager), |
47 pa_context_(NULL), | 47 pa_context_(NULL), |
48 pa_mainloop_(NULL), | 48 pa_mainloop_(NULL), |
49 pa_stream_(NULL), | 49 pa_stream_(NULL), |
50 volume_(1.0f), | 50 volume_(1.0f), |
51 source_callback_(NULL) { | 51 source_callback_(NULL) { |
52 DCHECK(manager_->GetTaskRunner()->BelongsToCurrentThread()); | |
53 | |
54 CHECK(params_.IsValid()); | 52 CHECK(params_.IsValid()); |
55 audio_bus_ = AudioBus::Create(params_); | 53 audio_bus_ = AudioBus::Create(params_); |
56 } | 54 } |
57 | 55 |
58 PulseAudioOutputStream::~PulseAudioOutputStream() { | 56 PulseAudioOutputStream::~PulseAudioOutputStream() { |
59 // All internal structures should already have been freed in Close(), which | 57 // All internal structures should already have been freed in Close(), which |
60 // calls AudioManagerBase::ReleaseOutputStream() which deletes this object. | 58 // calls AudioManagerBase::ReleaseOutputStream() which deletes this object. |
61 DCHECK(!pa_stream_); | 59 DCHECK(!pa_stream_); |
62 DCHECK(!pa_context_); | 60 DCHECK(!pa_context_); |
63 DCHECK(!pa_mainloop_); | 61 DCHECK(!pa_mainloop_); |
64 } | 62 } |
65 | 63 |
66 bool PulseAudioOutputStream::Open() { | 64 bool PulseAudioOutputStream::Open() { |
67 DCHECK(manager_->GetTaskRunner()->BelongsToCurrentThread()); | 65 DCHECK(thread_checker_.CalledOnValidThread()); |
68 return pulse::CreateOutputStream(&pa_mainloop_, &pa_context_, &pa_stream_, | 66 return pulse::CreateOutputStream(&pa_mainloop_, &pa_context_, &pa_stream_, |
69 params_, device_id_, &StreamNotifyCallback, | 67 params_, device_id_, &StreamNotifyCallback, |
70 &StreamRequestCallback, this); | 68 &StreamRequestCallback, this); |
71 } | 69 } |
72 | 70 |
73 void PulseAudioOutputStream::Reset() { | 71 void PulseAudioOutputStream::Reset() { |
74 if (!pa_mainloop_) { | 72 if (!pa_mainloop_) { |
75 DCHECK(!pa_stream_); | 73 DCHECK(!pa_stream_); |
76 DCHECK(!pa_context_); | 74 DCHECK(!pa_context_); |
77 return; | 75 return; |
(...skipping 24 matching lines...) Expand all Loading... |
102 pa_context_ = NULL; | 100 pa_context_ = NULL; |
103 } | 101 } |
104 } | 102 } |
105 | 103 |
106 pa_threaded_mainloop_stop(pa_mainloop_); | 104 pa_threaded_mainloop_stop(pa_mainloop_); |
107 pa_threaded_mainloop_free(pa_mainloop_); | 105 pa_threaded_mainloop_free(pa_mainloop_); |
108 pa_mainloop_ = NULL; | 106 pa_mainloop_ = NULL; |
109 } | 107 } |
110 | 108 |
111 void PulseAudioOutputStream::Close() { | 109 void PulseAudioOutputStream::Close() { |
112 DCHECK(manager_->GetTaskRunner()->BelongsToCurrentThread()); | 110 DCHECK(thread_checker_.CalledOnValidThread()); |
113 | 111 |
114 Reset(); | 112 Reset(); |
115 | 113 |
116 // Signal to the manager that we're closed and can be removed. | 114 // Signal to the manager that we're closed and can be removed. |
117 // This should be the last call in the function as it deletes "this". | 115 // This should be the last call in the function as it deletes "this". |
118 manager_->ReleaseOutputStream(this); | 116 manager_->ReleaseOutputStream(this); |
119 } | 117 } |
120 | 118 |
121 void PulseAudioOutputStream::FulfillWriteRequest(size_t requested_bytes) { | 119 void PulseAudioOutputStream::FulfillWriteRequest(size_t requested_bytes) { |
122 int bytes_remaining = requested_bytes; | 120 int bytes_remaining = requested_bytes; |
(...skipping 29 matching lines...) Expand all Loading... |
152 if (source_callback_) { | 150 if (source_callback_) { |
153 source_callback_->OnError(this); | 151 source_callback_->OnError(this); |
154 } | 152 } |
155 } | 153 } |
156 | 154 |
157 bytes_remaining -= bytes_to_fill; | 155 bytes_remaining -= bytes_to_fill; |
158 } | 156 } |
159 } | 157 } |
160 | 158 |
161 void PulseAudioOutputStream::Start(AudioSourceCallback* callback) { | 159 void PulseAudioOutputStream::Start(AudioSourceCallback* callback) { |
162 DCHECK(manager_->GetTaskRunner()->BelongsToCurrentThread()); | 160 DCHECK(thread_checker_.CalledOnValidThread()); |
163 CHECK(callback); | 161 CHECK(callback); |
164 CHECK(pa_stream_); | 162 CHECK(pa_stream_); |
165 | 163 |
166 AutoPulseLock auto_lock(pa_mainloop_); | 164 AutoPulseLock auto_lock(pa_mainloop_); |
167 | 165 |
168 // Ensure the context and stream are ready. | 166 // Ensure the context and stream are ready. |
169 if (pa_context_get_state(pa_context_) != PA_CONTEXT_READY && | 167 if (pa_context_get_state(pa_context_) != PA_CONTEXT_READY && |
170 pa_stream_get_state(pa_stream_) != PA_STREAM_READY) { | 168 pa_stream_get_state(pa_stream_) != PA_STREAM_READY) { |
171 callback->OnError(this); | 169 callback->OnError(this); |
172 return; | 170 return; |
173 } | 171 } |
174 | 172 |
175 source_callback_ = callback; | 173 source_callback_ = callback; |
176 | 174 |
177 // Uncork (resume) the stream. | 175 // Uncork (resume) the stream. |
178 pa_operation* operation = pa_stream_cork( | 176 pa_operation* operation = pa_stream_cork( |
179 pa_stream_, 0, &pulse::StreamSuccessCallback, pa_mainloop_); | 177 pa_stream_, 0, &pulse::StreamSuccessCallback, pa_mainloop_); |
180 WaitForOperationCompletion(pa_mainloop_, operation); | 178 WaitForOperationCompletion(pa_mainloop_, operation); |
181 } | 179 } |
182 | 180 |
183 void PulseAudioOutputStream::Stop() { | 181 void PulseAudioOutputStream::Stop() { |
184 DCHECK(manager_->GetTaskRunner()->BelongsToCurrentThread()); | 182 DCHECK(thread_checker_.CalledOnValidThread()); |
185 | 183 |
186 // Cork (pause) the stream. Waiting for the main loop lock will ensure | 184 // Cork (pause) the stream. Waiting for the main loop lock will ensure |
187 // outstanding callbacks have completed. | 185 // outstanding callbacks have completed. |
188 AutoPulseLock auto_lock(pa_mainloop_); | 186 AutoPulseLock auto_lock(pa_mainloop_); |
189 | 187 |
190 // Set |source_callback_| to NULL so all FulfillWriteRequest() calls which may | 188 // Set |source_callback_| to NULL so all FulfillWriteRequest() calls which may |
191 // occur while waiting on the flush and cork exit immediately. | 189 // occur while waiting on the flush and cork exit immediately. |
192 source_callback_ = NULL; | 190 source_callback_ = NULL; |
193 | 191 |
194 // Flush the stream prior to cork, doing so after will cause hangs. Write | 192 // Flush the stream prior to cork, doing so after will cause hangs. Write |
195 // callbacks are suspended while inside pa_threaded_mainloop_lock() so this | 193 // callbacks are suspended while inside pa_threaded_mainloop_lock() so this |
196 // is all thread safe. | 194 // is all thread safe. |
197 pa_operation* operation = pa_stream_flush( | 195 pa_operation* operation = pa_stream_flush( |
198 pa_stream_, &pulse::StreamSuccessCallback, pa_mainloop_); | 196 pa_stream_, &pulse::StreamSuccessCallback, pa_mainloop_); |
199 WaitForOperationCompletion(pa_mainloop_, operation); | 197 WaitForOperationCompletion(pa_mainloop_, operation); |
200 | 198 |
201 operation = pa_stream_cork(pa_stream_, 1, &pulse::StreamSuccessCallback, | 199 operation = pa_stream_cork(pa_stream_, 1, &pulse::StreamSuccessCallback, |
202 pa_mainloop_); | 200 pa_mainloop_); |
203 WaitForOperationCompletion(pa_mainloop_, operation); | 201 WaitForOperationCompletion(pa_mainloop_, operation); |
204 } | 202 } |
205 | 203 |
206 void PulseAudioOutputStream::SetVolume(double volume) { | 204 void PulseAudioOutputStream::SetVolume(double volume) { |
207 DCHECK(manager_->GetTaskRunner()->BelongsToCurrentThread()); | 205 DCHECK(thread_checker_.CalledOnValidThread()); |
208 | 206 |
209 volume_ = static_cast<float>(volume); | 207 volume_ = static_cast<float>(volume); |
210 } | 208 } |
211 | 209 |
212 void PulseAudioOutputStream::GetVolume(double* volume) { | 210 void PulseAudioOutputStream::GetVolume(double* volume) { |
213 DCHECK(manager_->GetTaskRunner()->BelongsToCurrentThread()); | 211 DCHECK(thread_checker_.CalledOnValidThread()); |
214 | 212 |
215 *volume = volume_; | 213 *volume = volume_; |
216 } | 214 } |
217 | 215 |
218 } // namespace media | 216 } // namespace media |
OLD | NEW |