diff options
15 files changed, 159 insertions, 45 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 18f9968..4cad13a 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -13583,6 +13583,15 @@ Please check your email at <ph name="ACCOUNT_EMAIL">$2<ex>jane.doe@gmail.com</ex <message name="IDS_DESKTOP_MEDIA_PICKER_TEXT_DELEGATED" desc="Text for the window picker dialog shown when desktop capture is requested by an app to be used by a tab."> <ph name="APP_NAME">$1<ex>Google Hangouts</ex></ph> would like to share the content of your screen with <ph name="TARGET_NAME">$2<ex>https://google.com</ex></ph>. Choose what you'd like to share. </message> + <message name="IDS_DESKTOP_MEDIA_PICKER_AUDIO_SHARE" desc="Text for the checkbox on the window picker dialog, when checked, audio will be shared, otherwise just video sharing"> + Also share audio + </message> + <message name="IDS_DESKTOP_MEDIA_PICKER_AUDIO_SHARE_TOOLTIP_WINDOW" desc="Tooltip text for the checkbox on the window picker dialog, explaining why the checkbox is disabled"> + Audio sharing is not supported for individual windows. + </message> + <message name="IDS_DESKTOP_MEDIA_PICKER_AUDIO_SHARE_TOOLTIP_NONE" desc="Tooltip text for the checkbox on the window picker dialog, explaining why the checkbox is disabled"> + Please select what to share first. + </message> <message name="IDS_DESKTOP_MEDIA_PICKER_SINGLE_SCREEN_NAME" desc="Name for screens in the desktop media picker UI when there is only one monitor."> Entire screen </message> diff --git a/chrome/browser/extensions/api/desktop_capture/desktop_capture_apitest.cc b/chrome/browser/extensions/api/desktop_capture/desktop_capture_apitest.cc index d6e026d..42b7e94 100644 --- a/chrome/browser/extensions/api/desktop_capture/desktop_capture_apitest.cc +++ b/chrome/browser/extensions/api/desktop_capture/desktop_capture_apitest.cc @@ -54,6 +54,7 @@ class FakeDesktopMediaPicker : public DesktopMediaPicker { const base::string16& app_name, const base::string16& target_name, scoped_ptr<DesktopMediaList> model, + bool request_audio, const DoneCallback& done_callback) override { if (!expectation_->cancelled) { // Post a task to call the callback asynchronously. diff --git a/chrome/browser/extensions/api/desktop_capture/desktop_capture_base.cc b/chrome/browser/extensions/api/desktop_capture/desktop_capture_base.cc index fccf615..7bc5da4 100644 --- a/chrome/browser/extensions/api/desktop_capture/desktop_capture_base.cc +++ b/chrome/browser/extensions/api/desktop_capture/desktop_capture_base.cc @@ -7,6 +7,7 @@ #include <tuple> #include <utility> +#include "base/command_line.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" #include "chrome/browser/extensions/extension_tab_util.h" @@ -18,6 +19,7 @@ #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/web_contents.h" +#include "extensions/common/switches.h" #include "third_party/webrtc/modules/desktop_capture/desktop_capture_options.h" #include "third_party/webrtc/modules/desktop_capture/screen_capturer.h" #include "third_party/webrtc/modules/desktop_capture/window_capturer.h" @@ -77,6 +79,8 @@ bool DesktopCaptureChooseDesktopMediaFunctionBase::Execute( bool show_screens = false; bool show_windows = false; + bool request_audio = false; + for (auto source_type : sources) { switch (source_type) { case api::desktop_capture::DESKTOP_CAPTURE_SOURCE_TYPE_NONE: @@ -94,6 +98,12 @@ bool DesktopCaptureChooseDesktopMediaFunctionBase::Execute( case api::desktop_capture::DESKTOP_CAPTURE_SOURCE_TYPE_TAB: error_ = kTabCaptureNotSupportedError; return false; + + case api::desktop_capture::DESKTOP_CAPTURE_SOURCE_TYPE_AUDIO: + bool has_flag = base::CommandLine::ForCurrentProcess()->HasSwitch( + extensions::switches::kEnableDesktopCaptureAudio); + request_audio = has_flag; + break; } } @@ -145,7 +155,7 @@ bool DesktopCaptureChooseDesktopMediaFunctionBase::Execute( picker_->Show(web_contents, parent_window, parent_window, base::UTF8ToUTF16(extension()->name()), target_name, - std::move(media_list), callback); + std::move(media_list), request_audio, callback); origin_ = origin; return true; } diff --git a/chrome/browser/media/desktop_capture_access_handler.cc b/chrome/browser/media/desktop_capture_access_handler.cc index 5bf01c1..1eced46 100644 --- a/chrome/browser/media/desktop_capture_access_handler.cc +++ b/chrome/browser/media/desktop_capture_access_handler.cc @@ -31,6 +31,7 @@ #include "extensions/browser/app_window/app_window_registry.h" #include "extensions/common/constants.h" #include "extensions/common/extension.h" +#include "extensions/common/switches.h" #include "media/audio/audio_manager_base.h" #include "net/base/url_util.h" #include "third_party/webrtc/modules/desktop_capture/desktop_capture_types.h" @@ -343,11 +344,25 @@ void DesktopCaptureAccessHandler::HandleRequest( loopback_audio_supported = true; #endif - // Audio is only supported for screen capture streams. + // This value essentially from the checkbox on picker window, so it + // corresponds to user permission. + bool audio_permitted = media_id.audio_share; + + // This value essentially from whether getUserMedia requests audio stream. + bool audio_requested = + request.audio_type == content::MEDIA_DESKTOP_AUDIO_CAPTURE; + + // This value shows for a given capture type, whether the system or our code + // can support audio sharing. Currently audio is only supported for screen + // capture streams. + bool audio_supported = + media_id.type == content::DesktopMediaID::TYPE_SCREEN && + loopback_audio_supported; + + bool has_flag = base::CommandLine::ForCurrentProcess()->HasSwitch( + extensions::switches::kEnableDesktopCaptureAudio); bool capture_audio = - (media_id.type == content::DesktopMediaID::TYPE_SCREEN && - request.audio_type == content::MEDIA_DESKTOP_AUDIO_CAPTURE && - loopback_audio_supported); + (has_flag ? audio_permitted : true) && audio_requested && audio_supported; ui = GetDevicesForDesktopCapture(&devices, media_id, capture_audio, true, GetApplicationTitle(web_contents, extension), diff --git a/chrome/browser/media/desktop_media_picker.h b/chrome/browser/media/desktop_media_picker.h index 5262fc9..22e9e1a 100644 --- a/chrome/browser/media/desktop_media_picker.h +++ b/chrome/browser/media/desktop_media_picker.h @@ -40,6 +40,7 @@ class DesktopMediaPicker { const base::string16& app_name, const base::string16& target_name, scoped_ptr<DesktopMediaList> list, + bool request_audio, const DoneCallback& done_callback) = 0; private: diff --git a/chrome/browser/ui/cocoa/media_picker/desktop_media_picker_cocoa.h b/chrome/browser/ui/cocoa/media_picker/desktop_media_picker_cocoa.h index 4acb0d8..02f3aba 100644 --- a/chrome/browser/ui/cocoa/media_picker/desktop_media_picker_cocoa.h +++ b/chrome/browser/ui/cocoa/media_picker/desktop_media_picker_cocoa.h @@ -23,6 +23,7 @@ class DesktopMediaPickerCocoa : public DesktopMediaPicker { const base::string16& app_name, const base::string16& target_name, scoped_ptr<DesktopMediaList> media_list, + bool request_audio, const DoneCallback& done_callback) override; private: diff --git a/chrome/browser/ui/cocoa/media_picker/desktop_media_picker_cocoa.mm b/chrome/browser/ui/cocoa/media_picker/desktop_media_picker_cocoa.mm index d8d4a3e..352dd46 100644 --- a/chrome/browser/ui/cocoa/media_picker/desktop_media_picker_cocoa.mm +++ b/chrome/browser/ui/cocoa/media_picker/desktop_media_picker_cocoa.mm @@ -20,6 +20,7 @@ void DesktopMediaPickerCocoa::Show(content::WebContents* web_contents, const base::string16& app_name, const base::string16& target_name, scoped_ptr<DesktopMediaList> media_list, + bool request_audio, const DoneCallback& done_callback) { controller_.reset([[DesktopMediaPickerController alloc] initWithMediaList:std::move(media_list) diff --git a/chrome/browser/ui/views/desktop_media_picker_views.cc b/chrome/browser/ui/views/desktop_media_picker_views.cc index 06479bf..68c0b89 100644 --- a/chrome/browser/ui/views/desktop_media_picker_views.cc +++ b/chrome/browser/ui/views/desktop_media_picker_views.cc @@ -28,6 +28,7 @@ #include "ui/native_theme/native_theme.h" #include "ui/views/background.h" #include "ui/views/bubble/bubble_frame_view.h" +#include "ui/views/controls/button/checkbox.h" #include "ui/views/controls/image_view.h" #include "ui/views/controls/label.h" #include "ui/views/controls/scroll_view.h" @@ -392,27 +393,39 @@ DesktopMediaPickerDialogView::DesktopMediaPickerDialogView( DesktopMediaPickerViews* parent, const base::string16& app_name, const base::string16& target_name, - scoped_ptr<DesktopMediaList> media_list) + scoped_ptr<DesktopMediaList> media_list, + bool request_audio) : parent_(parent), app_name_(app_name), - label_(new views::Label()), - scroll_view_(views::ScrollView::CreateScrollViewWithBorder()), - list_view_(new DesktopMediaListView(this, std::move(media_list))) { + description_label_(new views::Label()), + audio_share_checkbox_(nullptr), + sources_scroll_view_(views::ScrollView::CreateScrollViewWithBorder()), + sources_list_view_( + new DesktopMediaListView(this, std::move(media_list))) { if (app_name == target_name) { - label_->SetText( + description_label_->SetText( l10n_util::GetStringFUTF16(IDS_DESKTOP_MEDIA_PICKER_TEXT, app_name)); } else { - label_->SetText(l10n_util::GetStringFUTF16( + description_label_->SetText(l10n_util::GetStringFUTF16( IDS_DESKTOP_MEDIA_PICKER_TEXT_DELEGATED, app_name, target_name)); } - label_->SetMultiLine(true); - label_->SetHorizontalAlignment(gfx::ALIGN_LEFT); - AddChildView(label_); + description_label_->SetMultiLine(true); + description_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT); + AddChildView(description_label_); + + if (request_audio) { + audio_share_checkbox_ = new views::Checkbox( + l10n_util::GetStringUTF16(IDS_DESKTOP_MEDIA_PICKER_AUDIO_SHARE)); + AddChildView(audio_share_checkbox_); + audio_share_checkbox_->SetEnabled(false); + audio_share_checkbox_->SetTooltipText(l10n_util::GetStringUTF16( + IDS_DESKTOP_MEDIA_PICKER_AUDIO_SHARE_TOOLTIP_NONE)); + } - scroll_view_->SetContents(list_view_); - scroll_view_->ClipHeightTo( - GetMediaListViewHeightForRows(1), GetMediaListViewHeightForRows(2)); - AddChildView(scroll_view_); + sources_scroll_view_->SetContents(sources_list_view_); + sources_scroll_view_->ClipHeightTo(GetMediaListViewHeightForRows(1), + GetMediaListViewHeightForRows(2)); + AddChildView(sources_scroll_view_); // If |parent_web_contents| is set and it's not a background page then the // picker will be shown modal to the web contents. Otherwise the picker is @@ -450,7 +463,7 @@ DesktopMediaPickerDialogView::DesktopMediaPickerDialogView( } } - list_view_->StartUpdating(dialog_window_id); + sources_list_view_->StartUpdating(dialog_window_id); } DesktopMediaPickerDialogView::~DesktopMediaPickerDialogView() {} @@ -461,14 +474,24 @@ void DesktopMediaPickerDialogView::DetachParent() { gfx::Size DesktopMediaPickerDialogView::GetPreferredSize() const { static const size_t kDialogViewWidth = 600; + const gfx::Insets title_insets = views::BubbleFrameView::GetTitleInsets(); - size_t label_height = - label_->GetHeightForWidth(kDialogViewWidth - title_insets.height() * 2); + + const size_t kInnerWidth = kDialogViewWidth - title_insets.height() * 2; + + size_t label_height = description_label_->GetHeightForWidth(kInnerWidth); + + size_t checkbox_height_with_padding = + audio_share_checkbox_ + ? audio_share_checkbox_->GetHeightForWidth(kInnerWidth) + + views::kPanelVertMargin + : 0; return gfx::Size(kDialogViewWidth, views::kPanelVertMargin * 2 + label_height + + checkbox_height_with_padding + views::kPanelVerticalSpacing + - scroll_view_->GetPreferredSize().height()); + sources_scroll_view_->GetPreferredSize().height()); } void DesktopMediaPickerDialogView::Layout() { @@ -479,13 +502,29 @@ void DesktopMediaPickerDialogView::Layout() { rect.Inset(title_insets.left(), views::kPanelVertMargin); gfx::Rect label_rect(rect.x(), rect.y(), rect.width(), - label_->GetHeightForWidth(rect.width())); - label_->SetBoundsRect(label_rect); + description_label_->GetHeightForWidth(rect.width())); + description_label_->SetBoundsRect(label_rect); + + int checkbox_height = 0; + int checkbox_height_with_padding = 0; + if (audio_share_checkbox_) { + checkbox_height = audio_share_checkbox_->GetHeightForWidth(rect.width()); + checkbox_height_with_padding = checkbox_height + views::kPanelVertMargin; + } int scroll_view_top = label_rect.bottom() + views::kPanelVerticalSpacing; - scroll_view_->SetBounds( - rect.x(), scroll_view_top, - rect.width(), rect.height() - scroll_view_top); + int scroll_view_height = + rect.height() - scroll_view_top - checkbox_height_with_padding; + gfx::Rect scroll_view_rect(rect.x(), scroll_view_top, rect.width(), + scroll_view_height); + sources_scroll_view_->SetBoundsRect(scroll_view_rect); + + if (audio_share_checkbox_) { + gfx::Rect checkbox_rect(rect.x(), + scroll_view_rect.bottom() + views::kPanelVertMargin, + rect.width(), checkbox_height); + audio_share_checkbox_->SetBoundsRect(checkbox_rect); + } } ui::ModalType DesktopMediaPickerDialogView::GetModalType() const { @@ -499,12 +538,12 @@ base::string16 DesktopMediaPickerDialogView::GetWindowTitle() const { bool DesktopMediaPickerDialogView::IsDialogButtonEnabled( ui::DialogButton button) const { if (button == ui::DIALOG_BUTTON_OK) - return list_view_->GetSelection() != NULL; + return sources_list_view_->GetSelection() != NULL; return true; } views::View* DesktopMediaPickerDialogView::GetInitiallyFocusedView() { - return list_view_; + return sources_list_view_; } base::string16 DesktopMediaPickerDialogView::GetDialogButtonLabel( @@ -514,7 +553,7 @@ base::string16 DesktopMediaPickerDialogView::GetDialogButtonLabel( } bool DesktopMediaPickerDialogView::Accept() { - DesktopMediaSourceView* selection = list_view_->GetSelection(); + DesktopMediaSourceView* selection = sources_list_view_->GetSelection(); // Ok button should only be enabled when a source is selected. DCHECK(selection); @@ -523,6 +562,10 @@ bool DesktopMediaPickerDialogView::Accept() { if (selection) source = selection->source_id(); + source.audio_share = audio_share_checkbox_ && + audio_share_checkbox_->enabled() && + audio_share_checkbox_->checked(); + if (parent_) parent_->NotifyDialogResult(source); @@ -539,6 +582,26 @@ void DesktopMediaPickerDialogView::DeleteDelegate() { void DesktopMediaPickerDialogView::OnSelectionChanged() { GetDialogClientView()->UpdateDialogButtons(); + + // Disable the checkbox if we cannot support audio for the selected source. + if (audio_share_checkbox_) { + DesktopMediaSourceView* selection = sources_list_view_->GetSelection(); + + DesktopMediaID source; + if (selection) + source = selection->source_id(); + + if (source.type == DesktopMediaID::TYPE_SCREEN) { + audio_share_checkbox_->SetEnabled(true); + audio_share_checkbox_->SetTooltipText(base::string16()); + } else if (source.type == DesktopMediaID::TYPE_WINDOW) { + audio_share_checkbox_->SetEnabled(false); + audio_share_checkbox_->SetTooltipText(l10n_util::GetStringUTF16( + IDS_DESKTOP_MEDIA_PICKER_AUDIO_SHARE_TOOLTIP_WINDOW)); + } else { + NOTREACHED(); + } + } } void DesktopMediaPickerDialogView::OnDoubleClick() { @@ -549,23 +612,24 @@ void DesktopMediaPickerDialogView::OnDoubleClick() { void DesktopMediaPickerDialogView::OnMediaListRowsChanged() { gfx::Rect widget_bound = GetWidget()->GetWindowBoundsInScreen(); - int new_height = widget_bound.height() - scroll_view_->height() + - scroll_view_->GetPreferredSize().height(); + int new_height = widget_bound.height() - sources_scroll_view_->height() + + sources_scroll_view_->GetPreferredSize().height(); GetWidget()->CenterWindow(gfx::Size(widget_bound.width(), new_height)); } DesktopMediaListView* DesktopMediaPickerDialogView::GetMediaListViewForTesting() const { - return list_view_; + return sources_list_view_; } DesktopMediaSourceView* DesktopMediaPickerDialogView::GetMediaSourceViewForTesting(int index) const { - if (list_view_->child_count() <= index) + if (sources_list_view_->child_count() <= index) return NULL; - return reinterpret_cast<DesktopMediaSourceView*>(list_view_->child_at(index)); + return reinterpret_cast<DesktopMediaSourceView*>( + sources_list_view_->child_at(index)); } DesktopMediaPickerViews::DesktopMediaPickerViews() : dialog_(NULL) { @@ -584,11 +648,12 @@ void DesktopMediaPickerViews::Show(content::WebContents* web_contents, const base::string16& app_name, const base::string16& target_name, scoped_ptr<DesktopMediaList> media_list, + bool request_audio, const DoneCallback& done_callback) { callback_ = done_callback; - dialog_ = - new DesktopMediaPickerDialogView(web_contents, context, this, app_name, - target_name, std::move(media_list)); + dialog_ = new DesktopMediaPickerDialogView( + web_contents, context, this, app_name, target_name, std::move(media_list), + request_audio); } void DesktopMediaPickerViews::NotifyDialogResult(DesktopMediaID source) { diff --git a/chrome/browser/ui/views/desktop_media_picker_views.h b/chrome/browser/ui/views/desktop_media_picker_views.h index 01131d3..1341ad1 100644 --- a/chrome/browser/ui/views/desktop_media_picker_views.h +++ b/chrome/browser/ui/views/desktop_media_picker_views.h @@ -13,6 +13,7 @@ namespace views { class ImageView; class Label; +class Checkbox; } // namespace views class DesktopMediaPickerDialogView; @@ -118,7 +119,8 @@ class DesktopMediaPickerDialogView : public views::DialogDelegateView { DesktopMediaPickerViews* parent, const base::string16& app_name, const base::string16& target_name, - scoped_ptr<DesktopMediaList> media_list); + scoped_ptr<DesktopMediaList> media_list, + bool request_audio); ~DesktopMediaPickerDialogView() override; // Called by parent (DesktopMediaPickerViews) when it's destroyed. @@ -150,9 +152,10 @@ class DesktopMediaPickerDialogView : public views::DialogDelegateView { DesktopMediaPickerViews* parent_; base::string16 app_name_; - views::Label* label_; - views::ScrollView* scroll_view_; - DesktopMediaListView* list_view_; + views::Label* description_label_; + views::Checkbox* audio_share_checkbox_; + views::ScrollView* sources_scroll_view_; + DesktopMediaListView* sources_list_view_; DISALLOW_COPY_AND_ASSIGN(DesktopMediaPickerDialogView); }; @@ -172,6 +175,7 @@ class DesktopMediaPickerViews : public DesktopMediaPicker { const base::string16& app_name, const base::string16& target_name, scoped_ptr<DesktopMediaList> media_list, + bool request_audio, const DoneCallback& done_callback) override; DesktopMediaPickerDialogView* GetDialogViewForTesting() const { diff --git a/chrome/browser/ui/views/desktop_media_picker_views_unittest.cc b/chrome/browser/ui/views/desktop_media_picker_views_unittest.cc index c2af6c4..ea05df6 100644 --- a/chrome/browser/ui/views/desktop_media_picker_views_unittest.cc +++ b/chrome/browser/ui/views/desktop_media_picker_views_unittest.cc @@ -36,7 +36,7 @@ class DesktopMediaPickerViewsTest : public testing::Test { picker_views_.reset(new DesktopMediaPickerViews()); picker_views_->Show(NULL, test_helper_.GetContext(), NULL, app_name, - app_name, std::move(media_list), + app_name, std::move(media_list), false, base::Bind(&DesktopMediaPickerViewsTest::OnPickerDone, base::Unretained(this))); } diff --git a/chrome/common/extensions/api/desktop_capture.json b/chrome/common/extensions/api/desktop_capture.json index 965b975..5b9ff00 100644 --- a/chrome/common/extensions/api/desktop_capture.json +++ b/chrome/common/extensions/api/desktop_capture.json @@ -10,7 +10,7 @@ { "id": "DesktopCaptureSourceType", "type": "string", - "enum": ["screen", "window", "tab"], + "enum": ["screen", "window", "tab", "audio"], "description": "Enum used to define set of desktop media sources used in chooseDesktopMedia()." } ], diff --git a/chrome/common/extensions/docs/examples/api/desktopCapture/app.js b/chrome/common/extensions/docs/examples/api/desktopCapture/app.js index 65823af..7d5ba99 100644 --- a/chrome/common/extensions/docs/examples/api/desktopCapture/app.js +++ b/chrome/common/extensions/docs/examples/api/desktopCapture/app.js @@ -4,7 +4,7 @@ 'use strict'; -const DESKTOP_MEDIA = ['screen', 'window']; +const DESKTOP_MEDIA = ['screen', 'window', 'audio']; var pending_request_id = null; var pc1 = null; diff --git a/content/public/browser/desktop_media_id.h b/content/public/browser/desktop_media_id.h index 1d0ac67..5db272a 100644 --- a/content/public/browser/desktop_media_id.h +++ b/content/public/browser/desktop_media_id.h @@ -67,6 +67,9 @@ struct CONTENT_EXPORT DesktopMediaID { Id aura_id = kNullId; #endif + // This records whether the desktop share has sound or not. + bool audio_share = false; + // This id contains information for WebContents capture. WebContentsMediaCaptureId web_contents_id; }; diff --git a/extensions/common/switches.cc b/extensions/common/switches.cc index 9a14e75..41e1d27 100644 --- a/extensions/common/switches.cc +++ b/extensions/common/switches.cc @@ -31,6 +31,9 @@ const char kEnableAppWindowControls[] = "enable-app-window-controls"; // Enable BLE Advertisiing in apps. const char kEnableBLEAdvertising[] = "enable-ble-advertising-in-apps"; +const char kEnableDesktopCaptureAudio[] = + "enable-audio-support-for-desktop-share"; + // Hack so that feature switch can work with about_flags. See // kEnableScriptsRequireAction. const char kEnableEmbeddedExtensionOptions[] = diff --git a/extensions/common/switches.h b/extensions/common/switches.h index 43517cf..7c891d8 100644 --- a/extensions/common/switches.h +++ b/extensions/common/switches.h @@ -16,6 +16,7 @@ extern const char kAllowLegacyExtensionManifests[]; extern const char kEmbeddedExtensionOptions[]; extern const char kEnableAppsShowOnFirstPaint[]; extern const char kEnableAppWindowControls[]; +extern const char kEnableDesktopCaptureAudio[]; extern const char kEnableEmbeddedExtensionOptions[]; extern const char kEnableExperimentalExtensionApis[]; extern const char kEnableExtensionActionRedesign[]; |