1 /*
2 * Copyright (c) 2023 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
16 #ifdef HAVE_CONFIG_H
17 #include <config.h>
18 #endif
19
20 #include <pulsecore/sink.h>
21 #include <pulsecore/module.h>
22 #include <pulsecore/core-util.h>
23 #include <pulsecore/modargs.h>
24 #include <pulsecore/log.h>
25 #include <pulsecore/namereg.h>
26
27 #include "audio_effect_chain_adapter.h"
28 #include "audio_log.h"
29 #include "playback_capturer_adapter.h"
30
31 PA_MODULE_AUTHOR("OpenHarmony");
32 PA_MODULE_DESCRIPTION(_("Cluster module"));
33 PA_MODULE_VERSION(PACKAGE_VERSION);
34 PA_MODULE_LOAD_ONCE(false);
35 PA_MODULE_USAGE(
36 "sink_name=<name of sink> "
37 );
38
39 struct userdata {
40 pa_core *core;
41 pa_module *module;
42
43 bool isInnerCapturer;
44 };
45
46 static const char * const VALID_MODARGS[] = {
47 "sink_name",
48 NULL
49 };
50
MoveSinkInputIntoSink(pa_sink_input * si,pa_sink * sink)51 static pa_hook_result_t MoveSinkInputIntoSink(pa_sink_input *si, pa_sink *sink)
52 {
53 if (si->sink != sink) {
54 pa_sink_input_move_to(si, sink, false);
55 }
56 return PA_HOOK_OK;
57 }
58
IsSinkInputSupportInnerCapturer(pa_sink_input * si,struct userdata * u)59 static bool IsSinkInputSupportInnerCapturer(pa_sink_input *si, struct userdata *u)
60 {
61 pa_assert(si);
62 pa_assert(u);
63
64 // check if at an inner capturer scene.
65 if (!u->isInnerCapturer) {
66 return false;
67 }
68
69 const char *usageStr = pa_proplist_gets(si->proplist, "stream.usage");
70 const char *privacyTypeStr = pa_proplist_gets(si->proplist, "stream.privacyType");
71 int32_t usage = -1;
72 int32_t privacyType = -1;
73 bool usageSupport = false;
74 bool privacySupport = true;
75
76 if (privacyTypeStr != NULL) {
77 pa_atoi(privacyTypeStr, &privacyType);
78 privacySupport = IsPrivacySupportInnerCapturer(privacyType);
79 }
80
81 if (usageStr != NULL) {
82 pa_atoi(usageStr, &usage);
83 usageSupport = IsStreamSupportInnerCapturer(usage);
84 }
85
86 AUDIO_DEBUG_LOG("get privacyType:%{public}d, usage:%{public}d of sink input:%{public}d",
87 privacyType, usage, si->index);
88 return privacySupport && usageSupport;
89 }
90
SinkInputMoveForCapturerWithoutEffect(pa_core * c,pa_sink_input * si)91 static pa_hook_result_t SinkInputMoveForCapturerWithoutEffect(pa_core *c, pa_sink_input *si)
92 {
93 pa_assert(c);
94
95 bool isCaptureSilently = IsCaptureSilently();
96 pa_sink *receiverSink = pa_namereg_get(c, "Receiver", PA_NAMEREG_SINK);
97 pa_sink *captureSink = pa_namereg_get(c, "InnerCapturer", PA_NAMEREG_SINK);
98
99 if (isCaptureSilently && captureSink != NULL) {
100 return MoveSinkInputIntoSink(si, captureSink);
101 }
102 if (receiverSink != NULL) {
103 return MoveSinkInputIntoSink(si, receiverSink);
104 }
105 return MoveSinkInputIntoSink(si, c->default_sink);
106 }
107
SinkInputMoveForCapturerWithEffect(pa_core * c,pa_sink_input * si,const char * sceneType)108 static pa_hook_result_t SinkInputMoveForCapturerWithEffect(pa_core *c, pa_sink_input *si, const char *sceneType)
109 {
110 pa_assert(c);
111
112 bool isCaptureSilently = IsCaptureSilently();
113 pa_sink *captureSink = pa_namereg_get(c, "InnerCapturer", PA_NAMEREG_SINK);
114 const char *sinkName = pa_sprintf_malloc("%s_CAP", sceneType);
115 pa_sink *effectSink = pa_namereg_get(c, sinkName, PA_NAMEREG_SINK);
116
117 if (isCaptureSilently && captureSink != NULL) {
118 return MoveSinkInputIntoSink(si, captureSink);
119 }
120 if (effectSink != NULL) {
121 return MoveSinkInputIntoSink(si, effectSink);
122 }
123 return MoveSinkInputIntoSink(si, c->default_sink);
124 }
125
SinkInputMoveWithoutEffect(pa_core * c,pa_sink_input * si,bool isInnerCapture)126 static pa_hook_result_t SinkInputMoveWithoutEffect(pa_core *c, pa_sink_input *si, bool isInnerCapture)
127 {
128 if (isInnerCapture) {
129 return SinkInputMoveForCapturerWithoutEffect(c, si); // playback capturer
130 } else {
131 return MoveSinkInputIntoSink(si, c->default_sink); // if bypass move to hdi sink
132 }
133 }
134
SinkInputProplistChangedCb(pa_core * c,pa_sink_input * si,struct userdata * u)135 static pa_hook_result_t SinkInputProplistChangedCb(pa_core *c, pa_sink_input *si, struct userdata *u)
136 {
137 pa_assert(c);
138 pa_assert(u);
139 const char *sceneMode = pa_proplist_gets(si->proplist, "scene.mode");
140 const char *sceneType = pa_proplist_gets(si->proplist, "scene.type");
141
142 const char *deviceString = pa_proplist_gets(si->sink->proplist, PA_PROP_DEVICE_STRING);
143 if (pa_safe_streq(deviceString, "remote")) {
144 return PA_HOOK_OK;
145 }
146
147 const char *appUser = pa_proplist_gets(si->proplist, "application.process.user");
148 if (pa_safe_streq(appUser, "daudio")) {
149 return PA_HOOK_OK;
150 }
151
152 bool isSupportInnerCapturer = IsSinkInputSupportInnerCapturer(si, u);
153 bool innerCapturerFlag = u->isInnerCapturer && isSupportInnerCapturer && sceneType != NULL;
154
155 const char *clientUid = pa_proplist_gets(si->proplist, "stream.client.uid");
156 if (pa_safe_streq(clientUid, "1003")) {
157 return SinkInputMoveWithoutEffect(c, si, innerCapturerFlag);
158 }
159
160 bool existFlag = EffectChainManagerExist(sceneType, sceneMode);
161 // if EFFECT_NONE mode or effect chain does not exist
162 if (pa_safe_streq(sceneMode, "EFFECT_NONE") || !existFlag) {
163 return SinkInputMoveWithoutEffect(c, si, innerCapturerFlag);
164 }
165
166 pa_sink *effectSink = pa_namereg_get(c, sceneType, PA_NAMEREG_SINK);
167 if (!effectSink) { // if sink does not exist
168 AUDIO_ERR_LOG("Effect sink [%{public}s] sink not found.", sceneType);
169 return SinkInputMoveWithoutEffect(c, si, innerCapturerFlag);
170 } else {
171 if (innerCapturerFlag) {
172 SinkInputMoveForCapturerWithEffect(c, si, sceneType);
173 } else {
174 MoveSinkInputIntoSink(si, effectSink); // classify sinkinput to effect sink
175 }
176 }
177
178 return PA_HOOK_OK;
179 }
180
IsSourceOutputForInnerCapturer(pa_source_output * so,const struct userdata * u)181 static bool IsSourceOutputForInnerCapturer(pa_source_output *so, const struct userdata *u)
182 {
183 if (so == NULL || u == NULL) {
184 return false;
185 }
186 int32_t innerCapturerFlag = 0;
187
188 const char *flag = pa_proplist_gets(so->proplist, "stream.isInnerCapturer");
189 if (flag != NULL) {
190 pa_atoi(flag, &innerCapturerFlag);
191 }
192
193 if (innerCapturerFlag == 1) {
194 return true;
195 }
196 return false;
197 }
198
SourceOutputStateChangedCb(pa_core * c,pa_source_output * so,struct userdata * u)199 static pa_hook_result_t SourceOutputStateChangedCb(pa_core *c, pa_source_output *so, struct userdata *u)
200 {
201 uint32_t idx;
202 pa_sink_input *si;
203
204 pa_assert(c);
205 pa_assert(u);
206 pa_assert(so);
207
208 if (!IsSourceOutputForInnerCapturer(so, u)) {
209 return PA_HOOK_OK;
210 }
211
212 if (so->state != PA_SOURCE_OUTPUT_RUNNING) {
213 u->isInnerCapturer = false;
214 }
215
216 PA_IDXSET_FOREACH(si, c->sink_inputs, idx) {
217 const char *moduleName = si->module->name;
218 if (pa_safe_streq(moduleName, "libmodule-effect-sink.z.so")) {
219 continue;
220 }
221 SinkInputProplistChangedCb(c, si, u);
222 }
223 return PA_HOOK_OK;
224 }
225
SourceOutputPutCb(pa_core * c,pa_source_output * so,struct userdata * u)226 static pa_hook_result_t SourceOutputPutCb(pa_core *c, pa_source_output *so, struct userdata *u)
227 {
228 pa_assert(c);
229 pa_assert(u);
230 pa_assert(so);
231
232 if (IsSourceOutputForInnerCapturer(so, u)) {
233 u->isInnerCapturer = true;
234 IgnoreEffectChangeProcess(true);
235 }
236 return PA_HOOK_OK;
237 }
238
SinkStateChangedCb(pa_core * c,pa_sink * s,struct userdata * u)239 static pa_hook_result_t SinkStateChangedCb(pa_core *c, pa_sink *s, struct userdata *u)
240 {
241 pa_assert(c);
242 pa_assert(u);
243 pa_assert(s);
244
245 if (pa_safe_streq(s->name, "InnerCapturer") && s->state == PA_SINK_SUSPENDED) {
246 IgnoreEffectChangeProcess(false);
247 }
248 return PA_HOOK_OK;
249 }
250
ClientProplistChangedCb(pa_core * c,pa_client * client,struct userdata * u)251 static pa_hook_result_t ClientProplistChangedCb(pa_core *c, pa_client *client, struct userdata *u)
252 {
253 const char *name = pa_proplist_gets(client->proplist, "application.name");
254 if (!pa_safe_streq(name, "PulseAudio Service")) {
255 return PA_HOOK_OK;
256 }
257 uint32_t idx;
258 pa_sink_input *si;
259 PA_IDXSET_FOREACH(si, c->sink_inputs, idx) {
260 SinkInputProplistChangedCb(c, si, u);
261 }
262 return PA_HOOK_OK;
263 }
264
InitFail(pa_module * m,pa_modargs * ma)265 int InitFail(pa_module *m, pa_modargs *ma)
266 {
267 AUDIO_ERR_LOG("Failed to create cluster module");
268 if (ma) {
269 pa_modargs_free(ma);
270 }
271 pa__done(m);
272 return -1;
273 }
274
pa__init(pa_module * m)275 int pa__init(pa_module *m)
276 {
277 struct userdata *u = NULL;
278 pa_modargs *ma = NULL;
279
280 pa_assert(m);
281
282 if (!(ma = pa_modargs_new(m->argument, VALID_MODARGS))) {
283 AUDIO_ERR_LOG("Failed to parse module arguments.");
284 return InitFail(m, ma);
285 }
286
287 m->userdata = u = pa_xnew0(struct userdata, 1);
288 u->core = m->core;
289 u->module = m;
290
291 pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SINK_INPUT_PROPLIST_CHANGED], PA_HOOK_LATE,
292 (pa_hook_cb_t)SinkInputProplistChangedCb, u);
293 pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_CLIENT_PROPLIST_CHANGED], PA_HOOK_LATE,
294 (pa_hook_cb_t)ClientProplistChangedCb, u);
295 pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_STATE_CHANGED], PA_HOOK_LATE,
296 (pa_hook_cb_t)SourceOutputStateChangedCb, u);
297 pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SINK_STATE_CHANGED], PA_HOOK_LATE,
298 (pa_hook_cb_t)SinkStateChangedCb, u);
299 pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PUT], PA_HOOK_LATE,
300 (pa_hook_cb_t)SourceOutputPutCb, u);
301
302 pa_modargs_free(ma);
303
304 return 0;
305 }
306
pa__get_n_used(pa_module * m)307 int pa__get_n_used(pa_module *m)
308 {
309 struct userdata *u;
310
311 pa_assert(m);
312 pa_assert_se(u = m->userdata);
313
314 return 0;
315 }
316
pa__done(pa_module * m)317 void pa__done(pa_module *m)
318 {
319 struct userdata *u;
320
321 pa_assert(m);
322
323 if (!(u = m->userdata)) {
324 return;
325 }
326
327 pa_xfree(u);
328 }
329