1 // Copyright 2023 The Pigweed Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not 4 // use this file except in compliance with the License. You may obtain a copy of 5 // the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 // License for the specific language governing permissions and limitations under 13 // the License. 14 15 #pragma once 16 #include <lib/fit/function.h> 17 18 #include <queue> 19 20 #include "pw_bluetooth_sapphire/internal/host/common/byte_buffer.h" 21 #include "pw_bluetooth_sapphire/internal/host/hci/connection.h" 22 #include "pw_bluetooth_sapphire/internal/host/transport/sco_data_channel.h" 23 #include "pw_bluetooth_sapphire/internal/host/transport/sco_data_packet.h" 24 25 namespace bt::sco { 26 27 // ScoConnection is a wrapper around an owned SCO hci::Connection. It provides a 28 // high-level interface to the underlying connection. 29 // 30 // This class is intended to be owned by a ScoConnectionManager. 31 class ScoConnection final : public hci::ScoDataChannel::ConnectionInterface { 32 public: 33 // |connection| is the underlying connection and must have the link type kSCO 34 // or kESCO. |deactivated_cb| will be called when the connection has been 35 // Deactivated and should be destroyed. 36 ScoConnection( 37 std::unique_ptr<hci::Connection> connection, 38 fit::closure deactivated_cb, 39 bt::StaticPacket< 40 pw::bluetooth::emboss::SynchronousConnectionParametersWriter> 41 parameters, 42 hci::ScoDataChannel* channel); 43 44 // Destroying this object will disconnect the underlying HCI connection. 45 ~ScoConnection() override = default; 46 handle()47 hci_spec::ConnectionHandle handle() const override { return handle_; } 48 49 // Called by ScoConnectionManager to notify a connection it can no longer 50 // process data and its hci::Connection should be closed. 51 void Close(); 52 53 // Returns a value that's unique for any SCO connection on this device. 54 using UniqueId = hci_spec::ConnectionHandle; 55 UniqueId unique_id() const; 56 UniqueId id() const; 57 58 // Activates this channel. |rx_callback| and |closed_callback| are called as 59 // data is received and the channel is closed, respectively. `Deactivate` 60 // should be called in `closed_callback`. 61 // 62 // Returns false if the channel could not be activated. 63 bool Activate(fit::closure rx_callback, fit::closure closed_callback); 64 65 // Deactivates this channel. No more packets can be sent or received after 66 // this is called. |rx_callback| may still be called if it has been already 67 // dispatched to its task runner. 68 void Deactivate(); 69 70 // Maximum outbound SDU payload size that will be accepted by |Send()|. 71 uint16_t max_tx_sdu_size() const; 72 73 // Queue the given SCO payload for transmission over this channel, taking 74 // ownership of |payload|. Returns true if the payload was queued 75 // successfully, and false otherwise. 76 bool Send(ByteBufferPtr payload); 77 78 // If an inbound packet is ready to be read, returns the packet. Otherwise, 79 // returns nullptr. 80 std::unique_ptr<hci::ScoDataPacket> Read(); 81 82 using WeakPtr = WeakSelf<ScoConnection>::WeakPtr; GetWeakPtr()83 WeakPtr GetWeakPtr() { return weak_self_.GetWeakPtr(); } 84 85 // ScoDataChannel overrides: 86 bt::StaticPacket<pw::bluetooth::emboss::SynchronousConnectionParametersWriter> 87 parameters() override; 88 std::unique_ptr<hci::ScoDataPacket> GetNextOutboundPacket() override; 89 void ReceiveInboundPacket( 90 std::unique_ptr<hci::ScoDataPacket> packet) override; 91 void OnHciError() override; 92 93 private: 94 // Common clean up logic for Close() and Deactivate(). Marks connection as 95 // inactive and closes the underlying connection. 96 void CleanUp(); 97 98 // True if Activate() has been called and neither Close() or Deactivate() has 99 // been called yet. 100 bool active_; 101 102 hci_spec::ConnectionHandle handle_; 103 104 std::unique_ptr<hci::Connection> connection_; 105 106 // Called to notify the caller of Activate() that the connection was closed. 107 fit::closure activator_closed_cb_; 108 109 // Called to notify the owner that the connection was deactivated. 110 fit::closure deactivated_cb_; 111 112 // Notify caller of Activate() that an inbound packet has been received and 113 // may be read. 114 fit::closure rx_callback_ = nullptr; 115 116 // Contains outbound SCO payloads. 117 std::queue<ByteBufferPtr> outbound_queue_; 118 119 // Contains inbound SCO payloads. 120 std::queue<std::unique_ptr<hci::ScoDataPacket>> inbound_queue_; 121 122 // This will be null if HCI SCO is not supported. 123 hci::ScoDataChannel* channel_ = nullptr; 124 125 bt::StaticPacket<pw::bluetooth::emboss::SynchronousConnectionParametersWriter> 126 parameters_; 127 128 WeakSelf<ScoConnection> weak_self_; 129 130 BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(ScoConnection); 131 }; 132 133 } // namespace bt::sco 134