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 <audio_manager.h>
17 #include <config.h>
18 #include <pulse/rtclock.h>
19 #include <pulse/timeval.h>
20 #include <pulse/util.h>
21 #include <pulse/xmalloc.h>
22 #include <pulsecore/core.h>
23 #include <pulsecore/log.h>
24 #include <pulsecore/memchunk.h>
25 #include <pulsecore/modargs.h>
26 #include <pulsecore/module.h>
27 #include <pulsecore/rtpoll.h>
28 #include <pulsecore/thread-mq.h>
29 #include <pulsecore/thread.h>
30 #include <stddef.h>
31 #include <stdint.h>
32 #include <inttypes.h>
33 #include <stdbool.h>
34 #include "audio_log.h"
35 #include "audio_types.h"
36 #include "capturer_source_adapter.h"
37
38 #define DEFAULT_SOURCE_NAME "hdi_input"
39 #define DEFAULT_DEVICE_CLASS "primary"
40 #define DEFAULT_AUDIO_DEVICE_NAME "Internal Mic"
41 #define DEFAULT_DEVICE_CLASS "primary"
42 #define DEFAULT_DEVICE_NETWORKID "LocalDevice"
43
44 #define DEFAULT_BUFFER_SIZE (1024 * 16)
45 #define MAX_VOLUME_VALUE 15.0
46 #define DEFAULT_LEFT_VOLUME MAX_VOLUME_VALUE
47 #define DEFAULT_RIGHT_VOLUME MAX_VOLUME_VALUE
48 #define MAX_LATENCY_USEC (PA_USEC_PER_SEC * 2)
49 #define MIN_LATENCY_USEC 500
50 #define AUDIO_POINT_NUM 1024
51 #define AUDIO_FRAME_NUM_IN_BUF 30
52
53 struct Userdata {
54 pa_core *core;
55 pa_module *module;
56 pa_source *source;
57 pa_thread *thread;
58 pa_thread_mq thread_mq;
59 pa_rtpoll *rtpoll;
60 uint32_t buffer_size;
61 uint32_t open_mic_speaker;
62 pa_usec_t block_usec;
63 pa_usec_t timestamp;
64 SourceAttr attrs;
65 bool IsCapturerStarted;
66 struct CapturerSourceAdapter *sourceAdapter;
67 };
68
69 static int pa_capturer_init(struct Userdata *u);
70 static void pa_capturer_exit(struct Userdata *u);
71
userdata_free(struct Userdata * u)72 static void userdata_free(struct Userdata *u)
73 {
74 pa_assert(u);
75 if (u->source)
76 pa_source_unlink(u->source);
77
78 if (u->thread) {
79 pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL);
80 pa_thread_free(u->thread);
81 }
82
83 pa_thread_mq_done(&u->thread_mq);
84
85 if (u->source)
86 pa_source_unref(u->source);
87
88 if (u->rtpoll)
89 pa_rtpoll_free(u->rtpoll);
90
91 if (u->sourceAdapter) {
92 u->sourceAdapter->CapturerSourceStop(u->sourceAdapter->wapper);
93 u->sourceAdapter->CapturerSourceDeInit(u->sourceAdapter->wapper);
94 UnLoadSourceAdapter(u->sourceAdapter);
95 }
96
97 pa_xfree(u);
98 }
99
source_process_msg(pa_msgobject * o,int code,void * data,int64_t offset,pa_memchunk * chunk)100 static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk)
101 {
102 struct Userdata *u = PA_SOURCE(o)->userdata;
103 pa_assert(u);
104
105 switch (code) {
106 case PA_SOURCE_MESSAGE_GET_LATENCY: {
107 pa_usec_t now;
108 now = pa_rtclock_now();
109 *((int64_t*)data) = (int64_t)now - (int64_t)u->timestamp;
110 return 0;
111 }
112 default: {
113 pa_log("source_process_msg default case");
114 return pa_source_process_msg(o, code, data, offset, chunk);
115 }
116 }
117 }
118
119 /* Called from the IO thread. */
source_set_state_in_io_thread_cb(pa_source * s,pa_source_state_t newState,pa_suspend_cause_t newSuspendCause)120 static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t newState,
121 pa_suspend_cause_t newSuspendCause)
122 {
123 AUDIO_INFO_LOG("Capturer current state: %{public}d new state: %{public}d", s->thread_info.state, newState);
124 struct Userdata *u = NULL;
125 pa_assert(s);
126 pa_assert_se(u = s->userdata);
127
128 if ((s->thread_info.state == PA_SOURCE_SUSPENDED || s->thread_info.state == PA_SOURCE_INIT) &&
129 PA_SOURCE_IS_OPENED(newState)) {
130 u->timestamp = pa_rtclock_now();
131 if (newState == PA_SOURCE_RUNNING && !u->IsCapturerStarted) {
132 if (u->sourceAdapter->CapturerSourceStart(u->sourceAdapter->wapper)) {
133 AUDIO_ERR_LOG("HDI capturer start failed");
134 return -PA_ERR_IO;
135 }
136 u->IsCapturerStarted = true;
137 AUDIO_DEBUG_LOG("Successfully started HDI capturer");
138 }
139 } else if (s->thread_info.state == PA_SOURCE_IDLE) {
140 if (newState == PA_SOURCE_SUSPENDED) {
141 if (u->IsCapturerStarted) {
142 u->sourceAdapter->CapturerSourceStop(u->sourceAdapter->wapper);
143 u->IsCapturerStarted = false;
144 AUDIO_DEBUG_LOG("Stopped HDI capturer");
145 }
146 } else if (newState == PA_SOURCE_RUNNING && !u->IsCapturerStarted) {
147 AUDIO_DEBUG_LOG("Idle to Running starting HDI capturing device");
148 if (u->sourceAdapter->CapturerSourceStart(u->sourceAdapter->wapper)) {
149 AUDIO_ERR_LOG("Idle to Running HDI capturer start failed");
150 return -PA_ERR_IO;
151 }
152 u->IsCapturerStarted = true;
153 AUDIO_DEBUG_LOG("Idle to Running: Successfully reinitialized HDI renderer");
154 }
155 }
156
157 return 0;
158 }
159
get_capturer_frame_from_hdi(pa_memchunk * chunk,const struct Userdata * u)160 static int get_capturer_frame_from_hdi(pa_memchunk *chunk, const struct Userdata *u)
161 {
162 uint64_t requestBytes;
163 uint64_t replyBytes = 0;
164 void *p = NULL;
165
166 chunk->length = u->buffer_size;
167 AUDIO_DEBUG_LOG("HDI Source: chunk.length = u->buffer_size: %{public}zu", chunk->length);
168 chunk->memblock = pa_memblock_new(u->core->mempool, chunk->length);
169 pa_assert(chunk->memblock);
170 p = pa_memblock_acquire(chunk->memblock);
171 pa_assert(p);
172
173 requestBytes = pa_memblock_get_length(chunk->memblock);
174 u->sourceAdapter->CapturerSourceFrame(u->sourceAdapter->wapper, (char *)p, (uint64_t)requestBytes, &replyBytes);
175
176 pa_memblock_release(chunk->memblock);
177 AUDIO_DEBUG_LOG("HDI Source: request bytes: %{public}" PRIu64 ", replyBytes: %{public}" PRIu64,
178 requestBytes, replyBytes);
179 if (replyBytes > requestBytes) {
180 AUDIO_ERR_LOG("HDI Source: Error replyBytes > requestBytes. Requested data Length: "
181 "%{public}" PRIu64 ", Read: %{public}" PRIu64 " bytes", requestBytes, replyBytes);
182 pa_memblock_unref(chunk->memblock);
183 return 0;
184 }
185
186 if (replyBytes == 0) {
187 AUDIO_ERR_LOG("HDI Source: Failed to read, Requested data Length: %{public}" PRIu64 " bytes,"
188 " Read: %{public}" PRIu64 " bytes", requestBytes, replyBytes);
189 pa_memblock_unref(chunk->memblock);
190 return 0;
191 }
192
193 chunk->index = 0;
194 chunk->length = replyBytes;
195 pa_source_post(u->source, chunk);
196 pa_memblock_unref(chunk->memblock);
197
198 return 0;
199 }
200
thread_func(void * userdata)201 static void thread_func(void *userdata)
202 {
203 struct Userdata *u = userdata;
204 bool timer_elapsed = false;
205
206 pa_assert(u);
207
208 if (u->core->realtime_scheduling)
209 pa_thread_make_realtime(u->core->realtime_priority);
210
211 pa_thread_mq_install(&u->thread_mq);
212 u->timestamp = pa_rtclock_now();
213 AUDIO_DEBUG_LOG("HDI Source: u->timestamp : %{public}" PRIu64, u->timestamp);
214
215 while (true) {
216 int ret = 0;
217
218 if (PA_SOURCE_IS_OPENED(u->source->thread_info.state) && u->IsCapturerStarted) {
219 pa_memchunk chunk;
220 pa_usec_t now;
221
222 now = pa_rtclock_now();
223 AUDIO_DEBUG_LOG("HDI Source: now: %{public}" PRIu64 " timer_elapsed: %{public}d", now, timer_elapsed);
224
225 if (timer_elapsed) {
226 chunk.length = pa_usec_to_bytes(now - u->timestamp, &u->source->sample_spec);
227 if (chunk.length > 0) {
228 ret = get_capturer_frame_from_hdi(&chunk, u);
229 if (ret != 0) {
230 break;
231 }
232
233 u->timestamp += pa_bytes_to_usec(chunk.length, &u->source->sample_spec);
234 AUDIO_DEBUG_LOG("HDI Source: new u->timestamp : %{public}" PRIu64, u->timestamp);
235 }
236 }
237
238 pa_rtpoll_set_timer_absolute(u->rtpoll, u->timestamp + u->block_usec);
239 } else {
240 pa_rtpoll_set_timer_disabled(u->rtpoll);
241 AUDIO_DEBUG_LOG("HDI Source: pa_rtpoll_set_timer_disabled done ");
242 }
243
244 /* Hmm, nothing to do. Let's sleep */
245 if ((ret = pa_rtpoll_run(u->rtpoll)) < 0) {
246 /* If this was no regular exit from the loop we have to continue
247 * processing messages until we received PA_MESSAGE_SHUTDOWN */
248 AUDIO_ERR_LOG("HDI Source: pa_rtpoll_run ret:%{public}d failed", ret);
249 pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module,
250 0, NULL, NULL);
251 pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN);
252 return;
253 }
254
255 timer_elapsed = pa_rtpoll_timer_elapsed(u->rtpoll);
256
257 if (ret == 0) {
258 return;
259 }
260 }
261 }
262
pa_capturer_init(struct Userdata * u)263 static int pa_capturer_init(struct Userdata *u)
264 {
265 int ret;
266
267 ret = u->sourceAdapter->CapturerSourceInit(u->sourceAdapter->wapper, &u->attrs);
268 if (ret != 0) {
269 AUDIO_ERR_LOG("Audio capturer init failed!");
270 return ret;
271 }
272
273 ret = u->sourceAdapter->CapturerSourceStart(u->sourceAdapter->wapper);
274 if (ret != 0) {
275 AUDIO_ERR_LOG("Audio capturer start failed!");
276 goto fail;
277 }
278
279 u->IsCapturerStarted = true;
280 return ret;
281
282 fail:
283 pa_capturer_exit(u);
284 return ret;
285 }
286
pa_capturer_exit(struct Userdata * u)287 static void pa_capturer_exit(struct Userdata *u)
288 {
289 u->sourceAdapter->CapturerSourceStop(u->sourceAdapter->wapper);
290 u->sourceAdapter->CapturerSourceDeInit(u->sourceAdapter->wapper);
291 }
292
pa_set_source_properties(pa_module * m,pa_modargs * ma,const pa_sample_spec * ss,const pa_channel_map * map,struct Userdata * u)293 static int pa_set_source_properties(pa_module *m, pa_modargs *ma, const pa_sample_spec *ss, const pa_channel_map *map,
294 struct Userdata *u)
295 {
296 pa_source_new_data data;
297
298 if (pa_modargs_get_value_u32(ma, "buffer_size", &u->buffer_size) < 0) {
299 AUDIO_INFO_LOG("Failed to parse buffer_size argument.");
300 u->buffer_size = DEFAULT_BUFFER_SIZE;
301 }
302 pa_source_new_data_init(&data);
303 data.driver = __FILE__;
304 data.module = m;
305 pa_source_new_data_set_name(&data, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME));
306 pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING,
307 (u->attrs.adapterName ? u->attrs.adapterName : DEFAULT_AUDIO_DEVICE_NAME));
308 pa_proplist_setf(data.proplist, PA_PROP_DEVICE_DESCRIPTION, "HDI source is %s",
309 (u->attrs.adapterName ? u->attrs.adapterName : DEFAULT_AUDIO_DEVICE_NAME));
310 pa_source_new_data_set_sample_spec(&data, ss);
311 pa_source_new_data_set_channel_map(&data, map);
312 pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%lu", (unsigned long)u->buffer_size);
313
314 if (pa_modargs_get_proplist(ma, "source_properties", data.proplist, PA_UPDATE_REPLACE) < 0) {
315 AUDIO_ERR_LOG("Invalid properties");
316 pa_source_new_data_done(&data);
317 return -1;
318 }
319
320 u->source = pa_source_new(m->core, &data, PA_SOURCE_HARDWARE | PA_SOURCE_LATENCY);
321 pa_source_new_data_done(&data);
322
323 if (!u->source) {
324 AUDIO_ERR_LOG("Failed to create source object");
325 return -1;
326 }
327
328 u->source->parent.process_msg = source_process_msg;
329 u->source->set_state_in_io_thread = source_set_state_in_io_thread_cb;
330 u->source->userdata = u;
331
332 pa_source_set_asyncmsgq(u->source, u->thread_mq.inq);
333 pa_source_set_rtpoll(u->source, u->rtpoll);
334
335 u->block_usec = pa_bytes_to_usec(u->buffer_size, &u->source->sample_spec);
336 pa_source_set_latency_range(u->source, 0, u->block_usec);
337 u->source->thread_info.max_rewind = pa_usec_to_bytes(u->block_usec, &u->source->sample_spec);
338
339 return 0;
340 }
341
ConvertToHDIAudioFormat(pa_sample_format_t format)342 static enum AudioFormat ConvertToHDIAudioFormat(pa_sample_format_t format)
343 {
344 enum AudioFormat hdiAudioFormat;
345 switch (format) {
346 case PA_SAMPLE_U8:
347 hdiAudioFormat = AUDIO_FORMAT_PCM_8_BIT;
348 break;
349 case PA_SAMPLE_S16LE:
350 case PA_SAMPLE_S16BE:
351 hdiAudioFormat = AUDIO_FORMAT_PCM_16_BIT;
352 break;
353 case PA_SAMPLE_S24LE:
354 case PA_SAMPLE_S24BE:
355 hdiAudioFormat = AUDIO_FORMAT_PCM_24_BIT;
356 break;
357 case PA_SAMPLE_S32LE:
358 case PA_SAMPLE_S32BE:
359 hdiAudioFormat = AUDIO_FORMAT_PCM_32_BIT;
360 break;
361 default:
362 hdiAudioFormat = AUDIO_FORMAT_PCM_16_BIT;
363 break;
364 }
365
366 return hdiAudioFormat;
367 }
368
GetEndianInfo(pa_sample_format_t format)369 static bool GetEndianInfo(pa_sample_format_t format)
370 {
371 bool isBigEndian = false;
372 switch (format) {
373 case PA_SAMPLE_S16BE:
374 case PA_SAMPLE_S24BE:
375 case PA_SAMPLE_S32BE:
376 case PA_SAMPLE_FLOAT32BE:
377 case PA_SAMPLE_S24_32BE:
378 isBigEndian = true;
379 break;
380 default:
381 isBigEndian = false;
382 break;
383 }
384
385 return isBigEndian;
386 }
387
pa_hdi_source_new(pa_module * m,pa_modargs * ma,const char * driver)388 pa_source *pa_hdi_source_new(pa_module *m, pa_modargs *ma, const char *driver)
389 {
390 struct Userdata *u = NULL;
391 pa_sample_spec ss;
392 char *thread_name = NULL;
393 pa_channel_map map;
394 int ret;
395
396 pa_assert(m);
397 pa_assert(ma);
398
399 ss = m->core->default_sample_spec;
400 map = m->core->default_channel_map;
401
402 /* Override with modargs if provided */
403 if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
404 AUDIO_ERR_LOG("Failed to parse sample specification and channel map");
405 return NULL;
406 }
407
408 u = pa_xnew0(struct Userdata, 1);
409 pa_assert(u);
410
411 u->core = m->core;
412 u->module = m;
413 u->rtpoll = pa_rtpoll_new();
414
415 if (pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll) < 0) {
416 AUDIO_ERR_LOG("pa_thread_mq_init() failed.");
417 goto fail;
418 }
419
420 ret = LoadSourceAdapter(pa_modargs_get_value(ma, "device_class", DEFAULT_DEVICE_CLASS),
421 pa_modargs_get_value(ma, "network_id", DEFAULT_DEVICE_NETWORKID), &u->sourceAdapter);
422 if (ret) {
423 AUDIO_ERR_LOG("Load adapter failed");
424 goto fail;
425 }
426
427 u->buffer_size = DEFAULT_BUFFER_SIZE;
428 u->attrs.sampleRate = ss.rate;
429 u->attrs.filePath = pa_modargs_get_value(ma, "file_path", "");
430 if (pa_modargs_get_value_u32(ma, "open_mic_speaker", &u->open_mic_speaker) < 0) {
431 AUDIO_ERR_LOG("Failed to parse open_mic_speaker argument");
432 goto fail;
433 }
434 u->attrs.channel = ss.channels;
435 u->attrs.format = ConvertToHDIAudioFormat(ss.format);
436 u->attrs.isBigEndian = GetEndianInfo(ss.format);
437 u->attrs.adapterName = pa_modargs_get_value(ma, "adapter_name", DEFAULT_DEVICE_CLASS);
438 u->attrs.deviceNetworkId = pa_modargs_get_value(ma, "network_id", DEFAULT_DEVICE_NETWORKID);
439 if (pa_modargs_get_value_s32(ma, "device_type", &u->attrs.device_type) < 0) {
440 AUDIO_ERR_LOG("Failed to parse device_type argument");
441 }
442
443 AUDIO_DEBUG_LOG("AudioDeviceCreateCapture format: %{public}d, isBigEndian: %{public}d channel: %{public}d,"
444 "sampleRate: %{public}d", u->attrs.format, u->attrs.isBigEndian, u->attrs.channel, u->attrs.sampleRate);
445
446 ret = pa_set_source_properties(m, ma, &ss, &map, u);
447 if (ret != 0) {
448 AUDIO_ERR_LOG("Failed to pa_set_source_properties");
449 goto fail;
450 }
451
452 u->attrs.bufferSize = u->buffer_size;
453 u->attrs.open_mic_speaker = u->open_mic_speaker;
454
455 ret = pa_capturer_init(u);
456 if (ret != 0) {
457 AUDIO_ERR_LOG("Failed to pa_capturer_init");
458 goto fail;
459 }
460
461 thread_name = "hdi-source-record";
462 if (!(u->thread = pa_thread_new(thread_name, thread_func, u))) {
463 AUDIO_ERR_LOG("Failed to create hdi-source-record thread!");
464 goto fail;
465 }
466
467 pa_source_put(u->source);
468 return u->source;
469
470 fail:
471
472 if (u->IsCapturerStarted) {
473 pa_capturer_exit(u);
474 }
475 userdata_free(u);
476
477 return NULL;
478 }
479
pa_hdi_source_free(pa_source * s)480 void pa_hdi_source_free(pa_source *s)
481 {
482 struct Userdata *u = NULL;
483 pa_source_assert_ref(s);
484 pa_assert_se(u = s->userdata);
485 userdata_free(u);
486 }
487