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

Side by Side Diff: content/renderer/media/audio_input_device.cc

Issue 9104043: Monitor the IO message loop in the AudioDevice classes. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix indent Created 8 years, 10 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 | Annotate | Revision Log
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 "content/renderer/media/audio_input_device.h" 5 #include "content/renderer/media/audio_input_device.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/message_loop.h" 8 #include "base/message_loop.h"
9 #include "base/threading/thread_restrictions.h" 9 #include "base/threading/thread_restrictions.h"
10 #include "base/time.h" 10 #include "base/time.h"
11 #include "content/common/child_process.h" 11 #include "content/common/child_process.h"
12 #include "content/common/media/audio_messages.h" 12 #include "content/common/media/audio_messages.h"
13 #include "content/common/view_messages.h" 13 #include "content/common/view_messages.h"
14 #include "content/renderer/render_thread_impl.h" 14 #include "content/renderer/render_thread_impl.h"
15 #include "media/audio/audio_manager_base.h" 15 #include "media/audio/audio_manager_base.h"
16 #include "media/audio/audio_util.h" 16 #include "media/audio/audio_util.h"
17 17
18 AudioInputDevice::AudioInputDevice(size_t buffer_size, 18 AudioInputDevice::AudioInputDevice(size_t buffer_size,
19 int channels, 19 int channels,
20 double sample_rate, 20 double sample_rate,
21 CaptureCallback* callback, 21 CaptureCallback* callback,
22 CaptureEventHandler* event_handler) 22 CaptureEventHandler* event_handler)
23 : callback_(callback), 23 : ScopedLoopObserver(ChildProcess::current()->io_message_loop()),
24 callback_(callback),
24 event_handler_(event_handler), 25 event_handler_(event_handler),
25 audio_delay_milliseconds_(0), 26 audio_delay_milliseconds_(0),
26 volume_(1.0), 27 volume_(1.0),
27 stream_id_(0), 28 stream_id_(0),
28 session_id_(0), 29 session_id_(0),
29 pending_device_ready_(false), 30 pending_device_ready_(false),
30 shared_memory_handle_(base::SharedMemory::NULLHandle()), 31 shared_memory_handle_(base::SharedMemory::NULLHandle()),
31 memory_length_(0) { 32 memory_length_(0) {
32 filter_ = RenderThreadImpl::current()->audio_input_message_filter(); 33 filter_ = RenderThreadImpl::current()->audio_input_message_filter();
33 audio_data_.reserve(channels); 34 audio_data_.reserve(channels);
34 #if defined(OS_MACOSX) 35 #if defined(OS_MACOSX)
35 VLOG(1) << "Using AUDIO_PCM_LOW_LATENCY as input mode on Mac OS X."; 36 DVLOG(1) << "Using AUDIO_PCM_LOW_LATENCY as input mode on Mac OS X.";
36 audio_parameters_.format = AudioParameters::AUDIO_PCM_LOW_LATENCY; 37 audio_parameters_.format = AudioParameters::AUDIO_PCM_LOW_LATENCY;
37 #elif defined(OS_WIN) 38 #elif defined(OS_WIN)
38 VLOG(1) << "Using AUDIO_PCM_LOW_LATENCY as input mode on Windows."; 39 DVLOG(1) << "Using AUDIO_PCM_LOW_LATENCY as input mode on Windows.";
39 audio_parameters_.format = AudioParameters::AUDIO_PCM_LOW_LATENCY; 40 audio_parameters_.format = AudioParameters::AUDIO_PCM_LOW_LATENCY;
40 #else 41 #else
41 // TODO(henrika): add support for AUDIO_PCM_LOW_LATENCY on Linux as well. 42 // TODO(henrika): add support for AUDIO_PCM_LOW_LATENCY on Linux as well.
42 audio_parameters_.format = AudioParameters::AUDIO_PCM_LINEAR; 43 audio_parameters_.format = AudioParameters::AUDIO_PCM_LINEAR;
43 #endif 44 #endif
44 audio_parameters_.channels = channels; 45 audio_parameters_.channels = channels;
45 audio_parameters_.sample_rate = static_cast<int>(sample_rate); 46 audio_parameters_.sample_rate = static_cast<int>(sample_rate);
46 audio_parameters_.bits_per_sample = 16; 47 audio_parameters_.bits_per_sample = 16;
47 audio_parameters_.samples_per_packet = buffer_size; 48 audio_parameters_.samples_per_packet = buffer_size;
48 for (int i = 0; i < channels; ++i) { 49 for (int i = 0; i < channels; ++i) {
49 float* channel_data = new float[buffer_size]; 50 float* channel_data = new float[buffer_size];
50 audio_data_.push_back(channel_data); 51 audio_data_.push_back(channel_data);
51 } 52 }
52 } 53 }
53 54
54 AudioInputDevice::~AudioInputDevice() { 55 AudioInputDevice::~AudioInputDevice() {
55 // TODO(henrika): The current design requires that the user calls 56 // TODO(henrika): The current design requires that the user calls
56 // Stop before deleting this class. 57 // Stop before deleting this class.
57 CHECK_EQ(0, stream_id_); 58 CHECK_EQ(0, stream_id_);
58 for (int i = 0; i < audio_parameters_.channels; ++i) 59 for (int i = 0; i < audio_parameters_.channels; ++i)
59 delete [] audio_data_[i]; 60 delete [] audio_data_[i];
60 } 61 }
61 62
62 void AudioInputDevice::Start() { 63 void AudioInputDevice::Start() {
63 VLOG(1) << "Start()"; 64 DVLOG(1) << "Start()";
64 ChildProcess::current()->io_message_loop()->PostTask( 65 message_loop()->PostTask(FROM_HERE,
65 FROM_HERE,
66 base::Bind(&AudioInputDevice::InitializeOnIOThread, this)); 66 base::Bind(&AudioInputDevice::InitializeOnIOThread, this));
67 } 67 }
68 68
69 void AudioInputDevice::SetDevice(int session_id) { 69 void AudioInputDevice::SetDevice(int session_id) {
70 VLOG(1) << "SetDevice (session_id=" << session_id << ")"; 70 DVLOG(1) << "SetDevice (session_id=" << session_id << ")";
71 ChildProcess::current()->io_message_loop()->PostTask( 71 message_loop()->PostTask(FROM_HERE,
72 FROM_HERE, 72 base::Bind(&AudioInputDevice::SetSessionIdOnIOThread, this, session_id));
73 base::Bind(&AudioInputDevice::SetSessionIdOnIOThread, this,
74 session_id));
75 } 73 }
76 74
77 void AudioInputDevice::Stop() { 75 void AudioInputDevice::Stop() {
78 DCHECK(MessageLoop::current() != ChildProcess::current()->io_message_loop()); 76 DCHECK(!message_loop()->BelongsToCurrentThread());
79 VLOG(1) << "Stop()"; 77 DVLOG(1) << "Stop()";
80 78
81 base::WaitableEvent completion(false, false); 79 base::WaitableEvent completion(false, false);
82 ChildProcess::current()->io_message_loop()->PostTask( 80 if (message_loop()->PostTask(FROM_HERE,
83 FROM_HERE, 81 base::Bind(&AudioInputDevice::ShutDownOnIOThread, this,
84 base::Bind(&AudioInputDevice::ShutDownOnIOThread, this, 82 &completion))) {
85 &completion)); 83 // We wait here for the IO task to be completed to remove race conflicts
86 84 // with OnLowLatencyCreated() and to ensure that Stop() acts as a
87 // We wait here for the IO task to be completed to remove race conflicts 85 // synchronous function call.
88 // with OnLowLatencyCreated() and to ensure that Stop() acts as a synchronous 86 completion.Wait();
89 // function call. 87 }
90 completion.Wait();
91 } 88 }
92 89
93 bool AudioInputDevice::SetVolume(double volume) { 90 bool AudioInputDevice::SetVolume(double volume) {
94 NOTIMPLEMENTED(); 91 NOTIMPLEMENTED();
95 return false; 92 return false;
96 } 93 }
97 94
98 bool AudioInputDevice::GetVolume(double* volume) { 95 bool AudioInputDevice::GetVolume(double* volume) {
99 NOTIMPLEMENTED(); 96 NOTIMPLEMENTED();
100 return false; 97 return false;
101 } 98 }
102 99
103 void AudioInputDevice::InitializeOnIOThread() { 100 void AudioInputDevice::InitializeOnIOThread() {
104 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); 101 DCHECK(message_loop()->BelongsToCurrentThread());
105 // Make sure we don't call Start() more than once. 102 // Make sure we don't call Start() more than once.
106 DCHECK_EQ(0, stream_id_); 103 DCHECK_EQ(0, stream_id_);
107 if (stream_id_) 104 if (stream_id_)
108 return; 105 return;
109 106
110 stream_id_ = filter_->AddDelegate(this); 107 stream_id_ = filter_->AddDelegate(this);
111 // If |session_id_| is not specified, it will directly create the stream; 108 // If |session_id_| is not specified, it will directly create the stream;
112 // otherwise it will send a AudioInputHostMsg_StartDevice msg to the browser 109 // otherwise it will send a AudioInputHostMsg_StartDevice msg to the browser
113 // and create the stream when getting a OnDeviceReady() callback. 110 // and create the stream when getting a OnDeviceReady() callback.
114 if (!session_id_) { 111 if (!session_id_) {
115 Send(new AudioInputHostMsg_CreateStream( 112 Send(new AudioInputHostMsg_CreateStream(
116 stream_id_, audio_parameters_, true, 113 stream_id_, audio_parameters_, true,
117 AudioManagerBase::kDefaultDeviceId)); 114 AudioManagerBase::kDefaultDeviceId));
118 } else { 115 } else {
119 Send(new AudioInputHostMsg_StartDevice(stream_id_, session_id_)); 116 Send(new AudioInputHostMsg_StartDevice(stream_id_, session_id_));
120 pending_device_ready_ = true; 117 pending_device_ready_ = true;
121 } 118 }
122 } 119 }
123 120
124 void AudioInputDevice::SetSessionIdOnIOThread(int session_id) { 121 void AudioInputDevice::SetSessionIdOnIOThread(int session_id) {
125 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); 122 DCHECK(message_loop()->BelongsToCurrentThread());
126 session_id_ = session_id; 123 session_id_ = session_id;
127 } 124 }
128 125
129 void AudioInputDevice::StartOnIOThread() { 126 void AudioInputDevice::StartOnIOThread() {
130 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); 127 DCHECK(message_loop()->BelongsToCurrentThread());
131 if (stream_id_) 128 if (stream_id_)
132 Send(new AudioInputHostMsg_RecordStream(stream_id_)); 129 Send(new AudioInputHostMsg_RecordStream(stream_id_));
133 } 130 }
134 131
135 void AudioInputDevice::ShutDownOnIOThread(base::WaitableEvent* completion) { 132 void AudioInputDevice::ShutDownOnIOThread(base::WaitableEvent* completion) {
136 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); 133 DCHECK(message_loop()->BelongsToCurrentThread());
134 // NOTE: |completion| may be NULL.
137 // Make sure we don't call shutdown more than once. 135 // Make sure we don't call shutdown more than once.
138 if (!stream_id_) { 136 if (stream_id_) {
139 completion->Signal(); 137 filter_->RemoveDelegate(stream_id_);
140 return; 138 Send(new AudioInputHostMsg_CloseStream(stream_id_));
139
140 ShutDownAudioThread();
141
142 stream_id_ = 0;
143 session_id_ = 0;
144 pending_device_ready_ = false;
141 } 145 }
142 146
143 filter_->RemoveDelegate(stream_id_); 147 if (completion)
144 Send(new AudioInputHostMsg_CloseStream(stream_id_)); 148 completion->Signal();
145
146 ShutDownAudioThread();
147
148 stream_id_ = 0;
149 session_id_ = 0;
150 pending_device_ready_ = false;
151
152 completion->Signal();
153 } 149 }
154 150
155 void AudioInputDevice::SetVolumeOnIOThread(double volume) { 151 void AudioInputDevice::SetVolumeOnIOThread(double volume) {
156 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); 152 DCHECK(message_loop()->BelongsToCurrentThread());
157 if (stream_id_) 153 if (stream_id_)
158 Send(new AudioInputHostMsg_SetVolume(stream_id_, volume)); 154 Send(new AudioInputHostMsg_SetVolume(stream_id_, volume));
159 } 155 }
160 156
161 void AudioInputDevice::OnLowLatencyCreated( 157 void AudioInputDevice::OnLowLatencyCreated(
162 base::SharedMemoryHandle handle, 158 base::SharedMemoryHandle handle,
163 base::SyncSocket::Handle socket_handle, 159 base::SyncSocket::Handle socket_handle,
164 uint32 length) { 160 uint32 length) {
165 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); 161 DCHECK(message_loop()->BelongsToCurrentThread());
166 #if defined(OS_WIN) 162 #if defined(OS_WIN)
167 DCHECK(handle); 163 DCHECK(handle);
168 DCHECK(socket_handle); 164 DCHECK(socket_handle);
169 #else 165 #else
170 DCHECK_GE(handle.fd, 0); 166 DCHECK_GE(handle.fd, 0);
171 DCHECK_GE(socket_handle, 0); 167 DCHECK_GE(socket_handle, 0);
172 #endif 168 #endif
173 DCHECK(length); 169 DCHECK(length);
174 DCHECK(!audio_thread_.get()); 170 DCHECK(!audio_thread_.get());
175 171
176 VLOG(1) << "OnLowLatencyCreated (stream_id=" << stream_id_ << ")"; 172 DVLOG(1) << "OnLowLatencyCreated (stream_id=" << stream_id_ << ")";
177 // Takes care of the case when Stop() is called before OnLowLatencyCreated(). 173 // Takes care of the case when Stop() is called before OnLowLatencyCreated().
178 if (!stream_id_) { 174 if (!stream_id_) {
179 base::SharedMemory::CloseHandle(handle); 175 base::SharedMemory::CloseHandle(handle);
180 // Close the socket handler. 176 // Close the socket handler.
181 base::SyncSocket socket(socket_handle); 177 base::SyncSocket socket(socket_handle);
182 return; 178 return;
183 } 179 }
184 180
185 shared_memory_handle_ = handle; 181 shared_memory_handle_ = handle;
186 memory_length_ = length; 182 memory_length_ = length;
187 audio_socket_.reset(new base::CancelableSyncSocket(socket_handle)); 183 audio_socket_.reset(new base::CancelableSyncSocket(socket_handle));
188 184
189 audio_thread_.reset( 185 audio_thread_.reset(
190 new base::DelegateSimpleThread(this, "RendererAudioInputThread")); 186 new base::DelegateSimpleThread(this, "RendererAudioInputThread"));
191 audio_thread_->Start(); 187 audio_thread_->Start();
192 188
193 MessageLoop::current()->PostTask( 189 MessageLoop::current()->PostTask(
194 FROM_HERE, 190 FROM_HERE,
195 base::Bind(&AudioInputDevice::StartOnIOThread, this)); 191 base::Bind(&AudioInputDevice::StartOnIOThread, this));
196 } 192 }
197 193
198 void AudioInputDevice::OnVolume(double volume) { 194 void AudioInputDevice::OnVolume(double volume) {
199 NOTIMPLEMENTED(); 195 NOTIMPLEMENTED();
200 } 196 }
201 197
202 void AudioInputDevice::OnStateChanged(AudioStreamState state) { 198 void AudioInputDevice::OnStateChanged(AudioStreamState state) {
203 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); 199 DCHECK(message_loop()->BelongsToCurrentThread());
204 switch (state) { 200 switch (state) {
205 case kAudioStreamPaused: 201 case kAudioStreamPaused:
206 // TODO(xians): Should we just call ShutDownOnIOThread here instead? 202 // TODO(xians): Should we just call ShutDownOnIOThread here instead?
207 203
208 // Do nothing if the stream has been closed. 204 // Do nothing if the stream has been closed.
209 if (!stream_id_) 205 if (!stream_id_)
210 return; 206 return;
211 207
212 filter_->RemoveDelegate(stream_id_); 208 filter_->RemoveDelegate(stream_id_);
213 209
(...skipping 11 matching lines...) Expand all
225 case kAudioStreamError: 221 case kAudioStreamError:
226 DLOG(WARNING) << "AudioInputDevice::OnStateChanged(kError)"; 222 DLOG(WARNING) << "AudioInputDevice::OnStateChanged(kError)";
227 break; 223 break;
228 default: 224 default:
229 NOTREACHED(); 225 NOTREACHED();
230 break; 226 break;
231 } 227 }
232 } 228 }
233 229
234 void AudioInputDevice::OnDeviceReady(const std::string& device_id) { 230 void AudioInputDevice::OnDeviceReady(const std::string& device_id) {
235 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); 231 DCHECK(message_loop()->BelongsToCurrentThread());
236 VLOG(1) << "OnDeviceReady (device_id=" << device_id << ")"; 232 DVLOG(1) << "OnDeviceReady (device_id=" << device_id << ")";
237 233
238 // Takes care of the case when Stop() is called before OnDeviceReady(). 234 // Takes care of the case when Stop() is called before OnDeviceReady().
239 if (!pending_device_ready_) 235 if (!pending_device_ready_)
240 return; 236 return;
241 237
242 // If AudioInputDeviceManager returns an empty string, it means no device 238 // If AudioInputDeviceManager returns an empty string, it means no device
243 // is ready for start. 239 // is ready for start.
244 if (device_id.empty()) { 240 if (device_id.empty()) {
245 filter_->RemoveDelegate(stream_id_); 241 filter_->RemoveDelegate(stream_id_);
246 stream_id_ = 0; 242 stream_id_ = 0;
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
330 // Close the socket to terminate the main thread function in the 326 // Close the socket to terminate the main thread function in the
331 // audio thread. 327 // audio thread.
332 audio_socket_->Shutdown(); // Stops blocking Receive calls. 328 audio_socket_->Shutdown(); // Stops blocking Receive calls.
333 // TODO(tommi): We must not do this from the IO thread. Fix. 329 // TODO(tommi): We must not do this from the IO thread. Fix.
334 base::ThreadRestrictions::ScopedAllowIO allow_wait; 330 base::ThreadRestrictions::ScopedAllowIO allow_wait;
335 audio_thread_->Join(); 331 audio_thread_->Join();
336 audio_thread_.reset(NULL); 332 audio_thread_.reset(NULL);
337 audio_socket_.reset(); 333 audio_socket_.reset();
338 } 334 }
339 } 335 }
336
337 void AudioInputDevice::WillDestroyCurrentMessageLoop() {
338 ShutDownOnIOThread(NULL);
339 }
OLDNEW
« no previous file with comments | « content/renderer/media/audio_input_device.h ('k') | content/renderer/media/scoped_loop_observer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698