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