blob: 6e54fc96e3af6e785a22887a070f78a1d10911f0 [file] [log] [blame]
liubin281ac462023-07-19 14:22:54 +08001/**
2 * \file mbtk_audio.c
3 * \brief A Documented file.
4 *
5 * Detailed description
6 * \Author: js.wang <js.wang@mobiletek.cn>
7 * \Version: 1.0.0
8 * \Date: 2022-03-31
9 */
10#include <fcntl.h>
11#include <stdint.h>
12#include <limits.h>
13#include <termios.h>
14#include <stdarg.h>
15#include <dirent.h>
16#include <sys/stat.h>
17#include <sys/statfs.h>
18#include <sys/types.h>
19#include "mbtk_log.h"
20#include "mbtk_type.h"
21#include <libubox/blobmsg_json.h>
22#include "libubus.h"
23#include "mbtk_audio.h"
24
25/******************************************************************************\
26 * Macros / Defines
27\******************************************************************************/
28
29#ifndef UNUSEDPARAM
30#define UNUSEDPARAM(a) (void)(a)
31#endif
32
33#define AUDIO_UBUS_REQUEST_NAME "audio_if"
34#define mbtk_dtmf_UBUS_NAME "proslic_uBus" //Used by wake lock
35#define DTMFCODEID "dtmfcode"
36#define DTMFCODE_NOTIFICATION_NAME "audioif.dtmfcode"
37#define AUDIO_UBUS_VOLUME_SET "volume_set"
38#define AUDIO_UBUS_VOLUME_GET "volume_status"
39#define AUDIO_UBUS_MODE_SET "audio_mode_set"
LUOJian5bbddc22023-09-04 18:49:11 +080040#define AUDIO_UBUS_PATH_ENABLE "audio_path_enable"
41#define AUDIO_UBUS_SWITCH_PCM "switch_pcm"
liubin281ac462023-07-19 14:22:54 +080042#define AUDIO_UBUS_DSP_SET "config_dspgain"
43#define AUDIO_UBUS_LOOPBACK_EN "loopback_enable"
44#define AUDIO_UBUS_LOOPBACK_DIS "loopback_disable"
45
46// #define DEBUG 1
47
48#ifdef DEBUG
49 #define mbtk_audio_log(...) mbtk_audio_log(__VA_ARGS__)
50#else
51 #define mbtk_audio_log(...)
52#endif
53
54typedef enum {
55 PARAM_INT_POLICY_0,
56 PARAM_INT_POLICY_1,
57 PARAM_INT_POLICY_2,
58 PARAM_INT_POLICY_3,
59 PARAM_INT_POLICY_MAX,
60} PARAM_INT_POLICY;
61const struct blobmsg_policy int_policy[] ={
62 [PARAM_INT_POLICY_0] = {
63 .name = "param0",
64 .type = BLOBMSG_TYPE_INT32,
65 },
66};
67
68const struct blobmsg_policy dtmf_code_policy[] = {
69 [0] = {
70 .name = DTMFCODEID,
71 .type = BLOBMSG_TYPE_INT32,
72 },
73};
74
75static void mbtk_dtmf_add_subscriber_AudioIf(struct uloop_timeout *timeout);
76static struct uloop_timeout mbtk_dtmf_add_subscribe_timeout_AudioIf =
77{
78 .cb = mbtk_dtmf_add_subscriber_AudioIf,
79};
80
81static struct blob_buf audio_cm_b;
82pthread_mutex_t mbtk_dtmf_mutex;
83int mbtk_dtmf_PMConstraintWorks;
84//For UBUS listening to RILD & audio_if
85struct mbtk_audio_ubus_db_t
86{
87 pthread_t dtmf_pthread;
88 mbtk_dtmf_cb dtmf_cb;
89 mbtk_volume_cb audio_volume_get_cb;
90 int work_state;
91 struct ubus_context *ctx;
92
93 /* Audio_If */
94 struct ubus_subscriber audioif_event;
95 uint32_t audioif_subscriber_id;
96 uint32_t audioif_request_id;
97};
98
99static struct mbtk_audio_ubus_db_t *mbtk_audio_ubus_db = NULL;
100
101
102static int record_fd = 0;
103
104#define AUDIO_FILE_DIR "/data"
105#define MBTK_AUD_DEMO_WAV "/data/demo.wav"
106
107int create_audio_dir(const char *dirname)
108{
109 DIR *p_dir;
110 int res = -1;
111
112 if(NULL == (p_dir = opendir((const char *)dirname)))
113 {
114 if(mkdir(dirname, 0777) == 0)
115 {
116 res = 0;
117 }
118 else
119 {
120 fprintf(stderr, "create audio dir error \n");
121 res = -1;
122 }
123 }
124 else
125 {
126 closedir(p_dir);
127 res = 0;
128 }
129 return res;
130}
131int mbtk_at_play(const char *args)
132{
133 int fd = 0;
134 int play_hdl = 0;
135 char databuf[1024];
136 int size;
137
138 LOGI("%s %d", __FUNCTION__, __LINE__);
139 // play_hdl = Ql_AudPlayer_Open(NULL, NULL);
140 play_hdl = mbtk_audio_open(0, 1, 8000, NULL);
141 if(0 == play_hdl)
142 printf("Ql_AudPlayer_Open fail\n");
143
144 fd = open(MBTK_AUD_DEMO_WAV, O_RDWR);
145 if (fd <= 0)
146 {
147 printf("file open error\n");
148 goto err;
149 }
150 memset(databuf, 0, sizeof(databuf));
151 while(0 < (size = read(fd, databuf, sizeof(databuf))))
152 {
153 if(-1 == mbtk_audio_play_stream(play_hdl, databuf, size))
154 break;
155 }
156 mbtk_audio_log("aplay Stream end \n");
157
158err:
159 if(fd > 0)
160 close(fd);
161 mbtk_audio_close(play_hdl);
162
163 return 0;
164}
165
166void record_cb_func(int cb_result, char* databuf, unsigned int len)
167{
168 int rc;
169
170 if(NULL != databuf && len > 0 && record_fd > 0)
171 {
172 //for debug:save into file
173 rc = write(record_fd, databuf, len);
174 if (rc < 0) {
175 printf("%s: error writing to file!\n", __FUNCTION__);
176 } else if (rc < len) {
177 printf("%s: wrote less the buffer size!\n", __FUNCTION__);
178 }
179 }
180}
181
182int mbtk_at_rec(const char *args)
183{
184 LOGI("%s %d", __FUNCTION__, __LINE__);
185 //hdl = Ql_AudRecorder_Open(NULL, record_cb_func);
186 void *record_hdl = mbtk_audio_open(1, 1, 8000, NULL);
187 if (record_hdl == NULL)
188 {
189 printf("AudRecorder open error\n");
190 return -1;
191 }
192
193 create_audio_dir(AUDIO_FILE_DIR);
194 record_fd = open(MBTK_AUD_DEMO_WAV, O_RDWR|O_CREAT|O_TRUNC, 0644);
195 if (record_fd <= 0)
196 {
197 printf("file open error\n");
198 goto err;
199 }
200
201 if(-1 == mbtk_audio_record(record_hdl, record_cb_func, NULL))
202 {
203 printf("file write error\n");
204 close(record_fd);
205 record_fd = 0;
206 }
207 sleep(10);
208err:
209 mbtk_audio_close(record_hdl);
210 record_hdl = NULL;
211 if(record_fd > 0)
212 {
213 close(record_fd);
214 record_fd = 0;
215 }
216
217 return 0;
218}
219
220static void mbtk_ubus_complete_cb(struct ubus_request *req, int rc)
221{
222 if(NULL == mbtk_audio_ubus_db)
223 {
224 printf("mbtk_dtmf_ubus not init!\n");
225 return;
226 }
227 if (req)
228 {
229 free(req);
230 req = NULL;
231 }
232 mbtk_audio_log("%s do nothing, rc=%d\n", __FUNCTION__, rc);
233 LOGI("%s do nothing, rc=%d\n", __FUNCTION__, rc);
234 if(mbtk_audio_ubus_db->work_state)
235 mbtk_audio_ubus_db->work_state--;
236}
237/**
238 * @brief mbtk_audio_mode_set
239 *
240 * @details detailed description
241 *
242 * @param param
243 * "param0": UINT32
244 * typedef enum {
245 * AUDIO_MODE_INVALID = -2,
246 * AUDIO_MODE_CURRENT = -1,
247 * AUDIO_MODE_NORMAL = 0,
248 * AUDIO_MODE_RINGTONE = 1,
249 * AUDIO_MODE_IN_CALL = 2,
250 * AUDIO_MODE_IN_COMMUNICATION=3,
251 * AUDIO_MODE_IN_VT_CALL= 4,
252 * AUDIO_MODE_CNT,
253 * AUDIO_MODE_MAX = AUDIO_MODE_CNT-1,
254 * } audio_mode_
255 * @return return type
256 */
LUOJian5bbddc22023-09-04 18:49:11 +0800257void mbtk_audio_mode_set(int mode)
liubin281ac462023-07-19 14:22:54 +0800258{
259 int rc = 0;
260 struct ubus_request *req = NULL;
261
262 if(NULL == mbtk_audio_ubus_db)
263 {
264 printf("mbtk_dtmf_ubus not init!\n");
265 return;
266 }
267 req = (struct ubus_request *)malloc(sizeof(struct ubus_request));
268 if (req == NULL)
269 {
270 printf("leave %s: lack of memory\n", __FUNCTION__);
271 return;
272 }
273 memset(req, 0, sizeof(struct ubus_request));
274 blob_buf_init(&audio_cm_b, 0);
275 blobmsg_add_u32(&audio_cm_b, "param0", mode);
276 if ((rc = ubus_invoke_async(mbtk_audio_ubus_db->ctx,
277 mbtk_audio_ubus_db->audioif_request_id,
278 AUDIO_UBUS_MODE_SET,
279 audio_cm_b.head, req)) != UBUS_STATUS_OK)
280 {
281 free(req);
282 printf("%s, ubus_invoke_async %s failed %s\n", __FUNCTION__, AUDIO_UBUS_MODE_SET, ubus_strerror(rc));
283 }
284 else
285 {
286 printf("%s: ubus_invoke_async success\n", __FUNCTION__);
287 mbtk_audio_ubus_db->work_state++;
288 req->complete_cb = mbtk_ubus_complete_cb;
289 ubus_complete_request_async(mbtk_audio_ubus_db->ctx, req);
290 }
291}
LUOJian5bbddc22023-09-04 18:49:11 +0800292
293
294void mbtk_audio_path_enable(int mode)
295{
296 int rc = 0;
297 struct ubus_request *req = NULL;
298
299 if(NULL == mbtk_audio_ubus_db)
300 {
301 printf("mbtk_dtmf_ubus not init!\n");
302 return;
303 }
304 req = (struct ubus_request *)malloc(sizeof(struct ubus_request));
305 if (req == NULL)
306 {
307 printf("leave %s: lack of memory\n", __FUNCTION__);
308 return;
309 }
310 memset(req, 0, sizeof(struct ubus_request));
311 blob_buf_init(&audio_cm_b, 0);
312 blobmsg_add_u32(&audio_cm_b, "param0", mode);
313 if ((rc = ubus_invoke_async(mbtk_audio_ubus_db->ctx,
314 mbtk_audio_ubus_db->audioif_request_id,
315 AUDIO_UBUS_PATH_ENABLE,
316 audio_cm_b.head, req)) != UBUS_STATUS_OK)
317 {
318 free(req);
319 printf("%s, ubus_invoke_async %s failed %s\n", __FUNCTION__, AUDIO_UBUS_PATH_ENABLE, ubus_strerror(rc));
320 }
321 else
322 {
323 printf("%s: ubus_invoke_async success\n", __FUNCTION__);
324 mbtk_audio_ubus_db->work_state++;
325 req->complete_cb = mbtk_ubus_complete_cb;
326 ubus_complete_request_async(mbtk_audio_ubus_db->ctx, req);
327 }
328}
329
330
331/**
332 * @brief mbtk_audio_switch_pcm
333 *
334 * @details detailed description
335 *
336 * @param param
337 * "param0":UINT32 mode
338 * 0: Turn off MSA PCM
339 * 1: Turn on MSA PCM as NB PCM(i.e. 8KHz sample rate)
340 * 2: Turn on MSA PCM as WB PCM(i.e. 16KHz sample rate)
341 * @return return type
342 */
343void mbtk_audio_switch_pcm(int mode)
344{
345 int rc = 0;
346 struct ubus_request *req = NULL;
347
348 if(NULL == mbtk_audio_ubus_db)
349 {
350 printf("mbtk_dtmf_ubus not init!\n");
351 return;
352 }
353 req = (struct ubus_request *)malloc(sizeof(struct ubus_request));
354 if (req == NULL)
355 {
356 printf("leave %s: lack of memory\n", __FUNCTION__);
357 return;
358 }
359 memset(req, 0, sizeof(struct ubus_request));
360 blob_buf_init(&audio_cm_b, 0);
361 blobmsg_add_u32(&audio_cm_b, "param0", mode);
362 if ((rc = ubus_invoke_async(mbtk_audio_ubus_db->ctx,
363 mbtk_audio_ubus_db->audioif_request_id,
364 AUDIO_UBUS_SWITCH_PCM,
365 audio_cm_b.head, req)) != UBUS_STATUS_OK)
366 {
367 free(req);
368 printf("%s, ubus_invoke_async %s failed %s\n", __FUNCTION__, AUDIO_UBUS_MODE_SET, ubus_strerror(rc));
369 }
370 else
371 {
372 printf("%s: ubus_invoke_async success\n", __FUNCTION__);
373 mbtk_audio_ubus_db->work_state++;
374 req->complete_cb = mbtk_ubus_complete_cb;
375 ubus_complete_request_async(mbtk_audio_ubus_db->ctx, req);
376 }
377}
378
liubin281ac462023-07-19 14:22:54 +0800379int mbtk_audio_dsp_set(int type, int gain)
380{
381 LOGE("1type:%d, gain:%d\n", type, gain);
382 int rc = 0;
383 struct ubus_request *req = NULL;
384
385 if(NULL == mbtk_audio_ubus_db)
386 {
387 LOGE("mbtk_dtmf_ubus not init!\n");
388 return -1;
389 }
390 req = (struct ubus_request *)malloc(sizeof(struct ubus_request));
391 if (req == NULL)
392 {
393 LOGE("leave %s: lack of memory\n", __FUNCTION__);
394 return -1;
395 }
396
397 memset(req, 0, sizeof(struct ubus_request));
398 blob_buf_init(&audio_cm_b, 0);
399 blobmsg_add_u32(&audio_cm_b, "type", type);
400 blobmsg_add_u32(&audio_cm_b, "gain", gain);
401 if ((rc = ubus_invoke_async(mbtk_audio_ubus_db->ctx,
402 mbtk_audio_ubus_db->audioif_request_id,
403 AUDIO_UBUS_DSP_SET,
404 audio_cm_b.head, req)) != UBUS_STATUS_OK)
405 {
406 free(req);
407 LOGE("%s, ubus_invoke_async %s failed %s\n", __FUNCTION__, AUDIO_UBUS_DSP_SET, ubus_strerror(rc));
408 return -1;
409 }
410 else
411 {
412 LOGE("%s: ubus_invoke_async success\n", __FUNCTION__);
413 mbtk_audio_ubus_db->work_state++;
414 req->complete_cb = mbtk_ubus_complete_cb;
415 ubus_complete_request_async(mbtk_audio_ubus_db->ctx, req);
416 }
417 return 0;
418}
419/**
420 * @brief mbtk_audio_loopback_start
421 *
422 * @details detailed description
423 *
424 * @param param
425 * device: UINT32
426 * 0: earpiece
427 * 1: speaker
428 * 2: headset
429 * @return return type
430 */
431static void mbtk_audio_loopback_start(int device)
432{
433 int rc = 0;
434 struct ubus_request *req = NULL;
435
436 if(NULL == mbtk_audio_ubus_db)
437 {
438 LOGI("mbtk_dtmf_ubus not init!\n");
439 return;
440 }
441 req = (struct ubus_request *)malloc(sizeof(struct ubus_request));
442 if (req == NULL)
443 {
444 LOGI("leave %s: lack of memory\n", __FUNCTION__);
445 return;
446 }
447 memset(req, 0, sizeof(struct ubus_request));
448 blob_buf_init(&audio_cm_b, 0);
449 blobmsg_add_u32(&audio_cm_b, "param0", device);
450 if ((rc = ubus_invoke_async(mbtk_audio_ubus_db->ctx,
451 mbtk_audio_ubus_db->audioif_request_id,
452 AUDIO_UBUS_LOOPBACK_EN,
453 audio_cm_b.head, req)) != UBUS_STATUS_OK)
454 {
455 free(req);
456 LOGI("%s, ubus_invoke_async volume get failed %s\n", __FUNCTION__, ubus_strerror(rc));
457 }
458 else
459 {
460 LOGI("%s: ubus_invoke_async success\n", __FUNCTION__);
461 req->complete_cb = mbtk_ubus_complete_cb;
462 ubus_complete_request_async(mbtk_audio_ubus_db->ctx, req);
463 }
464}
465
466static void mbtk_audio_loopback_stop(void)
467{
468 int rc = 0;
469
470 if(NULL == mbtk_audio_ubus_db)
471 {
472 printf("mbtk_dtmf_ubus not init!\n");
473 return;
474 }
475 blob_buf_init(&audio_cm_b, 0);
476
477 if ((rc = ubus_invoke(mbtk_audio_ubus_db->ctx,
478 mbtk_audio_ubus_db->audioif_request_id,
479 AUDIO_UBUS_LOOPBACK_DIS,
480 audio_cm_b.head, NULL, 0, 0)) != UBUS_STATUS_OK)
481 {
482 LOGI("%s, ubus_invoke volume get failed %s\n", __FUNCTION__, ubus_strerror(rc));
483 }
484 else
485 {
486 LOGI("%s: ubus_invoke success\n", __FUNCTION__);
487 }
488}
489
490int mbtk_at_loopback(int type)
491{
492 static mbtk_audio_client_handle_type audio_handle = 0;
493 int ret = 0;
494
495 LOGI("%s %d:%d", __FUNCTION__, __LINE__, type);
496 if(0 == type) // Stop
497 {
498 mbtk_audio_loopback_stop();
499 if(audio_handle)
500 {
501 mbtk_audio_ubus_client_deinit(audio_handle);
502 audio_handle = 0;
503 }
504 }
505 else // Start
506 {
507 if(NULL == mbtk_audio_ubus_db)
508 ret = mbtk_audio_ubus_client_init(&audio_handle, NULL);
509 if(ret)
510 {
511 return -1;
512 }
513 mbtk_audio_mode_set(0);
514 mbtk_audio_loopback_start(2);
515 }
516
517 return 0;
518}
519
520/***************************************************** \
521 * Retry mechanism to add subscriber for Audio_if
522\*****************************************************/
523static void mbtk_dtmf_add_subscriber_AudioIf(struct uloop_timeout *timeout)
524{
525 /* add subscriber for Audio_If */
526 if (ubus_lookup_id(mbtk_audio_ubus_db->ctx, DTMFCODE_NOTIFICATION_NAME, &mbtk_audio_ubus_db->audioif_subscriber_id))
527 {
528 printf("%s, Failed to look up %s\n", __FUNCTION__, DTMFCODE_NOTIFICATION_NAME);
529 uloop_timeout_set(timeout, 2000);
530 return;
531 }
532
533 ubus_subscribe(mbtk_audio_ubus_db->ctx, &mbtk_audio_ubus_db->audioif_event, mbtk_audio_ubus_db->audioif_subscriber_id);
534 mbtk_audio_log("Audio_If subscribe %s object ok\n", DTMFCODE_NOTIFICATION_NAME);
535 return;
536}
537/*******************************************************************************\
538* Function: mbtk_dtmf_uBus_pmConstraint
539* Description: Lock/unlock system power management.
540* 0: unlock
541* 1: lock
542* Returns:
543\*******************************************************************************/
544static void mbtk_dtmf_uBus_PMConstraint(int set)
545{
546 FILE *flk;
547 if (mbtk_dtmf_PMConstraintWorks != 0)
548 return; //wake_lock unavailable or not exist. Do nothing
549
550#ifdef PROSLIC_ENABLEFREERUN
551 mbtk_audio_log("%s(%d): %s\n", __FUNCTION__, set, set ? "no sleep" : "sleep after 7s");
552#else
553 mbtk_audio_log("%s(%d): free-run is disabled, no sleep\n", __FUNCTION__, set);
554#endif
555
556 /* Do Not check fopen success. It must be ok, if failed
557 ** (for any reason) better to crash for logging and recovery
558 */
559 flk = fopen("/sys/power/wake_lock", "w");
560 if(set)
561 {
562 fprintf(flk, mbtk_dtmf_UBUS_NAME);
563 }
564 else
565 {
566#ifdef PROSLIC_ENABLEFREERUN
567 /* Clear constraint but with TimeOut enough
568 ** Stay awake for (mbtk_dtmf_DIAL_TIMER + 1) seconds, wait for ringing timer expire
569 */
570 fprintf(flk, mbtk_dtmf_UBUS_NAME " 7000000000"/*nsec*/);
571#endif
572 }
573
574 fclose(flk);
575}
576
577/*******************************************************************************\
578* Function: mbtk_dtmf_uBusInd_AudioIf_remove
579* Description: Handle upon Audio_if remove indication.
580* Returns:
581\*******************************************************************************/
582static void mbtk_dtmf_uBusInd_AudioIf_remove(struct ubus_context *ctx, struct ubus_subscriber *s,
583 uint32_t id)
584{
585 UNUSEDPARAM(ctx);
586 UNUSEDPARAM(s);
587 UNUSEDPARAM(id);
588
589 mbtk_audio_log("%s\n", __FUNCTION__);
590 uloop_timeout_set(&mbtk_dtmf_add_subscribe_timeout_AudioIf, 2000);
591}
592
593
594/*******************************************************************************\
595* Function: mbtk_dtmf_uBusInd_AudioIf
596* Description: Handle upon Audio_If incoming indication.
597* Returns: 0 on success
598\*******************************************************************************/
599static int mbtk_dtmf_uBusInd_AudioIf(struct ubus_context *ctx, struct ubus_object *obj,
600 struct ubus_request_data *req, const char *method,
601 struct blob_attr *msg)
602{
603 UNUSEDPARAM(ctx);
604 UNUSEDPARAM(obj);
605 UNUSEDPARAM(req);
606 UNUSEDPARAM(method);
607
608 char DTMFCode = 0;
609 struct blob_attr *tb[1];
610 int rc = 0;
611
612 //Lock from mbtk_dtmf interrupt handler (mbtk_dtmf_MainLoop)
613 pthread_mutex_lock(&mbtk_dtmf_mutex);
614 mbtk_audio_log("==================================%s : Begin==================================\n", __FUNCTION__);
615 mbtk_dtmf_uBus_PMConstraint(1);
616
617 /*parsing blob to be accessed easily with tb array - parse "1" argument*/
618 rc = blobmsg_parse(dtmf_code_policy, 1, tb, blob_data(msg), blob_len(msg));
619
620 if (rc < 0) {
621 printf("%s: parsing fail, rc = 0x%x\n", __FUNCTION__, rc);
622 }
623 else {
624 DTMFCode = (char)blobmsg_get_u32(tb[0]);
625 if(mbtk_audio_ubus_db->dtmf_cb)
626 mbtk_audio_ubus_db->dtmf_cb(DTMFCode);
627 mbtk_audio_log("%s got DTMF Code: Char[%c]=ASCII[0x%x]\n", __FUNCTION__, DTMFCode, DTMFCode);
628 }
629
630 mbtk_dtmf_uBus_PMConstraint(0);
631 mbtk_audio_log("==================================%s : End==================================", __FUNCTION__);
632 pthread_mutex_unlock(&mbtk_dtmf_mutex);
633
634 return rc;
635}
636
637/*******************************************************************************\
638* Function: mbtk_dtmf_uBusRegisterNotifications
639* Description: Register UBUS notifications of RIL and Audio_If.
640* Returns: 0 on success
641\*******************************************************************************/
642static int mbtk_dtmf_uBusRegisterNotifications(void)
643{
644 int ret = 0;
645
646 /* register UBUS notifications of Audio_If */
647 ret = ubus_register_subscriber(mbtk_audio_ubus_db->ctx, &mbtk_audio_ubus_db->audioif_event);
648 if (ret)
649 {
650 printf("%s Failed to add audio_if watch handler: %s\n", __FUNCTION__, ubus_strerror(ret));
651 return -1;
652 }
653
654 /* specify callback to handle notifications */
655 mbtk_audio_ubus_db->audioif_event.remove_cb = mbtk_dtmf_uBusInd_AudioIf_remove;
656 mbtk_audio_ubus_db->audioif_event.cb = mbtk_dtmf_uBusInd_AudioIf;
657
658 /* add subscribe */
659 uloop_timeout_set(&mbtk_dtmf_add_subscribe_timeout_AudioIf, 0);
660
661 mbtk_audio_log("%s: Make use of DTMF detection in modem.\n", __FUNCTION__);
662
663 return 0;
664}
665
666void mbtk_switch_dtmf_detection_cb(struct ubus_request *req, int rc)
667{
668 if (req)
669 {
670 free(req);
671 req = NULL;
672 }
673 mbtk_audio_log("%s do nothing, rc=%d\n", __FUNCTION__, rc);
674}
675/**
676 * @brief mbtk_switch_dtmf_detection
677 *
678 * @details detailed description
679 *
680 * @param param
681 * “param0": UINT32 onoff
682 * 0: disbale Tx DTMF detection
683 * 1: enable Tx DTMF detection
684 * 2: disbale Rx DTMF detection
685 * 3: enable Rx DTMF detection
686 * @return return type
687 */
688void mbtk_switch_dtmf_detection(unsigned short on_off, unsigned short param1,
689 unsigned short param2, unsigned short param3)
690{
691#if PCM_CTRL_OVER_VCM
692 vcm_DTMFDetection(on_off, param1, param2, param3);
693#else
694 int rc = 0;
695 struct ubus_request *req = NULL;
696
697 if(NULL == mbtk_audio_ubus_db)
698 {
699 printf("mbtk_dtmf_ubus not init!\n");
700 return;
701 }
702 req = (struct ubus_request *)malloc(sizeof(struct ubus_request));
703 if (req == NULL)
704 {
705 printf("leave %s: lack of memory\n", __FUNCTION__);
706 return;
707 }
708 memset(req, 0, sizeof(struct ubus_request));
709 blob_buf_init(&audio_cm_b, 0);
710 blobmsg_add_u32(&audio_cm_b, "param0", on_off);
711 blobmsg_add_u32(&audio_cm_b, "param1", param1);
712 blobmsg_add_u32(&audio_cm_b, "param2", param2);
713 blobmsg_add_u32(&audio_cm_b, "param3", param3);
714
715 if ((rc = ubus_invoke_async(mbtk_audio_ubus_db->ctx, mbtk_audio_ubus_db->audioif_request_id, "dtmf_detection", audio_cm_b.head, req)) != UBUS_STATUS_OK)
716 {
717 free(req);
718 printf("%s, ubus_invoke dtmf_detection failed %s\n", __FUNCTION__, ubus_strerror(rc));
719 }
720 else
721 {
722 mbtk_audio_log("%s: ubus_invoke_async success\n", __FUNCTION__);
723 req->complete_cb = mbtk_switch_dtmf_detection_cb;
724 ubus_complete_request_async(mbtk_audio_ubus_db->ctx, req);
725 }
726#endif
727}
728/*******************************************************************************\
729* Function: mbtk_dtmf_uBusInit
730* Description: Init UBUS context and register UBUS notifications of RIL.
731* Returns: 0 on success
732\*******************************************************************************/
733int mbtk_dtmf_uBusInit(void)
734{
735 int rc = 0;
736
737 uloop_init();
738
739 mbtk_audio_ubus_db->ctx = ubus_connect(NULL);
740 if (mbtk_audio_ubus_db->ctx == NULL)
741 {
742 printf(" %s Failed to connect to ubus\n", __FUNCTION__);
743 return -1;
744 }
745
746 ubus_add_uloop(mbtk_audio_ubus_db->ctx);
747
748 /* lookup fail if audio_if is not ready */
749 while(1)
750 {
751 rc = ubus_lookup_id(mbtk_audio_ubus_db->ctx, AUDIO_UBUS_REQUEST_NAME, &mbtk_audio_ubus_db->audioif_request_id);
752 if (0 != rc)
753 {
754 printf("%s, Failed to look up(%s), rc=%d\n", __FUNCTION__, AUDIO_UBUS_REQUEST_NAME, rc);
755 usleep(600000); //600ms
756 }
757 else
758 break;
759 }
760 mbtk_audio_log("%s, ubus_lookup_id(%s) OK\n", __FUNCTION__, AUDIO_UBUS_REQUEST_NAME);
761
762 /* subscribe for RIL & audio_if notifications */
763 if (mbtk_dtmf_uBusRegisterNotifications() != 0)
764 return -1;
765
766 mbtk_audio_log("%s success!\n", __FUNCTION__);
767 return 0;
768}
769
770
771/*******************************************************************************\
772* Function: mbtk_dtmf_uBusRun
773* Description: Start running of UBUS.
774* Returns:
775\*******************************************************************************/
776static void mbtk_audio_ubus_thread(void* hdl)
777{
778 pthread_detach(pthread_self());
779 uloop_run();
780 mbtk_audio_log("%s exit!\n", __FUNCTION__);
781 pthread_exit(NULL);
782}
783
784int mbtk_audio_ubus_client_init(mbtk_audio_client_handle_type *ph_audio, mbtk_dtmf_cb cb)
785{
786 int id;
787
788 // Set call handle.
789 if(ph_audio == NULL || mbtk_audio_ubus_db != NULL)
790 {
791 printf("ARG error or has inited.");
792 return -1;
793 }
794 mbtk_audio_ubus_db = malloc(sizeof(struct mbtk_audio_ubus_db_t));
795 if(NULL == mbtk_audio_ubus_db)
796 {
797 printf("malloc memory error\n");
798 }
799 memset(mbtk_audio_ubus_db, 0, sizeof(struct mbtk_audio_ubus_db_t));
800
801 mbtk_dtmf_PMConstraintWorks = access("/sys/power/wake_lock", R_OK | W_OK);
802 mbtk_dtmf_uBusInit();
803 mbtk_audio_ubus_db->dtmf_cb = cb;
804
805 mbtk_switch_dtmf_detection(3, 50, 4, 3);
806 pthread_create(&mbtk_audio_ubus_db->dtmf_pthread, NULL, (void *)mbtk_audio_ubus_thread, (void *)mbtk_audio_ubus_db);
807
808 *ph_audio = mbtk_audio_ubus_db;
809 LOGI("%s %d:%x", __FUNCTION__, __LINE__, mbtk_audio_ubus_db);
810
811 return 0;
812}
813
814int mbtk_audio_ubus_client_deinit(mbtk_audio_client_handle_type h_audio)
815{
816 int ret;
817 struct mbtk_audio_ubus_db_t *audio_ubus = (struct mbtk_audio_ubus_db_t *)h_audio;
818
819 mbtk_audio_log("%s \n", __FUNCTION__);
820 if(h_audio == NULL || mbtk_audio_ubus_db == NULL)
821 {
822 printf("ARG error or not inited.");
823 return -1;
824 }
825 LOGI("%s %d:%x", __FUNCTION__, __LINE__, audio_ubus);
826 ret = pthread_cancel(audio_ubus->dtmf_pthread);
827 mbtk_audio_log("kill pthread : %d \n", ret);
828 pthread_join(audio_ubus->dtmf_pthread, NULL);
829 do{
830 ret = pthread_kill(audio_ubus->dtmf_pthread, 0);
831 mbtk_audio_log("kill pthread: %d \n", ret);
832 if(ret == ESRCH)
833 mbtk_audio_log("The specified thread does not exist or has terminated\n");
834 else if(ret == EINVAL)
835 mbtk_audio_log("Useless signal\n");
836 else
837 mbtk_audio_log("The thread exists\n");
838 usleep(100000);
839 }while(0 == ret);
840 LOGI("%s %d", __FUNCTION__, __LINE__);
841
842 mbtk_switch_dtmf_detection(2, 0, 0, 0);
843 /*unregister uloop*/
844 /*thread will get here only if uloop stopped*/
845 ubus_free(mbtk_audio_ubus_db->ctx);
846 uloop_done();
847 LOGI("%s %d", __FUNCTION__, __LINE__);
848 free(h_audio);
849 mbtk_audio_ubus_db = NULL;
850
851 return 0;
852}
853
854/**********************************************************************\
855* Function: APP_Audio_VolumeSet
856* Description: This function is called to send command into audio_if.
857* unsigned int volume(0~100)
858* Returns: 0 on success
859\**********************************************************************/
860void mbtk_audio_ubus_volume_set(unsigned int volume)
861{
862 int rc = 0;
863 struct ubus_request *req = NULL;
864
865 if(NULL == mbtk_audio_ubus_db)
866 {
867 printf("mbtk_dtmf_ubus not init!\n");
868 return;
869 }
870 req = (struct ubus_request *)malloc(sizeof(struct ubus_request));
871 if (req == NULL)
872 {
873 printf("leave %s: lack of memory\n", __FUNCTION__);
874 return;
875 }
876 memset(req, 0, sizeof(struct ubus_request));
877 blob_buf_init(&audio_cm_b, 0);
878 blobmsg_add_u32(&audio_cm_b, "param0", volume);
879
880 if ((rc = ubus_invoke_async(mbtk_audio_ubus_db->ctx, mbtk_audio_ubus_db->audioif_request_id, AUDIO_UBUS_VOLUME_SET, audio_cm_b.head, req)) != UBUS_STATUS_OK)
881 {
882 free(req);
883 printf("%s, ubus_invoke_async volume set failed: %s\n", __FUNCTION__, ubus_strerror(rc));
884 }
885 else
886 {
887 mbtk_audio_log("%s: ubus_invoke_async success\n", __FUNCTION__);
888 req->complete_cb = mbtk_ubus_complete_cb;
889 ubus_complete_request_async(mbtk_audio_ubus_db->ctx, req);
890 }
891}
892
893static void audio_volume_get_data_cb (struct ubus_request *req, int type, struct blob_attr *msg)
894{
895 UNUSEDPARAM(req);
896 UNUSEDPARAM(type);
897 struct blob_attr *tb[1];
898 unsigned int volume = 888;
899 int rc = 0;
900
901 rc = blobmsg_parse(int_policy, 1, tb, blob_data(msg), blob_len(msg));
902 if (rc < 0)
903 {
904 printf("[%s] parsing blobmsg failed\n", __FUNCTION__);
905 return;
906 }
907
908 if(tb[0])
909 volume = blobmsg_get_u32(tb[0]);
910 if (mbtk_audio_ubus_db->audio_volume_get_cb)
911 mbtk_audio_ubus_db->audio_volume_get_cb(volume);
912 mbtk_audio_log("%s; volume:%d\n", __FUNCTION__, volume);
913}
914
915void mbtk_audio_ubus_volume_get(mbtk_volume_cb cb)
916{
917 int rc = 0;
918 struct ubus_request *req = NULL;
919
920 if(NULL == mbtk_audio_ubus_db || NULL == cb)
921 {
922 printf("mbtk_dtmf_ubus not init or callback invalid!\n");
923 return;
924 }
925 mbtk_audio_ubus_db->audio_volume_get_cb = cb;
926 req = (struct ubus_request *)malloc(sizeof(struct ubus_request));
927 if (req == NULL)
928 {
929 printf("leave %s: lack of memory\n", __FUNCTION__);
930 return;
931 }
932 memset(req, 0, sizeof(struct ubus_request));
933 blob_buf_init(&audio_cm_b, 0);
934
935 if ((rc = ubus_invoke_async(mbtk_audio_ubus_db->ctx,
936 mbtk_audio_ubus_db->audioif_request_id,
937 AUDIO_UBUS_VOLUME_GET,
938 audio_cm_b.head, req)) != UBUS_STATUS_OK)
939 {
940 free(req);
941 printf("%s, ubus_invoke_async volume get failed %s\n", __FUNCTION__, ubus_strerror(rc));
942 }
943 else
944 {
945 mbtk_audio_log("%s: ubus_invoke_async success\n", __FUNCTION__);
946 req->data_cb = audio_volume_get_data_cb;
947 req->complete_cb = mbtk_ubus_complete_cb;
948 ubus_complete_request_async(mbtk_audio_ubus_db->ctx, req);
949 }
950}