1*4d7e907cSAndroid Build Coastguard Worker /*
2*4d7e907cSAndroid Build Coastguard Worker * Copyright (C) 2023 The Android Open Source Project
3*4d7e907cSAndroid Build Coastguard Worker *
4*4d7e907cSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*4d7e907cSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*4d7e907cSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*4d7e907cSAndroid Build Coastguard Worker *
8*4d7e907cSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*4d7e907cSAndroid Build Coastguard Worker *
10*4d7e907cSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*4d7e907cSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*4d7e907cSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*4d7e907cSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*4d7e907cSAndroid Build Coastguard Worker * limitations under the License.
15*4d7e907cSAndroid Build Coastguard Worker */
16*4d7e907cSAndroid Build Coastguard Worker
17*4d7e907cSAndroid Build Coastguard Worker #include "A2dpOffloadCodecSbc.h"
18*4d7e907cSAndroid Build Coastguard Worker
19*4d7e907cSAndroid Build Coastguard Worker #include <algorithm>
20*4d7e907cSAndroid Build Coastguard Worker
21*4d7e907cSAndroid Build Coastguard Worker #include "A2dpBits.h"
22*4d7e907cSAndroid Build Coastguard Worker
23*4d7e907cSAndroid Build Coastguard Worker namespace aidl::android::hardware::bluetooth::audio {
24*4d7e907cSAndroid Build Coastguard Worker
25*4d7e907cSAndroid Build Coastguard Worker /**
26*4d7e907cSAndroid Build Coastguard Worker * SBC Local Capabilities
27*4d7e907cSAndroid Build Coastguard Worker */
28*4d7e907cSAndroid Build Coastguard Worker
29*4d7e907cSAndroid Build Coastguard Worker enum : bool {
30*4d7e907cSAndroid Build Coastguard Worker kEnableSamplingFrequency44100 = true,
31*4d7e907cSAndroid Build Coastguard Worker kEnableSamplingFrequency48000 = true,
32*4d7e907cSAndroid Build Coastguard Worker };
33*4d7e907cSAndroid Build Coastguard Worker
34*4d7e907cSAndroid Build Coastguard Worker enum : bool {
35*4d7e907cSAndroid Build Coastguard Worker kEnableChannelModeMono = true,
36*4d7e907cSAndroid Build Coastguard Worker kEnableChannelModeDualChannel = true,
37*4d7e907cSAndroid Build Coastguard Worker kEnableChannelModeStereo = true,
38*4d7e907cSAndroid Build Coastguard Worker kEnableChannelModeJointStereo = true,
39*4d7e907cSAndroid Build Coastguard Worker };
40*4d7e907cSAndroid Build Coastguard Worker
41*4d7e907cSAndroid Build Coastguard Worker enum : bool {
42*4d7e907cSAndroid Build Coastguard Worker kEnableBlockLength4 = true,
43*4d7e907cSAndroid Build Coastguard Worker kEnableBlockLength8 = true,
44*4d7e907cSAndroid Build Coastguard Worker kEnableBlockLength12 = true,
45*4d7e907cSAndroid Build Coastguard Worker kEnableBlockLength16 = true,
46*4d7e907cSAndroid Build Coastguard Worker };
47*4d7e907cSAndroid Build Coastguard Worker
48*4d7e907cSAndroid Build Coastguard Worker enum : bool {
49*4d7e907cSAndroid Build Coastguard Worker kEnableSubbands4 = true,
50*4d7e907cSAndroid Build Coastguard Worker kEnableSubbands8 = true,
51*4d7e907cSAndroid Build Coastguard Worker };
52*4d7e907cSAndroid Build Coastguard Worker
53*4d7e907cSAndroid Build Coastguard Worker enum : bool {
54*4d7e907cSAndroid Build Coastguard Worker kEnableAllocationMethodSnr = true,
55*4d7e907cSAndroid Build Coastguard Worker kEnableAllocationMethodLoudness = true,
56*4d7e907cSAndroid Build Coastguard Worker };
57*4d7e907cSAndroid Build Coastguard Worker
58*4d7e907cSAndroid Build Coastguard Worker enum : uint8_t {
59*4d7e907cSAndroid Build Coastguard Worker kDefaultMinimumBitpool = 2,
60*4d7e907cSAndroid Build Coastguard Worker kDefaultMaximumBitpool = 250,
61*4d7e907cSAndroid Build Coastguard Worker };
62*4d7e907cSAndroid Build Coastguard Worker
63*4d7e907cSAndroid Build Coastguard Worker enum : int {
64*4d7e907cSAndroid Build Coastguard Worker kBitdepth = 16,
65*4d7e907cSAndroid Build Coastguard Worker };
66*4d7e907cSAndroid Build Coastguard Worker
67*4d7e907cSAndroid Build Coastguard Worker /**
68*4d7e907cSAndroid Build Coastguard Worker * SBC Signaling format [A2DP - 4.3]
69*4d7e907cSAndroid Build Coastguard Worker */
70*4d7e907cSAndroid Build Coastguard Worker
71*4d7e907cSAndroid Build Coastguard Worker // clang-format off
72*4d7e907cSAndroid Build Coastguard Worker
73*4d7e907cSAndroid Build Coastguard Worker constexpr A2dpBits::Range kSamplingFrequency ( 0, 3 );
74*4d7e907cSAndroid Build Coastguard Worker constexpr A2dpBits::Range kChannelMode ( 4, 7 );
75*4d7e907cSAndroid Build Coastguard Worker constexpr A2dpBits::Range kBlockLength ( 8, 11 );
76*4d7e907cSAndroid Build Coastguard Worker constexpr A2dpBits::Range kSubbands ( 12, 13 );
77*4d7e907cSAndroid Build Coastguard Worker constexpr A2dpBits::Range kAllocationMethod ( 14, 15 );
78*4d7e907cSAndroid Build Coastguard Worker constexpr A2dpBits::Range kMinimumBitpool ( 16, 23 );
79*4d7e907cSAndroid Build Coastguard Worker constexpr A2dpBits::Range kMaximumBitpool ( 24, 31 );
80*4d7e907cSAndroid Build Coastguard Worker constexpr size_t kCapabilitiesSize = 32/8;
81*4d7e907cSAndroid Build Coastguard Worker
82*4d7e907cSAndroid Build Coastguard Worker // clang-format on
83*4d7e907cSAndroid Build Coastguard Worker
84*4d7e907cSAndroid Build Coastguard Worker enum {
85*4d7e907cSAndroid Build Coastguard Worker kSamplingFrequency16000 = kSamplingFrequency.first,
86*4d7e907cSAndroid Build Coastguard Worker kSamplingFrequency32000,
87*4d7e907cSAndroid Build Coastguard Worker kSamplingFrequency44100,
88*4d7e907cSAndroid Build Coastguard Worker kSamplingFrequency48000
89*4d7e907cSAndroid Build Coastguard Worker };
90*4d7e907cSAndroid Build Coastguard Worker
91*4d7e907cSAndroid Build Coastguard Worker enum {
92*4d7e907cSAndroid Build Coastguard Worker kChannelModeMono = kChannelMode.first,
93*4d7e907cSAndroid Build Coastguard Worker kChannelModeDualChannel,
94*4d7e907cSAndroid Build Coastguard Worker kChannelModeStereo,
95*4d7e907cSAndroid Build Coastguard Worker kChannelModeJointStereo
96*4d7e907cSAndroid Build Coastguard Worker };
97*4d7e907cSAndroid Build Coastguard Worker
98*4d7e907cSAndroid Build Coastguard Worker enum {
99*4d7e907cSAndroid Build Coastguard Worker kBlockLength4 = kBlockLength.first,
100*4d7e907cSAndroid Build Coastguard Worker kBlockLength8,
101*4d7e907cSAndroid Build Coastguard Worker kBlockLength12,
102*4d7e907cSAndroid Build Coastguard Worker kBlockLength16
103*4d7e907cSAndroid Build Coastguard Worker };
104*4d7e907cSAndroid Build Coastguard Worker
105*4d7e907cSAndroid Build Coastguard Worker enum { kSubbands8 = kSubbands.first, kSubbands4 };
106*4d7e907cSAndroid Build Coastguard Worker
107*4d7e907cSAndroid Build Coastguard Worker enum {
108*4d7e907cSAndroid Build Coastguard Worker kAllocationMethodSnr = kAllocationMethod.first,
109*4d7e907cSAndroid Build Coastguard Worker kAllocationMethodLoudness
110*4d7e907cSAndroid Build Coastguard Worker };
111*4d7e907cSAndroid Build Coastguard Worker
112*4d7e907cSAndroid Build Coastguard Worker /**
113*4d7e907cSAndroid Build Coastguard Worker * SBC Conversion functions
114*4d7e907cSAndroid Build Coastguard Worker */
115*4d7e907cSAndroid Build Coastguard Worker
GetSamplingFrequencyBit(int32_t sampling_frequency)116*4d7e907cSAndroid Build Coastguard Worker static int GetSamplingFrequencyBit(int32_t sampling_frequency) {
117*4d7e907cSAndroid Build Coastguard Worker switch (sampling_frequency) {
118*4d7e907cSAndroid Build Coastguard Worker case 16000:
119*4d7e907cSAndroid Build Coastguard Worker return kSamplingFrequency16000;
120*4d7e907cSAndroid Build Coastguard Worker case 32000:
121*4d7e907cSAndroid Build Coastguard Worker return kSamplingFrequency32000;
122*4d7e907cSAndroid Build Coastguard Worker case 44100:
123*4d7e907cSAndroid Build Coastguard Worker return kSamplingFrequency44100;
124*4d7e907cSAndroid Build Coastguard Worker case 48000:
125*4d7e907cSAndroid Build Coastguard Worker return kSamplingFrequency48000;
126*4d7e907cSAndroid Build Coastguard Worker default:
127*4d7e907cSAndroid Build Coastguard Worker return -1;
128*4d7e907cSAndroid Build Coastguard Worker }
129*4d7e907cSAndroid Build Coastguard Worker }
130*4d7e907cSAndroid Build Coastguard Worker
GetSamplingFrequencyValue(int sampling_frequency)131*4d7e907cSAndroid Build Coastguard Worker static int32_t GetSamplingFrequencyValue(int sampling_frequency) {
132*4d7e907cSAndroid Build Coastguard Worker switch (sampling_frequency) {
133*4d7e907cSAndroid Build Coastguard Worker case kSamplingFrequency16000:
134*4d7e907cSAndroid Build Coastguard Worker return 16000;
135*4d7e907cSAndroid Build Coastguard Worker case kSamplingFrequency32000:
136*4d7e907cSAndroid Build Coastguard Worker return 32000;
137*4d7e907cSAndroid Build Coastguard Worker case kSamplingFrequency44100:
138*4d7e907cSAndroid Build Coastguard Worker return 44100;
139*4d7e907cSAndroid Build Coastguard Worker case kSamplingFrequency48000:
140*4d7e907cSAndroid Build Coastguard Worker return 48000;
141*4d7e907cSAndroid Build Coastguard Worker default:
142*4d7e907cSAndroid Build Coastguard Worker return 0;
143*4d7e907cSAndroid Build Coastguard Worker }
144*4d7e907cSAndroid Build Coastguard Worker }
145*4d7e907cSAndroid Build Coastguard Worker
GetChannelModeBit(ChannelMode channel_mode)146*4d7e907cSAndroid Build Coastguard Worker static int GetChannelModeBit(ChannelMode channel_mode) {
147*4d7e907cSAndroid Build Coastguard Worker switch (channel_mode) {
148*4d7e907cSAndroid Build Coastguard Worker case ChannelMode::STEREO:
149*4d7e907cSAndroid Build Coastguard Worker return kChannelModeJointStereo | kChannelModeStereo;
150*4d7e907cSAndroid Build Coastguard Worker case ChannelMode::DUALMONO:
151*4d7e907cSAndroid Build Coastguard Worker return kChannelModeDualChannel;
152*4d7e907cSAndroid Build Coastguard Worker case ChannelMode::MONO:
153*4d7e907cSAndroid Build Coastguard Worker return kChannelModeMono;
154*4d7e907cSAndroid Build Coastguard Worker default:
155*4d7e907cSAndroid Build Coastguard Worker return -1;
156*4d7e907cSAndroid Build Coastguard Worker }
157*4d7e907cSAndroid Build Coastguard Worker }
158*4d7e907cSAndroid Build Coastguard Worker
GetChannelModeEnum(int channel_mode)159*4d7e907cSAndroid Build Coastguard Worker static ChannelMode GetChannelModeEnum(int channel_mode) {
160*4d7e907cSAndroid Build Coastguard Worker switch (channel_mode) {
161*4d7e907cSAndroid Build Coastguard Worker case kChannelModeMono:
162*4d7e907cSAndroid Build Coastguard Worker return ChannelMode::MONO;
163*4d7e907cSAndroid Build Coastguard Worker case kChannelModeDualChannel:
164*4d7e907cSAndroid Build Coastguard Worker return ChannelMode::DUALMONO;
165*4d7e907cSAndroid Build Coastguard Worker case kChannelModeStereo:
166*4d7e907cSAndroid Build Coastguard Worker case kChannelModeJointStereo:
167*4d7e907cSAndroid Build Coastguard Worker return ChannelMode::STEREO;
168*4d7e907cSAndroid Build Coastguard Worker default:
169*4d7e907cSAndroid Build Coastguard Worker return ChannelMode::UNKNOWN;
170*4d7e907cSAndroid Build Coastguard Worker }
171*4d7e907cSAndroid Build Coastguard Worker }
172*4d7e907cSAndroid Build Coastguard Worker
GetBlockLengthValue(int block_length)173*4d7e907cSAndroid Build Coastguard Worker static int32_t GetBlockLengthValue(int block_length) {
174*4d7e907cSAndroid Build Coastguard Worker switch (block_length) {
175*4d7e907cSAndroid Build Coastguard Worker case kBlockLength4:
176*4d7e907cSAndroid Build Coastguard Worker return 4;
177*4d7e907cSAndroid Build Coastguard Worker case kBlockLength8:
178*4d7e907cSAndroid Build Coastguard Worker return 8;
179*4d7e907cSAndroid Build Coastguard Worker case kBlockLength12:
180*4d7e907cSAndroid Build Coastguard Worker return 12;
181*4d7e907cSAndroid Build Coastguard Worker case kBlockLength16:
182*4d7e907cSAndroid Build Coastguard Worker return 16;
183*4d7e907cSAndroid Build Coastguard Worker default:
184*4d7e907cSAndroid Build Coastguard Worker return 0;
185*4d7e907cSAndroid Build Coastguard Worker }
186*4d7e907cSAndroid Build Coastguard Worker }
187*4d7e907cSAndroid Build Coastguard Worker
GetSubbandsValue(int subbands)188*4d7e907cSAndroid Build Coastguard Worker static int32_t GetSubbandsValue(int subbands) {
189*4d7e907cSAndroid Build Coastguard Worker switch (subbands) {
190*4d7e907cSAndroid Build Coastguard Worker case kSubbands4:
191*4d7e907cSAndroid Build Coastguard Worker return 4;
192*4d7e907cSAndroid Build Coastguard Worker case kSubbands8:
193*4d7e907cSAndroid Build Coastguard Worker return 8;
194*4d7e907cSAndroid Build Coastguard Worker default:
195*4d7e907cSAndroid Build Coastguard Worker return 0;
196*4d7e907cSAndroid Build Coastguard Worker }
197*4d7e907cSAndroid Build Coastguard Worker }
198*4d7e907cSAndroid Build Coastguard Worker
GetAllocationMethodEnum(int allocation_method)199*4d7e907cSAndroid Build Coastguard Worker static SbcParameters::AllocationMethod GetAllocationMethodEnum(
200*4d7e907cSAndroid Build Coastguard Worker int allocation_method) {
201*4d7e907cSAndroid Build Coastguard Worker switch (allocation_method) {
202*4d7e907cSAndroid Build Coastguard Worker case kAllocationMethodSnr:
203*4d7e907cSAndroid Build Coastguard Worker return SbcParameters::AllocationMethod::SNR;
204*4d7e907cSAndroid Build Coastguard Worker case kAllocationMethodLoudness:
205*4d7e907cSAndroid Build Coastguard Worker default:
206*4d7e907cSAndroid Build Coastguard Worker return SbcParameters::AllocationMethod::LOUDNESS;
207*4d7e907cSAndroid Build Coastguard Worker }
208*4d7e907cSAndroid Build Coastguard Worker }
209*4d7e907cSAndroid Build Coastguard Worker
GetSamplingFrequencyValue(const A2dpBits & configuration)210*4d7e907cSAndroid Build Coastguard Worker static int32_t GetSamplingFrequencyValue(const A2dpBits& configuration) {
211*4d7e907cSAndroid Build Coastguard Worker return GetSamplingFrequencyValue(
212*4d7e907cSAndroid Build Coastguard Worker configuration.find_active_bit(kSamplingFrequency));
213*4d7e907cSAndroid Build Coastguard Worker }
214*4d7e907cSAndroid Build Coastguard Worker
GetBlockLengthValue(const A2dpBits & configuration)215*4d7e907cSAndroid Build Coastguard Worker static int32_t GetBlockLengthValue(const A2dpBits& configuration) {
216*4d7e907cSAndroid Build Coastguard Worker return GetBlockLengthValue(configuration.find_active_bit(kBlockLength));
217*4d7e907cSAndroid Build Coastguard Worker }
218*4d7e907cSAndroid Build Coastguard Worker
GetSubbandsValue(const A2dpBits & configuration)219*4d7e907cSAndroid Build Coastguard Worker static int32_t GetSubbandsValue(const A2dpBits& configuration) {
220*4d7e907cSAndroid Build Coastguard Worker return GetSubbandsValue(configuration.find_active_bit(kSubbands));
221*4d7e907cSAndroid Build Coastguard Worker }
222*4d7e907cSAndroid Build Coastguard Worker
GetFrameSize(const A2dpBits & configuration,int bitpool)223*4d7e907cSAndroid Build Coastguard Worker static int GetFrameSize(const A2dpBits& configuration, int bitpool) {
224*4d7e907cSAndroid Build Coastguard Worker const int kSbcHeaderSize = 4;
225*4d7e907cSAndroid Build Coastguard Worker int subbands = GetSubbandsValue(configuration);
226*4d7e907cSAndroid Build Coastguard Worker int blocks = GetBlockLengthValue(configuration);
227*4d7e907cSAndroid Build Coastguard Worker
228*4d7e907cSAndroid Build Coastguard Worker unsigned bits =
229*4d7e907cSAndroid Build Coastguard Worker ((4 * subbands) << !configuration.get(kChannelModeMono)) +
230*4d7e907cSAndroid Build Coastguard Worker ((blocks * bitpool) << configuration.get(kChannelModeDualChannel)) +
231*4d7e907cSAndroid Build Coastguard Worker ((configuration.get(kChannelModeJointStereo) ? subbands : 0));
232*4d7e907cSAndroid Build Coastguard Worker
233*4d7e907cSAndroid Build Coastguard Worker return kSbcHeaderSize + ((bits + 7) >> 3);
234*4d7e907cSAndroid Build Coastguard Worker }
235*4d7e907cSAndroid Build Coastguard Worker
GetBitrate(const A2dpBits & configuration,int bitpool)236*4d7e907cSAndroid Build Coastguard Worker static int GetBitrate(const A2dpBits& configuration, int bitpool) {
237*4d7e907cSAndroid Build Coastguard Worker int sampling_frequency = GetSamplingFrequencyValue(configuration);
238*4d7e907cSAndroid Build Coastguard Worker int subbands = GetSubbandsValue(configuration);
239*4d7e907cSAndroid Build Coastguard Worker int blocks = GetBlockLengthValue(configuration);
240*4d7e907cSAndroid Build Coastguard Worker int bits = 8 * GetFrameSize(configuration, bitpool);
241*4d7e907cSAndroid Build Coastguard Worker
242*4d7e907cSAndroid Build Coastguard Worker return (bits * sampling_frequency) / (blocks * subbands);
243*4d7e907cSAndroid Build Coastguard Worker }
244*4d7e907cSAndroid Build Coastguard Worker
GetBitpool(const A2dpBits & configuration,int bitrate)245*4d7e907cSAndroid Build Coastguard Worker static uint8_t GetBitpool(const A2dpBits& configuration, int bitrate) {
246*4d7e907cSAndroid Build Coastguard Worker int bitpool = 0;
247*4d7e907cSAndroid Build Coastguard Worker
248*4d7e907cSAndroid Build Coastguard Worker for (int i = 128; i; i >>= 1)
249*4d7e907cSAndroid Build Coastguard Worker if (bitrate > GetBitrate(configuration, bitpool + i)) {
250*4d7e907cSAndroid Build Coastguard Worker bitpool += i;
251*4d7e907cSAndroid Build Coastguard Worker }
252*4d7e907cSAndroid Build Coastguard Worker
253*4d7e907cSAndroid Build Coastguard Worker return std::clamp(bitpool, 2, 250);
254*4d7e907cSAndroid Build Coastguard Worker }
255*4d7e907cSAndroid Build Coastguard Worker
256*4d7e907cSAndroid Build Coastguard Worker /**
257*4d7e907cSAndroid Build Coastguard Worker * SBC Class implementation
258*4d7e907cSAndroid Build Coastguard Worker */
259*4d7e907cSAndroid Build Coastguard Worker
A2dpOffloadCodecSbc()260*4d7e907cSAndroid Build Coastguard Worker A2dpOffloadCodecSbc::A2dpOffloadCodecSbc()
261*4d7e907cSAndroid Build Coastguard Worker : A2dpOffloadCodec(info_),
262*4d7e907cSAndroid Build Coastguard Worker info_({.id = CodecId(CodecId::A2dp::SBC), .name = "SBC"}) {
263*4d7e907cSAndroid Build Coastguard Worker info_.transport.set<CodecInfo::Transport::Tag::a2dp>();
264*4d7e907cSAndroid Build Coastguard Worker auto& a2dp_info = info_.transport.get<CodecInfo::Transport::Tag::a2dp>();
265*4d7e907cSAndroid Build Coastguard Worker
266*4d7e907cSAndroid Build Coastguard Worker /* --- Setup Capabilities --- */
267*4d7e907cSAndroid Build Coastguard Worker
268*4d7e907cSAndroid Build Coastguard Worker a2dp_info.capabilities.resize(kCapabilitiesSize);
269*4d7e907cSAndroid Build Coastguard Worker std::fill(begin(a2dp_info.capabilities), end(a2dp_info.capabilities), 0);
270*4d7e907cSAndroid Build Coastguard Worker
271*4d7e907cSAndroid Build Coastguard Worker auto capabilities = A2dpBits(a2dp_info.capabilities);
272*4d7e907cSAndroid Build Coastguard Worker
273*4d7e907cSAndroid Build Coastguard Worker capabilities.set(kSamplingFrequency44100, kEnableSamplingFrequency44100);
274*4d7e907cSAndroid Build Coastguard Worker capabilities.set(kSamplingFrequency48000, kEnableSamplingFrequency48000);
275*4d7e907cSAndroid Build Coastguard Worker
276*4d7e907cSAndroid Build Coastguard Worker capabilities.set(kChannelModeMono, kEnableChannelModeMono);
277*4d7e907cSAndroid Build Coastguard Worker capabilities.set(kChannelModeDualChannel, kEnableChannelModeDualChannel);
278*4d7e907cSAndroid Build Coastguard Worker capabilities.set(kChannelModeStereo, kEnableChannelModeStereo);
279*4d7e907cSAndroid Build Coastguard Worker capabilities.set(kChannelModeJointStereo, kEnableChannelModeJointStereo);
280*4d7e907cSAndroid Build Coastguard Worker
281*4d7e907cSAndroid Build Coastguard Worker capabilities.set(kBlockLength4, kEnableBlockLength4);
282*4d7e907cSAndroid Build Coastguard Worker capabilities.set(kBlockLength8, kEnableBlockLength8);
283*4d7e907cSAndroid Build Coastguard Worker capabilities.set(kBlockLength12, kEnableBlockLength12);
284*4d7e907cSAndroid Build Coastguard Worker capabilities.set(kBlockLength16, kEnableBlockLength16);
285*4d7e907cSAndroid Build Coastguard Worker
286*4d7e907cSAndroid Build Coastguard Worker capabilities.set(kSubbands4, kEnableSubbands4);
287*4d7e907cSAndroid Build Coastguard Worker capabilities.set(kSubbands8, kEnableSubbands8);
288*4d7e907cSAndroid Build Coastguard Worker
289*4d7e907cSAndroid Build Coastguard Worker capabilities.set(kSubbands4, kEnableSubbands4);
290*4d7e907cSAndroid Build Coastguard Worker capabilities.set(kSubbands8, kEnableSubbands8);
291*4d7e907cSAndroid Build Coastguard Worker
292*4d7e907cSAndroid Build Coastguard Worker capabilities.set(kAllocationMethodSnr, kEnableAllocationMethodSnr);
293*4d7e907cSAndroid Build Coastguard Worker capabilities.set(kAllocationMethodLoudness, kEnableAllocationMethodLoudness);
294*4d7e907cSAndroid Build Coastguard Worker
295*4d7e907cSAndroid Build Coastguard Worker capabilities.set(kMinimumBitpool, kDefaultMinimumBitpool);
296*4d7e907cSAndroid Build Coastguard Worker capabilities.set(kMaximumBitpool, kDefaultMaximumBitpool);
297*4d7e907cSAndroid Build Coastguard Worker
298*4d7e907cSAndroid Build Coastguard Worker /* --- Setup Sampling Frequencies --- */
299*4d7e907cSAndroid Build Coastguard Worker
300*4d7e907cSAndroid Build Coastguard Worker auto& sampling_frequency = a2dp_info.samplingFrequencyHz;
301*4d7e907cSAndroid Build Coastguard Worker
302*4d7e907cSAndroid Build Coastguard Worker for (auto v : {16000, 32000, 44100, 48000})
303*4d7e907cSAndroid Build Coastguard Worker if (capabilities.get(GetSamplingFrequencyBit(int32_t(v))))
304*4d7e907cSAndroid Build Coastguard Worker sampling_frequency.push_back(v);
305*4d7e907cSAndroid Build Coastguard Worker
306*4d7e907cSAndroid Build Coastguard Worker /* --- Setup Channel Modes --- */
307*4d7e907cSAndroid Build Coastguard Worker
308*4d7e907cSAndroid Build Coastguard Worker auto& channel_modes = a2dp_info.channelMode;
309*4d7e907cSAndroid Build Coastguard Worker
310*4d7e907cSAndroid Build Coastguard Worker for (auto v : {ChannelMode::MONO, ChannelMode::DUALMONO, ChannelMode::STEREO})
311*4d7e907cSAndroid Build Coastguard Worker if (capabilities.get(GetChannelModeBit(v))) channel_modes.push_back(v);
312*4d7e907cSAndroid Build Coastguard Worker
313*4d7e907cSAndroid Build Coastguard Worker /* --- Setup Bitdepth --- */
314*4d7e907cSAndroid Build Coastguard Worker
315*4d7e907cSAndroid Build Coastguard Worker a2dp_info.bitdepth.push_back(kBitdepth);
316*4d7e907cSAndroid Build Coastguard Worker }
317*4d7e907cSAndroid Build Coastguard Worker
ParseConfiguration(const std::vector<uint8_t> & configuration,CodecParameters * codec_parameters,SbcParameters * sbc_parameters) const318*4d7e907cSAndroid Build Coastguard Worker A2dpStatus A2dpOffloadCodecSbc::ParseConfiguration(
319*4d7e907cSAndroid Build Coastguard Worker const std::vector<uint8_t>& configuration,
320*4d7e907cSAndroid Build Coastguard Worker CodecParameters* codec_parameters, SbcParameters* sbc_parameters) const {
321*4d7e907cSAndroid Build Coastguard Worker auto& a2dp_info = info.transport.get<CodecInfo::Transport::Tag::a2dp>();
322*4d7e907cSAndroid Build Coastguard Worker
323*4d7e907cSAndroid Build Coastguard Worker if (configuration.size() != a2dp_info.capabilities.size())
324*4d7e907cSAndroid Build Coastguard Worker return A2dpStatus::BAD_LENGTH;
325*4d7e907cSAndroid Build Coastguard Worker
326*4d7e907cSAndroid Build Coastguard Worker auto config = A2dpBits(configuration);
327*4d7e907cSAndroid Build Coastguard Worker auto lcaps = A2dpBits(a2dp_info.capabilities);
328*4d7e907cSAndroid Build Coastguard Worker
329*4d7e907cSAndroid Build Coastguard Worker /* --- Check Sampling Frequency --- */
330*4d7e907cSAndroid Build Coastguard Worker
331*4d7e907cSAndroid Build Coastguard Worker int sampling_frequency = config.find_active_bit(kSamplingFrequency);
332*4d7e907cSAndroid Build Coastguard Worker if (sampling_frequency < 0) return A2dpStatus::INVALID_SAMPLING_FREQUENCY;
333*4d7e907cSAndroid Build Coastguard Worker if (!lcaps.get(sampling_frequency))
334*4d7e907cSAndroid Build Coastguard Worker return A2dpStatus::NOT_SUPPORTED_SAMPLING_FREQUENCY;
335*4d7e907cSAndroid Build Coastguard Worker
336*4d7e907cSAndroid Build Coastguard Worker /* --- Check Channel Mode --- */
337*4d7e907cSAndroid Build Coastguard Worker
338*4d7e907cSAndroid Build Coastguard Worker int channel_mode = config.find_active_bit(kChannelMode);
339*4d7e907cSAndroid Build Coastguard Worker if (channel_mode < 0) return A2dpStatus::INVALID_CHANNEL_MODE;
340*4d7e907cSAndroid Build Coastguard Worker if (!lcaps.get(channel_mode)) return A2dpStatus::NOT_SUPPORTED_CHANNEL_MODE;
341*4d7e907cSAndroid Build Coastguard Worker
342*4d7e907cSAndroid Build Coastguard Worker /* --- Check Block Length --- */
343*4d7e907cSAndroid Build Coastguard Worker
344*4d7e907cSAndroid Build Coastguard Worker int block_length = config.find_active_bit(kBlockLength);
345*4d7e907cSAndroid Build Coastguard Worker if (block_length < 0) return A2dpStatus::INVALID_BLOCK_LENGTH;
346*4d7e907cSAndroid Build Coastguard Worker
347*4d7e907cSAndroid Build Coastguard Worker /* --- Check Subbands --- */
348*4d7e907cSAndroid Build Coastguard Worker
349*4d7e907cSAndroid Build Coastguard Worker int subbands = config.find_active_bit(kSubbands);
350*4d7e907cSAndroid Build Coastguard Worker if (subbands < 0) return A2dpStatus::INVALID_SUBBANDS;
351*4d7e907cSAndroid Build Coastguard Worker if (!lcaps.get(subbands)) return A2dpStatus::NOT_SUPPORTED_SUBBANDS;
352*4d7e907cSAndroid Build Coastguard Worker
353*4d7e907cSAndroid Build Coastguard Worker /* --- Check Allocation Method --- */
354*4d7e907cSAndroid Build Coastguard Worker
355*4d7e907cSAndroid Build Coastguard Worker int allocation_method = config.find_active_bit(kAllocationMethod);
356*4d7e907cSAndroid Build Coastguard Worker if (allocation_method < 0) return A2dpStatus::INVALID_ALLOCATION_METHOD;
357*4d7e907cSAndroid Build Coastguard Worker if (!lcaps.get(allocation_method))
358*4d7e907cSAndroid Build Coastguard Worker return A2dpStatus::NOT_SUPPORTED_ALLOCATION_METHOD;
359*4d7e907cSAndroid Build Coastguard Worker
360*4d7e907cSAndroid Build Coastguard Worker /* --- Check Bitpool --- */
361*4d7e907cSAndroid Build Coastguard Worker
362*4d7e907cSAndroid Build Coastguard Worker uint8_t min_bitpool = config.get(kMinimumBitpool);
363*4d7e907cSAndroid Build Coastguard Worker if (min_bitpool < 2 || min_bitpool > 250)
364*4d7e907cSAndroid Build Coastguard Worker return A2dpStatus::INVALID_MINIMUM_BITPOOL_VALUE;
365*4d7e907cSAndroid Build Coastguard Worker if (min_bitpool < lcaps.get(kMinimumBitpool))
366*4d7e907cSAndroid Build Coastguard Worker return A2dpStatus::NOT_SUPPORTED_MINIMUM_BITPOOL_VALUE;
367*4d7e907cSAndroid Build Coastguard Worker
368*4d7e907cSAndroid Build Coastguard Worker uint8_t max_bitpool = config.get(kMaximumBitpool);
369*4d7e907cSAndroid Build Coastguard Worker if (max_bitpool < 2 || max_bitpool > 250)
370*4d7e907cSAndroid Build Coastguard Worker return A2dpStatus::INVALID_MAXIMUM_BITPOOL_VALUE;
371*4d7e907cSAndroid Build Coastguard Worker if (max_bitpool > lcaps.get(kMaximumBitpool))
372*4d7e907cSAndroid Build Coastguard Worker return A2dpStatus::NOT_SUPPORTED_MAXIMUM_BITPOOL_VALUE;
373*4d7e907cSAndroid Build Coastguard Worker
374*4d7e907cSAndroid Build Coastguard Worker /* --- Return --- */
375*4d7e907cSAndroid Build Coastguard Worker
376*4d7e907cSAndroid Build Coastguard Worker codec_parameters->channelMode = GetChannelModeEnum(channel_mode);
377*4d7e907cSAndroid Build Coastguard Worker codec_parameters->samplingFrequencyHz =
378*4d7e907cSAndroid Build Coastguard Worker GetSamplingFrequencyValue(sampling_frequency);
379*4d7e907cSAndroid Build Coastguard Worker codec_parameters->bitdepth = kBitdepth;
380*4d7e907cSAndroid Build Coastguard Worker
381*4d7e907cSAndroid Build Coastguard Worker codec_parameters->minBitrate = GetBitrate(config, min_bitpool);
382*4d7e907cSAndroid Build Coastguard Worker codec_parameters->maxBitrate = GetBitrate(config, max_bitpool);
383*4d7e907cSAndroid Build Coastguard Worker
384*4d7e907cSAndroid Build Coastguard Worker if (sbc_parameters) {
385*4d7e907cSAndroid Build Coastguard Worker sbc_parameters->block_length = GetBlockLengthValue(block_length);
386*4d7e907cSAndroid Build Coastguard Worker sbc_parameters->subbands = GetSubbandsValue(subbands);
387*4d7e907cSAndroid Build Coastguard Worker sbc_parameters->allocation_method =
388*4d7e907cSAndroid Build Coastguard Worker GetAllocationMethodEnum(allocation_method);
389*4d7e907cSAndroid Build Coastguard Worker sbc_parameters->min_bitpool = min_bitpool;
390*4d7e907cSAndroid Build Coastguard Worker sbc_parameters->max_bitpool = max_bitpool;
391*4d7e907cSAndroid Build Coastguard Worker }
392*4d7e907cSAndroid Build Coastguard Worker
393*4d7e907cSAndroid Build Coastguard Worker return A2dpStatus::OK;
394*4d7e907cSAndroid Build Coastguard Worker }
395*4d7e907cSAndroid Build Coastguard Worker
BuildConfiguration(const std::vector<uint8_t> & remote_capabilities,const std::optional<CodecParameters> & hint,std::vector<uint8_t> * configuration) const396*4d7e907cSAndroid Build Coastguard Worker bool A2dpOffloadCodecSbc::BuildConfiguration(
397*4d7e907cSAndroid Build Coastguard Worker const std::vector<uint8_t>& remote_capabilities,
398*4d7e907cSAndroid Build Coastguard Worker const std::optional<CodecParameters>& hint,
399*4d7e907cSAndroid Build Coastguard Worker std::vector<uint8_t>* configuration) const {
400*4d7e907cSAndroid Build Coastguard Worker auto& a2dp_info = info.transport.get<CodecInfo::Transport::Tag::a2dp>();
401*4d7e907cSAndroid Build Coastguard Worker
402*4d7e907cSAndroid Build Coastguard Worker if (remote_capabilities.size() != a2dp_info.capabilities.size()) return false;
403*4d7e907cSAndroid Build Coastguard Worker
404*4d7e907cSAndroid Build Coastguard Worker auto lcaps = A2dpBits(a2dp_info.capabilities);
405*4d7e907cSAndroid Build Coastguard Worker auto rcaps = A2dpBits(remote_capabilities);
406*4d7e907cSAndroid Build Coastguard Worker
407*4d7e907cSAndroid Build Coastguard Worker configuration->resize(a2dp_info.capabilities.size());
408*4d7e907cSAndroid Build Coastguard Worker std::fill(begin(*configuration), end(*configuration), 0);
409*4d7e907cSAndroid Build Coastguard Worker auto config = A2dpBits(*configuration);
410*4d7e907cSAndroid Build Coastguard Worker
411*4d7e907cSAndroid Build Coastguard Worker /* --- Select Sampling Frequency --- */
412*4d7e907cSAndroid Build Coastguard Worker
413*4d7e907cSAndroid Build Coastguard Worker auto sf_hint = hint ? GetSamplingFrequencyBit(hint->samplingFrequencyHz) : -1;
414*4d7e907cSAndroid Build Coastguard Worker
415*4d7e907cSAndroid Build Coastguard Worker if (sf_hint >= 0 && lcaps.get(sf_hint) && rcaps.get(sf_hint))
416*4d7e907cSAndroid Build Coastguard Worker config.set(sf_hint);
417*4d7e907cSAndroid Build Coastguard Worker else if (lcaps.get(kSamplingFrequency44100) &&
418*4d7e907cSAndroid Build Coastguard Worker rcaps.get(kSamplingFrequency44100))
419*4d7e907cSAndroid Build Coastguard Worker config.set(kSamplingFrequency44100);
420*4d7e907cSAndroid Build Coastguard Worker else if (lcaps.get(kSamplingFrequency48000) &&
421*4d7e907cSAndroid Build Coastguard Worker rcaps.get(kSamplingFrequency48000))
422*4d7e907cSAndroid Build Coastguard Worker config.set(kSamplingFrequency48000);
423*4d7e907cSAndroid Build Coastguard Worker else
424*4d7e907cSAndroid Build Coastguard Worker return false;
425*4d7e907cSAndroid Build Coastguard Worker
426*4d7e907cSAndroid Build Coastguard Worker /* --- Select Channel Mode --- */
427*4d7e907cSAndroid Build Coastguard Worker
428*4d7e907cSAndroid Build Coastguard Worker auto cm_hint = hint ? GetChannelModeBit(hint->channelMode) : -1;
429*4d7e907cSAndroid Build Coastguard Worker
430*4d7e907cSAndroid Build Coastguard Worker if (cm_hint >= 0 && lcaps.get(cm_hint) && rcaps.get(cm_hint))
431*4d7e907cSAndroid Build Coastguard Worker config.set(cm_hint);
432*4d7e907cSAndroid Build Coastguard Worker else if (lcaps.get(kChannelModeJointStereo) &&
433*4d7e907cSAndroid Build Coastguard Worker rcaps.get(kChannelModeJointStereo))
434*4d7e907cSAndroid Build Coastguard Worker config.set(kChannelModeJointStereo);
435*4d7e907cSAndroid Build Coastguard Worker else if (lcaps.get(kChannelModeStereo) && rcaps.get(kChannelModeStereo))
436*4d7e907cSAndroid Build Coastguard Worker config.set(kChannelModeStereo);
437*4d7e907cSAndroid Build Coastguard Worker else if (lcaps.get(kChannelModeDualChannel) &&
438*4d7e907cSAndroid Build Coastguard Worker rcaps.get(kChannelModeDualChannel))
439*4d7e907cSAndroid Build Coastguard Worker config.set(kChannelModeDualChannel);
440*4d7e907cSAndroid Build Coastguard Worker else if (lcaps.get(kChannelModeMono) && rcaps.get(kChannelModeMono))
441*4d7e907cSAndroid Build Coastguard Worker config.set(kChannelModeMono);
442*4d7e907cSAndroid Build Coastguard Worker else
443*4d7e907cSAndroid Build Coastguard Worker return false;
444*4d7e907cSAndroid Build Coastguard Worker
445*4d7e907cSAndroid Build Coastguard Worker /* --- Select Block Length --- */
446*4d7e907cSAndroid Build Coastguard Worker
447*4d7e907cSAndroid Build Coastguard Worker if (lcaps.get(kBlockLength16) && rcaps.get(kBlockLength16))
448*4d7e907cSAndroid Build Coastguard Worker config.set(kBlockLength16);
449*4d7e907cSAndroid Build Coastguard Worker else if (lcaps.get(kBlockLength12) && rcaps.get(kBlockLength12))
450*4d7e907cSAndroid Build Coastguard Worker config.set(kBlockLength12);
451*4d7e907cSAndroid Build Coastguard Worker else if (lcaps.get(kBlockLength8) && rcaps.get(kBlockLength8))
452*4d7e907cSAndroid Build Coastguard Worker config.set(kBlockLength8);
453*4d7e907cSAndroid Build Coastguard Worker else if (lcaps.get(kBlockLength4) && rcaps.get(kBlockLength4))
454*4d7e907cSAndroid Build Coastguard Worker config.set(kBlockLength4);
455*4d7e907cSAndroid Build Coastguard Worker else
456*4d7e907cSAndroid Build Coastguard Worker return false;
457*4d7e907cSAndroid Build Coastguard Worker
458*4d7e907cSAndroid Build Coastguard Worker /* --- Select Subbands --- */
459*4d7e907cSAndroid Build Coastguard Worker
460*4d7e907cSAndroid Build Coastguard Worker if (lcaps.get(kSubbands8) && rcaps.get(kSubbands8))
461*4d7e907cSAndroid Build Coastguard Worker config.set(kSubbands8);
462*4d7e907cSAndroid Build Coastguard Worker else if (lcaps.get(kSubbands4) && rcaps.get(kSubbands4))
463*4d7e907cSAndroid Build Coastguard Worker config.set(kSubbands4);
464*4d7e907cSAndroid Build Coastguard Worker else
465*4d7e907cSAndroid Build Coastguard Worker return false;
466*4d7e907cSAndroid Build Coastguard Worker
467*4d7e907cSAndroid Build Coastguard Worker /* --- Select Allocation method --- */
468*4d7e907cSAndroid Build Coastguard Worker
469*4d7e907cSAndroid Build Coastguard Worker if (lcaps.get(kAllocationMethodLoudness) &&
470*4d7e907cSAndroid Build Coastguard Worker rcaps.get(kAllocationMethodLoudness))
471*4d7e907cSAndroid Build Coastguard Worker config.set(kAllocationMethodLoudness);
472*4d7e907cSAndroid Build Coastguard Worker else if (lcaps.get(kAllocationMethodSnr) && rcaps.get(kAllocationMethodSnr))
473*4d7e907cSAndroid Build Coastguard Worker config.set(kAllocationMethodSnr);
474*4d7e907cSAndroid Build Coastguard Worker else
475*4d7e907cSAndroid Build Coastguard Worker return false;
476*4d7e907cSAndroid Build Coastguard Worker
477*4d7e907cSAndroid Build Coastguard Worker /* --- Select Bitpool --- */
478*4d7e907cSAndroid Build Coastguard Worker
479*4d7e907cSAndroid Build Coastguard Worker uint8_t min_bitpool = rcaps.get(kMinimumBitpool);
480*4d7e907cSAndroid Build Coastguard Worker uint8_t max_bitpool = rcaps.get(kMaximumBitpool);
481*4d7e907cSAndroid Build Coastguard Worker
482*4d7e907cSAndroid Build Coastguard Worker if (min_bitpool < 2 || min_bitpool > 250 || max_bitpool < 2 ||
483*4d7e907cSAndroid Build Coastguard Worker max_bitpool > 250 || min_bitpool > max_bitpool) {
484*4d7e907cSAndroid Build Coastguard Worker min_bitpool = 2;
485*4d7e907cSAndroid Build Coastguard Worker max_bitpool = 250;
486*4d7e907cSAndroid Build Coastguard Worker }
487*4d7e907cSAndroid Build Coastguard Worker
488*4d7e907cSAndroid Build Coastguard Worker min_bitpool = std::max(min_bitpool, uint8_t(lcaps.get(kMinimumBitpool)));
489*4d7e907cSAndroid Build Coastguard Worker max_bitpool = std::max(max_bitpool, uint8_t(lcaps.get(kMaximumBitpool)));
490*4d7e907cSAndroid Build Coastguard Worker
491*4d7e907cSAndroid Build Coastguard Worker if (hint) {
492*4d7e907cSAndroid Build Coastguard Worker min_bitpool =
493*4d7e907cSAndroid Build Coastguard Worker std::max(min_bitpool, GetBitpool(*configuration, hint->minBitrate));
494*4d7e907cSAndroid Build Coastguard Worker if (hint->maxBitrate && hint->maxBitrate >= hint->minBitrate)
495*4d7e907cSAndroid Build Coastguard Worker max_bitpool =
496*4d7e907cSAndroid Build Coastguard Worker std::min(max_bitpool, GetBitpool(*configuration, hint->maxBitrate));
497*4d7e907cSAndroid Build Coastguard Worker }
498*4d7e907cSAndroid Build Coastguard Worker
499*4d7e907cSAndroid Build Coastguard Worker config.set(kMinimumBitpool, min_bitpool);
500*4d7e907cSAndroid Build Coastguard Worker config.set(kMaximumBitpool, max_bitpool);
501*4d7e907cSAndroid Build Coastguard Worker
502*4d7e907cSAndroid Build Coastguard Worker return true;
503*4d7e907cSAndroid Build Coastguard Worker }
504*4d7e907cSAndroid Build Coastguard Worker
505*4d7e907cSAndroid Build Coastguard Worker } // namespace aidl::android::hardware::bluetooth::audio
506