1 /*
2  * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #ifndef LOG_TAG
16 #define LOG_TAG "HdiSource"
17 #endif
18 
19 #include <config.h>
20 #include <pulse/rtclock.h>
21 #include <pulse/timeval.h>
22 #include <pulse/util.h>
23 #include <pulse/xmalloc.h>
24 #include <pulsecore/core.h>
25 #include <pulsecore/log.h>
26 #include <pulsecore/memchunk.h>
27 #include <pulsecore/modargs.h>
28 #include <pulsecore/module.h>
29 #include <pulsecore/rtpoll.h>
30 #include <pulsecore/thread-mq.h>
31 #include <pulsecore/thread.h>
32 
33 #include <inttypes.h>
34 #include <stddef.h>
35 #include <stdint.h>
36 #include <stdbool.h>
37 
38 #include "audio_types.h"
39 #include "audio_manager.h"
40 
41 #include "audio_hdi_log.h"
42 #include "securec.h"
43 #include "audio_hdiadapter_info.h"
44 #include "audio_schedule.h"
45 #include "audio_source_type.h"
46 #include "audio_hdiadapter_info.h"
47 #include "capturer_source_adapter.h"
48 #include "audio_utils_c.h"
49 
50 #define DEFAULT_SOURCE_NAME "hdi_input"
51 #define DEFAULT_DEVICE_CLASS "primary"
52 #define DEFAULT_AUDIO_DEVICE_NAME "Internal Mic"
53 #define DEFAULT_DEVICE_NETWORKID "LocalDevice"
54 
55 #define DEFAULT_BUFFER_SIZE (1024 * 16)
56 #define MAX_VOLUME_VALUE 15.0
57 #define DEFAULT_LEFT_VOLUME MAX_VOLUME_VALUE
58 #define DEFAULT_RIGHT_VOLUME MAX_VOLUME_VALUE
59 #define MAX_LATENCY_USEC (PA_USEC_PER_SEC * 2)
60 #define MIN_LATENCY_USEC 500
61 #define AUDIO_POINT_NUM  1024
62 #define AUDIO_FRAME_NUM_IN_BUF 30
63 #define HDI_WAKEUP_BUFFER_TIME (PA_USEC_PER_SEC * 2)
64 
65 const char *DEVICE_CLASS_REMOTE = "remote";
66 
67 struct Userdata {
68     pa_core *core;
69     pa_module *module;
70     pa_source *source;
71     pa_thread *thread;
72     pa_thread_mq thread_mq;
73     pa_rtpoll *rtpoll;
74     uint32_t buffer_size;
75     uint32_t open_mic_speaker;
76     pa_usec_t block_usec;
77     pa_usec_t timestamp;
78     SourceAttr attrs;
79     bool IsCapturerStarted;
80     struct CapturerSourceAdapter *sourceAdapter;
81     pa_usec_t delayTime;
82 };
83 
84 static int PaHdiCapturerInit(struct Userdata *u);
85 static void PaHdiCapturerExit(struct Userdata *u);
86 
GetStateInfo(pa_source_state_t state)87 static char *GetStateInfo(pa_source_state_t state)
88 {
89     switch (state) {
90         case PA_SOURCE_INVALID_STATE:
91             return "INVALID";
92         case PA_SOURCE_RUNNING:
93             return "RUNNING";
94         case PA_SOURCE_IDLE:
95             return "IDLE";
96         case PA_SOURCE_SUSPENDED:
97             return "SUSPENDED";
98         case PA_SOURCE_INIT:
99             return "INIT";
100         case PA_SOURCE_UNLINKED:
101             return "UNLINKED";
102         default:
103             return "error state";
104     }
105 }
106 
UserdataFree(struct Userdata * u)107 static void UserdataFree(struct Userdata *u)
108 {
109     if (u == NULL) {
110         AUDIO_INFO_LOG("Userdata is null, free done");
111         return;
112     }
113     if (u->source) {
114         pa_source_unlink(u->source);
115     }
116 
117     if (u->thread) {
118         pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL);
119         pa_thread_free(u->thread);
120     }
121 
122     pa_thread_mq_done(&u->thread_mq);
123 
124     if (u->source) {
125         pa_source_unref(u->source);
126     }
127 
128     if (u->rtpoll) {
129         pa_rtpoll_free(u->rtpoll);
130     }
131 
132     if (u->sourceAdapter) {
133         u->sourceAdapter->CapturerSourceStop(u->sourceAdapter->wapper);
134         u->sourceAdapter->CapturerSourceDeInit(u->sourceAdapter->wapper);
135         UnLoadSourceAdapter(u->sourceAdapter);
136     }
137 
138     pa_xfree(u);
139 }
140 
SourceProcessMsg(pa_msgobject * o,int code,void * data,int64_t offset,pa_memchunk * chunk)141 static int SourceProcessMsg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk)
142 {
143     AUTO_CTRACE("hdi_source::SourceProcessMsg code: %d", code);
144     struct Userdata *u = PA_SOURCE(o)->userdata;
145     pa_assert(u);
146 
147     switch (code) {
148         case PA_SOURCE_MESSAGE_GET_LATENCY: {
149             pa_usec_t now;
150             now = pa_rtclock_now();
151             *((int64_t*)data) = (int64_t)now - (int64_t)u->timestamp;
152             return 0;
153         }
154         default: {
155             pa_log("SourceProcessMsg default case");
156             return pa_source_process_msg(o, code, data, offset, chunk);
157         }
158     }
159 }
160 
161 /* Called from the IO thread. */
SourceSetStateInIoThreadCb(pa_source * s,pa_source_state_t newState,pa_suspend_cause_t newSuspendCause)162 static int SourceSetStateInIoThreadCb(pa_source *s, pa_source_state_t newState,
163     pa_suspend_cause_t newSuspendCause)
164 {
165     struct Userdata *u = NULL;
166     pa_assert(s);
167     pa_assert_se(u = s->userdata);
168     AUDIO_INFO_LOG("Source[%{public}s] state change:[%{public}s]-->[%{public}s]",
169         GetDeviceClass(u->sourceAdapter->deviceClass), GetStateInfo(s->thread_info.state), GetStateInfo(newState));
170 
171     if ((s->thread_info.state == PA_SOURCE_SUSPENDED || s->thread_info.state == PA_SOURCE_INIT) &&
172         PA_SOURCE_IS_OPENED(newState)) {
173         u->delayTime = 0;
174         u->timestamp = pa_rtclock_now();
175         if (u->attrs.sourceType == SOURCE_TYPE_WAKEUP) {
176             u->timestamp -= HDI_WAKEUP_BUFFER_TIME;
177         }
178         if (newState == PA_SOURCE_RUNNING && !u->IsCapturerStarted) {
179             if (u->sourceAdapter->CapturerSourceStart(u->sourceAdapter->wapper)) {
180                 AUDIO_ERR_LOG("HDI capturer start failed");
181                 return -PA_ERR_IO;
182             }
183             u->IsCapturerStarted = true;
184             AUDIO_DEBUG_LOG("Successfully started HDI capturer");
185         }
186     } else if (s->thread_info.state == PA_SOURCE_IDLE) {
187         if (newState == PA_SOURCE_SUSPENDED) {
188             if (u->IsCapturerStarted) {
189                 u->sourceAdapter->CapturerSourceStop(u->sourceAdapter->wapper);
190                 u->IsCapturerStarted = false;
191                 AUDIO_DEBUG_LOG("Stopped HDI capturer");
192             }
193         } else if (newState == PA_SOURCE_RUNNING && !u->IsCapturerStarted) {
194             AUDIO_DEBUG_LOG("Idle to Running starting HDI capturing device");
195             if (u->sourceAdapter->CapturerSourceStart(u->sourceAdapter->wapper)) {
196                 AUDIO_ERR_LOG("Idle to Running HDI capturer start failed");
197                 return -PA_ERR_IO;
198             }
199             u->IsCapturerStarted = true;
200             AUDIO_DEBUG_LOG("Idle to Running: Successfully reinitialized HDI renderer");
201         }
202     }
203 
204     return 0;
205 }
206 
GetCapturerFrameFromHdi(pa_memchunk * chunk,const struct Userdata * u)207 static int GetCapturerFrameFromHdi(pa_memchunk *chunk, const struct Userdata *u)
208 {
209     uint64_t requestBytes;
210     uint64_t replyBytes = 0;
211     void *p = NULL;
212 
213     chunk->length = u->buffer_size;
214     AUDIO_DEBUG_LOG("HDI Source: chunk.length = u->buffer_size: %{public}zu", chunk->length);
215     chunk->memblock = pa_memblock_new(u->core->mempool, chunk->length);
216     pa_assert(chunk->memblock);
217     p = pa_memblock_acquire(chunk->memblock);
218     pa_assert(p);
219 
220     requestBytes = pa_memblock_get_length(chunk->memblock);
221     u->sourceAdapter->CapturerSourceFrame(u->sourceAdapter->wapper, (char *)p, (uint64_t)requestBytes, &replyBytes);
222 
223     pa_memblock_release(chunk->memblock);
224     AUDIO_DEBUG_LOG("HDI Source: request bytes: %{public}" PRIu64 ", replyBytes: %{public}" PRIu64,
225             requestBytes, replyBytes);
226     if (replyBytes > requestBytes) {
227         AUDIO_ERR_LOG("HDI Source: Error replyBytes > requestBytes. Requested data Length: "
228                 "%{public}" PRIu64 ", Read: %{public}" PRIu64 " bytes", requestBytes, replyBytes);
229         pa_memblock_unref(chunk->memblock);
230         return 0;
231     }
232 
233     if (replyBytes == 0) {
234         AUDIO_ERR_LOG("HDI Source: Failed to read, Requested data Length: %{public}" PRIu64 " bytes,"
235                 " Read: %{public}" PRIu64 " bytes", requestBytes, replyBytes);
236         pa_memblock_unref(chunk->memblock);
237         return 0;
238     }
239 
240     chunk->index = 0;
241     chunk->length = replyBytes;
242     pa_source_post(u->source, chunk);
243     pa_memblock_unref(chunk->memblock);
244 
245     return 0;
246 }
247 
PaRtpollSetTimerFunc(struct Userdata * u,bool timerElapsed)248 static bool PaRtpollSetTimerFunc(struct Userdata *u, bool timerElapsed)
249 {
250     bool flag = (u->attrs.sourceType == SOURCE_TYPE_WAKEUP) ?
251         (u->source->thread_info.state == PA_SOURCE_RUNNING && u->IsCapturerStarted) :
252         (PA_SOURCE_IS_OPENED(u->source->thread_info.state) && u->IsCapturerStarted);
253     if (!flag) {
254         pa_rtpoll_set_timer_disabled(u->rtpoll);
255         AUDIO_DEBUG_LOG("HDI Source: pa_rtpoll_set_timer_disabled done ");
256         return true;
257     }
258     pa_memchunk chunk;
259     pa_usec_t now;
260 
261     now = pa_rtclock_now();
262     AUDIO_DEBUG_LOG("HDI Source: now: %{public}" PRIu64 " timerElapsed: %{public}d", now, timerElapsed);
263 
264     if (timerElapsed) {
265         chunk.length = pa_usec_to_bytes(now - u->timestamp, &u->source->sample_spec);
266         if (chunk.length > 0) {
267             int ret = GetCapturerFrameFromHdi(&chunk, u);
268             if (ret != 0) {
269                 return false;
270             }
271 
272             u->timestamp += pa_bytes_to_usec(chunk.length, &u->source->sample_spec);
273             AUDIO_DEBUG_LOG("HDI Source: new u->timestamp : %{public}" PRIu64, u->timestamp);
274         }
275     }
276 
277     int32_t appsUid[PA_MAX_OUTPUTS_PER_SOURCE];
278     size_t count = 0;
279     void *state = NULL;
280     pa_source_output *sourceOutput;
281     while ((sourceOutput = pa_hashmap_iterate(u->source->thread_info.outputs, &state, NULL))) {
282         const char *cstringClientUid = pa_proplist_gets(sourceOutput->proplist, "stream.client.uid");
283         if (cstringClientUid && (sourceOutput->thread_info.state == PA_SOURCE_OUTPUT_RUNNING)) {
284             appsUid[count++] = atoi(cstringClientUid);
285         }
286     }
287 
288     if (u->sourceAdapter) {
289         u->sourceAdapter->CapturerSourceAppsUid(u->sourceAdapter->wapper, appsUid, count);
290     }
291 
292     pa_usec_t costTime = pa_rtclock_now() - now;
293     if (costTime > u->block_usec) {
294         u->delayTime += (costTime - u->block_usec);
295     }
296 
297     pa_rtpoll_set_timer_absolute(u->rtpoll, u->timestamp + u->block_usec + u->delayTime);
298     return true;
299 }
300 
ThreadFuncCapturerTimer(void * userdata)301 static void ThreadFuncCapturerTimer(void *userdata)
302 {
303     struct Userdata *u = userdata;
304     bool timerElapsed = false;
305 
306     //set audio thread priority
307     ScheduleThreadInServer(getpid(), gettid());
308     pa_assert(u);
309 
310     pa_thread_mq_install(&u->thread_mq);
311     u->timestamp = pa_rtclock_now();
312 
313     if (u->attrs.sourceType == SOURCE_TYPE_WAKEUP) {
314         u->timestamp -= HDI_WAKEUP_BUFFER_TIME;
315     }
316 
317     AUDIO_DEBUG_LOG("HDI Source: u->timestamp : %{public}" PRIu64, u->timestamp);
318 
319     while (true) {
320         AUTO_CTRACE("FuncCapturerLoop");
321         bool result = PaRtpollSetTimerFunc(u, timerElapsed);
322         if (!result) {
323             AUDIO_ERR_LOG("PaRtpollSetTimerFunc failed");
324             break;
325         }
326         /* Hmm, nothing to do. Let's sleep */
327         int ret = pa_rtpoll_run(u->rtpoll);
328         if (ret < 0) {
329             /* If this was no regular exit from the loop we have to continue
330             * processing messages until we received PA_MESSAGE_SHUTDOWN */
331             AUDIO_ERR_LOG("HDI Source: pa_rtpoll_run ret:%{public}d failed", ret);
332             pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module,
333                 0, NULL, NULL);
334             pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN);
335             return;
336         }
337 
338         timerElapsed = pa_rtpoll_timer_elapsed(u->rtpoll);
339 
340         if (ret == 0) {
341             AUDIO_INFO_LOG("Thread OS_ReadHdi shutting down, pid %{public}d, tid %{public}d", getpid(), gettid());
342             return;
343         }
344     }
345     UnscheduleThreadInServer(getpid(), gettid());
346 }
347 
PaHdiCapturerInit(struct Userdata * u)348 static int PaHdiCapturerInit(struct Userdata *u)
349 {
350     int ret;
351     ret = u->sourceAdapter->CapturerSourceInit(u->sourceAdapter->wapper, &u->attrs);
352     if (ret != 0) {
353         AUDIO_ERR_LOG("Audio capturer init failed!");
354         return ret;
355     }
356 
357     // No start test for remote device.
358     if (strcmp(GetDeviceClass(u->sourceAdapter->deviceClass), DEVICE_CLASS_REMOTE)) {
359         ret = u->sourceAdapter->CapturerSourceStart(u->sourceAdapter->wapper);
360         if (ret != 0) {
361             AUDIO_ERR_LOG("Audio capturer start failed!");
362             goto fail;
363         }
364     }
365 
366     u->IsCapturerStarted = true;
367     return ret;
368 
369 fail:
370     PaHdiCapturerExit(u);
371     return ret;
372 }
373 
PaHdiCapturerExit(struct Userdata * u)374 static void PaHdiCapturerExit(struct Userdata *u)
375 {
376     u->sourceAdapter->CapturerSourceStop(u->sourceAdapter->wapper);
377     u->sourceAdapter->CapturerSourceDeInit(u->sourceAdapter->wapper);
378 }
379 
PaSetSourceProperties(pa_module * m,pa_modargs * ma,const pa_sample_spec * ss,const pa_channel_map * map,struct Userdata * u)380 static int PaSetSourceProperties(pa_module *m, pa_modargs *ma, const pa_sample_spec *ss, const pa_channel_map *map,
381     struct Userdata *u)
382 {
383     pa_source_new_data data;
384 
385     pa_source_new_data_init(&data);
386     data.driver = __FILE__;
387     data.module = m;
388 
389     //if sourcetype is wakeup, source suspend after init
390     if (u->attrs.sourceType == SOURCE_TYPE_WAKEUP) {
391         data.suspend_cause = PA_SUSPEND_IDLE;
392     }
393 
394     pa_source_new_data_set_name(&data, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME));
395     pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING,
396         (u->attrs.adapterName ? u->attrs.adapterName : DEFAULT_AUDIO_DEVICE_NAME));
397     pa_proplist_setf(data.proplist, PA_PROP_DEVICE_DESCRIPTION, "HDI source is %s",
398         (u->attrs.adapterName ? u->attrs.adapterName : DEFAULT_AUDIO_DEVICE_NAME));
399     pa_source_new_data_set_sample_spec(&data, ss);
400     pa_source_new_data_set_channel_map(&data, map);
401     pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%lu", (unsigned long)u->buffer_size);
402 
403     // set suspend on idle timeout to 0s
404     pa_proplist_setf(data.proplist, "module-suspend-on-idle.timeout", "%d", 0);
405 
406     if (pa_modargs_get_proplist(ma, "source_properties", data.proplist, PA_UPDATE_REPLACE) < 0) {
407         AUDIO_ERR_LOG("Invalid properties");
408         pa_source_new_data_done(&data);
409         return -1;
410     }
411 
412     u->source = pa_source_new(m->core, &data, PA_SOURCE_HARDWARE | PA_SOURCE_LATENCY | PA_SOURCE_DYNAMIC_LATENCY);
413     pa_source_new_data_done(&data);
414 
415     if (!u->source) {
416         AUDIO_ERR_LOG("Failed to create source object");
417         return -1;
418     }
419 
420     u->source->parent.process_msg = SourceProcessMsg;
421     u->source->set_state_in_io_thread = SourceSetStateInIoThreadCb;
422     u->source->userdata = u;
423 
424     pa_source_set_asyncmsgq(u->source, u->thread_mq.inq);
425     pa_source_set_rtpoll(u->source, u->rtpoll);
426 
427     u->block_usec = pa_bytes_to_usec(u->buffer_size, &u->source->sample_spec);
428     pa_source_set_latency_range(u->source, 0, u->block_usec);
429     u->source->thread_info.max_rewind = pa_usec_to_bytes(u->block_usec, &u->source->sample_spec);
430 
431     return 0;
432 }
433 
ConvertPaToHdiAdapterFormat(pa_sample_format_t format)434 static enum HdiAdapterFormat ConvertPaToHdiAdapterFormat(pa_sample_format_t format)
435 {
436     enum HdiAdapterFormat adapterFormat;
437     switch (format) {
438         case PA_SAMPLE_U8:
439             adapterFormat = SAMPLE_U8;
440             break;
441         case PA_SAMPLE_S16LE:
442         case PA_SAMPLE_S16BE:
443             adapterFormat = SAMPLE_S16;
444             break;
445         case PA_SAMPLE_S24LE:
446         case PA_SAMPLE_S24BE:
447             adapterFormat = SAMPLE_S24;
448             break;
449         case PA_SAMPLE_S32LE:
450         case PA_SAMPLE_S32BE:
451             adapterFormat = SAMPLE_S32;
452             break;
453         default:
454             adapterFormat = SAMPLE_S16;
455             break;
456     }
457 
458     return adapterFormat;
459 }
460 
GetEndianInfo(pa_sample_format_t format)461 static bool GetEndianInfo(pa_sample_format_t format)
462 {
463     bool isBigEndian = false;
464     switch (format) {
465         case PA_SAMPLE_S16BE:
466         case PA_SAMPLE_S24BE:
467         case PA_SAMPLE_S32BE:
468         case PA_SAMPLE_FLOAT32BE:
469         case PA_SAMPLE_S24_32BE:
470             isBigEndian = true;
471             break;
472         default:
473             isBigEndian = false;
474             break;
475     }
476 
477     return isBigEndian;
478 }
479 
InitUserdataAttrs(pa_modargs * ma,struct Userdata * u,const pa_sample_spec * ss)480 static void InitUserdataAttrs(pa_modargs *ma, struct Userdata *u, const pa_sample_spec *ss)
481 {
482     if (pa_modargs_get_value_s32(ma, "source_type", &u->attrs.sourceType) < 0) {
483         AUDIO_ERR_LOG("Failed to parse source_type argument");
484     }
485 
486     if (pa_modargs_get_value_u32(ma, "buffer_size", &u->buffer_size) < 0) {
487         AUDIO_ERR_LOG("Failed to parse buffer_size argument.");
488         u->buffer_size = DEFAULT_BUFFER_SIZE;
489     }
490     u->attrs.bufferSize = u->buffer_size;
491 
492     u->attrs.sampleRate = ss->rate;
493     u->attrs.filePath = pa_modargs_get_value(ma, "file_path", "");
494     if (pa_modargs_get_value_u32(ma, "open_mic_speaker", &u->open_mic_speaker) < 0) {
495         AUDIO_ERR_LOG("Failed to parse open_mic_speaker argument");
496     }
497     u->attrs.channel = ss->channels;
498     u->attrs.format = ConvertPaToHdiAdapterFormat(ss->format);
499     u->attrs.isBigEndian = GetEndianInfo(ss->format);
500     u->attrs.adapterName = pa_modargs_get_value(ma, "adapter_name", DEFAULT_DEVICE_CLASS);
501     u->attrs.deviceNetworkId = pa_modargs_get_value(ma, "network_id", DEFAULT_DEVICE_NETWORKID);
502     if (pa_modargs_get_value_s32(ma, "device_type", &u->attrs.deviceType) < 0) {
503         AUDIO_ERR_LOG("Failed to parse deviceType argument");
504     }
505 
506     AUDIO_DEBUG_LOG("AudioDeviceCreateCapture format: %{public}d, isBigEndian: %{public}d channel: %{public}d,"
507         "sampleRate: %{public}d", u->attrs.format, u->attrs.isBigEndian, u->attrs.channel, u->attrs.sampleRate);
508 
509     u->attrs.openMicSpeaker = u->open_mic_speaker;
510 }
511 
PaHdiSourceNew(pa_module * m,pa_modargs * ma,const char * driver)512 pa_source *PaHdiSourceNew(pa_module *m, pa_modargs *ma, const char *driver)
513 {
514     int ret;
515 
516     pa_assert(m);
517     pa_assert(ma);
518 
519     pa_sample_spec ss = m->core->default_sample_spec;
520     pa_channel_map map = m->core->default_channel_map;
521 
522     /* Override with modargs if provided */
523     if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
524         AUDIO_ERR_LOG("Failed to parse sample specification and channel map");
525         return NULL;
526     }
527 
528     struct Userdata *u = pa_xnew0(struct Userdata, 1);
529 
530     u->core = m->core;
531     u->module = m;
532     u->rtpoll = pa_rtpoll_new();
533 
534     if (pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll) < 0) {
535         AUDIO_ERR_LOG("pa_thread_mq_init() failed.");
536         goto fail;
537     }
538 
539     InitUserdataAttrs(ma, u, &ss);
540 
541     ret = LoadSourceAdapter(pa_modargs_get_value(ma, "device_class", DEFAULT_DEVICE_CLASS),
542         pa_modargs_get_value(ma, "network_id", DEFAULT_DEVICE_NETWORKID), u->attrs.sourceType,
543         pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), &u->sourceAdapter);
544     if (ret) {
545         AUDIO_ERR_LOG("Load adapter failed");
546         goto fail;
547     }
548 
549     if (PaSetSourceProperties(m, ma, &ss, &map, u) != 0) {
550         AUDIO_ERR_LOG("Failed to PaSetSourceProperties");
551         goto fail;
552     }
553 
554     if (PaHdiCapturerInit(u) != 0) {
555         AUDIO_ERR_LOG("Failed to PaHdiCapturerInit");
556         goto fail;
557     }
558 
559     if (!(u->thread = pa_thread_new("OS_ReadHdi", ThreadFuncCapturerTimer, u))) {
560         AUDIO_ERR_LOG("Failed to create hdi-source-record thread!");
561         goto fail;
562     }
563 
564     pa_source_put(u->source);
565     return u->source;
566 
567 fail:
568 
569     if (u->IsCapturerStarted) {
570         PaHdiCapturerExit(u);
571     }
572     UserdataFree(u);
573 
574     return NULL;
575 }
576 
PaHdiSourceFree(pa_source * s)577 void PaHdiSourceFree(pa_source *s)
578 {
579     AUTO_CTRACE("PaHdiSourceFree");
580     struct Userdata *u = NULL;
581     pa_source_assert_ref(s);
582     pa_assert_se(u = s->userdata);
583     UserdataFree(u);
584 }
585