Chromium Code Reviews| 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/media/media_internals.h" | 5 #include "content/browser/media/media_internals.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include <memory> | 9 #include <memory> |
| 10 #include <tuple> | |
| 10 #include <utility> | 11 #include <utility> |
| 11 | 12 |
| 12 #include "base/macros.h" | 13 #include "base/macros.h" |
| 13 #include "base/metrics/histogram_macros.h" | 14 #include "base/metrics/histogram_macros.h" |
| 14 #include "base/strings/string16.h" | 15 #include "base/strings/string16.h" |
| 15 #include "base/strings/string_number_conversions.h" | 16 #include "base/strings/string_number_conversions.h" |
| 16 #include "base/strings/stringprintf.h" | 17 #include "base/strings/stringprintf.h" |
| 17 #include "build/build_config.h" | 18 #include "build/build_config.h" |
| 18 #include "content/browser/renderer_host/media/media_stream_manager.h" | 19 #include "content/browser/renderer_host/media/media_stream_manager.h" |
| 20 #include "content/public/browser/browser_context.h" | |
| 19 #include "content/public/browser/browser_thread.h" | 21 #include "content/public/browser/browser_thread.h" |
| 20 #include "content/public/browser/notification_service.h" | 22 #include "content/public/browser/notification_service.h" |
| 21 #include "content/public/browser/notification_types.h" | 23 #include "content/public/browser/notification_types.h" |
| 22 #include "content/public/browser/render_frame_host.h" | 24 #include "content/public/browser/render_frame_host.h" |
| 23 #include "content/public/browser/render_process_host.h" | 25 #include "content/public/browser/render_process_host.h" |
| 24 #include "content/public/browser/web_contents.h" | 26 #include "content/public/browser/web_contents.h" |
| 25 #include "content/public/browser/web_ui.h" | 27 #include "content/public/browser/web_ui.h" |
| 26 #include "media/base/audio_parameters.h" | 28 #include "media/base/audio_parameters.h" |
| 27 #include "media/base/media_log_event.h" | 29 #include "media/base/media_log_event.h" |
| 28 #include "media/filters/gpu_video_decoder.h" | 30 #include "media/filters/gpu_video_decoder.h" |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 83 case media::AudioParameters::AUDIO_BITSTREAM_EAC3: | 85 case media::AudioParameters::AUDIO_BITSTREAM_EAC3: |
| 84 return "eac3"; | 86 return "eac3"; |
| 85 case media::AudioParameters::AUDIO_FAKE: | 87 case media::AudioParameters::AUDIO_FAKE: |
| 86 return "fake"; | 88 return "fake"; |
| 87 } | 89 } |
| 88 | 90 |
| 89 NOTREACHED(); | 91 NOTREACHED(); |
| 90 return "unknown"; | 92 return "unknown"; |
| 91 } | 93 } |
| 92 | 94 |
| 95 bool IsIncognito(int render_process_id) { | |
|
ddorwin
2017/04/13 16:52:59
The function name is different from the method it
| |
| 96 content::RenderProcessHost* render_process_host = | |
| 97 content::RenderProcessHost::FromID(render_process_id); | |
| 98 DCHECK(render_process_host); | |
| 99 | |
| 100 content::BrowserContext* browser_context = | |
| 101 render_process_host->GetBrowserContext(); | |
| 102 DCHECK(browser_context); | |
| 103 | |
| 104 return browser_context->IsOffTheRecord(); | |
| 105 } | |
| 106 | |
| 93 const char kAudioLogStatusKey[] = "status"; | 107 const char kAudioLogStatusKey[] = "status"; |
| 94 const char kAudioLogUpdateFunction[] = "media.updateAudioComponent"; | 108 const char kAudioLogUpdateFunction[] = "media.updateAudioComponent"; |
| 95 | 109 |
| 96 } // namespace | 110 } // namespace |
| 97 | 111 |
| 98 namespace content { | 112 namespace content { |
| 99 | 113 |
| 100 class AudioLogImpl : public media::AudioLog { | 114 class AudioLogImpl : public media::AudioLog { |
| 101 public: | 115 public: |
| 102 AudioLogImpl(int owner_id, | 116 AudioLogImpl(int owner_id, |
| (...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 294 base::TimeDelta all_watch_time = media::kNoTimestamp; | 308 base::TimeDelta all_watch_time = media::kNoTimestamp; |
| 295 base::TimeDelta mse_watch_time = media::kNoTimestamp; | 309 base::TimeDelta mse_watch_time = media::kNoTimestamp; |
| 296 base::TimeDelta eme_watch_time = media::kNoTimestamp; | 310 base::TimeDelta eme_watch_time = media::kNoTimestamp; |
| 297 base::TimeDelta src_watch_time = media::kNoTimestamp; | 311 base::TimeDelta src_watch_time = media::kNoTimestamp; |
| 298 base::TimeDelta ac_watch_time = media::kNoTimestamp; | 312 base::TimeDelta ac_watch_time = media::kNoTimestamp; |
| 299 base::TimeDelta battery_watch_time = media::kNoTimestamp; | 313 base::TimeDelta battery_watch_time = media::kNoTimestamp; |
| 300 base::TimeDelta embedded_experience_watch_time = media::kNoTimestamp; | 314 base::TimeDelta embedded_experience_watch_time = media::kNoTimestamp; |
| 301 }; | 315 }; |
| 302 | 316 |
| 303 struct PipelineInfo { | 317 struct PipelineInfo { |
| 318 explicit PipelineInfo(bool is_incognito) : is_incognito(is_incognito) {} | |
| 319 | |
| 304 bool has_pipeline = false; | 320 bool has_pipeline = false; |
| 305 bool has_ever_played = false; | 321 bool has_ever_played = false; |
| 306 bool has_reached_have_enough = false; | 322 bool has_reached_have_enough = false; |
| 307 media::PipelineStatus last_pipeline_status = media::PIPELINE_OK; | 323 media::PipelineStatus last_pipeline_status = media::PIPELINE_OK; |
| 308 bool has_audio = false; | 324 bool has_audio = false; |
| 309 bool has_video = false; | 325 bool has_video = false; |
| 310 bool video_dds = false; | 326 bool video_dds = false; |
| 311 bool video_decoder_changed = false; | 327 bool video_decoder_changed = false; |
| 328 bool has_cdm = false; | |
| 329 bool is_incognito = false; | |
| 312 std::string audio_codec_name; | 330 std::string audio_codec_name; |
| 313 std::string video_codec_name; | 331 std::string video_codec_name; |
| 314 std::string video_decoder; | 332 std::string video_decoder; |
| 315 WatchTimeInfo watch_time_info; | 333 WatchTimeInfo watch_time_info; |
| 316 }; | 334 }; |
| 317 | 335 |
| 318 // Helper function to report PipelineStatus associated with a player to UMA. | 336 // Helper function to report PipelineStatus associated with a player to UMA. |
| 319 void ReportUMAForPipelineStatus(const PipelineInfo& player_info); | 337 void ReportUMAForPipelineStatus(const PipelineInfo& player_info); |
| 320 | 338 |
| 321 // Helper to generate PipelineStatus UMA name for AudioVideo streams. | 339 // Helper to generate PipelineStatus UMA name for AudioVideo streams. |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 395 DISALLOW_COPY_AND_ASSIGN(MediaInternalsUMAHandler); | 413 DISALLOW_COPY_AND_ASSIGN(MediaInternalsUMAHandler); |
| 396 }; | 414 }; |
| 397 | 415 |
| 398 MediaInternals::MediaInternalsUMAHandler::MediaInternalsUMAHandler() { | 416 MediaInternals::MediaInternalsUMAHandler::MediaInternalsUMAHandler() { |
| 399 } | 417 } |
| 400 | 418 |
| 401 void MediaInternals::MediaInternalsUMAHandler::SavePlayerState( | 419 void MediaInternals::MediaInternalsUMAHandler::SavePlayerState( |
| 402 int render_process_id, | 420 int render_process_id, |
| 403 const media::MediaLogEvent& event) { | 421 const media::MediaLogEvent& event) { |
| 404 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 422 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 405 PlayerInfoMap& player_info = renderer_info_[render_process_id]; | 423 |
| 424 PlayerInfoMap& player_info_map = renderer_info_[render_process_id]; | |
| 425 | |
| 426 auto it = player_info_map.find(event.id); | |
| 427 if (it == player_info_map.end()) { | |
| 428 bool success = false; | |
| 429 std::tie(it, success) = player_info_map.emplace( | |
| 430 std::make_pair(event.id, PipelineInfo(IsIncognito(render_process_id)))); | |
| 431 if (!success) { | |
| 432 LOG(ERROR) << "Failed to insert a new PipelineInfo."; | |
| 433 return; | |
| 434 } | |
| 435 } | |
| 436 | |
| 437 PipelineInfo& player_info = it->second; | |
| 438 | |
| 406 switch (event.type) { | 439 switch (event.type) { |
| 407 case media::MediaLogEvent::PLAY: { | 440 case media::MediaLogEvent::PLAY: { |
| 408 player_info[event.id].has_ever_played = true; | 441 player_info.has_ever_played = true; |
| 409 break; | 442 break; |
| 410 } | 443 } |
| 411 case media::MediaLogEvent::PIPELINE_STATE_CHANGED: { | 444 case media::MediaLogEvent::PIPELINE_STATE_CHANGED: { |
| 412 player_info[event.id].has_pipeline = true; | 445 player_info.has_pipeline = true; |
| 413 break; | 446 break; |
| 414 } | 447 } |
| 415 case media::MediaLogEvent::PIPELINE_ERROR: { | 448 case media::MediaLogEvent::PIPELINE_ERROR: { |
| 416 int status; | 449 int status; |
| 417 event.params.GetInteger("pipeline_error", &status); | 450 event.params.GetInteger("pipeline_error", &status); |
| 418 player_info[event.id].last_pipeline_status = | 451 player_info.last_pipeline_status = |
| 419 static_cast<media::PipelineStatus>(status); | 452 static_cast<media::PipelineStatus>(status); |
| 420 break; | 453 break; |
| 421 } | 454 } |
| 422 case media::MediaLogEvent::PROPERTY_CHANGE: | 455 case media::MediaLogEvent::PROPERTY_CHANGE: |
| 423 if (event.params.HasKey("found_audio_stream")) { | 456 if (event.params.HasKey("found_audio_stream")) { |
| 424 event.params.GetBoolean("found_audio_stream", | 457 event.params.GetBoolean("found_audio_stream", &player_info.has_audio); |
| 425 &player_info[event.id].has_audio); | |
| 426 } | 458 } |
| 427 if (event.params.HasKey("found_video_stream")) { | 459 if (event.params.HasKey("found_video_stream")) { |
| 428 event.params.GetBoolean("found_video_stream", | 460 event.params.GetBoolean("found_video_stream", &player_info.has_video); |
| 429 &player_info[event.id].has_video); | |
| 430 } | 461 } |
| 431 if (event.params.HasKey("audio_codec_name")) { | 462 if (event.params.HasKey("audio_codec_name")) { |
| 432 event.params.GetString("audio_codec_name", | 463 event.params.GetString("audio_codec_name", |
| 433 &player_info[event.id].audio_codec_name); | 464 &player_info.audio_codec_name); |
| 434 } | 465 } |
| 435 if (event.params.HasKey("video_codec_name")) { | 466 if (event.params.HasKey("video_codec_name")) { |
| 436 event.params.GetString("video_codec_name", | 467 event.params.GetString("video_codec_name", |
| 437 &player_info[event.id].video_codec_name); | 468 &player_info.video_codec_name); |
| 438 } | 469 } |
| 439 if (event.params.HasKey("video_decoder")) { | 470 if (event.params.HasKey("video_decoder")) { |
| 440 std::string previous_video_decoder(player_info[event.id].video_decoder); | 471 std::string previous_video_decoder(player_info.video_decoder); |
| 441 event.params.GetString("video_decoder", | 472 event.params.GetString("video_decoder", &player_info.video_decoder); |
| 442 &player_info[event.id].video_decoder); | |
| 443 if (!previous_video_decoder.empty() && | 473 if (!previous_video_decoder.empty() && |
| 444 previous_video_decoder != player_info[event.id].video_decoder) { | 474 previous_video_decoder != player_info.video_decoder) { |
| 445 player_info[event.id].video_decoder_changed = true; | 475 player_info.video_decoder_changed = true; |
| 446 } | 476 } |
| 447 } | 477 } |
| 448 if (event.params.HasKey("video_dds")) { | 478 if (event.params.HasKey("video_dds")) { |
| 449 event.params.GetBoolean("video_dds", &player_info[event.id].video_dds); | 479 event.params.GetBoolean("video_dds", &player_info.video_dds); |
| 480 } | |
| 481 if (event.params.HasKey("has_cdm")) { | |
| 482 event.params.GetBoolean("has_cdm", &player_info.has_cdm); | |
| 450 } | 483 } |
| 451 if (event.params.HasKey("pipeline_buffering_state")) { | 484 if (event.params.HasKey("pipeline_buffering_state")) { |
| 452 std::string buffering_state; | 485 std::string buffering_state; |
| 453 event.params.GetString("pipeline_buffering_state", &buffering_state); | 486 event.params.GetString("pipeline_buffering_state", &buffering_state); |
| 454 if (buffering_state == "BUFFERING_HAVE_ENOUGH") | 487 if (buffering_state == "BUFFERING_HAVE_ENOUGH") |
| 455 player_info[event.id].has_reached_have_enough = true; | 488 player_info.has_reached_have_enough = true; |
| 456 } | 489 } |
| 457 break; | 490 break; |
| 458 case media::MediaLogEvent::Type::WATCH_TIME_UPDATE: { | 491 case media::MediaLogEvent::Type::WATCH_TIME_UPDATE: { |
| 459 DVLOG(2) << "Processing watch time update."; | 492 DVLOG(2) << "Processing watch time update."; |
| 460 PipelineInfo& info = player_info[event.id]; | 493 WatchTimeInfo& wti = player_info.watch_time_info; |
| 461 WatchTimeInfo& wti = info.watch_time_info; | |
| 462 // Save audio only watch time information. | 494 // Save audio only watch time information. |
| 463 MaybeSaveWatchTime(event, media::MediaLog::kWatchTimeAudioAll, | 495 MaybeSaveWatchTime(event, media::MediaLog::kWatchTimeAudioAll, |
| 464 &wti.all_watch_time); | 496 &wti.all_watch_time); |
| 465 MaybeSaveWatchTime(event, media::MediaLog::kWatchTimeAudioMse, | 497 MaybeSaveWatchTime(event, media::MediaLog::kWatchTimeAudioMse, |
| 466 &wti.mse_watch_time); | 498 &wti.mse_watch_time); |
| 467 MaybeSaveWatchTime(event, media::MediaLog::kWatchTimeAudioEme, | 499 MaybeSaveWatchTime(event, media::MediaLog::kWatchTimeAudioEme, |
| 468 &wti.eme_watch_time); | 500 &wti.eme_watch_time); |
| 469 MaybeSaveWatchTime(event, media::MediaLog::kWatchTimeAudioSrc, | 501 MaybeSaveWatchTime(event, media::MediaLog::kWatchTimeAudioSrc, |
| 470 &wti.src_watch_time); | 502 &wti.src_watch_time); |
| 471 MaybeSaveWatchTime(event, media::MediaLog::kWatchTimeAudioBattery, | 503 MaybeSaveWatchTime(event, media::MediaLog::kWatchTimeAudioBattery, |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 491 &wti.ac_watch_time); | 523 &wti.ac_watch_time); |
| 492 MaybeSaveWatchTime( | 524 MaybeSaveWatchTime( |
| 493 event, media::MediaLog::kWatchTimeAudioVideoEmbeddedExperience, | 525 event, media::MediaLog::kWatchTimeAudioVideoEmbeddedExperience, |
| 494 &wti.embedded_experience_watch_time); | 526 &wti.embedded_experience_watch_time); |
| 495 | 527 |
| 496 if (event.params.HasKey(media::MediaLog::kWatchTimeFinalize)) { | 528 if (event.params.HasKey(media::MediaLog::kWatchTimeFinalize)) { |
| 497 bool should_finalize; | 529 bool should_finalize; |
| 498 DCHECK(event.params.GetBoolean(media::MediaLog::kWatchTimeFinalize, | 530 DCHECK(event.params.GetBoolean(media::MediaLog::kWatchTimeFinalize, |
| 499 &should_finalize) && | 531 &should_finalize) && |
| 500 should_finalize); | 532 should_finalize); |
| 501 FinalizeWatchTime(info.has_video, &wti, FinalizeType::EVERYTHING); | 533 FinalizeWatchTime(player_info.has_video, &wti, |
| 534 FinalizeType::EVERYTHING); | |
| 502 } else if (event.params.HasKey( | 535 } else if (event.params.HasKey( |
| 503 media::MediaLog::kWatchTimeFinalizePower)) { | 536 media::MediaLog::kWatchTimeFinalizePower)) { |
| 504 bool should_finalize; | 537 bool should_finalize; |
| 505 DCHECK(event.params.GetBoolean(media::MediaLog::kWatchTimeFinalizePower, | 538 DCHECK(event.params.GetBoolean(media::MediaLog::kWatchTimeFinalizePower, |
| 506 &should_finalize) && | 539 &should_finalize) && |
| 507 should_finalize); | 540 should_finalize); |
| 508 FinalizeWatchTime(info.has_video, &wti, FinalizeType::POWER_ONLY); | 541 FinalizeWatchTime(player_info.has_video, &wti, |
| 542 FinalizeType::POWER_ONLY); | |
| 509 } | 543 } |
| 510 break; | 544 break; |
| 511 } | 545 } |
| 512 case media::MediaLogEvent::Type::WEBMEDIAPLAYER_DESTROYED: { | 546 case media::MediaLogEvent::Type::WEBMEDIAPLAYER_DESTROYED: { |
| 513 // Upon player destruction report UMA data; if the player is not torn down | 547 // Upon player destruction report UMA data; if the player is not torn down |
| 514 // before process exit, it will be logged during OnProcessTerminated(). | 548 // before process exit, it will be logged during OnProcessTerminated(). |
| 515 auto it = player_info.find(event.id); | 549 auto it = player_info_map.find(event.id); |
| 516 if (it == player_info.end()) | 550 if (it == player_info_map.end()) |
| 517 break; | 551 break; |
| 518 | 552 |
| 519 ReportUMAForPipelineStatus(it->second); | 553 ReportUMAForPipelineStatus(it->second); |
| 520 player_info.erase(it); | 554 player_info_map.erase(it); |
| 521 } | 555 } |
| 522 default: | 556 default: |
| 523 break; | 557 break; |
| 524 } | 558 } |
| 525 return; | 559 return; |
| 526 } | 560 } |
| 527 | 561 |
| 528 std::string MediaInternals::MediaInternalsUMAHandler::GetUMANameForAVStream( | 562 std::string MediaInternals::MediaInternalsUMAHandler::GetUMANameForAVStream( |
| 529 const PipelineInfo& player_info) { | 563 const PipelineInfo& player_info) { |
| 530 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 564 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 552 } | 586 } |
| 553 | 587 |
| 554 if (player_info.video_decoder == media::GpuVideoDecoder::kDecoderName) { | 588 if (player_info.video_decoder == media::GpuVideoDecoder::kDecoderName) { |
| 555 uma_name += "HW"; | 589 uma_name += "HW"; |
| 556 } else { | 590 } else { |
| 557 uma_name += "SW"; | 591 uma_name += "SW"; |
| 558 } | 592 } |
| 559 return uma_name; | 593 return uma_name; |
| 560 } | 594 } |
| 561 | 595 |
| 562 void MediaInternals::MediaInternalsUMAHandler::ReportUMAForPipelineStatus( | 596 void MediaInternals::MediaInternalsUMAHandler::ReportUMAForPipelineStatus( |
|
ddorwin
2017/04/13 16:52:59
This function name does not make it clear that it
xhwang
2017/04/13 22:36:34
Added a TODO.
| |
| 563 const PipelineInfo& player_info) { | 597 const PipelineInfo& player_info) { |
| 564 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 598 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 565 | 599 |
| 566 // Don't log pipeline status for players which don't actually have a pipeline; | 600 // Don't log pipeline status for players which don't actually have a pipeline; |
| 567 // e.g., the Android MediaSourcePlayer implementation. | 601 // e.g., the Android MediaSourcePlayer implementation. |
| 568 if (!player_info.has_pipeline) | 602 if (!player_info.has_pipeline) |
| 569 return; | 603 return; |
| 570 | 604 |
| 571 if (player_info.has_video && player_info.has_audio) { | 605 if (player_info.has_video && player_info.has_audio) { |
| 572 base::LinearHistogram::FactoryGet( | 606 base::LinearHistogram::FactoryGet( |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 592 } | 626 } |
| 593 // Report whether video decoder fallback happened, but only if a video decoder | 627 // Report whether video decoder fallback happened, but only if a video decoder |
| 594 // was reported. | 628 // was reported. |
| 595 if (!player_info.video_decoder.empty()) { | 629 if (!player_info.video_decoder.empty()) { |
| 596 UMA_HISTOGRAM_BOOLEAN("Media.VideoDecoderFallback", | 630 UMA_HISTOGRAM_BOOLEAN("Media.VideoDecoderFallback", |
| 597 player_info.video_decoder_changed); | 631 player_info.video_decoder_changed); |
| 598 } | 632 } |
| 599 | 633 |
| 600 // Report whether this player ever saw a playback event. Used to measure the | 634 // Report whether this player ever saw a playback event. Used to measure the |
| 601 // effectiveness of efforts to reduce loaded-but-never-used players. | 635 // effectiveness of efforts to reduce loaded-but-never-used players. |
| 602 if (player_info.has_reached_have_enough) | 636 if (player_info.has_reached_have_enough) { |
| 603 UMA_HISTOGRAM_BOOLEAN("Media.HasEverPlayed", player_info.has_ever_played); | 637 UMA_HISTOGRAM_BOOLEAN("Media.HasEverPlayed", player_info.has_ever_played); |
| 638 } | |
| 639 | |
| 640 // Report whether an encrypted playback is in incognito window, excluding | |
|
ddorwin
2017/04/13 16:52:59
Once we have data, we should compare the `false` n
xhwang
2017/04/13 22:36:34
Acknowledged.
| |
| 641 // loaded-but-never-used players. | |
| 642 if (player_info.has_cdm && player_info.has_reached_have_enough) | |
|
DaleCurtis
2017/04/12 21:38:19
Needs && player_info.has_ever_played.
xhwang
2017/04/13 22:36:34
Done.
| |
| 643 UMA_HISTOGRAM_BOOLEAN("Media.EME.IsIncognito", player_info.is_incognito); | |
| 604 } | 644 } |
| 605 | 645 |
| 606 void MediaInternals::MediaInternalsUMAHandler::OnProcessTerminated( | 646 void MediaInternals::MediaInternalsUMAHandler::OnProcessTerminated( |
| 607 int render_process_id) { | 647 int render_process_id) { |
| 608 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 648 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 609 | 649 |
| 610 auto players_it = renderer_info_.find(render_process_id); | 650 auto players_it = renderer_info_.find(render_process_id); |
| 611 if (players_it == renderer_info_.end()) | 651 if (players_it == renderer_info_.end()) |
| 612 return; | 652 return; |
| 613 auto it = players_it->second.begin(); | 653 auto it = players_it->second.begin(); |
| (...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 872 audio_streams_cached_data_.GetDictionary(cache_key, &existing_dict)); | 912 audio_streams_cached_data_.GetDictionary(cache_key, &existing_dict)); |
| 873 existing_dict->MergeDictionary(value); | 913 existing_dict->MergeDictionary(value); |
| 874 } | 914 } |
| 875 } | 915 } |
| 876 | 916 |
| 877 if (CanUpdate()) | 917 if (CanUpdate()) |
| 878 SendUpdate(SerializeUpdate(function, value)); | 918 SendUpdate(SerializeUpdate(function, value)); |
| 879 } | 919 } |
| 880 | 920 |
| 881 } // namespace content | 921 } // namespace content |
| OLD | NEW |