diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 63ff3caef7307..25b9089d42522 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -4215,6 +4215,9 @@ Even if you have downloaded files from this website before, the website might ha
         <message name="IDS_EXTENSION_PROMPT_WARNING_USERS_PRIVATE" desc="Permission string for access to user accounts.">
           Read and change whitelisted users
         </message>
+        <message name="IDS_EXTENSION_PROMPT_WARNING_DISPLAY_SOURCE" desc="Permission string for access to Display Source API.">
+          Send audio and video to displays on the local network
+        </message>
       </if>
 
       <!-- Extension/App error messages -->
diff --git a/chrome/common/extensions/permissions/chrome_permission_message_rules.cc b/chrome/common/extensions/permissions/chrome_permission_message_rules.cc
index 66a4f2001c708..4ef877e718318 100644
--- a/chrome/common/extensions/permissions/chrome_permission_message_rules.cc
+++ b/chrome/common/extensions/permissions/chrome_permission_message_rules.cc
@@ -633,6 +633,9 @@ ChromePermissionMessageRule::GetAllRules() {
       {IDS_EXTENSION_PROMPT_WARNING_USERS_PRIVATE,
        {APIPermission::kUsersPrivate},
        {}},
+      {IDS_EXTENSION_PROMPT_WARNING_DISPLAY_SOURCE,
+       {APIPermission::kDisplaySource},
+       {}},
   };
 
   return std::vector<ChromePermissionMessageRule>(
diff --git a/extensions/browser/api/display_source/OWNERS b/extensions/browser/api/display_source/OWNERS
new file mode 100644
index 0000000000000..f7e4f6f87513e
--- /dev/null
+++ b/extensions/browser/api/display_source/OWNERS
@@ -0,0 +1,2 @@
+alexander.shalamov@intel.com
+mikhail.pozdnyakov@intel.com
diff --git a/extensions/browser/api/display_source/display_source_api.cc b/extensions/browser/api/display_source/display_source_api.cc
new file mode 100644
index 0000000000000..9b92f0f0c4346
--- /dev/null
+++ b/extensions/browser/api/display_source/display_source_api.cc
@@ -0,0 +1,97 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "extensions/browser/api/display_source/display_source_api.h"
+#include "extensions/browser/api/display_source/display_source_connection_delegate_factory.h"
+#include "extensions/common/api/display_source.h"
+
+namespace extensions {
+
+namespace {
+
+const char kErrorNotSupported[] = "Not supported";
+const char kErrorInvalidArguments[] = "Invalid arguments";
+
+}  // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+// DisplaySourceGetAvailableSinksFunction
+
+DisplaySourceGetAvailableSinksFunction::
+    ~DisplaySourceGetAvailableSinksFunction() {}
+
+ExtensionFunction::ResponseAction
+DisplaySourceGetAvailableSinksFunction::Run() {
+  DisplaySourceConnectionDelegate* delegate =
+      DisplaySourceConnectionDelegateFactory::GetForBrowserContext(
+          browser_context());
+  if (!delegate) {
+    return RespondNow(Error(kErrorNotSupported));
+  }
+
+  auto success_callback = base::Bind(
+      &DisplaySourceGetAvailableSinksFunction::OnGetSinksCompleted, this);
+  auto failure_callback = base::Bind(
+      &DisplaySourceGetAvailableSinksFunction::OnGetSinksFailed, this);
+  delegate->GetAvailableSinks(success_callback, failure_callback);
+
+  return RespondLater();
+}
+
+void DisplaySourceGetAvailableSinksFunction::OnGetSinksCompleted(
+    const DisplaySourceSinkInfoList& sinks) {
+  scoped_ptr<base::ListValue> result =
+      api::display_source::GetAvailableSinks::Results::Create(sinks);
+  Respond(ArgumentList(result.Pass()));
+}
+
+void DisplaySourceGetAvailableSinksFunction::OnGetSinksFailed(
+    const std::string& reason) {
+  Respond(Error(reason));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DisplaySourceRequestAuthenticationFunction
+
+DisplaySourceRequestAuthenticationFunction::
+    ~DisplaySourceRequestAuthenticationFunction() {}
+
+ExtensionFunction::ResponseAction
+DisplaySourceRequestAuthenticationFunction::Run() {
+  scoped_ptr<api::display_source::RequestAuthentication::Params> params(
+      api::display_source::RequestAuthentication::Params::Create(*args_));
+  if (!params) {
+    return RespondNow(Error(kErrorInvalidArguments));
+  }
+
+  DisplaySourceConnectionDelegate* delegate =
+      DisplaySourceConnectionDelegateFactory::GetForBrowserContext(
+          browser_context());
+  if (!delegate) {
+    return RespondNow(Error(kErrorNotSupported));
+  }
+
+  auto success_callback = base::Bind(
+      &DisplaySourceRequestAuthenticationFunction::OnRequestAuthCompleted,
+      this);
+  auto failure_callback = base::Bind(
+      &DisplaySourceRequestAuthenticationFunction::OnRequestAuthFailed, this);
+  delegate->RequestAuthentication(params->sink_id, success_callback,
+                                  failure_callback);
+  return RespondLater();
+}
+
+void DisplaySourceRequestAuthenticationFunction::OnRequestAuthCompleted(
+    const DisplaySourceAuthInfo& auth_info) {
+  scoped_ptr<base::ListValue> result =
+      api::display_source::RequestAuthentication::Results::Create(auth_info);
+  Respond(ArgumentList(result.Pass()));
+}
+
+void DisplaySourceRequestAuthenticationFunction::OnRequestAuthFailed(
+    const std::string& reason) {
+  Respond(Error(reason));
+}
+
+}  // namespace extensions
diff --git a/extensions/browser/api/display_source/display_source_api.h b/extensions/browser/api/display_source/display_source_api.h
new file mode 100644
index 0000000000000..f1e3ad44c4d19
--- /dev/null
+++ b/extensions/browser/api/display_source/display_source_api.h
@@ -0,0 +1,52 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef EXTENSIONS_BROWSER_API_DISPLAY_SOURCE_DISPLAY_SOURCE_API_H_
+#define EXTENSIONS_BROWSER_API_DISPLAY_SOURCE_DISPLAY_SOURCE_API_H_
+
+#include "base/macros.h"
+#include "extensions/browser/api/display_source/display_source_connection_delegate.h"
+#include "extensions/browser/extension_function.h"
+
+namespace extensions {
+
+class DisplaySourceGetAvailableSinksFunction
+    : public UIThreadExtensionFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION("displaySource.getAvailableSinks",
+                             DISPLAYSOURCE_GETAVAILABLESINKS);
+  DisplaySourceGetAvailableSinksFunction() = default;
+
+ protected:
+  ~DisplaySourceGetAvailableSinksFunction() override;
+  ResponseAction Run() final;
+
+ private:
+  void OnGetSinksCompleted(const DisplaySourceSinkInfoList& sinks);
+  void OnGetSinksFailed(const std::string& reason);
+
+  DISALLOW_COPY_AND_ASSIGN(DisplaySourceGetAvailableSinksFunction);
+};
+
+class DisplaySourceRequestAuthenticationFunction
+    : public UIThreadExtensionFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION("displaySource.requestAuthentication",
+                             DISPLAYSOURCE_REQUESTAUTHENTICATION);
+  DisplaySourceRequestAuthenticationFunction() = default;
+
+ protected:
+  ~DisplaySourceRequestAuthenticationFunction() override;
+  ResponseAction Run() final;
+
+ private:
+  void OnRequestAuthCompleted(const DisplaySourceAuthInfo& auth_info);
+  void OnRequestAuthFailed(const std::string& reason);
+
+  DISALLOW_COPY_AND_ASSIGN(DisplaySourceRequestAuthenticationFunction);
+};
+
+}  // namespace extensions
+
+#endif  // EXTENSIONS_BROWSER_API_DISPLAY_SOURCE_DISPLAY_SOURCE_API_H_
diff --git a/extensions/browser/api/display_source/display_source_apitest.cc b/extensions/browser/api/display_source/display_source_apitest.cc
new file mode 100644
index 0000000000000..9c44868a56869
--- /dev/null
+++ b/extensions/browser/api/display_source/display_source_apitest.cc
@@ -0,0 +1,99 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/scoped_ptr.h"
+#include "content/public/test/test_utils.h"
+#include "extensions/browser/api/display_source/display_source_connection_delegate.h"
+#include "extensions/browser/api/display_source/display_source_connection_delegate_factory.h"
+#include "extensions/shell/test/shell_apitest.h"
+
+namespace extensions {
+
+using api::display_source::SinkInfo;
+using api::display_source::SinkState;
+using api::display_source::SINK_STATE_DISCONNECTED;
+using api::display_source::AUTHENTICATION_METHOD_PBC;
+
+namespace {
+
+DisplaySourceSinkInfoPtr CreateSinkInfoPtr(int id,
+                                           const std::string& name,
+                                           SinkState state) {
+  DisplaySourceSinkInfoPtr ptr(new SinkInfo());
+  ptr->id = id;
+  ptr->name = name;
+  ptr->state = state;
+
+  return ptr;
+}
+
+}  // namespace
+
+class MockDisplaySourceConnectionDelegate
+    : public DisplaySourceConnectionDelegate {
+ public:
+  DisplaySourceSinkInfoList last_found_sinks() const override { return sinks_; }
+  const Connection* connection() const override { return nullptr; }
+  void GetAvailableSinks(const SinkInfoListCallback& sinks_callback,
+                         const FailureCallback& failure_callback) override {
+    AddSink(CreateSinkInfoPtr(1, "sink 1", SINK_STATE_DISCONNECTED));
+    sinks_callback.Run(sinks_);
+  }
+
+  void RequestAuthentication(int sink_id,
+                             const AuthInfoCallback& auth_info_callback,
+                             const FailureCallback& failure_callback) override {
+    DisplaySourceAuthInfo info;
+    info.method = AUTHENTICATION_METHOD_PBC;
+    auth_info_callback.Run(info);
+  }
+
+  void Connect(int sink_id,
+               const DisplaySourceAuthInfo& auth_info,
+               const base::Closure& connected_callback,
+               const FailureCallback& failure_callback) override {}
+
+  void Disconnect(const base::Closure& disconnected_callback,
+                  const FailureCallback& failure_callback) override {}
+
+  void StartWatchingSinks() override {
+    AddSink(CreateSinkInfoPtr(2, "sink 2", SINK_STATE_DISCONNECTED));
+  }
+
+  void StopWatchingSinks() override {}
+
+ private:
+  void AddSink(DisplaySourceSinkInfoPtr sink) {
+    sinks_.push_back(sink);
+    FOR_EACH_OBSERVER(DisplaySourceConnectionDelegate::Observer, observers_,
+                      OnSinksUpdated(sinks_));
+  }
+
+  DisplaySourceSinkInfoList sinks_;
+};
+
+class DisplaySourceApiTest : public ShellApiTest {
+ public:
+  DisplaySourceApiTest() = default;
+
+ private:
+  static scoped_ptr<KeyedService> CreateMockDelegate(
+      content::BrowserContext* profile) {
+    return make_scoped_ptr<KeyedService>(
+        new MockDisplaySourceConnectionDelegate());
+  }
+
+  void SetUpOnMainThread() override {
+    ShellApiTest::SetUpOnMainThread();
+    DisplaySourceConnectionDelegateFactory::GetInstance()->SetTestingFactory(
+        browser_context(), &CreateMockDelegate);
+    content::RunAllPendingInMessageLoop();
+  }
+};
+
+IN_PROC_BROWSER_TEST_F(DisplaySourceApiTest, DisplaySourceExtension) {
+  ASSERT_TRUE(RunAppTest("api_test/display_source/api")) << message_;
+}
+
+}  // namespace extensions
diff --git a/extensions/browser/api/display_source/display_source_connection_delegate.cc b/extensions/browser/api/display_source/display_source_connection_delegate.cc
new file mode 100644
index 0000000000000..1fd099011537d
--- /dev/null
+++ b/extensions/browser/api/display_source/display_source_connection_delegate.cc
@@ -0,0 +1,25 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "extensions/browser/api/display_source/display_source_connection_delegate.h"
+
+namespace extensions {
+
+DisplaySourceConnectionDelegate::Connection::Connection() {}
+
+DisplaySourceConnectionDelegate::Connection::~Connection() {}
+
+DisplaySourceConnectionDelegate::DisplaySourceConnectionDelegate() {}
+
+DisplaySourceConnectionDelegate::~DisplaySourceConnectionDelegate() {}
+
+void DisplaySourceConnectionDelegate::AddObserver(Observer* observer) {
+  observers_.AddObserver(observer);
+}
+
+void DisplaySourceConnectionDelegate::RemoveObserver(Observer* observer) {
+  observers_.RemoveObserver(observer);
+}
+
+}  // namespace extensions
diff --git a/extensions/browser/api/display_source/display_source_connection_delegate.h b/extensions/browser/api/display_source/display_source_connection_delegate.h
new file mode 100644
index 0000000000000..a885dacf1a9a0
--- /dev/null
+++ b/extensions/browser/api/display_source/display_source_connection_delegate.h
@@ -0,0 +1,103 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef EXTENSIONS_BROWSER_API_DISPLAY_SOURCE_DISPLAY_SOURCE_CONNECTION_DELEGATE_H_
+#define EXTENSIONS_BROWSER_API_DISPLAY_SOURCE_DISPLAY_SOURCE_CONNECTION_DELEGATE_H_
+
+#include "base/callback.h"
+#include "base/observer_list.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "extensions/common/api/display_source.h"
+
+namespace extensions {
+
+using DisplaySourceSinkInfoPtr = linked_ptr<api::display_source::SinkInfo>;
+using DisplaySourceSinkInfoList = std::vector<DisplaySourceSinkInfoPtr>;
+using DisplaySourceAuthInfo = api::display_source::AuthenticationInfo;
+
+// The DisplaySourceConnectionDelegate interface should be implemented
+// to provide sinks search and connection functionality for
+// 'chrome.displaySource'
+// API.
+class DisplaySourceConnectionDelegate : public KeyedService {
+ public:
+  using AuthInfoCallback = base::Callback<void(const DisplaySourceAuthInfo&)>;
+  using FailureCallback = base::Callback<void(const std::string&)>;
+  using SinkInfoListCallback =
+      base::Callback<void(const DisplaySourceSinkInfoList&)>;
+
+  struct Connection {
+    Connection();
+    ~Connection();
+    DisplaySourceSinkInfoPtr connected_sink;
+    std::string local_ip;
+    std::string sink_ip;
+  };
+
+  class Observer {
+   public:
+    // This method is called each tiome the list of available
+    // sinks is updated whether after 'GetAvailableSinks' call
+    // or while the implementation is constantly watching the sinks
+    // (after 'StartWatchingSinks' was called).
+    virtual void OnSinksUpdated(const DisplaySourceSinkInfoList& sinks) = 0;
+
+   protected:
+    virtual ~Observer() {}
+  };
+
+  DisplaySourceConnectionDelegate();
+  ~DisplaySourceConnectionDelegate() override;
+
+  virtual void AddObserver(Observer* observer);
+  virtual void RemoveObserver(Observer* observer);
+
+  // Returns the list of last found available sinks
+  // this list may contain outdated data if the delegate
+  // is not watching the sinks (via 'StartWatchingSinks'
+  // method). The list is refreshed after 'GetAvailableSinks'
+  // call.
+  virtual DisplaySourceSinkInfoList last_found_sinks() const = 0;
+
+  // Returns the Connection object representing the current
+  // connection to the sink or NULL if there is no curent connection.
+  virtual const Connection* connection() const = 0;
+
+  // Queries the list of currently available sinks.
+  virtual void GetAvailableSinks(const SinkInfoListCallback& sinks_callback,
+                                 const FailureCallback& failure_callback) = 0;
+
+  // Queries the authentication method required by the sink for connection.
+  // If the used authentication method requires authentication data to be
+  // visible on the sink's display (e.g. PIN) the implementation should
+  // request the sink to show it.
+  virtual void RequestAuthentication(
+      int sink_id,
+      const AuthInfoCallback& auth_info_callback,
+      const FailureCallback& failure_callback) = 0;
+
+  // Connects to a sink by given id and auth info.
+  virtual void Connect(int sink_id,
+                       const DisplaySourceAuthInfo& auth_info,
+                       const base::Closure& connected_callback,
+                       const FailureCallback& failure_callback) = 0;
+
+  // Disconnects the current connection to sink, the 'failure_callback'
+  // is called if there is no current connection.
+  virtual void Disconnect(const base::Closure& disconnected_callback,
+                          const FailureCallback& failure_callback) = 0;
+
+  // Implementation should start watching the sinks updates.
+  virtual void StartWatchingSinks() = 0;
+
+  // Implementation should stop watching the sinks updates.
+  virtual void StopWatchingSinks() = 0;
+
+ protected:
+  base::ObserverList<Observer> observers_;
+};
+
+}  // namespace extensions
+
+#endif  // EXTENSIONS_BROWSER_API_DISPLAY_SOURCE_DISPLAY_SOURCE_CONNECTION_DELEGATE_H_
diff --git a/extensions/browser/api/display_source/display_source_connection_delegate_factory.cc b/extensions/browser/api/display_source/display_source_connection_delegate_factory.cc
new file mode 100644
index 0000000000000..d6c5f27a4030b
--- /dev/null
+++ b/extensions/browser/api/display_source/display_source_connection_delegate_factory.cc
@@ -0,0 +1,60 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "extensions/browser/api/display_source/display_source_connection_delegate_factory.h"
+
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "content/public/browser/browser_thread.h"
+#include "extensions/browser/extensions_browser_client.h"
+
+namespace extensions {
+
+using content::BrowserContext;
+
+// static
+DisplaySourceConnectionDelegate*
+DisplaySourceConnectionDelegateFactory::GetForBrowserContext(
+    BrowserContext* browser_context) {
+  return static_cast<DisplaySourceConnectionDelegate*>(
+      GetInstance()->GetServiceForBrowserContext(browser_context, true));
+}
+
+// static
+DisplaySourceConnectionDelegateFactory*
+DisplaySourceConnectionDelegateFactory::GetInstance() {
+  return base::Singleton<DisplaySourceConnectionDelegateFactory>::get();
+}
+
+DisplaySourceConnectionDelegateFactory::DisplaySourceConnectionDelegateFactory()
+    : BrowserContextKeyedServiceFactory(
+          "DisplaySourceConnectionDelegate",
+          BrowserContextDependencyManager::GetInstance()) {}
+
+DisplaySourceConnectionDelegateFactory::
+    ~DisplaySourceConnectionDelegateFactory() {}
+
+KeyedService* DisplaySourceConnectionDelegateFactory::BuildServiceInstanceFor(
+    BrowserContext* browser_context) const {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+
+  DisplaySourceConnectionDelegate* delegate = nullptr;
+  // TODO(mikhail): Add implementation.
+  return delegate;
+}
+
+BrowserContext* DisplaySourceConnectionDelegateFactory::GetBrowserContextToUse(
+    BrowserContext* context) const {
+  return ExtensionsBrowserClient::Get()->GetOriginalContext(context);
+}
+
+bool DisplaySourceConnectionDelegateFactory::
+    ServiceIsCreatedWithBrowserContext() const {
+  return false;
+}
+
+bool DisplaySourceConnectionDelegateFactory::ServiceIsNULLWhileTesting() const {
+  return false;
+}
+
+}  // namespace extensions
diff --git a/extensions/browser/api/display_source/display_source_connection_delegate_factory.h b/extensions/browser/api/display_source/display_source_connection_delegate_factory.h
new file mode 100644
index 0000000000000..ec412a9884dbd
--- /dev/null
+++ b/extensions/browser/api/display_source/display_source_connection_delegate_factory.h
@@ -0,0 +1,47 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef EXTENSIONS_BROWSER_API_DISPLAY_SOURCE_DISPLAY_SOURCE_CONNECTION_DELEGATE_FACTORY_H_
+#define EXTENSIONS_BROWSER_API_DISPLAY_SOURCE_DISPLAY_SOURCE_CONNECTION_DELEGATE_FACTORY_H_
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/singleton.h"
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+#include "extensions/browser/api/display_source/display_source_connection_delegate.h"
+
+namespace context {
+class BrowserContext;
+}
+
+namespace extensions {
+
+class DisplaySourceConnectionDelegateFactory
+    : public BrowserContextKeyedServiceFactory {
+ public:
+  static DisplaySourceConnectionDelegate* GetForBrowserContext(
+      content::BrowserContext* browser_context);
+  static DisplaySourceConnectionDelegateFactory* GetInstance();
+
+ private:
+  friend struct base::DefaultSingletonTraits<
+      DisplaySourceConnectionDelegateFactory>;
+
+  DisplaySourceConnectionDelegateFactory();
+  ~DisplaySourceConnectionDelegateFactory() override;
+
+  // BrowserContextKeyedServiceFactory:
+  KeyedService* BuildServiceInstanceFor(
+      content::BrowserContext* browser_context) const override;
+  content::BrowserContext* GetBrowserContextToUse(
+      content::BrowserContext* context) const override;
+  bool ServiceIsCreatedWithBrowserContext() const override;
+  bool ServiceIsNULLWhileTesting() const override;
+
+  DISALLOW_COPY_AND_ASSIGN(DisplaySourceConnectionDelegateFactory);
+};
+
+}  // namespace extensions
+
+#endif  // EXTENSIONS_BROWSER_API_DISPLAY_SOURCE_DISPLAY_SOURCE_CONNECTION_DELEGATE_FACTORY_H_
diff --git a/extensions/browser/api/display_source/display_source_event_router.cc b/extensions/browser/api/display_source/display_source_event_router.cc
new file mode 100644
index 0000000000000..db6f9ab3f1996
--- /dev/null
+++ b/extensions/browser/api/display_source/display_source_event_router.cc
@@ -0,0 +1,100 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "extensions/browser/api/display_source/display_source_event_router.h"
+
+#include "content/public/browser/browser_context.h"
+#include "extensions/browser/api/display_source/display_source_api.h"
+#include "extensions/browser/api/display_source/display_source_connection_delegate_factory.h"
+#include "extensions/common/api/display_source.h"
+
+namespace extensions {
+
+DisplaySourceEventRouter::DisplaySourceEventRouter(
+    content::BrowserContext* browser_context)
+    : browser_context_(browser_context), listening_(false) {
+  EventRouter* event_router = EventRouter::Get(browser_context_);
+  if (!event_router)
+    return;
+  event_router->RegisterObserver(
+      this, api::display_source::OnSinksUpdated::kEventName);
+}
+
+DisplaySourceEventRouter::~DisplaySourceEventRouter() {
+  DCHECK(!listening_);
+}
+
+void DisplaySourceEventRouter::Shutdown() {
+  EventRouter* event_router = EventRouter::Get(browser_context_);
+  if (event_router)
+    event_router->UnregisterObserver(this);
+
+  if (!listening_)
+    return;
+  listening_ = false;
+  DisplaySourceConnectionDelegate* delegate =
+      DisplaySourceConnectionDelegateFactory::GetForBrowserContext(
+          browser_context_);
+  if (delegate)
+    delegate->RemoveObserver(this);
+}
+
+void DisplaySourceEventRouter::OnListenerAdded(
+    const EventListenerInfo& details) {
+  StartOrStopListeningForSinksChanges();
+}
+
+void DisplaySourceEventRouter::OnListenerRemoved(
+    const EventListenerInfo& details) {
+  StartOrStopListeningForSinksChanges();
+}
+
+void DisplaySourceEventRouter::StartOrStopListeningForSinksChanges() {
+  EventRouter* event_router = EventRouter::Get(browser_context_);
+  if (!event_router)
+    return;
+
+  bool should_listen = event_router->HasEventListener(
+      api::display_source::OnSinksUpdated::kEventName);
+  if (should_listen && !listening_) {
+    DisplaySourceConnectionDelegate* delegate =
+        DisplaySourceConnectionDelegateFactory::GetForBrowserContext(
+            browser_context_);
+    if (delegate) {
+      delegate->AddObserver(this);
+      delegate->StartWatchingSinks();
+    }
+  }
+  if (!should_listen && listening_) {
+    DisplaySourceConnectionDelegate* delegate =
+        DisplaySourceConnectionDelegateFactory::GetForBrowserContext(
+            browser_context_);
+    if (delegate) {
+      delegate->RemoveObserver(this);
+      delegate->StopWatchingSinks();
+    }
+  }
+
+  listening_ = should_listen;
+}
+
+void DisplaySourceEventRouter::OnSinksUpdated(
+    const DisplaySourceSinkInfoList& sinks) {
+  EventRouter* event_router = EventRouter::Get(browser_context_);
+  if (!event_router)
+    return;
+  scoped_ptr<base::ListValue> args(
+      api::display_source::OnSinksUpdated::Create(sinks));
+  scoped_ptr<Event> sinks_updated_event(
+      new Event(events::DISPLAY_SOURCE_ON_SINKS_UPDATED,
+                api::display_source::OnSinksUpdated::kEventName, args.Pass()));
+  event_router->BroadcastEvent(sinks_updated_event.Pass());
+}
+
+DisplaySourceEventRouter* DisplaySourceEventRouter::Create(
+    content::BrowserContext* browser_context) {
+  return new DisplaySourceEventRouter(browser_context);
+}
+
+}  // namespace extensions
diff --git a/extensions/browser/api/display_source/display_source_event_router.h b/extensions/browser/api/display_source/display_source_event_router.h
new file mode 100644
index 0000000000000..6697fe80dd60a
--- /dev/null
+++ b/extensions/browser/api/display_source/display_source_event_router.h
@@ -0,0 +1,54 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef EXTENSIONS_BROWSER_API_DISPLAY_SOURCE_DISPLAY_SOURCE_EVENT_ROUTER_H_
+#define EXTENSIONS_BROWSER_API_DISPLAY_SOURCE_DISPLAY_SOURCE_EVENT_ROUTER_H_
+
+#include "base/macros.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "extensions/browser/api/display_source/display_source_connection_delegate.h"
+#include "extensions/browser/event_router.h"
+
+namespace content {
+class BrowserContext;
+}
+
+namespace extensions {
+
+// Observe listeners to 'onSinksUpdated' events.
+class DisplaySourceEventRouter
+    : public KeyedService,
+      public EventRouter::Observer,
+      public DisplaySourceConnectionDelegate::Observer {
+ public:
+  static DisplaySourceEventRouter* Create(
+      content::BrowserContext* browser_context);
+
+  ~DisplaySourceEventRouter() override;
+
+ private:
+  explicit DisplaySourceEventRouter(content::BrowserContext* browser_context);
+
+  // KeyedService overrides:
+  void Shutdown() override;
+
+  // EventRouter::Observer overrides:
+  void OnListenerAdded(const EventListenerInfo& details) override;
+  void OnListenerRemoved(const EventListenerInfo& details) override;
+
+  // DisplaySourceConnectionDelegate::Observer overrides:
+  void OnSinksUpdated(const DisplaySourceSinkInfoList& sinks) override;
+
+ private:
+  void StartOrStopListeningForSinksChanges();
+
+  content::BrowserContext* browser_context_;
+  bool listening_;
+
+  DISALLOW_COPY_AND_ASSIGN(DisplaySourceEventRouter);
+};
+
+}  // namespace extensions
+
+#endif  // EXTENSIONS_BROWSER_API_DISPLAY_SOURCE_DISPLAY_SOURCE_EVENT_ROUTER_H_
diff --git a/extensions/browser/api/display_source/display_source_event_router_factory.cc b/extensions/browser/api/display_source/display_source_event_router_factory.cc
new file mode 100644
index 0000000000000..050159f19f967
--- /dev/null
+++ b/extensions/browser/api/display_source/display_source_event_router_factory.cc
@@ -0,0 +1,59 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "extensions/browser/api/display_source/display_source_event_router_factory.h"
+
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "content/public/browser/browser_context.h"
+#include "extensions/browser/api/display_source/display_source_connection_delegate_factory.h"
+#include "extensions/browser/api/display_source/display_source_event_router.h"
+#include "extensions/browser/extension_system_provider.h"
+#include "extensions/browser/extensions_browser_client.h"
+
+namespace extensions {
+
+// static
+DisplaySourceEventRouter* DisplaySourceEventRouterFactory::GetForProfile(
+    content::BrowserContext* context) {
+  return static_cast<DisplaySourceEventRouter*>(
+      GetInstance()->GetServiceForBrowserContext(context, true));
+}
+
+// static
+DisplaySourceEventRouterFactory*
+DisplaySourceEventRouterFactory::GetInstance() {
+  return base::Singleton<DisplaySourceEventRouterFactory>::get();
+}
+
+DisplaySourceEventRouterFactory::DisplaySourceEventRouterFactory()
+    : BrowserContextKeyedServiceFactory(
+          "DisplaySourceEventRouter",
+          BrowserContextDependencyManager::GetInstance()) {
+  DependsOn(ExtensionsBrowserClient::Get()->GetExtensionSystemFactory());
+  DependsOn(DisplaySourceConnectionDelegateFactory::GetInstance());
+}
+
+DisplaySourceEventRouterFactory::~DisplaySourceEventRouterFactory() {}
+
+KeyedService* DisplaySourceEventRouterFactory::BuildServiceInstanceFor(
+    content::BrowserContext* context) const {
+  return DisplaySourceEventRouter::Create(context);
+}
+
+content::BrowserContext*
+DisplaySourceEventRouterFactory::GetBrowserContextToUse(
+    content::BrowserContext* context) const {
+  return ExtensionsBrowserClient::Get()->GetOriginalContext(context);
+}
+
+bool DisplaySourceEventRouterFactory::ServiceIsCreatedWithBrowserContext()
+    const {
+  return true;
+}
+
+bool DisplaySourceEventRouterFactory::ServiceIsNULLWhileTesting() const {
+  return true;
+}
+
+}  // namespace extensions
diff --git a/extensions/browser/api/display_source/display_source_event_router_factory.h b/extensions/browser/api/display_source/display_source_event_router_factory.h
new file mode 100644
index 0000000000000..7fd777f2cb29b
--- /dev/null
+++ b/extensions/browser/api/display_source/display_source_event_router_factory.h
@@ -0,0 +1,48 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef EXTENSIONS_BROWSER_API_DISPLAY_SOURCE_DISPLAY_SOURCE_EVENT_ROUTER_FACTORY_H_
+#define EXTENSIONS_BROWSER_API_DISPLAY_SOURCE_DISPLAY_SOURCE_EVENT_ROUTER_FACTORY_H_
+
+#include "base/macros.h"
+#include "base/memory/singleton.h"
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+
+namespace extensions {
+
+class DisplaySourceEventRouter;
+
+class DisplaySourceEventRouterFactory
+    : public BrowserContextKeyedServiceFactory {
+ public:
+  // Returns the DisplaySourceEventRouter for |profile|, creating it if
+  // it is not yet created.
+  static DisplaySourceEventRouter* GetForProfile(
+      content::BrowserContext* context);
+
+  static DisplaySourceEventRouterFactory* GetInstance();
+
+ protected:
+  // BrowserContextKeyedBaseFactory overrides:
+  content::BrowserContext* GetBrowserContextToUse(
+      content::BrowserContext* context) const override;
+  bool ServiceIsCreatedWithBrowserContext() const override;
+  bool ServiceIsNULLWhileTesting() const override;
+
+ private:
+  friend struct base::DefaultSingletonTraits<DisplaySourceEventRouterFactory>;
+
+  DisplaySourceEventRouterFactory();
+  ~DisplaySourceEventRouterFactory() override;
+
+  // BrowserContextKeyedServiceFactory:
+  KeyedService* BuildServiceInstanceFor(
+      content::BrowserContext* profile) const override;
+
+  DISALLOW_COPY_AND_ASSIGN(DisplaySourceEventRouterFactory);
+};
+
+}  // namespace extensions
+
+#endif  // EXTENSIONS_BROWSER_API_DISPLAY_SOURCE_DISPLAY_SOURCE_EVENT_ROUTER_FACTORY_H_
diff --git a/extensions/browser/browser_context_keyed_service_factories.cc b/extensions/browser/browser_context_keyed_service_factories.cc
index 8d1061f1f76e1..002c68f796365 100644
--- a/extensions/browser/browser_context_keyed_service_factories.cc
+++ b/extensions/browser/browser_context_keyed_service_factories.cc
@@ -10,6 +10,7 @@
 #include "extensions/browser/api/bluetooth/bluetooth_api.h"
 #include "extensions/browser/api/bluetooth/bluetooth_private_api.h"
 #include "extensions/browser/api/bluetooth_socket/bluetooth_socket_event_dispatcher.h"
