Report errors from ChromiumEnv::GetChildren in Posix.
[chromium-blink-merge.git] / media / audio / audio_device_thread.cc
blob6998890dd2fc9ef29e80c6b8131406f718b9f393
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
3 // found in the LICENSE file.
5 #include "media/audio/audio_device_thread.h"
7 #include <algorithm>
9 #include "base/bind.h"
10 #include "base/logging.h"
11 #include "base/memory/aligned_memory.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/threading/platform_thread.h"
14 #include "base/threading/thread_restrictions.h"
15 #include "media/base/audio_bus.h"
17 using base::PlatformThread;
19 namespace media {
21 // The actual worker thread implementation. It's very bare bones and much
22 // simpler than SimpleThread (no synchronization in Start, etc) and supports
23 // joining the thread handle asynchronously via a provided message loop even
24 // after the Thread object itself has been deleted.
25 class AudioDeviceThread::Thread
26 : public PlatformThread::Delegate,
27 public base::RefCountedThreadSafe<AudioDeviceThread::Thread> {
28 public:
29 Thread(AudioDeviceThread::Callback* callback,
30 base::SyncSocket::Handle socket,
31 const char* thread_name);
33 void Start();
35 // Stops the thread. If |loop_for_join| is non-NULL, the function posts
36 // a task to join (close) the thread handle later instead of waiting for
37 // the thread. If loop_for_join is NULL, then the function waits
38 // synchronously for the thread to terminate.
39 void Stop(base::MessageLoop* loop_for_join);
41 private:
42 friend class base::RefCountedThreadSafe<AudioDeviceThread::Thread>;
43 virtual ~Thread();
45 // Overrides from PlatformThread::Delegate.
46 virtual void ThreadMain() OVERRIDE;
48 // Runs the loop that reads from the socket.
49 void Run();
51 private:
52 base::PlatformThreadHandle thread_;
53 AudioDeviceThread::Callback* callback_;
54 base::CancelableSyncSocket socket_;
55 base::Lock callback_lock_;
56 const char* thread_name_;
58 DISALLOW_COPY_AND_ASSIGN(Thread);
61 // AudioDeviceThread implementation
63 AudioDeviceThread::AudioDeviceThread() {
66 AudioDeviceThread::~AudioDeviceThread() { DCHECK(!thread_.get()); }
68 void AudioDeviceThread::Start(AudioDeviceThread::Callback* callback,
69 base::SyncSocket::Handle socket,
70 const char* thread_name) {
71 base::AutoLock auto_lock(thread_lock_);
72 CHECK(thread_.get() == NULL);
73 thread_ = new AudioDeviceThread::Thread(callback, socket, thread_name);
74 thread_->Start();
77 void AudioDeviceThread::Stop(base::MessageLoop* loop_for_join) {
78 base::AutoLock auto_lock(thread_lock_);
79 if (thread_.get()) {
80 thread_->Stop(loop_for_join);
81 thread_ = NULL;
85 bool AudioDeviceThread::IsStopped() {
86 base::AutoLock auto_lock(thread_lock_);
87 return thread_.get() == NULL;
90 // AudioDeviceThread::Thread implementation
91 AudioDeviceThread::Thread::Thread(AudioDeviceThread::Callback* callback,
92 base::SyncSocket::Handle socket,
93 const char* thread_name)
94 : thread_(),
95 callback_(callback),
96 socket_(socket),
97 thread_name_(thread_name) {
100 AudioDeviceThread::Thread::~Thread() {
101 DCHECK(thread_.is_null());
104 void AudioDeviceThread::Thread::Start() {
105 base::AutoLock auto_lock(callback_lock_);
106 DCHECK(thread_.is_null());
107 // This reference will be released when the thread exists.
108 AddRef();
110 PlatformThread::CreateWithPriority(0, this, &thread_,
111 base::kThreadPriority_RealtimeAudio);
112 CHECK(!thread_.is_null());
115 void AudioDeviceThread::Thread::Stop(base::MessageLoop* loop_for_join) {
116 socket_.Shutdown();
118 base::PlatformThreadHandle thread = base::PlatformThreadHandle();
120 { // NOLINT
121 base::AutoLock auto_lock(callback_lock_);
122 callback_ = NULL;
123 std::swap(thread, thread_);
126 if (!thread.is_null()) {
127 if (loop_for_join) {
128 loop_for_join->PostTask(FROM_HERE,
129 base::Bind(&base::PlatformThread::Join, thread));
130 } else {
131 base::PlatformThread::Join(thread);
136 void AudioDeviceThread::Thread::ThreadMain() {
137 PlatformThread::SetName(thread_name_);
139 // Singleton access is safe from this thread as long as callback is non-NULL.
140 // The callback is the only point where the thread calls out to 'unknown' code
141 // that might touch singletons and the lifetime of the callback is controlled
142 // by another thread on which singleton access is OK as well.
143 base::ThreadRestrictions::SetSingletonAllowed(true);
145 { // NOLINT
146 base::AutoLock auto_lock(callback_lock_);
147 if (callback_)
148 callback_->InitializeOnAudioThread();
151 Run();
153 // Release the reference for the thread. Note that after this, the Thread
154 // instance will most likely be deleted.
155 Release();
158 void AudioDeviceThread::Thread::Run() {
159 while (true) {
160 int pending_data = 0;
161 size_t bytes_read = socket_.Receive(&pending_data, sizeof(pending_data));
162 if (bytes_read != sizeof(pending_data)) {
163 DCHECK_EQ(bytes_read, 0U);
164 break;
167 base::AutoLock auto_lock(callback_lock_);
168 if (callback_)
169 callback_->Process(pending_data);
173 // AudioDeviceThread::Callback implementation
175 AudioDeviceThread::Callback::Callback(
176 const AudioParameters& audio_parameters,
177 base::SharedMemoryHandle memory,
178 int memory_length,
179 int total_segments)
180 : audio_parameters_(audio_parameters),
181 samples_per_ms_(audio_parameters.sample_rate() / 1000),
182 bytes_per_ms_(audio_parameters.channels() *
183 (audio_parameters_.bits_per_sample() / 8) *
184 samples_per_ms_),
185 shared_memory_(memory, false),
186 memory_length_(memory_length),
187 total_segments_(total_segments) {
188 CHECK_NE(bytes_per_ms_, 0); // Catch division by zero early.
189 CHECK_NE(samples_per_ms_, 0);
190 CHECK_GT(total_segments_, 0);
191 CHECK_EQ(memory_length_ % total_segments_, 0);
192 segment_length_ = memory_length_ / total_segments_;
195 AudioDeviceThread::Callback::~Callback() {}
197 void AudioDeviceThread::Callback::InitializeOnAudioThread() {
198 MapSharedMemory();
199 CHECK(shared_memory_.memory());
202 } // namespace media.