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