Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1106)

Side by Side Diff: media/audio/audio_device_thread.cc

Issue 1703473002: Make AudioOutputDevice restartable and reinitializable (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@new_mixing
Patch Set: Code review (guidou@). Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/audio/audio_device_thread.h" 5 #include "media/audio/audio_device_thread.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 #include <stdint.h> 8 #include <stdint.h>
9 9
10 #include <algorithm> 10 #include <algorithm>
11 #include <limits> 11 #include <limits>
12 12
13 #include "base/bind.h" 13 #include "base/bind.h"
14 #include "base/logging.h" 14 #include "base/logging.h"
15 #include "base/macros.h" 15 #include "base/macros.h"
16 #include "base/memory/aligned_memory.h" 16 #include "base/memory/aligned_memory.h"
17 #include "base/message_loop/message_loop.h" 17 #include "base/message_loop/message_loop.h"
18 #include "base/numerics/safe_conversions.h" 18 #include "base/numerics/safe_conversions.h"
19 #include "base/synchronization/condition_variable.h"
19 #include "base/threading/platform_thread.h" 20 #include "base/threading/platform_thread.h"
20 #include "base/threading/thread_restrictions.h" 21 #include "base/threading/thread_restrictions.h"
21 #include "media/base/audio_bus.h" 22 #include "media/base/audio_bus.h"
22 23
23 using base::PlatformThread; 24 using base::PlatformThread;
24 25
25 namespace media { 26 namespace media {
26 27
27 // The actual worker thread implementation. It's very bare bones and much 28 // The actual worker thread implementation. It's very bare bones and much
28 // simpler than SimpleThread (no synchronization in Start, etc) and supports 29 // simpler than SimpleThread (no synchronization in Start, etc) and supports
29 // joining the thread handle asynchronously via a provided message loop even 30 // joining the thread handle asynchronously via a provided message loop even
30 // after the Thread object itself has been deleted. 31 // after the Thread object itself has been deleted.
31 class AudioDeviceThread::Thread 32 class AudioDeviceThread::Thread
32 : public PlatformThread::Delegate, 33 : public PlatformThread::Delegate,
33 public base::RefCountedThreadSafe<AudioDeviceThread::Thread> { 34 public base::RefCountedThreadSafe<AudioDeviceThread::Thread> {
34 public: 35 public:
35 Thread(AudioDeviceThread::Callback* callback, 36 Thread(const char* thread_name, bool synchronized_buffers);
36 base::SyncSocket::Handle socket,
37 const char* thread_name,
38 bool synchronized_buffers);
39 37
38 // Starts the thread which will wait in ThreadMain(). Resume() must then be
39 // called to actually start running it.
40 void Start(); 40 void Start();
41 41
42 // Stops the thread. If |loop_for_join| is non-NULL, the function posts 42 // Shuts down the thread. If |loop_for_join| is non-NULL, the function posts
43 // a task to join (close) the thread handle later instead of waiting for 43 // a task to join (close) the thread handle later instead of waiting for
44 // the thread. If loop_for_join is NULL, then the function waits 44 // the thread. If loop_for_join is NULL, then the function waits
45 // synchronously for the thread to terminate. 45 // synchronously for the thread to terminate.
46 // Must be called.
o1ka 2016/05/10 13:04:53 .. before destruction? (It just sounds more comple
Henrik Grunell 2016/05/11 13:11:16 Done.
46 void Stop(base::MessageLoop* loop_for_join); 47 void Stop(base::MessageLoop* loop_for_join);
47 48
49 // Releases the thread from waiting and starts running it with the given
50 // |callback| and |socket|.
51 void Resume(AudioDeviceThread::Callback* callback,
52 base::SyncSocket::Handle socket);
53
54 // Pauses the thread, it will wait in ThreadMain(). Shuts down the
55 // socket. Resume() can then be called to restart it.
56 void Pause();
57
48 private: 58 private:
59 enum State { kStatePaused, kStatePlaying, kStateStopped };
60
49 friend class base::RefCountedThreadSafe<AudioDeviceThread::Thread>; 61 friend class base::RefCountedThreadSafe<AudioDeviceThread::Thread>;
62
50 ~Thread() override; 63 ~Thread() override;
51 64
52 // Overrides from PlatformThread::Delegate. 65 // Overrides from PlatformThread::Delegate.
53 void ThreadMain() override; 66 void ThreadMain() override;
54 67
55 // Runs the loop that reads from the socket. 68 // Runs the loop that reads from the socket, called in ThreadMain().
56 void Run(); 69 void Run();
57 70
58 private: 71 // Ensures that Start(), Resume() and Pause() are called on the same thread.
59 base::PlatformThreadHandle thread_; 72 // Stop() can be called any thread.
o1ka 2016/05/10 13:04:53 nit: on/from any thread
Henrik Grunell 2016/05/11 13:11:16 Done.
60 AudioDeviceThread::Callback* callback_; 73 base::ThreadChecker thread_checker_;
61 base::CancelableSyncSocket socket_; 74
62 base::Lock callback_lock_;
63 const char* thread_name_; 75 const char* thread_name_;
64 const bool synchronized_buffers_; 76 const bool synchronized_buffers_;
65 77
78 base::Lock state_lock_; // Protects everything below.
79 base::ConditionVariable state_condition_;
80 State state_;
81 AudioDeviceThread::Callback* callback_;
82
83 base::PlatformThreadHandle thread_;
84
85 // Reset in ThreadMain(). Shutdown on client thread.
86 std::unique_ptr<base::CancelableSyncSocket> socket_;
87
88 // Set on client thead.
89 base::SyncSocket::Handle new_socket_handle_;
90
66 DISALLOW_COPY_AND_ASSIGN(Thread); 91 DISALLOW_COPY_AND_ASSIGN(Thread);
67 }; 92 };
68 93
69 // AudioDeviceThread implementation 94 AudioDeviceThread::AudioDeviceThread() {}
o1ka 2016/05/10 13:04:53 Put the comment back?
Henrik Grunell 2016/05/11 13:11:16 Done. (Although I don't think it or the one for Au
70 95
71 AudioDeviceThread::AudioDeviceThread() { 96 AudioDeviceThread::~AudioDeviceThread() {
97 DCHECK(!thread_.get());
72 } 98 }
73 99
74 AudioDeviceThread::~AudioDeviceThread() { DCHECK(!thread_.get()); } 100 void AudioDeviceThread::Start(const char* thread_name,
75
76 void AudioDeviceThread::Start(AudioDeviceThread::Callback* callback,
77 base::SyncSocket::Handle socket,
78 const char* thread_name,
79 bool synchronized_buffers) { 101 bool synchronized_buffers) {
80 base::AutoLock auto_lock(thread_lock_); 102 base::AutoLock auto_lock(thread_lock_);
81 CHECK(!thread_.get()); 103 CHECK(!thread_.get());
82 thread_ = new AudioDeviceThread::Thread( 104 thread_ = new AudioDeviceThread::Thread(thread_name, synchronized_buffers);
83 callback, socket, thread_name, synchronized_buffers);
84 thread_->Start(); 105 thread_->Start();
85 } 106 }
86 107
87 void AudioDeviceThread::Stop(base::MessageLoop* loop_for_join) { 108 void AudioDeviceThread::Stop(base::MessageLoop* loop_for_join) {
88 base::AutoLock auto_lock(thread_lock_); 109 base::AutoLock auto_lock(thread_lock_);
89 if (thread_.get()) { 110 if (thread_.get()) {
90 thread_->Stop(loop_for_join); 111 thread_->Stop(loop_for_join);
91 thread_ = NULL; 112 thread_ = nullptr;
92 } 113 }
93 } 114 }
94 115
116 void AudioDeviceThread::Resume(AudioDeviceThread::Callback* callback,
117 base::SyncSocket::Handle socket) {
118 base::AutoLock auto_lock(thread_lock_);
119 if (thread_.get())
120 thread_->Resume(callback, socket);
121 }
122
123 void AudioDeviceThread::Pause() {
124 base::AutoLock auto_lock(thread_lock_);
125 if (thread_.get())
126 thread_->Pause();
127 }
128
95 bool AudioDeviceThread::IsStopped() { 129 bool AudioDeviceThread::IsStopped() {
96 base::AutoLock auto_lock(thread_lock_); 130 base::AutoLock auto_lock(thread_lock_);
97 return !thread_.get(); 131 return !thread_.get();
98 } 132 }
99 133
100 // AudioDeviceThread::Thread implementation 134 // AudioDeviceThread::Thread implementation
101 AudioDeviceThread::Thread::Thread(AudioDeviceThread::Callback* callback, 135 AudioDeviceThread::Thread::Thread(const char* thread_name,
102 base::SyncSocket::Handle socket,
103 const char* thread_name,
104 bool synchronized_buffers) 136 bool synchronized_buffers)
105 : thread_(), 137 : thread_name_(thread_name),
106 callback_(callback), 138 synchronized_buffers_(synchronized_buffers),
107 socket_(socket), 139 state_condition_(&state_lock_),
108 thread_name_(thread_name), 140 state_(kStatePaused),
109 synchronized_buffers_(synchronized_buffers) { 141 callback_(nullptr),
142 new_socket_handle_(base::CancelableSyncSocket::kInvalidHandle) {
143 thread_checker_.DetachFromThread();
110 } 144 }
111 145
112 AudioDeviceThread::Thread::~Thread() { 146 AudioDeviceThread::Thread::~Thread() {
113 DCHECK(thread_.is_null()); 147 DCHECK(thread_.is_null());
148 DCHECK_EQ(state_, kStateStopped);
o1ka 2016/05/10 13:04:53 nit: DCHECK_EQ(state_, kStateStopped) << "Thread m
Henrik Grunell 2016/05/11 13:11:16 Done.
114 } 149 }
115 150
116 void AudioDeviceThread::Thread::Start() { 151 void AudioDeviceThread::Thread::Start() {
117 base::AutoLock auto_lock(callback_lock_); 152 DCHECK(thread_checker_.CalledOnValidThread());
118 DCHECK(thread_.is_null()); 153
119 // This reference will be released when the thread exists. 154 base::AutoLock auto_lock(state_lock_);
155 DCHECK(thread_.is_null()) << "Calling Start() on a started thread?";
156 if (state_ == kStateStopped)
157 return; // Stop has already been executed on another thread.
158
159 // This reference will be released when the thread exits.
120 AddRef(); 160 AddRef();
121 161
122 PlatformThread::CreateWithPriority(0, this, &thread_, 162 PlatformThread::CreateWithPriority(0, this, &thread_,
123 base::ThreadPriority::REALTIME_AUDIO); 163 base::ThreadPriority::REALTIME_AUDIO);
124 CHECK(!thread_.is_null()); 164 CHECK(!thread_.is_null());
125 } 165 }
126 166
127 void AudioDeviceThread::Thread::Stop(base::MessageLoop* loop_for_join) { 167 void AudioDeviceThread::Thread::Stop(base::MessageLoop* loop_for_join) {
128 socket_.Shutdown(); 168 // Note: Stop() can be called any time, even before Start(), because it's
169 // allowed to be executed on a different thread.
129 170
130 base::PlatformThreadHandle thread = base::PlatformThreadHandle(); 171 base::PlatformThreadHandle thread = base::PlatformThreadHandle();
172 {
173 base::AutoLock auto_lock(state_lock_);
174 DCHECK(state_ != kStateStopped) << "Calling Stop() on a stopped thread?";
o1ka 2016/05/10 13:04:53 Why DCHECK? Can it be a problem? I think we allow
Henrik Grunell 2016/05/11 13:11:16 Multiple calls to AudioDeviceThread::Stop() is all
175 callback_ = nullptr;
131 176
132 { // NOLINT 177 // |socket_| is only set/reset under the |state_lock_|, so it's safe to
133 base::AutoLock auto_lock(callback_lock_); 178 // access under that lock here.
134 callback_ = NULL; 179 if (socket_)
180 socket_->Shutdown();
181
182 // Must be done under lock to avoid race wuth Start().
o1ka 2016/05/10 13:04:53 nit: wuth -> with
Henrik Grunell 2016/05/11 13:11:16 Done.
135 std::swap(thread, thread_); 183 std::swap(thread, thread_);
136 } 184
185 state_ = kStateStopped;
186 state_condition_.Signal();
187 } // auto_lock(state_lock_)
137 188
138 if (!thread.is_null()) { 189 if (!thread.is_null()) {
139 if (loop_for_join) { 190 if (loop_for_join) {
140 loop_for_join->PostTask(FROM_HERE, 191 loop_for_join->PostTask(FROM_HERE,
141 base::Bind(&base::PlatformThread::Join, thread)); 192 base::Bind(&base::PlatformThread::Join, thread));
142 } else { 193 } else {
143 base::PlatformThread::Join(thread); 194 base::PlatformThread::Join(thread);
144 } 195 }
145 } 196 }
146 } 197 }
147 198
199 void AudioDeviceThread::Thread::Resume(AudioDeviceThread::Callback* callback,
200 base::SyncSocket::Handle socket_handle) {
201 DCHECK(thread_checker_.CalledOnValidThread());
202
203 base::AutoLock auto_lock(state_lock_);
204 if (state_ == kStateStopped)
205 return; // Stop is the last operation to be executed.
206
207 DCHECK(state_ == kStatePaused) << "Resume a non-paused thread?";
208
209 DCHECK_EQ(new_socket_handle_, base::CancelableSyncSocket::kInvalidHandle);
210
211 callback_ = callback;
212 new_socket_handle_ = socket_handle;
213
214 state_ = kStatePlaying;
215 state_condition_.Signal();
216 }
217
218 void AudioDeviceThread::Thread::Pause() {
219 DCHECK(thread_checker_.CalledOnValidThread());
220
221 base::AutoLock auto_lock(state_lock_);
222 if (state_ == kStateStopped)
223 return; // Stop is the last operation to be executed.
224
225 DCHECK(state_ == kStatePlaying) << "Pause a paused thread?";
226 callback_ = nullptr;
227
228 // |socket_| is only set/reset under the |state_lock_|, so it's safe to
229 // access under that lock here.
230 if (socket_)
231 socket_->Shutdown();
232 state_ = kStatePaused;
233 }
234
148 void AudioDeviceThread::Thread::ThreadMain() { 235 void AudioDeviceThread::Thread::ThreadMain() {
149 PlatformThread::SetName(thread_name_); 236 PlatformThread::SetName(thread_name_);
150 237
151 // Singleton access is safe from this thread as long as callback is non-NULL. 238 // Singleton access is safe from this thread as long as callback is non-NULL.
152 // The callback is the only point where the thread calls out to 'unknown' code 239 // The callback is the only point where the thread calls out to 'unknown' code
153 // that might touch singletons and the lifetime of the callback is controlled 240 // that might touch singletons and the lifetime of the callback is controlled
154 // by another thread on which singleton access is OK as well. 241 // by another thread on which singleton access is OK as well.
155 base::ThreadRestrictions::SetSingletonAllowed(true); 242 base::ThreadRestrictions::SetSingletonAllowed(true);
156 243
157 { // NOLINT 244 while (true) {
158 base::AutoLock auto_lock(callback_lock_); 245 {
159 if (callback_) 246 base::AutoLock auto_lock(state_lock_);
160 callback_->InitializeOnAudioThread(); 247 while (state_ == kStatePaused)
161 } 248 state_condition_.Wait();
162 249
163 Run(); 250 if (state_ == kStateStopped)
251 break;
252 // Else reinitialize and resume.
253
254 socket_.reset(new base::CancelableSyncSocket(new_socket_handle_));
255
256 if (callback_)
257 callback_->InitializeOnAudioThread();
258
259 new_socket_handle_ = base::CancelableSyncSocket::kInvalidHandle;
260 } // auto_lock(state_lock_)
261
262 Run();
263
264 // We are here if and only if socket operation failed. The possible reasons
265 // are:
266 // 1. Shutdown() has been called on the socket, i.e. Stop() or Pause() has
267 // been called, or
268 // 2. Socket failed.
269 // In both cases go back and wait for stop or resume.
270 } // while
164 271
165 // Release the reference for the thread. Note that after this, the Thread 272 // Release the reference for the thread. Note that after this, the Thread
166 // instance will most likely be deleted. 273 // instance will most likely be deleted.
167 Release(); 274 Release();
168 } 275 }
169 276
170 void AudioDeviceThread::Thread::Run() { 277 void AudioDeviceThread::Thread::Run() {
171 uint32_t buffer_index = 0; 278 uint32_t buffer_index = 0;
279
172 while (true) { 280 while (true) {
173 uint32_t pending_data = 0; 281 uint32_t pending_data = 0;
174 size_t bytes_read = socket_.Receive(&pending_data, sizeof(pending_data)); 282 // |socket_| is only modified in ThreadMain, so it is safe to access here.
283 size_t bytes_read = socket_->Receive(&pending_data, sizeof(pending_data));
284
175 if (bytes_read != sizeof(pending_data)) 285 if (bytes_read != sizeof(pending_data))
176 break; 286 break;
177 287
178 // std::numeric_limits<uint32_t>::max() is a special signal which is 288 // std::numeric_limits<uint32_t>::max() is a special signal which is
179 // returned after the browser stops the output device in response to a 289 // returned after the browser stops the output device in response to a
180 // renderer side request. 290 // renderer side request.
181 // 291 //
182 // Avoid running Process() for the paused signal, we still need to update 292 // Avoid running Process() for the paused signal, we still need to update
183 // the buffer index if |synchronized_buffers_| is true though. 293 // the buffer index if |synchronized_buffers_| is true though.
184 // 294 //
185 // See comments in AudioOutputController::DoPause() for details on why. 295 // See comments in AudioOutputController::DoPause() for details on why.
186 if (pending_data != std::numeric_limits<uint32_t>::max()) { 296 if (pending_data != std::numeric_limits<uint32_t>::max()) {
187 base::AutoLock auto_lock(callback_lock_); 297 base::AutoLock auto_lock(state_lock_);
o1ka 2016/05/10 13:04:53 Could you add a comment why we should hold a lock
Henrik Grunell 2016/05/11 13:11:16 Done.
188 if (callback_) 298 if (callback_)
189 callback_->Process(pending_data); 299 callback_->Process(pending_data);
190 } 300 }
191 301
192 // The usage of |synchronized_buffers_| differs between input and output 302 // The usage of |synchronized_buffers_| differs between input and output
193 // cases. 303 // cases.
194 // Input: 304 // Input:
195 // Let the other end know that we have read data, so that it can verify 305 // Let the other end know that we have read data, so that it can verify
196 // it doesn't overwrite any data before read. The |buffer_index| value is 306 // it doesn't overwrite any data before read. The |buffer_index| value is
197 // not used. For more details, see AudioInputSyncWriter::Write(). 307 // not used. For more details, see AudioInputSyncWriter::Write().
198 // Output: 308 // Output:
199 // Let the other end know which buffer we just filled. The |buffer_index| is 309 // Let the other end know which buffer we just filled. The |buffer_index| is
200 // used to ensure the other end is getting the buffer it expects. For more 310 // used to ensure the other end is getting the buffer it expects. For more
201 // details on how this works see AudioSyncReader::WaitUntilDataIsReady(). 311 // details on how this works see AudioSyncReader::WaitUntilDataIsReady().
202 if (synchronized_buffers_) { 312 if (synchronized_buffers_) {
203 ++buffer_index; 313 ++buffer_index;
204 size_t bytes_sent = socket_.Send(&buffer_index, sizeof(buffer_index)); 314 size_t bytes_sent = socket_->Send(&buffer_index, sizeof(buffer_index));
315
205 if (bytes_sent != sizeof(buffer_index)) 316 if (bytes_sent != sizeof(buffer_index))
206 break; 317 break;
207 } 318 }
208 } 319 } // while
209 } 320 }
210 321
211 // AudioDeviceThread::Callback implementation 322 // AudioDeviceThread::Callback implementation
212 323
213 AudioDeviceThread::Callback::Callback(const AudioParameters& audio_parameters, 324 AudioDeviceThread::Callback::Callback(const AudioParameters& audio_parameters,
214 base::SharedMemoryHandle memory, 325 base::SharedMemoryHandle memory,
215 int memory_length, 326 int memory_length,
216 int total_segments) 327 int total_segments)
217 : audio_parameters_(audio_parameters), 328 : audio_parameters_(audio_parameters),
218 samples_per_ms_(static_cast<double>(audio_parameters.sample_rate()) / 329 samples_per_ms_(static_cast<double>(audio_parameters.sample_rate()) /
(...skipping 14 matching lines...) Expand all
233 } 344 }
234 345
235 AudioDeviceThread::Callback::~Callback() {} 346 AudioDeviceThread::Callback::~Callback() {}
236 347
237 void AudioDeviceThread::Callback::InitializeOnAudioThread() { 348 void AudioDeviceThread::Callback::InitializeOnAudioThread() {
238 MapSharedMemory(); 349 MapSharedMemory();
239 CHECK(shared_memory_.memory()); 350 CHECK(shared_memory_.memory());
240 } 351 }
241 352
242 } // namespace media. 353 } // namespace media.
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698