1 /*
2 * Copyright (c) 2021-2022 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 #undef LOG_TAG
16 #define LOG_TAG "ModuleHdiSource"
17
18 #include <config.h>
19 #include <pulsecore/log.h>
20 #include <pulsecore/modargs.h>
21 #include <pulsecore/module.h>
22 #include <pulsecore/source.h>
23 #include <stddef.h>
24 #include <stdbool.h>
25
26 #include <pulsecore/core.h>
27 #include <pulsecore/core-util.h>
28 #include <pulsecore/namereg.h>
29
30 #include "securec.h"
31 #include "audio_hdi_log.h"
32 #include "audio_enhance_chain_adapter.h"
33 #include "source_userdata.h"
34 #include "common/hdi_adapter_info.h"
35
36 pa_source *PaHdiSourceNew(pa_module *m, pa_modargs *ma, const char *driver);
37 void PaHdiSourceFree(pa_source *s);
38
39 PA_MODULE_AUTHOR("OpenHarmony");
40 PA_MODULE_DESCRIPTION("OpenHarmony HDI Source");
41 PA_MODULE_VERSION(PACKAGE_VERSION);
42 PA_MODULE_LOAD_ONCE(false);
43 PA_MODULE_USAGE(
44 "source_name=<name for the source> "
45 "device_class=<name for the device class> "
46 "source_properties=<properties for the source> "
47 "format=<sample format> "
48 "rate=<sample rate> "
49 "channels=<number of channels> "
50 "channel_map=<channel map>"
51 "buffer_size=<custom buffer size>"
52 "file_path=<file path for data reading>"
53 "adapter_name=<primary>"
54 "open_mic_speaker<open mic>"
55 "network_id<device network id>"
56 "device_type<device type or port>"
57 "source_type<source type or port>"
58 );
59
60 static const char * const VALID_MODARGS[] = {
61 "source_name",
62 "device_class",
63 "source_properties",
64 "format",
65 "rate",
66 "channels",
67 "channel_map",
68 "buffer_size",
69 "file_path",
70 "adapter_name",
71 "open_mic_speaker",
72 "network_id",
73 "device_type",
74 "source_type",
75 "ec_type",
76 "ec_adapter",
77 "ec_sampling_rate",
78 "ec_format",
79 "ec_channels",
80 "open_mic_ref",
81 "mic_ref_rate",
82 "mic_ref_format",
83 "mic_ref_channels",
84 "default_adapter_enable",
85 NULL
86 };
87
IncreaseScenekeyCount(pa_hashmap * sceneMap,const char * key)88 static void IncreaseScenekeyCount(pa_hashmap *sceneMap, const char *key)
89 {
90 if (sceneMap == NULL) {
91 return;
92 }
93 uint32_t *num = NULL;
94 if ((num = (uint32_t *)pa_hashmap_get(sceneMap, key)) != NULL) {
95 (*num)++;
96 } else {
97 char *sceneKey;
98 sceneKey = strdup(key);
99 if (sceneKey != NULL) {
100 num = pa_xnew0(uint32_t, 1);
101 *num = 1;
102 if (pa_hashmap_put(sceneMap, sceneKey, num) != 0) {
103 AUDIO_ERR_LOG("pa_hashmap_put failed");
104 free(sceneKey);
105 pa_xfree(num);
106 }
107 }
108 }
109 }
110
DecreaseScenekeyCount(pa_hashmap * sceneMap,const char * key)111 static bool DecreaseScenekeyCount(pa_hashmap *sceneMap, const char *key)
112 {
113 if (sceneMap == NULL) {
114 return false;
115 }
116 uint32_t *num = NULL;
117 if ((num = (uint32_t *)pa_hashmap_get(sceneMap, key)) != NULL) {
118 (*num)--;
119 if (*num == 0) {
120 pa_hashmap_remove_and_free(sceneMap, key);
121 return true;
122 }
123 }
124 return false;
125 }
126
ConvertPaFormat(pa_sample_format_t paFormat)127 static enum AudioSampleFormatIntf ConvertPaFormat(pa_sample_format_t paFormat)
128 {
129 enum AudioSampleFormatIntf format;
130 switch (paFormat) {
131 case PA_SAMPLE_U8:
132 format = SAMPLE_U8;
133 break;
134 case PA_SAMPLE_S16LE:
135 case PA_SAMPLE_S16BE:
136 format = SAMPLE_S16;
137 break;
138 case PA_SAMPLE_S24LE:
139 case PA_SAMPLE_S24BE:
140 format = SAMPLE_S24;
141 break;
142 case PA_SAMPLE_S32LE:
143 case PA_SAMPLE_S32BE:
144 format = SAMPLE_S32;
145 break;
146 default:
147 format = SAMPLE_S16;
148 break;
149 }
150
151 return format;
152 }
153
SetResampler(pa_source_output * so,const char * sceneKey,const struct Userdata * u,const struct AlgoSpecs * algoSpecs)154 static void SetResampler(pa_source_output *so, const char *sceneKey, const struct Userdata *u,
155 const struct AlgoSpecs *algoSpecs)
156 {
157 pa_hashmap *preResamplerMap = (pa_hashmap *)u->sceneToPreResamplerMap;
158 pa_hashmap *ecResamplerMap = (pa_hashmap *)u->sceneToEcResamplerMap;
159 pa_hashmap *micRefResamplerMap = (pa_hashmap *)u->sceneToMicRefResamplerMap;
160 if (!pa_sample_spec_equal(&so->source->sample_spec, &algoSpecs->micSpec)) {
161 AUDIO_INFO_LOG("SOURCE spec:%{public}u_%{public}u_%{public}u ALGO spec:%{public}u_%{public}u_%{public}u",
162 so->source->sample_spec.rate, (uint32_t)so->source->sample_spec.channels,
163 (uint32_t)ConvertPaFormat(so->source->sample_spec.format),
164 algoSpecs->micSpec.rate, (uint32_t)algoSpecs->micSpec.channels,
165 (uint32_t)ConvertPaFormat(algoSpecs->micSpec.format));
166 pa_resampler *preResampler = pa_resampler_new(so->source->core->mempool,
167 &so->source->sample_spec, &so->source->channel_map,
168 &algoSpecs->micSpec, &so->source->channel_map,
169 so->source->core->lfe_crossover_freq,
170 PA_RESAMPLER_AUTO, PA_RESAMPLER_VARIABLE_RATE);
171 pa_hashmap_put(preResamplerMap, pa_xstrdup(sceneKey), preResampler);
172 pa_resampler *postResampler = pa_resampler_new(so->source->core->mempool,
173 &algoSpecs->micSpec, &so->source->channel_map,
174 &so->sample_spec, &so->source->channel_map,
175 so->source->core->lfe_crossover_freq,
176 PA_RESAMPLER_AUTO, PA_RESAMPLER_VARIABLE_RATE);
177 so->thread_info.resampler = postResampler;
178 }
179 if ((u->ecType != EC_NONE) && (algoSpecs->ecSpec.rate != 0) &&
180 (!pa_sample_spec_equal(&u->ecSpec, &algoSpecs->ecSpec))) {
181 AUDIO_INFO_LOG("EC SOURCE spec:%{public}u_%{public}u_%{public}u ALGO spec:%{public}u_%{public}u_%{public}u",
182 u->ecSpec.rate, (uint32_t)u->ecSpec.channels, (uint32_t)ConvertPaFormat(u->ecSpec.format),
183 algoSpecs->ecSpec.rate, (uint32_t)algoSpecs->ecSpec.channels,
184 (uint32_t)ConvertPaFormat(algoSpecs->ecSpec.format));
185 pa_resampler *ecResampler = pa_resampler_new(so->source->core->mempool,
186 &u->ecSpec, &so->source->channel_map,
187 &algoSpecs->ecSpec, &so->source->channel_map,
188 so->source->core->lfe_crossover_freq,
189 PA_RESAMPLER_AUTO, PA_RESAMPLER_VARIABLE_RATE);
190 pa_hashmap_put(ecResamplerMap, pa_xstrdup(sceneKey), ecResampler);
191 }
192 if ((u->micRef == REF_ON) && (algoSpecs->micRefSpec.rate != 0) &&
193 (!pa_sample_spec_equal(&u->micRefSpec, &algoSpecs->micRefSpec))) {
194 AUDIO_INFO_LOG("MIC REF SOURCE spec:%{public}u_%{public}u_%{public}u ALGO:%{public}u_%{public}u_%{public}u",
195 u->micRefSpec.rate, (uint32_t)u->micRefSpec.channels, (uint32_t)ConvertPaFormat(u->micRefSpec.format),
196 algoSpecs->micRefSpec.rate, (uint32_t)algoSpecs->micRefSpec.channels,
197 (uint32_t)ConvertPaFormat(algoSpecs->micRefSpec.format));
198 pa_resampler *micRefResampler = pa_resampler_new(so->source->core->mempool,
199 &u->micRefSpec, &so->source->channel_map,
200 &algoSpecs->micRefSpec, &so->source->channel_map,
201 so->source->core->lfe_crossover_freq,
202 PA_RESAMPLER_AUTO, PA_RESAMPLER_VARIABLE_RATE);
203 pa_hashmap_put(micRefResamplerMap, pa_xstrdup(sceneKey), micRefResampler);
204 }
205 }
206
SetDefaultResampler(pa_source_output * so,const pa_sample_spec * algoConfig,struct Userdata * u)207 static void SetDefaultResampler(pa_source_output *so, const pa_sample_spec *algoConfig, struct Userdata *u)
208 {
209 if (!pa_sample_spec_equal(&so->source->sample_spec, algoConfig)) {
210 if (u->defaultSceneResampler) {
211 pa_resampler_free(u->defaultSceneResampler);
212 }
213 AUDIO_INFO_LOG("default SOURCE:%{public}u_%{public}u_%{public}u ALGO:%{public}u_%{public}u_%{public}u",
214 so->source->sample_spec.rate, (uint32_t)so->source->sample_spec.channels,
215 (uint32_t)ConvertPaFormat(so->source->sample_spec.format),
216 algoConfig->rate, (uint32_t)algoConfig->channels,
217 (uint32_t)ConvertPaFormat(algoConfig->format));
218 u->defaultSceneResampler = pa_resampler_new(so->source->core->mempool,
219 &so->source->sample_spec, &so->source->channel_map,
220 algoConfig, &so->source->channel_map,
221 so->source->core->lfe_crossover_freq,
222 PA_RESAMPLER_AUTO, PA_RESAMPLER_VARIABLE_RATE);
223 pa_resampler *postResampler = pa_resampler_new(so->source->core->mempool,
224 algoConfig, &so->source->channel_map,
225 &so->sample_spec, &so->source->channel_map,
226 so->source->core->lfe_crossover_freq,
227 PA_RESAMPLER_AUTO, PA_RESAMPLER_VARIABLE_RATE);
228 so->thread_info.resampler = postResampler;
229 }
230 }
231
GetByteSizeByFormat(enum AudioSampleFormatIntf format)232 static uint32_t GetByteSizeByFormat(enum AudioSampleFormatIntf format)
233 {
234 uint32_t byteSize = 0;
235 switch (format) {
236 case SAMPLE_U8:
237 byteSize = BYTE_SIZE_SAMPLE_U8;
238 break;
239 case SAMPLE_S16:
240 byteSize = BYTE_SIZE_SAMPLE_S16;
241 break;
242 case SAMPLE_S24:
243 byteSize = BYTE_SIZE_SAMPLE_S24;
244 break;
245 case SAMPLE_S32:
246 byteSize = BYTE_SIZE_SAMPLE_S32;
247 break;
248 default:
249 byteSize = BYTE_SIZE_SAMPLE_S16;
250 break;
251 }
252 return byteSize;
253 }
254
InitDeviceAttrAdapter(struct DeviceAttrAdapter * deviceAttrAdapter,struct Userdata * u)255 static void InitDeviceAttrAdapter(struct DeviceAttrAdapter *deviceAttrAdapter, struct Userdata *u)
256 {
257 deviceAttrAdapter->micRate = u->attrs.sampleRate;
258 deviceAttrAdapter->micChannels = u->attrs.channel;
259 deviceAttrAdapter->micFormat = GetByteSizeByFormat(u->attrs.format);
260 deviceAttrAdapter->needEc = false;
261 deviceAttrAdapter->needMicRef = false;
262 if (u->ecType != EC_NONE) {
263 deviceAttrAdapter->needEc = true;
264 deviceAttrAdapter->ecRate = u->ecSamplingRate;
265 deviceAttrAdapter->ecChannels = u->ecChannels;
266 deviceAttrAdapter->ecFormat = GetByteSizeByFormat(u->ecFormat);
267 } else {
268 deviceAttrAdapter->ecRate = 0;
269 deviceAttrAdapter->ecChannels = 0;
270 deviceAttrAdapter->ecFormat = 0;
271 }
272 if (u->micRef == REF_ON) {
273 deviceAttrAdapter->needMicRef = true;
274 deviceAttrAdapter->micRefRate = u->micRefRate;
275 deviceAttrAdapter->micRefChannels = u->micRefChannels;
276 deviceAttrAdapter->micRefFormat = GetByteSizeByFormat(u->micRefFormat);
277 } else {
278 deviceAttrAdapter->micRefRate = 0;
279 deviceAttrAdapter->micRefChannels = 0;
280 deviceAttrAdapter->micRefFormat = 0;
281 }
282 }
283
GetAlgoSpecs(uint64_t sceneKeyCode,struct AlgoSpecs * algoSpecs)284 static pa_hook_result_t GetAlgoSpecs(uint64_t sceneKeyCode, struct AlgoSpecs *algoSpecs)
285 {
286 pa_sample_spec_init(&algoSpecs->micSpec);
287 pa_sample_spec_init(&algoSpecs->ecSpec);
288 pa_sample_spec_init(&algoSpecs->micRefSpec);
289
290 if (EnhanceChainManagerGetAlgoConfig(sceneKeyCode, &algoSpecs->micSpec, &algoSpecs->ecSpec,
291 &algoSpecs->micRefSpec) != 0) {
292 AUDIO_ERR_LOG("Get algo config failed");
293 return PA_HOOK_OK;
294 }
295 return PA_HOOK_OK;
296 }
297
HandleSourceOutputPut(pa_source_output * so,struct Userdata * u)298 static pa_hook_result_t HandleSourceOutputPut(pa_source_output *so, struct Userdata *u)
299 {
300 const char *sceneType = pa_proplist_gets(so->proplist, "scene.type");
301 if (sceneType == NULL) {
302 sceneType = "";
303 }
304 const char *sceneBypass = pa_proplist_gets(so->proplist, "scene.bypass");
305 if (pa_safe_streq(sceneBypass, DEFAULT_SCENE_BYPASS)) {
306 AUDIO_INFO_LOG("scene:%{public}s has been set to bypass", sceneType);
307 return PA_HOOK_OK;
308 }
309 uint32_t captureId = u->captureId;
310 uint32_t renderId = u->renderId;
311 uint64_t sceneTypeCode = 0;
312 if (GetSceneTypeCode(sceneType, &sceneTypeCode) != 0) {
313 AUDIO_ERR_LOG("scenetype:%{public}s GetSceneTypeCode failed", sceneType);
314 pa_proplist_sets(so->proplist, "scene.bypass", DEFAULT_SCENE_BYPASS);
315 return PA_HOOK_OK;
316 }
317 uint64_t sceneKeyCode = 0;
318 AUDIO_INFO_LOG("sceneTypeCode = %{public}" PRIu64 ", captureId = %{public}u, renderId = %{public}u",
319 sceneTypeCode, captureId, renderId);
320 sceneKeyCode = (sceneTypeCode << SCENE_TYPE_OFFSET) + (captureId << CAPTURER_ID_OFFSET) + renderId;
321 struct DeviceAttrAdapter deviceAttrAdapter;
322 InitDeviceAttrAdapter(&deviceAttrAdapter, u);
323 int32_t ret = EnhanceChainManagerCreateCb(sceneKeyCode, &deviceAttrAdapter);
324 if (ret < 0) {
325 AUDIO_INFO_LOG("Create EnhanceChain failed, set to bypass");
326 pa_proplist_sets(so->proplist, "scene.bypass", DEFAULT_SCENE_BYPASS);
327 return PA_HOOK_OK;
328 }
329 struct AlgoSpecs algoSpecs;
330 GetAlgoSpecs(sceneKeyCode, &algoSpecs);
331 // default chain
332 if (ret > 0) {
333 SetDefaultResampler(so, &algoSpecs.micSpec, u);
334 pa_proplist_sets(so->proplist, "scene.default", "1");
335 } else {
336 char sceneKey[MAX_SCENE_NAME_LEN];
337 if (sprintf_s(sceneKey, sizeof(sceneKey), "%lu", sceneKeyCode) < 0) {
338 AUDIO_ERR_LOG("sprintf from sceneKeyCode to sceneKey failed");
339 return PA_HOOK_OK;
340 }
341 IncreaseScenekeyCount(u->sceneToCountMap, sceneKey);
342 SetResampler(so, sceneKey, u, &algoSpecs);
343 }
344 EnhanceChainManagerInitEnhanceBuffer();
345 return PA_HOOK_OK;
346 }
347
HandleSourceOutputUnlink(pa_source_output * so,struct Userdata * u)348 static pa_hook_result_t HandleSourceOutputUnlink(pa_source_output *so, struct Userdata *u)
349 {
350 const char *sceneType = pa_proplist_gets(so->proplist, "scene.type");
351 if (sceneType == NULL) {
352 sceneType = "";
353 }
354 const char *sceneBypass = pa_proplist_gets(so->proplist, "scene.bypass");
355 if (pa_safe_streq(sceneBypass, DEFAULT_SCENE_BYPASS)) {
356 AUDIO_INFO_LOG("scene:%{public}s has been set to bypass, do not need release", sceneType);
357 return PA_HOOK_OK;
358 }
359 uint32_t captureId = u->captureId;
360 uint32_t renderId = u->renderId;
361 uint64_t sceneTypeCode = 0;
362 if (GetSceneTypeCode(sceneType, &sceneTypeCode) != 0) {
363 AUDIO_ERR_LOG("scenetype:%{public}s GetSceneTypeCode failed", sceneType);
364 return PA_HOOK_OK;
365 }
366 uint64_t sceneKeyCode = 0;
367 sceneKeyCode = (sceneTypeCode << SCENE_TYPE_OFFSET) + (captureId << CAPTURER_ID_OFFSET) + renderId;
368 EnhanceChainManagerReleaseCb(sceneKeyCode);
369 char sceneKey[MAX_SCENE_NAME_LEN];
370 if (sprintf_s(sceneKey, sizeof(sceneKey), "%lu", sceneKeyCode) < 0) {
371 AUDIO_ERR_LOG("sprintf from sceneKeyCode to sceneKey failed");
372 return PA_HOOK_OK;
373 }
374 if (!pa_safe_streq(pa_proplist_gets(so->proplist, "scene.default"), "1") &&
375 DecreaseScenekeyCount(u->sceneToCountMap, sceneKey)) {
376 pa_hashmap_remove_and_free(u->sceneToPreResamplerMap, sceneKey);
377 pa_hashmap_remove_and_free(u->sceneToEcResamplerMap, sceneKey);
378 pa_hashmap_remove_and_free(u->sceneToMicRefResamplerMap, sceneKey);
379 }
380 return PA_HOOK_OK;
381 }
382
CheckIfAvailSource(pa_source_output * so,struct Userdata * u)383 static pa_hook_result_t CheckIfAvailSource(pa_source_output *so, struct Userdata *u)
384 {
385 pa_source *soSource = so->source;
386 pa_source *thisSource = u->source;
387 if (soSource == NULL || thisSource == NULL) {
388 return PA_HOOK_CANCEL;
389 }
390 if (soSource->index != thisSource->index) {
391 AUDIO_INFO_LOG("NOT correspondant SOURCE %{public}s AND %{public}s.", soSource->name, thisSource->name);
392 return PA_HOOK_CANCEL;
393 }
394 return PA_HOOK_OK;
395 }
396
SourceOutputPutCb(const pa_core * c,pa_source_output * so,struct Userdata * u)397 static pa_hook_result_t SourceOutputPutCb(const pa_core *c, pa_source_output *so, struct Userdata *u)
398 {
399 CHECK_AND_RETURN_RET_LOG(u != NULL, PA_HOOK_OK, "Get Userdata failed! userdata is NULL");
400 CHECK_AND_RETURN_RET_LOG(c != NULL, PA_HOOK_OK, "pa core is null");
401 CHECK_AND_RETURN_RET_LOG(so != NULL, PA_HOOK_OK, "so is NULL");
402
403 const char *sessionID = pa_proplist_gets(so->proplist, "stream.sessionID");
404 if (sessionID == NULL) {
405 sessionID = "";
406 }
407 AUDIO_INFO_LOG("Trigger SourceOutputPutCb sessionID:%{public}s", sessionID);
408
409 if (CheckIfAvailSource(so, u) == PA_HOOK_CANCEL) {
410 return PA_HOOK_OK;
411 }
412 return HandleSourceOutputPut(so, u);
413 }
414
SourceOutputUnlinkCb(const pa_core * c,pa_source_output * so,struct Userdata * u)415 static pa_hook_result_t SourceOutputUnlinkCb(const pa_core *c, pa_source_output *so, struct Userdata *u)
416 {
417 CHECK_AND_RETURN_RET_LOG(u != NULL, PA_HOOK_OK, "Get Userdata failed! userdata is NULL");
418 CHECK_AND_RETURN_RET_LOG(c != NULL, PA_HOOK_OK, "pa core is null");
419 CHECK_AND_RETURN_RET_LOG(so != NULL, PA_HOOK_OK, "so is NULL");
420
421 const char *sessionID = pa_proplist_gets(so->proplist, "stream.sessionID");
422 if (sessionID == NULL) {
423 sessionID = "";
424 }
425 AUDIO_INFO_LOG("Trigger SourceOutputUnlinkCb sessionID:%{public}s", sessionID);
426
427 if (CheckIfAvailSource(so, u) == PA_HOOK_CANCEL) {
428 return PA_HOOK_OK;
429 }
430 return HandleSourceOutputUnlink(so, u);
431 }
432
SourceOutputMoveStartCb(const pa_core * c,pa_source_output * so,struct Userdata * u)433 static pa_hook_result_t SourceOutputMoveStartCb(const pa_core *c, pa_source_output *so, struct Userdata *u)
434 {
435 CHECK_AND_RETURN_RET_LOG(u != NULL, PA_HOOK_OK, "Get Userdata failed! userdata is NULL");
436 CHECK_AND_RETURN_RET_LOG(c != NULL, PA_HOOK_OK, "pa core is null");
437 CHECK_AND_RETURN_RET_LOG(so != NULL, PA_HOOK_OK, "so is NULL");
438
439 const char *sessionID = pa_proplist_gets(so->proplist, "stream.sessionID");
440 if (sessionID == NULL) {
441 sessionID = "";
442 }
443 AUDIO_INFO_LOG("Trigger SourceOutputMoveStartCb sessionID:%{public}s", sessionID);
444
445 if (CheckIfAvailSource(so, u) == PA_HOOK_CANCEL) {
446 return PA_HOOK_OK;
447 }
448 return HandleSourceOutputUnlink(so, u);
449 }
450
SourceOutputMoveFinishCb(const pa_core * c,pa_source_output * so,struct Userdata * u)451 static pa_hook_result_t SourceOutputMoveFinishCb(const pa_core *c, pa_source_output *so, struct Userdata *u)
452 {
453 CHECK_AND_RETURN_RET_LOG(u != NULL, PA_HOOK_OK, "Get Userdata failed! userdata is NULL");
454 CHECK_AND_RETURN_RET_LOG(c != NULL, PA_HOOK_OK, "pa core is null");
455 CHECK_AND_RETURN_RET_LOG(so != NULL, PA_HOOK_OK, "so is NULL");
456
457 const char *sessionID = pa_proplist_gets(so->proplist, "stream.sessionID");
458 if (sessionID == NULL) {
459 sessionID = "";
460 }
461 AUDIO_INFO_LOG("Trigger SourceOutputMoveFinishCb sessionID:%{public}s", sessionID);
462
463 if (CheckIfAvailSource(so, u) == PA_HOOK_CANCEL) {
464 return PA_HOOK_OK;
465 }
466 return HandleSourceOutputPut(so, u);
467 }
468
pa__init(pa_module * m)469 int pa__init(pa_module *m)
470 {
471 pa_modargs *ma = NULL;
472
473 CHECK_AND_RETURN_RET_LOG(m != NULL, PA_HOOK_OK, "pa core is null");
474
475 if (!(ma = pa_modargs_new(m->argument, VALID_MODARGS))) {
476 AUDIO_ERR_LOG("Failed to parse module arguments");
477 goto fail;
478 }
479
480 if (!(m->userdata = PaHdiSourceNew(m, ma, __FILE__))) {
481 AUDIO_ERR_LOG("Failed to PaHdiSourceNew");
482 goto fail;
483 }
484 pa_source *source = (pa_source *)m->userdata;
485
486 pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PUT], PA_HOOK_LATE,
487 (pa_hook_cb_t)SourceOutputPutCb, source->userdata);
488 pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK], PA_HOOK_LATE,
489 (pa_hook_cb_t)SourceOutputUnlinkCb, source->userdata);
490 pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_FINISH], PA_HOOK_LATE,
491 (pa_hook_cb_t)SourceOutputMoveFinishCb, source->userdata);
492 pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_START], PA_HOOK_LATE,
493 (pa_hook_cb_t)SourceOutputMoveStartCb, source->userdata);
494
495 pa_source_put(source);
496 pa_modargs_free(ma);
497
498 return 0;
499
500 fail:
501
502 if (ma) {
503 pa_modargs_free(ma);
504 }
505
506 pa__done(m);
507
508 return -1;
509 }
510
pa__get_n_used(pa_module * m)511 int pa__get_n_used(pa_module *m)
512 {
513 CHECK_AND_RETURN_RET_LOG(m != NULL, PA_HOOK_OK, "pa core is null");
514
515 pa_source *source = m->userdata;
516
517 CHECK_AND_RETURN_RET_LOG(source != NULL, 0, "source is null");
518
519 return pa_source_linked_by(source);
520 }
521
ReleaseAllChains(struct Userdata * u)522 static void ReleaseAllChains(struct Userdata *u)
523 {
524 void *state = NULL;
525 uint32_t *sceneKeyNum;
526 const void *sceneKey;
527 while ((sceneKeyNum = pa_hashmap_iterate(u->sceneToCountMap, &state, &sceneKey))) {
528 uint64_t sceneKeyCode = (uint64_t)strtoul((char *)sceneKey, NULL, BASE_TEN);
529 for (uint32_t count = 0; count < *sceneKeyNum; count++) {
530 EnhanceChainManagerReleaseCb(sceneKeyCode);
531 }
532 }
533 }
534
pa__done(pa_module * m)535 void pa__done(pa_module *m)
536 {
537 pa_source *source = NULL;
538
539 CHECK_AND_RETURN_LOG(m != NULL, "pa core is null");
540
541 if ((source = m->userdata)) {
542 struct Userdata *u = (struct Userdata *)source->userdata;
543 if (u != NULL) {
544 AUDIO_INFO_LOG("Release all enhChains on [%{public}s]", source->name);
545 ReleaseAllChains(u);
546 }
547 PaHdiSourceFree(source);
548 m->userdata = NULL;
549 }
550 }