15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/media/media_stream_capture_indicator.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/i18n/rtl.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/memory/scoped_ptr.h" 11c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/prefs/pref_service.h" 12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/app/chrome_command_ids.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/browser_process.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/status_icons/status_icon.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/status_icons/status_tray.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/tab_contents/tab_util.h" 19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/common/pref_names.h" 2003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "chrome/grit/chromium_strings.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/content_browser_client.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/invalidate_type.h" 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/web_contents.h" 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/web_contents_delegate.h" 262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/web_contents_observer.h" 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/theme_resources.h" 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_util.h" 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h" 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/resource/resource_bundle.h" 312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/gfx/image/image_skia.h" 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 33116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#if defined(ENABLE_EXTENSIONS) 34116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "chrome/common/extensions/extension_constants.h" 35116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "extensions/browser/extension_registry.h" 36116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "extensions/common/extension.h" 37116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#endif 38116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread; 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::WebContents; 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 44116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#if defined(ENABLE_EXTENSIONS) 452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const extensions::Extension* GetExtension(WebContents* web_contents) { 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!web_contents) 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 51116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch extensions::ExtensionRegistry* registry = 52116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch extensions::ExtensionRegistry::Get(web_contents->GetBrowserContext()); 53116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return registry->enabled_extensions().GetExtensionOrAppByURL( 54ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch web_contents->GetURL()); 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 575c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liubool IsWhitelistedExtension(const extensions::Extension* extension) { 585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 605c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu static const char* const kExtensionWhitelist[] = { 615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu extension_misc::kHotwordExtensionId, 625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu }; 635c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 645c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu for (size_t i = 0; i < arraysize(kExtensionWhitelist); ++i) { 655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (extension->id() == kExtensionWhitelist[i]) 665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return true; 675c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 685c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 695c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return false; 705c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 71116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#endif // defined(ENABLE_EXTENSIONS) 725c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Gets the security originator of the tab. It returns a string with no '/' 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// at the end to display in the UI. 755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)base::string16 GetSecurityOrigin(WebContents* web_contents) { 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!web_contents) 79a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return base::string16(); 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string security_origin = web_contents->GetURL().GetOrigin().spec(); 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Remove the last character if it is a '/'. 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!security_origin.empty()) { 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string::iterator it = security_origin.end() - 1; 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (*it == '/') 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) security_origin.erase(it); 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return base::UTF8ToUTF16(security_origin); 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)base::string16 GetTitle(WebContents* web_contents) { 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!web_contents) 97a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return base::string16(); 982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 99116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#if defined(ENABLE_EXTENSIONS) 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const extensions::Extension* const extension = GetExtension(web_contents); 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (extension) 1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return base::UTF8ToUTF16(extension->name()); 103116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#endif 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 105a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16 tab_title = web_contents->GetTitle(); 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (tab_title.empty()) { 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the page's title is empty use its security originator. 1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) tab_title = GetSecurityOrigin(web_contents); 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the page's title matches its URL, use its security originator. 112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) Profile* profile = 113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) Profile::FromBrowserContext(web_contents->GetBrowserContext()); 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string languages = 115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) profile->GetPrefs()->GetString(prefs::kAcceptLanguages); 1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (tab_title == net::FormatUrl(web_contents->GetURL(), languages)) 1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) tab_title = GetSecurityOrigin(web_contents); 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return tab_title; 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Stores usage counts for all the capture devices associated with a single 126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// WebContents instance. Instances of this class are owned by 127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// MediaStreamCaptureIndicator. They also observe for the destruction of the 128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// WebContents instances and delete themselves when corresponding WebContents is 129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// deleted. 1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class MediaStreamCaptureIndicator::WebContentsDeviceUsage 131c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) : public content::WebContentsObserver { 1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public: 133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) explicit WebContentsDeviceUsage( 134c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) scoped_refptr<MediaStreamCaptureIndicator> indicator, 135c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) WebContents* web_contents) 136c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) : WebContentsObserver(web_contents), 137c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) indicator_(indicator), 138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) audio_ref_count_(0), 139c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) video_ref_count_(0), 140c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) mirroring_ref_count_(0), 141c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) weak_factory_(this) { 142c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool IsCapturingAudio() const { return audio_ref_count_ > 0; } 1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool IsCapturingVideo() const { return video_ref_count_ > 0; } 1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool IsMirroring() const { return mirroring_ref_count_ > 0; } 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 148c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) scoped_ptr<content::MediaStreamUI> RegisterMediaStream( 149c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const content::MediaStreamDevices& devices); 150c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 1517d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) // Increment ref-counts up based on the type of each device provided. 1523240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch void AddDevices(const content::MediaStreamDevices& devices); 1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Decrement ref-counts up based on the type of each device provided. 1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void RemoveDevices(const content::MediaStreamDevices& devices); 1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private: 158c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // content::WebContentsObserver overrides. 159010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) virtual void WebContentsDestroyed() OVERRIDE { 160010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) indicator_->UnregisterWebContents(web_contents()); 161c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) delete this; 162c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 163c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 164c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) scoped_refptr<MediaStreamCaptureIndicator> indicator_; 1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int audio_ref_count_; 1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int video_ref_count_; 1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int mirroring_ref_count_; 1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 169c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::WeakPtrFactory<WebContentsDeviceUsage> weak_factory_; 170c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(WebContentsDeviceUsage); 1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 174c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Implements MediaStreamUI interface. Instances of this class are created for 175c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// each MediaStream and their ownership is passed to MediaStream implementation 176c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// in the content layer. Each UIDelegate keeps a weak pointer to the 177c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// corresponding WebContentsDeviceUsage object to deliver updates about state of 178c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// the stream. 179c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)class MediaStreamCaptureIndicator::UIDelegate 180c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) : public content::MediaStreamUI { 181c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) public: 182c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) UIDelegate(base::WeakPtr<WebContentsDeviceUsage> device_usage, 183c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const content::MediaStreamDevices& devices) 184c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) : device_usage_(device_usage), 185c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) devices_(devices), 186c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) started_(false) { 187c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK(!devices_.empty()); 188c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 189c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 190c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) virtual ~UIDelegate() { 191868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (started_ && device_usage_.get()) 192c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) device_usage_->RemoveDevices(devices_); 193c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 194c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 195c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) private: 196c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // content::MediaStreamUI interface. 197effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch virtual gfx::NativeViewId OnStarted(const base::Closure& close_callback) 198effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch OVERRIDE { 199c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK(!started_); 200c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) started_ = true; 201868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (device_usage_.get()) 2023240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch device_usage_->AddDevices(devices_); 203effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch return 0; 204c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 205c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 206c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::WeakPtr<WebContentsDeviceUsage> device_usage_; 207c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) content::MediaStreamDevices devices_; 208c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) bool started_; 209c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 210c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(UIDelegate); 211c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}; 212c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 213c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 214c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)scoped_ptr<content::MediaStreamUI> 215c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)MediaStreamCaptureIndicator::WebContentsDeviceUsage::RegisterMediaStream( 216c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const content::MediaStreamDevices& devices) { 217c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return scoped_ptr<content::MediaStreamUI>(new UIDelegate( 218c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) weak_factory_.GetWeakPtr(), devices)); 2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 221c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void MediaStreamCaptureIndicator::WebContentsDeviceUsage::AddDevices( 2223240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch const content::MediaStreamDevices& devices) { 2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (content::MediaStreamDevices::const_iterator it = devices.begin(); 2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) it != devices.end(); ++it) { 2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (it->type == content::MEDIA_TAB_AUDIO_CAPTURE || 2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) it->type == content::MEDIA_TAB_VIDEO_CAPTURE) { 2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ++mirroring_ref_count_; 22846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) } else if (content::IsAudioInputMediaType(it->type)) { 2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ++audio_ref_count_; 2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else if (content::IsVideoMediaType(it->type)) { 2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ++video_ref_count_; 2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NOTIMPLEMENTED(); 2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 237c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (web_contents()) 238c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) web_contents()->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TAB); 2397d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 240c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) indicator_->UpdateNotificationUserInterface(); 2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void MediaStreamCaptureIndicator::WebContentsDeviceUsage::RemoveDevices( 2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const content::MediaStreamDevices& devices) { 2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (content::MediaStreamDevices::const_iterator it = devices.begin(); 2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) it != devices.end(); ++it) { 2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (it->type == content::MEDIA_TAB_AUDIO_CAPTURE || 2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) it->type == content::MEDIA_TAB_VIDEO_CAPTURE) { 2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) --mirroring_ref_count_; 25046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) } else if (content::IsAudioInputMediaType(it->type)) { 2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) --audio_ref_count_; 2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else if (content::IsVideoMediaType(it->type)) { 2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) --video_ref_count_; 2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NOTIMPLEMENTED(); 2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK_GE(audio_ref_count_, 0); 2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK_GE(video_ref_count_, 0); 2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK_GE(mirroring_ref_count_, 0); 262c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 263c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) web_contents()->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TAB); 264c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) indicator_->UpdateNotificationUserInterface(); 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MediaStreamCaptureIndicator::MediaStreamCaptureIndicator() 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : status_icon_(NULL), 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mic_image_(NULL), 2707d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) camera_image_(NULL) { 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MediaStreamCaptureIndicator::~MediaStreamCaptureIndicator() { 2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The user is responsible for cleaning up by reporting the closure of any 2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // opened devices. However, there exists a race condition at shutdown: The UI 2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // thread may be stopped before CaptureDevicesClosed() posts the task to 2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // invoke DoDevicesClosedOnUIThread(). In this case, usage_map_ won't be 2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // empty like it should. 2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(usage_map_.empty() || 2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) !BrowserThread::IsMessageLoopValid(BrowserThread::UI)); 2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Free any WebContentsDeviceUsage objects left over. 2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (UsageMap::const_iterator it = usage_map_.begin(); it != usage_map_.end(); 2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ++it) { 2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) delete it->second; 2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 289c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)scoped_ptr<content::MediaStreamUI> 290c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)MediaStreamCaptureIndicator::RegisterMediaStream( 291c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) content::WebContents* web_contents, 292c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const content::MediaStreamDevices& devices) { 293c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) WebContentsDeviceUsage*& usage = usage_map_[web_contents]; 294c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!usage) 295c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) usage = new WebContentsDeviceUsage(this, web_contents); 296c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return usage->RegisterMediaStream(devices); 297c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 298c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void MediaStreamCaptureIndicator::ExecuteCommand(int command_id, 3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int event_flags) { 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const int index = 3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) command_id - IDC_MEDIA_CONTEXT_MEDIA_STREAM_CAPTURE_LIST_FIRST; 3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK_LE(0, index); 3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK_GT(static_cast<int>(command_targets_.size()), index); 3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) WebContents* const web_contents = command_targets_[index]; 3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) UsageMap::const_iterator it = usage_map_.find(web_contents); 309c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (it == usage_map_.end()) 3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) web_contents->GetDelegate()->ActivateContents(web_contents); 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool MediaStreamCaptureIndicator::IsCapturingUserMedia( 315c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) content::WebContents* web_contents) const { 3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) UsageMap::const_iterator it = usage_map_.find(web_contents); 3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return (it != usage_map_.end() && 3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) (it->second->IsCapturingAudio() || it->second->IsCapturingVideo())); 3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3237d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)bool MediaStreamCaptureIndicator::IsCapturingVideo( 3247d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) content::WebContents* web_contents) const { 3257d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 3267d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 3277d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) UsageMap::const_iterator it = usage_map_.find(web_contents); 3287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) return (it != usage_map_.end() && it->second->IsCapturingVideo()); 3297d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 3307d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 3317d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)bool MediaStreamCaptureIndicator::IsCapturingAudio( 3327d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) content::WebContents* web_contents) const { 3337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 3347d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 3357d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) UsageMap::const_iterator it = usage_map_.find(web_contents); 3367d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) return (it != usage_map_.end() && it->second->IsCapturingAudio()); 3377d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 3387d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool MediaStreamCaptureIndicator::IsBeingMirrored( 340c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) content::WebContents* web_contents) const { 3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) UsageMap::const_iterator it = usage_map_.find(web_contents); 3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return it != usage_map_.end() && it->second->IsMirroring(); 3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 347c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void MediaStreamCaptureIndicator::UnregisterWebContents( 348c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) WebContents* web_contents) { 349c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) usage_map_.erase(web_contents); 350c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) UpdateNotificationUserInterface(); 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 353a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void MediaStreamCaptureIndicator::MaybeCreateStatusTrayIcon(bool audio, 354a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) bool video) { 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (status_icon_) 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If there is no browser process, we should not create the status tray. 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!g_browser_process) 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StatusTray* status_tray = g_browser_process->status_tray(); 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!status_tray) 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EnsureStatusTrayIconResources(); 368a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 369a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) gfx::ImageSkia image; 370a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16 tool_tip; 371a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) GetStatusTrayIconInfo(audio, video, &image, &tool_tip); 372a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) DCHECK(!image.isNull()); 373a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) DCHECK(!tool_tip.empty()); 374a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 375a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) status_icon_ = status_tray->CreateStatusIcon( 376a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) StatusTray::MEDIA_STREAM_CAPTURE_ICON, image, tool_tip); 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MediaStreamCaptureIndicator::EnsureStatusTrayIconResources() { 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!mic_image_) { 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mic_image_ = ResourceBundle::GetSharedInstance().GetImageSkiaNamed( 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IDR_INFOBAR_MEDIA_STREAM_MIC); 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!camera_image_) { 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) camera_image_ = ResourceBundle::GetSharedInstance().GetImageSkiaNamed( 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IDR_INFOBAR_MEDIA_STREAM_CAMERA); 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(mic_image_); 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(camera_image_); 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void MediaStreamCaptureIndicator::MaybeDestroyStatusTrayIcon() { 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!status_icon_) 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If there is no browser process, we should not do anything. 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!g_browser_process) 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StatusTray* status_tray = g_browser_process->status_tray(); 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (status_tray != NULL) { 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) status_tray->RemoveStatusIcon(status_icon_); 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) status_icon_ = NULL; 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void MediaStreamCaptureIndicator::UpdateNotificationUserInterface() { 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 412424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) scoped_ptr<StatusIconMenuModel> menu(new StatusIconMenuModel(this)); 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool audio = false; 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool video = false; 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int command_id = IDC_MEDIA_CONTEXT_MEDIA_STREAM_CAPTURE_LIST_FIRST; 4172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) command_targets_.clear(); 4182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (UsageMap::const_iterator iter = usage_map_.begin(); 4202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) iter != usage_map_.end(); ++iter) { 4212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Check if any audio and video devices have been used. 4222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const WebContentsDeviceUsage& usage = *iter->second; 4235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (!usage.IsCapturingAudio() && !usage.IsCapturingVideo()) 4245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu continue; 4255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 4262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) WebContents* const web_contents = iter->first; 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // The audio/video icon is shown only for non-whitelisted extensions or on 4295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Android. For regular tabs on desktop, we show an indicator in the tab 4305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // icon. 431116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#if defined(ENABLE_EXTENSIONS) 4325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu const extensions::Extension* extension = GetExtension(web_contents); 4335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (!extension || IsWhitelistedExtension(extension)) 4345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu continue; 435c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#endif 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4375c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu audio = audio || usage.IsCapturingAudio(); 4385c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu video = video || usage.IsCapturingVideo(); 4392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu command_targets_.push_back(web_contents); 4415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu menu->AddItem(command_id, GetTitle(web_contents)); 442424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 4435c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // If the menu item is not a label, enable it. 4445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu menu->SetCommandIdEnabled(command_id, 4455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu command_id != IDC_MinimumLabelValue); 4465c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 4475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // If reaching the maximum number, no more item will be added to the menu. 4485c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (command_id == IDC_MEDIA_CONTEXT_MEDIA_STREAM_CAPTURE_LIST_LAST) 4495c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu break; 4505c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu ++command_id; 4512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (command_targets_.empty()) { 4542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) MaybeDestroyStatusTrayIcon(); 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The icon will take the ownership of the passed context menu. 459a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) MaybeCreateStatusTrayIcon(audio, video); 4602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (status_icon_) { 461424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) status_icon_->SetContextMenu(menu.Pass()); 4622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 465a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void MediaStreamCaptureIndicator::GetStatusTrayIconInfo( 466a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) bool audio, 467a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) bool video, 468a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) gfx::ImageSkia* image, 469a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16* tool_tip) { 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(audio || video); 472a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int message_id = 0; 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (audio && video) { 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) message_id = IDS_MEDIA_STREAM_STATUS_TRAY_TEXT_AUDIO_AND_VIDEO; 476a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) *image = *camera_image_; 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (audio && !video) { 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) message_id = IDS_MEDIA_STREAM_STATUS_TRAY_TEXT_AUDIO_ONLY; 479a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) *image = *mic_image_; 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (!audio && video) { 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) message_id = IDS_MEDIA_STREAM_STATUS_TRAY_TEXT_VIDEO_ONLY; 482a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) *image = *camera_image_; 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 485a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) *tool_tip = l10n_util::GetStringUTF16(message_id); 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 487