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 "pw_bluetooth_sapphire/internal/host/l2cap/l2cap_defs.h" 17 #include "pw_bluetooth_sapphire/internal/host/transport/command_channel.h" 18 #include "pw_bluetooth_sapphire/internal/host/transport/error.h" 19 20 namespace bt::l2cap { 21 22 // Provides an API surface to start and stop A2DP offloading. A2dpOffloadManager 23 // tracks the state of A2DP offloading and allows at most one channel to be 24 // offloaded at a given time 25 class A2dpOffloadManager { 26 public: 27 // Configuration received from the profile server that needs to be converted 28 // to a command packet in order to send the StartA2dpOffload command 29 struct Configuration { 30 hci_spec::vendor::android::A2dpCodecType codec; 31 uint16_t max_latency; 32 hci_spec::vendor::android::A2dpScmsTEnable scms_t_enable; 33 hci_spec::vendor::android::A2dpSamplingFrequency sampling_frequency; 34 hci_spec::vendor::android::A2dpBitsPerSample bits_per_sample; 35 hci_spec::vendor::android::A2dpChannelMode channel_mode; 36 uint32_t encoded_audio_bit_rate; 37 hci_spec::vendor::android::A2dpOffloadCodecInformation codec_information; 38 }; 39 A2dpOffloadManager(hci::CommandChannel::WeakPtr cmd_channel)40 explicit A2dpOffloadManager(hci::CommandChannel::WeakPtr cmd_channel) 41 : cmd_channel_(std::move(cmd_channel)) {} 42 43 // Request the start of A2DP source offloading. |callback| will be called with 44 // the result of the request. If offloading is already started or still 45 // starting/stopping, the request will fail and |kInProgress| error will be 46 // reported synchronously. 47 void StartA2dpOffload(const Configuration& config, 48 ChannelId local_id, 49 ChannelId remote_id, 50 hci_spec::ConnectionHandle link_handle, 51 uint16_t max_tx_sdu_size, 52 hci::ResultCallback<> callback); 53 54 // Request the stop of A2DP source offloading on a specific channel. 55 // |callback| will be called with the result of the request. 56 // If offloading was not started or the channel requested is not offloaded, 57 // report success. Returns kInProgress error if channel offloading is 58 // currently in the process of stopping. 59 void RequestStopA2dpOffload(ChannelId local_id, 60 hci_spec::ConnectionHandle link_handle, 61 hci::ResultCallback<> callback); 62 63 // Returns true if channel with |id| and |link_handle| is starting/has started 64 // A2DP offloading 65 bool IsChannelOffloaded(ChannelId id, 66 hci_spec::ConnectionHandle link_handle) const; 67 GetWeakPtr()68 WeakPtr<A2dpOffloadManager> GetWeakPtr() { return weak_self_.GetWeakPtr(); } 69 70 private: 71 // Defines the state of A2DP offloading to the controller. 72 enum class A2dpOffloadStatus : uint8_t { 73 // The A2DP offload command was received and successfully started. 74 kStarted, 75 // The A2DP offload command was sent and the L2CAP channel is waiting for a 76 // response. 77 kStarting, 78 // The A2DP offload stop command was sent and the L2CAP channel is waiting 79 // for a response. 80 kStopping, 81 // Either an error or an A2DP offload command stopped offloading to the 82 // controller. 83 kStopped, 84 }; 85 86 hci::CommandChannel::WeakPtr cmd_channel_; 87 88 A2dpOffloadStatus a2dp_offload_status_ = A2dpOffloadStatus::kStopped; 89 90 // Identifier for offloaded channel's endpoint on this device 91 std::optional<ChannelId> offloaded_channel_id_; 92 93 // Connection handle of the offloaded channel's underlying logical link 94 std::optional<hci_spec::ConnectionHandle> offloaded_link_handle_; 95 96 // Contains a callback if stop command was requested before offload status was 97 // |kStarted| 98 std::optional<hci::ResultCallback<>> pending_stop_a2dp_offload_request_; 99 100 WeakSelf<A2dpOffloadManager> weak_self_{this}; 101 }; 102 103 } // namespace bt::l2cap 104