blob: 0f9604647be6e9d5ac29958b5a937433f74502fe [file] [log] [blame]
Yuyang Huang91d7f8b2023-10-26 16:01:27 -07001/*
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
25namespace aidl {
26namespace android {
27namespace hardware {
28namespace bluetooth {
29namespace audio {
30
31static constexpr uint32_t kBufferCount = 2; // two frame buffer
32
33HfpSoftwareOutputAudioProvider::HfpSoftwareOutputAudioProvider()
34 : HfpSoftwareAudioProvider() {
35 session_type_ = SessionType::HFP_SOFTWARE_ENCODING_DATAPATH;
36}
37
38HfpSoftwareInputAudioProvider::HfpSoftwareInputAudioProvider()
39 : HfpSoftwareAudioProvider() {
40 session_type_ = SessionType::HFP_SOFTWARE_DECODING_DATAPATH;
41}
42
43HfpSoftwareAudioProvider::HfpSoftwareAudioProvider()
44 : BluetoothAudioProvider(), data_mq_(nullptr) {
45}
46
47bool HfpSoftwareAudioProvider::isValid(const SessionType& sessionType) {
48 return (sessionType == session_type_);
49}
50
51ndk::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
123ndk::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