Create an initial chrome://supervised-user-internals page
[chromium-blink-merge.git] / media / audio / audio_device_thread.cc
bloba0f283ee5638ae49c01637c402c511700b942dfe
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/numerics/safe_conversions.h"
14 #include "base/threading/platform_thread.h"
15 #include "base/threading/thread_restrictions.h"
16 #include "media/base/audio_bus.h"
18 using base::PlatformThread;
20 namespace media {
22 // The actual worker thread implementation. It's very bare bones and much
23 // simpler than SimpleThread (no synchronization in Start, etc) and supports
24 // joining the thread handle asynchronously via a provided message loop even
25 // after the Thread object itself has been deleted.
26 class AudioDeviceThread::Thread
27 : public PlatformThread::Delegate,
28 public base::RefCountedThreadSafe<AudioDeviceThread::Thread> {
29 public:
30 Thread(AudioDeviceThread::Callback* callback,
31 base::SyncSocket::Handle socket,
32 const char* thread_name,
33 bool synchronized_buffers);
35 void Start();
37 // Stops the thread. If |loop_for_join| is non-NULL, the function posts
38 // a task to join (close) the thread handle later instead of waiting for
39 // the thread. If loop_for_join is NULL, then the function waits
40 // synchronously for the thread to terminate.
41 void Stop(base::MessageLoop* loop_for_join);
43 private:
44 friend class base::RefCountedThreadSafe<AudioDeviceThread::Thread>;
45 ~Thread() override;
47 // Overrides from PlatformThread::Delegate.
48 void ThreadMain() override;
50 // Runs the loop that reads from the socket.
51 void Run();
53 private:
54 base::PlatformThreadHandle thread_;
55 AudioDeviceThread::Callback* callback_;
56 base::CancelableSyncSocket socket_;
57 base::Lock callback_lock_;
58 const char* thread_name_;
59 const bool synchronized_buffers_;
61 DISALLOW_COPY_AND_ASSIGN(Thread);
64 // AudioDeviceThread implementation
66 AudioDeviceThread::AudioDeviceThread() {
69 AudioDeviceThread::~AudioDeviceThread() { DCHECK(!thread_.get()); }
71 void AudioDeviceThread::Start(AudioDeviceThread::Callback* callback,
72 base::SyncSocket::Handle socket,
73 const char* thread_name,
74 bool synchronized_buffers) {
75 base::AutoLock auto_lock(thread_lock_);
76 CHECK(!thread_.get());
77 thread_ = new AudioDeviceThread::Thread(
78 callback, socket, thread_name, synchronized_buffers);
79 thread_->Start();
82 void AudioDeviceThread::Stop(base::MessageLoop* loop_for_join) {
83 base::AutoLock auto_lock(thread_lock_);
84 if (thread_.get()) {
85 thread_->Stop(loop_for_join);
86 thread_ = NULL;
90 bool AudioDeviceThread::IsStopped() {
91 base::AutoLock auto_lock(thread_lock_);
92 return !thread_.get();
95 // AudioDeviceThread::Thread implementation
96 AudioDeviceThread::Thread::Thread(AudioDeviceThread::Callback* callback,
97 base::SyncSocket::Handle socket,
98 const char* thread_name,
99 bool synchronized_buffers)
100 : thread_(),
101 callback_(callback),
102 socket_(socket),
103 thread_name_(thread_name),
104 synchronized_buffers_(synchronized_buffers) {
107 AudioDeviceThread::Thread::~Thread() {
108 DCHECK(thread_.is_null());
111 void AudioDeviceThread::Thread::Start() {
112 base::AutoLock auto_lock(callback_lock_);
113 DCHECK(thread_.is_null());
114 // This reference will be released when the thread exists.
115 AddRef();
117 PlatformThread::CreateWithPriority(0, this, &thread_,
118 base::ThreadPriority::REALTIME_AUDIO);
119 CHECK(!thread_.is_null());
122 void AudioDeviceThread::Thread::Stop(base::MessageLoop* loop_for_join) {
123 socket_.Shutdown();
125 base::PlatformThreadHandle thread = base::PlatformThreadHandle();
127 { // NOLINT
128 base::AutoLock auto_lock(callback_lock_);
129 callback_ = NULL;
130 std::swap(thread, thread_);
133 if (!thread.is_null()) {
134 if (loop_for_join) {
135 loop_for_join->PostTask(FROM_HERE,
136 base::Bind(&base::PlatformThread::Join, thread));
137 } else {
138 base::PlatformThread::Join(thread);
143 void AudioDeviceThread::Thread::ThreadMain() {
144 PlatformThread::SetName(thread_name_);
146 // Singleton access is safe from this thread as long as callback is non-NULL.
147 // The callback is the only point where the thread calls out to 'unknown' code
148 // that might touch singletons and the lifetime of the callback is controlled
149 // by another thread on which singleton access is OK as well.
150 base::ThreadRestrictions::SetSingletonAllowed(true);
152 { // NOLINT
153 base::AutoLock auto_lock(callback_lock_);
154 if (callback_)
155 callback_->InitializeOnAudioThread();
158 Run();
160 // Release the reference for the thread. Note that after this, the Thread
161 // instance will most likely be deleted.
162 Release();
165 void AudioDeviceThread::Thread::Run() {
166 uint32 buffer_index = 0;
167 while (true) {
168 uint32 pending_data = 0;
169 size_t bytes_read = socket_.Receive(&pending_data, sizeof(pending_data));
170 if (bytes_read != sizeof(pending_data))
171 break;
173 // kuint32max is a special signal which is returned after the browser
174 // stops the output device in response to a renderer side request.
176 // Avoid running Process() for the paused signal, we still need to update
177 // the buffer index if |synchronized_buffers_| is true though.
179 // See comments in AudioOutputController::DoPause() for details on why.
180 if (pending_data != kuint32max) {
181 base::AutoLock auto_lock(callback_lock_);
182 if (callback_)
183 callback_->Process(pending_data);
186 // Let the other end know which buffer we just filled. The buffer index is
187 // used to ensure the other end is getting the buffer it expects. For more
188 // details on how this works see AudioSyncReader::WaitUntilDataIsReady().
189 if (synchronized_buffers_) {
190 ++buffer_index;
191 size_t bytes_sent = socket_.Send(&buffer_index, sizeof(buffer_index));
192 if (bytes_sent != sizeof(buffer_index))
193 break;
198 // AudioDeviceThread::Callback implementation
200 AudioDeviceThread::Callback::Callback(
201 const AudioParameters& audio_parameters,
202 base::SharedMemoryHandle memory,
203 int memory_length,
204 int total_segments)
205 : audio_parameters_(audio_parameters),
206 samples_per_ms_(audio_parameters.sample_rate() / 1000),
207 bytes_per_ms_(audio_parameters.channels() *
208 (audio_parameters_.bits_per_sample() / 8) *
209 samples_per_ms_),
210 shared_memory_(memory, false),
211 memory_length_(memory_length),
212 total_segments_(total_segments) {
213 CHECK_NE(bytes_per_ms_, 0); // Catch division by zero early.
214 CHECK_NE(samples_per_ms_, 0);
215 CHECK_GT(total_segments_, 0);
216 CHECK_EQ(memory_length_ % total_segments_, 0);
217 segment_length_ = memory_length_ / total_segments_;
220 AudioDeviceThread::Callback::~Callback() {}
222 void AudioDeviceThread::Callback::InitializeOnAudioThread() {
223 MapSharedMemory();
224 CHECK(shared_memory_.memory());
227 } // namespace media.