1 /*
2 * Copyright (c) 2024 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 #undef LOG_TAG
21 #define LOG_TAG "ModuleSplitStreamSink"
22
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <errno.h>
26 #include <unistd.h>
27 #include <string.h>
28 #include "securec.h"
29
30 #include <pulse/rtclock.h>
31 #include <pulse/timeval.h>
32 #include <pulse/util.h>
33 #include <pulse/xmalloc.h>
34
35 #include <pulsecore/i18n.h>
36 #include <pulsecore/macro.h>
37 #include <pulsecore/sink.h>
38 #include <pulsecore/module.h>
39 #include <pulsecore/core-util.h>
40 #include <pulsecore/modargs.h>
41 #include <pulsecore/log.h>
42 #include <pulsecore/thread.h>
43 #include <pulsecore/thread-mq.h>
44 #include <pulsecore/rtpoll.h>
45 #include <pulsecore/mix.h>
46 #include <pulsecore/memblockq.h>
47 #include <pulsecore/memblock.h>
48
49 #include <pthread.h>
50 #include "audio_pulseaudio_log.h"
51 #include "audio_schedule.h"
52 #include "audio_utils_c.h"
53 #include "volume_tools_c.h"
54 #include "audio_volume_c.h"
55 #include "intf_def.h"
56 #include "sink/sink_intf.h"
57
58 #define DEFAULT_SINK_NAME "hdi_output"
59 #define DEFAULT_DEVICE_CLASS "primary"
60 #define DEFAULT_DEVICE_NETWORKID "LocalDevice"
61 #define DEFAULT_BUFFER_SIZE 8192
62 #define MAX_SINK_VOLUME_LEVEL 1.0
63 #define MIX_BUFFER_LENGTH (pa_page_size())
64 #define MAX_REWIND (7000 * PA_USEC_PER_MSEC)
65 #define USEC_PER_SEC 1000000
66 #define SCENE_TYPE_NUM 7
67 #define PA_ERR (-1)
68 #define MAX_PARTS 10
69
70 #define STREAM_TYPE_MEDIA "1"
71 #define STREAM_TYPE_COMMUNICATION "2"
72 #define STREAM_TYPE_NAVIGATION "13"
73 #define STREAM_TYPE_VIDEO_COMMUNICATION "17"
74
75 char *g_splitArr[MAX_PARTS];
76 int g_splitNums = 0;
77 const char *SPLIT_MODE;
78 const uint32_t SPLIT_ONE_STREAM = 1;
79 const uint32_t SPLIT_TWO_STREAM = 2;
80 const uint32_t SPLIT_THREE_STREAM = 3;
81
82 PA_MODULE_AUTHOR("OpenHarmony");
83 PA_MODULE_DESCRIPTION(_("Split Stream Sink"));
84 PA_MODULE_VERSION(PACKAGE_VERSION);
85 PA_MODULE_LOAD_ONCE(false);
86 PA_MODULE_USAGE(
87 "sink_name=<name of sink> "
88 "sink_properties=<properties for the sink> "
89 "format=<sample format> "
90 "rate=<sample rate> "
91 "channels=<number of channels> "
92 "channel_map=<channel map>"
93 "buffer_size=<custom buffer size>"
94 "formats=<semi-colon separated sink formats>");
95
96 static ssize_t SplitRenderWrite(struct SinkAdapter *sinkAdapter, pa_memchunk *pchunk, char *streamType);
97
98 struct userdata {
99 pa_core *core;
100 pa_module *module;
101 pa_sink *sink;
102 pa_thread *thread;
103 pa_thread_mq thread_mq;
104 pa_rtpoll *rtpoll;
105 uint32_t buffer_size;
106 pa_usec_t block_usec;
107 pa_usec_t timestamp;
108 pa_idxset *formats;
109 pa_thread *thread_split_hdi;
110 bool isHDISinkStarted;
111 struct SinkAdapter *sinkAdapter;
112 pa_asyncmsgq *dq;
113 pa_atomic_t dflag;
114 pa_usec_t writeTime;
115 pa_usec_t prewrite;
116 pa_sink_state_t previousState;
117 pa_usec_t timestampLastLog;
118 const char *deviceNetworkId;
119 const char *adapterName;
120 uint32_t open_mic_speaker;
121 pa_sample_spec ss;
122 pa_channel_map map;
123 int32_t deviceType;
124 size_t bytesDropped;
125 uint32_t writeCount;
126 uint32_t renderCount;
127 uint32_t fixed_latency;
128 pa_usec_t lastProcessDataTime;
129 uint32_t renderInIdleState;
130 uint32_t defaultAdapterEnable;
131 };
132
133 static const char * const VALID_MODARGS[] = {
134 "sink_name",
135 "device_class",
136 "sink_properties",
137 "format",
138 "rate",
139 "channels",
140 "channel_map",
141 "buffer_size",
142 "file_path",
143 "adapter_name",
144 "fixed_latency",
145 "sink_latency",
146 "render_in_idle_state",
147 "open_mic_speaker",
148 "test_mode_on",
149 "network_id",
150 "device_type",
151 "offload_enable",
152 "default_adapter_enable",
153 "split_mode",
154 NULL
155 };
156
157 char *const SCENE_TYPE_SET[SCENE_TYPE_NUM] = {"SCENE_MUSIC", "SCENE_GAME", "SCENE_MOVIE", "SCENE_SPEECH", "SCENE_RING",
158 "SCENE_OTHERS", "EFFECT_NONE"};
159
160 enum {
161 HDI_INIT,
162 HDI_DEINIT,
163 HDI_START,
164 HDI_STOP,
165 HDI_RENDER,
166 QUIT,
167 HDI_RENDER_MEDIA,
168 HDI_RENDER_NAVIGATION,
169 HDI_RENDER_COMMUNICATION
170 };
171
ConvertPaToHdiAdapterFormat(pa_sample_format_t format)172 static enum AudioSampleFormatIntf ConvertPaToHdiAdapterFormat(pa_sample_format_t format)
173 {
174 enum AudioSampleFormatIntf adapterFormat;
175 switch (format) {
176 case PA_SAMPLE_U8:
177 adapterFormat = SAMPLE_U8;
178 break;
179 case PA_SAMPLE_S16LE:
180 adapterFormat = SAMPLE_S16;
181 break;
182 case PA_SAMPLE_S24LE:
183 adapterFormat = SAMPLE_S24;
184 break;
185 case PA_SAMPLE_S32LE:
186 adapterFormat = SAMPLE_S32;
187 break;
188 default:
189 adapterFormat = INVALID_WIDTH;
190 break;
191 }
192
193 return adapterFormat;
194 }
195
ConvertToSplitArr(const char * str)196 static void ConvertToSplitArr(const char *str)
197 {
198 for (int i = 0; i < MAX_PARTS; ++i) {
199 g_splitArr[i] = NULL;
200 }
201 char *token;
202 char *copy = strdup(str);
203 CHECK_AND_RETURN_LOG(copy != NULL, "copy is null");
204 int count = 0;
205 token = strtok(copy, ":");
206 while (token != NULL && count < MAX_PARTS) {
207 g_splitArr[count] = (char *)malloc(strlen(token) + 1);
208 if (g_splitArr[count] != NULL) {
209 if (strcpy_s(g_splitArr[count], strlen(token) + 1, token) != 0) {
210 AUDIO_ERR_LOG("strcpy_s failed.");
211 };
212 count++;
213 } else {
214 AUDIO_ERR_LOG("Memory allocation failed.\n");
215 break;
216 }
217 token = strtok(NULL, ":");
218 }
219 g_splitNums = count;
220 free(copy);
221 }
222
SinkProcessMsg(pa_msgobject * o,int code,void * data,int64_t offset,pa_memchunk * chunk)223 static int SinkProcessMsg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk)
224 {
225 switch (code) {
226 case PA_SINK_MESSAGE_GET_LATENCY:
227 *((int64_t*) data) = 0;
228 return 0;
229 default:
230 break;
231 }
232
233 return pa_sink_process_msg(o, code, data, offset, chunk);
234 }
235
236 /* Called from the IO thread. */
SinkSetStateInIoThreadCb(pa_sink * s,pa_sink_state_t new_state,pa_suspend_cause_t new_suspend_cause)237 static int SinkSetStateInIoThreadCb(pa_sink *s, pa_sink_state_t new_state, pa_suspend_cause_t new_suspend_cause)
238 {
239 struct userdata *u;
240
241 CHECK_AND_RETURN_RET_LOG(s != NULL, -1, "s is null");
242 pa_assert_se(u = s->userdata);
243 CHECK_AND_RETURN_RET_LOG(u != NULL, -1, "u is null");
244
245 if (s->thread_info.state == PA_SINK_SUSPENDED || s->thread_info.state == PA_SINK_INIT) {
246 if (PA_SINK_IS_OPENED(new_state)) {
247 u->timestamp = pa_rtclock_now();
248 }
249 }
250
251 return 0;
252 }
253
SinkUpdateRequestedLatencyCb(pa_sink * s)254 static void SinkUpdateRequestedLatencyCb(pa_sink *s)
255 {
256 struct userdata *u;
257 size_t nbytes;
258
259 pa_sink_assert_ref(s);
260 pa_assert_se(u = s->userdata);
261
262 u->block_usec = pa_sink_get_requested_latency_within_thread(s);
263
264 if (u->block_usec == (pa_usec_t) -1) {
265 u->block_usec = s->thread_info.max_latency;
266 }
267
268 nbytes = pa_usec_to_bytes(u->block_usec, &s->sample_spec);
269 pa_sink_set_max_rewind_within_thread(s, nbytes);
270 pa_sink_set_max_request_within_thread(s, nbytes);
271 }
272
SinkReconfigureCb(pa_sink * s,pa_sample_spec * spec,bool passthrough)273 static void SinkReconfigureCb(pa_sink *s, pa_sample_spec *spec, bool passthrough)
274 {
275 s->sample_spec = *spec;
276 }
277
SinkSetFormatsCb(pa_sink * s,pa_idxset * formats)278 static bool SinkSetFormatsCb(pa_sink *s, pa_idxset *formats)
279 {
280 CHECK_AND_RETURN_RET_LOG(s != NULL, false, "s is null");
281 CHECK_AND_RETURN_RET_LOG(formats != NULL, false, "formats is null");
282 struct userdata *u = s->userdata;
283
284 CHECK_AND_RETURN_RET_LOG(u != NULL, false, "u is null");
285
286 pa_idxset_free(u->formats, (pa_free_cb_t) pa_format_info_free);
287 u->formats = pa_idxset_copy(formats, (pa_copy_func_t) pa_format_info_copy);
288
289 return true;
290 }
291
SinkGetFormatsCb(pa_sink * s)292 static pa_idxset* SinkGetFormatsCb(pa_sink *s)
293 {
294 CHECK_AND_RETURN_RET_LOG(s != NULL, NULL, "s is null");
295 struct userdata *u = s->userdata;
296
297 CHECK_AND_RETURN_RET_LOG(u != NULL, NULL, "u is null");
298
299 return pa_idxset_copy(u->formats, (pa_copy_func_t) pa_format_info_copy);
300 }
301
ProcessRewind(struct userdata * u,pa_usec_t now)302 static void ProcessRewind(struct userdata *u, pa_usec_t now)
303 {
304 size_t rewindNbytes;
305 size_t inBuffer;
306 pa_usec_t delay;
307
308 CHECK_AND_RETURN_LOG(u != NULL, "u is null");
309
310 rewindNbytes = u->sink->thread_info.rewind_nbytes;
311 if (!PA_SINK_IS_OPENED(u->sink->thread_info.state) || rewindNbytes == 0) {
312 goto do_nothing;
313 }
314 AUDIO_DEBUG_LOG("Requested to rewind %lu bytes.", (unsigned long) rewindNbytes);
315
316 if (u->timestamp <= now) {
317 goto do_nothing;
318 }
319
320 delay = u->timestamp - now;
321 inBuffer = pa_usec_to_bytes(delay, &u->sink->sample_spec);
322 if (inBuffer == 0) {
323 goto do_nothing;
324 }
325
326 if (rewindNbytes > inBuffer) {
327 rewindNbytes = inBuffer;
328 }
329
330 pa_sink_process_rewind(u->sink, rewindNbytes);
331 u->timestamp -= pa_bytes_to_usec(rewindNbytes, &u->sink->sample_spec);
332
333 AUDIO_DEBUG_LOG("Rewound %lu bytes.", (unsigned long) rewindNbytes);
334 return;
335
336 do_nothing:
337 pa_sink_process_rewind(u->sink, 0);
338 }
339
StartSplitStreamHdiIfRunning(struct userdata * u)340 static void StartSplitStreamHdiIfRunning(struct userdata *u)
341 {
342 AUTO_CTRACE("split_stream_sink::StartPrimaryHdiIfRunning");
343 if (u->isHDISinkStarted) {
344 return;
345 }
346
347 if (u->sinkAdapter->SinkAdapterStart(u->sinkAdapter)) {
348 AUDIO_ERR_LOG("split_stream_sink,audiorenderer control start failed!");
349 u->sinkAdapter->SinkAdapterDeInit(u->sinkAdapter);
350 } else {
351 u->isHDISinkStarted = true;
352 u->writeCount = 0;
353 u->renderCount = 0;
354 AUDIO_INFO_LOG("StartPrimaryHdiIfRunning, Successfully restarted HDI renderer");
355 u->renderInIdleState = 1;
356 }
357 }
358
SplitSinkRenderInputsDrop(pa_sink * si,pa_mix_info * infoIn,unsigned n,pa_memchunk * chunkIn)359 static void SplitSinkRenderInputsDrop(pa_sink *si, pa_mix_info *infoIn, unsigned n, pa_memchunk *chunkIn)
360 {
361 CHECK_AND_RETURN_LOG(si != NULL, "s is null");
362 pa_sink_assert_io_context(si);
363 CHECK_AND_RETURN_LOG(chunkIn != NULL, "chunkIn is null");
364 CHECK_AND_RETURN_LOG(chunkIn->memblock != NULL, "chunkIn->memblock is null");
365 CHECK_AND_RETURN_LOG(chunkIn->length > 0, "chunkIn->length < 0");
366 AUTO_CTRACE("split_stream_sink::SplitSinkRenderInputsDrop:%u:len:%zu", n, chunkIn->length);
367
368 /* We optimize for the case where the order of the inputs has not changed */
369
370 pa_mix_info *infoCur = NULL;
371 pa_sink_input *sinkInput = NULL;
372 for (uint32_t k = 0; k < n; k++) {
373 sinkInput = infoIn[k].userdata;
374 pa_sink_input_assert_ref(sinkInput);
375 AUTO_CTRACE("hdi_sink::InnerCap:pa_sink_input_drop:%u:len:%zu", sinkInput->index, chunkIn->length);
376 pa_sink_input_drop(sinkInput, chunkIn->length);
377
378 infoCur = infoIn + k;
379 if (infoCur) {
380 if (infoCur->chunk.memblock) {
381 pa_memblock_unref(infoCur->chunk.memblock);
382 pa_memchunk_reset(&infoCur->chunk);
383 }
384
385 pa_sink_input_unref(infoCur->userdata);
386 }
387 }
388 }
389
IsPeekCurrentSinkInput(char * streamType,const char * usageStr)390 static int IsPeekCurrentSinkInput(char *streamType, const char *usageStr)
391 {
392 CHECK_AND_RETURN_RET_LOG(usageStr != NULL, -1, "usageStr is null");
393 int flag = 0;
394 if (g_splitNums == SPLIT_ONE_STREAM) {
395 flag = 1;
396 }
397
398 if (g_splitNums == SPLIT_TWO_STREAM) {
399 if (strcmp(usageStr, STREAM_TYPE_NAVIGATION) && !strcmp(streamType, STREAM_TYPE_MEDIA)) {
400 flag = 1;
401 } else if (!strcmp(usageStr, STREAM_TYPE_NAVIGATION) && !strcmp(streamType, STREAM_TYPE_NAVIGATION)) {
402 flag = 1;
403 }
404 }
405
406 if (g_splitNums == SPLIT_THREE_STREAM) {
407 if (strcmp(usageStr, STREAM_TYPE_NAVIGATION) && strcmp(usageStr, STREAM_TYPE_COMMUNICATION) &&
408 strcmp(usageStr, STREAM_TYPE_VIDEO_COMMUNICATION) && !strcmp(streamType, STREAM_TYPE_MEDIA)) {
409 flag = 1;
410 } else if (!strcmp(usageStr, STREAM_TYPE_NAVIGATION) && !strcmp(streamType, STREAM_TYPE_NAVIGATION)) {
411 flag = 1;
412 } else if ((!strcmp(usageStr, STREAM_TYPE_COMMUNICATION) ||
413 !strcmp(usageStr, STREAM_TYPE_VIDEO_COMMUNICATION)) &&
414 !strcmp(streamType, STREAM_TYPE_COMMUNICATION)) {
415 flag = 1;
416 }
417 }
418
419 return flag;
420 }
421
SafeProplistGets(const pa_proplist * p,const char * key,const char * defstr)422 static const char *SafeProplistGets(const pa_proplist *p, const char *key, const char *defstr)
423 {
424 const char *res = pa_proplist_gets(p, key);
425 if (res == NULL) {
426 return defstr;
427 }
428 return res;
429 }
430
ProcessAudioVolume(pa_sink_input * sinkIn,size_t length,pa_memchunk * pchunk,pa_sink * si)431 static void ProcessAudioVolume(pa_sink_input *sinkIn, size_t length, pa_memchunk *pchunk, pa_sink *si)
432 {
433 AUTO_CTRACE("module_split_stream_sink::ProcessAudioVolume: len:%zu", length);
434 struct userdata *u;
435 if (sinkIn == NULL || pchunk == NULL || si == NULL) {
436 AUDIO_ERR_LOG("Null pointer");
437 return;
438 }
439 pa_assert_se(u = si->userdata);
440 const char *streamType = SafeProplistGets(sinkIn->proplist, "stream.type", "NULL");
441 const char *sessionIDStr = SafeProplistGets(sinkIn->proplist, "stream.sessionID", "NULL");
442 const char *deviceClass = u->sinkAdapter->deviceClass;
443 uint32_t sessionID = sessionIDStr != NULL ? (uint32_t)atoi(sessionIDStr) : 0;
444 float volumeEnd = GetCurVolume(sessionID, streamType, deviceClass);
445 float volumeBeg = GetPreVolume(sessionID);
446 float fadeBeg = 1.0f;
447 float fadeEnd = 1.0f;
448 if (!pa_safe_streq(streamType, "ultrasonic")) {
449 GetStreamVolumeFade(sessionID, &fadeBeg, &fadeEnd);
450 }
451 if (pa_memblock_is_silence(pchunk->memblock)) {
452 AUTO_CTRACE("module_split_stream_sink::ProcessAudioVolume: is_silence");
453 AUDIO_PRERELEASE_LOGI("pa_memblock_is_silence");
454 } else {
455 AudioRawFormat rawFormat;
456 rawFormat.format = (uint32_t)ConvertPaToHdiAdapterFormat(si->sample_spec.format);
457 rawFormat.channels = (uint32_t)si->sample_spec.channels;
458
459 pa_memchunk_make_writable(pchunk, 0);
460 void *data = pa_memblock_acquire_chunk(pchunk);
461
462 AUDIO_DEBUG_LOG("length:%{public}zu channels:%{public}d format:%{public}d"
463 " volumeBeg:%{public}f, volumeEnd:%{public}f, fadeBeg:%{public}f, fadeEnd:%{public}f",
464 length, rawFormat.channels, rawFormat.format, volumeBeg, volumeEnd, fadeBeg, fadeEnd);
465 int32_t ret = ProcessVol(data, length, rawFormat, volumeBeg * fadeBeg, volumeEnd * fadeEnd);
466 if (ret != 0) {
467 AUDIO_WARNING_LOG("ProcessVol failed:%{public}d", ret);
468 }
469 pa_memblock_release(pchunk->memblock);
470 }
471 if (volumeBeg != volumeEnd || fadeBeg != fadeEnd) {
472 AUDIO_INFO_LOG("sessionID:%{public}s, length:%{public}zu, volumeBeg:%{public}f, volumeEnd:%{public}f"
473 ", fadeBeg:%{public}f, fadeEnd:%{public}f",
474 sessionIDStr, length, volumeBeg, volumeEnd, fadeBeg, fadeEnd);
475 if (volumeBeg != volumeEnd) {
476 SetPreVolume(sessionID, volumeEnd);
477 MonitorVolume(sessionID, true);
478 }
479 if (fadeBeg != fadeEnd) {
480 SetStreamVolumeFade(sessionID, fadeEnd, fadeEnd);
481 }
482 }
483 }
484
SplitFillMixInfo(pa_sink * s,size_t * length,pa_mix_info * info,unsigned maxInfo,char * streamType)485 static unsigned SplitFillMixInfo(pa_sink *s, size_t *length, pa_mix_info *info, unsigned maxInfo, char *streamType)
486 {
487 CHECK_AND_RETURN_RET_LOG(s != NULL, 0, "s is null");
488 CHECK_AND_RETURN_RET_LOG(length != NULL, 0, "length is null");
489 AUTO_CTRACE("split_stream_sink::SplitFillMixInfo:len:%zu", *length);
490 pa_sink_input *i;
491 unsigned n = 0;
492 void *state = NULL;
493 size_t mixlength = *length;
494
495 pa_sink_assert_ref(s);
496 pa_sink_assert_io_context(s);
497 CHECK_AND_RETURN_RET_LOG(info != NULL, 0, "info is null");
498
499 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)) && maxInfo > 0) {
500 const char *usageStr = pa_proplist_gets(i->proplist, "stream.usage");
501 AUDIO_DEBUG_LOG("splitFillMixInfo usageStr = %{public}s, streamType = %{public}s", usageStr, streamType);
502 if (IsPeekCurrentSinkInput(streamType, usageStr)) {
503 pa_sink_input_assert_ref(i);
504
505 AUTO_CTRACE("module_split_stream_sink::splitFillMixInfo::pa_sink_input_peek:%u len:%zu", i->index, *length);
506 pa_sink_input_peek(i, *length, &info->chunk, &info->volume);
507
508 if (mixlength == 0 || info->chunk.length < mixlength)
509 mixlength = info->chunk.length;
510
511 ProcessAudioVolume(i, mixlength, &info->chunk, s);
512
513 if (pa_memblock_is_silence(info->chunk.memblock)) {
514 pa_memblock_unref(info->chunk.memblock);
515 continue;
516 }
517
518 info->userdata = pa_sink_input_ref(i);
519 pa_assert(info->chunk.memblock);
520 pa_assert(info->chunk.length > 0);
521
522 info++;
523 n++;
524 maxInfo--;
525
526 if (mixlength > 0) {
527 *length = mixlength;
528 }
529 }
530 }
531 return n;
532 }
533
SplitSinkRenderMix(pa_sink * s,size_t length,pa_mix_info * info,unsigned n,pa_memchunk * result)534 static void SplitSinkRenderMix(pa_sink *s, size_t length, pa_mix_info *info, unsigned n, pa_memchunk *result)
535 {
536 CHECK_AND_RETURN_LOG(s != NULL, "s is null");
537 CHECK_AND_RETURN_LOG(info != NULL, "info is null");
538 if (n == 0) {
539 *result = s->silence;
540 pa_memblock_ref(result->memblock);
541
542 if (result->length > length)
543 result->length = length;
544 } else if (n == 1) {
545 pa_cvolume volume;
546
547 *result = info[0].chunk;
548 pa_memblock_ref(result->memblock);
549
550 if (result->length > length)
551 result->length = length;
552
553 pa_sw_cvolume_multiply(&volume, &s->thread_info.soft_volume, &info[0].volume);
554
555 if (s->thread_info.soft_muted || pa_cvolume_is_muted(&volume)) {
556 pa_memblock_unref(result->memblock);
557 pa_silence_memchunk_get(
558 &s->core->silence_cache, s->core->mempool, result, &s->sample_spec, result->length);
559 } else if (!pa_cvolume_is_norm(&volume)) {
560 pa_memchunk_make_writable(result, 0);
561 pa_volume_memchunk(result, &s->sample_spec, &volume);
562 }
563 } else {
564 void *ptr;
565 result->memblock = pa_memblock_new(s->core->mempool, length);
566
567 ptr = pa_memblock_acquire(result->memblock);
568 result->length =
569 pa_mix(info, n, ptr, length, &s->sample_spec, &s->thread_info.soft_volume, s->thread_info.soft_muted);
570 pa_memblock_release(result->memblock);
571
572 result->index = 0;
573 }
574 }
575
SplitPaSinkRender(pa_sink * s,size_t length,pa_memchunk * result,char * streamType)576 static unsigned SplitPaSinkRender(pa_sink *s, size_t length, pa_memchunk *result, char *streamType)
577 {
578 AUTO_CTRACE("module_split_stream_sink::SplitPaSinkRender:len:%zu", length);
579 unsigned streamCount = 0;
580 pa_mix_info info[MAX_MIX_CHANNELS];
581 unsigned n;
582 size_t blockSizeMax;
583
584 CHECK_AND_RETURN_RET_LOG(s != NULL, 0, "s is null");
585 pa_sink_assert_io_context(s);
586 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
587 pa_assert(pa_frame_aligned(length, &s->sample_spec));
588 CHECK_AND_RETURN_RET_LOG(result != NULL, 0, "result is null");
589
590 pa_assert(!s->thread_info.rewind_requested);
591 pa_assert(s->thread_info.rewind_nbytes == 0);
592
593 if (s->thread_info.state == PA_SINK_SUSPENDED) {
594 result->memblock = pa_memblock_ref(s->silence.memblock);
595 result->index = s->silence.index;
596 result->length = PA_MIN(s->silence.length, length);
597 return 0;
598 }
599
600 pa_sink_ref(s);
601
602 AUDIO_DEBUG_LOG("module_split_stream_sink, splitSinkRender in length = %{public}zu", length);
603 if (length == 0) {
604 length = pa_frame_align(MIX_BUFFER_LENGTH, &s->sample_spec);
605 }
606
607 blockSizeMax = pa_mempool_block_size_max(s->core->mempool);
608 if (length > blockSizeMax)
609 length = pa_frame_align(blockSizeMax, &s->sample_spec);
610
611 pa_assert(length > 0);
612
613 n = SplitFillMixInfo(s, &length, info, MAX_MIX_CHANNELS, streamType);
614 streamCount = n;
615 SplitSinkRenderMix(s, length, info, n, result);
616
617 SplitSinkRenderInputsDrop(s, info, n, result);
618
619 pa_sink_unref(s);
620 return streamCount;
621 }
622
SplitSinkRenderIntoMix(pa_sink * s,size_t length,pa_mix_info * info,unsigned n,pa_memchunk * target)623 static void SplitSinkRenderIntoMix(pa_sink *s, size_t length, pa_mix_info *info, unsigned n, pa_memchunk *target)
624 {
625 if (n == 0) {
626 if (target->length > length)
627 target->length = length;
628
629 pa_silence_memchunk(target, &s->sample_spec);
630 } else if (n == 1) {
631 pa_cvolume volume;
632
633 if (target->length > length)
634 target->length = length;
635
636 pa_sw_cvolume_multiply(&volume, &s->thread_info.soft_volume, &info[0].volume);
637
638 if (s->thread_info.soft_muted || pa_cvolume_is_muted(&volume)) {
639 pa_silence_memchunk(target, &s->sample_spec);
640 } else {
641 pa_memchunk vChunk;
642
643 vChunk = info[0].chunk;
644 pa_memblock_ref(vChunk.memblock);
645
646 if (vChunk.length > length)
647 vChunk.length = length;
648
649 if (!pa_cvolume_is_norm(&volume)) {
650 pa_memchunk_make_writable(&vChunk, 0);
651 pa_volume_memchunk(&vChunk, &s->sample_spec, &volume);
652 }
653
654 pa_memchunk_memcpy(target, &vChunk);
655 pa_memblock_unref(vChunk.memblock);
656 }
657 } else {
658 void *ptr;
659
660 ptr = pa_memblock_acquire(target->memblock);
661
662 target->length = pa_mix(info, n,
663 (uint8_t*) ptr + target->index, length,
664 &s->sample_spec,
665 &s->thread_info.soft_volume,
666 s->thread_info.soft_muted);
667
668 pa_memblock_release(target->memblock);
669 }
670 }
671
SplitPaSinkRenderInto(pa_sink * s,pa_memchunk * target,char * streamType)672 static void SplitPaSinkRenderInto(pa_sink *s, pa_memchunk *target, char *streamType)
673 {
674 pa_mix_info info[MAX_MIX_CHANNELS];
675 unsigned n;
676 size_t length;
677 size_t blockSizeMax;
678
679 pa_sink_assert_ref(s);
680 pa_sink_assert_io_context(s);
681 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
682 pa_assert(pa_frame_aligned(target->length, &s->sample_spec));
683
684 pa_assert(!s->thread_info.rewind_requested);
685 pa_assert(s->thread_info.rewind_nbytes == 0);
686
687 if (s->thread_info.state == PA_SINK_SUSPENDED) {
688 pa_silence_memchunk(target, &s->sample_spec);
689 return;
690 }
691
692 pa_sink_ref(s);
693
694 length = target->length;
695 blockSizeMax = pa_mempool_block_size_max(s->core->mempool);
696 if (length > blockSizeMax)
697 length = pa_frame_align(blockSizeMax, &s->sample_spec);
698
699 pa_assert(length > 0);
700
701 n = SplitFillMixInfo(s, &length, info, MAX_MIX_CHANNELS, streamType);
702 SplitSinkRenderIntoMix(s, length, info, n, target);
703
704 SplitSinkRenderInputsDrop(s, info, n, target);
705
706 pa_sink_unref(s);
707 }
708
SplitPaSinkRenderIntoFull(pa_sink * s,pa_memchunk * target,char * streamType)709 static void SplitPaSinkRenderIntoFull(pa_sink *s, pa_memchunk *target, char *streamType)
710 {
711 pa_memchunk chunk;
712 size_t l;
713 size_t d;
714
715 CHECK_AND_RETURN_LOG(s != NULL, "s is null");
716 pa_sink_assert_io_context(s);
717 CHECK_AND_RETURN_LOG(target != NULL, "target is null");
718 CHECK_AND_RETURN_LOG(target->memblock != NULL, "target->memblock is null");
719 CHECK_AND_RETURN_LOG(target->length > 0, "target->length < 0");
720 pa_assert(pa_frame_aligned(target->length, &s->sample_spec));
721
722 if (s->thread_info.state == PA_SINK_SUSPENDED) {
723 pa_silence_memchunk(target, &s->sample_spec);
724 return;
725 }
726
727 pa_sink_ref(s);
728
729 l = target->length;
730 d = 0;
731 while (l > 0) {
732 chunk = *target;
733 chunk.index += d;
734 chunk.length -=d;
735
736 SplitPaSinkRenderInto(s, &chunk, streamType);
737
738 d += chunk.length;
739 l -= chunk.length;
740 }
741
742 pa_sink_unref(s);
743 }
744
SplitPaSinkRenderFull(pa_sink * s,size_t length,pa_memchunk * result,char * streamType)745 static unsigned SplitPaSinkRenderFull(pa_sink *s, size_t length, pa_memchunk *result, char *streamType)
746 {
747 unsigned nSink;
748 pa_sink_assert_ref(s);
749 pa_sink_assert_io_context(s);
750 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
751 pa_assert(length > 0);
752 pa_assert(pa_frame_aligned(length, &s->sample_spec));
753 CHECK_AND_RETURN_RET_LOG(result != NULL, 0, "result is null");
754
755 pa_assert(!s->thread_info.rewind_requested);
756 pa_assert(s->thread_info.rewind_nbytes == 0);
757
758 if (s->thread_info.state == PA_SINK_SUSPENDED) {
759 result->memblock = pa_memblock_ref(s->silence.memblock);
760 result->index = s->silence.index;
761 result->length = PA_MIN(s->silence.length, length);
762 return 0;
763 }
764
765 pa_sink_ref(s);
766
767 AUDIO_DEBUG_LOG("module_split_stream_sink, splitSinkRender in length = %{public}zu", length);
768 nSink = SplitPaSinkRender(s, length, result, streamType);
769 if (nSink == 0) {
770 return nSink;
771 }
772
773 if (result->length < length) {
774 pa_memchunk chunk;
775
776 pa_memchunk_make_writable(result, length);
777
778 chunk.memblock = result->memblock;
779 chunk.index = result->index + result->length;
780 chunk.length = length - result->length;
781
782 SplitPaSinkRenderIntoFull(s, &chunk, streamType);
783
784 result->length = length;
785 }
786
787 pa_sink_unref(s);
788 return nSink;
789 }
790
SendStreamData(struct userdata * u,int num,pa_memchunk chunk)791 static void SendStreamData(struct userdata *u, int num, pa_memchunk chunk)
792 {
793 if (num < 0 || num >= g_splitNums) {
794 return;
795 }
796 // start hdi
797 StartSplitStreamHdiIfRunning(u);
798 // send msg post data
799 if (!strcmp(g_splitArr[num], STREAM_TYPE_NAVIGATION)) {
800 pa_asyncmsgq_post(u->dq, NULL, HDI_RENDER_NAVIGATION, NULL, 0, &chunk, NULL);
801 } else if (!strcmp(g_splitArr[num], STREAM_TYPE_COMMUNICATION)) {
802 pa_asyncmsgq_post(u->dq, NULL, HDI_RENDER_COMMUNICATION, NULL, 0, &chunk, NULL);
803 } else {
804 pa_asyncmsgq_post(u->dq, NULL, HDI_RENDER_MEDIA, NULL, 0, &chunk, NULL);
805 }
806 }
807
ProcessRender(struct userdata * u,pa_usec_t now)808 static void ProcessRender(struct userdata *u, pa_usec_t now)
809 {
810 AUTO_CTRACE("module_split_stream_sink: ProcessRender");
811
812 CHECK_AND_RETURN_LOG(u != NULL, "u is null");
813
814 /* Fill the buffer up the latency size */
815 int count = 0;
816 for (int i = 0; i < g_splitNums; i++) {
817 AUTO_CTRACE("module_split_stream_sink::ProcessRender:streamType:%s", g_splitArr[i]);
818 AUDIO_DEBUG_LOG("module_split_stream_sink: ProcessRender:streamType:%{public}s", g_splitArr[i]);
819
820 pa_memchunk chunk;
821 unsigned chunkIsNull = 0;
822 chunkIsNull = SplitPaSinkRenderFull(u->sink, u->sink->thread_info.max_request, &chunk, g_splitArr[i]);
823 if (chunkIsNull == 0) {
824 count++;
825 if (count != g_splitNums) {
826 continue;
827 }
828 for (int j = 0; j < g_splitNums; j++) {
829 SendStreamData(u, j, chunk);
830 }
831 break;
832 }
833 SendStreamData(u, i, chunk);
834 }
835 u->timestamp += pa_bytes_to_usec(u->sink->thread_info.max_request, &u->sink->sample_spec);
836 }
837
MonitorLinkedState(pa_sink * si,bool isRunning)838 static bool MonitorLinkedState(pa_sink *si, bool isRunning)
839 {
840 if (isRunning) {
841 return si->monitor_source && PA_SOURCE_IS_RUNNING(si->monitor_source->thread_info.state);
842 } else {
843 return si->monitor_source && PA_SOURCE_IS_LINKED(si->monitor_source->thread_info.state);
844 }
845 }
846
ThreadFunc(void * userdata)847 static void ThreadFunc(void *userdata)
848 {
849 ScheduleReportData(getpid(), gettid(), "audio_server");
850 struct userdata *u = userdata;
851 CHECK_AND_RETURN_LOG(u != NULL, "u is null");
852 AUDIO_DEBUG_LOG("Thread starting up");
853 if (u->core->realtime_scheduling) {
854 pa_thread_make_realtime(u->core->realtime_priority);
855 }
856 pa_thread_mq_install(&u->thread_mq);
857 u->timestamp = pa_rtclock_now();
858 for (;;) {
859 pa_usec_t now = 0;
860 int ret;
861
862 if (PA_SINK_IS_OPENED(u->sink->thread_info.state)) {
863 now = pa_rtclock_now();
864 }
865
866 bool flag = (((u->renderInIdleState && PA_SINK_IS_OPENED(u->sink->thread_info.state)) ||
867 (!u->renderInIdleState && PA_SINK_IS_RUNNING(u->sink->thread_info.state))) &&
868 !(u->sink->thread_info.state == PA_SINK_IDLE && u->previousState == PA_SINK_SUSPENDED) &&
869 !(u->sink->thread_info.state == PA_SINK_IDLE && u->previousState == PA_SINK_INIT)) ||
870 (u->sink->thread_info.state == PA_SINK_IDLE && MonitorLinkedState(u->sink, true));
871 if (flag) {
872 now = pa_rtclock_now();
873 }
874
875 if (PA_UNLIKELY(u->sink->thread_info.rewind_requested)) {
876 ProcessRewind(u, now);
877 }
878
879 /* Render some data and drop it immediately */
880 if (flag) {
881 if (u->timestamp <= now) {
882 ProcessRender(u, now);
883 }
884 pa_rtpoll_set_timer_absolute(u->rtpoll, u->timestamp);
885 } else {
886 pa_rtpoll_set_timer_disabled(u->rtpoll);
887 }
888 /* Hmm, nothing to do. Let's sleep */
889 if ((ret = pa_rtpoll_run(u->rtpoll)) < 0) {
890 goto fail;
891 }
892 if (ret == 0) {
893 goto finish;
894 }
895 }
896
897 fail:
898 /* If this was no regular exit from the loop we have to continue
899 * processing messages until we received PA_MESSAGE_SHUTDOWN */
900 pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core),
901 PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL);
902 pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN);
903
904 finish:
905 AUDIO_DEBUG_LOG("Thread shutting down");
906 }
907
ProcessSplitHdiRender(struct userdata * u,pa_memchunk * chunk,char * streamType)908 static void ProcessSplitHdiRender(struct userdata *u, pa_memchunk *chunk, char *streamType)
909 {
910 pa_usec_t now = pa_rtclock_now();
911 if (!u->isHDISinkStarted && now - u->timestampLastLog > USEC_PER_SEC) {
912 u->timestampLastLog = now;
913 const char *deviceClass = u->sinkAdapter->deviceClass;
914 AUDIO_DEBUG_LOG("HDI not started, skip RenderWrite, wait sink[%s] suspend", deviceClass);
915 pa_memblock_unref(chunk->memblock);
916 } else if (!u->isHDISinkStarted) {
917 pa_memblock_unref(chunk->memblock);
918 } else if (SplitRenderWrite(u->sinkAdapter, chunk, streamType) < 0) {
919 u->bytesDropped += chunk->length;
920 AUDIO_ERR_LOG("RenderWrite failed");
921 }
922 if (pa_atomic_load(&u->dflag) == 1) {
923 pa_atomic_sub(&u->dflag, 1);
924 }
925 u->writeTime = pa_rtclock_now() - now;
926 }
927
ThreadFuncWriteHDI(void * userdata)928 static void ThreadFuncWriteHDI(void *userdata)
929 {
930 // set audio thread priority
931 ScheduleReportData(getpid(), gettid(), "pulseaudio");
932
933 struct userdata *u = userdata;
934 CHECK_AND_RETURN_LOG(u != NULL, "u is null");
935
936 int32_t quit = 0;
937
938 do {
939 int32_t code = 0;
940 pa_memchunk chunk;
941
942 pa_assert_se(pa_asyncmsgq_get(u->dq, NULL, &code, NULL, NULL, &chunk, 1) == 0);
943
944 switch (code) {
945 case HDI_RENDER_MEDIA: {
946 ProcessSplitHdiRender(u, &chunk, STREAM_TYPE_MEDIA);
947 break;
948 }
949 case HDI_RENDER_COMMUNICATION: {
950 ProcessSplitHdiRender(u, &chunk, STREAM_TYPE_COMMUNICATION);
951 break;
952 }
953 case HDI_RENDER_NAVIGATION: {
954 ProcessSplitHdiRender(u, &chunk, STREAM_TYPE_NAVIGATION);
955 break;
956 }
957 case QUIT:
958 quit = 1;
959 break;
960 default:
961 break;
962 }
963 pa_asyncmsgq_done(u->dq, 0);
964 } while (!quit);
965 }
966
SplitRenderWrite(struct SinkAdapter * sinkAdapter,pa_memchunk * pchunk,char * streamType)967 static ssize_t SplitRenderWrite(struct SinkAdapter *sinkAdapter, pa_memchunk *pchunk, char *streamType)
968 {
969 size_t index;
970 size_t length;
971 ssize_t count = 0;
972 void *p = NULL;
973
974 CHECK_AND_RETURN_RET_LOG(pchunk != NULL, 0, "pchunk is null");
975
976 index = pchunk->index;
977 length = pchunk->length;
978 p = pa_memblock_acquire(pchunk->memblock);
979 CHECK_AND_RETURN_RET_LOG(p != NULL, 0, "p is null");
980
981 while (true) {
982 uint64_t writeLen = 0;
983
984 int32_t ret = sinkAdapter->SinkAdapterSplitRenderFrame(sinkAdapter, ((char*)p + index),
985 (uint64_t)length, &writeLen, streamType);
986 if (writeLen > length) {
987 AUDIO_ERR_LOG("Error writeLen > actual bytes. Length: %zu, Written: %" PRIu64 " bytes, %d ret",
988 length, writeLen, ret);
989 count = -1 - count;
990 break;
991 }
992 if (writeLen == 0) {
993 AUDIO_ERR_LOG("Failed to render Length: %{public}zu, Written: %{public}" PRIu64 " bytes, %{public}d ret",
994 length, writeLen, ret);
995 count = -1 - count;
996 break;
997 } else {
998 count += (ssize_t)writeLen;
999 index += writeLen;
1000 length -= writeLen;
1001 if (length == 0) {
1002 break;
1003 }
1004 }
1005 }
1006 pa_memblock_release(pchunk->memblock);
1007 pa_memblock_unref(pchunk->memblock);
1008
1009 return count;
1010 }
1011
CreateSink(pa_module * m,pa_modargs * ma,struct userdata * u)1012 static int CreateSink(pa_module *m, pa_modargs *ma, struct userdata *u)
1013 {
1014 pa_sample_spec ss;
1015 pa_channel_map map;
1016 pa_sink_new_data data;
1017 pa_format_info *format;
1018
1019 CHECK_AND_RETURN_RET_LOG(m != NULL, -1, "m is null");
1020
1021 ss = m->core->default_sample_spec;
1022 map = m->core->default_channel_map;
1023 if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
1024 AUDIO_ERR_LOG("Invalid sample format specification or channel map");
1025 return PA_ERR;
1026 }
1027
1028 pa_sink_new_data_init(&data);
1029 data.driver = __FILE__;
1030 data.module = m;
1031 pa_sink_new_data_set_name(&data, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME));
1032 pa_sink_new_data_set_sample_spec(&data, &ss);
1033 pa_sink_new_data_set_channel_map(&data, &map);
1034 pa_proplist_sets(data.proplist, PA_PROP_DEVICE_DESCRIPTION, _("Split Stream Output"));
1035 pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, "splitStream");
1036
1037 u->formats = pa_idxset_new(NULL, NULL);
1038 format = pa_format_info_new();
1039 format->encoding = PA_ENCODING_PCM;
1040 pa_idxset_put(u->formats, format, NULL);
1041
1042 if (pa_modargs_get_proplist(ma, "sink_properties", data.proplist, PA_UPDATE_REPLACE) < 0) {
1043 AUDIO_ERR_LOG("Invalid properties");
1044 pa_sink_new_data_done(&data);
1045 return PA_ERR;
1046 }
1047
1048 u->sink = pa_sink_new(m->core, &data, PA_SINK_LATENCY | PA_SINK_DYNAMIC_LATENCY);
1049 pa_sink_new_data_done(&data);
1050
1051 if (!u->sink) {
1052 AUDIO_ERR_LOG("Failed to create sink.");
1053 return PA_ERR;
1054 }
1055
1056 u->sink->parent.process_msg = SinkProcessMsg;
1057 u->sink->set_state_in_io_thread = SinkSetStateInIoThreadCb;
1058 u->sink->update_requested_latency = SinkUpdateRequestedLatencyCb;
1059 u->sink->reconfigure = SinkReconfigureCb;
1060 u->sink->get_formats = SinkGetFormatsCb;
1061 u->sink->set_formats = SinkSetFormatsCb;
1062 u->sink->userdata = u;
1063
1064 return 0;
1065 }
1066
InitRemoteSink(struct userdata * u,const char * filePath)1067 static int32_t InitRemoteSink(struct userdata *u, const char *filePath)
1068 {
1069 struct SinkAdapterAttr sample_attrs;
1070 int32_t ret;
1071
1072 sample_attrs.format = ConvertPaToHdiAdapterFormat(u->ss.format);
1073 sample_attrs.adapterName = u->adapterName;
1074 sample_attrs.openMicSpeaker = u->open_mic_speaker;
1075 sample_attrs.sampleRate = (uint32_t) u->ss.rate;
1076 sample_attrs.channel = u->ss.channels;
1077 sample_attrs.volume = MAX_SINK_VOLUME_LEVEL;
1078 sample_attrs.filePath = filePath;
1079 sample_attrs.deviceNetworkId = u->deviceNetworkId;
1080 sample_attrs.deviceType = u->deviceType;
1081 sample_attrs.aux = SPLIT_MODE;
1082
1083 ret = u->sinkAdapter->SinkAdapterInit(u->sinkAdapter, &sample_attrs);
1084 if (ret != 0) {
1085 AUDIO_ERR_LOG("audiorenderer Init failed!");
1086 return -1;
1087 }
1088
1089 return 0;
1090 }
1091
UserdataFree(struct userdata * u)1092 static void UserdataFree(struct userdata *u)
1093 {
1094 if (u->sink) {
1095 pa_sink_unlink(u->sink);
1096 }
1097
1098 if (u->thread) {
1099 pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL);
1100 pa_thread_free(u->thread);
1101 }
1102
1103 if (u->sinkAdapter) {
1104 u->sinkAdapter->SinkAdapterStop(u->sinkAdapter);
1105 u->sinkAdapter->SinkAdapterDeInit(u->sinkAdapter);
1106 ReleaseSinkAdapter(u->sinkAdapter);
1107 u->sinkAdapter = NULL;
1108 }
1109
1110 pa_thread_mq_done(&u->thread_mq);
1111
1112 if (u->sink) {
1113 pa_sink_unref(u->sink);
1114 }
1115
1116 if (u->rtpoll) {
1117 pa_rtpoll_free(u->rtpoll);
1118 }
1119
1120 if (u->formats) {
1121 pa_idxset_free(u->formats, (pa_free_cb_t)pa_format_info_free);
1122 }
1123
1124 pa_xfree(u);
1125
1126 for (int32_t i = 0; i < MAX_PARTS; ++i) {
1127 if (g_splitArr[i] == NULL) {
1128 continue;
1129 }
1130 free(g_splitArr[i]);
1131 g_splitArr[i] = NULL;
1132 }
1133 }
1134
InitFailed(pa_module * m,pa_modargs * ma)1135 static int InitFailed(pa_module *m, pa_modargs *ma)
1136 {
1137 AUDIO_ERR_LOG("Split Stream Sink Init Failed");
1138 UserdataFree(m->userdata);
1139 m->userdata = NULL;
1140 if (ma)
1141 pa_modargs_free(ma);
1142
1143 pa__done(m);
1144
1145 return PA_ERR;
1146 }
1147
PaHdiSinkNewInit(pa_module * m,pa_modargs * ma,struct userdata * u)1148 static int32_t PaHdiSinkNewInit(pa_module *m, pa_modargs *ma, struct userdata *u)
1149 {
1150 size_t nbytes;
1151 int mg;
1152 pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq);
1153 pa_sink_set_rtpoll(u->sink, u->rtpoll);
1154
1155 u->buffer_size = DEFAULT_BUFFER_SIZE;
1156
1157 mg = pa_modargs_get_value_u32(ma, "buffer_size", &u->buffer_size);
1158 CHECK_AND_RETURN_RET_LOG(mg >= 0, PA_ERR,
1159 "Failed to parse buffer_size arg in capturer sink");
1160
1161 u->block_usec = pa_bytes_to_usec(u->buffer_size, &u->sink->sample_spec);
1162
1163 nbytes = pa_usec_to_bytes(u->block_usec, &u->sink->sample_spec);
1164 pa_sink_set_max_rewind(u->sink, nbytes);
1165 pa_sink_set_max_request(u->sink, u->buffer_size);
1166
1167 if (u->fixed_latency) {
1168 pa_sink_set_fixed_latency(u->sink, u->block_usec);
1169 } else {
1170 pa_sink_set_latency_range(u->sink, 0, u->block_usec);
1171 }
1172
1173 const char *deviceClass = pa_modargs_get_value(ma, "device_class", DEFAULT_DEVICE_CLASS);
1174 u->sinkAdapter = GetSinkAdapter(deviceClass, pa_modargs_get_value(ma, "network_id", DEFAULT_DEVICE_NETWORKID));
1175 if (u->sinkAdapter == NULL) {
1176 AUDIO_ERR_LOG("Load adapter failed");
1177 return -1;
1178 }
1179
1180 if (pa_modargs_get_value_s32(ma, "device_type", &u->deviceType) < 0) {
1181 AUDIO_ERR_LOG("Failed to parse deviceType argument.");
1182 return -1;
1183 }
1184
1185 u->adapterName = pa_modargs_get_value(ma, "adapter_name", DEFAULT_DEVICE_CLASS);
1186 u->deviceNetworkId = pa_modargs_get_value(ma, "network_id", DEFAULT_DEVICE_NETWORKID);
1187
1188 u->ss = m->core->default_sample_spec;
1189 u->map = m->core->default_channel_map;
1190 if (pa_modargs_get_sample_spec_and_channel_map(ma, &u->ss, &u->map, PA_CHANNEL_MAP_DEFAULT) < 0) {
1191 AUDIO_ERR_LOG("Failed to parse sample specification and channel map");
1192 return -1;
1193 }
1194
1195 if (InitRemoteSink(u, pa_modargs_get_value(ma, "file_path", "")) < 0) {
1196 AUDIO_ERR_LOG("Failed to init remote audio render sink.");
1197 return -1;
1198 }
1199
1200 return 0;
1201 }
1202
pa__init(pa_module * m)1203 int pa__init(pa_module *m)
1204 {
1205 AUDIO_INFO_LOG("module_split_stream_sink pa__init start");
1206 struct userdata *u = NULL;
1207 pa_modargs *ma = NULL;
1208 int mq;
1209
1210 CHECK_AND_RETURN_RET_LOG(m != NULL, -1, "m is null");
1211
1212 ma = pa_modargs_new(m->argument, VALID_MODARGS);
1213 CHECK_AND_RETURN_RET_LOG(ma != NULL, InitFailed(m, ma), "Failed to parse module arguments:%{public}s", m->argument);
1214
1215 SPLIT_MODE = pa_modargs_get_value(ma, "split_mode", "1");
1216 AUDIO_INFO_LOG("module_split_stream_sink pa__init splitMode is %{public}s", SPLIT_MODE);
1217 ConvertToSplitArr(SPLIT_MODE);
1218
1219 m->userdata = u = pa_xnew0(struct userdata, 1);
1220 u->core = m->core;
1221 u->module = m;
1222 u->rtpoll = pa_rtpoll_new();
1223
1224 mq = pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll);
1225 CHECK_AND_RETURN_RET_LOG(mq >=0, InitFailed(m, ma), "pa_thread_mq_init() failed.");
1226
1227 if (CreateSink(m, ma, u) != 0) {
1228 return InitFailed(m, ma);
1229 }
1230
1231 if (PaHdiSinkNewInit(m, ma, u) < 0) {
1232 AUDIO_ERR_LOG("PaHdiSinkNewInit failed");
1233 return InitFailed(m, ma);
1234 }
1235
1236 u->dq = pa_asyncmsgq_new(0);
1237
1238 if (!(u->thread = pa_thread_new("OS_SplitStream", ThreadFunc, u))) {
1239 AUDIO_ERR_LOG("Failed to create thread.");
1240 return InitFailed(m, ma);
1241 }
1242
1243 if (!(u->thread_split_hdi = pa_thread_new("OS_splitToHdi", ThreadFuncWriteHDI, u))) {
1244 AUDIO_ERR_LOG("Failed to create OS_splitToHdi.");
1245 return InitFailed(m, ma);
1246 }
1247
1248 pa_sink_put(u->sink);
1249
1250 pa_modargs_free(ma);
1251
1252 return 0;
1253 }
1254
pa__get_n_used(pa_module * m)1255 int pa__get_n_used(pa_module *m)
1256 {
1257 struct userdata *u;
1258
1259 CHECK_AND_RETURN_RET_LOG(m != NULL, 0, "m is null");
1260 pa_assert_se(u = m->userdata);
1261
1262 return pa_sink_linked_by(u->sink);
1263 }
1264
pa__done(pa_module * m)1265 void pa__done(pa_module*m)
1266 {
1267 struct userdata *u;
1268
1269 CHECK_AND_RETURN_LOG(m != NULL, "m is null");
1270
1271 if (!(u = m->userdata)) {
1272 return;
1273 }
1274 UserdataFree(u);
1275 m->userdata = NULL;
1276 }
1277