blob: 345665cc54360b5d4f5348a69a6902b286788a5b [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;
43using media::HeadTrackingMode;
44using media::SpatializationLevel;
45
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(
180 std::vector<media::HeadTrackingMode>* modes) {
181 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
189 modes->push_back(HeadTrackingMode::RELATIVE_WORLD);
190 return Status::ok();
191}
192
193Status Spatializer::setDesiredHeadTrackingMode(media::HeadTrackingMode mode) {
194 ALOGV("%s level %d", __func__, (int)mode);
195 if (mode != HeadTrackingMode::DISABLED
196 && mode != HeadTrackingMode::RELATIVE_WORLD) {
197 return binderStatusFromStatusT(BAD_VALUE);
198 }
199 {
200 Mutex::Autolock _l(mLock);
201 mHeadTrackingMode = mode;
202 }
203 return Status::ok();
204}
205
206Status Spatializer::getActualHeadTrackingMode(media::HeadTrackingMode *mode) {
207 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
216Status Spatializer::recenterHeadtracker() {
217 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);
262 mEngine->set(nullptr, &mEngineDescriptor.uuid, 0,
263 Spatializer::engineCallback /* cbf */, this /* user */,
264 AUDIO_SESSION_OUTPUT_STAGE, output,
265 {} /* device */, false /* probe */, true /* notifyFramesProcessed */);
266 status_t status = mEngine->initCheck();
267 ALOGV("%s mEngine create status %d", __func__, (int)status);
268 if (status != NO_ERROR) {
269 return status;
270 }
271 mEngine->setEnabled(true);
272 mOutput = output;
273 return NO_ERROR;
274}
275
276audio_io_handle_t Spatializer::detachOutput() {
277 Mutex::Autolock _l(mLock);
278 ALOGV("%s mOutput %d", __func__, (int)mOutput);
279 if (mOutput == AUDIO_IO_HANDLE_NONE) {
280 return AUDIO_IO_HANDLE_NONE;
281 }
282 // remove FX instance
283 mEngine->setEnabled(false);
284 mEngine.clear();
285 audio_io_handle_t output = mOutput;
286 mOutput = AUDIO_IO_HANDLE_NONE;
287 return output;
288}
289
290void Spatializer::engineCallback(int32_t event, void *user, void *info) {
291
292 if (user == nullptr) {
293 return;
294 }
295 const Spatializer * const me = reinterpret_cast<Spatializer *>(user);
296 switch (event) {
297 case AudioEffect::EVENT_FRAMES_PROCESSED: {
298 int frames = info == nullptr ? 0 : *(int *)info;
299 ALOGD("%s frames processed %d for me %p", __func__, frames, me);
300 } break;
301 default:
302 ALOGD("%s event %d", __func__, event);
303 break;
304 }
305}
306
307// ---------------------------------------------------------------------------
308
309Spatializer::EffectClient::EffectClient(const sp<media::IEffectClient>& effectClient,
310 Spatializer& parent)
311 : BnEffect(),
312 mEffectClient(effectClient), mParent(parent) {
313}
314
315Spatializer::EffectClient::~EffectClient() {
316}
317
318// IEffect
319
320#define RETURN(code) \
321 *_aidl_return = (code); \
322 return Status::ok();
323
324// Write a POD value into a vector of bytes (clears the previous buffer
325// content).
326template<typename T>
327void writeToBuffer(const T& value, std::vector<uint8_t>* buffer) {
328 buffer->clear();
329 appendToBuffer(value, buffer);
330}
331
332Status Spatializer::EffectClient::enable(int32_t* _aidl_return) {
333 RETURN(OK);
334}
335
336Status Spatializer::EffectClient::disable(int32_t* _aidl_return) {
337 RETURN(OK);
338}
339
340Status Spatializer::EffectClient::command(int32_t cmdCode,
341 const std::vector<uint8_t>& cmdData __unused,
342 int32_t maxResponseSize __unused,
343 std::vector<uint8_t>* response __unused,
344 int32_t* _aidl_return) {
345
346 // reject commands reserved for internal use by audio framework if coming from outside
347 // of audioserver
348 switch(cmdCode) {
349 case EFFECT_CMD_ENABLE:
350 case EFFECT_CMD_DISABLE:
351 case EFFECT_CMD_SET_PARAM_DEFERRED:
352 case EFFECT_CMD_SET_PARAM_COMMIT:
353 RETURN(BAD_VALUE);
354 case EFFECT_CMD_SET_PARAM:
355 case EFFECT_CMD_GET_PARAM:
356 break;
357 default:
358 if (cmdCode >= EFFECT_CMD_FIRST_PROPRIETARY) {
359 break;
360 }
361 android_errorWriteLog(0x534e4554, "62019992");
362 RETURN(BAD_VALUE);
363 }
364 (void)mParent;
365 RETURN(OK);
366}
367
368Status Spatializer::EffectClient::disconnect() {
369 mDisconnected = true;
370 return Status::ok();
371}
372
373Status Spatializer::EffectClient::getCblk(media::SharedFileRegion* _aidl_return) {
374 LOG_ALWAYS_FATAL_IF(!convertIMemoryToSharedFileRegion(mCblkMemory, _aidl_return));
375 return Status::ok();
376}
377
378} // namespace android