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