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

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

Powered by Google App Engine
This is Rietveld 408576698