1 /*
2 * Copyright (C) 2024 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "gd/rust/topshim/vc/vc_shim.h"
18
19 #include <bluetooth/log.h>
20 #include <hardware/bluetooth.h>
21
22 #include <string>
23
24 #include "os/log.h"
25 #include "src/profiles/vc.rs.h"
26 #include "types/raw_address.h"
27
28 namespace rusty = ::bluetooth::topshim::rust;
29
30 namespace bluetooth {
31 namespace topshim {
32 namespace rust {
33 namespace internal {
34
35 static VolumeControlIntf* g_vc_if;
36
to_rust_btvc_connection_state(vc::ConnectionState state)37 static BtVcConnectionState to_rust_btvc_connection_state(vc::ConnectionState state) {
38 switch (state) {
39 case vc::ConnectionState::DISCONNECTED:
40 return BtVcConnectionState::Disconnected;
41 case vc::ConnectionState::CONNECTING:
42 return BtVcConnectionState::Connecting;
43 case vc::ConnectionState::CONNECTED:
44 return BtVcConnectionState::Connected;
45 case vc::ConnectionState::DISCONNECTING:
46 return BtVcConnectionState::Disconnecting;
47 default:
48 log::assert_that(false, "Unhandled enum value from C++");
49 }
50 return BtVcConnectionState{};
51 }
52
connection_state_cb(vc::ConnectionState state,const RawAddress & address)53 static void connection_state_cb(vc::ConnectionState state, const RawAddress& address) {
54 vc_connection_state_callback(to_rust_btvc_connection_state(state), address);
55 }
56
volume_state_cb(const RawAddress & address,uint8_t volume,bool mute,bool is_autonomous)57 static void volume_state_cb(
58 const RawAddress& address, uint8_t volume, bool mute, bool is_autonomous) {
59 vc_volume_state_callback(address, volume, mute, is_autonomous);
60 }
61
group_volume_state_cb(int group_id,uint8_t volume,bool mute,bool is_autonomous)62 static void group_volume_state_cb(int group_id, uint8_t volume, bool mute, bool is_autonomous) {
63 vc_group_volume_state_callback(group_id, volume, mute, is_autonomous);
64 }
65
device_available_cb(const RawAddress & address,uint8_t num_offset)66 static void device_available_cb(const RawAddress& address, uint8_t num_offset) {
67 vc_device_available_callback(address, num_offset);
68 }
69
ext_audio_out_volume_offset_cb(const RawAddress & address,uint8_t ext_output_id,int16_t offset)70 static void ext_audio_out_volume_offset_cb(
71 const RawAddress& address, uint8_t ext_output_id, int16_t offset) {
72 vc_ext_audio_out_volume_offset_callback(address, ext_output_id, offset);
73 }
74
ext_audio_out_location_cb(const RawAddress & address,uint8_t ext_output_id,uint32_t location)75 static void ext_audio_out_location_cb(
76 const RawAddress& address, uint8_t ext_output_id, uint32_t location) {
77 vc_ext_audio_out_location_callback(address, ext_output_id, location);
78 }
79
ext_audio_out_description_cb(const RawAddress & address,uint8_t ext_output_id,std::string descr)80 static void ext_audio_out_description_cb(
81 const RawAddress& address, uint8_t ext_output_id, std::string descr) {
82 vc_ext_audio_out_description_callback(address, ext_output_id, descr);
83 }
84
85 } // namespace internal
86
87 class DBusVolumeControlCallbacks : public vc::VolumeControlCallbacks {
88 public:
GetInstance()89 static vc::VolumeControlCallbacks* GetInstance() {
90 static auto instance = new DBusVolumeControlCallbacks();
91 return instance;
92 }
93
DBusVolumeControlCallbacks()94 DBusVolumeControlCallbacks(){};
95
OnConnectionState(vc::ConnectionState state,const RawAddress & address)96 void OnConnectionState(vc::ConnectionState state, const RawAddress& address) override {
97 log::info("state={}, address={}", static_cast<int>(state), ADDRESS_TO_LOGGABLE_CSTR(address));
98 topshim::rust::internal::connection_state_cb(state, address);
99 }
100
OnVolumeStateChanged(const RawAddress & address,uint8_t volume,bool mute,bool is_autonomous)101 void OnVolumeStateChanged(
102 const RawAddress& address, uint8_t volume, bool mute, bool is_autonomous) override {
103 log::info(
104 "address={}, volume={}, mute={}, is_autonomous={}",
105 ADDRESS_TO_LOGGABLE_CSTR(address),
106 volume,
107 mute,
108 is_autonomous);
109 topshim::rust::internal::volume_state_cb(address, volume, mute, is_autonomous);
110 }
111
OnGroupVolumeStateChanged(int group_id,uint8_t volume,bool mute,bool is_autonomous)112 void OnGroupVolumeStateChanged(
113 int group_id, uint8_t volume, bool mute, bool is_autonomous) override {
114 log::info(
115 "group_id={}, volume={}, mute={}, is_autonomous={}", group_id, volume, mute, is_autonomous);
116 topshim::rust::internal::group_volume_state_cb(group_id, volume, mute, is_autonomous);
117 }
118
OnDeviceAvailable(const RawAddress & address,uint8_t num_offset)119 void OnDeviceAvailable(const RawAddress& address, uint8_t num_offset) override {
120 log::info("address={}, num_offset={}", ADDRESS_TO_LOGGABLE_CSTR(address), num_offset);
121 topshim::rust::internal::device_available_cb(address, num_offset);
122 }
123
OnExtAudioOutVolumeOffsetChanged(const RawAddress & address,uint8_t ext_output_id,int16_t offset)124 void OnExtAudioOutVolumeOffsetChanged(
125 const RawAddress& address, uint8_t ext_output_id, int16_t offset) override {
126 log::info(
127 "address={}, ext_output_id={}, offset={}",
128 ADDRESS_TO_LOGGABLE_CSTR(address),
129 ext_output_id,
130 offset);
131 topshim::rust::internal::ext_audio_out_volume_offset_cb(address, ext_output_id, offset);
132 }
133
OnExtAudioOutLocationChanged(const RawAddress & address,uint8_t ext_output_id,uint32_t location)134 void OnExtAudioOutLocationChanged(
135 const RawAddress& address, uint8_t ext_output_id, uint32_t location) override {
136 log::info(
137 "address={}, ext_output_id, location={}",
138 ADDRESS_TO_LOGGABLE_CSTR(address),
139 ext_output_id,
140 location);
141 topshim::rust::internal::ext_audio_out_location_cb(address, ext_output_id, location);
142 }
143
OnExtAudioOutDescriptionChanged(const RawAddress & address,uint8_t ext_output_id,std::string descr)144 void OnExtAudioOutDescriptionChanged(
145 const RawAddress& address, uint8_t ext_output_id, std::string descr) override {
146 log::info(
147 "address={}, ext_output_id={}, descr={}",
148 ADDRESS_TO_LOGGABLE_CSTR(address),
149 ext_output_id,
150 descr.c_str());
151 topshim::rust::internal::ext_audio_out_description_cb(address, ext_output_id, descr);
152 }
153 };
154
GetVolumeControlProfile(const unsigned char * btif)155 std::unique_ptr<VolumeControlIntf> GetVolumeControlProfile(const unsigned char* btif) {
156 if (internal::g_vc_if) std::abort();
157
158 const bt_interface_t* btif_ = reinterpret_cast<const bt_interface_t*>(btif);
159
160 auto vc_if = std::make_unique<VolumeControlIntf>(
161 const_cast<vc::VolumeControlInterface*>(reinterpret_cast<const vc::VolumeControlInterface*>(
162 btif_->get_profile_interface("volume_control"))));
163
164 internal::g_vc_if = vc_if.get();
165
166 return vc_if;
167 }
168
init()169 void VolumeControlIntf::init(/*VolumeControlCallbacks* callbacks*/) {
170 return intf_->Init(DBusVolumeControlCallbacks::GetInstance());
171 }
172
cleanup()173 void VolumeControlIntf::cleanup() {
174 return intf_->Cleanup();
175 }
176
connect(RawAddress addr)177 void VolumeControlIntf::connect(RawAddress addr) {
178 return intf_->Connect(addr);
179 }
180
disconnect(RawAddress addr)181 void VolumeControlIntf::disconnect(RawAddress addr) {
182 return intf_->Disconnect(addr);
183 }
184
remove_device(RawAddress addr)185 void VolumeControlIntf::remove_device(RawAddress addr) {
186 return intf_->RemoveDevice(addr);
187 }
188
set_volume(int group_id,uint8_t volume)189 void VolumeControlIntf::set_volume(int group_id, uint8_t volume) {
190 return intf_->SetVolume(group_id, volume);
191 }
192
mute(RawAddress addr)193 void VolumeControlIntf::mute(RawAddress addr) {
194 return intf_->Mute(addr);
195 }
196
unmute(RawAddress addr)197 void VolumeControlIntf::unmute(RawAddress addr) {
198 return intf_->Unmute(addr);
199 }
200
get_ext_audio_out_volume_offset(RawAddress addr,uint8_t ext_output_id)201 void VolumeControlIntf::get_ext_audio_out_volume_offset(RawAddress addr, uint8_t ext_output_id) {
202 return intf_->GetExtAudioOutVolumeOffset(addr, ext_output_id);
203 }
204
set_ext_audio_out_volume_offset(RawAddress addr,uint8_t ext_output_id,int16_t offset_val)205 void VolumeControlIntf::set_ext_audio_out_volume_offset(
206 RawAddress addr, uint8_t ext_output_id, int16_t offset_val) {
207 return intf_->SetExtAudioOutVolumeOffset(addr, ext_output_id, offset_val);
208 }
209
get_ext_audio_out_location(RawAddress addr,uint8_t ext_output_id)210 void VolumeControlIntf::get_ext_audio_out_location(RawAddress addr, uint8_t ext_output_id) {
211 return intf_->GetExtAudioOutLocation(addr, ext_output_id);
212 }
213
set_ext_audio_out_location(RawAddress addr,uint8_t ext_output_id,uint32_t location)214 void VolumeControlIntf::set_ext_audio_out_location(
215 RawAddress addr, uint8_t ext_output_id, uint32_t location) {
216 return intf_->SetExtAudioOutLocation(addr, ext_output_id, location);
217 }
218
get_ext_audio_out_description(RawAddress addr,uint8_t ext_output_id)219 void VolumeControlIntf::get_ext_audio_out_description(RawAddress addr, uint8_t ext_output_id) {
220 return intf_->GetExtAudioOutDescription(addr, ext_output_id);
221 }
222
set_ext_audio_out_description(RawAddress addr,uint8_t ext_output_id,const char * descr)223 void VolumeControlIntf::set_ext_audio_out_description(
224 RawAddress addr, uint8_t ext_output_id, const char* descr) {
225 return intf_->SetExtAudioOutDescription(addr, ext_output_id, std::string(descr));
226 }
227 } // namespace rust
228 } // namespace topshim
229 } // namespace bluetooth
230