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