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/audio_output_device.h" | 5 #include "media/audio/audio_output_device.h" |
6 | 6 |
7 #include "base/debug/trace_event.h" | 7 #include "base/debug/trace_event.h" |
8 #include "base/message_loop.h" | 8 #include "base/message_loop.h" |
9 #include "base/threading/thread_restrictions.h" | 9 #include "base/threading/thread_restrictions.h" |
10 #include "base/time.h" | 10 #include "base/time.h" |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
42 AudioOutputDevice::AudioOutputDevice( | 42 AudioOutputDevice::AudioOutputDevice( |
43 AudioOutputIPC* ipc, | 43 AudioOutputIPC* ipc, |
44 const scoped_refptr<base::MessageLoopProxy>& io_loop) | 44 const scoped_refptr<base::MessageLoopProxy>& io_loop) |
45 : ScopedLoopObserver(io_loop), | 45 : ScopedLoopObserver(io_loop), |
46 callback_(NULL), | 46 callback_(NULL), |
47 ipc_(ipc), | 47 ipc_(ipc), |
48 state_(IDLE), | 48 state_(IDLE), |
49 play_on_start_(true), | 49 play_on_start_(true), |
50 stopping_hack_(false) { | 50 stopping_hack_(false) { |
51 CHECK(ipc_); | 51 CHECK(ipc_); |
52 stream_id_ = ipc_->AddDelegate(this); | |
53 } | 52 } |
54 | 53 |
55 void AudioOutputDevice::Initialize(const AudioParameters& params, | 54 void AudioOutputDevice::Initialize(const AudioParameters& params, |
56 RenderCallback* callback) { | 55 RenderCallback* callback) { |
57 DCHECK(!callback_) << "Calling Initialize() twice?"; | 56 DCHECK(!callback_) << "Calling Initialize() twice?"; |
58 DCHECK(params.IsValid()); | 57 DCHECK(params.IsValid()); |
59 audio_parameters_ = params; | 58 audio_parameters_ = params; |
60 callback_ = callback; | 59 callback_ = callback; |
61 } | 60 } |
62 | 61 |
63 AudioOutputDevice::~AudioOutputDevice() { | 62 AudioOutputDevice::~AudioOutputDevice() { |
64 // The current design requires that the user calls Stop() before deleting | 63 // The current design requires that the user calls Stop() before deleting |
65 // this class. | 64 // this class. |
66 DCHECK(audio_thread_.IsStopped()); | 65 DCHECK(audio_thread_.IsStopped()); |
67 | |
68 if (ipc_) | |
69 ipc_->RemoveDelegate(stream_id_); | |
70 } | 66 } |
71 | 67 |
72 void AudioOutputDevice::Start() { | 68 void AudioOutputDevice::Start() { |
73 DCHECK(callback_) << "Initialize hasn't been called"; | 69 DCHECK(callback_) << "Initialize hasn't been called"; |
74 message_loop()->PostTask(FROM_HERE, | 70 message_loop()->PostTask(FROM_HERE, |
75 base::Bind(&AudioOutputDevice::CreateStreamOnIOThread, this, | 71 base::Bind(&AudioOutputDevice::CreateStreamOnIOThread, this, |
76 audio_parameters_)); | 72 audio_parameters_)); |
77 } | 73 } |
78 | 74 |
79 void AudioOutputDevice::Stop() { | 75 void AudioOutputDevice::Stop() { |
(...skipping 26 matching lines...) Expand all Loading... | |
106 return false; | 102 return false; |
107 } | 103 } |
108 | 104 |
109 return true; | 105 return true; |
110 } | 106 } |
111 | 107 |
112 void AudioOutputDevice::CreateStreamOnIOThread(const AudioParameters& params) { | 108 void AudioOutputDevice::CreateStreamOnIOThread(const AudioParameters& params) { |
113 DCHECK(message_loop()->BelongsToCurrentThread()); | 109 DCHECK(message_loop()->BelongsToCurrentThread()); |
114 if (state_ == IDLE) { | 110 if (state_ == IDLE) { |
115 state_ = CREATING_STREAM; | 111 state_ = CREATING_STREAM; |
116 ipc_->CreateStream(stream_id_, params); | 112 ipc_->CreateStream(this, params); |
117 } | 113 } |
118 } | 114 } |
119 | 115 |
120 void AudioOutputDevice::PlayOnIOThread() { | 116 void AudioOutputDevice::PlayOnIOThread() { |
121 DCHECK(message_loop()->BelongsToCurrentThread()); | 117 DCHECK(message_loop()->BelongsToCurrentThread()); |
122 if (state_ == PAUSED) { | 118 if (state_ == PAUSED) { |
123 ipc_->PlayStream(stream_id_); | 119 ipc_->PlayStream(); |
124 state_ = PLAYING; | 120 state_ = PLAYING; |
125 play_on_start_ = false; | 121 play_on_start_ = false; |
126 } else { | 122 } else { |
127 play_on_start_ = true; | 123 play_on_start_ = true; |
128 } | 124 } |
129 } | 125 } |
130 | 126 |
131 void AudioOutputDevice::PauseOnIOThread(bool flush) { | 127 void AudioOutputDevice::PauseOnIOThread(bool flush) { |
132 DCHECK(message_loop()->BelongsToCurrentThread()); | 128 DCHECK(message_loop()->BelongsToCurrentThread()); |
133 if (state_ == PLAYING) { | 129 if (state_ == PLAYING) { |
134 ipc_->PauseStream(stream_id_); | 130 ipc_->PauseStream(); |
135 if (flush) | 131 if (flush) |
136 ipc_->FlushStream(stream_id_); | 132 ipc_->FlushStream(); |
137 state_ = PAUSED; | 133 state_ = PAUSED; |
138 } else { | 134 } else { |
139 // Note that |flush| isn't relevant here since this is the case where | 135 // Note that |flush| isn't relevant here since this is the case where |
140 // the stream is first starting. | 136 // the stream is first starting. |
141 } | 137 } |
142 play_on_start_ = false; | 138 play_on_start_ = false; |
143 } | 139 } |
144 | 140 |
145 void AudioOutputDevice::ShutDownOnIOThread() { | 141 void AudioOutputDevice::ShutDownOnIOThread() { |
146 DCHECK(message_loop()->BelongsToCurrentThread()); | 142 DCHECK(message_loop()->BelongsToCurrentThread()); |
147 | 143 |
148 // Make sure we don't call shutdown more than once. | 144 // Make sure we don't call shutdown more than once. |
149 if (state_ >= CREATING_STREAM) { | 145 if (state_ >= CREATING_STREAM) { |
150 ipc_->CloseStream(stream_id_); | 146 ipc_->CloseStream(); |
151 state_ = IDLE; | 147 state_ = IDLE; |
152 } | 148 } |
153 | 149 |
154 // We can run into an issue where ShutDownOnIOThread is called right after | 150 // We can run into an issue where ShutDownOnIOThread is called right after |
155 // OnStreamCreated is called in cases where Start/Stop are called before we | 151 // OnStreamCreated is called in cases where Start/Stop are called before we |
156 // get the OnStreamCreated callback. To handle that corner case, we call | 152 // get the OnStreamCreated callback. To handle that corner case, we call |
157 // Stop(). In most cases, the thread will already be stopped. | 153 // Stop(). In most cases, the thread will already be stopped. |
158 // | 154 // |
159 // Another situation is when the IO thread goes away before Stop() is called | 155 // Another situation is when the IO thread goes away before Stop() is called |
160 // in which case, we cannot use the message loop to close the thread handle | 156 // in which case, we cannot use the message loop to close the thread handle |
161 // and can't rely on the main thread existing either. | 157 // and can't rely on the main thread existing either. |
162 base::AutoLock auto_lock_(audio_thread_lock_); | 158 base::AutoLock auto_lock_(audio_thread_lock_); |
163 base::ThreadRestrictions::ScopedAllowIO allow_io; | 159 base::ThreadRestrictions::ScopedAllowIO allow_io; |
164 audio_thread_.Stop(NULL); | 160 audio_thread_.Stop(NULL); |
165 audio_callback_.reset(); | 161 audio_callback_.reset(); |
166 stopping_hack_ = false; | 162 stopping_hack_ = false; |
167 } | 163 } |
168 | 164 |
169 void AudioOutputDevice::SetVolumeOnIOThread(double volume) { | 165 void AudioOutputDevice::SetVolumeOnIOThread(double volume) { |
170 DCHECK(message_loop()->BelongsToCurrentThread()); | 166 DCHECK(message_loop()->BelongsToCurrentThread()); |
171 if (state_ >= CREATING_STREAM) | 167 if (state_ >= CREATING_STREAM) |
172 ipc_->SetVolume(stream_id_, volume); | 168 ipc_->SetVolume(volume); |
173 } | 169 } |
174 | 170 |
175 void AudioOutputDevice::OnStateChanged(AudioOutputIPCDelegate::State state) { | 171 void AudioOutputDevice::OnStateChanged(AudioOutputIPCDelegate::State state) { |
176 DCHECK(message_loop()->BelongsToCurrentThread()); | 172 DCHECK(message_loop()->BelongsToCurrentThread()); |
177 | 173 |
178 // Do nothing if the stream has been closed. | 174 // Do nothing if the stream has been closed. |
179 if (state_ < CREATING_STREAM) | 175 if (state_ < CREATING_STREAM) |
180 return; | 176 return; |
181 | 177 |
182 if (state == AudioOutputIPCDelegate::kError) { | 178 if (state == AudioOutputIPCDelegate::kError) { |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
233 | 229 |
234 // We handle the case where Play() and/or Pause() may have been called | 230 // We handle the case where Play() and/or Pause() may have been called |
235 // multiple times before OnStreamCreated() gets called. | 231 // multiple times before OnStreamCreated() gets called. |
236 if (play_on_start_) | 232 if (play_on_start_) |
237 PlayOnIOThread(); | 233 PlayOnIOThread(); |
238 } | 234 } |
239 | 235 |
240 void AudioOutputDevice::OnIPCClosed() { | 236 void AudioOutputDevice::OnIPCClosed() { |
241 DCHECK(message_loop()->BelongsToCurrentThread()); | 237 DCHECK(message_loop()->BelongsToCurrentThread()); |
242 state_ = IPC_CLOSED; | 238 state_ = IPC_CLOSED; |
243 ipc_ = NULL; | |
DaleCurtis
2013/03/01 00:27:52
filter_ is destroyed after this is called, so you
miu
2013/03/02 00:24:16
That's why I added the comment in the header file
| |
244 } | 239 } |
245 | 240 |
246 void AudioOutputDevice::WillDestroyCurrentMessageLoop() { | 241 void AudioOutputDevice::WillDestroyCurrentMessageLoop() { |
247 LOG(ERROR) << "IO loop going away before the audio device has been stopped"; | 242 LOG(ERROR) << "IO loop going away before the audio device has been stopped"; |
248 ShutDownOnIOThread(); | 243 ShutDownOnIOThread(); |
249 } | 244 } |
250 | 245 |
251 // AudioOutputDevice::AudioThreadCallback | 246 // AudioOutputDevice::AudioThreadCallback |
252 | 247 |
253 AudioOutputDevice::AudioThreadCallback::AudioThreadCallback( | 248 AudioOutputDevice::AudioThreadCallback::AudioThreadCallback( |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
323 // TODO(dalecurtis): Technically this is not always correct. Due to channel | 318 // TODO(dalecurtis): Technically this is not always correct. Due to channel |
324 // padding for alignment, there may be more data available than this. We're | 319 // padding for alignment, there may be more data available than this. We're |
325 // relying on AudioSyncReader::Read() to parse this with that in mind. Rename | 320 // relying on AudioSyncReader::Read() to parse this with that in mind. Rename |
326 // these methods to Set/GetActualFrameCount(). | 321 // these methods to Set/GetActualFrameCount(). |
327 SetActualDataSizeInBytes( | 322 SetActualDataSizeInBytes( |
328 &shared_memory_, memory_length_, | 323 &shared_memory_, memory_length_, |
329 num_frames * sizeof(*output_bus_->channel(0)) * output_bus_->channels()); | 324 num_frames * sizeof(*output_bus_->channel(0)) * output_bus_->channels()); |
330 } | 325 } |
331 | 326 |
332 } // namespace media. | 327 } // namespace media. |
OLD | NEW |