• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "libcef/browser/audio_loopback_stream_creator.h"
6 
7 #include <memory>
8 #include <utility>
9 
10 #include "base/bind.h"
11 #include "base/check_op.h"
12 #include "base/location.h"
13 #include "content/browser/browser_main_loop.h"
14 #include "content/browser/web_contents/web_contents_impl.h"
15 #include "content/public/browser/browser_task_traits.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "content/public/browser/render_frame_host.h"
18 #include "media/audio/audio_device_description.h"
19 #include "media/base/user_input_monitor.h"
20 #include "mojo/public/cpp/bindings/pending_remote.h"
21 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
22 #include "third_party/blink/public/mojom/media/renderer_audio_input_stream_factory.mojom.h"
23 
24 namespace {
25 
26 // A blink::mojom::RendererAudioInputStreamFactoryClient that holds a
27 // CefAudioLoopbackStreamCreator::StreamCreatedCallback. The callback runs when
28 // the requested audio stream is created.
29 class StreamCreatedCallbackAdapter final
30     : public blink::mojom::RendererAudioInputStreamFactoryClient {
31  public:
StreamCreatedCallbackAdapter(const CefAudioLoopbackStreamCreator::StreamCreatedCallback & callback)32   explicit StreamCreatedCallbackAdapter(
33       const CefAudioLoopbackStreamCreator::StreamCreatedCallback& callback)
34       : callback_(callback) {
35     DCHECK(callback_);
36   }
37 
38   StreamCreatedCallbackAdapter(const StreamCreatedCallbackAdapter&) = delete;
39   StreamCreatedCallbackAdapter& operator=(const StreamCreatedCallbackAdapter&) =
40       delete;
41 
~StreamCreatedCallbackAdapter()42   ~StreamCreatedCallbackAdapter() override {}
43 
44   // blink::mojom::RendererAudioInputStreamFactoryClient implementation.
StreamCreated(mojo::PendingRemote<media::mojom::AudioInputStream> stream,mojo::PendingReceiver<media::mojom::AudioInputStreamClient> client_receiver,media::mojom::ReadOnlyAudioDataPipePtr data_pipe,bool initially_muted,const absl::optional<base::UnguessableToken> & stream_id)45   void StreamCreated(
46       mojo::PendingRemote<media::mojom::AudioInputStream> stream,
47       mojo::PendingReceiver<media::mojom::AudioInputStreamClient>
48           client_receiver,
49       media::mojom::ReadOnlyAudioDataPipePtr data_pipe,
50       bool initially_muted,
51       const absl::optional<base::UnguessableToken>& stream_id) override {
52     DCHECK(!initially_muted);  // Loopback streams shouldn't be started muted.
53     callback_.Run(std::move(stream), std::move(client_receiver),
54                   std::move(data_pipe));
55   }
56 
57  private:
58   const CefAudioLoopbackStreamCreator::StreamCreatedCallback callback_;
59 };
60 
CreateLoopbackStreamHelper(content::ForwardingAudioStreamFactory::Core * factory,content::AudioStreamBroker::LoopbackSource * loopback_source,const media::AudioParameters & params,uint32_t total_segments,mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient> client_remote)61 void CreateLoopbackStreamHelper(
62     content::ForwardingAudioStreamFactory::Core* factory,
63     content::AudioStreamBroker::LoopbackSource* loopback_source,
64     const media::AudioParameters& params,
65     uint32_t total_segments,
66     mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
67         client_remote) {
68   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
69 
70   const bool mute_source = true;
71   factory->CreateLoopbackStream(-1, -1, loopback_source, params, total_segments,
72                                 mute_source, std::move(client_remote));
73 }
74 
CreateSystemWideLoopbackStreamHelper(content::ForwardingAudioStreamFactory::Core * factory,const media::AudioParameters & params,uint32_t total_segments,mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient> client_remote)75 void CreateSystemWideLoopbackStreamHelper(
76     content::ForwardingAudioStreamFactory::Core* factory,
77     const media::AudioParameters& params,
78     uint32_t total_segments,
79     mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
80         client_remote) {
81   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
82 
83   const bool enable_agc = false;
84   factory->CreateInputStream(
85       -1, -1, media::AudioDeviceDescription::kLoopbackWithMuteDeviceId, params,
86       total_segments, enable_agc, std::move(client_remote));
87 }
88 
89 }  // namespace
90 
CefAudioLoopbackStreamCreator()91 CefAudioLoopbackStreamCreator::CefAudioLoopbackStreamCreator()
92     : factory_(nullptr,
93                content::BrowserMainLoop::GetInstance()
94                    ? static_cast<media::UserInputMonitorBase*>(
95                          content::BrowserMainLoop::GetInstance()
96                              ->user_input_monitor())
97                    : nullptr,
98                content::AudioStreamBrokerFactory::CreateImpl()) {
99   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
100 }
101 
~CefAudioLoopbackStreamCreator()102 CefAudioLoopbackStreamCreator::~CefAudioLoopbackStreamCreator() {
103   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
104 }
105 
CreateLoopbackStream(content::WebContents * loopback_source,const media::AudioParameters & params,uint32_t total_segments,const StreamCreatedCallback & callback)106 void CefAudioLoopbackStreamCreator::CreateLoopbackStream(
107     content::WebContents* loopback_source,
108     const media::AudioParameters& params,
109     uint32_t total_segments,
110     const StreamCreatedCallback& callback) {
111   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
112   mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
113       client;
114   mojo::MakeSelfOwnedReceiver(
115       std::make_unique<StreamCreatedCallbackAdapter>(callback),
116       client.InitWithNewPipeAndPassReceiver());
117   // Deletion of factory_.core() is posted to the IO thread when |factory_| is
118   // destroyed, so Unretained is safe below.
119   if (loopback_source) {
120     content::GetIOThreadTaskRunner({})->PostTask(
121         FROM_HERE,
122         base::BindOnce(&CreateLoopbackStreamHelper, factory_.core(),
123                        static_cast<content::WebContentsImpl*>(loopback_source)
124                            ->GetAudioStreamFactory()
125                            ->core(),
126                        params, total_segments, std::move(client)));
127     return;
128   }
129   // A null |frame_of_source_web_contents| requests system-wide loopback.
130   content::GetIOThreadTaskRunner({})->PostTask(
131       FROM_HERE,
132       base::BindOnce(&CreateSystemWideLoopbackStreamHelper, factory_.core(),
133                      params, total_segments, std::move(client)));
134 }
135