• 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 <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