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