Separate Simple Backend creation from initialization.
[chromium-blink-merge.git] / media / audio / audio_device_thread.cc
blob29dc291b6ac5762c6e4f3f3b73a19d19f7440422
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.h"
13 #include "base/threading/platform_thread.h"
14 #include "base/threading/thread_restrictions.h"
15 #include "media/audio/audio_util.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);
34 void Start();
36 // Stops the thread. If |loop_for_join| is non-NULL, the function posts
37 // a task to join (close) the thread handle later instead of waiting for
38 // the thread. If loop_for_join is NULL, then the function waits
39 // synchronously for the thread to terminate.
40 void Stop(MessageLoop* loop_for_join);
42 private:
43 friend class base::RefCountedThreadSafe<AudioDeviceThread::Thread>;
44 virtual ~Thread();
46 // Overrides from PlatformThread::Delegate.
47 virtual void ThreadMain() OVERRIDE;
49 // Runs the loop that reads from the socket.
50 void Run();
52 private:
53 base::PlatformThreadHandle thread_;
54 AudioDeviceThread::Callback* callback_;
55 base::CancelableSyncSocket socket_;
56 base::Lock callback_lock_;
57 const char* thread_name_;
59 DISALLOW_COPY_AND_ASSIGN(Thread);
62 // AudioDeviceThread implementation
64 AudioDeviceThread::AudioDeviceThread() {
67 AudioDeviceThread::~AudioDeviceThread() {
68 DCHECK(!thread_);
71 void AudioDeviceThread::Start(AudioDeviceThread::Callback* callback,
72 base::SyncSocket::Handle socket,
73 const char* thread_name) {
74 base::AutoLock auto_lock(thread_lock_);
75 CHECK(thread_ == NULL);
76 thread_ = new AudioDeviceThread::Thread(callback, socket, thread_name);
77 thread_->Start();
80 void AudioDeviceThread::Stop(MessageLoop* loop_for_join) {
81 base::AutoLock auto_lock(thread_lock_);
82 if (thread_) {
83 thread_->Stop(loop_for_join);
84 thread_ = NULL;
88 bool AudioDeviceThread::IsStopped() {
89 base::AutoLock auto_lock(thread_lock_);
90 return thread_ == NULL;
93 // AudioDeviceThread::Thread implementation
94 AudioDeviceThread::Thread::Thread(AudioDeviceThread::Callback* callback,
95 base::SyncSocket::Handle socket,
96 const char* thread_name)
97 : thread_(base::kNullThreadHandle),
98 callback_(callback),
99 socket_(socket),
100 thread_name_(thread_name) {
103 AudioDeviceThread::Thread::~Thread() {
104 DCHECK_EQ(thread_, base::kNullThreadHandle) << "Stop wasn't called";
107 void AudioDeviceThread::Thread::Start() {
108 base::AutoLock auto_lock(callback_lock_);
109 DCHECK_EQ(thread_, base::kNullThreadHandle);
110 // This reference will be released when the thread exists.
111 AddRef();
113 PlatformThread::CreateWithPriority(0, this, &thread_,
114 base::kThreadPriority_RealtimeAudio);
115 CHECK(thread_ != base::kNullThreadHandle);
118 void AudioDeviceThread::Thread::Stop(MessageLoop* loop_for_join) {
119 socket_.Shutdown();
121 base::PlatformThreadHandle thread = base::kNullThreadHandle;
123 { // NOLINT
124 base::AutoLock auto_lock(callback_lock_);
125 callback_ = NULL;
126 std::swap(thread, thread_);
129 if (thread != base::kNullThreadHandle) {
130 if (loop_for_join) {
131 loop_for_join->PostTask(FROM_HERE,
132 base::Bind(&base::PlatformThread::Join, thread));
133 } else {
134 base::PlatformThread::Join(thread);
139 void AudioDeviceThread::Thread::ThreadMain() {
140 PlatformThread::SetName(thread_name_);
142 // Singleton access is safe from this thread as long as callback is non-NULL.
143 // The callback is the only point where the thread calls out to 'unknown' code
144 // that might touch singletons and the lifetime of the callback is controlled
145 // by another thread on which singleton access is OK as well.
146 base::ThreadRestrictions::SetSingletonAllowed(true);
148 { // NOLINT
149 base::AutoLock auto_lock(callback_lock_);
150 if (callback_)
151 callback_->InitializeOnAudioThread();
154 Run();
156 // Release the reference for the thread. Note that after this, the Thread
157 // instance will most likely be deleted.
158 Release();
161 void AudioDeviceThread::Thread::Run() {
162 while (true) {
163 int pending_data = 0;
164 size_t bytes_read = socket_.Receive(&pending_data, sizeof(pending_data));
165 if (bytes_read != sizeof(pending_data)) {
166 DCHECK_EQ(bytes_read, 0U);
167 break;
170 base::AutoLock auto_lock(callback_lock_);
171 if (callback_)
172 callback_->Process(pending_data);
176 // AudioDeviceThread::Callback implementation
178 AudioDeviceThread::Callback::Callback(
179 const AudioParameters& audio_parameters,
180 base::SharedMemoryHandle memory,
181 int memory_length,
182 int total_segments)
183 : audio_parameters_(audio_parameters),
184 samples_per_ms_(audio_parameters.sample_rate() / 1000),
185 bytes_per_ms_(audio_parameters.channels() *
186 (audio_parameters_.bits_per_sample() / 8) *
187 samples_per_ms_),
188 shared_memory_(memory, false),
189 memory_length_(memory_length),
190 total_segments_(total_segments) {
191 CHECK_NE(bytes_per_ms_, 0); // Catch division by zero early.
192 CHECK_NE(samples_per_ms_, 0);
193 CHECK_GT(total_segments_, 0);
194 CHECK_EQ(memory_length_ % total_segments_, 0);
195 segment_length_ = memory_length_ / total_segments_;
198 AudioDeviceThread::Callback::~Callback() {}
200 void AudioDeviceThread::Callback::InitializeOnAudioThread() {
201 MapSharedMemory();
202 CHECK(shared_memory_.memory());
205 } // namespace media.