+#include "extensions/browser/api/display_source/display_source_event_router_factory.h"
 #include "extensions/browser/api/hid/hid_device_manager.h"
 #include "extensions/browser/api/idle/idle_manager_factory.h"
 #include "extensions/browser/api/management/management_api.h"
@@ -61,6 +62,7 @@ void EnsureBrowserContextKeyedServiceFactoriesBuilt() {
   api::TCPSocketEventDispatcher::GetFactoryInstance();
   api::UDPSocketEventDispatcher::GetFactoryInstance();
   DeclarativeUserScriptManagerFactory::GetInstance();
+  DisplaySourceEventRouterFactory::GetInstance();
   EventRouterFactory::GetInstance();
   ExtensionMessageFilter::EnsureShutdownNotifierFactoryBuilt();
   ExtensionPrefsFactory::GetInstance();
diff --git a/extensions/browser/extension_event_histogram_value.h b/extensions/browser/extension_event_histogram_value.h
index 8a2bf65f29777..6d0b30e4f1db5 100644
--- a/extensions/browser/extension_event_histogram_value.h
+++ b/extensions/browser/extension_event_histogram_value.h
@@ -410,6 +410,7 @@ enum HistogramValue {
   EASY_UNLOCK_PRIVATE_ON_CONNECTION_STATUS_CHANGED,
   EASY_UNLOCK_PRIVATE_ON_DATA_RECEIVED,
   EASY_UNLOCK_PRIVATE_ON_SEND_COMPLETED,
+  DISPLAY_SOURCE_ON_SINKS_UPDATED,
   // Last entry: Add new entries above, then run:
   // python tools/metrics/histograms/update_extension_histograms.py
   ENUM_BOUNDARY
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h
index 1faed633fde4c..7820b7f5a706a 100644
--- a/extensions/browser/extension_function_histogram_value.h
+++ b/extensions/browser/extension_function_histogram_value.h
@@ -1156,6 +1156,8 @@ enum HistogramValue {
   SETTINGSPRIVATE_SETDEFAULTZOOMPERCENTFUNCTION,
   BLUETOOTHPRIVATE_CONNECT,
   BLUETOOTHPRIVATE_FORGETDEVICE,
+  DISPLAYSOURCE_GETAVAILABLESINKS,
+  DISPLAYSOURCE_REQUESTAUTHENTICATION,
   // Last entry: Add new entries above, then run:
   // python tools/metrics/histograms/update_extension_histograms.py
   ENUM_BOUNDARY
diff --git a/extensions/common/api/_api_features.json b/extensions/common/api/_api_features.json
index 540818b0f9090..012d906ac6114 100644
--- a/extensions/common/api/_api_features.json
+++ b/extensions/common/api/_api_features.json
@@ -127,6 +127,10 @@
     "extension_types": ["platform_app"],
     "contexts": ["blessed_extension"]
   },
+  "displaySource": {
+    "dependencies": ["permission:displaySource"],
+    "contexts": ["blessed_extension"]
+  },
   "dns": {
     "dependencies": ["permission:dns"],
     "contexts": ["blessed_extension"]
diff --git a/extensions/common/api/_permission_features.json b/extensions/common/api/_permission_features.json
index c395360a5c86a..ed3e53565ebda 100644
--- a/extensions/common/api/_permission_features.json
+++ b/extensions/common/api/_permission_features.json
@@ -184,6 +184,10 @@
       ]
     }
   ],
