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 "BTAudioProviderA2dpHW"
18
19 #include "A2dpOffloadAudioProvider.h"
20
21 #include <BluetoothAudioCodecs.h>
22 #include <BluetoothAudioSessionReport.h>
23 #include <android-base/logging.h>
24
25 #include "A2dpOffloadCodecAac.h"
26 #include "A2dpOffloadCodecSbc.h"
27
28 namespace aidl {
29 namespace android {
30 namespace hardware {
31 namespace bluetooth {
32 namespace audio {
33
A2dpOffloadEncodingAudioProvider(const A2dpOffloadCodecFactory & codec_factory)34 A2dpOffloadEncodingAudioProvider::A2dpOffloadEncodingAudioProvider(
35 const A2dpOffloadCodecFactory& codec_factory)
36 : A2dpOffloadAudioProvider(codec_factory) {
37 session_type_ = SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH;
38 }
39
A2dpOffloadDecodingAudioProvider(const A2dpOffloadCodecFactory & codec_factory)40 A2dpOffloadDecodingAudioProvider::A2dpOffloadDecodingAudioProvider(
41 const A2dpOffloadCodecFactory& codec_factory)
42 : A2dpOffloadAudioProvider(codec_factory) {
43 session_type_ = SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH;
44 }
45
A2dpOffloadAudioProvider(const A2dpOffloadCodecFactory & codec_factory)46 A2dpOffloadAudioProvider::A2dpOffloadAudioProvider(
47 const A2dpOffloadCodecFactory& codec_factory)
48 : codec_factory_(codec_factory) {}
49
isValid(const SessionType & session_type)50 bool A2dpOffloadAudioProvider::isValid(const SessionType& session_type) {
51 return (session_type == session_type_);
52 }
53
startSession(const std::shared_ptr<IBluetoothAudioPort> & host_if,const AudioConfiguration & audio_config,const std::vector<LatencyMode> & latency_modes,DataMQDesc * _aidl_return)54 ndk::ScopedAStatus A2dpOffloadAudioProvider::startSession(
55 const std::shared_ptr<IBluetoothAudioPort>& host_if,
56 const AudioConfiguration& audio_config,
57 const std::vector<LatencyMode>& latency_modes, DataMQDesc* _aidl_return) {
58 if (audio_config.getTag() == AudioConfiguration::Tag::a2dp) {
59 auto a2dp_config = audio_config.get<AudioConfiguration::Tag::a2dp>();
60 A2dpStatus a2dp_status = A2dpStatus::NOT_SUPPORTED_CODEC_TYPE;
61
62 auto codec = codec_factory_.GetCodec(a2dp_config.codecId);
63 if (!codec) {
64 LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
65 << " - CodecId=" << a2dp_config.codecId.toString()
66 << " is not found";
67 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
68 }
69
70 if (codec->info.id == CodecId(CodecId::A2dp::SBC)) {
71 SbcParameters sbc_parameters;
72
73 auto codec_sbc =
74 std::static_pointer_cast<const A2dpOffloadCodecSbc>(codec);
75 a2dp_status = codec_sbc->ParseConfiguration(a2dp_config.configuration,
76 &sbc_parameters);
77
78 } else if (codec->info.id == CodecId(CodecId::A2dp::AAC)) {
79 AacParameters aac_parameters;
80
81 auto codec_aac =
82 std::static_pointer_cast<const A2dpOffloadCodecAac>(codec);
83 a2dp_status = codec_aac->ParseConfiguration(a2dp_config.configuration,
84 &aac_parameters);
85 }
86 if (a2dp_status != A2dpStatus::OK) {
87 LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
88 << audio_config.toString();
89 *_aidl_return = DataMQDesc();
90 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
91 }
92 } else if (audio_config.getTag() == AudioConfiguration::Tag::a2dpConfig) {
93 if (!BluetoothAudioCodecs::IsOffloadCodecConfigurationValid(
94 session_type_,
95 audio_config.get<AudioConfiguration::a2dpConfig>())) {
96 LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
97 << audio_config.toString();
98 *_aidl_return = DataMQDesc();
99 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
100 }
101 } else {
102 LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
103 << audio_config.toString();
104 *_aidl_return = DataMQDesc();
105 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
106 }
107
108 return BluetoothAudioProvider::startSession(
109 host_if, audio_config, latency_modes, _aidl_return);
110 }
111
onSessionReady(DataMQDesc * _aidl_return)112 ndk::ScopedAStatus A2dpOffloadAudioProvider::onSessionReady(
113 DataMQDesc* _aidl_return) {
114 *_aidl_return = DataMQDesc();
115 BluetoothAudioSessionReport::OnSessionStarted(
116 session_type_, stack_iface_, nullptr, *audio_config_, latency_modes_);
117 return ndk::ScopedAStatus::ok();
118 }
119
parseA2dpConfiguration(const CodecId & codec_id,const std::vector<uint8_t> & configuration,CodecParameters * codec_parameters,A2dpStatus * _aidl_return)120 ndk::ScopedAStatus A2dpOffloadAudioProvider::parseA2dpConfiguration(
121 const CodecId& codec_id, const std::vector<uint8_t>& configuration,
122 CodecParameters* codec_parameters, A2dpStatus* _aidl_return) {
123 if (!kEnableA2dpCodecExtensibility) {
124 // parseA2dpConfiguration must not be implemented if A2dp codec
125 // extensibility is not supported.
126 return ndk::ScopedAStatus::fromStatus(STATUS_UNKNOWN_TRANSACTION);
127 }
128
129 auto codec = codec_factory_.GetCodec(codec_id);
130 if (!codec) {
131 LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
132 << " - CodecId=" << codec_id.toString() << " is not found";
133 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
134 }
135
136 *_aidl_return = codec->ParseConfiguration(configuration, codec_parameters);
137
138 return ndk::ScopedAStatus::ok();
139 }
140
getA2dpConfiguration(const std::vector<A2dpRemoteCapabilities> & remote_a2dp_capabilities,const A2dpConfigurationHint & hint,std::optional<audio::A2dpConfiguration> * _aidl_return)141 ndk::ScopedAStatus A2dpOffloadAudioProvider::getA2dpConfiguration(
142 const std::vector<A2dpRemoteCapabilities>& remote_a2dp_capabilities,
143 const A2dpConfigurationHint& hint,
144 std::optional<audio::A2dpConfiguration>* _aidl_return) {
145 if (!kEnableA2dpCodecExtensibility) {
146 // getA2dpConfiguration must not be implemented if A2dp codec
147 // extensibility is not supported.
148 return ndk::ScopedAStatus::fromStatus(STATUS_UNKNOWN_TRANSACTION);
149 }
150
151 *_aidl_return = std::nullopt;
152 A2dpConfiguration avdtp_configuration;
153
154 if (codec_factory_.GetConfiguration(remote_a2dp_capabilities, hint,
155 &avdtp_configuration))
156 *_aidl_return =
157 std::make_optional<A2dpConfiguration>(std::move(avdtp_configuration));
158
159 return ndk::ScopedAStatus::ok();
160 }
161
162 } // namespace audio
163 } // namespace bluetooth
164 } // namespace hardware
165 } // namespace android
166 } // namespace aidl
167