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