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