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
HandleSourceOutputUnlinkForRemote(struct Userdata * u)348 static void HandleSourceOutputUnlinkForRemote(struct Userdata *u)
349 {
350 CHECK_AND_RETURN_LOG(u != NULL, "Get Userdata failed! userdata is NULL");
351 CHECK_AND_RETURN_LOG(u->sourceAdapter != NULL, "sourceAdapter is null");
352 CHECK_AND_RETURN_LOG(u->sourceAdapter->deviceClass != NULL, "deviceClass is null");
353 CHECK_AND_RETURN_LOG(u->source != NULL, "source is null");
354
355 if (strcmp(u->sourceAdapter->deviceClass, "remote") != 0) {
356 AUDIO_INFO_LOG("HandleSourceOutputUnlinkForRemote: not remote source");
357 } else {
358 void *state = NULL;
359 pa_source_output *sourceOutput;
360 bool noStreamRunning = true;
361 while ((sourceOutput = pa_hashmap_iterate(u->source->thread_info.outputs, &state, NULL))) {
362 if (sourceOutput->thread_info.state == PA_SOURCE_OUTPUT_RUNNING) {
363 noStreamRunning = false;
364 break;
365 }
366 }
367 if (!noStreamRunning) {
368 AUDIO_INFO_LOG("HandleSourceOutputUnlinkForRemote: source has running stream");
369 } else {
370 u->sourceAdapter->SourceAdapterStop(u->sourceAdapter);
371 }
372 }
373 }
374
HandleSourceOutputUnlink(pa_source_output * so,struct Userdata * u)375 static pa_hook_result_t HandleSourceOutputUnlink(pa_source_output *so, struct Userdata *u)
376 {
377 // If remote source has no running stream, stop source
378 HandleSourceOutputUnlinkForRemote(u);
379
380 const char *sceneType = pa_proplist_gets(so->proplist, "scene.type");
381 if (sceneType == NULL) {
382 sceneType = "";
383 }
384 const char *sceneBypass = pa_proplist_gets(so->proplist, "scene.bypass");
385 if (pa_safe_streq(sceneBypass, DEFAULT_SCENE_BYPASS)) {
386 AUDIO_INFO_LOG("scene:%{public}s has been set to bypass, do not need release", sceneType);
387 return PA_HOOK_OK;
388 }
389 uint32_t captureId = u->captureId;
390 uint32_t renderId = u->renderId;
391 uint64_t sceneTypeCode = 0;
392 if (GetSceneTypeCode(sceneType, &sceneTypeCode) != 0) {
393 AUDIO_ERR_LOG("scenetype:%{public}s GetSceneTypeCode failed", sceneType);
394 return PA_HOOK_OK;
395 }
396 uint64_t sceneKeyCode = 0;
397 sceneKeyCode = (sceneTypeCode << SCENE_TYPE_OFFSET) + (captureId << CAPTURER_ID_OFFSET) + renderId;
398 EnhanceChainManagerReleaseCb(sceneKeyCode);
399 char sceneKey[MAX_SCENE_NAME_LEN];
400 if (sprintf_s(sceneKey, sizeof(sceneKey), "%lu", sceneKeyCode) < 0) {
401 AUDIO_ERR_LOG("sprintf from sceneKeyCode to sceneKey failed");
402 return PA_HOOK_OK;
403 }
404 if (!pa_safe_streq(pa_proplist_gets(so->proplist, "scene.default"), "1") &&
405 DecreaseScenekeyCount(u->sceneToCountMap, sceneKey)) {
406 pa_hashmap_remove_and_free(u->sceneToPreResamplerMap, sceneKey);
407 pa_hashmap_remove_and_free(u->sceneToEcResamplerMap, sceneKey);
408 pa_hashmap_remove_and_free(u->sceneToMicRefResamplerMap, sceneKey);
409 }
410 return PA_HOOK_OK;
411 }
412
CheckIfAvailSource(pa_source_output * so,struct Userdata * u)413 static pa_hook_result_t CheckIfAvailSource(pa_source_output *so, struct Userdata *u)
414 {
415 pa_source *soSource = so->source;
416 pa_source *thisSource = u->source;
417 if (soSource == NULL || thisSource == NULL) {
418 return PA_HOOK_CANCEL;
419 }
420 if (soSource->index != thisSource->index) {
421 AUDIO_INFO_LOG("NOT correspondant SOURCE %{public}s AND %{public}s.", soSource->name, thisSource->name);
422 return PA_HOOK_CANCEL;
423 }
424 return PA_HOOK_OK;
425 }
426
SourceOutputPutCb(const pa_core * c,pa_source_output * so,struct Userdata * u)427 static pa_hook_result_t SourceOutputPutCb(const pa_core *c, pa_source_output *so, struct Userdata *u)
428 {
429 CHECK_AND_RETURN_RET_LOG(u != NULL, PA_HOOK_OK, "Get Userdata failed! userdata is NULL");
430 CHECK_AND_RETURN_RET_LOG(c != NULL, PA_HOOK_OK, "pa core is null");
431 CHECK_AND_RETURN_RET_LOG(so != NULL, PA_HOOK_OK, "so is NULL");
432
433 const char *sessionID = pa_proplist_gets(so->proplist, "stream.sessionID");
434 if (sessionID == NULL) {
435 sessionID = "";
436 }
437 AUDIO_INFO_LOG("Trigger SourceOutputPutCb sessionID:%{public}s", sessionID);
438
439 if (CheckIfAvailSource(so, u) == PA_HOOK_CANCEL) {
440 return PA_HOOK_OK;
441 }
442 return HandleSourceOutputPut(so, u);
443 }
444
SourceOutputUnlinkCb(const pa_core * c,pa_source_output * so,struct Userdata * u)445 static pa_hook_result_t SourceOutputUnlinkCb(const pa_core *c, pa_source_output *so, struct Userdata *u)
446 {
447 CHECK_AND_RETURN_RET_LOG(u != NULL, PA_HOOK_OK, "Get Userdata failed! userdata is NULL");
448 CHECK_AND_RETURN_RET_LOG(c != NULL, PA_HOOK_OK, "pa core is null");
449 CHECK_AND_RETURN_RET_LOG(so != NULL, PA_HOOK_OK, "so is NULL");
450
451 const char *sessionID = pa_proplist_gets(so->proplist, "stream.sessionID");
452 if (sessionID == NULL) {
453 sessionID = "";
454 }
455 AUDIO_INFO_LOG("Trigger SourceOutputUnlinkCb sessionID:%{public}s", sessionID);
456
457 if (CheckIfAvailSource(so, u) == PA_HOOK_CANCEL) {
458 return PA_HOOK_OK;
459 }
460 return HandleSourceOutputUnlink(so, u);
461 }
462
SourceOutputMoveStartCb(const pa_core * c,pa_source_output * so,struct Userdata * u)463 static pa_hook_result_t SourceOutputMoveStartCb(const pa_core *c, pa_source_output *so, struct Userdata *u)
464 {
465 CHECK_AND_RETURN_RET_LOG(u != NULL, PA_HOOK_OK, "Get Userdata failed! userdata is NULL");
466 CHECK_AND_RETURN_RET_LOG(c != NULL, PA_HOOK_OK, "pa core is null");
467 CHECK_AND_RETURN_RET_LOG(so != NULL, PA_HOOK_OK, "so is NULL");
468
469 const char *sessionID = pa_proplist_gets(so->proplist, "stream.sessionID");
470 if (sessionID == NULL) {
471 sessionID = "";
472 }
473 AUDIO_INFO_LOG("Trigger SourceOutputMoveStartCb sessionID:%{public}s", sessionID);
474
475 if (CheckIfAvailSource(so, u) == PA_HOOK_CANCEL) {
476 return PA_HOOK_OK;
477 }
478 return HandleSourceOutputUnlink(so, u);
479 }
480
SourceOutputMoveFinishCb(const pa_core * c,pa_source_output * so,struct Userdata * u)481 static pa_hook_result_t SourceOutputMoveFinishCb(const pa_core *c, pa_source_output *so, struct Userdata *u)
482 {
483 CHECK_AND_RETURN_RET_LOG(u != NULL, PA_HOOK_OK, "Get Userdata failed! userdata is NULL");
484 CHECK_AND_RETURN_RET_LOG(c != NULL, PA_HOOK_OK, "pa core is null");
485 CHECK_AND_RETURN_RET_LOG(so != NULL, PA_HOOK_OK, "so is NULL");
486
487 const char *sessionID = pa_proplist_gets(so->proplist, "stream.sessionID");
488 if (sessionID == NULL) {
489 sessionID = "";
490 }
491 AUDIO_INFO_LOG("Trigger SourceOutputMoveFinishCb sessionID:%{public}s", sessionID);
492
493 if (CheckIfAvailSource(so, u) == PA_HOOK_CANCEL) {
494 return PA_HOOK_OK;
495 }
496 return HandleSourceOutputPut(so, u);
497 }
498
pa__init(pa_module * m)499 int pa__init(pa_module *m)
500 {
501 pa_modargs *ma = NULL;
502
503 CHECK_AND_RETURN_RET_LOG(m != NULL, PA_HOOK_OK, "pa core is null");
504
505 if (!(ma = pa_modargs_new(m->argument, VALID_MODARGS))) {
506 AUDIO_ERR_LOG("Failed to parse module arguments");
507 goto fail;
508 }
509
510 if (!(m->userdata = PaHdiSourceNew(m, ma, __FILE__))) {
511 AUDIO_ERR_LOG("Failed to PaHdiSourceNew");
512 goto fail;
513 }
514 pa_source *source = (pa_source *)m->userdata;
515
516 pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PUT], PA_HOOK_LATE,
517 (pa_hook_cb_t)SourceOutputPutCb, source->userdata);
518 pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK], PA_HOOK_LATE,
519 (pa_hook_cb_t)SourceOutputUnlinkCb, source->userdata);
520 pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_FINISH], PA_HOOK_LATE,
521 (pa_hook_cb_t)SourceOutputMoveFinishCb, source->userdata);
522 pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_START], PA_HOOK_LATE,
523 (pa_hook_cb_t)SourceOutputMoveStartCb, source->userdata);
524
525 pa_source_put(source);
526 pa_modargs_free(ma);
527
528 return 0;
529
530 fail:
531
532 if (ma) {
533 pa_modargs_free(ma);
534 }
535
536 pa__done(m);
537
538 return -1;
539 }
540
pa__get_n_used(pa_module * m)541 int pa__get_n_used(pa_module *m)
542 {
543 CHECK_AND_RETURN_RET_LOG(m != NULL, PA_HOOK_OK, "pa core is null");
544
545 pa_source *source = m->userdata;
546
547 CHECK_AND_RETURN_RET_LOG(source != NULL, 0, "source is null");
548
549 return pa_source_linked_by(source);
550 }
551
ReleaseAllChains(struct Userdata * u)552 static void ReleaseAllChains(struct Userdata *u)
553 {
554 void *state = NULL;
555 uint32_t *sceneKeyNum;
556 const void *sceneKey;
557 while ((sceneKeyNum = pa_hashmap_iterate(u->sceneToCountMap, &state, &sceneKey))) {
558 uint64_t sceneKeyCode = (uint64_t)strtoul((char *)sceneKey, NULL, BASE_TEN);
559 for (uint32_t count = 0; count < *sceneKeyNum; count++) {
560 EnhanceChainManagerReleaseCb(sceneKeyCode);
561 }
562 }
563 }
564
pa__done(pa_module * m)565 void pa__done(pa_module *m)
566 {
567 pa_source *source = NULL;
568
569 CHECK_AND_RETURN_LOG(m != NULL, "pa core is null");
570
571 if ((source = m->userdata)) {
572 struct Userdata *u = (struct Userdata *)source->userdata;
573 if (u != NULL) {
574 AUDIO_INFO_LOG("Release all enhChains on [%{public}s]", source->name);
575 ReleaseAllChains(u);
576 }
577 PaHdiSourceFree(source);
578 m->userdata = NULL;
579 }
580 }