Browse Source

Refine more about desktop capturer API.

* Simplify the coffeescript code.
* Add more options in desktopCapturer.startUpdating.
Haojian Wu 9 years ago
parent
commit
36c0ad7fda

+ 0 - 10
atom.gyp

@@ -278,11 +278,6 @@
               '-lwinmm.lib',
             ],
           },
-          'defines': [
-            # The usage of "webrtc/modules/desktop_capture/desktop_capture_options.h"
-            # is required to see this macro.
-            'WEBRTC_WIN',
-          ],
           'dependencies': [
             # Node is built as static_library on Windows, so we also need to
             # include its dependencies here.
@@ -296,11 +291,6 @@
           ],
         }],  # OS=="win"
         ['OS=="mac"', {
-          'defines': [
-            # The usage of "webrtc/modules/desktop_capture/desktop_capture_options.h"
-            # is required to see this macro.
-            'WEBRTC_MAC',
-          ],
           'dependencies': [
             'vendor/crashpad/client/client.gyp:crashpad_client',
             'vendor/crashpad/handler/handler.gyp:crashpad_handler',

+ 39 - 25
atom/browser/api/atom_api_desktop_capturer.cc

@@ -14,30 +14,13 @@
 #include "third_party/webrtc/modules/desktop_capture/screen_capturer.h"
 #include "third_party/webrtc/modules/desktop_capture/window_capturer.h"
 
-namespace mate {
-
-template<>
-struct Converter<DesktopMediaList::Source> {
-  static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
-                                   const DesktopMediaList::Source& source) {
-    mate::Dictionary dict(isolate, v8::Object::New(isolate));
-    content::DesktopMediaID id = source.id;
-    dict.Set("name", base::UTF16ToUTF8(source.name));
-    dict.Set("id", id.ToString());
-    dict.Set(
-        "thumbnail",
-        atom::api::NativeImage::Create(isolate, gfx::Image(source.thumbnail)));
-    return ConvertToV8(isolate, dict);
-  }
-};
-
-}  // namespace mate
-
 namespace atom {
 
 namespace api {
 
 namespace {
+// Refresh every second.
+const int kUpdatePeriod = 1000;
 const int kThumbnailWidth = 150;
 const int kThumbnailHeight = 150;
 }  // namespace
@@ -48,7 +31,11 @@ DesktopCapturer::DesktopCapturer() {
 DesktopCapturer::~DesktopCapturer() {
 }
 
-void DesktopCapturer::StartUpdating(const std::vector<std::string>& sources) {
+void DesktopCapturer::StartUpdating(const mate::Dictionary& args) {
+  std::vector<std::string> sources;
+  if (!args.Get("types", &sources))
+    return;
+
   bool show_screens = false;
   bool show_windows = false;
   for (const auto& source_type : sources) {
@@ -80,7 +67,16 @@ void DesktopCapturer::StartUpdating(const std::vector<std::string>& sources) {
       show_windows ? webrtc::WindowCapturer::Create(options) : nullptr);
   media_list_.reset(new NativeDesktopMediaList(screen_capturer.Pass(),
       window_capturer.Pass()));
-  media_list_->SetThumbnailSize(gfx::Size(kThumbnailWidth, kThumbnailHeight));
+
+  int update_period = kUpdatePeriod;
+  int thumbnail_width = kThumbnailWidth, thumbnail_height = kThumbnailHeight;
+  args.Get("updatePeriod", &update_period);
+  args.Get("thumbnailWidth", &thumbnail_width);
+  args.Get("thumbnailHeight", &thumbnail_height);
+
+  media_list_->SetUpdatePeriod(base::TimeDelta::FromMilliseconds(
+        update_period));
+  media_list_->SetThumbnailSize(gfx::Size(thumbnail_width, thumbnail_height));
   media_list_->StartUpdating(this);
 }
 
@@ -89,22 +85,40 @@ void DesktopCapturer::StopUpdating() {
 }
 
 void DesktopCapturer::OnSourceAdded(int index) {
-  Emit("source-added", media_list_->GetSource(index));
+  EmitDesktopCapturerEvent("source-added", index, false);
 }
 
 void DesktopCapturer::OnSourceRemoved(int index) {
-  Emit("source-removed", media_list_->GetSource(index));
+  EmitDesktopCapturerEvent("source-removed", index, false);
 }
 
+// Ignore this event.
 void DesktopCapturer::OnSourceMoved(int old_index, int new_index) {
 }
 
 void DesktopCapturer::OnSourceNameChanged(int index) {
-  Emit("source-name-changed", media_list_->GetSource(index));
+  EmitDesktopCapturerEvent("source-removed", index, false);
 }
 
 void DesktopCapturer::OnSourceThumbnailChanged(int index) {
-  Emit("source-thumbnail-changed", media_list_->GetSource(index));
+  EmitDesktopCapturerEvent("source-thumbnail-changed", index, true);
+}
+
+void DesktopCapturer::OnRefreshFinished() {
+  Emit("refresh-finished");
+}
+
+void DesktopCapturer::EmitDesktopCapturerEvent(
+    const std::string& event_name, int index, bool with_thumbnail) {
+  const DesktopMediaList::Source& source = media_list_->GetSource(index);
+  content::DesktopMediaID id = source.id;
+  if (!with_thumbnail)
+    Emit(event_name, id.ToString(), base::UTF16ToUTF8(source.name));
+  else {
+    Emit(event_name, id.ToString(), base::UTF16ToUTF8(source.name),
+         atom::api::NativeImage::Create(isolate(),
+                                        gfx::Image(source.thumbnail)));
+  }
 }
 
 mate::ObjectTemplateBuilder DesktopCapturer::GetObjectTemplateBuilder(

+ 9 - 1
atom/browser/api/atom_api_desktop_capturer.h

@@ -14,6 +14,10 @@
 #include "chrome/browser/media/native_desktop_media_list.h"
 #include "native_mate/handle.h"
 
+namespace mate {
+class Dictionary;
+}
+
 namespace atom {
 
 namespace api {
@@ -23,7 +27,8 @@ class DesktopCapturer: public mate::EventEmitter,
  public:
   static mate::Handle<DesktopCapturer> Create(v8::Isolate* isolate);
 
-  void StartUpdating(const std::vector<std::string>& sources);
+  void StartUpdating(const mate::Dictionary& args);
+
   void StopUpdating();
 
  protected:
@@ -36,8 +41,11 @@ class DesktopCapturer: public mate::EventEmitter,
   void OnSourceMoved(int old_index, int new_index) override;
   void OnSourceNameChanged(int index) override;
   void OnSourceThumbnailChanged(int index) override;
+  void OnRefreshFinished() override;
 
  private:
+  void EmitDesktopCapturerEvent(
+      const std::string& event_name, int index, bool with_thumbnail);
   // mate::Wrappable:
   mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
       v8::Isolate* isolate) override;

+ 11 - 15
atom/browser/lib/desktop-capturer.coffee

@@ -1,10 +1,8 @@
 ipc = require 'ipc'
 BrowserWindow = require 'browser-window'
-EventEmitter = require('events').EventEmitter
 
 # The browser module manages all desktop-capturer moduels in renderer process.
 desktopCapturer = process.atomBinding('desktop_capturer').desktopCapturer
-desktopCapturer.__proto__ = EventEmitter.prototype
 
 getWebContentsFromId = (id) ->
   windows = BrowserWindow.getAllWindows()
@@ -15,28 +13,26 @@ webContentsIds = new Set
 
 stopDesktopCapture = (id) ->
   webContentsIds.delete id
+  # Stop updating if no renderer process listens the desktop capturer.
   if webContentsIds.size is 0
     desktopCapturer.stopUpdating()
 
-ipc.on 'ATOM_BROWSER_DESKTOP_CAPTURER_REQUIRED', (event) ->
-  id = event.sender.getId()
-  # Remove the tracked webContents when it is destroyed.
-  getWebContentsFromId(id).on 'destroyed', ()->
-    stopDesktopCapture id
-  event.returnValue = 'done'
-
 # Handle `desktopCapturer.startUpdating` API.
 ipc.on 'ATOM_BROWSER_DESKTOP_CAPTURER_START_UPDATING', (event, args) ->
   id = event.sender.getId()
+  if not webContentsIds.has id
+    # Stop sending desktop capturer events to the destroyed webContents.
+    event.sender.on 'destroyed', ()->
+      stopDesktopCapture id
+  # Start updating the desktopCapturer if it doesn't.
+  if webContentsIds.size is 0
+    desktopCapturer.startUpdating args
   webContentsIds.add id
-  desktopCapturer.startUpdating args
 
 # Handle `desktopCapturer.stopUpdating` API.
 ipc.on 'ATOM_BROWSER_DESKTOP_CAPTURER_STOP_UPDATING', (event) ->
   stopDesktopCapture event.sender.getId()
 
-for event_name in ['source-added', 'source-removed', 'source-name-changed', "source-thumbnail-changed"]
-  do (event_name) ->
-    desktopCapturer.on event_name, (event, source) ->
-      webContentsIds.forEach (id) ->
-        getWebContentsFromId(id).send event_name, { id: source.id, name: source.name, dataUrl: source.thumbnail.toDataUrl() }
+desktopCapturer.emit = (event_name, event, desktopId, name, thumbnail) ->
+  webContentsIds.forEach (id) ->
+    getWebContentsFromId(id).send 'ATOM_RENDERER_DESKTOP_CAPTURER', event_name, desktopId, name, thumbnail?.toDataUrl()

+ 4 - 7
atom/renderer/api/lib/desktop-capturer.coffee

@@ -5,18 +5,15 @@ NativeImage = require 'native-image'
 EventEmitter = require('events').EventEmitter
 desktopCapturer = new EventEmitter
 
-# Tells main process the renderer is requiring 'desktop-capture' module.
-ipc.sendSync 'ATOM_BROWSER_DESKTOP_CAPTURER_REQUIRED'
-
 desktopCapturer.startUpdating = (args) ->
   ipc.send 'ATOM_BROWSER_DESKTOP_CAPTURER_START_UPDATING', args
 
 desktopCapturer.stopUpdating = () ->
   ipc.send 'ATOM_BROWSER_DESKTOP_CAPTURER_STOP_UPDATING'
 
-for event_name in ['source-added', 'source-removed', 'source-name-changed', "source-thumbnail-changed"]
-  do (event_name) ->
-    ipc.on event_name, (source) ->
-      desktopCapturer.emit event_name, { id: source.id, name: source.name, thumbnail: NativeImage.createFromDataUrl source.dataUrl }
+ipc.on 'ATOM_RENDERER_DESKTOP_CAPTURER', (event_name, id, name, thumbnail) ->
+  if not thumbnail
+    return desktopCapturer.emit event_name, id, name
+  desktopCapturer.emit event_name, id, name, NativeImage.createFromDataUrl thumbnail
 
 module.exports = desktopCapturer

+ 1 - 0
chromium_src/chrome/browser/media/desktop_media_list_observer.h

@@ -14,6 +14,7 @@ class DesktopMediaListObserver {
   virtual void OnSourceMoved(int old_index, int new_index) = 0;
   virtual void OnSourceNameChanged(int index) = 0;
   virtual void OnSourceThumbnailChanged(int index) = 0;
+  virtual void OnRefreshFinished() = 0;
 
  protected:
   virtual ~DesktopMediaListObserver() {}

+ 1 - 0
chromium_src/chrome/browser/media/native_desktop_media_list.cc

@@ -358,6 +358,7 @@ void NativeDesktopMediaList::OnSourceThumbnail(
 }
 
 void NativeDesktopMediaList::OnRefreshFinished() {
+  observer_->OnRefreshFinished();
   BrowserThread::PostDelayedTask(
       BrowserThread::UI, FROM_HERE,
       base::Bind(&NativeDesktopMediaList::Refresh,

+ 39 - 26
docs/api/desktop-capturer.md

@@ -7,13 +7,13 @@ screen and individual app windows.
 // In the renderer process.
 var desktopCapturer = require('desktop-capturer');
 
-desktopCapturer.on('source-added', function(source) {
-  console.log("source " + source.name + " is added.");
-  // source.thumbnail is not ready to use here and webkitGetUserMedia neither.
+desktopCapturer.on('source-added', function(id, name) {
+  console.log("source " + name + " is added.");
+  // navigator.webkitGetUserMedia is not ready for use now.
 });
 
-desktopCapturer.on('source-thumbnail-changed', function(source) {
-  if (source.name == "Electron") {
+desktopCapturer.on('source-thumbnail-changed', function(id, name, thumbnail) {
+  if (name == "Electron") {
     // stopUpdating since we have found the window that we want to capture.
     desktopCapturer.stopUpdating();
 
@@ -23,7 +23,7 @@ desktopCapturer.on('source-thumbnail-changed', function(source) {
       video: {
         mandatory: {
           chromeMediaSource: 'desktop',
-          chromeMediaSourceId: source.id,
+          chromeMediaSourceId: id,
           minWidth: 1280,
           maxWidth: 1280,
           minHeight: 720,
@@ -50,42 +50,65 @@ function getUserMediaError(e) {
 
 ### Event: 'source-added'
 
-* `source` Source
+* `id` String - The id of the captured window or screen used in
+  `navigator.webkitGetUserMedia`. The format looks like 'window:XX' or
+  'screen:XX' where XX is a random generated number.
+* `name` String - The descriped name of the capturing screen or window. If the
+  source is a screen, the name will be 'Entire Screen' or 'Screen <index>'; if
+  it is a window, the name will be the window's title.
 
-Emits when there is a new source added, usually a new window is created,
-a new screen is attached.
+Emits when there is a new source added, usually a new window is created or a new
+screen is attached.
 
-**Note:** The thumbnail of the source is not ready for use when 'source-added'
-event is emitted, and `navigator.webkitGetUserMedia` neither.
+**Note:** `navigator.webkitGetUserMedia` is not ready for use in this event.
 
 ### Event: 'source-removed'
 
-* `source` Source
+* `id` String - The id of the captured window or screen used in
+  `navigator.webkitGetUserMedia`.
+* `name` String - The descriped name of the capturing screen or window.
 
 Emits when there is a source removed.
 
 ### Event: 'source-name-changed'
 
-* `source` Source
+* `id` String - The id of the captured window or screen used in
+  `navigator.webkitGetUserMedia`.
+* `name` String - The descriped name of the capturing screen or window.
 
 Emits when the name of source is changed.
 
 ### Event: 'source-thumbnail-changed'
 
-* `source` Source
+* `id` String - The id of the captured window or screen used in
+  `navigator.webkitGetUserMedia`.
+* `name` String - The descriped name of the capturing screen or window.
+* `thumbnail` [NativeImage](NativeImage.md) - A thumbnail image.
 
 Emits when the thumbnail of source is changed. `desktopCapturer` will refresh
 all sources every second.
 
+### Event: 'refresh-finished'
+
+Emits when `desktopCapturer` finishes a refresh.
+
 ## Methods
 
 The `desktopCapturer` module has the following methods:
 
 ### `desktopCapturer.startUpdating(options)`
 
-* `options` Array - An array of String that enums the types of desktop sources.
+`options` Object, properties:
+
+* `types` Array - An array of String that enums the types of desktop sources.
   * `screen` String - Screen
   * `window` String - Individual window
+* `updatePeriod` Integer (optional) - The update period in milliseconds. By
+  default, `desktopCapturer` updates every second.
+* `thumbnailWidth` Integer (optional) - The width of thumbnail. By default, it
+  is 150px.
+* `thumbnailHeight` Integer (optional) - The height of thumbnail. By default, it
+  is 150px.
 
 Starts updating desktopCapturer. The events of `desktopCapturer` will only be
 emitted after `startUpdating` API is invoked.
@@ -104,15 +127,5 @@ Stops updating desktopCapturer. The events of `desktopCapturer` will not be
 emitted after the API is invoked.
 
 **Note:** It is a good practice to call `stopUpdating` when you do not need
-getting any infomation of sources, usually after passing a id of source to
+getting any infomation of sources, usually after passing a id to
 `navigator.webkitGetUserMedia`.
-
-## Source
-
-`Source` is an object represents a captured screen or individual window. It has
-following properties:
-
-* `id` String - The id of the capturing window or screen used in
-  `navigator.webkitGetUserMedia`.
-* `name` String - The descriped name of the capturing screen or window.
-* `thumbnail` [NativeImage](NativeImage.md) - A thumbnail image.