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.
5 #include "content/browser/renderer_host/media/render_frame_audio_input_stream_factory.h"
10 #include "base/trace_event/trace_event.h"
11 #include "content/browser/browser_main_loop.h"
12 #include "content/browser/media/capture/desktop_capture_device_uma_types.h"
13 #include "content/browser/media/forwarding_audio_stream_factory.h"
14 #include "content/browser/media/media_devices_permission_checker.h"
15 #include "content/browser/renderer_host/media/media_stream_manager.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "content/public/browser/media_device_id.h"
18 #include "content/public/browser/render_frame_host.h"
19 #include "content/public/browser/render_process_host.h"
20 #include "content/public/browser/web_contents_media_capture_id.h"
21 #include "content/public/common/media_stream_request.h"
22 #include "media/audio/audio_device_description.h"
23 #include "media/audio/audio_input_device.h"
24 #include "media/base/audio_parameters.h"
30 void LookUpDeviceAndRespondIfFound(
31 scoped_refptr<AudioInputDeviceManager> audio_input_device_manager,
33 base::OnceCallback<void(const MediaStreamDevice&)> response) {
34 DCHECK_CURRENTLY_ON(BrowserThread::IO);
35 const MediaStreamDevice* device =
36 audio_input_device_manager->GetOpenedDeviceById(session_id);
39 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
40 base::BindOnce(std::move(response), *device));
44 void EnumerateOutputDevices(MediaStreamManager* media_stream_manager,
45 MediaDevicesManager::EnumerationCallback cb) {
46 DCHECK_CURRENTLY_ON(BrowserThread::IO);
47 MediaDevicesManager::BoolDeviceTypes device_types;
48 device_types[MEDIA_DEVICE_TYPE_AUDIO_OUTPUT] = true;
49 media_stream_manager->media_devices_manager()->EnumerateDevices(
50 device_types, std::move(cb));
53 void TranslateDeviceId(const std::string& device_id,
54 const MediaDeviceSaltAndOrigin& salt_and_origin,
55 base::RepeatingCallback<void(const std::string&)> cb,
56 const MediaDeviceEnumeration& device_array) {
57 DCHECK_CURRENTLY_ON(BrowserThread::IO);
58 for (const auto& device_info : device_array[MEDIA_DEVICE_TYPE_AUDIO_OUTPUT]) {
59 if (MediaStreamManager::DoesMediaDeviceIDMatchHMAC(
60 salt_and_origin.device_id_salt, salt_and_origin.origin, device_id,
61 device_info.device_id)) {
62 BrowserThread::PostTask(
63 BrowserThread::UI, FROM_HERE,
64 base::BindOnce(std::move(cb), device_info.device_id));
68 // If we're unable to translate the device id, |cb| will not be run.
73 RenderFrameAudioInputStreamFactory::RenderFrameAudioInputStreamFactory(
74 mojom::RendererAudioInputStreamFactoryRequest request,
75 scoped_refptr<AudioInputDeviceManager> audio_input_device_manager,
76 RenderFrameHost* render_frame_host)
77 : binding_(this, std::move(request)),
78 audio_input_device_manager_(std::move(audio_input_device_manager)),
79 render_frame_host_(render_frame_host),
80 weak_ptr_factory_(this) {
81 DCHECK_CURRENTLY_ON(BrowserThread::UI);
84 RenderFrameAudioInputStreamFactory::~RenderFrameAudioInputStreamFactory() {
85 DCHECK_CURRENTLY_ON(BrowserThread::UI);
88 void RenderFrameAudioInputStreamFactory::CreateStream(
89 mojom::RendererAudioInputStreamFactoryClientPtr client,
91 const media::AudioParameters& audio_params,
92 bool automatic_gain_control,
93 uint32_t shared_memory_count) {
94 DCHECK_CURRENTLY_ON(BrowserThread::UI);
95 TRACE_EVENT_INSTANT1("audio",
96 "RenderFrameAudioInputStreamFactory::CreateStream",
97 TRACE_EVENT_SCOPE_THREAD, "session id", session_id);
99 BrowserThread::PostTask(
100 BrowserThread::IO, FROM_HERE,
102 &LookUpDeviceAndRespondIfFound, audio_input_device_manager_,
104 base::BindOnce(&RenderFrameAudioInputStreamFactory::
105 CreateStreamAfterLookingUpDevice,
106 weak_ptr_factory_.GetWeakPtr(), std::move(client),
107 audio_params, automatic_gain_control,
108 shared_memory_count)));
111 void RenderFrameAudioInputStreamFactory::CreateStreamAfterLookingUpDevice(
112 mojom::RendererAudioInputStreamFactoryClientPtr client,
113 const media::AudioParameters& audio_params,
114 bool automatic_gain_control,
115 uint32_t shared_memory_count,
116 const MediaStreamDevice& device) {
119 "RenderFrameAudioInputStreamFactory::CreateStreamAfterLookingUpDevice",
120 "device id", device.id);
121 DCHECK_CURRENTLY_ON(BrowserThread::UI);
122 ForwardingAudioStreamFactory* factory =
123 ForwardingAudioStreamFactory::ForFrame(render_frame_host_);
127 WebContentsMediaCaptureId capture_id;
128 if (WebContentsMediaCaptureId::Parse(device.id, &capture_id)) {
129 // For MEDIA_DESKTOP_AUDIO_CAPTURE, the source is selected from picker
130 // window, we do not mute the source audio.
131 // For MEDIA_TAB_AUDIO_CAPTURE, the probable use case is Cast, we mute
133 // TODO(qiangchen): Analyze audio constraints to make a duplicating or
134 // diverting decision. It would give web developer more flexibility.
136 RenderFrameHost* source_host = RenderFrameHost::FromID(
137 capture_id.render_process_id, capture_id.main_render_frame_id);
139 // The source of the capture has already been destroyed, so fail early.
143 factory->CreateLoopbackStream(
144 render_frame_host_, source_host, audio_params, shared_memory_count,
145 capture_id.disable_local_echo, std::move(client));
147 if (device.type == MEDIA_DESKTOP_AUDIO_CAPTURE)
148 IncrementDesktopCaptureCounter(SYSTEM_LOOPBACK_AUDIO_CAPTURER_CREATED);
150 factory->CreateInputStream(render_frame_host_, device.id, audio_params,
151 shared_memory_count, automatic_gain_control,
154 // Only count for captures from desktop media picker dialog and system loop
156 if (device.type == MEDIA_DESKTOP_AUDIO_CAPTURE &&
157 (media::AudioDeviceDescription::IsLoopbackDevice(device.id))) {
158 IncrementDesktopCaptureCounter(SYSTEM_LOOPBACK_AUDIO_CAPTURER_CREATED);
163 void RenderFrameAudioInputStreamFactory::AssociateInputAndOutputForAec(
164 const base::UnguessableToken& input_stream_id,
165 const std::string& output_device_id) {
166 DCHECK_CURRENTLY_ON(BrowserThread::UI);
167 if (!IsValidDeviceId(output_device_id))
170 ForwardingAudioStreamFactory* factory =
171 ForwardingAudioStreamFactory::ForFrame(render_frame_host_);
175 const int process_id = render_frame_host_->GetProcess()->GetID();
176 const int frame_id = render_frame_host_->GetRoutingID();
177 auto salt_and_origin = GetMediaDeviceSaltAndOrigin(process_id, frame_id);
179 // Check permissions for everything but the default device
180 if (!media::AudioDeviceDescription::IsDefaultDevice(output_device_id) &&
181 !MediaDevicesPermissionChecker().CheckPermissionOnUIThread(
182 MEDIA_DEVICE_TYPE_AUDIO_OUTPUT, process_id, frame_id)) {
186 if (media::AudioDeviceDescription::IsDefaultDevice(output_device_id) ||
187 media::AudioDeviceDescription::IsCommunicationsDevice(output_device_id)) {
188 factory->AssociateInputAndOutputForAec(input_stream_id, output_device_id);
190 auto* media_stream_manager =
191 BrowserMainLoop::GetInstance()->media_stream_manager();
192 BrowserThread::PostTask(
193 BrowserThread::IO, FROM_HERE,
195 EnumerateOutputDevices, media_stream_manager,
197 &TranslateDeviceId, output_device_id, salt_and_origin,
198 base::BindRepeating(&RenderFrameAudioInputStreamFactory::
199 AssociateTranslatedOutputDeviceForAec,
200 weak_ptr_factory_.GetWeakPtr(),
205 void RenderFrameAudioInputStreamFactory::AssociateTranslatedOutputDeviceForAec(
206 const base::UnguessableToken& input_stream_id,
207 const std::string& raw_output_device_id) {
208 DCHECK_CURRENTLY_ON(BrowserThread::UI);
209 ForwardingAudioStreamFactory* factory =
210 ForwardingAudioStreamFactory::ForFrame(render_frame_host_);
212 factory->AssociateInputAndOutputForAec(input_stream_id,
213 raw_output_device_id);
216 } // namespace content