blob: a563ed1fec76b8bb79ff0e691fd92639d50a191f [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_FIDL_PROFILE_SERVER_H_
#define SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_FIDL_PROFILE_SERVER_H_
#include <fuchsia/bluetooth/bredr/cpp/fidl.h>
#include "lib/fidl/cpp/binding.h"
#include "pw_intrusive_ptr/intrusive_ptr.h"
#include "src/connectivity/bluetooth/core/bt-host/fidl/server_base.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/common/macros.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/gap/bredr_connection_manager.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/sdp/server.h"
#include "src/connectivity/bluetooth/core/bt-host/socket/socket_factory.h"
namespace bthost {
// Implements the bredr::Profile FIDL interface.
class ProfileServer : public ServerBase<fuchsia::bluetooth::bredr::Profile> {
public:
ProfileServer(bt::gap::Adapter::WeakPtr adapter,
fidl::InterfaceRequest<fuchsia::bluetooth::bredr::Profile> request);
~ProfileServer() override;
private:
class AudioDirectionExt;
class L2capParametersExt final
: public ServerBase<fuchsia::bluetooth::bredr::L2capParametersExt> {
public:
L2capParametersExt(
fidl::InterfaceRequest<fuchsia::bluetooth::bredr::L2capParametersExt> request,
bt::l2cap::Channel::WeakPtr channel)
: ServerBase(this, std::move(request)),
unique_id_(channel->unique_id()),
channel_(std::move(channel)) {}
bt::l2cap::Channel::UniqueId unique_id() const { return unique_id_; }
void RequestParameters(fuchsia::bluetooth::bredr::ChannelParameters requested,
RequestParametersCallback callback) override;
void handle_unknown_method(uint64_t ordinal, bool method_has_response) override;
private:
bt::l2cap::Channel::UniqueId unique_id_;
bt::l2cap::Channel::WeakPtr channel_;
};
class AudioOffloadExt final : public ServerBase<fuchsia::bluetooth::bredr::AudioOffloadExt> {
public:
AudioOffloadExt(ProfileServer& profile_server,
fidl::InterfaceRequest<fuchsia::bluetooth::bredr::AudioOffloadExt> request,
bt::l2cap::Channel::WeakPtr channel, bt::gap::Adapter::WeakPtr adapter)
: ServerBase(this, std::move(request)),
profile_server_(profile_server),
unique_id_(channel->unique_id()),
channel_(std::move(channel)),
adapter_(std::move(adapter)) {}
void GetSupportedFeatures(GetSupportedFeaturesCallback callback) override;
void StartAudioOffload(
fuchsia::bluetooth::bredr::AudioOffloadConfiguration audio_offload_configuration,
fidl::InterfaceRequest<fuchsia::bluetooth::bredr::AudioOffloadController> controller)
override;
bt::l2cap::Channel::UniqueId unique_id() const { return unique_id_; }
void handle_unknown_method(uint64_t ordinal, bool method_has_response) override;
private:
std::unique_ptr<bt::l2cap::A2dpOffloadManager::Configuration> AudioOffloadConfigFromFidl(
fuchsia::bluetooth::bredr::AudioOffloadConfiguration& audio_offload_configuration);
ProfileServer& profile_server_;
bt::l2cap::Channel::UniqueId unique_id_;
bt::l2cap::Channel::WeakPtr channel_;
bt::gap::Adapter::WeakPtr adapter_;
};
class AudioOffloadController
: public ServerBase<fuchsia::bluetooth::bredr::AudioOffloadController> {
public:
explicit AudioOffloadController(
fidl::InterfaceRequest<fuchsia::bluetooth::bredr::AudioOffloadController> request,
bt::l2cap::Channel::WeakPtr channel)
: ServerBase(this, std::move(request)),
unique_id_(channel->unique_id()),
channel_(std::move(channel)) {}
void handle_unknown_method(uint64_t ordinal, bool method_has_response) override;
bt::l2cap::Channel::UniqueId unique_id() const { return unique_id_; }
void Stop(StopCallback callback) override {}
void SendOnStartedEvent() { binding()->events().OnStarted(); }
void Close(zx_status_t epitaph) { binding()->Close(epitaph); }
WeakPtr<AudioOffloadController> GetWeakPtr() { return weak_self_.GetWeakPtr(); }
private:
bt::l2cap::Channel::UniqueId unique_id_;
bt::l2cap::Channel::WeakPtr channel_;
WeakSelf<AudioOffloadController> weak_self_{this};
};
class ScoConnectionServer final : public ServerBase<fuchsia::bluetooth::bredr::ScoConnection> {
public:
ScoConnectionServer(fidl::InterfaceRequest<fuchsia::bluetooth::bredr::ScoConnection> request,
bt::sco::ScoConnection::WeakPtr connection);
~ScoConnectionServer() override;
void Activate(fit::callback<void()> on_closed);
void Read(ReadCallback callback) override;
void Write(std::vector<uint8_t> data, WriteCallback callback) override;
private:
void TryRead();
void Close(zx_status_t epitaph);
bt::sco::ScoConnection::WeakPtr connection_;
fit::callback<void()> on_closed_;
// Non-null when a read request is waiting for an inbound packet.
fit::callback<void(fuchsia::bluetooth::bredr::RxPacketStatus, std::vector<uint8_t>)> read_cb_;
};
struct ScoRequest : public pw::RefCounted<ScoRequest> {
std::optional<bt::gap::BrEdrConnectionManager::ScoRequestHandle> request_handle;
fuchsia::bluetooth::bredr::ScoConnectionReceiverPtr receiver;
std::vector<fuchsia::bluetooth::bredr::ScoConnectionParameters> parameters;
};
// fuchsia::bluetooth::bredr::Profile overrides:
void Advertise(fuchsia::bluetooth::bredr::ProfileAdvertiseRequest request,
AdvertiseCallback callback) override;
void Search(::fuchsia::bluetooth::bredr::ProfileSearchRequest request) override;
void Connect(fuchsia::bluetooth::PeerId peer_id,
fuchsia::bluetooth::bredr::ConnectParameters connection,
ConnectCallback callback) override;
void ConnectSco(::fuchsia::bluetooth::bredr::ProfileConnectScoRequest request) override;
void handle_unknown_method(uint64_t ordinal, bool method_has_response) override;
// Callback when clients close or revoke their connection targets
void OnConnectionReceiverClosed(uint64_t ad_id);
// Callback when clients close their search results
void OnSearchResultError(uint64_t search_id, zx_status_t status);
// Callback for incoming connections
void OnChannelConnected(uint64_t ad_id, bt::l2cap::Channel::WeakPtr channel,
const bt::sdp::DataElement& protocol_list);
// Callback for services found on connected device
void OnServiceFound(uint64_t search_id, bt::PeerId peer_id,
const std::map<bt::sdp::AttributeId, bt::sdp::DataElement>& attributes);
// Callback for SCO connections requests.
void OnScoConnectionResult(pw::IntrusivePtr<ScoRequest> request,
bt::sco::ScoConnectionManager::AcceptConnectionResult);
// Callback when clients close their audio direction extension.
void OnAudioDirectionExtError(AudioDirectionExt* ext_server, zx_status_t status);
// Create an AudioDirectionExt server for the given channel and set up callbacks.
// Returns the client end of the channel.
fidl::InterfaceHandle<fuchsia::bluetooth::bredr::AudioDirectionExt> BindAudioDirectionExtServer(
bt::l2cap::Channel::WeakPtr channel);
// Callback when clients close their l2cap parameters extension.
void OnL2capParametersExtError(L2capParametersExt* ext_server, zx_status_t status);
// Create an L2capParametersExt server for the given channel and set up callbacks.
// Returns the client end of the channel.
fidl::InterfaceHandle<fuchsia::bluetooth::bredr::L2capParametersExt> BindL2capParametersExtServer(
bt::l2cap::Channel::WeakPtr channel);
// Callback when clients close their audio offload extension.
void OnAudioOffloadExtError(AudioOffloadExt* ext_server, zx_status_t status);
// Create an AudioOffloadExt server for the given channel and set up callbacks.
// Returns the client end of the channel.
fidl::InterfaceHandle<fuchsia::bluetooth::bredr::AudioOffloadExt> BindAudioOffloadExtServer(
bt::l2cap::Channel::WeakPtr channel);
// Create a FIDL Channel from an l2cap::Channel. A socket channel relay is created from |channel|
// and returned in the FIDL Channel.
fuchsia::bluetooth::bredr::Channel ChannelToFidl(bt::l2cap::Channel::WeakPtr channel);
const bt::gap::Adapter::WeakPtr& adapter() const { return adapter_; }
// Advertised Services
struct AdvertisedService {
AdvertisedService(fidl::InterfacePtr<fuchsia::bluetooth::bredr::ConnectionReceiver> receiver,
bt::sdp::Server::RegistrationHandle registration_handle)
: receiver(std::move(receiver)), registration_handle(registration_handle) {}
fidl::InterfacePtr<fuchsia::bluetooth::bredr::ConnectionReceiver> receiver;
bt::sdp::Server::RegistrationHandle registration_handle;
};
uint64_t advertised_total_;
std::map<uint64_t, AdvertisedService> current_advertised_;
// Searches registered
struct RegisteredSearch {
RegisteredSearch(fidl::InterfacePtr<fuchsia::bluetooth::bredr::SearchResults> results,
bt::gap::BrEdrConnectionManager::SearchId search_id)
: results(std::move(results)), search_id(search_id) {}
fidl::InterfacePtr<fuchsia::bluetooth::bredr::SearchResults> results;
bt::gap::BrEdrConnectionManager::SearchId search_id;
};
uint64_t searches_total_;
std::map<uint64_t, RegisteredSearch> searches_;
class AudioDirectionExt final : public ServerBase<fuchsia::bluetooth::bredr::AudioDirectionExt> {
public:
// Calls to SetPriority() are forwarded to |priority_cb|.
AudioDirectionExt(fidl::InterfaceRequest<fuchsia::bluetooth::bredr::AudioDirectionExt> request,
bt::l2cap::Channel::WeakPtr channel)
: ServerBase(this, std::move(request)),
unique_id_(channel->unique_id()),
channel_(std::move(channel)) {};
bt::l2cap::Channel::UniqueId unique_id() const { return unique_id_; }
// fuchsia::bluetooth::bredr::AudioDirectionExt overrides:
void SetPriority(fuchsia::bluetooth::bredr::A2dpDirectionPriority priority,
SetPriorityCallback callback) override;
void handle_unknown_method(uint64_t ordinal, bool method_has_response) override;
private:
bt::l2cap::Channel::UniqueId unique_id_;
bt::l2cap::Channel::WeakPtr channel_;
};
std::unordered_map<bt::l2cap::Channel::UniqueId, std::unique_ptr<L2capParametersExt>>
l2cap_parameters_ext_servers_;
std::unordered_map<bt::l2cap::Channel::UniqueId, std::unique_ptr<AudioDirectionExt>>
audio_direction_ext_servers_;
std::unordered_map<bt::l2cap::Channel::UniqueId, std::unique_ptr<AudioOffloadExt>>
audio_offload_ext_servers_;
std::unique_ptr<AudioOffloadController> audio_offload_controller_server_;
bt::gap::Adapter::WeakPtr adapter_;
// Creates sockets that bridge L2CAP channels to profile processes.
bt::socket::SocketFactory<bt::l2cap::Channel> l2cap_socket_factory_;
std::unordered_map<bt::sco::ScoConnection*, std::unique_ptr<ScoConnectionServer>>
sco_connection_servers_;
// Keep this as the last member to make sure that all weak pointers are
// invalidated before other members get destroyed.
WeakSelf<ProfileServer> weak_self_;
BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(ProfileServer);
};
} // namespace bthost
#endif // SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_FIDL_PROFILE_SERVER_H_