blob: 35d6b15546b30ad737c1ac9b176738d2d3e3de78 [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001/******************************************************************************
2 *(C) Copyright 2019 ASR.
3 * All Rights Reserved
4 ******************************************************************************/
5/* -------------------------------------------------------------------------------------------------------------------
6 *
7 * Filename:VoIP_service.c
8 *
9 * Authors:
10 *
11 * Description: The service will start the service of record and playback PCM stream based on ASR platforms.
12 *
13 *
14 * HISTORY:
15 *
16 *
17 *
18 * Notes:
19 *
20 ******************************************************************************/
21
22/******************************************************************************
23 * Include files
24 ******************************************************************************/
25#include "audio_if_types.h"
26#include "audio_if_ubus.h"
27#include "audio_if_parameter.h"
28#include "audio_if.h"
29#include "audio_if_api.h"
30#include <unistd.h>
31#include <sys/types.h>
32#include <sys/stat.h>
33#include <fcntl.h>
34#include "telatparamdef_ubus.h"
35#include <libubox/blobmsg_json.h>
36#include "libubus.h"
37#include <string.h>
38#include "audio_if_audio_hw_mrvl.h"
39#include "utlEventHandler.h"
40#include "udev_monitor.h"
41#include "audio_hw_mrvl.h"
42#include <stdlib.h>
43#include <stdio.h>
44#include <cutils/str_parms.h>
45#include "vcm.h"
46#include <signal.h>
47
48extern void* audio_hal_install(void);
49extern void audio_hal_uninstall(void);
50extern void configure_vcm(unsigned int data[]);
51extern int vcm_DTMFDetection(unsigned int onoff, unsigned int dialToneToOthersTones, unsigned int dialTonesToOthersDialTones, unsigned int dialVadDuration);
52
53/******************************************************************************
54 * Globals
55 ******************************************************************************/
56static audio_hw_device_t *VoIP_ahw_dev_ubus;
57
58struct audio_stream_in *stream_in = NULL;
59struct audio_stream_out *stream_out = NULL;
60bool go_on_service = true;
61unsigned int pcm_record_size = 0; //320:NB, 640:WB
62unsigned int pcm_playback_size = 0; //320:NB, 640:WB
63
64
65//#define IOCTL_DEV "/dev/audiostub_ctl"
66//#define PCM_DEV "/dev/audiostub_pcm"
67//#define VoIP_DEV "/dev/VoIP_ctl"
68
69//add the device interface for test
70//#define TEST_VoIP_DEV "/dev/VoIP_pcm"
71
72#define OPEN_VoIP_DEV 1
73//#define OPEN_TEST_VoIP_DEV 2
74
75#define CONFIG_RECORD_FMT 1
76#define CONFIG_PLAYBACK_FMT 0
77/////////////////////////////////////////////////////////////////////////////
78
79static int config_parameters(int in_out, int is_wb, int near_far_end, int near_codec_or_vocoder)
80{
81 unsigned int direction = 0xFF, type, srcdst, priority, dest;
82 char kvpair[128];
83 struct str_parms *param = NULL;
84 int data[5];
85 const char *key = NULL;
86 bool update_vcm = false;
87
88 direction = in_out;/* 0-play, 1-record */
89 type = is_wb; /* 0:PCM_NB_BUF_SIZE, 1:PCM_WB_BUF_SIZE */
90 srcdst = near_far_end;/* 0-None, 1-Near end, 2-Far end, 3-Both ends */
91 priority = 1;/* 0-Do not combine(override), 1-Combine */
92 dest = near_codec_or_vocoder;/* 0-Near codec, 1-Near Vocoder */
93
94 if(direction == 0){//output
95 if(type == 0)
96 pcm_playback_size = PCM_NB_BUF_SIZE;
97 else
98 pcm_playback_size = PCM_WB_BUF_SIZE;
99
100 printf("config playback parameters.\n");
101 }
102 else if(direction == 1){//input
103 if(type == 0)
104 pcm_record_size = PCM_NB_BUF_SIZE;
105 else
106 pcm_record_size = PCM_WB_BUF_SIZE;
107
108 printf("config record parameters.\n");
109 }
110
111 memset(kvpair, 0x00, sizeof(kvpair));
112 sprintf(kvpair, "%s=%d;%s=%d;%s=%d;%s=%d;%s=%d", VCM_CONFIG_DIRECTION, direction,
113 VCM_CONFIG_TYPE, type, VCM_CONFIG_SRC_DST, srcdst,
114 VCM_CONFIG_PRIORITY, priority, VCM_CONFIG_DEST, dest);
115
116 printf("%s: config information kvpair is %s.\n", __FUNCTION__, kvpair);
117
118 //extract the parameter and config from string
119 param = str_parms_create_str(kvpair);
120 if (!param) {
121 printf("%s: param create str is null!", __FUNCTION__);
122 return -1;
123 }
124
125 //set vcm configurations
126 key = VCM_CONFIG_DIRECTION;
127 if (str_parms_get_int(param, key, &data[0]) == 0) {
128 update_vcm = true;
129 str_parms_del(param, key);
130 }
131 key = VCM_CONFIG_TYPE;
132 if (str_parms_get_int(param, key, &data[1]) == 0) {
133 update_vcm = true;
134 str_parms_del(param, key);
135 }
136 key = VCM_CONFIG_SRC_DST;
137 if (str_parms_get_int(param, key, &data[2]) == 0) {
138 update_vcm = true;
139 str_parms_del(param, key);
140 }
141 key = VCM_CONFIG_PRIORITY;
142 if (str_parms_get_int(param, key, &data[3]) == 0) {
143 update_vcm = true;
144 str_parms_del(param, key);
145 }
146 key = VCM_CONFIG_DEST;
147 if (str_parms_get_int(param, key, &data[4]) == 0) {
148 update_vcm = true;
149 str_parms_del(param, key);
150 }
151
152 //printf("Direction is %d, Type is %d, Src_Dst is %d, Priority is %d, Dest is %d. \n",data[0], data[1], data[2], data[3], data[4]);
153
154 if (update_vcm) {
155 configure_vcm(data); /*TODO check if all inputs got all values successfully*/
156 }
157
158 return 0;
159}
160
161/*******************************************************************************\
162 * Function: VoIP_thread
163 * Description:This function will be main thread to start the service of record and
164 * and playback.
165 *
166 * NOTE:
167 sample rate is 8000
168 channel number is 1/MONO
169 bit of sample is 16
170 Due to modem limited, only support 8k/16k sample rate
171 * Returns: void
172 \*******************************************************************************/
173static void VoIP_thread(void *arg)
174{
175 int rc, len;
176 char buffer[PCM_WB_BUF_SIZE];
177
178 printf("enter VoIP_thread.\n");
179
180 //Must set vcm_configure before playback
181 if((pcm_record_size != PCM_NB_BUF_SIZE) && (pcm_record_size != PCM_WB_BUF_SIZE)){
182 printf("%s: Please use vcm_configure to set pcm_record_size!!\n", __FUNCTION__);
183 return;
184 }
185
186 //Must set vcm_configure before playback
187 if((pcm_playback_size != PCM_NB_BUF_SIZE) && (pcm_playback_size != PCM_WB_BUF_SIZE)){
188 printf("%s: Please use vcm_configure to set pcm_playback_size!!\n", __FUNCTION__);
189 return;
190 }
191
192 //Must set vcm_configure before playback
193 if(pcm_record_size != pcm_playback_size){
194 printf("%s: Please configure pcm_record_size = pcm_playback_size!!\n", __FUNCTION__);
195 return;
196 }
197
198 //open the audiostub_ctl, prepare for record and playback
199 VCMInit();
200
201 //open record stream
202 rc = VoIP_ahw_dev_ubus->open_input_stream(VoIP_ahw_dev_ubus, 0,
203 VoIP_ahw_dev_ubus->get_supported_devices(VoIP_ahw_dev_ubus),
204 NULL, &stream_in, 0, 0, AUDIO_SOURCE_VOICE_CALL);
205 if (rc < 0) {
206 printf("%s: error opening input device. rc = %d!\n", __FUNCTION__, rc);
207 goto bad_stream;
208 }
209
210 //open playback stream
211 rc = VoIP_ahw_dev_ubus->open_output_stream(VoIP_ahw_dev_ubus, 0,
212 VoIP_ahw_dev_ubus->get_supported_devices(VoIP_ahw_dev_ubus),
213 AUDIO_OUTPUT_FLAG_DIRECT, NULL, &stream_out, 0);
214 if (rc < 0) {
215 printf("%s: error opening output device. rc = %d!\n", __FUNCTION__, rc);
216 goto bad_stream;
217 }
218
219 //bypass VoIP Record, only send the command "AUDIOSTUB_PCMRECCTL"
220 stream_in->read(stream_in, buffer, pcm_record_size);
221
222 //bypass VoIP playback, only send the command "AUDIOSTUB_PCMPLAYBACKCTL"
223 stream_out->write(stream_out, buffer, pcm_record_size);
224
225 printf("%s: waiting for ending of pcm stream service!\n", __FUNCTION__);
226
227 go_on_service = true;
228 while (go_on_service) {
229
230 //wait the program ending.
231 sleep(1);
232
233 }
234
235 //close the VoIP device FD when quit the programe.
236 stream_in->common.standby(&stream_in->common);
237 VoIP_ahw_dev_ubus->close_input_stream(VoIP_ahw_dev_ubus, stream_in);
238 stream_out->common.standby(&stream_out->common);
239 VoIP_ahw_dev_ubus->close_output_stream(VoIP_ahw_dev_ubus, stream_out);
240 VCMDeinit();//close the fd of audiostub_ctl when exit the thread.
241
242 go_on_service = false;
243
244bad_stream:
245 printf("%s: finished pcm stream service!\n", __FUNCTION__);
246 printf("exit VoIP_thread!\n");
247 return;
248}
249
250/*******************************************************************************\
251 * Function: simulateOffhook
252 * send the command of "AUDIOSTUB_PCMCTL" and "AUDIOSTUB_DTMFDETECTIONCTL" to simulate telephone offhook.
253 \*******************************************************************************/
254static void simulateOffhook(unsigned int onoff)
255{
256 unsigned int pcm_on;
257 unsigned int DTMFDetectiononoff;
258 unsigned int dialToneToOthersTones;
259 unsigned int dialTonesToOthersDialTones;
260 unsigned int dialVadDuration;
261
262 pcm_on = onoff;
263 //send the command of "AUDIOSTUB_PCMCTL"
264 VoIP_ahw_dev_ubus->switch_pcm(VoIP_ahw_dev_ubus, pcm_on);
265
266 DTMFDetectiononoff = onoff;
267 dialToneToOthersTones = 50;
268 dialTonesToOthersDialTones = 4;
269 dialVadDuration = 3;
270 //send the command of "AUDIOSTUB_DTMFDETECTIONCTL"
271 //vcm_DTMFDetection(1, 50, 4, 3);
272 vcm_DTMFDetection(DTMFDetectiononoff, dialToneToOthersTones, dialTonesToOthersDialTones, dialVadDuration);
273
274 return;
275}
276
277/*******************************************************************************\
278 * Function: sig_handler
279 * handle the signal of "CTRL+C" and "kill -15" to end the VoIP service
280 \*******************************************************************************/
281static void sig_handler(int sig)
282{
283 //simulate telephone onhook
284 simulateOffhook(0);
285
286 go_on_service = false;
287 printf("output signal number: %d.\n", sig);
288 printf("ending the service of record and playback!\n");
289
290 return;
291}
292
293/*******************************************************************************\
294 * Function: show_usage
295 \*******************************************************************************/
296static void show_usage(void)
297{
298 printf("ASR VoIP_service\n");
299 printf("Usage: VoIP_service [sampling_rate] scenario\n");
300 printf(" \n");
301 printf(" sampling_rate nb set PCM sampling rate to narrowband 8kHz\n");
302 printf(" wb set PCM sampling rate to wideband 16kHz\n");
303 printf(" default value is nb\n");
304 printf(" scenario 1 start service for scenario 1\n");
305 printf(" 2 start service for scenario 2\n");
306}
307
308/*******************************************************************************\
309 * Function: main
310 \*******************************************************************************/
311int main(int argc, char**argv)
312{
313 pthread_t thread_start;
314 int rc = 0;
315 int i = 0;
316 unsigned int is_wb = 2; /* 0:PCM_NB_BUF_SIZE, 1:PCM_WB_BUF_SIZE */
317 unsigned int near_far_end = 4; /* 0-None, 1-Near end, 2-Far end, 3-Both ends */
318 unsigned int near_codec_or_vocoder = 2; /* 0-Near codec, 1-Near Vocoder */
319
320 if(argc == 2)
321 {
322 is_wb = 0;
323 if(strcmp(argv[1], "1") == 0)
324 {
325 near_far_end = 1;
326 near_codec_or_vocoder = 1;
327 }
328 else if(strcmp(argv[1], "2") == 0)
329 {
330 near_far_end = 2;
331 near_codec_or_vocoder = 0;
332 }
333 else
334 {
335 show_usage();
336 exit (-1);
337 }
338 }
339 else if(argc == 3)
340 {
341 for (i=1; i<argc; i++)
342 {
343 if(strcmp(argv[i], "nb") == 0)
344 {
345 is_wb = 0;
346 }
347 else if(strcmp(argv[i], "wb") == 0)
348 {
349 is_wb = 1;
350 }
351 else if(strcmp(argv[i], "1") == 0)
352 {
353 near_far_end = 1;
354 near_codec_or_vocoder = 1;
355 }
356 else if(strcmp(argv[i], "2") == 0)
357 {
358 near_far_end = 2;
359 near_codec_or_vocoder = 0;
360 }
361 else
362 {
363 show_usage();
364 exit (-1);
365 }
366 }
367 }
368 else
369 {
370 show_usage();
371 exit (-1);
372 }
373
374 if(is_wb<2 && near_far_end<4 && near_codec_or_vocoder<2)
375 {
376 printf("start VoIP service with %s PCM sampling rate for scenario %d: %s\n", 0==is_wb?"nb":"wb", near_far_end, 1==near_far_end?"Near end | Near vocoder":"Far end | Near codec");
377 }
378 else
379 {
380 show_usage();
381 exit (-1);
382 }
383
384 //use the VoIP device file. It means starting service.
385 config_VoIP_device(OPEN_VoIP_DEV);
386
387 /* install signal handler and begin to capture signal for close */
388 signal(SIGINT, sig_handler);
389 signal(SIGTERM, sig_handler);
390
391 //init global variables
392 VoIP_ahw_dev_ubus = audio_hal_install();
393 if (VoIP_ahw_dev_ubus == NULL) {
394 printf("%s: audio_hal_install failed!\n", __FUNCTION__);
395 exit (-1);
396 }
397
398 //send the command of "AUDIOSTUB_PCMCTL" and "AUDIOSTUB_DTMFDETECTIONCTL" to simulate telephone offhook.
399 simulateOffhook(1);
400
401 //The following config parameters are needed for main thread.
402 //config record parameters.
403 config_parameters(CONFIG_RECORD_FMT, is_wb, near_far_end, near_codec_or_vocoder);
404 //config playback parameters.
405 config_parameters(CONFIG_PLAYBACK_FMT, is_wb, near_far_end, near_codec_or_vocoder);
406
407 rc = pthread_create(&thread_start, NULL, (void *)&VoIP_thread, NULL);
408 if (rc < 0) {
409 printf("%s: error creating thread_start!\n", __FUNCTION__);
410 rc = UBUS_STATUS_PERMISSION_DENIED;
411 }
412
413 if (pthread_join(thread_start, NULL)){
414 printf("error join thread!\n");
415 abort();
416 }
417
418 audio_hal_uninstall();
419
420 return 0;
421}
422