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