xref: /aosp_15_r20/hardware/interfaces/bluetooth/audio/aidl/default/HfpSoftwareAudioProvider.cpp (revision 4d7e907c777eeecc4c5bd7cf640a754fac206ff7)
1 /*
2  * Copyright (C) 2023 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 "BTAudioProviderHfpSW"
18 
19 #include "HfpSoftwareAudioProvider.h"
20 
21 #include <BluetoothAudioCodecs.h>
22 #include <BluetoothAudioSessionReport.h>
23 #include <android-base/logging.h>
24 
25 namespace aidl {
26 namespace android {
27 namespace hardware {
28 namespace bluetooth {
29 namespace audio {
30 
31 static constexpr uint32_t kBufferCount = 2;  // two frame buffer
32 
HfpSoftwareOutputAudioProvider()33 HfpSoftwareOutputAudioProvider::HfpSoftwareOutputAudioProvider()
34     : HfpSoftwareAudioProvider() {
35   session_type_ = SessionType::HFP_SOFTWARE_ENCODING_DATAPATH;
36 }
37 
HfpSoftwareInputAudioProvider()38 HfpSoftwareInputAudioProvider::HfpSoftwareInputAudioProvider()
39     : HfpSoftwareAudioProvider() {
40   session_type_ = SessionType::HFP_SOFTWARE_DECODING_DATAPATH;
41 }
42 
HfpSoftwareAudioProvider()43 HfpSoftwareAudioProvider::HfpSoftwareAudioProvider()
44     : BluetoothAudioProvider(), data_mq_(nullptr) {
45 }
46 
isValid(const SessionType & sessionType)47 bool HfpSoftwareAudioProvider::isValid(const SessionType& sessionType) {
48   return (sessionType == session_type_);
49 }
50 
startSession(const std::shared_ptr<IBluetoothAudioPort> & host_if,const AudioConfiguration & audio_config,const std::vector<LatencyMode> & latency_modes,DataMQDesc * _aidl_return)51 ndk::ScopedAStatus HfpSoftwareAudioProvider::startSession(
52     const std::shared_ptr<IBluetoothAudioPort>& host_if,
53     const AudioConfiguration& audio_config,
54     const std::vector<LatencyMode>& latency_modes, DataMQDesc* _aidl_return) {
55   if (audio_config.getTag() != AudioConfiguration::pcmConfig) {
56     LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
57                  << audio_config.toString();
58     *_aidl_return = DataMQDesc();
59     return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
60   }
61   const PcmConfiguration& pcm_config =
62       audio_config.get<AudioConfiguration::pcmConfig>();
63   if (!BluetoothAudioCodecs::IsSoftwarePcmConfigurationValid(pcm_config)) {
64     LOG(WARNING) << __func__ << " - Unsupported PCM Configuration="
65                  << pcm_config.toString();
66     *_aidl_return = DataMQDesc();
67     return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
68   }
69 
70   bool isValidConfig = true;
71 
72   if (pcm_config.bitsPerSample != 16) {
73     isValidConfig = false;
74   }
75 
76   if (pcm_config.sampleRateHz != 8000 && pcm_config.sampleRateHz != 16000 &&
77       pcm_config.sampleRateHz != 32000) {
78     isValidConfig = false;
79   }
80 
81   if (pcm_config.channelMode != ChannelMode::MONO) {
82     isValidConfig = false;
83   }
84 
85   if (pcm_config.dataIntervalUs != 7500) {
86     isValidConfig = false;
87   }
88 
89   int bytes_per_sample = pcm_config.bitsPerSample / 8;
90 
91   uint32_t data_mq_size = kBufferCount * bytes_per_sample *
92                           (pcm_config.sampleRateHz / 1000) *
93                           pcm_config.dataIntervalUs / 1000;
94   if (!isValidConfig) {
95     LOG(ERROR) << __func__ << "Unexpected audio buffer size: " << data_mq_size
96                << ", SampleRateHz: " << pcm_config.sampleRateHz
97                << ", ChannelMode: " << toString(pcm_config.channelMode)
98                << ", BitsPerSample: "
99                << static_cast<int>(pcm_config.bitsPerSample)
100                << ", BytesPerSample: " << bytes_per_sample
101                << ", DataIntervalUs: " << pcm_config.dataIntervalUs
102                << ", SessionType: " << toString(session_type_);
103     return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
104   }
105 
106   LOG(INFO) << __func__ << " - size of audio buffer " << data_mq_size
107             << " byte(s)";
108 
109   std::unique_ptr<DataMQ> temp_data_mq(
110       new DataMQ(data_mq_size, /* EventFlag */ true));
111   if (temp_data_mq == nullptr || !temp_data_mq->isValid()) {
112     ALOGE_IF(!temp_data_mq, "failed to allocate data MQ");
113     ALOGE_IF(temp_data_mq && !temp_data_mq->isValid(), "data MQ is invalid");
114     *_aidl_return = DataMQDesc();
115     return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
116   }
117   data_mq_ = std::move(temp_data_mq);
118 
119   return BluetoothAudioProvider::startSession(host_if, audio_config,
120                                               latency_modes, _aidl_return);
121 }
122 
onSessionReady(DataMQDesc * _aidl_return)123 ndk::ScopedAStatus HfpSoftwareAudioProvider::onSessionReady(
124     DataMQDesc* _aidl_return) {
125   if (data_mq_ == nullptr || !data_mq_->isValid()) {
126     *_aidl_return = DataMQDesc();
127     return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
128   }
129   *_aidl_return = data_mq_->dupeDesc();
130   auto desc = data_mq_->dupeDesc();
131   BluetoothAudioSessionReport::OnSessionStarted(
132       session_type_, stack_iface_, &desc, *audio_config_, latency_modes_);
133   return ndk::ScopedAStatus::ok();
134 }
135 
136 }  // namespace audio
137 }  // namespace bluetooth
138 }  // namespace hardware
139 }  // namespace android
140 }  // namespace aidl
141