From 7ce42dee29c9a533054579f4557b943f0a1f615b Mon Sep 17 00:00:00 2001 From: Cong Liu Date: Tue, 1 Mar 2016 10:29:18 +0800 Subject: [PATCH] Added `registerStream()` for using stream id in `getUserMedia()` Media source id returned by `added` event should be registered before using with `getUserMedia()`. Media source id, e.g. "screen:0", is permanent until removed, while registered stream id is a temporary one-time random string accessible only from the frame that requesting it. Fixed #4459 --- docs/For Users/Migration/From 0.12 to 0.13.md | 4 ++ docs/References/Screen.md | 49 +++++++++++++------ src/api/nw_screen.idl | 3 +- src/api/nw_screen_api.cc | 37 ++++++++++++++ src/api/nw_screen_api.h | 14 ++++++ src/resources/api_nw_screen.js | 5 +- 6 files changed, 94 insertions(+), 18 deletions(-) diff --git a/docs/For Users/Migration/From 0.12 to 0.13.md b/docs/For Users/Migration/From 0.12 to 0.13.md index 1fb78eb273..a4773e741b 100644 --- a/docs/For Users/Migration/From 0.12 to 0.13.md +++ b/docs/For Users/Migration/From 0.12 to 0.13.md @@ -46,6 +46,10 @@ + Window options `always-on-top` and `visible-on-all-workspaces` is renamed to [`always_on_top`](../../References/Manifest Format.md#always_on_top) and [`visible_on_all_workspaces`](../../References/Manifest Format.md#visible_on_all_workspaces) respectively in `package.json` or as argument of `Window.open()`. + Window is not inherited from `EventEmitter` anymore, but the methods `on()`, `once()`, `removeListener()` and `removeAllListeners()` are still supported. +### Screen + ++ The `id` obtained by `added`, `orderchanged`, `namechanged`, `thumbnailchanged` should be registered and use the stream id returned by [`registerStream(id)`](../../References/Screen.md#screendesktopcapturemonitorregisterstreamid) before passing to `getUserMedia`. See [Synopsis](../../References/Screen.md#synopsis_1) for the usage. + ### Known issues + The following window options passed to nw.Window.open() is not effective on Linux: `min_width`, `min_height`, `max_width`, `max_height`, `resizable` for now; try to set them in the callback. diff --git a/docs/References/Screen.md b/docs/References/Screen.md index 28ae400091..073afa40fe 100644 --- a/docs/References/Screen.md +++ b/docs/References/Screen.md @@ -119,34 +119,35 @@ This API behaves similar functions as `Screen.chooseDesktopMedia`. But it doesn' ### Synopsis ```javascript +var dcm = nw.Screen.DesktopCaptureMonitor; nw.Screen.Init(); -nw.Screen.DesktopCaptureMonitor.on("added", function (id, name, order, type) { +dcm.on("added", function (id, name, order, type) { //select first stream and shutdown var constraints = { audio: { mandatory: { chromeMediaSource: "system", - chromeMediaSourceId: id + chromeMediaSourceId: dcm.registerStream(id) } }, video: { mandatory: { chromeMediaSource: 'desktop', - chromeMediaSourceId: id, + chromeMediaSourceId: dcm.registerStream(id) } } }; // TODO: call getUserMedia with contraints - nw.Screen.DesktopCaptureMonitor.stop(); + dcm.stop(); }); -nw.Screen.DesktopCaptureMonitor.on("removed", function (id) { }); -nw.Screen.DesktopCaptureMonitor.on("orderchanged", function (id, new_order, old_order) { }); -nw.Screen.DesktopCaptureMonitor.on("namechanged", function (id, name) { }); -nw.Screen.DesktopCaptureMonitor.on("thumbnailchanged", function (id, thumbnail) { }); -nw.Screen.DesktopCaptureMonitor.start(true, true); +dcm.on("removed", function (id) { }); +dcm.on("orderchanged", function (id, new_order, old_order) { }); +dcm.on("namechanged", function (id, name) { }); +dcm.on("thumbnailchanged", function (id, thumbnail) { }); +dcm.start(true, true); ``` ### Screen.DesktopCaptureMonitor.started @@ -162,11 +163,18 @@ The `DesktopCaptureMonitor` will start monitoring the system and trigger the the ### Screen.DesktopCaptureMonitor.stop() -The `DesktopCaptureMonitor` will stop monitoring the system. The `id` provided can be passed into `chromeMediaSourceId` in `getUserMedia` constraints. `DesktopCaptureMonitor` should be stopped after a stream is selected. +The `DesktopCaptureMonitor` will stop monitoring the system. `DesktopCaptureMonitor` should be stopped after a stream is selected. + +### Screen.DesktopCaptureMonitor.registerStream(id) + +Register and return a valid stream id passed into `chromeMediaSourceId` in `getUserMedia` constraints. See [Synopsis](#synopsis_1) for the usage. ### Event: added (id, name, order, type, primary) -* `id` `{String}` is unique id that can be passed as chromeMediaSourceId +!!! warning "Behavior Changed" + This feature is changed in 0.13.0. See [Migration Notes from 0.12 to 0.13](../For Users/Migration/From 0.12 to 0.13.md). + +* `id` `{String}` is the media id. Use `registerStream(id)` to obtain a valid stream id used with `getUserMedia()`. See [registerStream](#screendesktopcapturemonitorregisterstreamid) * `name` `{String}` is the title of the window or screen * `order` `{Integer}` is the z-order of the windows, if screens are selected they will appear first * `type` `{String}` type of the stream: "screen", "window", "other" or "unknown" @@ -174,15 +182,18 @@ The `DesktopCaptureMonitor` will stop monitoring the system. The `id` provided c Emit when a new source was added. -### Event: removed (id) +### Event: removed (order) -* `id` `{String}` is the chromeMediaSourceId of the screen or monitor that is no longer capturable +* `order` `{Integer}` is the order of the media source that is no longer capturable Emit when a source was removed. ### Event: orderchanged (id, new_order, old_order) -* `id` `{String}` is the chromeMediaSourceId of the screen or window that has changed z-order +!!! warning "Behavior Changed" + This feature is changed in 0.13.0. See [Migration Notes from 0.12 to 0.13](../For Users/Migration/From 0.12 to 0.13.md). + +* `id` `{String}` is the media id of the screen or window that has changed z-order * `new_order` `{Integer}` is the new z-order * `old_order` `{Integer}` is the old z-order @@ -190,14 +201,20 @@ Emit when the Z-order of a source changed (this may change for windows as others ### Event: namechanged (id, name) -* `id` `{String}` is the chromeMediaSourceId of the screen or window that has a name changed +!!! warning "Behavior Changed" + This feature is changed in 0.13.0. See [Migration Notes from 0.12 to 0.13](../For Users/Migration/From 0.12 to 0.13.md). + +* `id` `{String}` is the media id of the screen or window that has a name changed * `name` `{String}` is the new new name of the screen or window Emit when the name of the source has changed. This can happen when a window changes title. ### Event: thumbnailchanged (id, thumbnail) -* `id` `{String}` is the chromeMediaSourceId of the screen or window that has an updated thumbnail +!!! warning "Behavior Changed" + This feature is changed in 0.13.0. See [Migration Notes from 0.12 to 0.13](../For Users/Migration/From 0.12 to 0.13.md). + +* `id` `{String}` is the media id of the screen or window that has an updated thumbnail * `thumbnail` `{String}` is the base64 encoded png of the thumbnail Emit when the thumbnail of a source changed. diff --git a/src/api/nw_screen.idl b/src/api/nw_screen.idl index 22a307a436..601e0d7d07 100644 --- a/src/api/nw_screen.idl +++ b/src/api/nw_screen.idl @@ -46,7 +46,8 @@ namespace nw.Screen { [nocompile] static long cancelChooseDesktopMedia(long request_id); static void startMonitor(boolean screens, boolean windows); static void stopMonitor(); - static boolean isMonitorStarted(); + static boolean[] isMonitorStarted(); + static DOMString[] registerStream(DOMString id); }; }; diff --git a/src/api/nw_screen_api.cc b/src/api/nw_screen_api.cc index 37fdc71886..9177c9935d 100644 --- a/src/api/nw_screen_api.cc +++ b/src/api/nw_screen_api.cc @@ -12,7 +12,12 @@ #include "base/strings/string16.h" #include "base/strings/utf_string_conversions.h" #include "chrome/browser/media/desktop_media_list_observer.h" +#include "chrome/browser/media/desktop_streams_registry.h" +#include "chrome/browser/media/media_capture_devices_dispatcher.h" #include "chrome/browser/media/native_desktop_media_list.h" +#include "content/public/browser/render_frame_host.h" +#include "content/public/browser/render_process_host.h" +#include "content/public/browser/web_contents.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" @@ -345,4 +350,36 @@ namespace extensions { return true; } + NwScreenRegisterStreamFunction::NwScreenRegisterStreamFunction() {} + + bool NwScreenRegisterStreamFunction::RunNWSync(base::ListValue* response, std::string* error) { + std::string id; + EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &id)); + + // following code is modified from `DesktopCaptureChooseDesktopMediaFunctionBase::OnPickerDialogResults` + // in chrome/browser/extensions/api/desktop_capture/desktop_capture_base.cc + + content::DesktopMediaID source = content::DesktopMediaID::Parse(id); + content::WebContents* web_contents = GetSenderWebContents(); + if (!source.is_null() && web_contents) { + std::string result; + DesktopStreamsRegistry* registry = + MediaCaptureDevicesDispatcher::GetInstance()-> + GetDesktopStreamsRegistry(); + // TODO(miu): Once render_frame_host() is being set, we should register the + // exact RenderFrame requesting the stream, not the main RenderFrame. With + // that change, also update + // MediaCaptureDevicesDispatcher::ProcessDesktopCaptureAccessRequest(). + // http://crbug.com/304341 + content::RenderFrameHost* const main_frame = web_contents->GetMainFrame(); + result = registry->RegisterStream(main_frame->GetProcess()->GetID(), + main_frame->GetRoutingID(), + extension()->url(), + source, + extension()->name()); + response->AppendString(result); + } + return true; + } + } // extensions diff --git a/src/api/nw_screen_api.h b/src/api/nw_screen_api.h index cd9bcacbee..0caa9bbb78 100644 --- a/src/api/nw_screen_api.h +++ b/src/api/nw_screen_api.h @@ -74,6 +74,20 @@ namespace extensions { private: DISALLOW_COPY_AND_ASSIGN(NwScreenIsMonitorStartedFunction); }; + + // implement nw.Screen.registerStream() + class NwScreenRegisterStreamFunction : public NWSyncExtensionFunction { + public: + NwScreenRegisterStreamFunction(); + bool RunNWSync(base::ListValue* response, std::string* error) override; + + protected: + ~NwScreenRegisterStreamFunction() override {} + DECLARE_EXTENSION_FUNCTION("nw.Screen.registerStream", UNKNOWN) + + private: + DISALLOW_COPY_AND_ASSIGN(NwScreenRegisterStreamFunction); + }; } // extensions #endif //NW_SRC_API_NW_SCREEN_API_H_ diff --git a/src/resources/api_nw_screen.js b/src/resources/api_nw_screen.js index a468beefeb..3b21c1b722 100644 --- a/src/resources/api_nw_screen.js +++ b/src/resources/api_nw_screen.js @@ -5,7 +5,7 @@ var EventEmitter = nw.require('events').EventEmitter; // Hook Sync API calls nw_binding.registerCustomHook(function(bindingsAPI) { var apiFunctions = bindingsAPI.apiFunctions; - ['getScreens', 'initEventListeners', 'startMonitor', 'stopMonitor', 'isMonitorStarted'].forEach(function(nwSyncAPIName) { + ['getScreens', 'initEventListeners', 'startMonitor', 'stopMonitor', 'isMonitorStarted', 'registerStream'].forEach(function(nwSyncAPIName) { apiFunctions.setHandleRequest(nwSyncAPIName, function() { return sendRequest.sendRequestSync(this.name, arguments, this.definition.parameters, {}); }); @@ -65,6 +65,9 @@ Screen.cancelChooseDesktopMedia = chrome.desktopCapture.cancelChooseDesktopMedia Screen.DesktopCaptureMonitor = new EventEmitter(); Screen.DesktopCaptureMonitor.start = nwScreenBinding.startMonitor; Screen.DesktopCaptureMonitor.stop = nwScreenBinding.stopMonitor; +Screen.DesktopCaptureMonitor.registerStream = function(id) { + return nwScreenBinding.registerStream(id)[0]; +}; Object.defineProperty(Screen.DesktopCaptureMonitor, 'started', { get: function() {