1 /*
2  * Copyright 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include <iomanip>
20 #include <sstream>
21 #include <vector>
22 
23 #include "a2dp_codec_api.h"
24 #include "a2dp_constants.h"
25 #include "avdt_api.h"
26 #include "common/message_loop_thread.h"
27 #include "hardware/bt_av.h"
28 
29 namespace bluetooth {
30 namespace audio {
31 namespace a2dp {
32 
33 /// Loosely copied after the definition from the Bluetooth Audio interface:
34 /// audio/aidl/android/hardware/bluetooth/audio/BluetoothAudioStatus.aidl
35 enum class Status {
36   SUCCESS = 0,
37   UNKNOWN,
38   UNSUPPORTED_CODEC_CONFIGURATION,
39   FAILURE,
40   PENDING,
41 };
42 
43 /// Loosely copied after the definition from the Bluetooth Audio interface:
44 /// audio/aidl/android/hardware/bluetooth/audio/IBluetoothAudioPort.aidl
45 ///
46 /// Implements callbacks for the BT Audio HAL to start, suspend and configure
47 /// the audio stream. Completion of the requested operation is indicated
48 /// by the methods ack_stream_started, ack_stream_suspended.
49 ///
50 /// The callbacks are always invoked from one of the binder threads.
51 class StreamCallbacks {
52 public:
~StreamCallbacks()53   virtual ~StreamCallbacks() {}
StartStream(bool)54   virtual Status StartStream(bool /*low_latency*/) const { return Status::FAILURE; }
SuspendStream()55   virtual Status SuspendStream() const { return Status::FAILURE; }
StopStream()56   virtual Status StopStream() const { return SuspendStream(); }
SetLatencyMode(bool)57   virtual Status SetLatencyMode(bool /*low_latency*/) const { return Status::FAILURE; }
58 };
59 
60 bool update_codec_offloading_capabilities(
61         const std::vector<btav_a2dp_codec_config_t>& framework_preference,
62         bool supports_a2dp_hw_offload_v2);
63 
64 // Check if new bluetooth_audio is enabled
65 bool is_hal_enabled();
66 
67 // Check if new bluetooth_audio is running with offloading encoders
68 bool is_hal_offloading();
69 
70 // Initialize BluetoothAudio HAL: openProvider
71 bool init(bluetooth::common::MessageLoopThread* message_loop,
72           StreamCallbacks const* strean_callbacks, bool offload_enabled);
73 
74 // Clean up BluetoothAudio HAL
75 void cleanup();
76 
77 // Set up the codec into BluetoothAudio HAL
78 bool setup_codec(A2dpCodecConfig* a2dp_config, uint16_t peer_mtu,
79                  int preferred_encoding_interval_us);
80 
81 // Set low latency buffer mode allowed or disallowed
82 void set_audio_low_latency_mode_allowed(bool allowed);
83 
84 // Send command to the BluetoothAudio HAL: StartSession, EndSession,
85 // StreamStarted, StreamSuspended
86 void start_session();
87 void end_session();
88 void ack_stream_started(Status status);
89 void ack_stream_suspended(Status status);
90 
91 // Read from the FMQ of BluetoothAudio HAL
92 size_t read(uint8_t* p_buf, uint32_t len);
93 
94 // Update A2DP delay report to BluetoothAudio HAL
95 void set_remote_delay(uint16_t delay_report);
96 
97 // Check whether OPUS is supported
98 bool is_opus_supported();
99 
100 // Definitions for A2DP hardware offload codec extensibility.
101 namespace provider {
102 
103 // Lookup the codec info in the list of supported offloaded sink codecs.
104 std::optional<btav_a2dp_codec_index_t> sink_codec_index(const uint8_t* p_codec_info);
105 
106 // Lookup the codec info in the list of supported offloaded source codecs.
107 std::optional<btav_a2dp_codec_index_t> source_codec_index(const uint8_t* p_codec_info);
108 
109 // Return the name of the codec which is assigned to the input index.
110 // The codec index must be in the ranges
111 // BTAV_A2DP_CODEC_INDEX_SINK_EXT_MIN..BTAV_A2DP_CODEC_INDEX_SINK_EXT_MAX or
112 // BTAV_A2DP_CODEC_INDEX_SOURCE_EXT_MIN..BTAV_A2DP_CODEC_INDEX_SOURCE_EXT_MAX.
113 // Returns nullopt if the codec_index is not assigned or codec extensibility
114 // is not supported or enabled.
115 std::optional<const char*> codec_index_str(btav_a2dp_codec_index_t codec_index);
116 
117 // Return true if the codec is supported for the session type
118 // A2DP_HARDWARE_ENCODING_DATAPATH or A2DP_HARDWARE_DECODING_DATAPATH.
119 bool supports_codec(btav_a2dp_codec_index_t codec_index);
120 
121 // Return the A2DP capabilities for the selected codec.
122 // `codec_info` returns the OTA codec capabilities, `codec_config`
123 // returns the supported capabilities in a generic format.
124 bool codec_info(btav_a2dp_codec_index_t codec_index, bluetooth::a2dp::CodecId* codec_id,
125                 uint8_t* codec_info, btav_a2dp_codec_config_t* codec_config);
126 
127 struct a2dp_configuration {
128   int remote_seid;
129   uint8_t codec_config[AVDT_CODEC_SIZE];
130   btav_a2dp_codec_config_t codec_parameters;
131   std::vector<uint8_t> vendor_specific_parameters;
132 
toStringa2dp_configuration133   inline std::string toString() const {
134     std::ostringstream os;
135     os << "A2dpConfiguration{";
136     os << "remote_seid: " << remote_seid;
137     os << ", codec_index: " << codec_parameters.codec_type;
138     os << ", codec_config: {";
139     for (int i = 0; i < AVDT_CODEC_SIZE; i++) {
140       os << "0x" << std::hex << std::setw(2) << std::setfill('0')
141          << static_cast<int>(codec_config[i]);
142       if (i != AVDT_CODEC_SIZE - 1) {
143         os << ",";
144       }
145     }
146     os << "}";
147     os << "}";
148     return os.str();
149   }
150 };
151 
152 struct a2dp_remote_capabilities {
153   int seid;
154   uint8_t const* capabilities;
155 
toStringa2dp_remote_capabilities156   inline std::string toString() const {
157     std::ostringstream os;
158     os << "A2dpRemoteCapabilities{";
159     os << "seid: " << seid;
160     os << ", capabilities: {";
161     if (capabilities != nullptr) {
162       for (int i = 0; i < AVDT_CODEC_SIZE; i++) {
163         os << "0x" << std::hex << std::setw(2) << std::setfill('0')
164            << static_cast<int>(capabilities[i]);
165         if (i != AVDT_CODEC_SIZE - 1) {
166           os << ",";
167         }
168       }
169     }
170     os << "}";
171     os << "}";
172     return os.str();
173   }
174 };
175 
176 // Query the codec selection fromt the audio HAL.
177 // The HAL is expected to pick the best audio configuration based on the
178 // discovered remote SEPs.
179 std::optional<a2dp_configuration> get_a2dp_configuration(
180         RawAddress peer_address, std::vector<a2dp_remote_capabilities> const& remote_seps,
181         btav_a2dp_codec_config_t const& user_preferences);
182 
183 // Query the codec parameters from the audio HAL.
184 // The HAL is expected to parse the codec configuration
185 // received from the peer and decide whether accept
186 // the it or not.
187 tA2DP_STATUS parse_a2dp_configuration(btav_a2dp_codec_index_t codec_index,
188                                       const uint8_t* codec_info,
189                                       btav_a2dp_codec_config_t* codec_parameters,
190                                       std::vector<uint8_t>* vendor_specific_parameters);
191 
192 }  // namespace provider
193 }  // namespace a2dp
194 }  // namespace audio
195 }  // namespace bluetooth
196 
197 namespace std {
198 template <>
199 struct formatter<::bluetooth::audio::a2dp::Status>
200     : enum_formatter<::bluetooth::audio::a2dp::Status> {};
201 }  // namespace std
202