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