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