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
16 #include <config.h>
17 #include <pulse/rtclock.h>
18 #include <pulse/timeval.h>
19 #include <pulse/xmalloc.h>
20 #include <pulsecore/log.h>
21 #include <pulsecore/modargs.h>
22 #include <pulsecore/module.h>
23 #include <pulsecore/rtpoll.h>
24 #include <pulsecore/sink.h>
25 #include <pulsecore/thread-mq.h>
26 #include <pulsecore/thread.h>
27
28 #include <stddef.h>
29 #include <stdint.h>
30 #include <stdbool.h>
31 #include <string.h>
32 #include <inttypes.h>
33 #include <sys/types.h>
34
35 #include "audio_log.h"
36 #include "audio_schedule.h"
37 #include "renderer_sink_adapter.h"
38
39 #define DEFAULT_SINK_NAME "hdi_output"
40 #define DEFAULT_AUDIO_DEVICE_NAME "Speaker"
41 #define DEFAULT_DEVICE_CLASS "primary"
42 #define DEFAULT_DEVICE_NETWORKID "LocalDevice"
43 #define DEFAULT_BUFFER_SIZE 8192
44 #define MAX_SINK_VOLUME_LEVEL 1.0
45 #define DEFAULT_WRITE_TIME 1000
46
47 const char *DEVICE_CLASS_A2DP = "a2dp";
48 const char *DEVICE_CLASS_REMOTE = "remote";
49
50 enum {
51 HDI_INIT,
52 HDI_DEINIT,
53 HDI_START,
54 HDI_STOP,
55 HDI_RENDER,
56 QUIT
57 };
58
59 struct Userdata {
60 const char *adapterName;
61 uint32_t buffer_size;
62 uint32_t fixed_latency;
63 uint32_t sink_latency;
64 uint32_t render_in_idle_state;
65 uint32_t open_mic_speaker;
66 const char *deviceNetworkId;
67 int32_t deviceType;
68 size_t bytes_dropped;
69 pa_thread_mq thread_mq;
70 pa_memchunk memchunk;
71 pa_usec_t block_usec;
72 pa_usec_t timestamp;
73 pa_thread *thread;
74 pa_thread *thread_hdi;
75 pa_rtpoll *rtpoll;
76 pa_core *core;
77 pa_module *module;
78 pa_sink *sink;
79 pa_sample_spec ss;
80 pa_channel_map map;
81 bool isHDISinkStarted;
82 struct RendererSinkAdapter *sinkAdapter;
83 pa_asyncmsgq *dq;
84 pa_atomic_t dflag;
85 bool test_mode_on;
86 uint32_t writeCount;
87 uint32_t renderCount;
88 pa_usec_t writeTime;
89 };
90
91 static void UserdataFree(struct Userdata *u);
92 static int32_t PrepareDevice(struct Userdata *u, const char* filePath);
93
RenderWrite(struct Userdata * u,pa_memchunk * pchunk)94 static ssize_t RenderWrite(struct Userdata *u, pa_memchunk *pchunk)
95 {
96 size_t index, length;
97 ssize_t count = 0;
98 void *p = NULL;
99
100 pa_assert(pchunk);
101
102 index = pchunk->index;
103 length = pchunk->length;
104 p = pa_memblock_acquire(pchunk->memblock);
105 pa_assert(p);
106
107 while (true) {
108 uint64_t writeLen = 0;
109
110 int32_t ret = u->sinkAdapter->RendererRenderFrame(u->sinkAdapter, ((char *)p + index),
111 (uint64_t)length, &writeLen);
112 if (writeLen > length) {
113 AUDIO_ERR_LOG("Error writeLen > actual bytes. Length: %zu, Written: %" PRIu64 " bytes, %d ret",
114 length, writeLen, ret);
115 count = -1 - count;
116 break;
117 }
118 if (writeLen == 0) {
119 AUDIO_ERR_LOG("Failed to render Length: %{public}zu, Written: %{public}" PRIu64 " bytes, %{public}d ret",
120 length, writeLen, ret);
121 count = -1 - count;
122 break;
123 } else {
124 count += writeLen;
125 index += writeLen;
126 length -= writeLen;
127 if (length <= 0) {
128 break;
129 }
130 }
131 }
132 pa_memblock_release(pchunk->memblock);
133 pa_memblock_unref(pchunk->memblock);
134
135 return count;
136 }
137
TestModeRenderWrite(struct Userdata * u,pa_memchunk * pchunk)138 static ssize_t TestModeRenderWrite(struct Userdata *u, pa_memchunk *pchunk)
139 {
140 size_t index, length;
141 ssize_t count = 0;
142 void *p = NULL;
143
144 pa_assert(pchunk);
145
146 index = pchunk->index;
147 length = pchunk->length;
148 p = pa_memblock_acquire(pchunk->memblock);
149 pa_assert(p);
150
151 if (*((int*)p) > 0) {
152 AUDIO_DEBUG_LOG("RenderWrite Write: %{public}d", ++u->writeCount);
153 }
154 AUDIO_DEBUG_LOG("RenderWrite Write renderCount: %{public}d", ++u->renderCount);
155
156 while (true) {
157 uint64_t writeLen = 0;
158
159 int32_t ret = u->sinkAdapter->RendererRenderFrame(u->sinkAdapter, ((char *)p + index),
160 (uint64_t)length, &writeLen);
161 if (writeLen > length) {
162 AUDIO_ERR_LOG("Error writeLen > actual bytes. Length: %zu, Written: %" PRIu64 " bytes, %d ret",
163 length, writeLen, ret);
164 count = -1 - count;
165 break;
166 }
167 if (writeLen == 0) {
168 AUDIO_ERR_LOG("Failed to render Length: %zu, Written: %" PRIu64 " bytes, %d ret",
169 length, writeLen, ret);
170 count = -1 - count;
171 break;
172 } else {
173 count += writeLen;
174 index += writeLen;
175 length -= writeLen;
176 if (length <= 0) {
177 break;
178 }
179 }
180 }
181 pa_memblock_release(pchunk->memblock);
182 pa_memblock_unref(pchunk->memblock);
183
184 return count;
185 }
186
ProcessRenderUseTiming(struct Userdata * u,pa_usec_t now)187 static void ProcessRenderUseTiming(struct Userdata *u, pa_usec_t now)
188 {
189 pa_assert(u);
190
191 // Fill the buffer up the latency size
192 pa_memchunk chunk;
193
194 // Change from pa_sink_render to pa_sink_render_full for alignment issue in 3516
195 pa_sink_render_full(u->sink, u->sink->thread_info.max_request, &chunk);
196 pa_assert(chunk.length > 0);
197
198 pa_asyncmsgq_post(u->dq, NULL, HDI_RENDER, NULL, 0, &chunk, NULL);
199 u->timestamp += pa_bytes_to_usec(chunk.length, &u->sink->sample_spec);
200 }
201
ThreadFuncRendererTimer(void * userdata)202 static void ThreadFuncRendererTimer(void *userdata)
203 {
204 // set audio thread priority
205 ScheduleReportData(getpid(), gettid(), "pulseaudio");
206
207 struct Userdata *u = userdata;
208
209 pa_assert(u);
210
211 pa_thread_mq_install(&u->thread_mq);
212
213 u->timestamp = pa_rtclock_now();
214
215 while (true) {
216 pa_usec_t now = 0;
217 int ret;
218
219 bool flag = (u->render_in_idle_state && PA_SINK_IS_OPENED(u->sink->thread_info.state)) ||
220 (!u->render_in_idle_state && PA_SINK_IS_RUNNING(u->sink->thread_info.state));
221 if (flag) {
222 now = pa_rtclock_now();
223 }
224
225 if (PA_UNLIKELY(u->sink->thread_info.rewind_requested)) {
226 pa_sink_process_rewind(u->sink, 0);
227 }
228
229 if (flag) {
230 if (u->timestamp <= now && pa_atomic_load(&u->dflag) == 0) {
231 pa_atomic_add(&u->dflag, 1);
232 ProcessRenderUseTiming(u, now);
233 }
234 pa_usec_t blockTime = pa_bytes_to_usec(u->sink->thread_info.max_request, &u->sink->sample_spec);
235 int64_t sleepForUsec = PA_MIN(blockTime - (pa_rtclock_now() - now), u->writeTime);
236 sleepForUsec = PA_MAX(sleepForUsec, 0);
237 pa_rtpoll_set_timer_relative(u->rtpoll, (pa_usec_t)sleepForUsec);
238 } else {
239 pa_rtpoll_set_timer_disabled(u->rtpoll);
240 }
241
242 // Hmm, nothing to do. Let's sleep
243 if ((ret = pa_rtpoll_run(u->rtpoll)) < 0) {
244 // If this was no regular exit from the loop we have to continue
245 // processing messages until we received PA_MESSAGE_SHUTDOWN
246 pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE,
247 u->module, 0, NULL, NULL);
248 pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN);
249 break;
250 }
251
252 if (ret == 0) {
253 AUDIO_INFO_LOG("Thread (use timing) shutting down");
254 break;
255 }
256 }
257 }
258
ThreadFuncWriteHDI(void * userdata)259 static void ThreadFuncWriteHDI(void *userdata)
260 {
261 // set audio thread priority
262 ScheduleReportData(getpid(), gettid(), "pulseaudio");
263
264 struct Userdata *u = userdata;
265 pa_assert(u);
266
267 int quit = 0;
268
269 do {
270 int code = 0;
271 pa_memchunk chunk;
272
273 pa_assert_se(pa_asyncmsgq_get(u->dq, NULL, &code, NULL, NULL, &chunk, 1) == 0);
274
275 switch (code) {
276 case HDI_RENDER: {
277 pa_usec_t now = pa_rtclock_now();
278 if (RenderWrite(u, &chunk) < 0) {
279 u->bytes_dropped += chunk.length;
280 AUDIO_ERR_LOG("RenderWrite failed");
281 }
282 if (pa_atomic_load(&u->dflag) == 1) {
283 pa_atomic_sub(&u->dflag, 1);
284 }
285 u->writeTime = pa_rtclock_now() - now;
286 break;
287 }
288 case QUIT:
289 quit = 1;
290 break;
291 default:
292 break;
293 }
294 pa_asyncmsgq_done(u->dq, 0);
295 } while (!quit);
296 }
297
TestModeThreadFuncWriteHDI(void * userdata)298 static void TestModeThreadFuncWriteHDI(void *userdata)
299 {
300 // set audio thread priority
301 ScheduleReportData(getpid(), gettid(), "pulseaudio");
302
303 struct Userdata *u = userdata;
304 pa_assert(u);
305
306 int quit = 0;
307
308 do {
309 int code = 0;
310 pa_memchunk chunk;
311
312 pa_assert_se(pa_asyncmsgq_get(u->dq, NULL, &code, NULL, NULL, &chunk, 1) == 0);
313
314 switch (code) {
315 case HDI_RENDER:
316 if (TestModeRenderWrite(u, &chunk) < 0) {
317 u->bytes_dropped += chunk.length;
318 AUDIO_ERR_LOG("TestModeRenderWrite failed");
319 }
320 if (pa_atomic_load(&u->dflag) == 1) {
321 pa_atomic_sub(&u->dflag, 1);
322 }
323 break;
324 case QUIT:
325 quit = 1;
326 break;
327 default:
328 break;
329 }
330 pa_asyncmsgq_done(u->dq, 0);
331 } while (!quit);
332 }
333
SinkUpdateRequestedLatencyCb(pa_sink * s)334 static void SinkUpdateRequestedLatencyCb(pa_sink *s)
335 {
336 struct Userdata *u = NULL;
337 size_t nbytes;
338
339 pa_sink_assert_ref(s);
340 pa_assert_se(u = s->userdata);
341
342 u->block_usec = pa_sink_get_requested_latency_within_thread(s);
343
344 if (u->block_usec == (pa_usec_t) - 1)
345 u->block_usec = s->thread_info.max_latency;
346
347 nbytes = pa_usec_to_bytes(u->block_usec, &s->sample_spec);
348 pa_sink_set_max_request_within_thread(s, nbytes);
349 }
350
SinkProcessMsg(pa_msgobject * o,int code,void * data,int64_t offset,pa_memchunk * chunk)351 static int SinkProcessMsg(pa_msgobject *o, int code, void *data, int64_t offset,
352 pa_memchunk *chunk)
353 {
354 AUDIO_DEBUG_LOG("SinkProcessMsg: code: %{public}d", code);
355 struct Userdata *u = PA_SINK(o)->userdata;
356 pa_assert(u);
357
358 switch (code) {
359 case PA_SINK_MESSAGE_GET_LATENCY: {
360 if (u->sink_latency) {
361 *((uint64_t *)data) = u->sink_latency * PA_USEC_PER_MSEC;
362 } else {
363 uint64_t latency;
364 uint32_t hdiLatency;
365
366 // Tries to fetch latency from HDI else will make an estimate based
367 // on samples to be rendered based on the timestamp and current time
368 if (u->sinkAdapter->RendererSinkGetLatency(u->sinkAdapter, &hdiLatency) == 0) {
369 latency = (PA_USEC_PER_MSEC * hdiLatency);
370 } else {
371 pa_usec_t now = pa_rtclock_now();
372 latency = (now - u->timestamp);
373 }
374
375 *((uint64_t *)data) = latency;
376 }
377 return 0;
378 }
379 default:
380 break;
381 }
382 return pa_sink_process_msg(o, code, data, offset, chunk);
383 }
384
GetStateInfo(pa_sink_state_t state)385 static char *GetStateInfo(pa_sink_state_t state)
386 {
387 switch (state) {
388 case PA_SINK_INVALID_STATE:
389 return "INVALID";
390 case PA_SINK_RUNNING:
391 return "RUNNING";
392 case PA_SINK_IDLE:
393 return "IDLE";
394 case PA_SINK_SUSPENDED:
395 return "SUSPENDED";
396 case PA_SINK_INIT:
397 return "INIT";
398 case PA_SINK_UNLINKED:
399 return "UNLINKED";
400 default:
401 return "error state";
402 }
403 }
404
RemoteSinkStateChange(pa_sink * s,pa_sink_state_t newState)405 static int RemoteSinkStateChange(pa_sink *s, pa_sink_state_t newState)
406 {
407 struct Userdata *u = s->userdata;
408 if (s->thread_info.state == PA_SINK_INIT && newState == PA_SINK_IDLE) {
409 AUDIO_INFO_LOG("First start.");
410 }
411
412 if (s->thread_info.state == PA_SINK_SUSPENDED && PA_SINK_IS_OPENED(newState)) {
413 u->timestamp = pa_rtclock_now();
414 if (u->isHDISinkStarted) {
415 return 0;
416 }
417
418 if (u->sinkAdapter->RendererSinkStart(u->sinkAdapter)) {
419 AUDIO_ERR_LOG("audiorenderer control start failed!");
420 } else {
421 u->isHDISinkStarted = true;
422 u->render_in_idle_state = 1; // enable to reduce noise from idle to running.
423 u->writeCount = 0;
424 u->renderCount = 0;
425 AUDIO_INFO_LOG("Successfully restarted remote renderer");
426 }
427 }
428 if (PA_SINK_IS_OPENED(s->thread_info.state) && newState == PA_SINK_SUSPENDED) {
429 // Continuously dropping data (clear counter on entering suspended state.
430 if (u->bytes_dropped != 0) {
431 AUDIO_INFO_LOG("HDI-sink continuously dropping data - clear statistics (%zu -> 0 bytes dropped)",
432 u->bytes_dropped);
433 u->bytes_dropped = 0;
434 }
435
436 if (u->isHDISinkStarted) {
437 u->sinkAdapter->RendererSinkStop(u->sinkAdapter);
438 AUDIO_INFO_LOG("Stopped HDI renderer");
439 u->isHDISinkStarted = false;
440 }
441 }
442
443 return 0;
444 }
445
446 // Called from the IO thread.
SinkSetStateInIoThreadCb(pa_sink * s,pa_sink_state_t newState,pa_suspend_cause_t newSuspendCause)447 static int SinkSetStateInIoThreadCb(pa_sink *s, pa_sink_state_t newState,
448 pa_suspend_cause_t newSuspendCause)
449 {
450 struct Userdata *u = NULL;
451
452 pa_assert(s);
453 pa_assert_se(u = s->userdata);
454
455 AUDIO_INFO_LOG("Sink[%{public}s] state change:[%{public}s]-->[%{public}s]",
456 GetDeviceClass(u->sinkAdapter->deviceClass), GetStateInfo(s->thread_info.state), GetStateInfo(newState));
457
458 if (!strcmp(GetDeviceClass(u->sinkAdapter->deviceClass), DEVICE_CLASS_REMOTE)) {
459 return RemoteSinkStateChange(s, newState);
460 }
461
462 if (!strcmp(GetDeviceClass(u->sinkAdapter->deviceClass), DEVICE_CLASS_A2DP)) {
463 if (s->thread_info.state == PA_SINK_IDLE && newState == PA_SINK_RUNNING) {
464 u->sinkAdapter->RendererSinkResume(u->sinkAdapter);
465 } else if (s->thread_info.state == PA_SINK_RUNNING && newState == PA_SINK_IDLE) {
466 u->sinkAdapter->RendererSinkPause(u->sinkAdapter);
467 }
468 }
469
470 if (s->thread_info.state == PA_SINK_SUSPENDED || s->thread_info.state == PA_SINK_INIT) {
471 if (!PA_SINK_IS_OPENED(newState)) {
472 return 0;
473 }
474
475 u->timestamp = pa_rtclock_now();
476 if (u->isHDISinkStarted) {
477 return 0;
478 }
479
480 AUDIO_INFO_LOG("Restart with rate:%{public}d,channels:%{public}d", u->ss.rate, u->ss.channels);
481 if (u->sinkAdapter->RendererSinkStart(u->sinkAdapter)) {
482 AUDIO_ERR_LOG("audiorenderer control start failed!");
483 u->sinkAdapter->RendererSinkDeInit(u->sinkAdapter);
484 } else {
485 u->isHDISinkStarted = true;
486 u->writeCount = 0;
487 u->renderCount = 0;
488 AUDIO_INFO_LOG("Successfully restarted HDI renderer");
489 }
490 } else if (PA_SINK_IS_OPENED(s->thread_info.state)) {
491 if (newState != PA_SINK_SUSPENDED) {
492 return 0;
493 }
494 // Continuously dropping data (clear counter on entering suspended state.
495 if (u->bytes_dropped != 0) {
496 AUDIO_INFO_LOG("HDI-sink continuously dropping data - clear statistics (%zu -> 0 bytes dropped)",
497 u->bytes_dropped);
498 u->bytes_dropped = 0;
499 }
500
501 if (u->isHDISinkStarted) {
502 u->sinkAdapter->RendererSinkStop(u->sinkAdapter);
503 AUDIO_INFO_LOG("Stopped HDI renderer");
504 u->isHDISinkStarted = false;
505 }
506 }
507
508 return 0;
509 }
510
ConvertToFwkFormat(pa_sample_format_t format)511 static enum SampleFormat ConvertToFwkFormat(pa_sample_format_t format)
512 {
513 enum SampleFormat fwkFormat;
514 switch (format) {
515 case PA_SAMPLE_U8:
516 fwkFormat = SAMPLE_U8;
517 break;
518 case PA_SAMPLE_S16LE:
519 fwkFormat = SAMPLE_S16LE;
520 break;
521 case PA_SAMPLE_S24LE:
522 fwkFormat = SAMPLE_S24LE;
523 break;
524 case PA_SAMPLE_S32LE:
525 fwkFormat = SAMPLE_S32LE;
526 break;
527 default:
528 fwkFormat = INVALID_WIDTH;
529 break;
530 }
531
532 return fwkFormat;
533 }
534
PrepareDevice(struct Userdata * u,const char * filePath)535 static int32_t PrepareDevice(struct Userdata *u, const char* filePath)
536 {
537 SinkAttr sample_attrs;
538 int32_t ret;
539
540 enum SampleFormat format = ConvertToFwkFormat(u->ss.format);
541 sample_attrs.format = format;
542 sample_attrs.sampleFmt = format;
543 AUDIO_DEBUG_LOG("audiorenderer format: %d", sample_attrs.format);
544 sample_attrs.adapterName = u->adapterName;
545 sample_attrs.openMicSpeaker = u->open_mic_speaker;
546 sample_attrs.sampleRate = u->ss.rate;
547 sample_attrs.channel = u->ss.channels;
548 sample_attrs.volume = MAX_SINK_VOLUME_LEVEL;
549 sample_attrs.filePath = filePath;
550 sample_attrs.deviceNetworkId = u->deviceNetworkId;
551 sample_attrs.deviceType = u->deviceType;
552
553 ret = u->sinkAdapter->RendererSinkInit(u->sinkAdapter, &sample_attrs);
554 if (ret != 0) {
555 AUDIO_ERR_LOG("audiorenderer Init failed!");
556 return -1;
557 }
558
559 // call start in io thread for remote device.
560 if (strcmp(GetDeviceClass(u->sinkAdapter->deviceClass), DEVICE_CLASS_REMOTE)) {
561 ret = u->sinkAdapter->RendererSinkStart(u->sinkAdapter);
562 }
563
564 if (ret != 0) {
565 AUDIO_ERR_LOG("audiorenderer control start failed!");
566 u->sinkAdapter->RendererSinkDeInit(u->sinkAdapter);
567 return -1;
568 }
569
570 return 0;
571 }
572
PaHdiSinkInit(struct Userdata * u,pa_modargs * ma,const char * driver)573 static pa_sink* PaHdiSinkInit(struct Userdata *u, pa_modargs *ma, const char *driver)
574 {
575 // set audio thread priority
576 ScheduleReportData(getpid(), gettid(), "pulseaudio");
577
578 pa_sink_new_data data;
579 pa_module *m;
580 pa_sink *sink = NULL;
581
582 m = u->module;
583 u->ss = m->core->default_sample_spec;
584 u->map = m->core->default_channel_map;
585 if (pa_modargs_get_sample_spec_and_channel_map(ma, &u->ss, &u->map, PA_CHANNEL_MAP_DEFAULT) < 0) {
586 AUDIO_ERR_LOG("Failed to parse sample specification and channel map");
587 goto fail;
588 }
589
590 AUDIO_INFO_LOG("Initializing HDI rendering device with rate: %{public}d, channels: %{public}d",
591 u->ss.rate, u->ss.channels);
592 if (PrepareDevice(u, pa_modargs_get_value(ma, "file_path", "")) < 0)
593 goto fail;
594
595 u->isHDISinkStarted = true;
596 AUDIO_DEBUG_LOG("Initialization of HDI rendering device[%{public}s] completed", u->adapterName);
597 pa_sink_new_data_init(&data);
598 data.driver = driver;
599 data.module = m;
600
601 pa_sink_new_data_set_name(&data, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME));
602 pa_sink_new_data_set_sample_spec(&data, &u->ss);
603 pa_sink_new_data_set_channel_map(&data, &u->map);
604 pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING,
605 (u->adapterName ? u->adapterName : DEFAULT_AUDIO_DEVICE_NAME));
606 pa_proplist_setf(data.proplist, PA_PROP_DEVICE_DESCRIPTION, "HDI sink is %s",
607 (u->adapterName ? u->adapterName : DEFAULT_AUDIO_DEVICE_NAME));
608
609 if (pa_modargs_get_proplist(ma, "sink_properties", data.proplist, PA_UPDATE_REPLACE) < 0) {
610 AUDIO_ERR_LOG("Invalid properties");
611 pa_sink_new_data_done(&data);
612 goto fail;
613 }
614
615 sink = pa_sink_new(m->core, &data,
616 PA_SINK_HARDWARE | PA_SINK_LATENCY | PA_SINK_DYNAMIC_LATENCY);
617 pa_sink_new_data_done(&data);
618
619 return sink;
620
621 fail:
622 return NULL;
623 }
624
PaHdiSinkNew(pa_module * m,pa_modargs * ma,const char * driver)625 pa_sink *PaHdiSinkNew(pa_module *m, pa_modargs *ma, const char *driver)
626 {
627 struct Userdata *u = NULL;
628 char *paThreadName = NULL;
629 char *hdiThreadName = NULL;
630
631 pa_assert(m);
632 pa_assert(ma);
633
634 u = pa_xnew0(struct Userdata, 1);
635 pa_assert(u);
636 u->core = m->core;
637 u->module = m;
638
639 pa_memchunk_reset(&u->memchunk);
640 u->rtpoll = pa_rtpoll_new();
641
642 if (pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll) < 0) {
643 AUDIO_ERR_LOG("pa_thread_mq_init() failed.");
644 goto fail;
645 }
646
647 AUDIO_DEBUG_LOG("Load sink adapter");
648 int32_t ret = LoadSinkAdapter(pa_modargs_get_value(ma, "device_class", DEFAULT_DEVICE_CLASS),
649 pa_modargs_get_value(ma, "network_id", DEFAULT_DEVICE_NETWORKID), &u->sinkAdapter);
650 if (ret) {
651 AUDIO_ERR_LOG("Load adapter failed");
652 goto fail;
653 }
654 if (pa_modargs_get_value_u32(ma, "fixed_latency", &u->fixed_latency) < 0) {
655 AUDIO_ERR_LOG("Failed to parse fixed latency argument.");
656 goto fail;
657 }
658 if (pa_modargs_get_value_s32(ma, "device_type", &u->deviceType) < 0) {
659 AUDIO_ERR_LOG("Failed to parse deviceType argument.");
660 goto fail;
661 }
662
663 u->adapterName = pa_modargs_get_value(ma, "adapter_name", DEFAULT_DEVICE_CLASS);
664 u->sink_latency = 0;
665 if (pa_modargs_get_value_u32(ma, "sink_latency", &u->sink_latency) < 0) {
666 AUDIO_ERR_LOG("No sink_latency argument.");
667 }
668
669 u->deviceNetworkId = pa_modargs_get_value(ma, "network_id", DEFAULT_DEVICE_NETWORKID);
670
671 if (pa_modargs_get_value_u32(ma, "render_in_idle_state", &u->render_in_idle_state) < 0) {
672 AUDIO_ERR_LOG("Failed to parse render_in_idle_state argument.");
673 goto fail;
674 }
675
676 if (pa_modargs_get_value_u32(ma, "open_mic_speaker", &u->open_mic_speaker) < 0) {
677 AUDIO_ERR_LOG("Failed to parse open_mic_speaker argument.");
678 goto fail;
679 }
680
681 u->test_mode_on = false;
682 if (pa_modargs_get_value_boolean(ma, "test_mode_on", &u->test_mode_on) < 0) {
683 AUDIO_INFO_LOG("No test_mode_on arg. Normal mode it is.");
684 }
685
686 pa_atomic_store(&u->dflag, 0);
687 u->dq = pa_asyncmsgq_new(0);
688
689 u->sink = PaHdiSinkInit(u, ma, driver);
690 if (!u->sink) {
691 AUDIO_ERR_LOG("Failed to create sink object");
692 goto fail;
693 }
694
695 u->sink->parent.process_msg = SinkProcessMsg;
696 u->sink->set_state_in_io_thread = SinkSetStateInIoThreadCb;
697 if (!u->fixed_latency) {
698 u->sink->update_requested_latency = SinkUpdateRequestedLatencyCb;
699 }
700 u->sink->userdata = u;
701
702 pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq);
703 pa_sink_set_rtpoll(u->sink, u->rtpoll);
704
705 u->bytes_dropped = 0;
706 u->buffer_size = DEFAULT_BUFFER_SIZE;
707 if (pa_modargs_get_value_u32(ma, "buffer_size", &u->buffer_size) < 0) {
708 AUDIO_ERR_LOG("Failed to parse buffer_size argument.");
709 goto fail;
710 }
711
712 u->block_usec = pa_bytes_to_usec(u->buffer_size, &u->sink->sample_spec);
713
714 if (u->fixed_latency) {
715 pa_sink_set_fixed_latency(u->sink, u->block_usec);
716 } else {
717 pa_sink_set_latency_range(u->sink, 0, u->block_usec);
718 }
719
720 pa_sink_set_max_request(u->sink, u->buffer_size);
721
722 paThreadName = "write-pa";
723 if (!(u->thread = pa_thread_new(paThreadName, ThreadFuncRendererTimer, u))) {
724 AUDIO_ERR_LOG("Failed to write-pa thread.");
725 goto fail;
726 }
727
728 if (u->test_mode_on) {
729 u->writeCount = 0;
730 u->renderCount = 0;
731 hdiThreadName = "test-mode-write-hdi";
732 if (!(u->thread_hdi = pa_thread_new(hdiThreadName, TestModeThreadFuncWriteHDI, u))) {
733 AUDIO_ERR_LOG("Failed to test-mode-write-hdi thread.");
734 goto fail;
735 }
736 } else {
737 hdiThreadName = "write-hdi";
738 if (!(u->thread_hdi = pa_thread_new(hdiThreadName, ThreadFuncWriteHDI, u))) {
739 AUDIO_ERR_LOG("Failed to write-hdi thread.");
740 goto fail;
741 }
742 }
743
744 u->writeTime = DEFAULT_WRITE_TIME;
745
746 pa_sink_put(u->sink);
747
748 return u->sink;
749 fail:
750 UserdataFree(u);
751
752 return NULL;
753 }
754
UserdataFree(struct Userdata * u)755 static void UserdataFree(struct Userdata *u)
756 {
757 pa_assert(u);
758
759 if (u->sink)
760 pa_sink_unlink(u->sink);
761
762 if (u->thread) {
763 pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL);
764 pa_thread_free(u->thread);
765 }
766
767 if (u->thread_hdi) {
768 pa_asyncmsgq_post(u->dq, NULL, QUIT, NULL, 0, NULL, NULL);
769 pa_thread_free(u->thread_hdi);
770 }
771
772 pa_thread_mq_done(&u->thread_mq);
773
774 if (u->sink)
775 pa_sink_unref(u->sink);
776
777 if (u->memchunk.memblock)
778 pa_memblock_unref(u->memchunk.memblock);
779
780 if (u->rtpoll)
781 pa_rtpoll_free(u->rtpoll);
782
783 if (u->sinkAdapter) {
784 u->sinkAdapter->RendererSinkStop(u->sinkAdapter);
785 u->sinkAdapter->RendererSinkDeInit(u->sinkAdapter);
786 UnLoadSinkAdapter(u->sinkAdapter);
787 }
788
789 pa_xfree(u);
790 }
791
PaHdiSinkFree(pa_sink * s)792 void PaHdiSinkFree(pa_sink *s)
793 {
794 struct Userdata *u = NULL;
795
796 pa_sink_assert_ref(s);
797 pa_assert_se(u = s->userdata);
798
799 UserdataFree(u);
800 }
801