blob: 608b5e36eb7263566862545c2486e530b16aed55 [file] [log] [blame]
Avi Drissman4e1b7bc32022-09-15 14:03:501// Copyright 2019 The Chromium Authors
Ken Rockot72964402019-12-06 10:40:512// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "content/public/browser/audio_service.h"
6
David Sanders6f0eeb02025-01-30 06:48:507#include "base/auto_reset.h"
Ken Rockot72964402019-12-06 10:40:518#include "base/command_line.h"
Ken Rockot72964402019-12-06 10:40:519#include "base/metrics/field_trial_params.h"
Douglas Wong6961d232022-10-07 17:19:0110#include "base/strings/strcat.h"
Ken Rockot72964402019-12-06 10:40:5111#include "base/strings/string_number_conversions.h"
Patrick Monette643cdf62021-10-15 19:13:4212#include "base/task/deferred_sequenced_task_runner.h"
Ken Rockot72964402019-12-06 10:40:5113#include "base/threading/sequence_local_storage_slot.h"
14#include "base/time/time.h"
15#include "build/build_config.h"
16#include "content/browser/browser_main_loop.h"
17#include "content/public/browser/browser_task_traits.h"
18#include "content/public/browser/browser_thread.h"
19#include "content/public/browser/content_browser_client.h"
20#include "content/public/browser/service_process_host.h"
21#include "content/public/common/content_client.h"
22#include "content/public/common/content_features.h"
23#include "content/public/common/content_switches.h"
24#include "media/audio/audio_manager.h"
25#include "media/base/media_switches.h"
Roy Funderburkb7cbf5a92022-11-10 19:10:1126#include "media/media_buildflags.h"
Ken Rockot72964402019-12-06 10:40:5127#include "mojo/public/cpp/bindings/remote.h"
28#include "services/audio/public/cpp/audio_system_to_service_adapter.h"
Alex Goughec5693892021-10-12 00:55:4429#include "services/audio/public/mojom/audio_service.mojom.h"
Ken Rockot72964402019-12-06 10:40:5130#include "services/audio/service.h"
31#include "services/audio/service_factory.h"
32
Roy Funderburkb7cbf5a92022-11-10 19:10:1133#if BUILDFLAG(ENABLE_PASSTHROUGH_AUDIO_CODECS)
Roy Funderburk32f66f6b2022-10-25 02:46:2834#include "ui/display/util/edid_parser.h"
Roy Funderburkb7cbf5a92022-11-10 19:10:1135
36#if BUILDFLAG(IS_LINUX)
37#include "ui/display/display_util.h"
38#endif // BUILDFLAG(IS_LINUX)
39
40#if BUILDFLAG(IS_WIN)
Roy Funderburk32f66f6b2022-10-25 02:46:2841#include "ui/display/win/audio_edid_scan.h"
Roy Funderburkb7cbf5a92022-11-10 19:10:1142#endif // BUILDFLAG(IS_WIN)
43#endif // BUILDFLAG(ENABLE_PASSTHROUGH_AUDIO_CODECS)
Douglas Wong6961d232022-10-07 17:19:0144
Ken Rockot72964402019-12-06 10:40:5145namespace content {
46
47namespace {
48
ahmedmoussaf16c8c92023-12-12 09:33:4049audio::mojom::AudioService* g_service_override = nullptr;
50
Ken Rockot72964402019-12-06 10:40:5151bool IsAudioServiceOutOfProcess() {
Lei Lid9d7df42020-03-27 04:33:2352 return !base::CommandLine::ForCurrentProcess()->HasSwitch(
53 switches::kSingleProcess) &&
54 base::FeatureList::IsEnabled(features::kAudioServiceOutOfProcess) &&
Ken Rockot72964402019-12-06 10:40:5155 !GetContentClient()->browser()->OverridesAudioManager();
56}
57
58void BindSystemInfoFromAnySequence(
59 mojo::PendingReceiver<audio::mojom::SystemInfo> receiver) {
60 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
Gabriel Charettee7cdc5cd2020-05-27 23:35:0561 GetUIThreadTaskRunner({})->PostTask(
62 FROM_HERE,
Ken Rockot72964402019-12-06 10:40:5163 base::BindOnce(&BindSystemInfoFromAnySequence, std::move(receiver)));
64 return;
65 }
66
67 GetAudioService().BindSystemInfo(std::move(receiver));
68}
69
70void BindStreamFactoryFromAnySequence(
Katie Dektare87ac2e2021-03-03 01:05:5871 mojo::PendingReceiver<media::mojom::AudioStreamFactory> receiver) {
Ken Rockot72964402019-12-06 10:40:5172 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
Gabriel Charettee7cdc5cd2020-05-27 23:35:0573 GetUIThreadTaskRunner({})->PostTask(
74 FROM_HERE,
Ken Rockot72964402019-12-06 10:40:5175 base::BindOnce(&BindStreamFactoryFromAnySequence, std::move(receiver)));
76 return;
77 }
78
79 GetAudioService().BindStreamFactory(std::move(receiver));
80}
81
82void LaunchAudioServiceInProcess(
Roy Funderburkb7cbf5a92022-11-10 19:10:1183 mojo::PendingReceiver<audio::mojom::AudioService> receiver) {
Ken Rockot72964402019-12-06 10:40:5184 // NOTE: If BrowserMainLoop is uninitialized, we have no AudioManager. In
85 // this case we discard the receiver. The remote will always discard
86 // messages. This is to work around unit testing environments where no
87 // BrowserMainLoop is initialized.
88 if (!BrowserMainLoop::GetInstance())
89 return;
90
Georg Neis35ff854b2024-12-17 02:02:0891#if BUILDFLAG(IS_CHROMEOS) && BUILDFLAG(USE_CRAS)
Simon Hangl90a481c12023-02-22 13:45:4692 if (GetContentClient()->browser()->EnforceSystemAudioEchoCancellation()) {
93 base::CommandLine::ForCurrentProcess()->AppendSwitch(
94 switches::kSystemAecEnabled);
95 }
Georg Neis35ff854b2024-12-17 02:02:0896#endif // BUILDFLAG(IS_CHROMEOS) && BUILDFLAG(USE_CRAS)
Simon Hangl90a481c12023-02-22 13:45:4697
Alison Gale53c77f62024-04-22 15:16:2798 // TODO(crbug.com/40580951): Remove
Ken Rockot72964402019-12-06 10:40:5199 // BrowserMainLoop::GetAudioManager().
100 audio::Service::GetInProcessTaskRunner()->PostTask(
101 FROM_HERE,
102 base::BindOnce(
103 [](media::AudioManager* audio_manager,
104 mojo::PendingReceiver<audio::mojom::AudioService> receiver) {
Avi Drissmanded77172021-07-02 18:23:00105 static base::SequenceLocalStorageSlot<
106 std::unique_ptr<audio::Service>>
Ken Rockot72964402019-12-06 10:40:51107 service;
Avi Drissmanded77172021-07-02 18:23:00108 service.GetOrCreateValue() = audio::CreateEmbeddedService(
Ken Rockot72964402019-12-06 10:40:51109 audio_manager, std::move(receiver));
110 },
111 BrowserMainLoop::GetAudioManager(), std::move(receiver)));
112}
113
114void LaunchAudioServiceOutOfProcess(
Douglas Wong6961d232022-10-07 17:19:01115 mojo::PendingReceiver<audio::mojom::AudioService> receiver,
116 uint32_t codec_bitmask) {
117 std::vector<std::string> switches;
118#if BUILDFLAG(IS_MAC)
119 // On Mac, the audio service requires a CFRunLoop provided by a
120 // UI MessageLoop type, to run AVFoundation and CoreAudio code.
121 // See https://crbug.com/834581.
122 switches.push_back(switches::kMessageLoopTypeUi);
123#elif BUILDFLAG(IS_WIN)
124 if (GetContentClient()->browser()->ShouldEnableAudioProcessHighPriority())
125 switches.push_back(switches::kAudioProcessHighPriority);
Roy Funderburkb7cbf5a92022-11-10 19:10:11126#endif // BUILDFLAG(IS_WIN)
127#if BUILDFLAG(ENABLE_PASSTHROUGH_AUDIO_CODECS)
Douglas Wong6961d232022-10-07 17:19:01128 switches.push_back(base::StrCat({switches::kAudioCodecsFromEDID, "=",
129 base::NumberToString(codec_bitmask)}));
Roy Funderburkb7cbf5a92022-11-10 19:10:11130#endif // BUILDFLAG(ENABLE_PASSTHROUGH_AUDIO_CODECS)
Georg Neis35ff854b2024-12-17 02:02:08131#if BUILDFLAG(IS_CHROMEOS) && BUILDFLAG(USE_CRAS)
Simon Hangl90a481c12023-02-22 13:45:46132 if (GetContentClient()->browser()->EnforceSystemAudioEchoCancellation()) {
133 switches.push_back(switches::kSystemAecEnabled);
134 }
Georg Neis81f9d7f42024-08-06 02:43:45135#endif // BUILDFLAG(IS_CHROMEOS) && BUILDFLAG(USE_CRAS)
Ken Rockot72964402019-12-06 10:40:51136 ServiceProcessHost::Launch(
137 std::move(receiver),
138 ServiceProcessHost::Options()
139 .WithDisplayName("Audio Service")
Douglas Wong6961d232022-10-07 17:19:01140 .WithExtraCommandLineSwitches(std::move(switches))
Ken Rockot72964402019-12-06 10:40:51141 .Pass());
142}
143
Douglas Wong6961d232022-10-07 17:19:01144void LaunchAudioService(
145 mojo::PendingReceiver<audio::mojom::AudioService> receiver,
146 uint32_t codec_bitmask) {
147 // The static storage slot in GetAudioService() prevents LaunchAudioService
148 // from being called more than once.
Ken Rockot72964402019-12-06 10:40:51149 if (IsAudioServiceOutOfProcess()) {
Douglas Wong6961d232022-10-07 17:19:01150 LaunchAudioServiceOutOfProcess(std::move(receiver), codec_bitmask);
Ken Rockot72964402019-12-06 10:40:51151 } else {
Roy Funderburkb7cbf5a92022-11-10 19:10:11152 LaunchAudioServiceInProcess(std::move(receiver));
Ken Rockot72964402019-12-06 10:40:51153 }
Ken Rockot72964402019-12-06 10:40:51154}
155
Roy Funderburkb7cbf5a92022-11-10 19:10:11156#if BUILDFLAG(ENABLE_PASSTHROUGH_AUDIO_CODECS)
Roy Funderburk32f66f6b2022-10-25 02:46:28157// Convert the EDID supported audio bitstream formats into media codec bitmasks.
Roy Funderburkb7cbf5a92022-11-10 19:10:11158uint32_t ConvertEdidBitstreams(uint32_t formats) {
Roy Funderburk32f66f6b2022-10-25 02:46:28159 uint32_t codec_bitmask = 0;
Roy Funderburk32f66f6b2022-10-25 02:46:28160 if (formats & display::EdidParser::kAudioBitstreamPcmLinear)
161 codec_bitmask |= media::AudioParameters::AUDIO_PCM_LINEAR;
162 if (formats & display::EdidParser::kAudioBitstreamDts)
163 codec_bitmask |= media::AudioParameters::AUDIO_BITSTREAM_DTS;
164 if (formats & display::EdidParser::kAudioBitstreamDtsHd)
165 codec_bitmask |= media::AudioParameters::AUDIO_BITSTREAM_DTS_HD;
166 return codec_bitmask;
167}
Roy Funderburkb7cbf5a92022-11-10 19:10:11168
169#if BUILDFLAG(IS_WIN)
170// Convert the EDID supported audio bitstream formats into media codec bitmasks.
171uint32_t ScanEdidBitstreams() {
172 return ConvertEdidBitstreams(display::win::ScanEdidBitstreams());
173}
174#endif // BUILDFLAG(IS_WIN)
175#endif // BUILDFLAG(ENABLE_PASSTHROUGH_AUDIO_CODECS)
Roy Funderburk32f66f6b2022-10-25 02:46:28176
Ken Rockot72964402019-12-06 10:40:51177} // namespace
178
179audio::mojom::AudioService& GetAudioService() {
180 DCHECK_CURRENTLY_ON(BrowserThread::UI);
ahmedmoussaf16c8c92023-12-12 09:33:40181 if (g_service_override) {
182 return *g_service_override;
183 }
Ken Rockot72964402019-12-06 10:40:51184
185 // NOTE: We use sequence-local storage slot not because we support access from
186 // any sequence, but to limit the lifetime of this Remote to the lifetime of
187 // UI-thread sequence. This is to support re-creation after task environment
188 // shutdown and reinitialization e.g. between unit tests.
Avi Drissmanded77172021-07-02 18:23:00189 static base::SequenceLocalStorageSlot<
190 mojo::Remote<audio::mojom::AudioService>>
Ken Rockot72964402019-12-06 10:40:51191 remote_slot;
Avi Drissmanded77172021-07-02 18:23:00192 auto& remote = remote_slot.GetOrCreateValue();
Douglas Wong6961d232022-10-07 17:19:01193 if (!remote) {
194 auto receiver = remote.BindNewPipeAndPassReceiver();
Roy Funderburkb7cbf5a92022-11-10 19:10:11195#if BUILDFLAG(ENABLE_PASSTHROUGH_AUDIO_CODECS) && BUILDFLAG(IS_WIN)
Douglas Wong6961d232022-10-07 17:19:01196 // The EDID scan is done in a COM STA thread and the result
197 // passed to the audio service launcher.
198 base::ThreadPool::CreateCOMSTATaskRunner(
199 {base::MayBlock(), base::TaskPriority::USER_BLOCKING,
200 base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN})
201 ->PostTaskAndReplyWithResult(
Roy Funderburk32f66f6b2022-10-25 02:46:28202 FROM_HERE, base::BindOnce(&ScanEdidBitstreams),
Douglas Wong6961d232022-10-07 17:19:01203 base::BindOnce(&LaunchAudioService, std::move(receiver)));
Roy Funderburkb7cbf5a92022-11-10 19:10:11204#elif BUILDFLAG(ENABLE_PASSTHROUGH_AUDIO_CODECS) && BUILDFLAG(IS_LINUX)
205 LaunchAudioService(
206 std::move(receiver),
207 ConvertEdidBitstreams(display::DisplayUtil::GetAudioFormats()));
Douglas Wong6961d232022-10-07 17:19:01208#else
209 LaunchAudioService(std::move(receiver), 0);
Roy Funderburkb7cbf5a92022-11-10 19:10:11210#endif // BUILDFLAG(ENABLE_PASSTHROUGH_AUDIO_CODECS) && BUILDFLAG(IS_WIN)
Douglas Wong6961d232022-10-07 17:19:01211 remote.reset_on_disconnect();
212 }
Ken Rockot72964402019-12-06 10:40:51213 return *remote.get();
214}
215
ahmedmoussaf16c8c92023-12-12 09:33:40216base::AutoReset<audio::mojom::AudioService*>
217OverrideAudioServiceForTesting( // IN-TEST
218 audio::mojom::AudioService* service) {
219 DCHECK_CURRENTLY_ON(BrowserThread::UI);
220 return {&g_service_override, service};
221}
222
Ken Rockot72964402019-12-06 10:40:51223std::unique_ptr<media::AudioSystem> CreateAudioSystemForAudioService() {
Peter Kastinge5a38ed2021-10-02 03:06:35224 constexpr auto kServiceDisconnectTimeout = base::Seconds(1);
Ken Rockot72964402019-12-06 10:40:51225 return std::make_unique<audio::AudioSystemToServiceAdapter>(
226 base::BindRepeating(&BindSystemInfoFromAnySequence),
227 kServiceDisconnectTimeout);
228}
229
230AudioServiceStreamFactoryBinder GetAudioServiceStreamFactoryBinder() {
231 return base::BindRepeating(&BindStreamFactoryFromAnySequence);
232}
233
234} // namespace content