Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(960)

Side by Side Diff: media/audio/audio_output_device.cc

Issue 10958004: Prevent AudioDeviceThread from starting if clients have called Stop() (round 2). (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « media/audio/audio_output_device.h ('k') | media/audio/audio_output_device_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
42 42
43 AudioOutputDevice::AudioOutputDevice( 43 AudioOutputDevice::AudioOutputDevice(
44 AudioOutputIPC* ipc, 44 AudioOutputIPC* ipc,
45 const scoped_refptr<base::MessageLoopProxy>& io_loop) 45 const scoped_refptr<base::MessageLoopProxy>& io_loop)
46 : ScopedLoopObserver(io_loop), 46 : ScopedLoopObserver(io_loop),
47 input_channels_(0), 47 input_channels_(0),
48 callback_(NULL), 48 callback_(NULL),
49 ipc_(ipc), 49 ipc_(ipc),
50 stream_id_(0), 50 stream_id_(0),
51 play_on_start_(true), 51 play_on_start_(true),
52 is_started_(false) { 52 is_started_(false),
53 stopping_hack_(false) {
53 CHECK(ipc_); 54 CHECK(ipc_);
54 } 55 }
55 56
56 void AudioOutputDevice::Initialize(const AudioParameters& params, 57 void AudioOutputDevice::Initialize(const AudioParameters& params,
57 RenderCallback* callback) { 58 RenderCallback* callback) {
58 CHECK_EQ(0, stream_id_) << 59 CHECK_EQ(0, stream_id_) <<
59 "AudioOutputDevice::Initialize() must be called before Start()"; 60 "AudioOutputDevice::Initialize() must be called before Start()";
60 61
61 CHECK(!callback_); // Calling Initialize() twice? 62 CHECK(!callback_); // Calling Initialize() twice?
62 63
(...skipping 20 matching lines...) Expand all
83 DCHECK(callback_) << "Initialize hasn't been called"; 84 DCHECK(callback_) << "Initialize hasn't been called";
84 message_loop()->PostTask(FROM_HERE, 85 message_loop()->PostTask(FROM_HERE,
85 base::Bind(&AudioOutputDevice::CreateStreamOnIOThread, this, 86 base::Bind(&AudioOutputDevice::CreateStreamOnIOThread, this,
86 audio_parameters_, input_channels_)); 87 audio_parameters_, input_channels_));
87 } 88 }
88 89
89 void AudioOutputDevice::Stop() { 90 void AudioOutputDevice::Stop() {
90 { 91 {
91 base::AutoLock auto_lock(audio_thread_lock_); 92 base::AutoLock auto_lock(audio_thread_lock_);
92 audio_thread_.Stop(MessageLoop::current()); 93 audio_thread_.Stop(MessageLoop::current());
94 stopping_hack_ = true;
93 } 95 }
94 96
95 message_loop()->PostTask(FROM_HERE, 97 message_loop()->PostTask(FROM_HERE,
96 base::Bind(&AudioOutputDevice::ShutDownOnIOThread, this)); 98 base::Bind(&AudioOutputDevice::ShutDownOnIOThread, this));
97 } 99 }
98 100
99 void AudioOutputDevice::Play() { 101 void AudioOutputDevice::Play() {
100 message_loop()->PostTask(FROM_HERE, 102 message_loop()->PostTask(FROM_HERE,
101 base::Bind(&AudioOutputDevice::PlayOnIOThread, this)); 103 base::Bind(&AudioOutputDevice::PlayOnIOThread, this));
102 } 104 }
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
163 ipc_->RemoveDelegate(stream_id_); 165 ipc_->RemoveDelegate(stream_id_);
164 } 166 }
165 167
166 stream_id_ = 0; 168 stream_id_ = 0;
167 } 169 }
168 170
169 // We can run into an issue where ShutDownOnIOThread is called right after 171 // We can run into an issue where ShutDownOnIOThread is called right after
170 // OnStreamCreated is called in cases where Start/Stop are called before we 172 // OnStreamCreated is called in cases where Start/Stop are called before we
171 // get the OnStreamCreated callback. To handle that corner case, we call 173 // get the OnStreamCreated callback. To handle that corner case, we call
172 // Stop(). In most cases, the thread will already be stopped. 174 // Stop(). In most cases, the thread will already be stopped.
175 //
173 // Another situation is when the IO thread goes away before Stop() is called 176 // Another situation is when the IO thread goes away before Stop() is called
174 // in which case, we cannot use the message loop to close the thread handle 177 // in which case, we cannot use the message loop to close the thread handle
175 // and can't not rely on the main thread existing either. 178 // and can't rely on the main thread existing either.
179 base::AutoLock auto_lock_(audio_thread_lock_);
176 base::ThreadRestrictions::ScopedAllowIO allow_io; 180 base::ThreadRestrictions::ScopedAllowIO allow_io;
177 audio_thread_.Stop(NULL); 181 audio_thread_.Stop(NULL);
178 audio_callback_.reset(); 182 audio_callback_.reset();
183 stopping_hack_ = false;
179 } 184 }
180 185
181 void AudioOutputDevice::SetVolumeOnIOThread(double volume) { 186 void AudioOutputDevice::SetVolumeOnIOThread(double volume) {
182 DCHECK(message_loop()->BelongsToCurrentThread()); 187 DCHECK(message_loop()->BelongsToCurrentThread());
183 if (stream_id_) 188 if (stream_id_)
184 ipc_->SetVolume(stream_id_, volume); 189 ipc_->SetVolume(stream_id_, volume);
185 } 190 }
186 191
187 void AudioOutputDevice::OnStateChanged(AudioOutputIPCDelegate::State state) { 192 void AudioOutputDevice::OnStateChanged(AudioOutputIPCDelegate::State state) {
188 DCHECK(message_loop()->BelongsToCurrentThread()); 193 DCHECK(message_loop()->BelongsToCurrentThread());
(...skipping 28 matching lines...) Expand all
217 DCHECK_GE(socket_handle, 0); 222 DCHECK_GE(socket_handle, 0);
218 #endif 223 #endif
219 224
220 // We should only get this callback if stream_id_ is valid. If it is not, 225 // We should only get this callback if stream_id_ is valid. If it is not,
221 // the IPC layer should have closed the shared memory and socket handles 226 // the IPC layer should have closed the shared memory and socket handles
222 // for us and not invoked the callback. The basic assertion is that when 227 // for us and not invoked the callback. The basic assertion is that when
223 // stream_id_ is 0 the AudioOutputDevice instance is not registered as a 228 // stream_id_ is 0 the AudioOutputDevice instance is not registered as a
224 // delegate and hence it should not receive callbacks. 229 // delegate and hence it should not receive callbacks.
225 DCHECK(stream_id_); 230 DCHECK(stream_id_);
226 231
232 // We can receive OnStreamCreated() on the IO thread after the client has
233 // called Stop() but before ShutDownOnIOThread() is processed. In such a
234 // situation |callback_| might point to freed memory. Instead of starting
235 // |audio_thread_| do nothing and wait for ShutDownOnIOThread() to get called.
236 //
237 // TODO(scherkus): The real fix is to have sane ownership semantics. The fact
238 // that |callback_| (which should own and outlive this object!) can point to
239 // freed memory is a mess. AudioRendererSink should be non-refcounted so that
240 // owners (WebRtcAudioDeviceImpl, AudioRendererImpl, etc...) can Stop() and
241 // delete as they see fit. AudioOutputDevice should internally use WeakPtr
242 // to handle teardown and thread hopping. See http://crbug.com/151051 for
243 // details.
227 base::AutoLock auto_lock(audio_thread_lock_); 244 base::AutoLock auto_lock(audio_thread_lock_);
245 if (stopping_hack_)
246 return;
228 247
229 DCHECK(audio_thread_.IsStopped()); 248 DCHECK(audio_thread_.IsStopped());
230 audio_callback_.reset(new AudioOutputDevice::AudioThreadCallback( 249 audio_callback_.reset(new AudioOutputDevice::AudioThreadCallback(
231 audio_parameters_, input_channels_, handle, length, callback_)); 250 audio_parameters_, input_channels_, handle, length, callback_));
232 audio_thread_.Start(audio_callback_.get(), socket_handle, 251 audio_thread_.Start(audio_callback_.get(), socket_handle,
233 "AudioOutputDevice"); 252 "AudioOutputDevice");
234 253
235 // We handle the case where Play() and/or Pause() may have been called 254 // We handle the case where Play() and/or Pause() may have been called
236 // multiple times before OnStreamCreated() gets called. 255 // multiple times before OnStreamCreated() gets called.
237 is_started_ = true; 256 is_started_ = true;
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
323 // TODO(dalecurtis): Technically this is not always correct. Due to channel 342 // 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 343 // 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 344 // relying on AudioSyncReader::Read() to parse this with that in mind. Rename
326 // these methods to Set/GetActualFrameCount(). 345 // these methods to Set/GetActualFrameCount().
327 SetActualDataSizeInBytes( 346 SetActualDataSizeInBytes(
328 &shared_memory_, memory_length_, 347 &shared_memory_, memory_length_,
329 num_frames * sizeof(*output_bus_->channel(0)) * output_bus_->channels()); 348 num_frames * sizeof(*output_bus_->channel(0)) * output_bus_->channels());
330 } 349 }
331 350
332 } // namespace media. 351 } // namespace media.
OLDNEW
« no previous file with comments | « media/audio/audio_output_device.h ('k') | media/audio/audio_output_device_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698