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
~StreamCreatedCallbackAdapter()38 ~StreamCreatedCallbackAdapter() override {}
39
40 // 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 base::Optional<base::UnguessableToken> & stream_id)41 void StreamCreated(
42 mojo::PendingRemote<media::mojom::AudioInputStream> stream,
43 mojo::PendingReceiver<media::mojom::AudioInputStreamClient>
44 client_receiver,
45 media::mojom::ReadOnlyAudioDataPipePtr data_pipe,
46 bool initially_muted,
47 const base::Optional<base::UnguessableToken>& stream_id) override {
48 DCHECK(!initially_muted); // Loopback streams shouldn't be started muted.
49 callback_.Run(std::move(stream), std::move(client_receiver),
50 std::move(data_pipe));
51 }
52
53 private:
54 const CefAudioLoopbackStreamCreator::StreamCreatedCallback callback_;
55
56 DISALLOW_COPY_AND_ASSIGN(StreamCreatedCallbackAdapter);
57 };
58
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)59 void CreateLoopbackStreamHelper(
60 content::ForwardingAudioStreamFactory::Core* factory,
61 content::AudioStreamBroker::LoopbackSource* loopback_source,
62 const media::AudioParameters& params,
63 uint32_t total_segments,
64 mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
65 client_remote) {
66 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
67
68 const bool mute_source = true;
69 factory->CreateLoopbackStream(-1, -1, loopback_source, params, total_segments,
70 mute_source, std::move(client_remote));
71 }
72
CreateSystemWideLoopbackStreamHelper(content::ForwardingAudioStreamFactory::Core * factory,const media::AudioParameters & params,uint32_t total_segments,mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient> client_remote)73 void CreateSystemWideLoopbackStreamHelper(
74 content::ForwardingAudioStreamFactory::Core* factory,
75 const media::AudioParameters& params,
76 uint32_t total_segments,
77 mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
78 client_remote) {
79 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
80
81 const bool enable_agc = false;
82 factory->CreateInputStream(
83 -1, -1, media::AudioDeviceDescription::kLoopbackWithMuteDeviceId, params,
84 total_segments, enable_agc, std::move(client_remote));
85 }
86
87 } // namespace
88
CefAudioLoopbackStreamCreator()89 CefAudioLoopbackStreamCreator::CefAudioLoopbackStreamCreator()
90 : factory_(nullptr,
91 content::BrowserMainLoop::GetInstance()
92 ? static_cast<media::UserInputMonitorBase*>(
93 content::BrowserMainLoop::GetInstance()
94 ->user_input_monitor())
95 : nullptr,
96 content::AudioStreamBrokerFactory::CreateImpl()) {
97 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
98 }
99
~CefAudioLoopbackStreamCreator()100 CefAudioLoopbackStreamCreator::~CefAudioLoopbackStreamCreator() {
101 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
102 }
103
CreateLoopbackStream(content::WebContents * loopback_source,const media::AudioParameters & params,uint32_t total_segments,const StreamCreatedCallback & callback)104 void CefAudioLoopbackStreamCreator::CreateLoopbackStream(
105 content::WebContents* loopback_source,
106 const media::AudioParameters& params,
107 uint32_t total_segments,
108 const StreamCreatedCallback& callback) {
109 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
110 mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
111 client;
112 mojo::MakeSelfOwnedReceiver(
113 std::make_unique<StreamCreatedCallbackAdapter>(callback),
114 client.InitWithNewPipeAndPassReceiver());
115 // Deletion of factory_.core() is posted to the IO thread when |factory_| is
116 // destroyed, so Unretained is safe below.
117 if (loopback_source) {
118 content::GetIOThreadTaskRunner({})->PostTask(
119 FROM_HERE,
120 base::BindOnce(&CreateLoopbackStreamHelper, factory_.core(),
121 static_cast<content::WebContentsImpl*>(loopback_source)
122 ->GetAudioStreamFactory()
123 ->core(),
124 params, total_segments, std::move(client)));
125 return;
126 }
127 // A null |frame_of_source_web_contents| requests system-wide loopback.
128 content::GetIOThreadTaskRunner({})->PostTask(
129 FROM_HERE,
130 base::BindOnce(&CreateSystemWideLoopbackStreamHelper, factory_.core(),
131 params, total_segments, std::move(client)));
132 }
133