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

Side by Side Diff: media/audio/audio_output_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_output_device.h ('k') | media/audio/audio_output_device_unittest.cc » ('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_output_device.h" 5 #include "media/audio/audio_output_device.h"
6 6
7 #include "base/basictypes.h"
7 #include "base/debug/trace_event.h" 8 #include "base/debug/trace_event.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_output_controller.h" 12 #include "media/audio/audio_output_controller.h"
12 #include "media/audio/audio_util.h" 13 #include "media/audio/audio_util.h"
13 #include "media/audio/shared_memory_util.h" 14 #include "media/audio/shared_memory_util.h"
14 #include "media/base/limits.h" 15 #include "media/base/limits.h"
15 16
16 namespace media { 17 namespace media {
(...skipping 16 matching lines...) Expand all
33 virtual void Process(int pending_data) OVERRIDE; 34 virtual void Process(int pending_data) OVERRIDE;
34 35
35 private: 36 private:
36 AudioRendererSink::RenderCallback* render_callback_; 37 AudioRendererSink::RenderCallback* render_callback_;
37 scoped_ptr<AudioBus> input_bus_; 38 scoped_ptr<AudioBus> input_bus_;
38 scoped_ptr<AudioBus> output_bus_; 39 scoped_ptr<AudioBus> output_bus_;
39 DISALLOW_COPY_AND_ASSIGN(AudioThreadCallback); 40 DISALLOW_COPY_AND_ASSIGN(AudioThreadCallback);
40 }; 41 };
41 42
42 AudioOutputDevice::AudioOutputDevice( 43 AudioOutputDevice::AudioOutputDevice(
43 AudioOutputIPC* ipc, 44 scoped_ptr<AudioOutputIPC> ipc,
44 const scoped_refptr<base::MessageLoopProxy>& io_loop) 45 const scoped_refptr<base::MessageLoopProxy>& io_loop)
45 : ScopedLoopObserver(io_loop), 46 : ScopedLoopObserver(io_loop),
46 callback_(NULL), 47 callback_(NULL),
47 ipc_(ipc), 48 ipc_(ipc.Pass()),
48 stream_id_(0),
49 state_(IDLE), 49 state_(IDLE),
50 play_on_start_(true), 50 play_on_start_(true),
51 stopping_hack_(false) { 51 stopping_hack_(false) {
52 CHECK(ipc_); 52 CHECK(ipc_);
53
54 // The correctness of the code depends on the relative values assigned in the
55 // State enum.
56 COMPILE_ASSERT(IPC_CLOSED < IDLE, invalid_enum_value_assignment_0);
57 COMPILE_ASSERT(IDLE < CREATING_STREAM, invalid_enum_value_assignment_1);
58 COMPILE_ASSERT(CREATING_STREAM < PAUSED, invalid_enum_value_assignment_2);
59 COMPILE_ASSERT(PAUSED < PLAYING, invalid_enum_value_assignment_3);
53 } 60 }
54 61
55 void AudioOutputDevice::Initialize(const AudioParameters& params, 62 void AudioOutputDevice::Initialize(const AudioParameters& params,
56 RenderCallback* callback) { 63 RenderCallback* callback) {
57 DCHECK(!callback_) << "Calling Initialize() twice?"; 64 DCHECK(!callback_) << "Calling Initialize() twice?";
58 DCHECK(params.IsValid()); 65 DCHECK(params.IsValid());
59 audio_parameters_ = params; 66 audio_parameters_ = params;
60 callback_ = callback; 67 callback_ = callback;
61 } 68 }
62 69
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
102 base::Bind(&AudioOutputDevice::SetVolumeOnIOThread, this, volume))) { 109 base::Bind(&AudioOutputDevice::SetVolumeOnIOThread, this, volume))) {
103 return false; 110 return false;
104 } 111 }
105 112
106 return true; 113 return true;
107 } 114 }
108 115
109 void AudioOutputDevice::CreateStreamOnIOThread(const AudioParameters& params) { 116 void AudioOutputDevice::CreateStreamOnIOThread(const AudioParameters& params) {
110 DCHECK(message_loop()->BelongsToCurrentThread()); 117 DCHECK(message_loop()->BelongsToCurrentThread());
111 if (state_ == IDLE) { 118 if (state_ == IDLE) {
112 stream_id_ = ipc_->AddDelegate(this);
113 state_ = CREATING_STREAM; 119 state_ = CREATING_STREAM;
114 ipc_->CreateStream(stream_id_, params); 120 ipc_->CreateStream(this, params);
115 } 121 }
116 } 122 }
117 123
118 void AudioOutputDevice::PlayOnIOThread() { 124 void AudioOutputDevice::PlayOnIOThread() {
119 DCHECK(message_loop()->BelongsToCurrentThread()); 125 DCHECK(message_loop()->BelongsToCurrentThread());
120 if (state_ == PAUSED) { 126 if (state_ == PAUSED) {
121 ipc_->PlayStream(stream_id_); 127 ipc_->PlayStream();
122 state_ = PLAYING; 128 state_ = PLAYING;
123 play_on_start_ = false; 129 play_on_start_ = false;
124 } else { 130 } else {
125 play_on_start_ = true; 131 play_on_start_ = true;
126 } 132 }
127 } 133 }
128 134
129 void AudioOutputDevice::PauseOnIOThread() { 135 void AudioOutputDevice::PauseOnIOThread() {
130 DCHECK(message_loop()->BelongsToCurrentThread()); 136 DCHECK(message_loop()->BelongsToCurrentThread());
131 if (state_ == PLAYING) { 137 if (state_ == PLAYING) {
132 ipc_->PauseStream(stream_id_); 138 ipc_->PauseStream();
133 state_ = PAUSED; 139 state_ = PAUSED;
134 } 140 }
135 play_on_start_ = false; 141 play_on_start_ = false;
136 } 142 }
137 143
138 void AudioOutputDevice::ShutDownOnIOThread() { 144 void AudioOutputDevice::ShutDownOnIOThread() {
139 DCHECK(message_loop()->BelongsToCurrentThread()); 145 DCHECK(message_loop()->BelongsToCurrentThread());
140 146
141 // Make sure we don't call shutdown more than once. 147 // Close the stream, if we haven't already.
142 if (state_ >= CREATING_STREAM) { 148 if (state_ >= CREATING_STREAM) {
143 ipc_->CloseStream(stream_id_); 149 ipc_->CloseStream();
144 ipc_->RemoveDelegate(stream_id_);
145 state_ = IDLE; 150 state_ = IDLE;
146 stream_id_ = 0;
147 } 151 }
148 152
149 // We can run into an issue where ShutDownOnIOThread is called right after 153 // We can run into an issue where ShutDownOnIOThread is called right after
150 // OnStreamCreated is called in cases where Start/Stop are called before we 154 // OnStreamCreated is called in cases where Start/Stop are called before we
151 // get the OnStreamCreated callback. To handle that corner case, we call 155 // get the OnStreamCreated callback. To handle that corner case, we call
152 // Stop(). In most cases, the thread will already be stopped. 156 // Stop(). In most cases, the thread will already be stopped.
153 // 157 //
154 // Another situation is when the IO thread goes away before Stop() is called 158 // Another situation is when the IO thread goes away before Stop() is called
155 // in which case, we cannot use the message loop to close the thread handle 159 // in which case, we cannot use the message loop to close the thread handle
156 // and can't rely on the main thread existing either. 160 // and can't rely on the main thread existing either.
157 base::AutoLock auto_lock_(audio_thread_lock_); 161 base::AutoLock auto_lock_(audio_thread_lock_);
158 base::ThreadRestrictions::ScopedAllowIO allow_io; 162 base::ThreadRestrictions::ScopedAllowIO allow_io;
159 audio_thread_.Stop(NULL); 163 audio_thread_.Stop(NULL);
160 audio_callback_.reset(); 164 audio_callback_.reset();
161 stopping_hack_ = false; 165 stopping_hack_ = false;
162 } 166 }
163 167
164 void AudioOutputDevice::SetVolumeOnIOThread(double volume) { 168 void AudioOutputDevice::SetVolumeOnIOThread(double volume) {
165 DCHECK(message_loop()->BelongsToCurrentThread()); 169 DCHECK(message_loop()->BelongsToCurrentThread());
166 if (state_ >= CREATING_STREAM) 170 if (state_ >= CREATING_STREAM)
167 ipc_->SetVolume(stream_id_, volume); 171 ipc_->SetVolume(volume);
168 } 172 }
169 173
170 void AudioOutputDevice::OnStateChanged(AudioOutputIPCDelegate::State state) { 174 void AudioOutputDevice::OnStateChanged(AudioOutputIPCDelegate::State state) {
171 DCHECK(message_loop()->BelongsToCurrentThread()); 175 DCHECK(message_loop()->BelongsToCurrentThread());
172 176
173 // Do nothing if the stream has been closed. 177 // Do nothing if the stream has been closed.
174 if (state_ < CREATING_STREAM) 178 if (state_ < CREATING_STREAM)
175 return; 179 return;
176 180
177 if (state == AudioOutputIPCDelegate::kError) { 181 // TODO(miu): Clean-up inconsistent and incomplete handling here.
178 DLOG(WARNING) << "AudioOutputDevice::OnStateChanged(kError)"; 182 // http://crbug.com/180640
179 // Don't dereference the callback object if the audio thread 183 switch (state) {
180 // is stopped or stopping. That could mean that the callback 184 case AudioOutputIPCDelegate::kPlaying:
181 // object has been deleted. 185 case AudioOutputIPCDelegate::kPaused:
182 // TODO(tommi): Add an explicit contract for clearing the callback 186 NOTIMPLEMENTED();
183 // object. Possibly require calling Initialize again or provide 187 break;
184 // a callback object via Start() and clear it in Stop(). 188 case AudioOutputIPCDelegate::kError:
185 if (!audio_thread_.IsStopped()) 189 DLOG(WARNING) << "AudioOutputDevice::OnStateChanged(kError)";
186 callback_->OnRenderError(); 190 // Don't dereference the callback object if the audio thread
191 // is stopped or stopping. That could mean that the callback
192 // object has been deleted.
193 // TODO(tommi): Add an explicit contract for clearing the callback
194 // object. Possibly require calling Initialize again or provide
195 // a callback object via Start() and clear it in Stop().
196 if (!audio_thread_.IsStopped())
197 callback_->OnRenderError();
198 break;
199 default:
200 NOTREACHED();
201 break;
187 } 202 }
188 } 203 }
189 204
190 void AudioOutputDevice::OnStreamCreated( 205 void AudioOutputDevice::OnStreamCreated(
191 base::SharedMemoryHandle handle, 206 base::SharedMemoryHandle handle,
192 base::SyncSocket::Handle socket_handle, 207 base::SyncSocket::Handle socket_handle,
193 int length) { 208 int length) {
194 DCHECK(message_loop()->BelongsToCurrentThread()); 209 DCHECK(message_loop()->BelongsToCurrentThread());
195 #if defined(OS_WIN) 210 #if defined(OS_WIN)
196 DCHECK(handle); 211 DCHECK(handle);
197 DCHECK(socket_handle); 212 DCHECK(socket_handle);
198 #else 213 #else
199 DCHECK_GE(handle.fd, 0); 214 DCHECK_GE(handle.fd, 0);
200 DCHECK_GE(socket_handle, 0); 215 DCHECK_GE(socket_handle, 0);
201 #endif 216 #endif
217 DCHECK_GT(length, 0);
202 218
203 if (state_ != CREATING_STREAM) 219 if (state_ != CREATING_STREAM)
204 return; 220 return;
205 221
206 // We can receive OnStreamCreated() on the IO thread after the client has 222 // We can receive OnStreamCreated() on the IO thread after the client has
207 // called Stop() but before ShutDownOnIOThread() is processed. In such a 223 // called Stop() but before ShutDownOnIOThread() is processed. In such a
208 // situation |callback_| might point to freed memory. Instead of starting 224 // situation |callback_| might point to freed memory. Instead of starting
209 // |audio_thread_| do nothing and wait for ShutDownOnIOThread() to get called. 225 // |audio_thread_| do nothing and wait for ShutDownOnIOThread() to get called.
210 // 226 //
211 // TODO(scherkus): The real fix is to have sane ownership semantics. The fact 227 // TODO(scherkus): The real fix is to have sane ownership semantics. The fact
(...skipping 16 matching lines...) Expand all
228 244
229 // We handle the case where Play() and/or Pause() may have been called 245 // We handle the case where Play() and/or Pause() may have been called
230 // multiple times before OnStreamCreated() gets called. 246 // multiple times before OnStreamCreated() gets called.
231 if (play_on_start_) 247 if (play_on_start_)
232 PlayOnIOThread(); 248 PlayOnIOThread();
233 } 249 }
234 250
235 void AudioOutputDevice::OnIPCClosed() { 251 void AudioOutputDevice::OnIPCClosed() {
236 DCHECK(message_loop()->BelongsToCurrentThread()); 252 DCHECK(message_loop()->BelongsToCurrentThread());
237 state_ = IPC_CLOSED; 253 state_ = IPC_CLOSED;
238 ipc_ = NULL; 254 ipc_.reset();
239 } 255 }
240 256
241 void AudioOutputDevice::WillDestroyCurrentMessageLoop() { 257 void AudioOutputDevice::WillDestroyCurrentMessageLoop() {
242 LOG(ERROR) << "IO loop going away before the audio device has been stopped"; 258 LOG(ERROR) << "IO loop going away before the audio device has been stopped";
243 ShutDownOnIOThread(); 259 ShutDownOnIOThread();
244 } 260 }
245 261
246 // AudioOutputDevice::AudioThreadCallback 262 // AudioOutputDevice::AudioThreadCallback
247 263
248 AudioOutputDevice::AudioThreadCallback::AudioThreadCallback( 264 AudioOutputDevice::AudioThreadCallback::AudioThreadCallback(
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
320 // TODO(dalecurtis): Technically this is not always correct. Due to channel 336 // TODO(dalecurtis): Technically this is not always correct. Due to channel
321 // padding for alignment, there may be more data available than this. We're 337 // padding for alignment, there may be more data available than this. We're
322 // relying on AudioSyncReader::Read() to parse this with that in mind. Rename 338 // relying on AudioSyncReader::Read() to parse this with that in mind. Rename
323 // these methods to Set/GetActualFrameCount(). 339 // these methods to Set/GetActualFrameCount().
324 SetActualDataSizeInBytes( 340 SetActualDataSizeInBytes(
325 &shared_memory_, memory_length_, 341 &shared_memory_, memory_length_,
326 num_frames * sizeof(*output_bus_->channel(0)) * output_bus_->channels()); 342 num_frames * sizeof(*output_bus_->channel(0)) * output_bus_->channels());
327 } 343 }
328 344
329 } // namespace media. 345 } // namespace media.
OLDNEW
« no previous file with comments | « media/audio/audio_output_device.h ('k') | media/audio/audio_output_device_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698