Shunkai Yao | 65c7c70 | 2024-01-09 20:50:53 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2024 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 <memory> |
| 18 | #define LOG_TAG "AHAL_EffectContext" |
| 19 | #include "effect-impl/EffectContext.h" |
| 20 | #include "include/effect-impl/EffectTypes.h" |
| 21 | |
| 22 | using aidl::android::hardware::audio::common::getChannelCount; |
| 23 | using aidl::android::hardware::audio::common::getFrameSizeInBytes; |
| 24 | using aidl::android::hardware::audio::effect::IEffect; |
Shunkai Yao | 7e2c371 | 2024-02-03 06:47:18 +0000 | [diff] [blame] | 25 | using aidl::android::hardware::audio::effect::kReopenSupportedVersion; |
Shunkai Yao | 65c7c70 | 2024-01-09 20:50:53 +0000 | [diff] [blame] | 26 | using aidl::android::media::audio::common::PcmType; |
| 27 | using ::android::hardware::EventFlag; |
| 28 | |
| 29 | namespace aidl::android::hardware::audio::effect { |
| 30 | |
| 31 | EffectContext::EffectContext(size_t statusDepth, const Parameter::Common& common) { |
| 32 | LOG_ALWAYS_FATAL_IF(RetCode::SUCCESS != setCommon(common), "illegalCommonParameter"); |
| 33 | |
| 34 | // in/outBuffer size in float (FMQ data format defined for DataMQ) |
| 35 | size_t inBufferSizeInFloat = common.input.frameCount * mInputFrameSize / sizeof(float); |
| 36 | size_t outBufferSizeInFloat = common.output.frameCount * mOutputFrameSize / sizeof(float); |
| 37 | |
| 38 | // only status FMQ use the EventFlag |
| 39 | mStatusMQ = std::make_shared<StatusMQ>(statusDepth, true /*configureEventFlagWord*/); |
| 40 | mInputMQ = std::make_shared<DataMQ>(inBufferSizeInFloat); |
| 41 | mOutputMQ = std::make_shared<DataMQ>(outBufferSizeInFloat); |
| 42 | |
| 43 | if (!mStatusMQ->isValid() || !mInputMQ->isValid() || !mOutputMQ->isValid()) { |
Shunkai Yao | 7e2c371 | 2024-02-03 06:47:18 +0000 | [diff] [blame] | 44 | LOG(ERROR) << __func__ << " created invalid FMQ, statusMQ: " << mStatusMQ->isValid() |
| 45 | << " inputMQ: " << mInputMQ->isValid() << " outputMQ: " << mOutputMQ->isValid(); |
Shunkai Yao | 65c7c70 | 2024-01-09 20:50:53 +0000 | [diff] [blame] | 46 | } |
| 47 | |
| 48 | ::android::status_t status = |
| 49 | EventFlag::createEventFlag(mStatusMQ->getEventFlagWord(), &mEfGroup); |
| 50 | LOG_ALWAYS_FATAL_IF(status != ::android::OK || !mEfGroup, " create EventFlagGroup failed "); |
Shunkai Yao | 08c05dd | 2024-01-25 00:45:55 +0000 | [diff] [blame] | 51 | mWorkBuffer.resize(std::max(inBufferSizeInFloat, outBufferSizeInFloat)); |
Shunkai Yao | 65c7c70 | 2024-01-09 20:50:53 +0000 | [diff] [blame] | 52 | } |
| 53 | |
| 54 | // reset buffer status by abandon input data in FMQ |
| 55 | void EffectContext::resetBuffer() { |
| 56 | auto buffer = static_cast<float*>(mWorkBuffer.data()); |
Shunkai Yao | 7e2c371 | 2024-02-03 06:47:18 +0000 | [diff] [blame] | 57 | if (mStatusMQ) { |
| 58 | std::vector<IEffect::Status> status(mStatusMQ->availableToRead()); |
| 59 | } |
Shunkai Yao | 65c7c70 | 2024-01-09 20:50:53 +0000 | [diff] [blame] | 60 | if (mInputMQ) { |
| 61 | mInputMQ->read(buffer, mInputMQ->availableToRead()); |
| 62 | } |
| 63 | } |
| 64 | |
| 65 | void EffectContext::dupeFmqWithReopen(IEffect::OpenEffectReturn* effectRet) { |
| 66 | if (!mInputMQ) { |
| 67 | mInputMQ = std::make_shared<DataMQ>(mCommon.input.frameCount * mInputFrameSize / |
| 68 | sizeof(float)); |
| 69 | } |
| 70 | if (!mOutputMQ) { |
| 71 | mOutputMQ = std::make_shared<DataMQ>(mCommon.output.frameCount * mOutputFrameSize / |
| 72 | sizeof(float)); |
| 73 | } |
| 74 | dupeFmq(effectRet); |
| 75 | } |
| 76 | |
| 77 | void EffectContext::dupeFmq(IEffect::OpenEffectReturn* effectRet) { |
Shunkai Yao | 7e2c371 | 2024-02-03 06:47:18 +0000 | [diff] [blame] | 78 | if (effectRet && mStatusMQ && mInputMQ && mOutputMQ) { |
Shunkai Yao | 65c7c70 | 2024-01-09 20:50:53 +0000 | [diff] [blame] | 79 | effectRet->statusMQ = mStatusMQ->dupeDesc(); |
| 80 | effectRet->inputDataMQ = mInputMQ->dupeDesc(); |
| 81 | effectRet->outputDataMQ = mOutputMQ->dupeDesc(); |
| 82 | } |
| 83 | } |
| 84 | |
| 85 | float* EffectContext::getWorkBuffer() { |
| 86 | return static_cast<float*>(mWorkBuffer.data()); |
| 87 | } |
| 88 | |
Shunkai Yao | 08c05dd | 2024-01-25 00:45:55 +0000 | [diff] [blame] | 89 | size_t EffectContext::getWorkBufferSize() const { |
| 90 | return mWorkBuffer.size(); |
| 91 | } |
| 92 | |
Shunkai Yao | 65c7c70 | 2024-01-09 20:50:53 +0000 | [diff] [blame] | 93 | std::shared_ptr<EffectContext::StatusMQ> EffectContext::getStatusFmq() const { |
| 94 | return mStatusMQ; |
| 95 | } |
| 96 | |
| 97 | std::shared_ptr<EffectContext::DataMQ> EffectContext::getInputDataFmq() const { |
| 98 | return mInputMQ; |
| 99 | } |
| 100 | |
| 101 | std::shared_ptr<EffectContext::DataMQ> EffectContext::getOutputDataFmq() const { |
| 102 | return mOutputMQ; |
| 103 | } |
| 104 | |
| 105 | size_t EffectContext::getInputFrameSize() const { |
| 106 | return mInputFrameSize; |
| 107 | } |
| 108 | |
| 109 | size_t EffectContext::getOutputFrameSize() const { |
| 110 | return mOutputFrameSize; |
| 111 | } |
| 112 | |
| 113 | int EffectContext::getSessionId() const { |
| 114 | return mCommon.session; |
| 115 | } |
| 116 | |
| 117 | int EffectContext::getIoHandle() const { |
| 118 | return mCommon.ioHandle; |
| 119 | } |
| 120 | |
| 121 | RetCode EffectContext::setOutputDevice( |
| 122 | const std::vector<aidl::android::media::audio::common::AudioDeviceDescription>& device) { |
| 123 | mOutputDevice = device; |
| 124 | return RetCode::SUCCESS; |
| 125 | } |
| 126 | |
| 127 | std::vector<aidl::android::media::audio::common::AudioDeviceDescription> |
| 128 | EffectContext::getOutputDevice() { |
| 129 | return mOutputDevice; |
| 130 | } |
| 131 | |
| 132 | RetCode EffectContext::setAudioMode(const aidl::android::media::audio::common::AudioMode& mode) { |
| 133 | mMode = mode; |
| 134 | return RetCode::SUCCESS; |
| 135 | } |
| 136 | aidl::android::media::audio::common::AudioMode EffectContext::getAudioMode() { |
| 137 | return mMode; |
| 138 | } |
| 139 | |
| 140 | RetCode EffectContext::setAudioSource( |
| 141 | const aidl::android::media::audio::common::AudioSource& source) { |
| 142 | mSource = source; |
| 143 | return RetCode::SUCCESS; |
| 144 | } |
| 145 | |
| 146 | aidl::android::media::audio::common::AudioSource EffectContext::getAudioSource() { |
| 147 | return mSource; |
| 148 | } |
| 149 | |
| 150 | RetCode EffectContext::setVolumeStereo(const Parameter::VolumeStereo& volumeStereo) { |
| 151 | mVolumeStereo = volumeStereo; |
| 152 | return RetCode::SUCCESS; |
| 153 | } |
| 154 | |
| 155 | Parameter::VolumeStereo EffectContext::getVolumeStereo() { |
| 156 | return mVolumeStereo; |
| 157 | } |
| 158 | |
| 159 | RetCode EffectContext::setCommon(const Parameter::Common& common) { |
| 160 | LOG(VERBOSE) << __func__ << common.toString(); |
| 161 | auto& input = common.input; |
| 162 | auto& output = common.output; |
| 163 | |
| 164 | if (input.base.format.pcm != aidl::android::media::audio::common::PcmType::FLOAT_32_BIT || |
| 165 | output.base.format.pcm != aidl::android::media::audio::common::PcmType::FLOAT_32_BIT) { |
| 166 | LOG(ERROR) << __func__ << " illegal IO, input " |
| 167 | << ::android::internal::ToString(input.base.format) << ", output " |
| 168 | << ::android::internal::ToString(output.base.format); |
| 169 | return RetCode::ERROR_ILLEGAL_PARAMETER; |
| 170 | } |
| 171 | |
| 172 | if (auto ret = updateIOFrameSize(common); ret != RetCode::SUCCESS) { |
| 173 | return ret; |
| 174 | } |
| 175 | |
| 176 | mInputChannelCount = getChannelCount(input.base.channelMask); |
| 177 | mOutputChannelCount = getChannelCount(output.base.channelMask); |
| 178 | if (mInputChannelCount == 0 || mOutputChannelCount == 0) { |
| 179 | LOG(ERROR) << __func__ << " illegal channel count input " << mInputChannelCount |
| 180 | << ", output " << mOutputChannelCount; |
| 181 | return RetCode::ERROR_ILLEGAL_PARAMETER; |
| 182 | } |
| 183 | |
| 184 | mCommon = common; |
| 185 | return RetCode::SUCCESS; |
| 186 | } |
| 187 | |
| 188 | Parameter::Common EffectContext::getCommon() { |
| 189 | LOG(VERBOSE) << __func__ << mCommon.toString(); |
| 190 | return mCommon; |
| 191 | } |
| 192 | |
| 193 | EventFlag* EffectContext::getStatusEventFlag() { |
| 194 | return mEfGroup; |
| 195 | } |
| 196 | |
| 197 | RetCode EffectContext::updateIOFrameSize(const Parameter::Common& common) { |
Shunkai Yao | 7e2c371 | 2024-02-03 06:47:18 +0000 | [diff] [blame] | 198 | const auto prevInputFrameSize = mInputFrameSize; |
| 199 | const auto prevOutputFrameSize = mOutputFrameSize; |
| 200 | mInputFrameSize = ::aidl::android::hardware::audio::common::getFrameSizeInBytes( |
Shunkai Yao | 65c7c70 | 2024-01-09 20:50:53 +0000 | [diff] [blame] | 201 | common.input.base.format, common.input.base.channelMask); |
Shunkai Yao | 7e2c371 | 2024-02-03 06:47:18 +0000 | [diff] [blame] | 202 | mOutputFrameSize = ::aidl::android::hardware::audio::common::getFrameSizeInBytes( |
Shunkai Yao | 65c7c70 | 2024-01-09 20:50:53 +0000 | [diff] [blame] | 203 | common.output.base.format, common.output.base.channelMask); |
| 204 | |
Shunkai Yao | 7e2c371 | 2024-02-03 06:47:18 +0000 | [diff] [blame] | 205 | // workBuffer and data MQ not allocated yet, no need to update |
| 206 | if (mWorkBuffer.size() == 0 || !mInputMQ || !mOutputMQ) { |
| 207 | return RetCode::SUCCESS; |
| 208 | } |
| 209 | // IEffect::reopen introduced in android.hardware.audio.effect-V2 |
| 210 | if (mVersion < kReopenSupportedVersion) { |
| 211 | LOG(WARNING) << __func__ << " skipped for HAL version " << mVersion; |
| 212 | return RetCode::SUCCESS; |
| 213 | } |
Shunkai Yao | 65c7c70 | 2024-01-09 20:50:53 +0000 | [diff] [blame] | 214 | bool needUpdateMq = false; |
Shunkai Yao | 7e2c371 | 2024-02-03 06:47:18 +0000 | [diff] [blame] | 215 | if (mInputFrameSize != prevInputFrameSize || |
| 216 | mCommon.input.frameCount != common.input.frameCount) { |
Shunkai Yao | 65c7c70 | 2024-01-09 20:50:53 +0000 | [diff] [blame] | 217 | mInputMQ.reset(); |
| 218 | needUpdateMq = true; |
| 219 | } |
Shunkai Yao | 7e2c371 | 2024-02-03 06:47:18 +0000 | [diff] [blame] | 220 | if (mOutputFrameSize != prevOutputFrameSize || |
| 221 | mCommon.output.frameCount != common.output.frameCount) { |
Shunkai Yao | 65c7c70 | 2024-01-09 20:50:53 +0000 | [diff] [blame] | 222 | mOutputMQ.reset(); |
| 223 | needUpdateMq = true; |
| 224 | } |
Shunkai Yao | 7e2c371 | 2024-02-03 06:47:18 +0000 | [diff] [blame] | 225 | |
Shunkai Yao | 65c7c70 | 2024-01-09 20:50:53 +0000 | [diff] [blame] | 226 | if (needUpdateMq) { |
Shunkai Yao | 08c05dd | 2024-01-25 00:45:55 +0000 | [diff] [blame] | 227 | mWorkBuffer.resize(std::max(common.input.frameCount * mInputFrameSize / sizeof(float), |
| 228 | common.output.frameCount * mOutputFrameSize / sizeof(float))); |
Shunkai Yao | 65c7c70 | 2024-01-09 20:50:53 +0000 | [diff] [blame] | 229 | return notifyDataMqUpdate(); |
| 230 | } |
| 231 | return RetCode::SUCCESS; |
| 232 | } |
| 233 | |
| 234 | RetCode EffectContext::notifyDataMqUpdate() { |
| 235 | if (!mEfGroup) { |
| 236 | LOG(ERROR) << __func__ << ": invalid EventFlag group"; |
| 237 | return RetCode::ERROR_EVENT_FLAG_ERROR; |
| 238 | } |
| 239 | |
| 240 | if (const auto ret = mEfGroup->wake(kEventFlagDataMqUpdate); ret != ::android::OK) { |
| 241 | LOG(ERROR) << __func__ << ": wake failure with ret " << ret; |
| 242 | return RetCode::ERROR_EVENT_FLAG_ERROR; |
| 243 | } |
| 244 | LOG(DEBUG) << __func__ << " : signal client for reopen"; |
| 245 | return RetCode::SUCCESS; |
| 246 | } |
| 247 | } // namespace aidl::android::hardware::audio::effect |