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