• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #ifndef LOG_TAG
16 #define LOG_TAG "HpaeMixerNode"
17 #endif
18 
19 #include <iostream>
20 #include "hpae_mixer_node.h"
21 #include "hpae_pcm_buffer.h"
22 #include "audio_utils.h"
23 #include "cinttypes"
24 #include "audio_errors.h"
25 #include "audio_effect_log.h"
26 
27 namespace OHOS {
28 namespace AudioStandard {
29 namespace HPAE {
30 
31 static constexpr uint32_t WAIT_FRAMES_NUM = 5; // wait 5 * 20ms before disconnect
32 static constexpr uint32_t DEFAULT_CHANNEL_COUNT = 2;
33 static constexpr uint32_t DEFAULT_FRAME_LEN = 960;
34 static constexpr uint32_t DEFAULT_SAMPLE_RATE = 48000;
35 
HpaeMixerNode(HpaeNodeInfo & nodeInfo)36 HpaeMixerNode::HpaeMixerNode(HpaeNodeInfo &nodeInfo)
37     : HpaeNode(nodeInfo), HpaePluginNode(nodeInfo),
38     pcmBufferInfo_(nodeInfo.channels, nodeInfo.frameLen, nodeInfo.samplingRate, nodeInfo.channelLayout),
39     mixedOutput_(pcmBufferInfo_), tmpOutput_(pcmBufferInfo_)
40 {
41     mixedOutput_.SetSplitStreamType(nodeInfo.GetSplitStreamType());
42 #ifdef ENABLE_HIDUMP_DFX
43     SetNodeName("hpaeMixerNode");
44 #endif
45 }
46 
~HpaeMixerNode()47 HpaeMixerNode::~HpaeMixerNode()
48 {
49 #ifdef ENABLE_HIDUMP_DFX
50     AUDIO_INFO_LOG("NodeId: %{public}u NodeName: %{public}s destructed.",
51         GetNodeId(), GetNodeName().c_str());
52 #endif
53 }
54 
Reset()55 bool HpaeMixerNode::Reset()
56 {
57     return HpaePluginNode::Reset();
58 }
59 
SetupAudioLimiter()60 int32_t HpaeMixerNode::SetupAudioLimiter()
61 {
62     if (limiter_ != nullptr) {
63         AUDIO_INFO_LOG("NodeId: %{public}d, limiter has already been setup!", GetNodeId());
64         return ERROR;
65     }
66     return InitAudioLimiter();
67 }
68 
InitAudioLimiter()69 int32_t HpaeMixerNode::InitAudioLimiter()
70 {
71     limiter_ = std::make_unique<AudioLimiter>(GetNodeId());
72     // limiter only supports float format
73     int32_t ret = limiter_->SetConfig(GetFrameLen() * GetChannelCount() * sizeof(float), sizeof(float), GetSampleRate(),
74         GetChannelCount());
75     if (ret == SUCCESS) {
76         AUDIO_INFO_LOG("NodeId: %{public}d, limiter init sucess!", GetNodeId());
77     } else {
78         limiter_ = nullptr;
79         AUDIO_INFO_LOG("NodeId: %{public}d, limiter init fail!!", GetNodeId());
80     }
81     return ret;
82 }
83 
SignalProcess(const std::vector<HpaePcmBuffer * > & inputs)84 HpaePcmBuffer *HpaeMixerNode::SignalProcess(const std::vector<HpaePcmBuffer *> &inputs)
85 {
86     Trace trace("[sceneType:" + std::to_string(GetSceneType()) + "]" + "HpaeMixerNode::SignalProcess");
87     mixedOutput_.Reset();
88 
89     if (GetSceneType() != HPAE_SCENE_EFFECT_OUT) {
90         DrainProcess();
91     }
92 
93     uint32_t bufferState = PCM_BUFFER_STATE_INVALID | PCM_BUFFER_STATE_SILENCE;
94     if (limiter_ == nullptr) {
95         bool ret = inputs.empty() ? CheckUpdateInfoForDisConnect() : CheckUpdateInfo(inputs[0]);
96         if (ret) {
97             mixedOutput_.ReConfig(pcmBufferInfo_);
98         }
99         for (auto input: inputs) {
100             mixedOutput_ += *input;
101             bufferState &= input->GetBufferState();
102         }
103     } else { // limiter does not support reconfigging frameLen at runtime
104         tmpOutput_.Reset();
105         for (auto input: inputs) {
106             tmpOutput_ += *input;
107             bufferState &= input->GetBufferState();
108         }
109         limiter_->Process(GetFrameLen() * GetChannelCount(),
110             tmpOutput_.GetPcmDataBuffer(), mixedOutput_.GetPcmDataBuffer());
111     }
112     mixedOutput_.SetBufferState(bufferState);
113     return &mixedOutput_;
114 }
115 
CheckUpdateInfo(HpaePcmBuffer * input)116 bool HpaeMixerNode::CheckUpdateInfo(HpaePcmBuffer* input)
117 {
118     struct UpdateCheck {
119         std::string name;
120         uint32_t &currentVal;
121         uint32_t newVal;
122     } checks[] = {
123         {"channel count", pcmBufferInfo_.ch, input->GetChannelCount()},
124         {"frame len", pcmBufferInfo_.frameLen, input->GetFrameLen()},
125         {"sample rate", pcmBufferInfo_.rate, input->GetSampleRate()}
126     };
127 
128     bool isPCMBufferInfoUpdated = false;
129 
130     for (auto& check : checks) {
131         if (check.currentVal != check.newVal) {
132             AUDIO_INFO_LOG("Update %{public}s: %{public}d -> %{public}d",
133                 check.name.c_str(), check.currentVal, check.newVal);
134             check.currentVal = check.newVal;
135             isPCMBufferInfoUpdated = true;
136         }
137     }
138 
139     if (pcmBufferInfo_.channelLayout != input->GetChannelLayout()) {
140         AUDIO_INFO_LOG("Update channel layout %{public}" PRIu64 " -> %{public}" PRIu64 "",
141             pcmBufferInfo_.channelLayout, input->GetChannelLayout());
142         pcmBufferInfo_.channelLayout = input->GetChannelLayout();
143         isPCMBufferInfoUpdated = true;
144     }
145 
146     // if other bitwidth is supported, add check here
147 
148     return isPCMBufferInfoUpdated;
149 }
150 
151 
CheckUpdateInfoForDisConnect()152 bool HpaeMixerNode::CheckUpdateInfoForDisConnect()
153 {
154     struct UpdateCheck {
155         std::string name;
156         uint32_t &currentVal;
157         uint32_t newVal;
158     } checks[] = {
159         {"channel count", pcmBufferInfo_.ch, DEFAULT_CHANNEL_COUNT},
160         {"frame len", pcmBufferInfo_.frameLen, DEFAULT_FRAME_LEN},
161         {"sample rate", pcmBufferInfo_.rate, DEFAULT_SAMPLE_RATE}
162     };
163 
164     bool isPCMBufferInfoUpdated = false;
165 
166     for (auto& check : checks) {
167         if (check.currentVal != check.newVal) {
168             AUDIO_INFO_LOG("Update %{public}s: %{public}d -> %{public}d",
169                 check.name.c_str(), check.currentVal, check.newVal);
170             check.currentVal = check.newVal;
171             isPCMBufferInfoUpdated = true;
172         }
173     }
174 
175     if (pcmBufferInfo_.channelLayout != AudioChannelLayout::CH_LAYOUT_STEREO) {
176         AUDIO_INFO_LOG("Update channel layout %{public}" PRIu64 " -> %{public}" PRIu64 "",
177             pcmBufferInfo_.channelLayout, AudioChannelLayout::CH_LAYOUT_STEREO);
178         pcmBufferInfo_.channelLayout = AudioChannelLayout::CH_LAYOUT_STEREO;
179         isPCMBufferInfoUpdated = true;
180     }
181 
182     // if other bitwidth is supported, add check here
183 
184     return isPCMBufferInfoUpdated;
185 }
186 
DrainProcess()187 void HpaeMixerNode::DrainProcess()
188 {
189     if (GetPreOutNum() != 0) {
190         waitFrames_ = 0;
191     } else {
192         waitFrames_++;
193         if (waitFrames_ == WAIT_FRAMES_NUM) {
194             waitFrames_ = 0;
195             auto statusCallback = GetNodeStatusCallback().lock();
196             if (statusCallback) {
197                 AUDIO_INFO_LOG("trigger callback to disconnect");
198                 statusCallback->OnDisConnectProcessCluster(GetSceneType());
199             }
200         }
201     }
202 }
203 }  // namespace HPAE
204 }  // namespace AudioStandard
205 }  // namespace OHOS