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