1 /*
2  * Copyright 2018 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 #define LOG_TAG "BTAudioProviderSession_2_1"
18 
19 #include "BluetoothAudioSession_2_1.h"
20 
21 #include <android-base/logging.h>
22 #include <android-base/stringprintf.h>
23 
24 #include "../aidl_session/HidlToAidlMiddleware_2_0.h"
25 #include "../aidl_session/HidlToAidlMiddleware_2_1.h"
26 
27 namespace android {
28 namespace bluetooth {
29 namespace audio {
30 using ::aidl::android::hardware::bluetooth::audio::HidlToAidlMiddleware_2_0;
31 using ::aidl::android::hardware::bluetooth::audio::HidlToAidlMiddleware_2_1;
32 using SessionType_2_1 =
33     ::android::hardware::bluetooth::audio::V2_1::SessionType;
34 using SessionType_2_0 =
35     ::android::hardware::bluetooth::audio::V2_0::SessionType;
36 
37 ::android::hardware::bluetooth::audio::V2_1::AudioConfiguration
38     BluetoothAudioSession_2_1::invalidSoftwareAudioConfiguration = {};
39 ::android::hardware::bluetooth::audio::V2_1::AudioConfiguration
40     BluetoothAudioSession_2_1::invalidOffloadAudioConfiguration = {};
41 
42 namespace {
is_2_0_session_type(const::android::hardware::bluetooth::audio::V2_1::SessionType & session_type)43 bool is_2_0_session_type(
44     const ::android::hardware::bluetooth::audio::V2_1::SessionType&
45         session_type) {
46   if (session_type == SessionType_2_1::A2DP_SOFTWARE_ENCODING_DATAPATH ||
47       session_type == SessionType_2_1::A2DP_HARDWARE_OFFLOAD_DATAPATH ||
48       session_type == SessionType_2_1::HEARING_AID_SOFTWARE_ENCODING_DATAPATH) {
49     return true;
50   } else {
51     return false;
52   }
53 }
54 
is_unsupported_2_1_session_type(const::android::hardware::bluetooth::audio::V2_1::SessionType & session_type)55 bool is_unsupported_2_1_session_type(
56     const ::android::hardware::bluetooth::audio::V2_1::SessionType&
57         session_type) {
58   if (session_type ==
59           SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
60       session_type ==
61           SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
62     return true;
63   } else {
64     return false;
65   }
66 }
67 }  // namespace
68 
BluetoothAudioSession_2_1(const::android::hardware::bluetooth::audio::V2_1::SessionType & session_type)69 BluetoothAudioSession_2_1::BluetoothAudioSession_2_1(
70     const ::android::hardware::bluetooth::audio::V2_1::SessionType&
71         session_type)
72     : audio_session(BluetoothAudioSessionInstance::GetSessionInstance(
73           static_cast<SessionType_2_0>(session_type))) {
74   if (is_2_0_session_type(session_type) ||
75       is_unsupported_2_1_session_type(session_type)) {
76     session_type_2_1_ = (SessionType_2_1::UNKNOWN);
77   } else {
78     session_type_2_1_ = (session_type);
79   }
80   raw_session_type_ = session_type;
81 }
82 
83 std::shared_ptr<BluetoothAudioSession>
GetAudioSession()84 BluetoothAudioSession_2_1::GetAudioSession() {
85   return audio_session;
86 }
87 
88 // The control function is for the bluetooth_audio module to get the current
89 // AudioConfiguration
90 const ::android::hardware::bluetooth::audio::V2_1::AudioConfiguration
GetAudioConfig()91 BluetoothAudioSession_2_1::GetAudioConfig() {
92   if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
93     return HidlToAidlMiddleware_2_1::GetAudioConfig(raw_session_type_);
94   std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
95   if (audio_session->IsSessionReady()) {
96     // If session is unknown it means it should be 2.0 type
97     if (session_type_2_1_ != SessionType_2_1::UNKNOWN)
98       return audio_config_2_1_;
99 
100     ::android::hardware::bluetooth::audio::V2_1::AudioConfiguration toConf;
101     const AudioConfiguration fromConf = GetAudioSession()->GetAudioConfig();
102     // pcmConfig only differs between 2.0 and 2.1 in AudioConfiguration
103     if (fromConf.getDiscriminator() ==
104         AudioConfiguration::hidl_discriminator::codecConfig) {
105       toConf.codecConfig(fromConf.codecConfig());
106     } else {
107       toConf.pcmConfig() = {
108           .sampleRate = static_cast<
109               ::android::hardware::bluetooth::audio::V2_1::SampleRate>(
110               fromConf.pcmConfig().sampleRate),
111           .channelMode = fromConf.pcmConfig().channelMode,
112           .bitsPerSample = fromConf.pcmConfig().bitsPerSample,
113           .dataIntervalUs = 0};
114     }
115     return toConf;
116   } else if (session_type_2_1_ ==
117              SessionType_2_1::A2DP_HARDWARE_OFFLOAD_DATAPATH) {
118     return kInvalidOffloadAudioConfiguration;
119   } else {
120     return kInvalidSoftwareAudioConfiguration;
121   }
122 }
123 
UpdateAudioConfig(const::android::hardware::bluetooth::audio::V2_1::AudioConfiguration & audio_config)124 bool BluetoothAudioSession_2_1::UpdateAudioConfig(
125     const ::android::hardware::bluetooth::audio::V2_1::AudioConfiguration&
126         audio_config) {
127   bool is_software_session =
128       (session_type_2_1_ == SessionType_2_1::A2DP_SOFTWARE_ENCODING_DATAPATH ||
129        session_type_2_1_ ==
130            SessionType_2_1::HEARING_AID_SOFTWARE_ENCODING_DATAPATH ||
131        session_type_2_1_ ==
132            SessionType_2_1::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH ||
133        session_type_2_1_ ==
134            SessionType_2_1::LE_AUDIO_SOFTWARE_DECODED_DATAPATH);
135   bool is_offload_a2dp_session =
136       (session_type_2_1_ == SessionType_2_1::A2DP_HARDWARE_OFFLOAD_DATAPATH);
137   auto audio_config_discriminator = audio_config.getDiscriminator();
138   bool is_software_audio_config =
139       (is_software_session &&
140        audio_config_discriminator ==
141            ::android::hardware::bluetooth::audio::V2_1::AudioConfiguration::
142                hidl_discriminator::pcmConfig);
143   bool is_a2dp_offload_audio_config =
144       (is_offload_a2dp_session &&
145        audio_config_discriminator ==
146            ::android::hardware::bluetooth::audio::V2_1::AudioConfiguration::
147                hidl_discriminator::codecConfig);
148   if (!is_software_audio_config && !is_a2dp_offload_audio_config) {
149     return false;
150   }
151   audio_config_2_1_ = audio_config;
152   return true;
153 }
154 
155 // The report function is used to report that the Bluetooth stack has started
156 // this session without any failure, and will invoke session_changed_cb_ to
157 // notify those registered bluetooth_audio outputs
OnSessionStarted(const sp<IBluetoothAudioPort> stack_iface,const DataMQ::Descriptor * dataMQ,const::android::hardware::bluetooth::audio::V2_1::AudioConfiguration & audio_config)158 void BluetoothAudioSession_2_1::OnSessionStarted(
159     const sp<IBluetoothAudioPort> stack_iface, const DataMQ::Descriptor* dataMQ,
160     const ::android::hardware::bluetooth::audio::V2_1::AudioConfiguration&
161         audio_config) {
162   if (session_type_2_1_ == SessionType_2_1::UNKNOWN) {
163     ::android::hardware::bluetooth::audio::V2_0::AudioConfiguration config;
164     if (audio_config.getDiscriminator() ==
165         ::android::hardware::bluetooth::audio::V2_1::AudioConfiguration::
166             hidl_discriminator::codecConfig) {
167       config.codecConfig(audio_config.codecConfig());
168     } else {
169       auto& tmpPcm = audio_config.pcmConfig();
170       config.pcmConfig(
171           ::android::hardware::bluetooth::audio::V2_0::PcmParameters{
172               .sampleRate = static_cast<SampleRate>(tmpPcm.sampleRate),
173               .channelMode = tmpPcm.channelMode,
174               .bitsPerSample = tmpPcm.bitsPerSample
175               /*dataIntervalUs is not passed to 2.0 */
176           });
177     }
178 
179     audio_session->OnSessionStarted(stack_iface, dataMQ, config);
180   } else {
181     std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
182     if (stack_iface == nullptr) {
183       LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_2_1_)
184                  << ", IBluetoothAudioPort Invalid";
185     } else if (!UpdateAudioConfig(audio_config)) {
186       LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_2_1_)
187                  << ", AudioConfiguration=" << toString(audio_config)
188                  << " Invalid";
189     } else if (!audio_session->UpdateDataPath(dataMQ)) {
190       LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_2_1_)
191                  << " DataMQ Invalid";
192       audio_config_2_1_ =
193           (session_type_2_1_ == SessionType_2_1::A2DP_HARDWARE_OFFLOAD_DATAPATH
194                ? kInvalidOffloadAudioConfiguration
195                : kInvalidSoftwareAudioConfiguration);
196     } else {
197       audio_session->stack_iface_ = stack_iface;
198       LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_2_1_)
199                 << ", AudioConfiguration=" << toString(audio_config);
200       audio_session->ReportSessionStatus();
201     };
202   }
203 }
204 
205 std::unique_ptr<BluetoothAudioSessionInstance_2_1>
206     BluetoothAudioSessionInstance_2_1::instance_ptr =
207         std::unique_ptr<BluetoothAudioSessionInstance_2_1>(
208             new BluetoothAudioSessionInstance_2_1());
209 
210 // API to fetch the session of A2DP / Hearing Aid
211 std::shared_ptr<BluetoothAudioSession_2_1>
GetSessionInstance(const SessionType_2_1 & session_type)212 BluetoothAudioSessionInstance_2_1::GetSessionInstance(
213     const SessionType_2_1& session_type) {
214   std::lock_guard<std::mutex> guard(instance_ptr->mutex_);
215   if (!instance_ptr->sessions_map_.empty()) {
216     auto entry = instance_ptr->sessions_map_.find(session_type);
217     if (entry != instance_ptr->sessions_map_.end()) {
218       return entry->second;
219     }
220   }
221   std::shared_ptr<BluetoothAudioSession_2_1> session_ptr =
222       std::make_shared<BluetoothAudioSession_2_1>(session_type);
223   instance_ptr->sessions_map_[session_type] = session_ptr;
224   return session_ptr;
225 }
226 
227 }  // namespace audio
228 }  // namespace bluetooth
229 }  // namespace android
230