blob: 768170a397cff7a913b35d1336d8c8c6250127c0 [file] [log] [blame]
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_MEDIA_SPATIALIZER_H
#define ANDROID_MEDIA_SPATIALIZER_H
#include <android/media/BnEffect.h>
#include <android/media/BnSpatializer.h>
#include <android/media/SpatializerHeadTrackingMode.h>
#include <android/media/SpatializationLevel.h>
#include <media/AudioEffect.h>
#include <system/audio_effects/effect_spatializer.h>
namespace android {
// ----------------------------------------------------------------------------
/**
* A callback interface from the Spatializer object or its parent AudioPolicyService.
* This is implemented by the audio policy service hosting the Spatializer to perform
* actions needed when a state change inside the Spatializer requires some audio system
* changes that cannot be performed by the Spatializer. For instance opening or closing a
* spatializer output stream when the spatializer is enabled or disabled
*/
class SpatializerPolicyCallback {
public:
/** Called when a stage change occurs that requires the parent audio policy service to take
* some action.
*/
virtual void onCheckSpatializer() = 0;
virtual ~SpatializerPolicyCallback() = default;
};
/**
* The Spatializer class implements all functional controlling the multichannel spatializer
* with head tracking implementation in the native audio service: audio policy and audio flinger.
* It presents an AIDL interface available to the java audio service to discover the availability
* of the feature and options, control its state and register an active head tracking sensor.
* It maintains the current state of the platform spatializer and applies the stored parameters
* when the spatializer engine is created and enabled.
* Based on the requested spatializer level, it will request the creation of a specialized output
* mixer to the audio policy service which will in turn notify the Spatializer of the output
* stream on which a spatializer engine should be created, configured and enabled.
* The spatializer also hosts the head tracking management logic. This logic receives the
* desired head tracking mode and selected head tracking sensor, registers a sensor event listener
* and derives the compounded head pose information to the spatializer engine.
*
* Workflow:
* - Initialization: when the audio policy service starts, it checks if a spatializer effect
* engine exists and if the audio policy manager reports a dedicated spatializer output profile.
* If both conditions are met, a Spatializer object is created
* - Capabilities discovery: AudioService will call AudioSystem::canBeSpatialized() and if true,
* acquire an ISpatializer interface with AudioSystem::getSpatializer(). This interface
* will be used to query the implementation capabilities and configure the spatializer.
* - Enabling: when ISpatializer::setLevel() sets a level different from NONE the spatializer
* is considered enabled. The audio policy callback onCheckSpatializer() is called. This
* triggers a request to audio policy manager to open a spatialization output stream and a
* spatializer mixer is created in audio flinger. When an output is returned by audio policy
* manager, Spatializer::attachOutput() is called which creates and enables the spatializer
* stage engine on the specified output.
* - Disabling: when the spatialization level is set to NONE, the spatializer is considered
* disabled. The audio policy callback onCheckSpatializer() is called. This triggers a call
* to Spatializer::detachOutput() and the spatializer engine is released. Then a request is
* made to audio policy manager to release and close the spatializer output stream and the
* spatializer mixer thread is destroyed.
*/
class Spatializer : public media::BnSpatializer, public IBinder::DeathRecipient {
public:
static sp<Spatializer> create(SpatializerPolicyCallback *callback);
~Spatializer() override;
/** ISpatializer, see ISpatializer.aidl */
binder::Status release() override;
binder::Status getSupportedLevels(std::vector<media::SpatializationLevel>* levels) override;
binder::Status setLevel(media::SpatializationLevel level) override;
binder::Status getLevel(media::SpatializationLevel *level) override;
binder::Status getSupportedHeadTrackingModes(
std::vector<media::SpatializerHeadTrackingMode>* modes) override;
binder::Status setDesiredHeadTrackingMode(
media::SpatializerHeadTrackingMode mode) override;
binder::Status getActualHeadTrackingMode(
media::SpatializerHeadTrackingMode* mode) override;
binder::Status recenterHeadTracker() override;
binder::Status setGlobalTransform(const std::vector<float>& screenToStage) override;
/** IBinder::DeathRecipient. Listen to the death of the INativeSpatializerCallback. */
virtual void binderDied(const wp<IBinder>& who);
/** Registers a INativeSpatializerCallback when a client is attached to this Spatializer
* by audio policy service.
*/
status_t registerCallback(const sp<media::INativeSpatializerCallback>& callback);
/** Level getter for use by local classes. */
media::SpatializationLevel getLevel() const { Mutex::Autolock _l(mLock); return mLevel; }
/** Called by audio policy service when the special output mixer dedicated to spatialization
* is opened and the spatializer engine must be created.
*/
status_t attachOutput(audio_io_handle_t output);
/** Called by audio policy service when the special output mixer dedicated to spatialization
* is closed and the spatializer engine must be release.
*/
audio_io_handle_t detachOutput();
/** Returns the output stream the spatializer is attached to. */
audio_io_handle_t getOutput() const { Mutex::Autolock _l(mLock); return mOutput; }
/** Sets the channel mask, sampling rate and format for the spatializer input. */
void setAudioInConfig(const audio_config_base_t& config) {
Mutex::Autolock _l(mLock);
mAudioInConfig = config;
}
/** Gets the channel mask, sampling rate and format set for the spatializer input. */
audio_config_base_t getAudioInConfig() const {
Mutex::Autolock _l(mLock);
return mAudioInConfig;
}
/** An implementation of an IEffect interface that can be used to pass advanced parameters to
* the spatializer engine. All APis are noop (i.e. the interface cannot be used to control
* the effect) except for passing parameters via the command() API. */
class EffectClient: public android::media::BnEffect {
public:
EffectClient(const sp<media::IEffectClient>& effectClient,
Spatializer& parent);
virtual ~EffectClient();
// IEffect
android::binder::Status enable(int32_t* _aidl_return) override;
android::binder::Status disable(int32_t* _aidl_return) override;
android::binder::Status command(int32_t cmdCode,
const std::vector<uint8_t>& cmdData,
int32_t maxResponseSize,
std::vector<uint8_t>* response,
int32_t* _aidl_return) override;
android::binder::Status disconnect() override;
android::binder::Status getCblk(media::SharedFileRegion* _aidl_return) override;
private:
const sp<media::IEffectClient> mEffectClient;
sp<IMemory> mCblkMemory;
const Spatializer& mParent;
bool mDisconnected = false;
};
private:
Spatializer(effect_descriptor_t engineDescriptor,
SpatializerPolicyCallback *callback);
static void engineCallback(int32_t event, void* user, void *info);
/** Effect engine descriptor */
const effect_descriptor_t mEngineDescriptor;
/** Callback interface to parent audio policy service */
SpatializerPolicyCallback* mPolicyCallback;
/** Mutex protecting internal state */
mutable Mutex mLock;
/** Client AudioEffect for the engine */
sp<AudioEffect> mEngine GUARDED_BY(mLock);
/** Output stream the spatializer mixer thread is attached to */
audio_io_handle_t mOutput GUARDED_BY(mLock) = AUDIO_IO_HANDLE_NONE;
/** Virtualizer engine input configuration */
audio_config_base_t mAudioInConfig GUARDED_BY(mLock) = AUDIO_CONFIG_BASE_INITIALIZER;
/** Callback interface to the client (AudioService) controlling this`Spatializer */
sp<media::INativeSpatializerCallback> mSpatializerCallback GUARDED_BY(mLock);
/** Requested spatialization level */
media::SpatializationLevel mLevel GUARDED_BY(mLock) = media::SpatializationLevel::NONE;
/** Requested head tracking mode */
media::SpatializerHeadTrackingMode mHeadTrackingMode GUARDED_BY(mLock)
= media::SpatializerHeadTrackingMode::DISABLED;
/** Configured screen to stage transform */
std::vector<float> mScreenToStageTransform GUARDED_BY(mLock);
/** Extended IEffect interface is one has been created */
sp<EffectClient> mEffectClient GUARDED_BY(mLock);
};
}; // namespace android
#endif // ANDROID_MEDIA_SPATIALIZER_H