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