| OLD | NEW |
| 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/browser/renderer_host/media/audio_renderer_host.h" | 5 #include "content/browser/renderer_host/media/audio_renderer_host.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/metrics/histogram.h" | 8 #include "base/metrics/histogram.h" |
| 9 #include "base/process.h" | 9 #include "base/process.h" |
| 10 #include "base/shared_memory.h" | 10 #include "base/shared_memory.h" |
| 11 #include "content/browser/browser_main_loop.h" | 11 #include "content/browser/browser_main_loop.h" |
| 12 #include "content/browser/renderer_host/media/audio_sync_reader.h" | 12 #include "content/browser/renderer_host/media/audio_sync_reader.h" |
| 13 #include "content/common/media/audio_messages.h" | 13 #include "content/common/media/audio_messages.h" |
| 14 #include "content/public/browser/media_observer.h" | 14 #include "content/public/browser/media_observer.h" |
| 15 #include "media/audio/audio_util.h" | 15 #include "media/audio/audio_util.h" |
| 16 | 16 |
| 17 using content::BrowserMessageFilter; | 17 using content::BrowserMessageFilter; |
| 18 using content::BrowserThread; | 18 using content::BrowserThread; |
| 19 | 19 |
| 20 AudioRendererHost::AudioEntry::AudioEntry() | 20 AudioRendererHost::AudioEntry::AudioEntry() |
| 21 : stream_id(0), | 21 : stream_id(0), |
| 22 pending_close(false) { | 22 pending_close(false) { |
| 23 } | 23 } |
| 24 | 24 |
| 25 AudioRendererHost::AudioEntry::~AudioEntry() {} | 25 AudioRendererHost::AudioEntry::~AudioEntry() {} |
| 26 | 26 |
| 27 /////////////////////////////////////////////////////////////////////////////// | 27 /////////////////////////////////////////////////////////////////////////////// |
| 28 // AudioRendererHost implementations. | 28 // AudioRendererHost implementations. |
| 29 AudioRendererHost::AudioRendererHost( | 29 AudioRendererHost::AudioRendererHost( |
| 30 int render_process_id, |
| 30 media::AudioManager* audio_manager, | 31 media::AudioManager* audio_manager, |
| 31 content::MediaObserver* media_observer) | 32 content::MediaObserver* media_observer) |
| 32 : audio_manager_(audio_manager), | 33 : render_process_id_(render_process_id), |
| 34 audio_manager_(audio_manager), |
| 33 media_observer_(media_observer) { | 35 media_observer_(media_observer) { |
| 34 } | 36 } |
| 35 | 37 |
| 36 AudioRendererHost::~AudioRendererHost() { | 38 AudioRendererHost::~AudioRendererHost() { |
| 37 DCHECK(audio_entries_.empty()); | 39 DCHECK(audio_entries_.empty()); |
| 38 } | 40 } |
| 39 | 41 |
| 40 void AudioRendererHost::OnChannelClosing() { | 42 void AudioRendererHost::OnChannelClosing() { |
| 41 BrowserMessageFilter::OnChannelClosing(); | 43 BrowserMessageFilter::OnChannelClosing(); |
| 42 | 44 |
| (...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 230 audio_manager_, this, audio_params, entry->reader.get()); | 232 audio_manager_, this, audio_params, entry->reader.get()); |
| 231 | 233 |
| 232 if (!entry->controller) { | 234 if (!entry->controller) { |
| 233 SendErrorMessage(stream_id); | 235 SendErrorMessage(stream_id); |
| 234 return; | 236 return; |
| 235 } | 237 } |
| 236 | 238 |
| 237 // If we have created the controller successfully, create an entry and add it | 239 // If we have created the controller successfully, create an entry and add it |
| 238 // to the map. | 240 // to the map. |
| 239 entry->stream_id = stream_id; | 241 entry->stream_id = stream_id; |
| 242 entry->render_view_id = render_view_id; |
| 240 audio_entries_.insert(std::make_pair(stream_id, entry.release())); | 243 audio_entries_.insert(std::make_pair(stream_id, entry.release())); |
| 241 if (media_observer_) | 244 if (media_observer_) { |
| 242 media_observer_->OnSetAudioStreamStatus(this, stream_id, "created"); | 245 media_observer_->OnSetAudioStreamStatus( |
| 246 render_process_id_, render_view_id, stream_id, "created"); |
| 247 } |
| 243 } | 248 } |
| 244 | 249 |
| 245 void AudioRendererHost::OnPlayStream(int stream_id) { | 250 void AudioRendererHost::OnPlayStream(int stream_id) { |
| 246 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 251 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 247 | 252 |
| 248 AudioEntry* entry = LookupById(stream_id); | 253 AudioEntry* entry = LookupById(stream_id); |
| 249 if (!entry) { | 254 if (!entry) { |
| 250 SendErrorMessage(stream_id); | 255 SendErrorMessage(stream_id); |
| 251 return; | 256 return; |
| 252 } | 257 } |
| 253 | 258 |
| 254 entry->controller->Play(); | 259 entry->controller->Play(); |
| 255 if (media_observer_) | 260 if (media_observer_) { |
| 256 media_observer_->OnSetAudioStreamPlaying(this, stream_id, true); | 261 media_observer_->OnSetAudioStreamPlaying( |
| 262 render_process_id_, entry->render_view_id, stream_id, true); |
| 263 } |
| 257 } | 264 } |
| 258 | 265 |
| 259 void AudioRendererHost::OnPauseStream(int stream_id) { | 266 void AudioRendererHost::OnPauseStream(int stream_id) { |
| 260 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 267 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 261 | 268 |
| 262 AudioEntry* entry = LookupById(stream_id); | 269 AudioEntry* entry = LookupById(stream_id); |
| 263 if (!entry) { | 270 if (!entry) { |
| 264 SendErrorMessage(stream_id); | 271 SendErrorMessage(stream_id); |
| 265 return; | 272 return; |
| 266 } | 273 } |
| 267 | 274 |
| 268 entry->controller->Pause(); | 275 entry->controller->Pause(); |
| 269 if (media_observer_) | 276 if (media_observer_) { |
| 270 media_observer_->OnSetAudioStreamPlaying(this, stream_id, false); | 277 media_observer_->OnSetAudioStreamPlaying( |
| 278 render_process_id_, entry->render_view_id, stream_id, false); |
| 279 } |
| 271 } | 280 } |
| 272 | 281 |
| 273 void AudioRendererHost::OnFlushStream(int stream_id) { | 282 void AudioRendererHost::OnFlushStream(int stream_id) { |
| 274 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 283 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 275 | 284 |
| 276 AudioEntry* entry = LookupById(stream_id); | 285 AudioEntry* entry = LookupById(stream_id); |
| 277 if (!entry) { | 286 if (!entry) { |
| 278 SendErrorMessage(stream_id); | 287 SendErrorMessage(stream_id); |
| 279 return; | 288 return; |
| 280 } | 289 } |
| 281 | 290 |
| 282 entry->controller->Flush(); | 291 entry->controller->Flush(); |
| 283 if (media_observer_) | 292 if (media_observer_) { |
| 284 media_observer_->OnSetAudioStreamStatus(this, stream_id, "flushed"); | 293 media_observer_->OnSetAudioStreamStatus( |
| 294 render_process_id_, entry->render_view_id, stream_id, "flushed"); |
| 295 } |
| 285 } | 296 } |
| 286 | 297 |
| 287 void AudioRendererHost::OnCloseStream(int stream_id) { | 298 void AudioRendererHost::OnCloseStream(int stream_id) { |
| 288 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 299 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 289 | 300 |
| 290 if (media_observer_) | 301 AudioEntry* entry = LookupById(stream_id); |
| 291 media_observer_->OnSetAudioStreamStatus(this, stream_id, "closed"); | 302 if (!entry) |
| 303 return; |
| 292 | 304 |
| 293 AudioEntry* entry = LookupById(stream_id); | 305 if (media_observer_) { |
| 306 media_observer_->OnSetAudioStreamStatus( |
| 307 render_process_id_, entry->render_view_id, stream_id, "closed"); |
| 308 } |
| 294 | 309 |
| 295 if (entry) | 310 CloseAndDeleteStream(entry); |
| 296 CloseAndDeleteStream(entry); | |
| 297 } | 311 } |
| 298 | 312 |
| 299 void AudioRendererHost::OnSetVolume(int stream_id, double volume) { | 313 void AudioRendererHost::OnSetVolume(int stream_id, double volume) { |
| 300 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 314 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 301 | 315 |
| 302 AudioEntry* entry = LookupById(stream_id); | 316 AudioEntry* entry = LookupById(stream_id); |
| 303 if (!entry) { | 317 if (!entry) { |
| 304 SendErrorMessage(stream_id); | 318 SendErrorMessage(stream_id); |
| 305 return; | 319 return; |
| 306 } | 320 } |
| 307 | 321 |
| 308 // Make sure the volume is valid. | 322 // Make sure the volume is valid. |
| 309 if (volume < 0 || volume > 1.0) | 323 if (volume < 0 || volume > 1.0) |
| 310 return; | 324 return; |
| 311 entry->controller->SetVolume(volume); | 325 entry->controller->SetVolume(volume); |
| 312 if (media_observer_) | 326 if (media_observer_) { |
| 313 media_observer_->OnSetAudioStreamVolume(this, stream_id, volume); | 327 media_observer_->OnSetAudioStreamVolume( |
| 328 render_process_id_, entry->render_view_id, stream_id, volume); |
| 329 } |
| 314 } | 330 } |
| 315 | 331 |
| 316 void AudioRendererHost::SendErrorMessage(int32 stream_id) { | 332 void AudioRendererHost::SendErrorMessage(int32 stream_id) { |
| 317 Send(new AudioMsg_NotifyStreamStateChanged( | 333 Send(new AudioMsg_NotifyStreamStateChanged( |
| 318 stream_id, media::AudioOutputIPCDelegate::kError)); | 334 stream_id, media::AudioOutputIPCDelegate::kError)); |
| 319 } | 335 } |
| 320 | 336 |
| 321 void AudioRendererHost::DeleteEntries() { | 337 void AudioRendererHost::DeleteEntries() { |
| 322 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 338 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 323 | 339 |
| (...skipping 16 matching lines...) Expand all Loading... |
| 340 void AudioRendererHost::DeleteEntry(AudioEntry* entry) { | 356 void AudioRendererHost::DeleteEntry(AudioEntry* entry) { |
| 341 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 357 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 342 | 358 |
| 343 // Delete the entry when this method goes out of scope. | 359 // Delete the entry when this method goes out of scope. |
| 344 scoped_ptr<AudioEntry> entry_deleter(entry); | 360 scoped_ptr<AudioEntry> entry_deleter(entry); |
| 345 | 361 |
| 346 // Erase the entry identified by |stream_id| from the map. | 362 // Erase the entry identified by |stream_id| from the map. |
| 347 audio_entries_.erase(entry->stream_id); | 363 audio_entries_.erase(entry->stream_id); |
| 348 | 364 |
| 349 // Notify the media observer. | 365 // Notify the media observer. |
| 350 if (media_observer_) | 366 if (media_observer_) { |
| 351 media_observer_->OnDeleteAudioStream(this, entry->stream_id); | 367 media_observer_->OnDeleteAudioStream( |
| 368 render_process_id_, entry->render_view_id, entry->stream_id); |
| 369 } |
| 352 } | 370 } |
| 353 | 371 |
| 354 void AudioRendererHost::DeleteEntryOnError(AudioEntry* entry) { | 372 void AudioRendererHost::DeleteEntryOnError(AudioEntry* entry) { |
| 355 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 373 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 356 | 374 |
| 357 // Sends the error message first before we close the stream because | 375 // Sends the error message first before we close the stream because |
| 358 // |entry| is destroyed in DeleteEntry(). | 376 // |entry| is destroyed in DeleteEntry(). |
| 359 SendErrorMessage(entry->stream_id); | 377 SendErrorMessage(entry->stream_id); |
| 360 | 378 |
| 361 if (media_observer_) | 379 if (media_observer_) { |
| 362 media_observer_->OnSetAudioStreamStatus(this, entry->stream_id, "error"); | 380 media_observer_->OnSetAudioStreamStatus( |
| 381 render_process_id_, entry->render_view_id, entry->stream_id, "error"); |
| 382 } |
| 363 CloseAndDeleteStream(entry); | 383 CloseAndDeleteStream(entry); |
| 364 } | 384 } |
| 365 | 385 |
| 366 AudioRendererHost::AudioEntry* AudioRendererHost::LookupById(int stream_id) { | 386 AudioRendererHost::AudioEntry* AudioRendererHost::LookupById(int stream_id) { |
| 367 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 387 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 368 | 388 |
| 369 AudioEntryMap::iterator i = audio_entries_.find(stream_id); | 389 AudioEntryMap::iterator i = audio_entries_.find(stream_id); |
| 370 if (i != audio_entries_.end() && !i->second->pending_close) | 390 if (i != audio_entries_.end() && !i->second->pending_close) |
| 371 return i->second; | 391 return i->second; |
| 372 return NULL; | 392 return NULL; |
| 373 } | 393 } |
| 374 | 394 |
| 375 AudioRendererHost::AudioEntry* AudioRendererHost::LookupByController( | 395 AudioRendererHost::AudioEntry* AudioRendererHost::LookupByController( |
| 376 media::AudioOutputController* controller) { | 396 media::AudioOutputController* controller) { |
| 377 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 397 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 378 | 398 |
| 379 // Iterate the map of entries. | 399 // Iterate the map of entries. |
| 380 // TODO(hclam): Implement a faster look up method. | 400 // TODO(hclam): Implement a faster look up method. |
| 381 for (AudioEntryMap::iterator i = audio_entries_.begin(); | 401 for (AudioEntryMap::iterator i = audio_entries_.begin(); |
| 382 i != audio_entries_.end(); ++i) { | 402 i != audio_entries_.end(); ++i) { |
| 383 if (!i->second->pending_close && controller == i->second->controller.get()) | 403 if (!i->second->pending_close && controller == i->second->controller.get()) |
| 384 return i->second; | 404 return i->second; |
| 385 } | 405 } |
| 386 return NULL; | 406 return NULL; |
| 387 } | 407 } |
| OLD | NEW |