• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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/btav/btav_shim.h"
18 
19 #include <cstdio>
20 #include <memory>
21 
22 #include "base/functional/callback.h"
23 #include "include/hardware/avrcp/avrcp.h"
24 #include "include/hardware/bluetooth.h"
25 #include "rust/cxx.h"
26 #include "src/profiles/a2dp.rs.h"
27 #include "src/profiles/avrcp.rs.h"
28 #include "types/raw_address.h"
29 
30 namespace rusty = ::bluetooth::topshim::rust;
31 
32 namespace bluetooth::avrcp {
33 class AvrcpMediaInterfaceImpl : public MediaInterface {
34  public:
SendKeyEvent(uint8_t key,KeyState state)35   void SendKeyEvent(uint8_t key, KeyState state) {
36     rusty::avrcp_send_key_event(key, state == KeyState::PUSHED);
37   }
38 
GetSongInfo(SongInfoCallback cb)39   void GetSongInfo(SongInfoCallback cb) override {
40     cb.Run(songInfo_);
41   }
42 
GetPlayStatus(PlayStatusCallback cb)43   void GetPlayStatus(PlayStatusCallback cb) override {
44     cb.Run(playStatus_);
45   }
46 
GetNowPlayingList(NowPlayingCallback cb)47   void GetNowPlayingList(NowPlayingCallback cb) override {
48     cb.Run(currentSongId_, nowPlayingList_);
49   }
50 
GetMediaPlayerList(MediaListCallback cb)51   void GetMediaPlayerList(MediaListCallback cb) override {
52     cb.Run(currentPlayer_, playerList_);
53   }
54 
GetFolderItems(uint16_t player_id,std::string media_id,FolderItemsCallback folder_cb)55   void GetFolderItems(
56       [[maybe_unused]] uint16_t player_id,
57       [[maybe_unused]] std::string media_id,
58       [[maybe_unused]] FolderItemsCallback folder_cb) override {}
59 
SetBrowsedPlayer(uint16_t player_id,SetBrowsedPlayerCallback browse_cb)60   void SetBrowsedPlayer(
61       [[maybe_unused]] uint16_t player_id, [[maybe_unused]] SetBrowsedPlayerCallback browse_cb) override {}
62 
RegisterUpdateCallback(MediaCallbacks * callback)63   void RegisterUpdateCallback(MediaCallbacks* callback) override {
64     mediaCb_ = callback;
65   }
66 
UnregisterUpdateCallback(MediaCallbacks * callback)67   void UnregisterUpdateCallback([[maybe_unused]] MediaCallbacks* callback) override {
68     mediaCb_ = nullptr;
69   }
70 
PlayItem(uint16_t player_id,bool now_playing,std::string media_id)71   void PlayItem(
72       [[maybe_unused]] uint16_t player_id,
73       [[maybe_unused]] bool now_playing,
74       [[maybe_unused]] std::string media_id) override {}
75 
SetActiveDevice(const RawAddress & addr)76   void SetActiveDevice(const RawAddress& addr) override {
77     rusty::avrcp_set_active_device(addr);
78   }
79 
SetPlaybackStatus(const PlayState & state)80   void SetPlaybackStatus(const PlayState& state) {
81     playStatus_.state = state;
82     if (mediaCb_) mediaCb_->SendMediaUpdate(/*track_changed*/ false, /*play_state*/ true, /*queuefalse*/ false);
83   }
84 
SetPosition(int64_t position_us)85   void SetPosition(int64_t position_us) {
86     // Unit conversion from microsecond to millisecond.
87     playStatus_.position = position_us / 1000;
88     if (mediaCb_) mediaCb_->SendMediaUpdate(/*track_changed*/ false, /*play_state*/ true, /*queuefalse*/ false);
89   }
90 
SetMetadata(const std::string & title,const std::string & artist,const std::string & album,int64_t length_us)91   void SetMetadata(const std::string& title, const std::string& artist, const std::string& album, int64_t length_us) {
92     if (title.length() || artist.length() || album.length()) {
93       songInfo_.attributes.clear();
94       // Reuse title for media_id, ideally this should be a shorter UID.
95       songInfo_.media_id = title;
96       if (title.length()) songInfo_.attributes.emplace(avrcp::AttributeEntry(avrcp::Attribute::TITLE, title));
97       if (artist.length()) songInfo_.attributes.emplace(avrcp::AttributeEntry(avrcp::Attribute::ARTIST_NAME, artist));
98       if (album.length()) songInfo_.attributes.emplace(avrcp::AttributeEntry(avrcp::Attribute::ALBUM_NAME, album));
99       // Floss's media implementation does not fully support the "Now Playing List," as Floss does not receive
100       // additional media information other than the current playing one. However, not all peripherals request metadata
101       // through the "Get Element Attributes" request. Instead, many get such information through the "Track Changed
102       // Notification." Hence, fill the playlist with one item here and have the Current Song ID always point to the
103       // only entry to support the track changed notification.
104       nowPlayingList_.clear();
105       nowPlayingList_.emplace_back(songInfo_);
106       currentSongId_ = songInfo_.media_id;
107       if (mediaCb_) mediaCb_->SendMediaUpdate(/*track_changed*/ true, /*play_state*/ false, /*queuefalse*/ false);
108     }
109 
110     if (length_us) {
111       // Unit conversion from microsecond to millisecond.
112       playStatus_.duration = length_us / 1000;
113       if (mediaCb_) mediaCb_->SendMediaUpdate(/*track_changed*/ false, /*play_state*/ true, /*queuefalse*/ false);
114     }
115   }
116 
AddPlayer(std::string name,bool browsing_supported)117   uint16_t AddPlayer(std::string name, bool browsing_supported) {
118     playerList_.push_back(MediaPlayerInfo{player_id_, name, browsing_supported});
119 
120     if (mediaCb_)
121       mediaCb_->SendFolderUpdate(
122           /*available_players*/ true, /*addressed_players*/ true, /*uids_changed*/ false);
123 
124     return player_id_++;
125   }
126 
127  private:
128   MediaCallbacks* mediaCb_;
129 
130   PlayStatus playStatus_;
131   SongInfo songInfo_;
132   std::string currentSongId_;
133   std::vector<MediaPlayerInfo> playerList_;
134   std::vector<SongInfo> nowPlayingList_;
135   uint16_t currentPlayer_;
136 
137   uint16_t player_id_ = 0;
138 };
139 
140 class VolumeInterfaceImpl : public VolumeInterface {
141  public:
DeviceConnected(const RawAddress & addr)142   void DeviceConnected(const RawAddress& addr) override {
143     rusty::avrcp_device_connected(addr, /*absolute_volume_enabled=*/false);
144   }
145 
DeviceConnected(const RawAddress & addr,VolumeChangedCb cb)146   void DeviceConnected(const RawAddress& addr, VolumeChangedCb cb) override {
147     volumeCb = std::move(cb);
148     rusty::avrcp_device_connected(addr, /*absolute_volume_enabled=*/true);
149   }
150 
DeviceDisconnected(const RawAddress & addr)151   void DeviceDisconnected(const RawAddress& addr) override {
152     volumeCb.Reset();
153     rusty::avrcp_device_disconnected(addr);
154   }
155 
156   // Set TG's (Android, ChromeOS) volume.
SetVolume(int8_t volume)157   void SetVolume(int8_t volume) override {
158     if (volume < 0) return;
159 
160     rusty::avrcp_absolute_volume_update(volume);
161   }
162 
163   // Set CT's (headsets, speakers) volume.
SetDeviceVolume(int8_t volume)164   void SetDeviceVolume(int8_t volume) {
165     if (!volumeCb || volume < 0) return;
166 
167     volumeCb.Run(volume);
168   }
169 
170  private:
171   VolumeInterface::VolumeChangedCb volumeCb;
172 };
173 
174 }  // namespace bluetooth::avrcp
175 
176 namespace bluetooth {
177 namespace topshim {
178 namespace rust {
179 namespace internal {
180 static A2dpIntf* g_a2dpif;
181 static AvrcpIntf* g_avrcpif;
182 
to_rust_codec_config(const btav_a2dp_codec_config_t & config)183 static A2dpCodecConfig to_rust_codec_config(const btav_a2dp_codec_config_t& config) {
184   A2dpCodecConfig rconfig = {
185       .codec_type = static_cast<uint8_t>(config.codec_type),
186       .codec_priority = config.codec_priority,
187       .sample_rate = static_cast<uint8_t>(config.sample_rate),
188       .bits_per_sample = static_cast<uint8_t>(config.bits_per_sample),
189       .channel_mode = static_cast<uint8_t>(config.channel_mode),
190       .codec_specific_1 = config.codec_specific_1,
191       .codec_specific_2 = config.codec_specific_2,
192       .codec_specific_3 = config.codec_specific_3,
193       .codec_specific_4 = config.codec_specific_4};
194   return rconfig;
195 }
196 
from_rust_codec_config(const A2dpCodecConfig & rconfig)197 static btav_a2dp_codec_config_t from_rust_codec_config(const A2dpCodecConfig& rconfig) {
198   btav_a2dp_codec_config_t config = {
199       .codec_type = static_cast<btav_a2dp_codec_index_t>(rconfig.codec_type),
200       .codec_priority = static_cast<btav_a2dp_codec_priority_t>(rconfig.codec_priority),
201       .sample_rate = static_cast<btav_a2dp_codec_sample_rate_t>(rconfig.sample_rate),
202       .bits_per_sample = static_cast<btav_a2dp_codec_bits_per_sample_t>(rconfig.bits_per_sample),
203       .channel_mode = static_cast<btav_a2dp_codec_channel_mode_t>(rconfig.channel_mode),
204       .codec_specific_1 = rconfig.codec_specific_1,
205       .codec_specific_2 = rconfig.codec_specific_2,
206       .codec_specific_3 = rconfig.codec_specific_3,
207       .codec_specific_4 = rconfig.codec_specific_4,
208   };
209   return config;
210 }
211 
to_rust_codec_config_vec(const std::vector<btav_a2dp_codec_config_t> & configs)212 static ::rust::Vec<A2dpCodecConfig> to_rust_codec_config_vec(const std::vector<btav_a2dp_codec_config_t>& configs) {
213   ::rust::Vec<A2dpCodecConfig> rconfigs;
214 
215   for (btav_a2dp_codec_config_t c : configs) {
216     rconfigs.push_back(to_rust_codec_config(c));
217   }
218   return rconfigs;
219 }
220 
to_rust_error(const btav_error_t & error)221 static A2dpError to_rust_error(const btav_error_t& error) {
222   A2dpError a2dp_error = {
223       .status = error.status,
224       .error_code = error.error_code,
225       .error_msg = error.error_msg.value_or(""),
226   };
227   return a2dp_error;
228 }
229 
connection_state_cb(const RawAddress & addr,btav_connection_state_t state,const btav_error_t & error)230 static void connection_state_cb(const RawAddress& addr, btav_connection_state_t state, const btav_error_t& error) {
231   A2dpError a2dp_error = to_rust_error(error);
232   rusty::connection_state_callback(addr, state, a2dp_error);
233 }
audio_state_cb(const RawAddress & addr,btav_audio_state_t state)234 static void audio_state_cb(const RawAddress& addr, btav_audio_state_t state) {
235   rusty::audio_state_callback(addr, state);
236 }
audio_config_cb(const RawAddress & addr,btav_a2dp_codec_config_t codec_config,std::vector<btav_a2dp_codec_config_t> codecs_local_capabilities,std::vector<btav_a2dp_codec_config_t> codecs_selectable_capabilities)237 static void audio_config_cb(
238     const RawAddress& addr,
239     btav_a2dp_codec_config_t codec_config,
240     std::vector<btav_a2dp_codec_config_t> codecs_local_capabilities,
241     std::vector<btav_a2dp_codec_config_t> codecs_selectable_capabilities) {
242   A2dpCodecConfig cfg = to_rust_codec_config(codec_config);
243   ::rust::Vec<A2dpCodecConfig> lcaps = to_rust_codec_config_vec(codecs_local_capabilities);
244   ::rust::Vec<A2dpCodecConfig> scaps = to_rust_codec_config_vec(codecs_selectable_capabilities);
245   rusty::audio_config_callback(addr, cfg, lcaps, scaps);
246 }
mandatory_codec_preferred_cb(const RawAddress & addr)247 static bool mandatory_codec_preferred_cb(const RawAddress& addr) {
248   rusty::mandatory_codec_preferred_callback(addr);
249   return true;
250 }
251 
252 btav_source_callbacks_t g_callbacks = {
253     sizeof(btav_source_callbacks_t),
254     connection_state_cb,
255     audio_state_cb,
256     audio_config_cb,
257     mandatory_codec_preferred_cb,
258 };
259 }  // namespace internal
260 
~A2dpIntf()261 A2dpIntf::~A2dpIntf() {
262   // TODO
263 }
264 
GetA2dpProfile(const unsigned char * btif)265 std::unique_ptr<A2dpIntf> GetA2dpProfile(const unsigned char* btif) {
266   if (internal::g_a2dpif) std::abort();
267 
268   const bt_interface_t* btif_ = reinterpret_cast<const bt_interface_t*>(btif);
269 
270   auto a2dpif = std::make_unique<A2dpIntf>(
271       reinterpret_cast<const btav_source_interface_t*>(btif_->get_profile_interface("a2dp")));
272   internal::g_a2dpif = a2dpif.get();
273   return a2dpif;
274 }
275 
init() const276 int A2dpIntf::init() const {
277   std::vector<btav_a2dp_codec_config_t> a;
278   std::vector<btav_a2dp_codec_config_t> b;
279   return intf_->init(&internal::g_callbacks, 1, a, b);
280 }
281 
connect(RawAddress addr) const282 uint32_t A2dpIntf::connect(RawAddress addr) const {
283   return intf_->connect(addr);
284 }
disconnect(RawAddress addr) const285 uint32_t A2dpIntf::disconnect(RawAddress addr) const {
286   return intf_->disconnect(addr);
287 }
set_silence_device(RawAddress addr,bool silent) const288 int A2dpIntf::set_silence_device(RawAddress addr, bool silent) const {
289   return intf_->set_silence_device(addr, silent);
290 }
set_active_device(RawAddress addr) const291 int A2dpIntf::set_active_device(RawAddress addr) const {
292   return intf_->set_active_device(addr);
293 }
config_codec(RawAddress addr,::rust::Vec<A2dpCodecConfig> codec_preferences) const294 int A2dpIntf::config_codec(RawAddress addr, ::rust::Vec<A2dpCodecConfig> codec_preferences) const {
295   std::vector<btav_a2dp_codec_config_t> prefs;
296   for (size_t i = 0; i < codec_preferences.size(); ++i) {
297     prefs.push_back(internal::from_rust_codec_config(codec_preferences[i]));
298   }
299   return intf_->config_codec(addr, prefs);
300 }
301 
cleanup() const302 void A2dpIntf::cleanup() const {
303   intf_->cleanup();
304 }
set_audio_config(A2dpCodecConfig rconfig) const305 bool A2dpIntf::set_audio_config(A2dpCodecConfig rconfig) const {
306   bluetooth::audio::a2dp::AudioConfig config = {
307       .sample_rate = static_cast<btav_a2dp_codec_sample_rate_t>(rconfig.sample_rate),
308       .bits_per_sample = static_cast<btav_a2dp_codec_bits_per_sample_t>(rconfig.bits_per_sample),
309       .channel_mode = static_cast<btav_a2dp_codec_channel_mode_t>(rconfig.channel_mode),
310   };
311   return bluetooth::audio::a2dp::SetAudioConfig(config);
312 }
start_audio_request() const313 bool A2dpIntf::start_audio_request() const {
314   return bluetooth::audio::a2dp::StartRequest();
315 }
stop_audio_request() const316 bool A2dpIntf::stop_audio_request() const {
317   return bluetooth::audio::a2dp::StopRequest();
318 }
suspend_audio_request() const319 bool A2dpIntf::suspend_audio_request() const {
320   return bluetooth::audio::a2dp::SuspendRequest();
321 }
get_presentation_position() const322 RustPresentationPosition A2dpIntf::get_presentation_position() const {
323   bluetooth::audio::a2dp::PresentationPosition p = bluetooth::audio::a2dp::GetPresentationPosition();
324   RustPresentationPosition rposition = {
325       .remote_delay_report_ns = p.remote_delay_report_ns,
326       .total_bytes_read = p.total_bytes_read,
327       .data_position_sec = p.data_position.tv_sec,
328       .data_position_nsec = static_cast<int32_t>(p.data_position.tv_nsec),
329   };
330   return rposition;
331 }
332 
333 // AVRCP
334 
335 static bluetooth::avrcp::AvrcpMediaInterfaceImpl mAvrcpInterface;
336 static bluetooth::avrcp::VolumeInterfaceImpl mVolumeInterface;
337 
GetAvrcpProfile(const unsigned char * btif)338 std::unique_ptr<AvrcpIntf> GetAvrcpProfile(const unsigned char* btif) {
339   if (internal::g_avrcpif) std::abort();
340 
341   const bt_interface_t* btif_ = reinterpret_cast<const bt_interface_t*>(btif);
342 
343   auto avrcpif = std::make_unique<AvrcpIntf>(reinterpret_cast<avrcp::ServiceInterface*>(btif_->get_avrcp_service()));
344   internal::g_avrcpif = avrcpif.get();
345   return avrcpif;
346 }
347 
~AvrcpIntf()348 AvrcpIntf::~AvrcpIntf() {}
349 
init()350 void AvrcpIntf::init() {
351   intf_->Init(&mAvrcpInterface, &mVolumeInterface, nullptr);
352 }
353 
cleanup()354 void AvrcpIntf::cleanup() {
355   intf_->Cleanup();
356 }
357 
connect(RawAddress addr)358 uint32_t AvrcpIntf::connect(RawAddress addr) {
359   return intf_->ConnectDevice(addr);
360 }
disconnect(RawAddress addr)361 uint32_t AvrcpIntf::disconnect(RawAddress addr) {
362   return intf_->DisconnectDevice(addr);
363 }
364 
set_volume(int8_t volume)365 void AvrcpIntf::set_volume(int8_t volume) {
366   return mVolumeInterface.SetDeviceVolume(volume);
367 }
368 
set_playback_status(const::rust::String & status)369 void AvrcpIntf::set_playback_status(const ::rust::String& status) {
370   avrcp::PlayState state = avrcp::PlayState::STOPPED;
371 
372   if (status == "stopped") state = avrcp::PlayState::STOPPED;
373   if (status == "playing") state = avrcp::PlayState::PLAYING;
374   if (status == "paused") state = avrcp::PlayState::PAUSED;
375 
376   mAvrcpInterface.SetPlaybackStatus(state);
377 }
378 
set_position(int64_t position)379 void AvrcpIntf::set_position(int64_t position) {
380   mAvrcpInterface.SetPosition(position);
381 }
382 
set_metadata(const::rust::String & title,const::rust::String & artist,const::rust::String & album,int64_t length_us)383 void AvrcpIntf::set_metadata(
384     const ::rust::String& title, const ::rust::String& artist, const ::rust::String& album, int64_t length_us) {
385   mAvrcpInterface.SetMetadata(std::string(title), std::string(artist), std::string(album), length_us);
386 }
387 
add_player(const::rust::String & name,bool browsing_supported)388 uint16_t AvrcpIntf::add_player(const ::rust::String& name, bool browsing_supported) {
389   return mAvrcpInterface.AddPlayer(std::string(name), browsing_supported);
390 }
391 
392 }  // namespace rust
393 }  // namespace topshim
394 }  // namespace bluetooth
395