blob: aa104a020230bcc591a7e99350c29fcb7fafa046 [file] [log] [blame]
Eric Laurent6d607012021-07-05 11:54:40 +02001/*
2**
3** Copyright 2021, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18
19#define LOG_TAG "Spatializer"
20//#define LOG_NDEBUG 0
21#include <utils/Log.h>
22
23#include <limits.h>
24#include <stdint.h>
25#include <sys/types.h>
26
27#include <android/content/AttributionSourceState.h>
28#include <audio_utils/fixedfft.h>
29#include <cutils/bitops.h>
30#include <media/ShmemCompat.h>
31#include <media/audiohal/EffectsFactoryHalInterface.h>
32#include <mediautils/ServiceUtilities.h>
33#include <utils/Thread.h>
34
35#include "Spatializer.h"
36
37namespace android {
38
39using aidl_utils::statusTFromBinderStatus;
40using aidl_utils::binderStatusFromStatusT;
41using android::content::AttributionSourceState;
42using binder::Status;
Eric Laurent6d607012021-07-05 11:54:40 +020043using media::SpatializationLevel;
Ytai Ben-Tsvia16a9df2021-08-05 08:57:06 -070044using media::SpatializerHeadTrackingMode;
Eric Laurent6d607012021-07-05 11:54:40 +020045
46#define VALUE_OR_RETURN_BINDER_STATUS(x) \
47 ({ auto _tmp = (x); \
48 if (!_tmp.ok()) return aidl_utils::binderStatusFromStatusT(_tmp.error()); \
49 std::move(_tmp.value()); })
50
51#define RETURN_IF_BINDER_ERROR(x) \
52 { \
53 binder::Status _tmp = (x); \
54 if (!_tmp.isOk()) return _tmp; \
55 }
56
57// ---------------------------------------------------------------------------
58
59sp<Spatializer> Spatializer::create(SpatializerPolicyCallback *callback) {
60 sp<Spatializer> spatializer;
61
62 sp<EffectsFactoryHalInterface> effectsFactoryHal = EffectsFactoryHalInterface::create();
63 if (effectsFactoryHal == nullptr) {
64 ALOGW("%s failed to create effect factory interface", __func__);
65 return spatializer;
66 }
67
68 std::vector<effect_descriptor_t> descriptors;
69 status_t status =
Eric Laurent1c5e2e32021-08-18 18:50:28 +020070 effectsFactoryHal->getDescriptors(FX_IID_SPATIALIZER, &descriptors);
Eric Laurent6d607012021-07-05 11:54:40 +020071 if (status != NO_ERROR) {
72 ALOGW("%s failed to get spatializer descriptor, error %d", __func__, status);
73 return spatializer;
74 }
75 ALOG_ASSERT(!descriptors.empty(),
76 "%s getDescriptors() returned no error but empty list", __func__);
77
78 //TODO: get supported spatialization modes from FX engine or descriptor
79
80 sp<EffectHalInterface> effect;
81 status = effectsFactoryHal->createEffect(&descriptors[0].uuid, AUDIO_SESSION_OUTPUT_STAGE,
82 AUDIO_IO_HANDLE_NONE, AUDIO_PORT_HANDLE_NONE, &effect);
83 ALOGI("%s FX create status %d effect %p", __func__, status, effect.get());
84
85 if (status == NO_ERROR && effect != nullptr) {
86 spatializer = new Spatializer(descriptors[0], callback);
87 // TODO: Read supported config from engine
88 audio_config_base_t config = AUDIO_CONFIG_BASE_INITIALIZER;
89 config.channel_mask = AUDIO_CHANNEL_OUT_5POINT1;
90 spatializer->setAudioInConfig(config);
91 }
92
93 return spatializer;
94}
95
96Spatializer::Spatializer(effect_descriptor_t engineDescriptor,
97 SpatializerPolicyCallback *callback)
98 : mEngineDescriptor(engineDescriptor), mPolicyCallback(callback) {
99 ALOGV("%s", __func__);
100}
101
102Spatializer::~Spatializer() {
103 ALOGV("%s", __func__);
104}
105
106status_t Spatializer::registerCallback(
107 const sp<media::INativeSpatializerCallback>& callback) {
108 Mutex::Autolock _l(mLock);
109 if (callback == nullptr) {
110 return BAD_VALUE;
111 }
112
113 sp<IBinder> binder = IInterface::asBinder(callback);
114 status_t status = binder->linkToDeath(this);
115 if (status == NO_ERROR) {
116 mSpatializerCallback = callback;
117 }
118 ALOGV("%s status %d", __func__, status);
119 return status;
120}
121
122// IBinder::DeathRecipient
123void Spatializer::binderDied(__unused const wp<IBinder> &who) {
124 {
125 Mutex::Autolock _l(mLock);
126 mLevel = SpatializationLevel::NONE;
127 mSpatializerCallback.clear();
128 }
129 ALOGV("%s", __func__);
130 mPolicyCallback->onCheckSpatializer();
131}
132
133// ISpatializer
134Status Spatializer::getSupportedLevels(std::vector<SpatializationLevel> *levels) {
135 ALOGV("%s", __func__);
136 if (levels == nullptr) {
137 return binderStatusFromStatusT(BAD_VALUE);
138 }
139 //TODO: get this from engine
140 levels->push_back(SpatializationLevel::NONE);
141 levels->push_back(SpatializationLevel::SPATIALIZER_MULTICHANNEL);
142 return Status::ok();
143}
144
145Status Spatializer::setLevel(media::SpatializationLevel level) {
146 ALOGV("%s level %d", __func__, (int)level);
147 if (level != SpatializationLevel::NONE
148 && level != SpatializationLevel::SPATIALIZER_MULTICHANNEL) {
149 return binderStatusFromStatusT(BAD_VALUE);
150 }
151 sp<media::INativeSpatializerCallback> callback;
152 bool levelChanged = false;
153 {
154 Mutex::Autolock _l(mLock);
155 levelChanged = mLevel != level;
156 mLevel = level;
157 callback = mSpatializerCallback;
158 }
159
160 if (levelChanged) {
161 mPolicyCallback->onCheckSpatializer();
162 if (callback != nullptr) {
163 callback->onLevelChanged(level);
164 }
165 }
166 return Status::ok();
167}
168
169Status Spatializer::getLevel(media::SpatializationLevel *level) {
170 if (level == nullptr) {
171 return binderStatusFromStatusT(BAD_VALUE);
172 }
173 Mutex::Autolock _l(mLock);
174 *level = mLevel;
175 ALOGV("%s level %d", __func__, (int)*level);
176 return Status::ok();
177}
178
179Status Spatializer::getSupportedHeadTrackingModes(
Ytai Ben-Tsvia16a9df2021-08-05 08:57:06 -0700180 std::vector<media::SpatializerHeadTrackingMode>* modes) {
Eric Laurent6d607012021-07-05 11:54:40 +0200181 ALOGV("%s", __func__);
182 if (modes == nullptr) {
183 return binderStatusFromStatusT(BAD_VALUE);
184 }
185 //TODO: get this from:
186 // - The engine capabilities
187 // - If a head tracking sensor is registered and linked to a connected audio device
188 // - if we have indications on the screen orientation
Ytai Ben-Tsvia16a9df2021-08-05 08:57:06 -0700189 modes->push_back(SpatializerHeadTrackingMode::RELATIVE_WORLD);
Eric Laurent6d607012021-07-05 11:54:40 +0200190 return Status::ok();
191}
192
Ytai Ben-Tsvia16a9df2021-08-05 08:57:06 -0700193Status Spatializer::setDesiredHeadTrackingMode(media::SpatializerHeadTrackingMode mode) {
Eric Laurent6d607012021-07-05 11:54:40 +0200194 ALOGV("%s level %d", __func__, (int)mode);
Ytai Ben-Tsvia16a9df2021-08-05 08:57:06 -0700195 if (mode != SpatializerHeadTrackingMode::DISABLED
196 && mode != SpatializerHeadTrackingMode::RELATIVE_WORLD) {
Eric Laurent6d607012021-07-05 11:54:40 +0200197 return binderStatusFromStatusT(BAD_VALUE);
198 }
199 {
200 Mutex::Autolock _l(mLock);
201 mHeadTrackingMode = mode;
202 }
203 return Status::ok();
204}
205
Ytai Ben-Tsvia16a9df2021-08-05 08:57:06 -0700206Status Spatializer::getActualHeadTrackingMode(media::SpatializerHeadTrackingMode *mode) {
Eric Laurent6d607012021-07-05 11:54:40 +0200207 if (mode == nullptr) {
208 return binderStatusFromStatusT(BAD_VALUE);
209 }
210 Mutex::Autolock _l(mLock);
211 *mode = mHeadTrackingMode;
212 ALOGV("%s mode %d", __func__, (int)*mode);
213 return Status::ok();
214}
215
Ytai Ben-Tsvia16a9df2021-08-05 08:57:06 -0700216Status Spatializer::recenterHeadTracker() {
Eric Laurent6d607012021-07-05 11:54:40 +0200217 return Status::ok();
218}
219
220Status Spatializer::setGlobalTransform(const std::vector<float>& screenToStage) {
221 Mutex::Autolock _l(mLock);
222 mScreenToStageTransform = screenToStage;
223 ALOGV("%s", __func__);
224 return Status::ok();
225}
226
227Status Spatializer::release() {
228 ALOGV("%s", __func__);
229 bool levelChanged = false;
230 {
231 Mutex::Autolock _l(mLock);
232 if (mSpatializerCallback == nullptr) {
233 return binderStatusFromStatusT(INVALID_OPERATION);
234 }
235
236 sp<IBinder> binder = IInterface::asBinder(mSpatializerCallback);
237 binder->unlinkToDeath(this);
238 mSpatializerCallback.clear();
239
240 levelChanged = mLevel != SpatializationLevel::NONE;
241 mLevel = SpatializationLevel::NONE;
242 }
243
244 if (levelChanged) {
245 mPolicyCallback->onCheckSpatializer();
246 }
247 return Status::ok();
248}
249
250status_t Spatializer::attachOutput(audio_io_handle_t output) {
251 Mutex::Autolock _l(mLock);
252 ALOGV("%s output %d mOutput %d", __func__, (int)output, (int)mOutput);
253 if (mOutput != AUDIO_IO_HANDLE_NONE) {
254 LOG_ALWAYS_FATAL_IF(mEngine != nullptr, "%s output set without FX engine", __func__);
255 // remove FX instance
256 mEngine->setEnabled(false);
257 mEngine.clear();
258 }
259 // create FX instance on output
260 AttributionSourceState attributionSource = AttributionSourceState();
261 mEngine = new AudioEffect(attributionSource);
Ytai Ben-Tsvia16a9df2021-08-05 08:57:06 -0700262 mEngine->set(nullptr, &mEngineDescriptor.uuid, 0, Spatializer::engineCallback /* cbf */,
263 this /* user */, AUDIO_SESSION_OUTPUT_STAGE, output, {} /* device */,
264 false /* probe */, true /* notifyFramesProcessed */);
Eric Laurent6d607012021-07-05 11:54:40 +0200265 status_t status = mEngine->initCheck();
266 ALOGV("%s mEngine create status %d", __func__, (int)status);
267 if (status != NO_ERROR) {
268 return status;
269 }
270 mEngine->setEnabled(true);
271 mOutput = output;
272 return NO_ERROR;
273}
274
275audio_io_handle_t Spatializer::detachOutput() {
276 Mutex::Autolock _l(mLock);
277 ALOGV("%s mOutput %d", __func__, (int)mOutput);
278 if (mOutput == AUDIO_IO_HANDLE_NONE) {
279 return AUDIO_IO_HANDLE_NONE;
280 }
281 // remove FX instance
282 mEngine->setEnabled(false);
283 mEngine.clear();
284 audio_io_handle_t output = mOutput;
285 mOutput = AUDIO_IO_HANDLE_NONE;
286 return output;
287}
288
289void Spatializer::engineCallback(int32_t event, void *user, void *info) {
290
291 if (user == nullptr) {
292 return;
293 }
294 const Spatializer * const me = reinterpret_cast<Spatializer *>(user);
295 switch (event) {
296 case AudioEffect::EVENT_FRAMES_PROCESSED: {
297 int frames = info == nullptr ? 0 : *(int *)info;
298 ALOGD("%s frames processed %d for me %p", __func__, frames, me);
299 } break;
300 default:
301 ALOGD("%s event %d", __func__, event);
302 break;
303 }
304}
305
306// ---------------------------------------------------------------------------
307
308Spatializer::EffectClient::EffectClient(const sp<media::IEffectClient>& effectClient,
309 Spatializer& parent)
310 : BnEffect(),
311 mEffectClient(effectClient), mParent(parent) {
312}
313
314Spatializer::EffectClient::~EffectClient() {
315}
316
317// IEffect
318
319#define RETURN(code) \
320 *_aidl_return = (code); \
321 return Status::ok();
322
323// Write a POD value into a vector of bytes (clears the previous buffer
324// content).
325template<typename T>
326void writeToBuffer(const T& value, std::vector<uint8_t>* buffer) {
327 buffer->clear();
328 appendToBuffer(value, buffer);
329}
330
331Status Spatializer::EffectClient::enable(int32_t* _aidl_return) {
332 RETURN(OK);
333}
334
335Status Spatializer::EffectClient::disable(int32_t* _aidl_return) {
336 RETURN(OK);
337}
338
339Status Spatializer::EffectClient::command(int32_t cmdCode,
340 const std::vector<uint8_t>& cmdData __unused,
341 int32_t maxResponseSize __unused,
342 std::vector<uint8_t>* response __unused,
343 int32_t* _aidl_return) {
344
345 // reject commands reserved for internal use by audio framework if coming from outside
346 // of audioserver
347 switch(cmdCode) {
348 case EFFECT_CMD_ENABLE:
349 case EFFECT_CMD_DISABLE:
350 case EFFECT_CMD_SET_PARAM_DEFERRED:
351 case EFFECT_CMD_SET_PARAM_COMMIT:
352 RETURN(BAD_VALUE);
353 case EFFECT_CMD_SET_PARAM:
354 case EFFECT_CMD_GET_PARAM:
355 break;
356 default:
357 if (cmdCode >= EFFECT_CMD_FIRST_PROPRIETARY) {
358 break;
359 }
360 android_errorWriteLog(0x534e4554, "62019992");
361 RETURN(BAD_VALUE);
362 }
363 (void)mParent;
364 RETURN(OK);
365}
366
367Status Spatializer::EffectClient::disconnect() {
368 mDisconnected = true;
369 return Status::ok();
370}
371
372Status Spatializer::EffectClient::getCblk(media::SharedFileRegion* _aidl_return) {
373 LOG_ALWAYS_FATAL_IF(!convertIMemoryToSharedFileRegion(mCblkMemory, _aidl_return));
374 return Status::ok();
375}
376
377} // namespace android