1 // Copyright 2016 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 "components/arc/audio/arc_audio_bridge.h"
6
7 #include <utility>
8
9 #include "ash/public/cpp/system_tray.h"
10 #include "base/logging.h"
11 #include "base/memory/singleton.h"
12 #include "chromeos/audio/audio_device.h"
13 #include "components/arc/arc_browser_context_keyed_service_factory_base.h"
14 #include "components/arc/session/arc_bridge_service.h"
15
16 namespace arc {
17 namespace {
18
19 // Singleton factory for ArcAccessibilityHelperBridge.
20 class ArcAudioBridgeFactory
21 : public internal::ArcBrowserContextKeyedServiceFactoryBase<
22 ArcAudioBridge,
23 ArcAudioBridgeFactory> {
24 public:
25 // Factory name used by ArcBrowserContextKeyedServiceFactoryBase.
26 static constexpr const char* kName = "ArcAudioBridgeFactory";
27
GetInstance()28 static ArcAudioBridgeFactory* GetInstance() {
29 return base::Singleton<ArcAudioBridgeFactory>::get();
30 }
31
32 private:
33 friend base::DefaultSingletonTraits<ArcAudioBridgeFactory>;
34 ArcAudioBridgeFactory() = default;
35 ~ArcAudioBridgeFactory() override = default;
36 };
37
38 } // namespace
39
40 // static
GetForBrowserContext(content::BrowserContext * context)41 ArcAudioBridge* ArcAudioBridge::GetForBrowserContext(
42 content::BrowserContext* context) {
43 return ArcAudioBridgeFactory::GetForBrowserContext(context);
44 }
45
ArcAudioBridge(content::BrowserContext * context,ArcBridgeService * bridge_service)46 ArcAudioBridge::ArcAudioBridge(content::BrowserContext* context,
47 ArcBridgeService* bridge_service)
48 : arc_bridge_service_(bridge_service),
49 cras_audio_handler_(chromeos::CrasAudioHandler::Get()) {
50 arc_bridge_service_->audio()->SetHost(this);
51 arc_bridge_service_->audio()->AddObserver(this);
52 cras_audio_handler_->AddAudioObserver(this);
53 }
54
~ArcAudioBridge()55 ArcAudioBridge::~ArcAudioBridge() {
56 cras_audio_handler_->RemoveAudioObserver(this);
57 arc_bridge_service_->audio()->RemoveObserver(this);
58 arc_bridge_service_->audio()->SetHost(nullptr);
59 }
60
OnConnectionReady()61 void ArcAudioBridge::OnConnectionReady() {
62 // TODO(hidehiko): Replace with ConnectionHolder::IsConnected().
63 available_ = true;
64 }
65
OnConnectionClosed()66 void ArcAudioBridge::OnConnectionClosed() {
67 available_ = false;
68 }
69
ShowVolumeControls()70 void ArcAudioBridge::ShowVolumeControls() {
71 DVLOG(2) << "ArcAudioBridge::ShowVolumeControls";
72 ash::SystemTray::Get()->ShowVolumeSliderBubble();
73 }
74
OnSystemVolumeUpdateRequest(int32_t percent)75 void ArcAudioBridge::OnSystemVolumeUpdateRequest(int32_t percent) {
76 if (percent < 0 || percent > 100)
77 return;
78 cras_audio_handler_->SetOutputVolumePercent(percent);
79 bool is_muted =
80 percent <= cras_audio_handler_->GetOutputDefaultVolumeMuteThreshold();
81 if (cras_audio_handler_->IsOutputMuted() != is_muted)
82 cras_audio_handler_->SetOutputMute(is_muted);
83 }
84
OnAudioNodesChanged()85 void ArcAudioBridge::OnAudioNodesChanged() {
86 uint64_t output_id = cras_audio_handler_->GetPrimaryActiveOutputNode();
87 const chromeos::AudioDevice* output_device =
88 cras_audio_handler_->GetDeviceFromId(output_id);
89 bool headphone_inserted =
90 (output_device &&
91 (output_device->type ==
92 chromeos::AudioDeviceType::AUDIO_TYPE_HEADPHONE ||
93 output_device->type == chromeos::AudioDeviceType::AUDIO_TYPE_USB ||
94 output_device->type == chromeos::AudioDeviceType::AUDIO_TYPE_LINEOUT));
95
96 uint64_t input_id = cras_audio_handler_->GetPrimaryActiveInputNode();
97 const chromeos::AudioDevice* input_device =
98 cras_audio_handler_->GetDeviceFromId(input_id);
99 bool microphone_inserted =
100 (input_device &&
101 (input_device->type == chromeos::AudioDeviceType::AUDIO_TYPE_MIC ||
102 input_device->type == chromeos::AudioDeviceType::AUDIO_TYPE_USB));
103
104 DVLOG(1) << "HEADPHONE " << headphone_inserted << " MICROPHONE "
105 << microphone_inserted;
106 SendSwitchState(headphone_inserted, microphone_inserted);
107 }
108
OnOutputNodeVolumeChanged(uint64_t node_id,int volume)109 void ArcAudioBridge::OnOutputNodeVolumeChanged(uint64_t node_id, int volume) {
110 DVLOG(1) << "Output node " << node_id << " volume " << volume;
111 volume_ = volume;
112 SendVolumeState();
113 }
114
OnOutputMuteChanged(bool mute_on)115 void ArcAudioBridge::OnOutputMuteChanged(bool mute_on) {
116 DVLOG(1) << "Output mute " << mute_on;
117 muted_ = mute_on;
118 SendVolumeState();
119 }
120
SendSwitchState(bool headphone_inserted,bool microphone_inserted)121 void ArcAudioBridge::SendSwitchState(bool headphone_inserted,
122 bool microphone_inserted) {
123 uint32_t switch_state = 0;
124 if (headphone_inserted) {
125 switch_state |=
126 (1 << static_cast<uint32_t>(mojom::AudioSwitch::SW_HEADPHONE_INSERT));
127 }
128 if (microphone_inserted) {
129 switch_state |=
130 (1 << static_cast<uint32_t>(mojom::AudioSwitch::SW_MICROPHONE_INSERT));
131 }
132
133 DVLOG(1) << "Send switch state " << switch_state;
134 if (!available_)
135 return;
136 mojom::AudioInstance* audio_instance = ARC_GET_INSTANCE_FOR_METHOD(
137 arc_bridge_service_->audio(), NotifySwitchState);
138 if (audio_instance)
139 audio_instance->NotifySwitchState(switch_state);
140 }
141
SendVolumeState()142 void ArcAudioBridge::SendVolumeState() {
143 DVLOG(1) << "Send volume " << volume_ << " muted " << muted_;
144 if (!available_)
145 return;
146 mojom::AudioInstance* audio_instance = ARC_GET_INSTANCE_FOR_METHOD(
147 arc_bridge_service_->audio(), NotifyVolumeState);
148 if (audio_instance)
149 audio_instance->NotifyVolumeState(volume_, muted_);
150 }
151
152 } // namespace arc
153