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

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

Issue 12383016: Merge AssociateStreamWithProducer message into CreateStream message for both audio output and input. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 7 years, 8 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
« no previous file with comments | « media/audio/audio_input_device.h ('k') | media/audio/audio_input_ipc.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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_input_device.h" 5 #include "media/audio/audio_input_device.h"
6 6
7 #include "base/basictypes.h"
7 #include "base/bind.h" 8 #include "base/bind.h"
8 #include "base/message_loop.h" 9 #include "base/message_loop.h"
9 #include "base/threading/thread_restrictions.h" 10 #include "base/threading/thread_restrictions.h"
10 #include "base/time.h" 11 #include "base/time.h"
11 #include "media/audio/audio_manager_base.h" 12 #include "media/audio/audio_manager_base.h"
12 #include "media/base/audio_bus.h" 13 #include "media/base/audio_bus.h"
13 14
14 namespace media { 15 namespace media {
15 16
16 // The number of shared memory buffer segments indicated to browser process 17 // The number of shared memory buffer segments indicated to browser process
(...skipping 21 matching lines...) Expand all
38 virtual void Process(int pending_data) OVERRIDE; 39 virtual void Process(int pending_data) OVERRIDE;
39 40
40 private: 41 private:
41 int current_segment_id_; 42 int current_segment_id_;
42 CaptureCallback* capture_callback_; 43 CaptureCallback* capture_callback_;
43 scoped_ptr<AudioBus> audio_bus_; 44 scoped_ptr<AudioBus> audio_bus_;
44 DISALLOW_COPY_AND_ASSIGN(AudioThreadCallback); 45 DISALLOW_COPY_AND_ASSIGN(AudioThreadCallback);
45 }; 46 };
46 47
47 AudioInputDevice::AudioInputDevice( 48 AudioInputDevice::AudioInputDevice(
48 AudioInputIPC* ipc, 49 scoped_ptr<AudioInputIPC> ipc,
49 const scoped_refptr<base::MessageLoopProxy>& io_loop) 50 const scoped_refptr<base::MessageLoopProxy>& io_loop)
50 : ScopedLoopObserver(io_loop), 51 : ScopedLoopObserver(io_loop),
51 callback_(NULL), 52 callback_(NULL),
52 ipc_(ipc), 53 ipc_(ipc.Pass()),
53 stream_id_(0), 54 state_(IDLE),
54 session_id_(0), 55 session_id_(0),
55 agc_is_enabled_(false) { 56 agc_is_enabled_(false),
57 stopping_hack_(false) {
56 CHECK(ipc_); 58 CHECK(ipc_);
59
60 // The correctness of the code depends on the relative values assigned in the
61 // State enum.
62 COMPILE_ASSERT(IPC_CLOSED < IDLE, invalid_enum_value_assignment_0);
63 COMPILE_ASSERT(IDLE < CREATING_STREAM, invalid_enum_value_assignment_1);
64 COMPILE_ASSERT(CREATING_STREAM < RECORDING, invalid_enum_value_assignment_2);
57 } 65 }
58 66
59 void AudioInputDevice::Initialize(const AudioParameters& params, 67 void AudioInputDevice::Initialize(const AudioParameters& params,
60 CaptureCallback* callback, 68 CaptureCallback* callback,
61 int session_id) { 69 int session_id) {
70 DCHECK(params.IsValid());
62 DCHECK(!callback_); 71 DCHECK(!callback_);
63 DCHECK_EQ(0, session_id_); 72 DCHECK_EQ(0, session_id_);
64 audio_parameters_ = params; 73 audio_parameters_ = params;
65 callback_ = callback; 74 callback_ = callback;
66 session_id_ = session_id; 75 session_id_ = session_id;
67 } 76 }
68 77
69 void AudioInputDevice::Start() { 78 void AudioInputDevice::Start() {
79 DCHECK(callback_) << "Initialize hasn't been called";
70 DVLOG(1) << "Start()"; 80 DVLOG(1) << "Start()";
71 message_loop()->PostTask(FROM_HERE, 81 message_loop()->PostTask(FROM_HERE,
72 base::Bind(&AudioInputDevice::InitializeOnIOThread, this)); 82 base::Bind(&AudioInputDevice::StartUpOnIOThread, this));
73 } 83 }
74 84
75 void AudioInputDevice::Stop() { 85 void AudioInputDevice::Stop() {
76 DVLOG(1) << "Stop()"; 86 DVLOG(1) << "Stop()";
77 87
78 { 88 {
79 base::AutoLock auto_lock(audio_thread_lock_); 89 base::AutoLock auto_lock(audio_thread_lock_);
80 audio_thread_.Stop(MessageLoop::current()); 90 audio_thread_.Stop(MessageLoop::current());
91 stopping_hack_ = true;
81 } 92 }
82 93
83 message_loop()->PostTask(FROM_HERE, 94 message_loop()->PostTask(FROM_HERE,
84 base::Bind(&AudioInputDevice::ShutDownOnIOThread, this)); 95 base::Bind(&AudioInputDevice::ShutDownOnIOThread, this));
85 } 96 }
86 97
87 void AudioInputDevice::SetVolume(double volume) { 98 void AudioInputDevice::SetVolume(double volume) {
88 if (volume < 0 || volume > 1.0) { 99 if (volume < 0 || volume > 1.0) {
89 DLOG(ERROR) << "Invalid volume value specified"; 100 DLOG(ERROR) << "Invalid volume value specified";
90 return; 101 return;
(...skipping 16 matching lines...) Expand all
107 int length, 118 int length,
108 int total_segments) { 119 int total_segments) {
109 DCHECK(message_loop()->BelongsToCurrentThread()); 120 DCHECK(message_loop()->BelongsToCurrentThread());
110 #if defined(OS_WIN) 121 #if defined(OS_WIN)
111 DCHECK(handle); 122 DCHECK(handle);
112 DCHECK(socket_handle); 123 DCHECK(socket_handle);
113 #else 124 #else
114 DCHECK_GE(handle.fd, 0); 125 DCHECK_GE(handle.fd, 0);
115 DCHECK_GE(socket_handle, 0); 126 DCHECK_GE(socket_handle, 0);
116 #endif 127 #endif
117 DCHECK(length); 128 DCHECK_GT(length, 0);
118 DVLOG(1) << "OnStreamCreated (stream_id=" << stream_id_ << ")";
119 129
120 // We should only get this callback if stream_id_ is valid. If it is not, 130 if (state_ != CREATING_STREAM)
121 // the IPC layer should have closed the shared memory and socket handles 131 return;
122 // for us and not invoked the callback. The basic assertion is that when
123 // stream_id_ is 0 the AudioInputDevice instance is not registered as a
124 // delegate and hence it should not receive callbacks.
125 DCHECK(stream_id_);
126 132
127 base::AutoLock auto_lock(audio_thread_lock_); 133 base::AutoLock auto_lock(audio_thread_lock_);
134 // TODO(miu): See TODO in OnStreamCreated method for AudioOutputDevice.
135 // Interface changes need to be made; likely, after AudioInputDevice is merged
136 // into AudioOutputDevice (http://crbug.com/179597).
137 if (stopping_hack_)
138 return;
128 139
129 DCHECK(audio_thread_.IsStopped()); 140 DCHECK(audio_thread_.IsStopped());
130 audio_callback_.reset( 141 audio_callback_.reset(
131 new AudioInputDevice::AudioThreadCallback( 142 new AudioInputDevice::AudioThreadCallback(
132 audio_parameters_, handle, length, total_segments, callback_)); 143 audio_parameters_, handle, length, total_segments, callback_));
133 audio_thread_.Start(audio_callback_.get(), socket_handle, "AudioInputDevice"); 144 audio_thread_.Start(audio_callback_.get(), socket_handle, "AudioInputDevice");
134 145
135 MessageLoop::current()->PostTask(FROM_HERE, 146 state_ = RECORDING;
136 base::Bind(&AudioInputDevice::StartOnIOThread, this)); 147 ipc_->RecordStream();
137 } 148 }
138 149
139 void AudioInputDevice::OnVolume(double volume) { 150 void AudioInputDevice::OnVolume(double volume) {
140 NOTIMPLEMENTED(); 151 NOTIMPLEMENTED();
141 } 152 }
142 153
143 void AudioInputDevice::OnStateChanged( 154 void AudioInputDevice::OnStateChanged(
144 AudioInputIPCDelegate::State state) { 155 AudioInputIPCDelegate::State state) {
145 DCHECK(message_loop()->BelongsToCurrentThread()); 156 DCHECK(message_loop()->BelongsToCurrentThread());
146 157
147 // Do nothing if the stream has been closed. 158 // Do nothing if the stream has been closed.
148 if (!stream_id_) 159 if (state_ < CREATING_STREAM)
149 return; 160 return;
150 161
162 // TODO(miu): Clean-up inconsistent and incomplete handling here.
163 // http://crbug.com/180640
151 switch (state) { 164 switch (state) {
152 case AudioInputIPCDelegate::kStopped: 165 case AudioInputIPCDelegate::kStopped:
153 // TODO(xians): Should we just call ShutDownOnIOThread here instead? 166 ShutDownOnIOThread();
154 ipc_->RemoveDelegate(stream_id_);
155
156 audio_thread_.Stop(MessageLoop::current());
157 audio_callback_.reset();
158
159 stream_id_ = 0;
160 break; 167 break;
161 case AudioInputIPCDelegate::kRecording: 168 case AudioInputIPCDelegate::kRecording:
162 NOTIMPLEMENTED(); 169 NOTIMPLEMENTED();
163 break; 170 break;
164 case AudioInputIPCDelegate::kError: 171 case AudioInputIPCDelegate::kError:
165 DLOG(WARNING) << "AudioInputDevice::OnStateChanged(kError)"; 172 DLOG(WARNING) << "AudioInputDevice::OnStateChanged(kError)";
166 // Don't dereference the callback object if the audio thread 173 // Don't dereference the callback object if the audio thread
167 // is stopped or stopping. That could mean that the callback 174 // is stopped or stopping. That could mean that the callback
168 // object has been deleted. 175 // object has been deleted.
169 // TODO(tommi): Add an explicit contract for clearing the callback 176 // TODO(tommi): Add an explicit contract for clearing the callback
170 // object. Possibly require calling Initialize again or provide 177 // object. Possibly require calling Initialize again or provide
171 // a callback object via Start() and clear it in Stop(). 178 // a callback object via Start() and clear it in Stop().
172 if (!audio_thread_.IsStopped()) 179 if (!audio_thread_.IsStopped())
173 callback_->OnCaptureError(); 180 callback_->OnCaptureError();
174 break; 181 break;
175 default: 182 default:
176 NOTREACHED(); 183 NOTREACHED();
177 break; 184 break;
178 } 185 }
179 } 186 }
180 187
181 void AudioInputDevice::OnIPCClosed() { 188 void AudioInputDevice::OnIPCClosed() {
182 ipc_ = NULL; 189 DCHECK(message_loop()->BelongsToCurrentThread());
190 state_ = IPC_CLOSED;
191 ipc_.reset();
183 } 192 }
184 193
185 AudioInputDevice::~AudioInputDevice() { 194 AudioInputDevice::~AudioInputDevice() {
186 // TODO(henrika): The current design requires that the user calls 195 // TODO(henrika): The current design requires that the user calls
187 // Stop before deleting this class. 196 // Stop before deleting this class.
188 CHECK_EQ(0, stream_id_); 197 DCHECK(audio_thread_.IsStopped());
189 } 198 }
190 199
191 void AudioInputDevice::InitializeOnIOThread() { 200 void AudioInputDevice::StartUpOnIOThread() {
192 DCHECK(message_loop()->BelongsToCurrentThread()); 201 DCHECK(message_loop()->BelongsToCurrentThread());
202
193 // Make sure we don't call Start() more than once. 203 // Make sure we don't call Start() more than once.
194 DCHECK_EQ(0, stream_id_); 204 if (state_ != IDLE)
195 if (stream_id_)
196 return; 205 return;
197 206
198 if (session_id_ <= 0) { 207 if (session_id_ <= 0) {
199 DLOG(WARNING) << "Invalid session id for the input stream " << session_id_; 208 DLOG(WARNING) << "Invalid session id for the input stream " << session_id_;
200 return; 209 return;
201 } 210 }
202 211
203 stream_id_ = ipc_->AddDelegate(this); 212 state_ = CREATING_STREAM;
204 ipc_->CreateStream(stream_id_, session_id_, audio_parameters_, 213 ipc_->CreateStream(this, session_id_, audio_parameters_,
205 agc_is_enabled_, kRequestedSharedMemoryCount); 214 agc_is_enabled_, kRequestedSharedMemoryCount);
206 } 215 }
207 216
208 void AudioInputDevice::StartOnIOThread() {
209 DCHECK(message_loop()->BelongsToCurrentThread());
210 if (stream_id_)
211 ipc_->RecordStream(stream_id_);
212 }
213
214 void AudioInputDevice::ShutDownOnIOThread() { 217 void AudioInputDevice::ShutDownOnIOThread() {
215 DCHECK(message_loop()->BelongsToCurrentThread()); 218 DCHECK(message_loop()->BelongsToCurrentThread());
216 // NOTE: |completion| may be NULL.
217 // Make sure we don't call shutdown more than once.
218 if (stream_id_) {
219 if (ipc_) {
220 ipc_->CloseStream(stream_id_);
221 ipc_->RemoveDelegate(stream_id_);
222 }
223 219
224 stream_id_ = 0; 220 // Close the stream, if we haven't already.
221 if (state_ >= CREATING_STREAM) {
222 ipc_->CloseStream();
223 state_ = IDLE;
225 agc_is_enabled_ = false; 224 agc_is_enabled_ = false;
226 } 225 }
227 226
228 // We can run into an issue where ShutDownOnIOThread is called right after 227 // We can run into an issue where ShutDownOnIOThread is called right after
229 // OnStreamCreated is called in cases where Start/Stop are called before we 228 // OnStreamCreated is called in cases where Start/Stop are called before we
230 // get the OnStreamCreated callback. To handle that corner case, we call 229 // get the OnStreamCreated callback. To handle that corner case, we call
231 // Stop(). In most cases, the thread will already be stopped. 230 // Stop(). In most cases, the thread will already be stopped.
231 //
232 // Another situation is when the IO thread goes away before Stop() is called 232 // Another situation is when the IO thread goes away before Stop() is called
233 // in which case, we cannot use the message loop to close the thread handle 233 // in which case, we cannot use the message loop to close the thread handle
234 // and can't not rely on the main thread existing either. 234 // and can't not rely on the main thread existing either.
235 base::AutoLock auto_lock_(audio_thread_lock_);
235 base::ThreadRestrictions::ScopedAllowIO allow_io; 236 base::ThreadRestrictions::ScopedAllowIO allow_io;
236 audio_thread_.Stop(NULL); 237 audio_thread_.Stop(NULL);
237 audio_callback_.reset(); 238 audio_callback_.reset();
238 session_id_ = 0; 239 stopping_hack_ = false;
239 } 240 }
240 241
241 void AudioInputDevice::SetVolumeOnIOThread(double volume) { 242 void AudioInputDevice::SetVolumeOnIOThread(double volume) {
242 DCHECK(message_loop()->BelongsToCurrentThread()); 243 DCHECK(message_loop()->BelongsToCurrentThread());
243 if (stream_id_) 244 if (state_ >= CREATING_STREAM)
244 ipc_->SetVolume(stream_id_, volume); 245 ipc_->SetVolume(volume);
245 } 246 }
246 247
247 void AudioInputDevice::SetAutomaticGainControlOnIOThread(bool enabled) { 248 void AudioInputDevice::SetAutomaticGainControlOnIOThread(bool enabled) {
248 DCHECK(message_loop()->BelongsToCurrentThread()); 249 DCHECK(message_loop()->BelongsToCurrentThread());
249 DCHECK_EQ(0, stream_id_) << 250
250 "The AGC state can not be modified while capturing is active."; 251 if (state_ >= CREATING_STREAM) {
251 if (stream_id_) 252 DLOG(WARNING) << "The AGC state can not be modified after starting.";
252 return; 253 return;
254 }
253 255
254 // We simply store the new AGC setting here. This value will be used when 256 // We simply store the new AGC setting here. This value will be used when
255 // a new stream is initialized and by GetAutomaticGainControl(). 257 // a new stream is initialized and by GetAutomaticGainControl().
256 agc_is_enabled_ = enabled; 258 agc_is_enabled_ = enabled;
257 } 259 }
258 260
259 void AudioInputDevice::WillDestroyCurrentMessageLoop() { 261 void AudioInputDevice::WillDestroyCurrentMessageLoop() {
260 LOG(ERROR) << "IO loop going away before the input device has been stopped"; 262 LOG(ERROR) << "IO loop going away before the input device has been stopped";
261 ShutDownOnIOThread(); 263 ShutDownOnIOThread();
262 } 264 }
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
304 // with nominal range -1.0 -> +1.0. 306 // with nominal range -1.0 -> +1.0.
305 audio_bus_->FromInterleaved(memory, audio_bus_->frames(), bytes_per_sample); 307 audio_bus_->FromInterleaved(memory, audio_bus_->frames(), bytes_per_sample);
306 308
307 // Deliver captured data to the client in floating point format 309 // Deliver captured data to the client in floating point format
308 // and update the audio-delay measurement. 310 // and update the audio-delay measurement.
309 capture_callback_->Capture(audio_bus_.get(), 311 capture_callback_->Capture(audio_bus_.get(),
310 audio_delay_milliseconds, volume); 312 audio_delay_milliseconds, volume);
311 } 313 }
312 314
313 } // namespace media 315 } // namespace media
OLDNEW
« no previous file with comments | « media/audio/audio_input_device.h ('k') | media/audio/audio_input_ipc.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698