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