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