summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/media/media_stream_capture_indicator.cc187
-rw-r--r--chrome/browser/media/media_stream_capture_indicator.h18
-rw-r--r--content/browser/renderer_host/media/media_stream_manager.cc42
-rw-r--r--content/browser/renderer_host/media/media_stream_manager.h3
4 files changed, 178 insertions, 72 deletions
diff --git a/chrome/browser/media/media_stream_capture_indicator.cc b/chrome/browser/media/media_stream_capture_indicator.cc
index 8e18c65..710a9d8 100644
--- a/chrome/browser/media/media_stream_capture_indicator.cc
+++ b/chrome/browser/media/media_stream_capture_indicator.cc
@@ -17,6 +17,7 @@
#include "chrome/browser/status_icons/status_icon.h"
#include "chrome/browser/status_icons/status_tray.h"
#include "chrome/browser/tab_contents/tab_util.h"
+#include "chrome/browser/ui/screen_capture_notification_ui.h"
#include "chrome/common/extensions/api/icons/icons_handler.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/content_browser_client.h"
@@ -118,17 +119,26 @@ class MediaStreamCaptureIndicator::WebContentsDeviceUsage
bool IsCapturingAudio() const { return audio_ref_count_ > 0; }
bool IsCapturingVideo() const { return video_ref_count_ > 0; }
bool IsMirroring() const { return mirroring_ref_count_ > 0; }
+ bool IsCapturingScreen() const { return screen_capture_ref_count_ > 0; }
+ const base::Closure& StopScreenCaptureCallback() const {
+ return stop_screen_capture_callback_;
+ }
- // Updates ref-counts up (|direction| is true) or down by one, based on the
- // type of each device provided. In the increment-upward case, the return
- // value is the message ID for the balloon body to show, or zero if the
+ // Increment ref-counts up based on the type of each device provided. The
+ // return value is the message ID for the balloon body to show, or zero if the
// balloon should not be shown.
- int TallyUsage(const content::MediaStreamDevices& devices, bool direction);
+ int AddDevices(const content::MediaStreamDevices& devices,
+ const base::Closure& close_callback);
+
+ // Decrement ref-counts up based on the type of each device provided.
+ void RemoveDevices(const content::MediaStreamDevices& devices);
private:
int audio_ref_count_;
int video_ref_count_;
int mirroring_ref_count_;
+ int screen_capture_ref_count_;
+ base::Closure stop_screen_capture_callback_;
DISALLOW_COPY_AND_ASSIGN(WebContentsDeviceUsage);
};
@@ -136,34 +146,34 @@ class MediaStreamCaptureIndicator::WebContentsDeviceUsage
MediaStreamCaptureIndicator::WebContentsDeviceUsage::WebContentsDeviceUsage(
WebContents* web_contents)
: content::WebContentsObserver(web_contents),
- audio_ref_count_(0), video_ref_count_(0), mirroring_ref_count_(0) {
+ audio_ref_count_(0),
+ video_ref_count_(0),
+ mirroring_ref_count_(0),
+ screen_capture_ref_count_(0) {
}
-int MediaStreamCaptureIndicator::WebContentsDeviceUsage::TallyUsage(
- const content::MediaStreamDevices& devices, bool direction) {
- const int inc_amount = direction ? +1 : -1;
+int MediaStreamCaptureIndicator::WebContentsDeviceUsage::AddDevices(
+ const content::MediaStreamDevices& devices,
+ const base::Closure& close_callback) {
bool incremented_audio_count = false;
bool incremented_video_count = false;
for (content::MediaStreamDevices::const_iterator it = devices.begin();
it != devices.end(); ++it) {
if (it->type == content::MEDIA_TAB_AUDIO_CAPTURE ||
it->type == content::MEDIA_TAB_VIDEO_CAPTURE) {
- mirroring_ref_count_ += inc_amount;
+ ++mirroring_ref_count_;
+ } else if (it->type == content::MEDIA_SCREEN_VIDEO_CAPTURE) {
+ ++screen_capture_ref_count_;
+ stop_screen_capture_callback_ = close_callback;
} else if (content::IsAudioMediaType(it->type)) {
- audio_ref_count_ += inc_amount;
- incremented_audio_count = (inc_amount > 0);
+ ++audio_ref_count_;
} else if (content::IsVideoMediaType(it->type)) {
- video_ref_count_ += inc_amount;
- incremented_video_count = (inc_amount > 0);
+ ++video_ref_count_;
} else {
NOTIMPLEMENTED();
}
}
- DCHECK_LE(0, audio_ref_count_);
- DCHECK_LE(0, video_ref_count_);
- DCHECK_LE(0, mirroring_ref_count_);
-
if (incremented_audio_count && incremented_video_count)
return IDS_MEDIA_STREAM_STATUS_TRAY_BALLOON_BODY_AUDIO_AND_VIDEO;
else if (incremented_audio_count)
@@ -174,6 +184,30 @@ int MediaStreamCaptureIndicator::WebContentsDeviceUsage::TallyUsage(
return 0;
}
+void MediaStreamCaptureIndicator::WebContentsDeviceUsage::RemoveDevices(
+ const content::MediaStreamDevices& devices) {
+ for (content::MediaStreamDevices::const_iterator it = devices.begin();
+ it != devices.end(); ++it) {
+ if (it->type == content::MEDIA_TAB_AUDIO_CAPTURE ||
+ it->type == content::MEDIA_TAB_VIDEO_CAPTURE) {
+ --mirroring_ref_count_;
+ } else if (it->type == content::MEDIA_SCREEN_VIDEO_CAPTURE) {
+ --screen_capture_ref_count_;
+ } else if (content::IsAudioMediaType(it->type)) {
+ --audio_ref_count_;
+ } else if (content::IsVideoMediaType(it->type)) {
+ --video_ref_count_;
+ } else {
+ NOTIMPLEMENTED();
+ }
+ }
+
+ DCHECK_GE(audio_ref_count_, 0);
+ DCHECK_GE(video_ref_count_, 0);
+ DCHECK_GE(mirroring_ref_count_, 0);
+ DCHECK_GE(screen_capture_ref_count_, 0);
+}
+
MediaStreamCaptureIndicator::MediaStreamCaptureIndicator()
: status_icon_(NULL),
mic_image_(NULL),
@@ -258,6 +292,34 @@ void MediaStreamCaptureIndicator::CaptureDevicesClosed(
this, render_process_id, render_view_id, devices));
}
+
+bool MediaStreamCaptureIndicator::IsCapturingUserMedia(
+ int render_process_id, int render_view_id) const {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ WebContents* const web_contents =
+ LookUpByKnownAlias(render_process_id, render_view_id);
+ if (!web_contents)
+ return false;
+
+ UsageMap::const_iterator it = usage_map_.find(web_contents);
+ return (it != usage_map_.end() &&
+ (it->second->IsCapturingAudio() || it->second->IsCapturingVideo()));
+}
+
+bool MediaStreamCaptureIndicator::IsBeingMirrored(
+ int render_process_id, int render_view_id) const {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ WebContents* const web_contents =
+ LookUpByKnownAlias(render_process_id, render_view_id);
+ if (!web_contents)
+ return false;
+
+ UsageMap::const_iterator it = usage_map_.find(web_contents);
+ return it != usage_map_.end() && it->second->IsMirroring();
+}
+
void MediaStreamCaptureIndicator::DoDevicesOpenedOnUIThread(
int render_process_id,
int render_view_id,
@@ -374,7 +436,7 @@ void MediaStreamCaptureIndicator::MaybeDestroyStatusTrayIcon() {
}
}
-void MediaStreamCaptureIndicator::UpdateStatusTrayIconContextMenu() {
+void MediaStreamCaptureIndicator::UpdateNotificationUserInterface() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
scoped_ptr<ui::SimpleMenuModel> menu(new ui::SimpleMenuModel(this));
@@ -382,30 +444,57 @@ void MediaStreamCaptureIndicator::UpdateStatusTrayIconContextMenu() {
bool video = false;
int command_id = IDC_MEDIA_CONTEXT_MEDIA_STREAM_CAPTURE_LIST_FIRST;
command_targets_.clear();
+
+ WebContents* screen_capturer = NULL;
+ base::Closure close_callback;
+
for (UsageMap::const_iterator iter = usage_map_.begin();
iter != usage_map_.end(); ++iter) {
// Check if any audio and video devices have been used.
const WebContentsDeviceUsage& usage = *iter->second;
WebContents* const web_contents = iter->first;
- if (usage.IsWebContentsDestroyed() ||
- !GetExtension(web_contents) ||
- (!usage.IsCapturingAudio() && !usage.IsCapturingVideo())) {
+ if (usage.IsWebContentsDestroyed()) {
// We only show the tray icon for extensions that have not been
// destroyed and are capturing audio or video.
- // For regular tabs, we show an indicator in the tab icon.
continue;
}
- audio = audio || usage.IsCapturingAudio();
- video = video || usage.IsCapturingVideo();
+ if (usage.IsCapturingScreen()) {
+ DCHECK(!screen_capturer);
+ screen_capturer = web_contents;
+ close_callback = usage.StopScreenCaptureCallback();
+ }
+
+ // Audio/video icon is shown only for extensions. For regular tabs, we show
+ // an indicator in the tab icon.
+ if (GetExtension(web_contents) &&
+ (usage.IsCapturingAudio() || usage.IsCapturingVideo())) {
+ audio = audio || usage.IsCapturingAudio();
+ video = video || usage.IsCapturingVideo();
- command_targets_.push_back(web_contents);
- menu->AddItem(command_id, GetTitle(web_contents));
+ command_targets_.push_back(web_contents);
+ menu->AddItem(command_id, GetTitle(web_contents));
- // If reaching the maximum number, no more item will be added to the menu.
- if (command_id == IDC_MEDIA_CONTEXT_MEDIA_STREAM_CAPTURE_LIST_LAST)
- break;
- ++command_id;
+ // If reaching the maximum number, no more item will be added to the menu.
+ if (command_id == IDC_MEDIA_CONTEXT_MEDIA_STREAM_CAPTURE_LIST_LAST)
+ break;
+ ++command_id;
+ }
+ }
+
+ if (screen_capturer) {
+ if (!screen_capture_notification_) {
+ screen_capture_notification_ = ScreenCaptureNotificationUI::Create();
+ if (!screen_capture_notification_->Show(
+ base::Bind(&MediaStreamCaptureIndicator::OnStopScreenCapture,
+ this, close_callback),
+ GetTitle(screen_capturer))) {
+ OnStopScreenCapture(close_callback);
+ screen_capture_notification_.reset();
+ }
+ }
+ } else {
+ screen_capture_notification_.reset();
}
if (command_targets_.empty()) {
@@ -473,7 +562,8 @@ void MediaStreamCaptureIndicator::AddCaptureDevices(
WebContentsDeviceUsage*& usage = usage_map_[web_contents];
if (!usage)
usage = new WebContentsDeviceUsage(web_contents);
- const int balloon_body_message_id = usage->TallyUsage(devices, true);
+ const int balloon_body_message_id =
+ usage->AddDevices(devices, close_callback);
// Keep track of the IDs as a known alias to the WebContents instance.
const AliasMap::iterator insert_it = aliases_.insert(
@@ -484,7 +574,7 @@ void MediaStreamCaptureIndicator::AddCaptureDevices(
web_contents->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TAB);
- UpdateStatusTrayIconContextMenu();
+ UpdateNotificationUserInterface();
if (balloon_body_message_id)
ShowBalloon(web_contents, balloon_body_message_id);
}
@@ -507,14 +597,14 @@ void MediaStreamCaptureIndicator::RemoveCaptureDevices(
return;
}
WebContentsDeviceUsage* const usage = it->second;
- usage->TallyUsage(devices, false);
+ usage->RemoveDevices(devices);
if (!usage->IsWebContentsDestroyed())
web_contents->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TAB);
// Remove the usage and alias mappings if all the devices have been closed.
if (!usage->IsCapturingAudio() && !usage->IsCapturingVideo() &&
- !usage->IsMirroring()) {
+ !usage->IsMirroring() && !usage->IsCapturingScreen()) {
for (AliasMap::iterator alias_it = aliases_.begin();
alias_it != aliases_.end(); ) {
if (alias_it->second == web_contents)
@@ -526,32 +616,11 @@ void MediaStreamCaptureIndicator::RemoveCaptureDevices(
usage_map_.erase(it);
}
- UpdateStatusTrayIconContextMenu();
-}
-
-bool MediaStreamCaptureIndicator::IsCapturingUserMedia(
- int render_process_id, int render_view_id) const {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- WebContents* const web_contents =
- LookUpByKnownAlias(render_process_id, render_view_id);
- if (!web_contents)
- return false;
-
- UsageMap::const_iterator it = usage_map_.find(web_contents);
- return (it != usage_map_.end() &&
- (it->second->IsCapturingAudio() || it->second->IsCapturingVideo()));
+ UpdateNotificationUserInterface();
}
-bool MediaStreamCaptureIndicator::IsBeingMirrored(
- int render_process_id, int render_view_id) const {
+void MediaStreamCaptureIndicator::OnStopScreenCapture(
+ const base::Closure& stop) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- WebContents* const web_contents =
- LookUpByKnownAlias(render_process_id, render_view_id);
- if (!web_contents)
- return false;
-
- UsageMap::const_iterator it = usage_map_.find(web_contents);
- return it != usage_map_.end() && it->second->IsMirroring();
+ stop.Run();
}
diff --git a/chrome/browser/media/media_stream_capture_indicator.h b/chrome/browser/media/media_stream_capture_indicator.h
index c5f603b..9acf977 100644
--- a/chrome/browser/media/media_stream_capture_indicator.h
+++ b/chrome/browser/media/media_stream_capture_indicator.h
@@ -23,6 +23,7 @@ namespace gfx {
class ImageSkia;
} // namespace gfx
+class ScreenCaptureNotificationUI;
class StatusIcon;
class StatusTray;
@@ -61,9 +62,6 @@ class MediaStreamCaptureIndicator
// media for remote broadcast).
bool IsBeingMirrored(int render_process_id, int render_view_id) const;
- // ImageLoader callback.
- void OnImageLoaded(const string16& message, const gfx::Image& image);
-
private:
class WebContentsDeviceUsage;
@@ -112,19 +110,25 @@ class MediaStreamCaptureIndicator
void ShowBalloon(content::WebContents* web_contents,
int balloon_body_message_id);
+ // ImageLoader callback.
+ void OnImageLoaded(const string16& message, const gfx::Image& image);
+
// Removes the status tray icon from the desktop. This function is called by
// RemoveCaptureDevices() when the device usage map becomes empty.
void MaybeDestroyStatusTrayIcon();
- // Updates the status tray menu with the new device list. This call will be
- // triggered by both AddCaptureDevices() and RemoveCaptureDevices().
- void UpdateStatusTrayIconContextMenu();
+ // Updates the status tray menu and the screen capture notification. Called
+ // from AddCaptureDevices() and RemoveCaptureDevices().
+ void UpdateNotificationUserInterface();
// Updates the status tray tooltip and image according to which kind of
// devices are being used. This function is called by
// UpdateStatusTrayIconContextMenu().
void UpdateStatusTrayIconDisplay(bool audio, bool video);
+ // Callback for ScreenCaptureNotificationUI.
+ void OnStopScreenCapture(const base::Closure& stop);
+
// Reference to our status icon - owned by the StatusTray. If null,
// the platform doesn't support status icons.
StatusIcon* status_icon_;
@@ -152,6 +156,8 @@ class MediaStreamCaptureIndicator
CommandTargets command_targets_;
bool should_show_balloon_;
+
+ scoped_ptr<ScreenCaptureNotificationUI> screen_capture_notification_;
};
#endif // CHROME_BROWSER_MEDIA_MEDIA_STREAM_CAPTURE_INDICATOR_H_
diff --git a/content/browser/renderer_host/media/media_stream_manager.cc b/content/browser/renderer_host/media/media_stream_manager.cc
index 87dbfe2..a640dc5 100644
--- a/content/browser/renderer_host/media/media_stream_manager.cc
+++ b/content/browser/renderer_host/media/media_stream_manager.cc
@@ -151,7 +151,8 @@ MediaStreamManager::MediaStreamManager(media::AudioManager* audio_manager)
ui_controller_(new MediaStreamUIController(this))),
audio_manager_(audio_manager),
monitoring_started_(false),
- io_loop_(NULL) {
+ io_loop_(NULL),
+ screen_capture_active_(false) {
DCHECK(audio_manager_);
memset(active_enumeration_ref_count_, 0,
sizeof(active_enumeration_ref_count_));
@@ -249,6 +250,23 @@ std::string MediaStreamManager::GenerateStream(
}
}
+ if (options.video_type == MEDIA_SCREEN_VIDEO_CAPTURE) {
+ if (options.audio_type != MEDIA_NO_SERVICE) {
+ // TODO(sergeyu): Surface error message to the calling JS code.
+ LOG(ERROR) << "Audio is not supported for screen capture streams.";
+ return std::string();
+ }
+
+ if (screen_capture_active_) {
+ // TODO(sergeyu): Implement support for more than one concurrent screen
+ // capture streams.
+ LOG(ERROR) << "Another screen capture stream is active.";
+ return std::string();
+ }
+
+ screen_capture_active_ = true;
+ }
+
// Create a new request based on options.
DeviceRequest* request = new DeviceRequest(requester,
options,
@@ -274,7 +292,7 @@ void MediaStreamManager::CancelRequest(const std::string& label) {
// TODO(xians): update the |state| to STATE_DONE to trigger a state
// changed notification to UI before deleting the request?
scoped_ptr<DeviceRequest> request(it->second);
- requests_.erase(it);
+ RemoveRequest(it);
for (int i = MEDIA_NO_SERVICE + 1; i < NUM_MEDIA_TYPES; ++i) {
const MediaStreamType stream_type = static_cast<MediaStreamType>(i);
MediaStreamProvider* device_manager = GetDeviceManager(stream_type);
@@ -299,6 +317,7 @@ void MediaStreamManager::CancelRequest(const std::string& label) {
void MediaStreamManager::StopGeneratedStream(const std::string& label) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
// Find the request and close all open devices for the request.
DeviceRequests::iterator it = requests_.find(label);
if (it != requests_.end()) {
@@ -308,7 +327,7 @@ void MediaStreamManager::StopGeneratedStream(const std::string& label) {
}
scoped_ptr<DeviceRequest> request(it->second);
- requests_.erase(it);
+ RemoveRequest(it);
for (StreamDeviceInfoArray::const_iterator device_it =
request->devices.begin();
device_it != request->devices.end(); ++device_it) {
@@ -400,7 +419,7 @@ void MediaStreamManager::StopEnumerateDevices(const std::string& label) {
DCHECK_EQ(it->second->type, MEDIA_ENUMERATE_DEVICES);
// Delete the DeviceRequest.
scoped_ptr<DeviceRequest> request(it->second);
- requests_.erase(it);
+ RemoveRequest(it);
}
}
@@ -539,6 +558,15 @@ std::string MediaStreamManager::AddRequest(DeviceRequest* request) {
return unique_label;
}
+void MediaStreamManager::RemoveRequest(DeviceRequests::iterator it) {
+ if (it->second->options.video_type == MEDIA_SCREEN_VIDEO_CAPTURE) {
+ DCHECK(screen_capture_active_);
+ screen_capture_active_ = false;
+ }
+
+ requests_.erase(it);
+}
+
void MediaStreamManager::PostRequestToUI(const std::string& label) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
DeviceRequest* request = requests_[label];
@@ -810,7 +838,7 @@ void MediaStreamManager::Error(MediaStreamType stream_type,
if (request->requester)
request->requester->StreamGenerationFailed(it->first);
- requests_.erase(it);
+ RemoveRequest(it);
} else {
// 2. Not opened but other devices exists for this request -> remove
// device from list, but don't signal an error.
@@ -845,7 +873,7 @@ void MediaStreamManager::DevicesAccepted(const std::string& label,
}
// Delete the request since it is done.
- requests_.erase(request_it);
+ RemoveRequest(request_it);
return;
}
@@ -923,7 +951,7 @@ void MediaStreamManager::SettingsError(const std::string& label) {
request->callback.Run(label, MediaStreamDevices());
}
- requests_.erase(it);
+ RemoveRequest(it);
}
void MediaStreamManager::StopStreamFromUI(const std::string& label) {
diff --git a/content/browser/renderer_host/media/media_stream_manager.h b/content/browser/renderer_host/media/media_stream_manager.h
index 4558e0f..205ddb2 100644
--- a/content/browser/renderer_host/media/media_stream_manager.h
+++ b/content/browser/renderer_host/media/media_stream_manager.h
@@ -203,6 +203,7 @@ class CONTENT_EXPORT MediaStreamManager
MediaStreamProvider* GetDeviceManager(MediaStreamType stream_type);
void StartEnumeration(DeviceRequest* request);
std::string AddRequest(DeviceRequest* request);
+ void RemoveRequest(DeviceRequests::iterator it);
void ClearEnumerationCache(EnumerationCache* cache);
void PostRequestToUI(const std::string& label);
void HandleRequest(const std::string& label);
@@ -250,6 +251,8 @@ class CONTENT_EXPORT MediaStreamManager
// managers on the right thread.
MessageLoop* io_loop_;
+ bool screen_capture_active_;
+
DISALLOW_COPY_AND_ASSIGN(MediaStreamManager);
};