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