// // Copyright (C) 2017 Google, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #include "service/a2dp_source.h" #include "base/logging.h" #include "base/memory/ptr_util.h" #include "service/logging_helpers.h" #define PARSE_ADDR(str) \ ({ \ RawAddress tmp; \ if (!RawAddress::FromString((str), tmp)) { \ LOG(ERROR) << "Invalid device address given: " << (str); \ return false; \ } \ tmp; \ }) #define TRY_RET(expr, err_msg) \ do { \ if (!(expr)) { \ LOG(ERROR) << err_msg; \ return false; \ } \ return true; \ } while (0) #define TRY_RET_FUNC(expr) TRY_RET(expr, __func__ << " failed") using bluetooth::hal::BluetoothAvInterface; using LockGuard = std::lock_guard; namespace bluetooth { namespace { btav_a2dp_codec_config_t CodecConfigToFluoride(const A2dpCodecConfig& config) { btav_a2dp_codec_config_t ret = { .codec_type = static_cast(config.codec_type()), .codec_priority = static_cast(config.codec_priority()), .sample_rate = static_cast(config.sample_rate()), .bits_per_sample = static_cast( config.bits_per_sample()), .channel_mode = static_cast(config.channel_mode()), .codec_specific_1 = config.codec_specific_1(), .codec_specific_2 = config.codec_specific_2(), .codec_specific_3 = config.codec_specific_3(), .codec_specific_4 = config.codec_specific_4(), }; return ret; } std::vector CodecConfigsToFluoride( const std::vector& configs) { std::vector ret; ret.reserve(configs.size()); for (const auto& config : configs) { ret.push_back(CodecConfigToFluoride(config)); } return ret; } A2dpCodecConfig FluorideCodecToCodec(const btav_a2dp_codec_config_t& config) { A2dpCodecConfig ret(config.codec_type, config.codec_priority, config.sample_rate, config.bits_per_sample, config.channel_mode, config.codec_specific_1, config.codec_specific_2, config.codec_specific_3, config.codec_specific_4); return ret; } std::vector FluorideCodecsToCodec( const std::vector& configs) { std::vector ret; ret.reserve(configs.size()); for (const auto& config : configs) { ret.push_back(FluorideCodecToCodec(config)); } return ret; } } // namespace // static const int A2dpSource::kSingletonInstanceId = 0; A2dpSource::A2dpSource(const Uuid& uuid) : app_identifier_(uuid) { hal::BluetoothAvInterface::Get()->AddA2dpSourceObserver(this); } A2dpSource::~A2dpSource() { hal::BluetoothAvInterface::Get()->RemoveA2dpSourceObserver(this); } const Uuid& A2dpSource::GetAppIdentifier() const { return app_identifier_; } int A2dpSource::GetInstanceId() const { return kSingletonInstanceId; } void A2dpSource::SetDelegate(Delegate* delegate) { LockGuard lock(delegate_mutex_); delegate_ = delegate; } bool A2dpSource::Enable(const std::vector& codec_priorities) { auto fluoride_priorities = CodecConfigsToFluoride(codec_priorities); LockGuard lock(mutex_); return hal::BluetoothAvInterface::Get()->A2dpSourceEnable( fluoride_priorities); } void A2dpSource::Disable() { LockGuard lock(mutex_); hal::BluetoothAvInterface::Get()->A2dpSourceDisable(); } bool A2dpSource::Connect(const std::string& device_address) { RawAddress addr = PARSE_ADDR(device_address); LockGuard lock(mutex_); TRY_RET_FUNC( hal::BluetoothAvInterface::Get()->GetA2dpSourceHALInterface()->connect( addr) == BT_STATUS_SUCCESS); } bool A2dpSource::Disconnect(const std::string& device_address) { RawAddress addr = PARSE_ADDR(device_address); LockGuard lock(mutex_); TRY_RET_FUNC( hal::BluetoothAvInterface::Get()->GetA2dpSourceHALInterface()->disconnect( addr) == BT_STATUS_SUCCESS); } bool A2dpSource::ConfigCodec( const std::string& device_address, const std::vector& codec_preferences) { RawAddress addr = PARSE_ADDR(device_address); auto fluoride_preferences = CodecConfigsToFluoride(codec_preferences); LockGuard lock(mutex_); TRY_RET_FUNC(hal::BluetoothAvInterface::Get() ->GetA2dpSourceHALInterface() ->config_codec(addr, fluoride_preferences) == BT_STATUS_SUCCESS); } void A2dpSource::ConnectionStateCallback(BluetoothAvInterface* iface, const RawAddress& bd_addr, btav_connection_state_t state) { auto device_address = BtAddrString(&bd_addr); LockGuard lock(delegate_mutex_); if (delegate_) delegate_->OnConnectionState(device_address, static_cast(state)); } void A2dpSource::AudioStateCallback(BluetoothAvInterface* iface, const RawAddress& bd_addr, btav_audio_state_t state) { auto device_address = BtAddrString(&bd_addr); LockGuard lock(delegate_mutex_); if (delegate_) delegate_->OnAudioState(device_address, static_cast(state)); } void A2dpSource::AudioConfigCallback( BluetoothAvInterface* iface, const RawAddress& bd_addr, const btav_a2dp_codec_config_t& codec_config_fluoride, const std::vector codecs_local_capabilities_fluoride, const std::vector codecs_selectable_capabilities_fluoride) { auto device_address = BtAddrString(&bd_addr); auto codec_config = FluorideCodecToCodec(codec_config_fluoride); auto codecs_local_capabilities = FluorideCodecsToCodec(codecs_local_capabilities_fluoride); auto codecs_selectable_capabilities = FluorideCodecsToCodec(codecs_selectable_capabilities_fluoride); LockGuard lock(delegate_mutex_); if (delegate_) delegate_->OnAudioConfig(device_address, codec_config, codecs_local_capabilities, codecs_selectable_capabilities); } bool A2dpSource::MandatoryCodecPreferredCallback(BluetoothAvInterface* iface, const RawAddress& bd_addr) { LockGuard lock(delegate_mutex_); // Do nothing. Optional codecs are preferred by default. return false; } // A2dpSourceFactory implementation // ======================================================== A2dpSourceFactory::A2dpSourceFactory() = default; A2dpSourceFactory::~A2dpSourceFactory() = default; bool A2dpSourceFactory::RegisterInstance(const Uuid& uuid, const RegisterCallback& callback) { VLOG(1) << __func__ << " - UUID: " << uuid.ToString(); auto a2dp_source = base::WrapUnique(new A2dpSource(uuid)); callback(BLE_STATUS_SUCCESS, uuid, std::move(a2dp_source)); return true; } } // namespace bluetooth