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

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

Issue 2076793002: Cleanup AudioDeviceThread to reduce locking and unused features. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 6 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>
8 #include <stdint.h>
9
10 #include <algorithm>
11 #include <limits> 7 #include <limits>
12 8
13 #include "base/bind.h"
14 #include "base/logging.h" 9 #include "base/logging.h"
15 #include "base/macros.h"
16 #include "base/memory/aligned_memory.h"
17 #include "base/message_loop/message_loop.h"
18 #include "base/numerics/safe_conversions.h"
19 #include "base/threading/platform_thread.h"
20 #include "base/threading/thread_restrictions.h" 10 #include "base/threading/thread_restrictions.h"
21 #include "media/base/audio_bus.h"
22
23 using base::PlatformThread;
24 11
25 namespace media { 12 namespace media {
26 13
27 // The actual worker thread implementation. It's very bare bones and much 14 // AudioDeviceThread::Callback implementation
28 // simpler than SimpleThread (no synchronization in Start, etc) and supports
29 // joining the thread handle asynchronously via a provided message loop even
30 // after the Thread object itself has been deleted.
31 class AudioDeviceThread::Thread
32 : public PlatformThread::Delegate,
33 public base::RefCountedThreadSafe<AudioDeviceThread::Thread> {
34 public:
35 Thread(AudioDeviceThread::Callback* callback,
36 base::SyncSocket::Handle socket,
37 const char* thread_name,
38 bool synchronized_buffers);
39 15
40 void Start(); 16 AudioDeviceThread::Callback::Callback(const AudioParameters& audio_parameters,
17 base::SharedMemoryHandle memory,
18 int memory_length,
19 int total_segments)
20 : audio_parameters_(audio_parameters),
21 samples_per_ms_(static_cast<double>(audio_parameters.sample_rate()) /
22 base::Time::kMillisecondsPerSecond),
23 bytes_per_ms_(audio_parameters.channels() *
24 (audio_parameters_.bits_per_sample() / 8) *
25 samples_per_ms_),
26 bytes_per_frame_(audio_parameters.GetBytesPerFrame()),
27 shared_memory_(memory, false),
28 memory_length_(memory_length),
29 total_segments_(total_segments) {
30 CHECK_NE(bytes_per_ms_, 0.0); // Catch division by zero early.
31 CHECK_NE(samples_per_ms_, 0.0);
32 CHECK_NE(bytes_per_frame_, 0u);
33 CHECK_GT(total_segments_, 0);
34 CHECK_EQ(memory_length_ % total_segments_, 0);
35 segment_length_ = memory_length_ / total_segments_;
36 }
41 37
42 // Stops the thread. If |loop_for_join| is non-NULL, the function posts 38 AudioDeviceThread::Callback::~Callback() {}
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
45 // synchronously for the thread to terminate.
46 void Stop(base::MessageLoop* loop_for_join);
47 39
48 private: 40 void AudioDeviceThread::Callback::InitializeOnAudioThread() {
49 friend class base::RefCountedThreadSafe<AudioDeviceThread::Thread>; 41 MapSharedMemory();
50 ~Thread() override; 42 CHECK(shared_memory_.memory());
tommi (sloooow) - chröme 2016/06/16 22:19:22 should there be a [D]CHECK for memory() being null
DaleCurtis 2016/06/16 22:24:59 It's called in the ThreadMain() below so it must b
51 43 }
52 // Overrides from PlatformThread::Delegate.
53 void ThreadMain() override;
54
55 // Runs the loop that reads from the socket.
56 void Run();
57
58 private:
59 base::PlatformThreadHandle thread_;
60 AudioDeviceThread::Callback* callback_;
61 base::CancelableSyncSocket socket_;
62 base::Lock callback_lock_;
63 const char* thread_name_;
64 const bool synchronized_buffers_;
65
66 DISALLOW_COPY_AND_ASSIGN(Thread);
67 };
68 44
69 // AudioDeviceThread implementation 45 // AudioDeviceThread implementation
70 46
71 AudioDeviceThread::AudioDeviceThread() { 47 AudioDeviceThread::AudioDeviceThread(Callback* callback,
48 base::SyncSocket::Handle socket,
49 const char* thread_name)
50 : callback_(callback), thread_name_(thread_name), socket_(socket) {
51 CHECK(base::PlatformThread::CreateWithPriority(
52 0, this, &thread_handle_, base::ThreadPriority::REALTIME_AUDIO));
53 DCHECK(!thread_handle_.is_null());
72 } 54 }
73 55
74 AudioDeviceThread::~AudioDeviceThread() { DCHECK(!thread_.get()); } 56 AudioDeviceThread::~AudioDeviceThread() {
75 57 socket_.Shutdown();
76 void AudioDeviceThread::Start(AudioDeviceThread::Callback* callback, 58 if (thread_handle_.is_null())
77 base::SyncSocket::Handle socket, 59 return;
78 const char* thread_name, 60 base::PlatformThread::Join(thread_handle_);
79 bool synchronized_buffers) { 61 DCHECK(thread_handle_.is_null());
80 base::AutoLock auto_lock(thread_lock_);
81 CHECK(!thread_.get());
82 thread_ = new AudioDeviceThread::Thread(
83 callback, socket, thread_name, synchronized_buffers);
84 thread_->Start();
85 } 62 }
86 63
87 void AudioDeviceThread::Stop(base::MessageLoop* loop_for_join) { 64 void AudioDeviceThread::ThreadMain() {
88 base::AutoLock auto_lock(thread_lock_); 65 base::PlatformThread::SetName(thread_name_);
89 if (thread_.get()) { 66 base::ThreadRestrictions::SetSingletonAllowed(true);
90 thread_->Stop(loop_for_join); 67 callback_->InitializeOnAudioThread();
91 thread_ = NULL;
92 }
93 }
94 68
95 bool AudioDeviceThread::IsStopped() {
96 base::AutoLock auto_lock(thread_lock_);
97 return !thread_.get();
98 }
99
100 // AudioDeviceThread::Thread implementation
101 AudioDeviceThread::Thread::Thread(AudioDeviceThread::Callback* callback,
102 base::SyncSocket::Handle socket,
103 const char* thread_name,
104 bool synchronized_buffers)
105 : thread_(),
106 callback_(callback),
107 socket_(socket),
108 thread_name_(thread_name),
109 synchronized_buffers_(synchronized_buffers) {
110 }
111
112 AudioDeviceThread::Thread::~Thread() {
113 DCHECK(thread_.is_null());
114 }
115
116 void AudioDeviceThread::Thread::Start() {
117 base::AutoLock auto_lock(callback_lock_);
118 DCHECK(thread_.is_null());
119 // This reference will be released when the thread exists.
120 AddRef();
121
122 PlatformThread::CreateWithPriority(0, this, &thread_,
123 base::ThreadPriority::REALTIME_AUDIO);
124 CHECK(!thread_.is_null());
125 }
126
127 void AudioDeviceThread::Thread::Stop(base::MessageLoop* loop_for_join) {
128 socket_.Shutdown();
129
130 base::PlatformThreadHandle thread = base::PlatformThreadHandle();
131
132 { // NOLINT
133 base::AutoLock auto_lock(callback_lock_);
134 callback_ = NULL;
135 std::swap(thread, thread_);
136 }
137
138 if (!thread.is_null()) {
139 if (loop_for_join) {
140 loop_for_join->PostTask(FROM_HERE,
141 base::Bind(&base::PlatformThread::Join, thread));
142 } else {
143 base::PlatformThread::Join(thread);
144 }
145 }
146 }
147
148 void AudioDeviceThread::Thread::ThreadMain() {
149 PlatformThread::SetName(thread_name_);
150
151 // 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
153 // that might touch singletons and the lifetime of the callback is controlled
154 // by another thread on which singleton access is OK as well.
155 base::ThreadRestrictions::SetSingletonAllowed(true);
156
157 { // NOLINT
158 base::AutoLock auto_lock(callback_lock_);
159 if (callback_)
160 callback_->InitializeOnAudioThread();
161 }
162
163 Run();
164
165 // Release the reference for the thread. Note that after this, the Thread
166 // instance will most likely be deleted.
167 Release();
168 }
169
170 void AudioDeviceThread::Thread::Run() {
171 uint32_t buffer_index = 0; 69 uint32_t buffer_index = 0;
172 while (true) { 70 while (true) {
173 uint32_t pending_data = 0; 71 uint32_t pending_data = 0;
174 size_t bytes_read = socket_.Receive(&pending_data, sizeof(pending_data)); 72 size_t bytes_read = socket_.Receive(&pending_data, sizeof(pending_data));
175 if (bytes_read != sizeof(pending_data)) 73 if (bytes_read != sizeof(pending_data))
176 break; 74 break;
177 75
178 // std::numeric_limits<uint32_t>::max() is a special signal which is 76 // 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 77 // returned after the browser stops the output device in response to a
180 // renderer side request. 78 // renderer side request.
181 // 79 //
182 // Avoid running Process() for the paused signal, we still need to update 80 // Avoid running Process() for the paused signal, we still need to update
183 // the buffer index if |synchronized_buffers_| is true though. 81 // the buffer index for synchronized buffers though.
184 // 82 //
185 // See comments in AudioOutputController::DoPause() for details on why. 83 // See comments in AudioOutputController::DoPause() for details on why.
186 if (pending_data != std::numeric_limits<uint32_t>::max()) { 84 if (pending_data != std::numeric_limits<uint32_t>::max())
187 base::AutoLock auto_lock(callback_lock_); 85 callback_->Process(pending_data);
188 if (callback_)
189 callback_->Process(pending_data);
190 }
191 86
192 // The usage of |synchronized_buffers_| differs between input and output 87 // The usage of synchronized buffers differs between input and output cases.
193 // cases. 88 //
194 // Input: 89 // Input: Let the other end know that we have read data, so that it can
195 // Let the other end know that we have read data, so that it can verify 90 // verify it doesn't overwrite any data before read. The |buffer_index|
196 // it doesn't overwrite any data before read. The |buffer_index| value is 91 // value is not used. For more details, see AudioInputSyncWriter::Write().
197 // not used. For more details, see AudioInputSyncWriter::Write(). 92 //
198 // Output: 93 // Output: Let the other end know which buffer we just filled. The
199 // Let the other end know which buffer we just filled. The |buffer_index| is 94 // |buffer_index| is used to ensure the other end is getting the buffer it
200 // used to ensure the other end is getting the buffer it expects. For more 95 // expects. For more details on how this works see
201 // details on how this works see AudioSyncReader::WaitUntilDataIsReady(). 96 // AudioSyncReader::WaitUntilDataIsReady().
202 if (synchronized_buffers_) { 97 ++buffer_index;
203 ++buffer_index; 98 size_t bytes_sent = socket_.Send(&buffer_index, sizeof(buffer_index));
204 size_t bytes_sent = socket_.Send(&buffer_index, sizeof(buffer_index)); 99 if (bytes_sent != sizeof(buffer_index))
205 if (bytes_sent != sizeof(buffer_index)) 100 break;
206 break;
207 }
208 } 101 }
209 }
210 102
211 // AudioDeviceThread::Callback implementation 103 // This can be racy, but we can't hold a lock here and if we don't clear this
212 104 // on failure, we may join the wrong thread during a later Stop().
213 AudioDeviceThread::Callback::Callback(const AudioParameters& audio_parameters, 105 // TODO(dalecurtis): Is there a better option here?
214 base::SharedMemoryHandle memory, 106 thread_handle_ = base::PlatformThreadHandle();
tommi (sloooow) - chröme 2016/06/16 22:19:22 I think we'll need to fix this before checkin. Id
DaleCurtis 2016/06/16 22:24:59 What do you think about changing this to a shutdow
tommi (sloooow) - chröme 2016/06/16 22:36:18 Hmm... this is both the normal and abnormal exit p
DaleCurtis 2016/06/16 22:55:16 Derp, I should actually do a bit more research bef
215 int memory_length,
216 int total_segments)
217 : audio_parameters_(audio_parameters),
218 samples_per_ms_(static_cast<double>(audio_parameters.sample_rate()) /
219 base::Time::kMillisecondsPerSecond),
220 bytes_per_ms_(audio_parameters.channels() *
221 (audio_parameters_.bits_per_sample() / 8) *
222 samples_per_ms_),
223 bytes_per_frame_(audio_parameters.GetBytesPerFrame()),
224 shared_memory_(memory, false),
225 memory_length_(memory_length),
226 total_segments_(total_segments) {
227 CHECK_NE(bytes_per_ms_, 0.0); // Catch division by zero early.
228 CHECK_NE(samples_per_ms_, 0.0);
229 CHECK_NE(bytes_per_frame_, 0u);
230 CHECK_GT(total_segments_, 0);
231 CHECK_EQ(memory_length_ % total_segments_, 0);
232 segment_length_ = memory_length_ / total_segments_;
233 }
234
235 AudioDeviceThread::Callback::~Callback() {}
236
237 void AudioDeviceThread::Callback::InitializeOnAudioThread() {
238 MapSharedMemory();
239 CHECK(shared_memory_.memory());
240 } 107 }
241 108
242 } // namespace media. 109 } // namespace media.
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698