OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "content/renderer/media/audio_device_thread.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/logging.h" | |
9 #include "base/message_loop.h" | |
10 #include "base/threading/platform_thread.h" | |
11 #include "base/threading/thread_restrictions.h" | |
12 #include "media/audio/audio_util.h" | |
13 | |
14 using base::PlatformThread; | |
15 | |
16 // The actual worker thread implementation. It's very bare bones and much | |
17 // simpler than SimpleThread (no synchronization in Start, etc) and supports | |
18 // joining the thread handle asynchronously via a provided message loop even | |
19 // after the Thread object itself has been deleted. | |
20 class AudioDeviceThread::Thread | |
21 : public PlatformThread::Delegate, | |
22 public base::RefCountedThreadSafe<AudioDeviceThread::Thread> { | |
23 public: | |
24 Thread(AudioDeviceThread::Callback* callback, | |
25 base::SyncSocket::Handle socket, | |
26 const char* thread_name); | |
27 | |
28 void Start(); | |
29 | |
30 // Stops the thread. If |loop_for_join| is non-NULL, the function posts | |
31 // a task to join (close) the thread handle later instead of waiting for | |
32 // the thread. If loop_for_join is NULL, then the function waits | |
33 // synchronously for the thread to terminate. | |
34 void Stop(MessageLoop* loop_for_join); | |
35 | |
36 private: | |
37 friend class base::RefCountedThreadSafe<AudioDeviceThread::Thread>; | |
38 virtual ~Thread(); | |
39 | |
40 // Overrides from PlatformThread::Delegate. | |
41 virtual void ThreadMain() OVERRIDE; | |
42 | |
43 // Runs the loop that reads from the socket. | |
44 void Run(); | |
45 | |
46 private: | |
47 base::PlatformThreadHandle thread_; | |
48 AudioDeviceThread::Callback* callback_; | |
49 base::CancelableSyncSocket socket_; | |
50 base::Lock callback_lock_; | |
51 const char* thread_name_; | |
52 | |
53 DISALLOW_COPY_AND_ASSIGN(Thread); | |
54 }; | |
55 | |
56 // AudioDeviceThread implementation | |
57 | |
58 AudioDeviceThread::AudioDeviceThread() { | |
59 } | |
60 | |
61 AudioDeviceThread::~AudioDeviceThread() { | |
62 DCHECK(!thread_); | |
63 } | |
64 | |
65 void AudioDeviceThread::Start(AudioDeviceThread::Callback* callback, | |
66 base::SyncSocket::Handle socket, | |
67 const char* thread_name) { | |
68 base::AutoLock auto_lock(thread_lock_); | |
69 CHECK(thread_ == NULL); | |
70 thread_ = new AudioDeviceThread::Thread(callback, socket, thread_name); | |
71 thread_->Start(); | |
72 } | |
73 | |
74 void AudioDeviceThread::Stop(MessageLoop* loop_for_join) { | |
75 base::AutoLock auto_lock(thread_lock_); | |
76 if (thread_) { | |
77 thread_->Stop(loop_for_join); | |
78 thread_ = NULL; | |
79 } | |
80 } | |
81 | |
82 bool AudioDeviceThread::IsStopped() { | |
83 base::AutoLock auto_lock(thread_lock_); | |
84 return thread_ == NULL; | |
85 } | |
86 | |
87 // AudioDeviceThread::Thread implementation | |
88 AudioDeviceThread::Thread::Thread(AudioDeviceThread::Callback* callback, | |
89 base::SyncSocket::Handle socket, | |
90 const char* thread_name) | |
91 : thread_(base::kNullThreadHandle), | |
92 callback_(callback), | |
93 socket_(socket), | |
94 thread_name_(thread_name) { | |
95 } | |
96 | |
97 AudioDeviceThread::Thread::~Thread() { | |
98 DCHECK_EQ(thread_, base::kNullThreadHandle) << "Stop wasn't called"; | |
99 } | |
100 | |
101 void AudioDeviceThread::Thread::Start() { | |
102 base::AutoLock auto_lock(callback_lock_); | |
103 DCHECK_EQ(thread_, base::kNullThreadHandle); | |
104 // This reference will be released when the thread exists. | |
105 AddRef(); | |
106 | |
107 PlatformThread::CreateWithPriority(0, this, &thread_, | |
108 base::kThreadPriority_RealtimeAudio); | |
109 CHECK(thread_ != base::kNullThreadHandle); | |
110 } | |
111 | |
112 void AudioDeviceThread::Thread::Stop(MessageLoop* loop_for_join) { | |
113 socket_.Shutdown(); | |
114 | |
115 base::PlatformThreadHandle thread = base::kNullThreadHandle; | |
116 | |
117 { // NOLINT | |
118 base::AutoLock auto_lock(callback_lock_); | |
119 callback_ = NULL; | |
120 std::swap(thread, thread_); | |
121 } | |
122 | |
123 if (thread != base::kNullThreadHandle) { | |
124 if (loop_for_join) { | |
125 loop_for_join->PostTask(FROM_HERE, | |
126 base::Bind(&base::PlatformThread::Join, thread)); | |
127 } else { | |
128 base::PlatformThread::Join(thread); | |
129 } | |
130 } | |
131 } | |
132 | |
133 void AudioDeviceThread::Thread::ThreadMain() { | |
134 PlatformThread::SetName(thread_name_); | |
135 | |
136 // Singleton access is safe from this thread as long as callback is non-NULL. | |
137 // The callback is the only point where the thread calls out to 'unknown' code | |
138 // that might touch singletons and the lifetime of the callback is controlled | |
139 // by another thread on which singleton access is OK as well. | |
140 base::ThreadRestrictions::SetSingletonAllowed(true); | |
141 | |
142 { // NOLINT | |
143 base::AutoLock auto_lock(callback_lock_); | |
144 if (callback_) | |
145 callback_->InitializeOnAudioThread(); | |
146 } | |
147 | |
148 Run(); | |
149 | |
150 // Release the reference for the thread. Note that after this, the Thread | |
151 // instance will most likely be deleted. | |
152 Release(); | |
153 } | |
154 | |
155 void AudioDeviceThread::Thread::Run() { | |
156 while (true) { | |
157 int pending_data = 0; | |
158 size_t bytes_read = socket_.Receive(&pending_data, sizeof(pending_data)); | |
159 if (bytes_read != sizeof(pending_data)) { | |
160 DCHECK_EQ(bytes_read, 0U); | |
161 break; | |
162 } | |
163 | |
164 base::AutoLock auto_lock(callback_lock_); | |
165 if (callback_) | |
166 callback_->Process(pending_data); | |
167 } | |
168 } | |
169 | |
170 // AudioDeviceThread::Callback implementation | |
171 | |
172 AudioDeviceThread::Callback::Callback( | |
173 const media::AudioParameters& audio_parameters, | |
174 base::SharedMemoryHandle memory, int memory_length) | |
175 : audio_parameters_(audio_parameters), | |
176 samples_per_ms_(audio_parameters.sample_rate() / 1000), | |
177 bytes_per_ms_(audio_parameters.channels() * | |
178 (audio_parameters_.bits_per_sample() / 8) * | |
179 samples_per_ms_), | |
180 shared_memory_(memory, false), | |
181 memory_length_(memory_length) { | |
182 CHECK_NE(bytes_per_ms_, 0); // Catch division by zero early. | |
183 CHECK_NE(samples_per_ms_, 0); | |
184 } | |
185 | |
186 AudioDeviceThread::Callback::~Callback() { | |
187 for (size_t i = 0; i < audio_data_.size(); ++i) | |
188 delete [] audio_data_[i]; | |
189 } | |
190 | |
191 void AudioDeviceThread::Callback::InitializeOnAudioThread() { | |
192 DCHECK(audio_data_.empty()); | |
193 | |
194 MapSharedMemory(); | |
195 DCHECK(shared_memory_.memory() != NULL); | |
196 | |
197 audio_data_.reserve(audio_parameters_.channels()); | |
198 for (int i = 0; i < audio_parameters_.channels(); ++i) { | |
199 float* channel_data = new float[audio_parameters_.frames_per_buffer()]; | |
200 audio_data_.push_back(channel_data); | |
201 } | |
202 } | |
OLD | NEW |