Skip to content

Commit

Permalink
Added registerStream() for using stream id in getUserMedia()
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Cong Liu committed Mar 2, 2016
1 parent 1471763 commit 7ce42de
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 18 deletions.
4 changes: 4 additions & 0 deletions docs/For Users/Migration/From 0.12 to 0.13.md
Expand Up @@ -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.
Expand Down
49 changes: 33 additions & 16 deletions docs/References/Screen.md
Expand Up @@ -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
Expand All @@ -162,42 +163,58 @@ 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"
* `primary` `{Boolean}` _Windows OS only_ this will be `true` if the source is the primary monitor

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

Emit when the Z-order of a source changed (this may change for windows as others are focused).

### 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.
3 changes: 2 additions & 1 deletion src/api/nw_screen.idl
Expand Up @@ -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);
};

};
37 changes: 37 additions & 0 deletions src/api/nw_screen_api.cc
Expand Up @@ -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"
Expand Down Expand Up @@ -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
14 changes: 14 additions & 0 deletions src/api/nw_screen_api.h
Expand Up @@ -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_
5 changes: 4 additions & 1 deletion src/resources/api_nw_screen.js
Expand Up @@ -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, {});
});
Expand Down Expand Up @@ -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() {
Expand Down

0 comments on commit 7ce42de

Please sign in to comment.