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