1 /*
2 * Copyright 2020 HIMSA II K/S - www.himsa.com. Represented by EHIMA -
3 * www.ehima.com
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 #define LOG_TAG "BTAudioProviderLeAudio"
19
20 #include "LeAudioAudioProvider.h"
21
22 #include <android-base/logging.h>
23
24 #include "BluetoothAudioSessionReport_2_1.h"
25 #include "BluetoothAudioSupportedCodecsDB_2_1.h"
26
27 namespace android {
28 namespace hardware {
29 namespace bluetooth {
30 namespace audio {
31 namespace V2_1 {
32 namespace implementation {
33
34 using ::android::bluetooth::audio::BluetoothAudioSessionReport_2_1;
35 using ::android::hardware::Void;
36 using ::android::hardware::bluetooth::audio::V2_0::BitsPerSample;
37 using ::android::hardware::bluetooth::audio::V2_0::ChannelMode;
38 using ::android::hardware::bluetooth::audio::V2_1::SampleRate;
39
40 static constexpr uint32_t kBufferOutCount = 2; // two frame buffer
41 static constexpr uint32_t kBufferInCount = 2; // two frame buffer
42
LeAudioOutputAudioProvider()43 LeAudioOutputAudioProvider::LeAudioOutputAudioProvider()
44 : LeAudioAudioProvider() {
45 session_type_ = SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH;
46 }
47
LeAudioInputAudioProvider()48 LeAudioInputAudioProvider::LeAudioInputAudioProvider()
49 : LeAudioAudioProvider() {
50 session_type_ = SessionType::LE_AUDIO_SOFTWARE_DECODED_DATAPATH;
51 }
52
LeAudioAudioProvider()53 LeAudioAudioProvider::LeAudioAudioProvider()
54 : BluetoothAudioProvider(), mDataMQ(nullptr) {}
55
isValid(const V2_0::SessionType & sessionType)56 bool LeAudioAudioProvider::isValid(const V2_0::SessionType& sessionType) {
57 LOG(ERROR) << __func__ << ", invalid session type for Le Audio provider: "
58 << toString(sessionType);
59
60 return false;
61 }
62
isValid(const SessionType & sessionType)63 bool LeAudioAudioProvider::isValid(const SessionType& sessionType) {
64 return (sessionType == session_type_);
65 }
66
startSession_2_1(const sp<V2_0::IBluetoothAudioPort> & hostIf,const AudioConfiguration & audioConfig,startSession_cb _hidl_cb)67 Return<void> LeAudioAudioProvider::startSession_2_1(
68 const sp<V2_0::IBluetoothAudioPort>& hostIf,
69 const AudioConfiguration& audioConfig, startSession_cb _hidl_cb) {
70 /**
71 * Initialize the audio platform if audioConfiguration is supported.
72 * Save the IBluetoothAudioPort interface, so that it can be used
73 * later to send stream control commands to the HAL client, based on
74 * interaction with Audio framework.
75 */
76 if (audioConfig.getDiscriminator() !=
77 AudioConfiguration::hidl_discriminator::pcmConfig) {
78 LOG(WARNING) << __func__
79 << " - Invalid Audio Configuration=" << toString(audioConfig);
80 _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION,
81 DataMQ::Descriptor());
82 return Void();
83 } else if (!android::bluetooth::audio::IsSoftwarePcmConfigurationValid_2_1(
84 audioConfig.pcmConfig())) {
85 LOG(WARNING) << __func__ << " - Unsupported PCM Configuration="
86 << toString(audioConfig.pcmConfig());
87 _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION,
88 DataMQ::Descriptor());
89 return Void();
90 }
91
92 uint32_t kDataMqSize = 0;
93 switch (audioConfig.pcmConfig().sampleRate) {
94 case SampleRate::RATE_8000:
95 kDataMqSize = 8000;
96 break;
97 case SampleRate::RATE_16000:
98 kDataMqSize = 16000;
99 break;
100 case SampleRate::RATE_24000:
101 kDataMqSize = 24000;
102 break;
103 case SampleRate::RATE_32000:
104 kDataMqSize = 32000;
105 break;
106 case SampleRate::RATE_44100:
107 kDataMqSize = 44100;
108 break;
109 case SampleRate::RATE_48000:
110 kDataMqSize = 48000;
111 break;
112 default:
113 LOG(WARNING) << __func__ << " - Unsupported sampling frequency="
114 << toString(audioConfig.pcmConfig());
115 _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION,
116 DataMQ::Descriptor());
117 return Void();
118 }
119
120 /* Number of samples per millisecond */
121 kDataMqSize = ceil(kDataMqSize / 1000);
122
123 switch (audioConfig.pcmConfig().channelMode) {
124 case ChannelMode::MONO:
125 break;
126 case ChannelMode::STEREO:
127 kDataMqSize *= 2;
128 break;
129 default:
130 /* This should never happen it would be caught while validating
131 * parameters.
132 */
133 break;
134 }
135
136 switch (audioConfig.pcmConfig().bitsPerSample) {
137 case BitsPerSample::BITS_16:
138 kDataMqSize *= 2;
139 break;
140 case BitsPerSample::BITS_24:
141 kDataMqSize *= 3;
142 break;
143 case BitsPerSample::BITS_32:
144 kDataMqSize *= 4;
145 break;
146 default:
147 /* This should never happen it would be caught while validating
148 * parameters.
149 */
150 break;
151 }
152
153 if (session_type_ == SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH)
154 kDataMqSize *= kBufferOutCount;
155 else if (session_type_ == SessionType::LE_AUDIO_SOFTWARE_DECODED_DATAPATH)
156 kDataMqSize *= kBufferInCount;
157 else
158 LOG(WARNING) << __func__ << ", default single buffer used";
159
160 kDataMqSize *= audioConfig.pcmConfig().dataIntervalUs / 1000;
161
162 LOG(INFO) << __func__ << " - size of audio buffer " << kDataMqSize
163 << " byte(s)";
164
165 std::unique_ptr<DataMQ> tempDataMQ(
166 new DataMQ(kDataMqSize, /* EventFlag */ true));
167 if (tempDataMQ && tempDataMQ->isValid()) {
168 mDataMQ = std::move(tempDataMQ);
169 } else {
170 ALOGE_IF(!tempDataMQ, "failed to allocate data MQ");
171 ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "data MQ is invalid");
172 _hidl_cb(BluetoothAudioStatus::FAILURE, DataMQ::Descriptor());
173 return Void();
174 }
175
176 return BluetoothAudioProvider::startSession_2_1(hostIf, audioConfig,
177 _hidl_cb);
178 }
179
onSessionReady(startSession_cb _hidl_cb)180 Return<void> LeAudioAudioProvider::onSessionReady(startSession_cb _hidl_cb) {
181 if (mDataMQ && mDataMQ->isValid()) {
182 BluetoothAudioSessionReport_2_1::OnSessionStarted(
183 session_type_, stack_iface_, mDataMQ->getDesc(), audio_config_);
184 _hidl_cb(BluetoothAudioStatus::SUCCESS, *mDataMQ->getDesc());
185 } else {
186 _hidl_cb(BluetoothAudioStatus::FAILURE, DataMQ::Descriptor());
187 }
188 return Void();
189 }
190
191 } // namespace implementation
192 } // namespace V2_1
193 } // namespace audio
194 } // namespace bluetooth
195 } // namespace hardware
196 } // namespace android
197