+  "displaySource": {
+    "channel": "dev",
+    "extension_types": ["extension", "platform_app"]
+  },
   "dns": [
     {
       "channel": "dev",
diff --git a/extensions/common/api/display_source.idl b/extensions/common/api/display_source.idl
new file mode 100644
index 0000000000000..a3821e3517984
--- /dev/null
+++ b/extensions/common/api/display_source.idl
@@ -0,0 +1,152 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// The <code>chrome.displaySource</code> API creates a Display
+// session using WebMediaStreamTrack as sources.
+namespace displaySource {
+  enum ErrorType {
+    // Cannot create media pipeline from the given media stream which could be
+    // appropriate for a Display session (e.g., necessary codecs are missing
+    // on the platform).
+    create_media_pipeline_error,
+
+    // A new Display session cannot be started before the existing one is
+    // terminated.
+    exceeded_session_limit_error,
+
+    // Could not establish connection to the sink.
+    establish_connection_error,
+
+    // The capabilities of this Display Source and the connected  
+    // sink do not fit (e.g. the sink cannot play the media content of
+    // the formats given by the source).
+    capabilities_negotiation_error,
+
+    // There was an error while packetizing and sending the media content.
+    media_send_error,
+
+    // The TCP connection with sink has dropped unexpectedly.
+    connection_error,
+
+    // An unexpected message has arrived from the sink.
+    unexpected_message_error,
+
+    // The sink became unresponsive.
+    timeout_error,
+
+    // Unspecified error.
+    unknown_error
+  };
+
+  dictionary ErrorInfo {
+    ErrorType type;
+    DOMString? description;
+  };
+
+  enum SinkState {
+    // Connected using this Display Source (i.e., there is an active session)
+    Connected,
+    // In process of connection to this Display Source
+    Connecting,
+    // Disconnected from this Display Source
+    Disconnected
+  };
+
+  dictionary SinkInfo {
+    // Id of the sink. It is guaranteed to be unique during the browser session.
+    long id;
+    // Human readable name of the sink.
+    DOMString name;
+    // State of the sink.
+    SinkState state;
+  };
+
+  enum AuthenticationMethod {
+    // Push Button Config authentication method.
+    PBC,
+    // PIN authentication method.
+    PIN
+  };
+
+  dictionary AuthenticationInfo {
+    // Authentication method.
+    AuthenticationMethod method;
+    // Authentication data (e.g. PIN value).
+    DOMString? data;
+  };
+
+  dictionary StartSessionInfo {
+    // Id of the sink to connect.
+    long sinkId;
+    // Authentication information.
+    AuthenticationInfo? authenticationInfo;
+    // The source audio track.
+    [instanceOf=MediaStreamTrack] object? audioTrack;
+    // The source audio track.
+    [instanceOf=MediaStreamTrack] object? videoTrack;
+  };
+
+  callback GetSinksCallback = void (SinkInfo[] result);
+  callback RequestAuthenticationCallback = void (AuthenticationInfo result);
+  callback TerminateSessionCallback = void ();
+ 
+  interface Functions {
+    // Queries the list of the currently available Display sinks.
+    //
+    // |callback| : Called when the request is completed. The argument list
+    // is empty if no available sinks were found.
+    static void getAvailableSinks(GetSinksCallback callback);
+
+    // Queries authentication data from the sink device.
+    //
+    // |sinkId| : Id of the sink
+    // |callback| : Called when authentication info retrieved from the sink.
+    // The argument |method| field contains the authentication method required
+    // by the sink for connection; the |data| field can be null or can contain
+    // some supplementary data provided by the sink. If authentication info
+    // cannot be retrieved from the sink the "chrome.runtime.lastError" property
+    // is defined.
+    static void requestAuthentication(long sinkId,
+                                      RequestAuthenticationCallback callback);
+
+    // Creates a Display session using the provided StartSessionInfo instance.
+    // The input argument fields must be initialized as described below:
+    // The |sinkId|  must be a valid id of a sink (obtained via
+    // ‘getAvailableSinks’).
+    //
+    // The |audioTrack| or |videoTrack| must be of type MediaStreamTrack.
+    // Either |audioTrack| or |videoTrack| can be null but not both. This
+    // means creating a session with only audio or video.
+    //
+    // The |authenticationInfo| can be null if no additional authentication data
+    // are required by the sink; otherwise its |data| field must contain the
+    // required authentication data (e.g. PIN value) and its |method| field must
+    // be the same as one obtained from ‘requestAuthentication’.
+    [nocompile] static void startSession(StartSessionInfo sessionInfo);
+
+    // Terminates the active Display session.
+    // |sinkId| : Id of the connected sink.
+    // |callback| : Called when the session is terminated.
+    [nocompile] static void terminateSession(
+        long sinkId, optional TerminateSessionCallback callback);
+  };
+
+  interface Events {
+    // Event fired when the available sinks are modified (either their amount
+    // or properties)
+    // |sinks| the list of all currently available sinks
+    static void onSinksUpdated(SinkInfo[] sinks);
+    // Event fired when the Display session is started.
+    // |sinkId| Id of the peer sink
+    [nocompile] static void onSessionStarted(long sinkId);
+    // Event fired when the Display session is terminated.
+    // |sinkId| Id of the peer sink
+    [nocompile] static void onSessionTerminated(long sinkId);
+    // Event fired when an error occurs.
+    // |sinkId| Id of the peer sink
+    // |errorInfo| error description
+    [nocompile] static void onSessionErrorOccured(long sinkId,
+                                                  ErrorInfo errorInfo);
+  };
+};
diff --git a/extensions/common/api/schemas.gypi b/extensions/common/api/schemas.gypi
index 63b8fcf74872e..a661132c4de8e 100644
--- a/extensions/common/api/schemas.gypi
+++ b/extensions/common/api/schemas.gypi
@@ -20,6 +20,7 @@
       'bluetooth_socket.idl',
       'cast_channel.idl',
       'document_scan.idl',
+      'display_source.idl',
       'dns.idl',
       'events.json',
       'extensions_manifest_types.json',
diff --git a/extensions/common/permissions/api_permission.h b/extensions/common/permissions/api_permission.h
index 4f5b38cedc077..5d46ce91f5142 100644
--- a/extensions/common/permissions/api_permission.h
+++ b/extensions/common/permissions/api_permission.h
@@ -243,6 +243,7 @@ class APIPermission {
     kEnterpriseDeviceAttributes,
     kCertificateProvider,
     kResourcesPrivate,
+    kDisplaySource,
     // Last entry: Add new entries above and ensure to update the
     // "ExtensionPermission3" enum in tools/metrics/histograms/histograms.xml
     // (by running update_extension_permission.py).
diff --git a/extensions/common/permissions/extensions_api_permissions.cc b/extensions/common/permissions/extensions_api_permissions.cc
index c9eb11b5e7944..70a667fe6b412 100644
--- a/extensions/common/permissions/extensions_api_permissions.cc
+++ b/extensions/common/permissions/extensions_api_permissions.cc
@@ -54,6 +54,7 @@ std::vector<APIPermissionInfo*> ExtensionsAPIPermissions::GetAllPermissions()
       {APIPermission::kDiagnostics,
        "diagnostics",
        APIPermissionInfo::kFlagCannotBeOptional},
+      {APIPermission::kDisplaySource, "displaySource"},
       {APIPermission::kDns, "dns"},
       {APIPermission::kDocumentScan, "documentScan"},
       {APIPermission::kExtensionView,
diff --git a/extensions/extensions.gypi b/extensions/extensions.gypi
index d963eb3defa3a..3f7ad6c6e6422 100644
--- a/extensions/extensions.gypi
+++ b/extensions/extensions.gypi
@@ -321,6 +321,16 @@
       'browser/api/device_permissions_manager.h',
       'browser/api/device_permissions_prompt.cc',
       'browser/api/device_permissions_prompt.h',
+      'browser/api/display_source/display_source_api.cc',
+      'browser/api/display_source/display_source_api.h',
+      'browser/api/display_source/display_source_connection_delegate.cc',
+      'browser/api/display_source/display_source_connection_delegate.h',
+      'browser/api/display_source/display_source_connection_delegate_factory.cc',
+      'browser/api/display_source/display_source_connection_delegate_factory.h',
+      'browser/api/display_source/display_source_event_router.cc',
+      'browser/api/display_source/display_source_event_router_factory.cc',
+      'browser/api/display_source/display_source_event_router_factory.h',
+      'browser/api/display_source/display_source_event_router.h',
       'browser/api/dns/dns_api.cc',
       'browser/api/dns/dns_api.h',
       'browser/api/dns/host_resolver_wrapper.cc',
diff --git a/extensions/extensions_tests.gypi b/extensions/extensions_tests.gypi
index aab657003e92d..687586048507b 100644
--- a/extensions/extensions_tests.gypi
+++ b/extensions/extensions_tests.gypi
@@ -7,6 +7,7 @@
     'extensions_browsertests_sources': [
       'browser/api/audio/audio_apitest.cc',
       'browser/api/bluetooth_socket/bluetooth_socket_apitest.cc',
+      'browser/api/display_source/display_source_apitest.cc',
       'browser/api/dns/dns_apitest.cc',
       'browser/api/hid/hid_apitest.cc',
       'browser/api/printer_provider/printer_provider_apitest.cc',
diff --git a/extensions/test/data/api_test/display_source/api/background.js b/extensions/test/data/api_test/display_source/api/background.js
new file mode 100644
index 0000000000000..a54d6b5ea05a1
--- /dev/null
+++ b/extensions/test/data/api_test/display_source/api/background.js
@@ -0,0 +1,39 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var testGetAvailableSinks = function() {
+  var callback = function(sinks) {
+    chrome.test.assertEq(1, sinks.length);
+    var sink = sinks[0];
+    chrome.test.assertEq(1, sink.id);
+    chrome.test.assertEq("Disconnected", sink.state);
+    chrome.test.assertEq("sink 1", sink.name);
+    chrome.test.succeed("GetAvailableSinks succeded");
+  };
+  chrome.displaySource.getAvailableSinks(callback);
+};
+
+var testOnSinksUpdated = function() {
+  var callback = function(sinks) {
+    chrome.test.assertEq(2, sinks.length);
+    var sink = sinks[1];
+    chrome.test.assertEq(2, sink.id);
+    chrome.test.assertEq("Disconnected", sink.state);
+    chrome.test.assertEq("sink 2", sink.name);
+    chrome.test.succeed("onSinksUpdated event delivered");
+  };
+  chrome.displaySource.onSinksUpdated.addListener(callback);
+};
+
+var testRequestAuthentication = function() {
+  var callback = function(auth_info) {
+    chrome.test.assertEq("PBC", auth_info.method);
+    chrome.test.succeed("RequestAuthentication succeded");
+  };
+  chrome.displaySource.requestAuthentication(1, callback);
+};
+
+chrome.test.runTests([testGetAvailableSinks,
+                      testOnSinksUpdated,
+                      testRequestAuthentication]);
diff --git a/extensions/test/data/api_test/display_source/api/manifest.json b/extensions/test/data/api_test/display_source/api/manifest.json
new file mode 100644
index 0000000000000..c390d3ccabf8e
--- /dev/null
+++ b/extensions/test/data/api_test/display_source/api/manifest.json
@@ -0,0 +1,12 @@
+{
+  "name": "chrome.displaySource",
+  "version": "0.1",
+  "description": "end-to-end browser test for chrome.displaySource API",
+  "app": {
+    "background": {
+      "scripts": ["background.js"]
+    }
+  },
+  "permissions": ["displaySource"]
+}
+
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 926604419c8c7..0d99c05574f6b 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -59445,6 +59445,7 @@ http://cs/file:chrome/histograms.xml - but prefer this file for new entries.
   <int value="389" label="EASY_UNLOCK_PRIVATE_ON_CONNECTION_STATUS_CHANGED"/>
   <int value="390" label="EASY_UNLOCK_PRIVATE_ON_DATA_RECEIVED"/>
   <int value="391" label="EASY_UNLOCK_PRIVATE_ON_SEND_COMPLETED"/>
+  <int value="392" label="DISPLAY_SOURCE_ON_SINKS_UPDATED"/>
 </enum>
 
 <enum name="ExtensionFileWriteResult" type="int">
@@ -60588,6 +60589,8 @@ http://cs/file:chrome/histograms.xml - but prefer this file for new entries.
   <int value="1095" label="SETTINGSPRIVATE_SETDEFAULTZOOMPERCENTFUNCTION"/>
   <int value="1096" label="BLUETOOTHPRIVATE_CONNECT"/>
   <int value="1097" label="BLUETOOTHPRIVATE_FORGETDEVICE"/>
+  <int value="1098" label="DISPLAYSOURCE_GETAVAILABLESINKS"/>
+  <int value="1099" label="DISPLAYSOURCE_REQUESTAUTHENTICATION"/>
 </enum>
 
 <enum name="ExtensionInstallCause" type="int">