Browse Source

feat: add webContents.getMediaSourceId() method (#31204)

* feat: add webContents.getMediaSourceId() method

* fix: account for null frame_hosts in webContents.getMediaSourceId()

* fix: move webContents.getMediaSourceId definition to be more organised

* fix: move webContents.getMediaSourceId implementation

* fix: move webContents.getMediaSourceId docs
Mitchell McCaffrey 3 years ago
parent
commit
23cdf65c53

+ 8 - 0
docs/api/web-contents.md

@@ -1923,6 +1923,14 @@ Setting the WebRTC IP handling policy allows you to control which IPs are
 exposed via WebRTC. See [BrowserLeaks](https://browserleaks.com/webrtc) for
 more details.
 
+#### `contents.getMediaSourceId(requestWebContents)`
+
+* `requestWebContents` WebContents - Web contents that the id will be registered to.
+
+Returns `String` - The identifier of a WebContents stream. This identifier can be used
+with `navigator.mediaDevices.getUserMedia` using a `chromeMediaSource` of `tab`.
+The identifier is restricted to the web contents that it is registered to and is only valid for 10 seconds.
+
 #### `contents.getOSProcessId()`
 
 Returns `Integer` - The operating system `pid` of the associated renderer

+ 30 - 0
shell/browser/api/electron_api_web_contents.cc

@@ -38,6 +38,8 @@
 #include "content/browser/renderer_host/render_widget_host_view_base.h"  // nogncheck
 #include "content/public/browser/child_process_security_policy.h"
 #include "content/public/browser/context_menu_params.h"
+#include "content/public/browser/desktop_media_id.h"
+#include "content/public/browser/desktop_streams_registry.h"
 #include "content/public/browser/download_request_utils.h"
 #include "content/public/browser/favicon_status.h"
 #include "content/public/browser/file_select_listener.h"
@@ -2198,6 +2200,33 @@ void WebContents::SetWebRTCIPHandlingPolicy(
   web_contents()->SyncRendererPrefs();
 }
 
+std::string WebContents::GetMediaSourceID(
+    content::WebContents* request_web_contents) {
+  auto* frame_host = web_contents()->GetMainFrame();
+  if (!frame_host)
+    return std::string();
+
+  content::DesktopMediaID media_id(
+      content::DesktopMediaID::TYPE_WEB_CONTENTS,
+      content::DesktopMediaID::kNullId,
+      content::WebContentsMediaCaptureId(frame_host->GetProcess()->GetID(),
+                                         frame_host->GetRoutingID()));
+
+  auto* request_frame_host = request_web_contents->GetMainFrame();
+  if (!request_frame_host)
+    return std::string();
+
+  std::string id =
+      content::DesktopStreamsRegistry::GetInstance()->RegisterStream(
+          request_frame_host->GetProcess()->GetID(),
+          request_frame_host->GetRoutingID(),
+          url::Origin::Create(
+              request_frame_host->GetLastCommittedURL().GetOrigin()),
+          media_id, "", content::kRegistryStreamTypeTab);
+
+  return id;
+}
+
 bool WebContents::IsCrashed() const {
   return web_contents()->IsCrashed();
 }
@@ -3875,6 +3904,7 @@ v8::Local<v8::ObjectTemplate> WebContents::FillObjectTemplate(
       .SetMethod("isBeingCaptured", &WebContents::IsBeingCaptured)
       .SetMethod("setWebRTCIPHandlingPolicy",
                  &WebContents::SetWebRTCIPHandlingPolicy)
+      .SetMethod("getMediaSourceId", &WebContents::GetMediaSourceID)
       .SetMethod("getWebRTCIPHandlingPolicy",
                  &WebContents::GetWebRTCIPHandlingPolicy)
       .SetMethod("takeHeapSnapshot", &WebContents::TakeHeapSnapshot)

+ 1 - 0
shell/browser/api/electron_api_web_contents.h

@@ -185,6 +185,7 @@ class WebContents : public gin::Wrappable<WebContents>,
   int GetHistoryLength() const;
   const std::string GetWebRTCIPHandlingPolicy() const;
   void SetWebRTCIPHandlingPolicy(const std::string& webrtc_ip_handling_policy);
+  std::string GetMediaSourceID(content::WebContents* request_web_contents);
   bool IsCrashed() const;
   void ForcefullyCrashRenderer();
   void SetUserAgent(const std::string& user_agent);

+ 8 - 0
spec-main/api-web-contents-spec.ts

@@ -838,6 +838,14 @@ describe('webContents module', () => {
     });
   });
 
+  describe('getMediaSourceId()', () => {
+    afterEach(closeAllWindows);
+    it('returns a valid stream id', () => {
+      const w = new BrowserWindow({ show: false });
+      expect(w.webContents.getMediaSourceId(w.webContents)).to.be.a('string').that.is.not.empty();
+    });
+  });
+
   describe('userAgent APIs', () => {
     it('can set the user agent (functions)', () => {
       const w = new BrowserWindow({ show: false });