Index: content/renderer/media/audio_device.h |
diff --git a/content/renderer/media/audio_device.h b/content/renderer/media/audio_device.h |
index de6ba3b0e2df9da6bd6a11b4fe5c44c5bee67b56..0d48fc84e3ad4dd0ebc51af8c43f4293bc31a314 100644 |
--- a/content/renderer/media/audio_device.h |
+++ b/content/renderer/media/audio_device.h |
@@ -66,7 +66,9 @@ |
#include <vector> |
#include "base/basictypes.h" |
+#include "base/bind.h" |
#include "base/memory/scoped_ptr.h" |
+#include "base/message_loop.h" |
#include "base/shared_memory.h" |
#include "base/synchronization/lock.h" |
#include "base/threading/simple_thread.h" |
@@ -75,14 +77,77 @@ |
#include "media/audio/audio_parameters.h" |
#include "media/base/audio_renderer_sink.h" |
-namespace base { |
-class WaitableEvent; |
-} |
+// A common base class for AudioDevice and AudioInputDevice that manages |
+// the IO message loop pointer and monitors it for destruction. |
+// When the loop goes away, we automatically stop any running streams. |
+template <class T> |
+class AudioDeviceIOLoopObserver |
+ : public MessageLoop::DestructionObserver { |
+ public: |
+ AudioDeviceIOLoopObserver() |
+ : io_loop_( |
+ ChildProcess::current()->io_message_loop()->message_loop_proxy()) { |
+ // Watch the IO loop and make sure that we stop the audio thread before we |
+ // lose the IO thread. |
+ ObserveIOLoopDestruction(true, NULL); |
+ } |
+ |
+ ~AudioDeviceIOLoopObserver() { |
+ ObserveIOLoopDestruction(false, NULL); |
+ } |
+ |
+ protected: |
+ // Accessor to the IO loop that's used by the derived class. |
+ base::MessageLoopProxy* loop() { return io_loop_; } |
+ |
+ private: |
+ // MessageLoop::DestructionObserver implementation. |
+ // Called on the IO thread when the thread is going away. |
+ virtual void WillDestroyCurrentMessageLoop() OVERRIDE { |
+ DCHECK(io_loop_->BelongsToCurrentThread()); |
+ // The IO thread is terminating. We must stop the audio thread before the |
+ // IO thread goes away. |
+ static_cast<T*>(this)->ShutDownOnIOThread(NULL); |
+ } |
+ |
+ // Call from the IO thread to add or remove ourselves from the list of |
+ // destruction observers for the IO message loop. |
+ void ObserveIOLoopDestruction(bool enable, base::WaitableEvent* done) { |
+ if (io_loop_->BelongsToCurrentThread()) { |
+ MessageLoop* loop = MessageLoop::current(); |
+ enable ? loop->AddDestructionObserver(this) : |
enal1
2012/01/31 17:23:54
Why not regular if statement?
tommi (sloooow) - chröme
2012/02/01 14:50:49
Done.
|
+ loop->RemoveDestructionObserver(this); |
+ } else { |
+ base::WaitableEvent event(false, false); |
+ if (io_loop_->PostTask(FROM_HERE, |
enal1
2012/01/31 17:23:54
Are you sure we can post anything on IO loop if lo
tommi (sloooow) - chröme
2012/02/01 14:50:49
It's OK if the loop is being deleted and PostTask
|
+ base::Bind( |
+ &AudioDeviceIOLoopObserver<T>::ObserveIOLoopDestruction, |
+ base::Unretained(this), enable, &event))) { |
+ event.Wait(); |
+ } else { |
+ // The IO thread has already terminated, so no need to wait. |
+ } |
+ } |
+ |
+ if (done) |
+ done->Signal(); |
+ } |
+ |
+ // A pointer to the IO thread's message loop. That's here we do control the |
+ // stream from. It is possible during shutdown that the IO thread has gone |
+ // away before the user of the AudioDevice instance has called Stop(). |
+ // So, we need to be prepared to stop and take down the audio thread if |
+ // the IO thread ever goes away while we're still playing. |
+ // So, when this pointer is NULL, the IO thread has gone away and all methods |
+ // that post to it, must check for this first. |
enal1
2012/01/31 17:23:54
I don't see how this pointer can become NULL. It i
tommi (sloooow) - chröme
2012/02/01 14:50:49
It cannot become NULL - did you see any checks for
|
+ scoped_refptr<base::MessageLoopProxy> io_loop_; |
+}; |
class CONTENT_EXPORT AudioDevice |
: NON_EXPORTED_BASE(public media::AudioRendererSink), |
public AudioMessageFilter::Delegate, |
- public base::DelegateSimpleThread::Delegate { |
+ public base::DelegateSimpleThread::Delegate, |
+ public AudioDeviceIOLoopObserver<AudioDevice> { |
public: |
// Methods called on main render thread ------------------------------------- |
@@ -154,6 +219,8 @@ class CONTENT_EXPORT AudioDevice |
void InitializeOnIOThread(const AudioParameters& params); |
void PlayOnIOThread(); |
void PauseOnIOThread(bool flush); |
+ // Allow AudioDeviceIOLoopObserver to call ShutDownOnIOThread. |
+ friend class AudioDeviceIOLoopObserver<AudioDevice>; |
void ShutDownOnIOThread(base::WaitableEvent* signal); |
void SetVolumeOnIOThread(double volume); |