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 "chrome/browser/ui/tabs/tab_utils.h" | 5 #include "chrome/browser/ui/tabs/tab_utils.h" |
| 6 | 6 |
| 7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
| 8 #include "base/strings/string16.h" | 8 #include "base/strings/string16.h" |
| 9 #include "chrome/browser/media/media_capture_devices_dispatcher.h" | 9 #include "chrome/browser/media/media_capture_devices_dispatcher.h" |
| 10 #include "chrome/browser/media/media_stream_capture_indicator.h" | 10 #include "chrome/browser/media/media_stream_capture_indicator.h" |
| 11 #include "chrome/browser/ui/tabs/tab_strip_model.h" | 11 #include "chrome/browser/ui/tabs/tab_strip_model.h" |
| 12 #include "chrome/common/chrome_switches.h" | 12 #include "chrome/common/chrome_switches.h" |
| 13 #include "chrome/grit/generated_resources.h" | 13 #include "chrome/grit/generated_resources.h" |
| 14 #include "content/public/browser/web_contents.h" | 14 #include "content/public/browser/web_contents.h" |
| 15 #include "grit/theme_resources.h" | 15 #include "grit/theme_resources.h" |
| 16 #include "ui/base/l10n/l10n_util.h" | 16 #include "ui/base/l10n/l10n_util.h" |
| 17 #include "ui/base/resource/resource_bundle.h" | 17 #include "ui/base/resource/resource_bundle.h" |
| 18 #include "ui/gfx/animation/multi_animation.h" | 18 #include "ui/gfx/animation/multi_animation.h" |
| 19 | 19 |
| 20 struct LastMuteMetadata | 20 struct MuteMetadata : public content::WebContentsUserData<MuteMetadata> { |
| 21 : public content::WebContentsUserData<LastMuteMetadata> { | |
| 22 std::string cause; // Extension ID or constant from header file | 21 std::string cause; // Extension ID or constant from header file |
| 23 // or empty string | 22 // or empty string |
| 23 chrome::MuteTokenBucketInfoMap cause_info; | |
| 24 | |
| 24 private: | 25 private: |
| 25 explicit LastMuteMetadata(content::WebContents* contents) {} | 26 explicit MuteMetadata(content::WebContents* contents) {} |
| 26 friend class content::WebContentsUserData<LastMuteMetadata>; | 27 friend class content::WebContentsUserData<MuteMetadata>; |
| 27 }; | 28 }; |
| 28 | 29 |
| 29 DEFINE_WEB_CONTENTS_USER_DATA_KEY(LastMuteMetadata); | 30 DEFINE_WEB_CONTENTS_USER_DATA_KEY(MuteMetadata); |
| 30 | 31 |
| 31 namespace chrome { | 32 namespace chrome { |
| 32 | 33 |
| 33 const char kMutedToggleCauseUser[] = "user"; | 34 const char kMutedToggleCauseUser[] = "user"; |
| 34 const char kMutedToggleCauseCapture[] = "capture"; | 35 const char kMutedToggleCauseCapture[] = "capture"; |
| 35 | 36 |
| 36 namespace { | 37 namespace { |
| 37 | 38 |
| 38 // Interval between frame updates of the tab indicator animations. This is not | 39 // Interval between frame updates of the tab indicator animations. This is not |
| 39 // the usual 60 FPS because a trade-off must be made between tab UI animation | 40 // the usual 60 FPS because a trade-off must be made between tab UI animation |
| (...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 259 case TAB_MEDIA_STATE_AUDIO_MUTING: | 260 case TAB_MEDIA_STATE_AUDIO_MUTING: |
| 260 return IsTabAudioMutingFeatureEnabled(); | 261 return IsTabAudioMutingFeatureEnabled(); |
| 261 case TAB_MEDIA_STATE_RECORDING: | 262 case TAB_MEDIA_STATE_RECORDING: |
| 262 case TAB_MEDIA_STATE_CAPTURING: | 263 case TAB_MEDIA_STATE_CAPTURING: |
| 263 return false; | 264 return false; |
| 264 } | 265 } |
| 265 NOTREACHED(); | 266 NOTREACHED(); |
| 266 return false; | 267 return false; |
| 267 } | 268 } |
| 268 | 269 |
| 270 // In addition to indicating whether a request is rate limited, this also | |
| 271 // updates the rate limiting state. | |
|
miu
2015/07/15 01:45:55
Rather than having a side effect, could you just m
Jared Sohn
2015/07/15 02:33:34
Yeah, that's cleaner.
| |
| 272 bool IsTabAudioMutedRateLimited(content::WebContents* contents, | |
| 273 const std::string& cause) { | |
| 274 if (!contents) | |
| 275 return false; | |
| 276 | |
| 277 if ((cause == kMutedToggleCauseUser) || (cause == kMutedToggleCauseCapture)) | |
| 278 return false; | |
| 279 | |
| 280 MuteMetadata::CreateForWebContents(contents); // Create if not exists. | |
| 281 | |
| 282 chrome::MuteTokenBucketInfoMap mute_token_bucket_info_map = | |
| 283 MuteMetadata::FromWebContents(contents)->cause_info; | |
| 284 | |
| 285 if (mute_token_bucket_info_map.find(cause) == | |
|
miu
2015/07/15 01:45:55
I like the idea of using a token bucket here. How
Jared Sohn
2015/07/15 02:33:34
I'm okay with that.
On 2015/07/15 at 01:45:55, mi
| |
| 286 mute_token_bucket_info_map.end()) { | |
| 287 MuteMetadata::FromWebContents(contents)->cause_info[cause] = | |
| 288 linked_ptr<MuteTokenBucketInfo>(new MuteTokenBucketInfo()); | |
| 289 mute_token_bucket_info_map = | |
| 290 MuteMetadata::FromWebContents(contents)->cause_info; | |
| 291 } | |
| 292 | |
| 293 linked_ptr<MuteTokenBucketInfo> cause_info = | |
| 294 MuteMetadata::FromWebContents(contents)->cause_info[cause]; | |
| 295 | |
| 296 base::TimeTicks now = base::TimeTicks::Now(); | |
| 297 base::TimeDelta elapsed_since_last_attempt = now - cause_info->last_attempt; | |
| 298 cause_info->last_attempt = now; | |
| 299 | |
| 300 // Add tokens to the bucket, proportional to how much time has elapsed, capped | |
| 301 // at the maximum capacity. | |
| 302 cause_info->token_bucket = | |
| 303 std::min(kMuteTokenBucketCapacity, | |
| 304 cause_info->token_bucket + elapsed_since_last_attempt); | |
| 305 | |
| 306 // If we can't take kMuteTokenBucketCost seconds worth of tokens | |
| 307 // out of the bucket to "pay for this," reject the request to toggle mute. | |
| 308 if (cause_info->token_bucket < kMuteTokenBucketCost) | |
| 309 return true; // RATE LIMITED | |
| 310 | |
| 311 // Take kMuteTokenBucketCost seconds worth of tokens from the bucket | |
| 312 // and execute the toggle. | |
| 313 cause_info->token_bucket -= kMuteTokenBucketCost; | |
| 314 return false; | |
| 315 } | |
| 316 | |
| 269 const std::string& GetTabAudioMutedCause(content::WebContents* contents) { | 317 const std::string& GetTabAudioMutedCause(content::WebContents* contents) { |
| 270 LastMuteMetadata::CreateForWebContents(contents); // Create if not exists. | 318 MuteMetadata::CreateForWebContents(contents); // Create if not exists. |
| 271 if (GetTabMediaStateForContents(contents) == TAB_MEDIA_STATE_CAPTURING) { | 319 if (GetTabMediaStateForContents(contents) == TAB_MEDIA_STATE_CAPTURING) { |
| 272 // For tab capture, libcontent forces muting off. | 320 // For tab capture, libcontent forces muting off. |
| 273 LastMuteMetadata::FromWebContents(contents)->cause = | 321 MuteMetadata::FromWebContents(contents)->cause = kMutedToggleCauseCapture; |
| 274 kMutedToggleCauseCapture; | |
| 275 } | 322 } |
| 276 return LastMuteMetadata::FromWebContents(contents)->cause; | 323 return MuteMetadata::FromWebContents(contents)->cause; |
| 277 } | 324 } |
| 278 | 325 |
| 279 void SetTabAudioMuted(content::WebContents* contents, | 326 TabMutedResult SetTabAudioMuted(content::WebContents* contents, |
| 280 bool mute, | 327 bool mute, |
| 281 const std::string& cause) { | 328 const std::string& cause) { |
| 282 if (!contents || !chrome::CanToggleAudioMute(contents)) | 329 if (!IsTabAudioMutingFeatureEnabled()) |
| 283 return; | 330 return TAB_MUTED_RESULT_FAIL_NOT_ENABLED; |
| 284 | 331 |
| 285 LastMuteMetadata::CreateForWebContents(contents); // Create if not exists. | 332 if (!contents) |
|
miu
2015/07/15 01:45:55
Instead of this one, I'm thinking we should DCHECK
Jared Sohn
2015/07/15 02:33:34
I considered changing it but was concerned I might
miu
2015/07/16 00:28:25
I took a quick look at all the callers of SetTabAu
| |
| 286 LastMuteMetadata::FromWebContents(contents)->cause = cause; | 333 return TAB_MUTED_RESULT_FAIL_NO_CONTENTS; |
| 334 | |
| 335 if (!chrome::CanToggleAudioMute(contents)) | |
| 336 return TAB_MUTED_RESULT_FAIL_TABCAPTURE; | |
| 337 | |
| 338 if (IsTabAudioMutedRateLimited(contents, cause)) | |
| 339 return TAB_MUTED_RESULT_FAIL_RATE_LIMITED; | |
| 340 | |
| 341 MuteMetadata::CreateForWebContents(contents); // Create if not exists. | |
| 342 MuteMetadata::FromWebContents(contents)->cause = cause; | |
| 287 | 343 |
| 288 contents->SetAudioMuted(mute); | 344 contents->SetAudioMuted(mute); |
| 345 | |
| 346 return TAB_MUTED_RESULT_SUCCESS; | |
| 289 } | 347 } |
| 290 | 348 |
| 291 bool IsTabAudioMuted(content::WebContents* contents) { | 349 bool IsTabAudioMuted(content::WebContents* contents) { |
| 292 return contents && contents->IsAudioMuted(); | 350 return contents && contents->IsAudioMuted(); |
| 293 } | 351 } |
| 294 | 352 |
| 295 bool AreAllTabsMuted(const TabStripModel& tab_strip, | 353 bool AreAllTabsMuted(const TabStripModel& tab_strip, |
| 296 const std::vector<int>& indices) { | 354 const std::vector<int>& indices) { |
| 297 for (std::vector<int>::const_iterator i = indices.begin(); i != indices.end(); | 355 for (std::vector<int>::const_iterator i = indices.begin(); i != indices.end(); |
| 298 ++i) { | 356 ++i) { |
| 299 if (!IsTabAudioMuted(tab_strip.GetWebContentsAt(*i))) | 357 if (!IsTabAudioMuted(tab_strip.GetWebContentsAt(*i))) |
| 300 return false; | 358 return false; |
| 301 } | 359 } |
| 302 return true; | 360 return true; |
| 303 } | 361 } |
| 304 | 362 |
| 305 } // namespace chrome | 363 } // namespace chrome |
| OLD | NEW |