diff --git a/atom.gyp b/atom.gyp index 77ad2e22ae3..b2e55e9be30 100644 --- a/atom.gyp +++ b/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', diff --git a/atom/browser/api/atom_api_desktop_capturer.cc b/atom/browser/api/atom_api_desktop_capturer.cc index f3e05486e9b..a6556f6a89f 100644 --- a/atom/browser/api/atom_api_desktop_capturer.cc +++ b/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 { - static v8::Local 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& sources) { +void DesktopCapturer::StartUpdating(const mate::Dictionary& args) { + std::vector 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& 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( diff --git a/atom/browser/api/atom_api_desktop_capturer.h b/atom/browser/api/atom_api_desktop_capturer.h index f4be410ed61..f0620c8e9cf 100644 --- a/atom/browser/api/atom_api_desktop_capturer.h +++ b/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 Create(v8::Isolate* isolate); - void StartUpdating(const std::vector& 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; diff --git a/atom/browser/lib/desktop-capturer.coffee b/atom/browser/lib/desktop-capturer.coffee index 29bb1ae6051..0177d9721bb 100644 --- a/atom/browser/lib/desktop-capturer.coffee +++ b/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() diff --git a/atom/renderer/api/lib/desktop-capturer.coffee b/atom/renderer/api/lib/desktop-capturer.coffee index bf2d27597a0..ae5e054c2a7 100644 --- a/atom/renderer/api/lib/desktop-capturer.coffee +++ b/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 diff --git a/chromium_src/chrome/browser/media/desktop_media_list_observer.h b/chromium_src/chrome/browser/media/desktop_media_list_observer.h index 1988f52b5bc..eccaa407d2d 100644 --- a/chromium_src/chrome/browser/media/desktop_media_list_observer.h +++ b/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() {} diff --git a/chromium_src/chrome/browser/media/native_desktop_media_list.cc b/chromium_src/chrome/browser/media/native_desktop_media_list.cc index 050c5e1d5a7..a326ded91b8 100644 --- a/chromium_src/chrome/browser/media/native_desktop_media_list.cc +++ b/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, diff --git a/docs/api/desktop-capturer.md b/docs/api/desktop-capturer.md index 8862762ddab..6dc971cd206 100644 --- a/docs/api/desktop-capturer.md +++ b/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 '; 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.