• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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