• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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 #define LOG_TAG "AHAL_DownmixContext"
18 
19 #include <android-base/logging.h>
20 
21 #include "DownmixContext.h"
22 
23 using aidl::android::hardware::audio::effect::IEffect;
24 using aidl::android::hardware::audio::common::getChannelCount;
25 using aidl::android::media::audio::common::AudioChannelLayout;
26 
27 namespace aidl::android::hardware::audio::effect {
28 
DownmixContext(int statusDepth,const Parameter::Common & common)29 DownmixContext::DownmixContext(int statusDepth, const Parameter::Common& common)
30     : EffectContext(statusDepth, common) {
31     LOG(DEBUG) << __func__;
32     mState = DOWNMIX_STATE_UNINITIALIZED;
33     init_params(common);
34 }
35 
~DownmixContext()36 DownmixContext::~DownmixContext() {
37     LOG(DEBUG) << __func__;
38     mState = DOWNMIX_STATE_UNINITIALIZED;
39 }
40 
enable()41 RetCode DownmixContext::enable() {
42     LOG(DEBUG) << __func__;
43     if (mState != DOWNMIX_STATE_INITIALIZED) {
44         return RetCode::ERROR_EFFECT_LIB_ERROR;
45     }
46     mState = DOWNMIX_STATE_ACTIVE;
47     return RetCode::SUCCESS;
48 }
49 
disable()50 RetCode DownmixContext::disable() {
51     LOG(DEBUG) << __func__;
52     if (mState != DOWNMIX_STATE_ACTIVE) {
53         return RetCode::ERROR_EFFECT_LIB_ERROR;
54     }
55     mState = DOWNMIX_STATE_INITIALIZED;
56     return RetCode::SUCCESS;
57 }
58 
reset()59 void DownmixContext::reset() {
60     LOG(DEBUG) << __func__;
61     disable();
62     resetBuffer();
63 }
64 
lvmProcess(float * in,float * out,int samples)65 IEffect::Status DownmixContext::lvmProcess(float* in, float* out, int samples) {
66     LOG(DEBUG) << __func__ << " in " << in << " out " << out << " sample " << samples;
67     IEffect::Status status = {EX_ILLEGAL_ARGUMENT, 0, 0};
68 
69     if (in == nullptr || out == nullptr || getInputFrameSize() != getOutputFrameSize() ||
70         getInputFrameSize() == 0) {
71         return status;
72     }
73 
74     status = {EX_ILLEGAL_STATE, 0, 0};
75     if (mState == DOWNMIX_STATE_UNINITIALIZED) {
76         LOG(ERROR) << __func__ << "Trying to use an uninitialized downmixer";
77         return status;
78     } else if (mState == DOWNMIX_STATE_INITIALIZED) {
79         LOG(ERROR) << __func__ << "Trying to use a non-configured downmixer";
80         return status;
81     }
82 
83     LOG(DEBUG) << __func__ << " start processing";
84     bool accumulate = false;
85     int frames = samples * sizeof(float) / getInputFrameSize();
86     if (mType == Downmix::Type::STRIP) {
87         int inputChannelCount = getChannelCount(mChMask);
88         while (frames) {
89             if (accumulate) {
90                 out[0] = std::clamp(out[0] + in[0], -1.f, 1.f);
91                 out[1] = std::clamp(out[1] + in[1], -1.f, 1.f);
92             } else {
93                 out[0] = in[0];
94                 out[1] = in[1];
95             }
96             in += inputChannelCount;
97             out += 2;
98             frames--;
99         }
100     } else {
101         int chMask = mChMask.get<AudioChannelLayout::layoutMask>();
102         if (!mChannelMix.process(in, out, frames, accumulate, (audio_channel_mask_t)chMask)) {
103             LOG(ERROR) << "Multichannel configuration " << mChMask.toString()
104                        << " is not supported";
105             return status;
106         }
107     }
108     LOG(DEBUG) << __func__ << " done processing";
109     return {STATUS_OK, samples, samples};
110 }
111 
init_params(const Parameter::Common & common)112 void DownmixContext::init_params(const Parameter::Common& common) {
113     // when configuring the effect, do not allow a blank or unsupported channel mask
114     AudioChannelLayout channelMask = common.input.base.channelMask;
115     if (isChannelMaskValid(channelMask)) {
116         LOG(ERROR) << "Downmix_Configure error: input channel mask " << channelMask.toString()
117                    << " not supported";
118     } else {
119         mType = Downmix::Type::FOLD;
120         mChMask = channelMask;
121         mState = DOWNMIX_STATE_INITIALIZED;
122     }
123 }
124 
isChannelMaskValid(AudioChannelLayout channelMask)125 bool DownmixContext::isChannelMaskValid(AudioChannelLayout channelMask) {
126     if (channelMask.getTag() == AudioChannelLayout::layoutMask) return false;
127     int chMask = channelMask.get<AudioChannelLayout::layoutMask>();
128     // check against unsupported channels (up to FCC_26)
129     constexpr uint32_t MAXIMUM_CHANNEL_MASK = AudioChannelLayout::LAYOUT_22POINT2 |
130                                               AudioChannelLayout::CHANNEL_FRONT_WIDE_LEFT |
131                                               AudioChannelLayout::CHANNEL_FRONT_WIDE_RIGHT;
132     if (chMask & ~MAXIMUM_CHANNEL_MASK) {
133         LOG(ERROR) << "Unsupported channels in " << (chMask & ~MAXIMUM_CHANNEL_MASK);
134         return false;
135     }
136     return true;
137 }
138 
139 }  // namespace aidl::android::hardware::audio::effect
140