4 * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
33 #include "tizen-audio-internal.h"
35 #define vbc_thread_new pthread_create
36 #define MIXER_VBC_SWITCH "VBC Switch"
38 #define PIN_SWITCH_IIS0_SYS_SEL "IIS0 pin select"
39 #define PIN_SWITCH_IIS0_AP_ID 0
40 #define PIN_SWITCH_IIS0_CP0_ID 1
41 #define PIN_SWITCH_IIS0_CP1_ID 2
42 #define PIN_SWITCH_IIS0_CP2_ID 3
43 #define PIN_SWITCH_IIS0_VBC_ID 4
45 #define PIN_SWITCH_BT_IIS_SYS_SEL "BT IIS pin select"
46 #define PIN_SWITCH_BT_IIS_CP0_IIS0_ID 0
47 #define PIN_SWITCH_BT_IIS_CP1_IIS0_ID 4
48 #define PIN_SWITCH_BT_IIS_AP_IIS0_ID 8
50 #define PIN_SWITCH_BT_IIS_CON_SWITCH "BT IIS con switch"
52 #define VBC_TD_CHANNELID 0 /* cp [3g] */
53 #define VBC_ARM_CHANNELID 2 /* ap */
55 #define VBPIPE_DEVICE "/dev/spipe_w6"
56 #define VBPIPE_VOIP_DEVICE "/dev/spipe_w4"
57 #define VBC_CMD_TAG "VBC"
62 /* current mode and volume gain parameters.*/
64 VBC_CMD_RESP_MODE = 2,
67 VBC_CMD_RESP_GAIN = 4,
69 /* whether switch vb control to dsp parameters.*/
70 VBC_CMD_SWITCH_CTRL = 5,
71 VBC_CMD_RESP_SWITCH = 6,
73 /* whether mute or not.*/
75 VBC_CMD_RESP_MUTE = 8,
77 /* open/close device parameters.*/
78 VBC_CMD_DEVICE_CTRL = 9,
79 VBC_CMD_RESP_DEVICE = 10,
81 VBC_CMD_PCM_OPEN = 11,
82 VBC_CMD_RESP_OPEN =12,
84 VBC_CMD_PCM_CLOSE = 13,
85 VBC_CMD_RESP_CLOSE = 14,
87 VBC_CMD_SET_SAMPLERATE = 15,
88 VBC_CMD_RESP_SAMPLERATE = 16,
93 const static char* vbc_cmd_str_arry[VBC_CMD_MAX] = {"NONE", "SET_MODE", "RESP_MODE", "SET_GAIN", "RESP_GAIN", "SWITCH_CTL", "RESP_SWITCH",
94 "SET_MUTE", "RESP_MUTE", "DEVICE_CTL", "RESP_DEVICE", "PCM_OPEN", "RESP_OPEN", "PCM_CLOSE", "RESP_CLOSE", "SET_SAMPL", "RESP_SAMPL"};
97 unsigned int sim_card; /*sim card number*/
100 typedef struct _vbc_parameters_head {
102 unsigned int cmd_type;
103 unsigned int paras_size;
104 } vbc_parameters_head;
106 typedef struct vbc_control_params {
109 } vbc_control_params_t;
112 unsigned short is_open; /* if is_open is true, open device; else close device.*/
113 unsigned short is_headphone;
114 unsigned int is_downlink_mute;
115 unsigned int is_uplink_mute;
118 typedef struct samplerate_ctrl {
119 unsigned int samplerate; /* change samplerate.*/
123 unsigned int is_switch; /* switch vbc contrl to dsp.*/
126 static int __read_nonblock(int fd, void *buf, int bytes)
129 int bytes_to_read = bytes;
131 if ((fd > 0) && (buf != NULL)) {
133 ret = read(fd, buf, bytes);
138 } else if ((!((errno == EAGAIN) || (errno == EINTR))) || (0 == ret)) {
144 if (bytes == bytes_to_read)
147 return (bytes_to_read - bytes);
150 static int __write_nonblock(int fd, void *buf, int bytes)
153 int bytes_to_write = bytes;
155 if ((fd > 0) && (buf != NULL)) {
157 ret = write(fd, buf, bytes);
162 } else if ((!((errno == EAGAIN) || (errno == EINTR))) || (0 == ret)) {
168 if (bytes == bytes_to_write)
171 return (bytes_to_write - bytes);
175 int _audio_modem_is_call_connected(audio_hal_t *ah)
177 int val = -1; /* Mixer values 0 - cp [3g] ,1 - cp [2g] ,2 - ap */
179 _audio_mixer_control_get_value(ah, MIXER_VBC_SWITCH, &val);
180 AUDIO_LOG_INFO("modem is connected for call = %d", (val == VBC_TD_CHANNELID));
182 return (val == VBC_TD_CHANNELID) ? 1 : 0;
185 static int __voice_read_samplerate(int fd, set_samplerate_t *paras_ptr)
188 if (fd > 0 && paras_ptr != NULL) {
189 ret = __read_nonblock(fd, paras_ptr, sizeof(set_samplerate_t));
190 if (ret != sizeof(set_samplerate_t))
193 AUDIO_LOG_INFO("Return value of read sample rate = %d", ret);
198 static int __voice_get_samplerate(audio_hal_t *ah, int fd)
200 set_samplerate_t samplerate_paras;
202 memset(&samplerate_paras, 0, sizeof(set_samplerate_t));
203 __voice_read_samplerate(fd, &samplerate_paras);
205 if (samplerate_paras.samplerate <= 0)
206 ah->modem.samplerate = 8000;
208 ah->modem.samplerate = samplerate_paras.samplerate;
213 static int __vbc_write_response(int fd, unsigned int cmd, uint32_t paras_size)
216 vbc_parameters_head write_head;
218 memset(&write_head, 0, sizeof(vbc_parameters_head));
219 memcpy(&write_head.tag[0], VBC_CMD_TAG, 3);
220 write_head.cmd_type = cmd + 1;
221 write_head.paras_size = paras_size;
223 ret = __write_nonblock(fd, (void*)&write_head, sizeof(vbc_parameters_head));
225 AUDIO_LOG_ERROR("write failed");
227 AUDIO_LOG_DEBUG("write success for VBC_CMD_[%s]", vbc_cmd_str_arry[cmd]);
233 static void i2s_pin_mux_sel(audio_hal_t *ah, int type)
235 audio_return_t ret = AUDIO_RET_OK;
236 audio_modem_t *modem;
239 AUDIO_LOG_ERROR("ah is null");
243 AUDIO_LOG_INFO("type is %d",type);
244 modem = ah->modem.cp;
246 if (type == FM_IIS) {
247 _audio_mixer_control_set_value(ah,
248 PIN_SWITCH_IIS0_SYS_SEL, PIN_SWITCH_IIS0_VBC_ID);
252 if(ah->device.active_out & AUDIO_DEVICE_OUT_BT_SCO) {
253 if(modem->i2s_bt.is_ext) {
254 if(modem->i2s_bt.is_switch) {
255 ret = _audio_mixer_control_set_value(ah,
256 PIN_SWITCH_IIS0_SYS_SEL, PIN_SWITCH_IIS0_CP0_ID);
259 if(modem->i2s_bt.is_switch) {
261 _audio_mixer_control_get_value (ah, PIN_SWITCH_IIS0_SYS_SEL, &value);
262 if(value == PIN_SWITCH_IIS0_CP0_ID) {
263 ret = _audio_mixer_control_set_value(ah,
264 PIN_SWITCH_IIS0_SYS_SEL, PIN_SWITCH_IIS0_AP_ID);
267 if(ah->device.active_out & AUDIO_DEVICE_OUT_BT_SCO) {
268 if(modem->i2s_bt.is_switch) {
269 ret = _audio_mixer_control_set_value(ah,
270 PIN_SWITCH_BT_IIS_SYS_SEL, PIN_SWITCH_BT_IIS_CP0_IIS0_ID);
275 } else if (type == 1) {
276 if(ah->device.active_out & AUDIO_DEVICE_OUT_BT_SCO) {
277 if(modem->i2s_bt.is_ext) {
278 if(modem->i2s_bt.is_switch) {
279 ret = _audio_mixer_control_set_value(ah,
280 PIN_SWITCH_IIS0_SYS_SEL, PIN_SWITCH_IIS0_CP1_ID);
283 if(modem->i2s_bt.is_switch) {
285 _audio_mixer_control_get_value (ah, PIN_SWITCH_IIS0_SYS_SEL, &value);
286 if(value == PIN_SWITCH_IIS0_CP1_ID) {
287 ret = _audio_mixer_control_set_value(ah,
288 PIN_SWITCH_IIS0_SYS_SEL, PIN_SWITCH_IIS0_CP2_ID);
291 if(ah->device.active_out & AUDIO_DEVICE_OUT_BT_SCO) {
292 if(modem->i2s_bt.is_switch) {
293 ret = _audio_mixer_control_set_value(ah,
294 PIN_SWITCH_BT_IIS_SYS_SEL, PIN_SWITCH_BT_IIS_CP1_IIS0_ID);
300 AUDIO_LOG_ERROR("invalid type");
304 AUDIO_LOG_ERROR("error(0x%x)", ret);
309 static void *__vbc_control_voice_thread_run(void *args)
311 audio_return_t audio_ret = AUDIO_RET_OK;
312 vbc_parameters_head read_head;
313 vbc_parameters_head write_head;
314 int exit_thread = 0; /* make exit variable global if required to gracefully exit */
316 vbc_control_params_t *params = (vbc_control_params_t*)args;
317 if (params == NULL) {
318 return (void*)AUDIO_ERR_PARAMETER;
320 audio_hal_t *ah = params->ah;
322 struct timeval timeout = {5,0};
324 memset(&read_head, 0, sizeof(vbc_parameters_head));
325 memset(&write_head, 0, sizeof(vbc_parameters_head));
327 memcpy(&write_head.tag[0], VBC_CMD_TAG, 3);
328 write_head.cmd_type = VBC_CMD_NONE;
329 write_head.paras_size = 0;
331 AUDIO_LOG_INFO("[voice] vbc control VOICE thread run");
334 /* open vbpipe device for vb parameter interface between ap and cp */
335 vbpipe_fd = open(VBPIPE_DEVICE, O_RDWR);
339 AUDIO_LOG_ERROR("[voice] vbpipe open failed: %s", strerror(errno));
340 return (void*)AUDIO_ERR_IOCTL;
342 ah->modem.vbc.vbpipe_fd = vbpipe_fd;
344 if (fcntl(vbpipe_fd, F_SETFL, O_NONBLOCK) < 0) {
345 AUDIO_LOG_DEBUG("[voice] vbpipe_fd(%d) fcntl error.", vbpipe_fd);
348 AUDIO_LOG_INFO("[voice] %s opened. vbc start loop", VBPIPE_DEVICE);
351 while (!exit_thread) {
356 /* read command received from cp */
358 FD_SET(vbpipe_fd, &fds_read);
360 ret = select(vbpipe_fd+1, &fds_read, NULL, NULL, &timeout);
362 ALOGE("voice:select error %d", errno);
367 ret = __read_nonblock(vbpipe_fd, &read_head, sizeof(vbc_parameters_head));
373 AUDIO_LOG_DEBUG("[voice] Received %d bytes. data: %s, cmd_type: %d", ret, read_head.tag, read_head.cmd_type);
375 if (!memcmp(&read_head.tag[0], VBC_CMD_TAG, 3)) {
376 switch (read_head.cmd_type) {
377 case VBC_CMD_PCM_OPEN: {
378 open_pcm_t open_pcm_params;
379 uint32_t paras_size = ((ah->modem.cp->i2s_bt.is_switch << 8) | (ah->modem.cp->i2s_bt.index << 0)
380 | (ah->modem.cp->i2s_extspk.is_switch << 9) | (ah->modem.cp->i2s_extspk.index << 4));
382 AUDIO_LOG_INFO("[voice] Received VBC_CMD_PCM_OPEN");
384 ah->modem.is_connected = 1;
385 audio_ret = _audio_do_route_voicecall(ah, ah->device.init_call_devices, ah->device.num_of_call_devices);
386 if (AUDIO_IS_ERROR(audio_ret)) {
387 AUDIO_LOG_WARN("set voicecall route return 0x%x", audio_ret);
388 if (audio_ret == AUDIO_ERR_INVALID_STATE) {
389 /* send signal and wait for the ucm setting,
390 * it might an incoming call scenario */
391 _audio_comm_send_message(ah, SIGNAL_ROUTING_FOR_VOICE_CALL, 1);
392 COND_TIMEDWAIT(ah->device.device_cond, ah->device.device_lock, "device_cond", TIMEOUT_SEC);
393 MUTEX_UNLOCK(ah->device.device_lock, "device_lock");
397 memset(&open_pcm_params, 0, sizeof(open_pcm_t));
398 ret = __read_nonblock(vbpipe_fd, &open_pcm_params, sizeof(open_pcm_t));
400 AUDIO_LOG_ERROR("read failed");
402 ah->modem.sim_id = open_pcm_params.sim_card;
404 if (ah->device.active_out & (AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_OUT_BT_SCO)) {
405 if (ah->modem.cp_type == CP_TG)
406 i2s_pin_mux_sel(ah, 1);
407 else if(ah->modem.cp_type == CP_W)
408 i2s_pin_mux_sel(ah, 0);
411 AUDIO_LOG_DEBUG("[voice] Send response for VBC_CMD_PCM_OPEN");
412 __vbc_write_response(vbpipe_fd, VBC_CMD_PCM_OPEN, paras_size);
416 case VBC_CMD_PCM_CLOSE: {
417 AUDIO_LOG_INFO("[voice] Received VBC_CMD_PCM_CLOSE");
419 ah->modem.samplerate = 0;
420 ah->modem.is_connected = 0;
422 /* send signal and wait for the reset ucm */
423 _audio_comm_send_message(ah, SIGNAL_ROUTING_FOR_VOICE_CALL, 0);
424 COND_TIMEDWAIT(ah->device.device_cond, ah->device.device_lock, "device_cond", TIMEOUT_SEC);
425 MUTEX_UNLOCK(ah->device.device_lock, "device_lock");
427 _audio_mixer_control_set_value(ah, MIXER_VBC_SWITCH, VBC_ARM_CHANNELID);
429 AUDIO_LOG_DEBUG("[voice] Send response for VBC_CMD_PCM_CLOSE");
430 __vbc_write_response(vbpipe_fd, VBC_CMD_PCM_CLOSE, 0);
434 case VBC_CMD_RESP_CLOSE: {
435 AUDIO_LOG_INFO("[voice] Received VBC_CMD_RESP_CLOSE & send response");
436 ret = __vbc_write_response(vbpipe_fd, VBC_CMD_PCM_CLOSE, 0);
440 case VBC_CMD_SET_MODE: {
442 memset(dummy, 0, sizeof(dummy));
443 AUDIO_LOG_INFO("[voice] Received VBC_CMD_SET_MODE");
445 if (ah->device.active_out & (AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_OUT_BT_SCO)) {
446 if (ah->modem.cp_type == CP_TG)
447 i2s_pin_mux_sel(ah, 1);
448 else if(ah->modem.cp_type == CP_W)
449 i2s_pin_mux_sel(ah, 0);
451 /* To do: set mode params : __vbc_set_mode_params(ah, vbpipe_fd); */
453 __read_nonblock(vbpipe_fd, dummy, sizeof(dummy));
454 AUDIO_LOG_DEBUG("[voice] Send response for VBC_CMD_SET_MODE");
455 __vbc_write_response(vbpipe_fd, VBC_CMD_SET_MODE, 0);
458 case VBC_CMD_SET_GAIN: {
459 AUDIO_LOG_INFO("[voice] Received VBC_CMD_SET_GAIN");
461 /* To do: set gain params : __vbc_set_gain_params(ah, vbpipe_fd); */
463 AUDIO_LOG_DEBUG("[voice] Send response for VBC_CMD_SET_GAIN");
464 __vbc_write_response(vbpipe_fd, VBC_CMD_SET_GAIN, 0);
467 case VBC_CMD_SWITCH_CTRL: {
468 switch_ctrl_t switch_ctrl_params;
470 AUDIO_LOG_INFO("[voice] Received VBC_CMD_SWITCH_CTRL");
472 memset(&switch_ctrl_params,0,sizeof(switch_ctrl_t));
473 ret = __read_nonblock(vbpipe_fd, &switch_ctrl_params, sizeof(switch_ctrl_t));
475 AUDIO_LOG_ERROR("read failed");
477 AUDIO_LOG_INFO("is_switch:%d", switch_ctrl_params.is_switch);
479 _audio_mixer_control_set_value(ah, MIXER_VBC_SWITCH, VBC_TD_CHANNELID);
481 AUDIO_LOG_DEBUG("[voice] Send response for VBC_CMD_SET_GAIN");
482 __vbc_write_response(vbpipe_fd, VBC_CMD_SWITCH_CTRL, 0);
485 case VBC_CMD_SET_MUTE: {
486 AUDIO_LOG_INFO("[voice] Received VBC_CMD_SET_MUTE");
489 case VBC_CMD_DEVICE_CTRL: {
491 memset(dummy, 0, sizeof(dummy));
492 AUDIO_LOG_INFO("[voice] Received VBC_CMD_DEVICE_CTRL");
494 /* To do: set device ctrl params :__vbc_set_device_ctrl_params(ah, vbpipe_fd); */
495 __read_nonblock(vbpipe_fd, dummy, sizeof(dummy));
497 AUDIO_LOG_DEBUG("[voice] Send response for VBC_CMD_DEVICE_CTRL");
498 __vbc_write_response(vbpipe_fd, VBC_CMD_DEVICE_CTRL, 0);
502 case VBC_CMD_SET_SAMPLERATE: {
503 AUDIO_LOG_INFO("[voice] Received VBC_CMD_SET_SAMPLERATE");
505 // _voice_pcm_close(ah, 0);
507 // __voice_get_samplerate(ah, vbpipe_fd);
509 // ret = _voice_pcm_open(ah);
511 // _voice_pcm_close(ah, 1);
515 AUDIO_LOG_DEBUG("[voice] Send response for VBC_CMD_SET_SAMPLERATE");
516 __vbc_write_response(vbpipe_fd, VBC_CMD_SET_SAMPLERATE, 0);
520 AUDIO_LOG_WARN("[voice] Unknown command received : %d", read_head.cmd_type);
530 AUDIO_LOG_INFO("Exit vbc VOICE thread");
535 static void *__vbc_control_voip_thread_run(void *args)
537 open_pcm_t open_pcm_params;
538 vbc_parameters_head read_head;
539 vbc_parameters_head write_head;
540 int exit_thread = 0; /* make exit variable global if required to gracefully exit */
542 vbc_control_params_t *params = (vbc_control_params_t*)args;
543 if (params == NULL) {
544 return (void*)AUDIO_ERR_PARAMETER;
546 audio_hal_t *ah = params->ah;
549 struct timeval timeout = {5,0};
551 memset(&read_head, 0, sizeof(vbc_parameters_head));
552 memset(&write_head, 0, sizeof(vbc_parameters_head));
554 memcpy(&write_head.tag[0], VBC_CMD_TAG, 3);
555 write_head.cmd_type = VBC_CMD_NONE;
556 write_head.paras_size = 0;
558 AUDIO_LOG_INFO("[voip] vbc control VOIP thread run");
561 /* open vbpipe device for vb parameter interface between ap and cp */
562 vbpipe_fd = open(VBPIPE_VOIP_DEVICE, O_RDWR);
566 AUDIO_LOG_ERROR("[voip] vbpipe open failed: %s", strerror(errno));
569 ah->modem.vbc.vbpipe_voip_fd = vbpipe_fd;
571 if (fcntl(vbpipe_fd, F_SETFL, O_NONBLOCK) < 0) {
572 AUDIO_LOG_DEBUG("[voip] vbpipe_fd(%d) fcntl error.", vbpipe_fd);
575 AUDIO_LOG_INFO("[voip] %s opened. vbc start loop", VBPIPE_VOIP_DEVICE);
578 while (!exit_thread) {
583 /* read command received from cp */
586 FD_SET(vbpipe_fd, &fds_read);
588 ret = select(vbpipe_fd+1, &fds_read, NULL, NULL, &timeout);
590 ALOGE("[voip] select error %d", errno);
594 ret = __read_nonblock(vbpipe_fd, &read_head, sizeof(vbc_parameters_head));
599 AUDIO_LOG_DEBUG("[voip] Received %d bytes. data: %s, cmd_type: %d", ret, read_head.tag, read_head.cmd_type);
601 if (!memcmp(&read_head.tag[0], VBC_CMD_TAG, 3)) {
602 switch (read_head.cmd_type) {
603 case VBC_CMD_PCM_OPEN: {
604 uint32_t paras_size = ((ah->modem.cp->i2s_bt.is_switch << 8) | (ah->modem.cp->i2s_bt.index << 0)
605 | (ah->modem.cp->i2s_extspk.is_switch << 9) | (ah->modem.cp->i2s_extspk.index << 4));
607 AUDIO_LOG_INFO("[voip] Received VBC_CMD_PCM_OPEN");
609 memset(&open_pcm_params, 0, sizeof(open_pcm_t));
610 ret = __read_nonblock(vbpipe_fd, &open_pcm_params, sizeof(open_pcm_t));
612 AUDIO_LOG_ERROR("read failed");
614 AUDIO_LOG_DEBUG("[voip] Send response for VBC_CMD_PCM_OPEN");
615 __vbc_write_response(vbpipe_fd, VBC_CMD_PCM_OPEN, paras_size);
618 case VBC_CMD_PCM_CLOSE: {
619 AUDIO_LOG_INFO("[voip] Received VBC_CMD_PCM_CLOSE & send response");
621 __vbc_write_response(vbpipe_fd, VBC_CMD_PCM_CLOSE, 0);
625 case VBC_CMD_RESP_CLOSE: {
626 AUDIO_LOG_INFO("[voip] Received VBC_CMD_RESP_CLOSE & send response");
628 ret = __vbc_write_response(vbpipe_fd, VBC_CMD_PCM_CLOSE, 0);
631 case VBC_CMD_SET_MODE: {
632 AUDIO_LOG_INFO("[voip] Received VBC_CMD_SET_MODE");
634 if (ah->device.active_out & (AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_OUT_BT_SCO)) {
635 if (ah->modem.cp_type == CP_TG)
636 i2s_pin_mux_sel(ah, 1);
637 else if(ah->modem.cp_type == CP_W)
638 i2s_pin_mux_sel(ah, 0);
640 /* To do: set mode params : __vbc_set_mode_params(ah, vbpipe_fd); */
641 AUDIO_LOG_DEBUG("[voip] Send response for VBC_CMD_SET_MODE");
642 __vbc_write_response(vbpipe_fd, VBC_CMD_SET_MODE, 0);
645 case VBC_CMD_SET_GAIN: {
646 AUDIO_LOG_INFO("[voip] Received VBC_CMD_SET_GAIN");
648 /* To do: set gain params : __vbc_set_gain_params(ah, vbpipe_fd); */
649 AUDIO_LOG_DEBUG("[voip] Send response for VBC_CMD_SET_GAIN");
650 __vbc_write_response(vbpipe_fd, VBC_CMD_SET_GAIN, 0);
653 case VBC_CMD_SWITCH_CTRL: {
654 switch_ctrl_t switch_ctrl_params;
656 AUDIO_LOG_INFO("[voip] Received VBC_CMD_SWITCH_CTRL");
658 memset(&switch_ctrl_params, 0, sizeof(switch_ctrl_t));
659 ret = __read_nonblock(vbpipe_fd, &switch_ctrl_params, sizeof(switch_ctrl_t));
661 AUDIO_LOG_ERROR("read failed");
663 AUDIO_LOG_INFO("is_switch:%d", switch_ctrl_params.is_switch);
665 _audio_mixer_control_set_value(ah, MIXER_VBC_SWITCH, VBC_TD_CHANNELID);
667 AUDIO_LOG_DEBUG("[voip] Send response for VBC_CMD_SWITCH_CTRL");
668 __vbc_write_response(vbpipe_fd, VBC_CMD_SWITCH_CTRL, 0);
671 case VBC_CMD_SET_MUTE: {
672 AUDIO_LOG_INFO("[voip] Received VBC_CMD_SET_MUTE & send response");
673 __vbc_write_response(vbpipe_fd, VBC_CMD_SET_MUTE, 0);
676 case VBC_CMD_DEVICE_CTRL: {
677 AUDIO_LOG_INFO("[voip] Received VBC_CMD_DEVICE_CTRL");
678 __vbc_write_response(vbpipe_fd, VBC_CMD_DEVICE_CTRL, 0);
681 case VBC_CMD_SET_SAMPLERATE: {
682 AUDIO_LOG_INFO("[voip] Received VBC_CMD_SET_SAMPLERATE");
684 // _voice_pcm_close(ah, 0);
685 // __voice_get_samplerate(ah, vbpipe_fd);
687 // ret = _voice_pcm_open(ah);
689 // _voice_pcm_close(ah, 1);
692 AUDIO_LOG_DEBUG("[voip] Send response for VBC_CMD_SET_SAMPLERATE");
693 __vbc_write_response(vbpipe_fd, VBC_CMD_SET_SAMPLERATE, 0);
697 AUDIO_LOG_WARN("Unknown command received : %d", read_head.cmd_type);
706 AUDIO_LOG_INFO("Exit vbc VOIP thread");
711 static audio_return_t __vbc_control_open(audio_hal_t *ah)
713 vbc_control_params_t *params = (vbc_control_params_t*)malloc(sizeof(vbc_control_params_t));
714 audio_return_t ret = AUDIO_RET_OK;
715 audio_return_t ret2 = AUDIO_RET_OK;
717 if (params == NULL) {
718 AUDIO_LOG_ERROR("vbc control param allocation failed");
719 return AUDIO_ERR_RESOURCE;
723 AUDIO_LOG_INFO("vbc control thread create");
724 ret = vbc_thread_new(&ah->modem.vbc.voice_thread_handle, NULL, __vbc_control_voice_thread_run, (void*)params);
726 AUDIO_LOG_ERROR("vbc control thread create failed");
727 ret = AUDIO_ERR_RESOURCE;
731 ret2 = vbc_thread_new(&ah->modem.vbc.voip_thread_handle, NULL, __vbc_control_voip_thread_run, (void*)params);
733 AUDIO_LOG_ERROR("vbc control VOIP thread create failed");
734 ret2 = AUDIO_ERR_RESOURCE;
741 static audio_return_t __vbc_control_close(audio_hal_t *ah)
743 /* TODO. Make sure we always receive CLOSE command from modem and then close pcm device */
744 ah->modem.vbc.exit_vbc_thread = 1;
745 close(ah->modem.vbc.vbpipe_fd);
747 pthread_cancel(ah->modem.vbc.voice_thread_handle);
748 pthread_cancel(ah->modem.vbc.voip_thread_handle);
753 static vbc_ctrl_pipe_para_t *__audio_modem_create(audio_modem_t *modem, const char *num)
755 if (!atoi((char *)num)) {
756 AUDIO_LOG_ERROR("Unnormal modem num!");
760 modem->num = atoi((char *)num);
761 /* check if we need to allocate space for modem profile */
762 if(!modem->vbc_ctrl_pipe_info) {
763 modem->vbc_ctrl_pipe_info = malloc(modem->num * sizeof(vbc_ctrl_pipe_para_t));
765 if (modem->vbc_ctrl_pipe_info == NULL) {
766 AUDIO_LOG_ERROR("Unable to allocate modem profiles");
769 /* initialise the new profile */
770 memset((void*)modem->vbc_ctrl_pipe_info, 0x00, modem->num * sizeof(vbc_ctrl_pipe_para_t));
774 AUDIO_LOG_DEBUG("peter: modem num is %d",modem->num);
775 /* return the profile just added */
776 return modem->vbc_ctrl_pipe_info;
780 static void __audio_modem_start_tag(void *data, const XML_Char *tag_name,
781 const XML_Char **attr)
783 struct modem_config_parse_state *state = data;
784 audio_modem_t *modem = state->modem_info;
787 if (strcmp(tag_name, "audio") == 0) {
788 if (strcmp(attr[0], "device") == 0) {
789 AUDIO_LOG_INFO("The device name is %s", attr[1]);
791 AUDIO_LOG_ERROR("Unnamed audio!");
793 } else if (strcmp(tag_name, "modem") == 0) {
794 /* Obtain the modem num */
795 if (strcmp(attr[0], "num") == 0) {
796 AUDIO_LOG_DEBUG("The modem num is '%s'", attr[1]);
797 state->vbc_ctrl_pipe_info = __audio_modem_create(modem, attr[1]);
799 AUDIO_LOG_ERROR("no modem num!");
801 } else if (strcmp(tag_name, "cp") == 0) {
802 if (state->vbc_ctrl_pipe_info) {
803 /* Obtain the modem name \pipe\vbc filed */
804 if (strcmp(attr[0], "name") != 0) {
805 AUDIO_LOG_ERROR("Unnamed modem!");
808 if (strcmp(attr[2], "pipe") != 0) {
809 AUDIO_LOG_ERROR("'%s' No pipe filed!", attr[0]);
812 if (strcmp(attr[4], "vbchannel") != 0) {
813 AUDIO_LOG_ERROR("'%s' No vbc filed!", attr[0]);
816 AUDIO_LOG_DEBUG("cp name is '%s', pipe is '%s',vbc is '%s'", attr[1], attr[3],attr[5]);
817 if(strcmp(attr[1], "w") == 0)
819 state->vbc_ctrl_pipe_info->cp_type = CP_W;
821 else if(strcmp(attr[1], "t") == 0)
823 state->vbc_ctrl_pipe_info->cp_type = CP_TG;
825 memcpy((void*)state->vbc_ctrl_pipe_info->s_vbc_ctrl_pipe_name,(void*)attr[3],strlen((char *)attr[3]));
826 state->vbc_ctrl_pipe_info->channel_id = atoi((char *)attr[5]);
827 state->vbc_ctrl_pipe_info++;
830 AUDIO_LOG_ERROR("error profile!");
832 } else if (strcmp(tag_name, "i2s_for_btcall") == 0) {
833 if (strcmp(attr[0], "index") == 0) {
834 AUDIO_LOG_DEBUG("The iis_for_btcall index is '%s'", attr[1]);
835 modem->i2s_bt.index = atoi((char *)attr[1]);
837 AUDIO_LOG_ERROR("no iis_ctl index for bt call!");
840 if (strcmp(attr[2], "switch") == 0) {
841 AUDIO_LOG_DEBUG("The iis_for_btcall switch is '%s'", attr[3]);
842 if(strcmp(attr[3],"1") == 0)
843 modem->i2s_bt.is_switch = true;
844 else if(strcmp(attr[3],"0") == 0)
845 modem->i2s_bt.is_switch = false;
847 AUDIO_LOG_ERROR("no iis_ctl switch for bt call!");
849 if (strcmp(attr[4], "dst") == 0) {
850 AUDIO_LOG_DEBUG("The iis_for_btcall dst is '%s'", attr[5]);
851 if (strcmp(attr[5], "internal") == 0)
852 modem->i2s_bt.is_ext = 0;
853 else if (strcmp(attr[5], "external") == 0)
854 modem->i2s_bt.is_ext = 1;
856 AUDIO_LOG_ERROR("no dst path for bt call!");
858 } else if (strcmp(tag_name, "i2s_for_extspeaker") == 0) {
859 if (strcmp(attr[0], "index") == 0) {
860 AUDIO_LOG_DEBUG("The i2s_for_extspeaker index is '%s'", attr[1]);
861 modem->i2s_extspk.index = atoi((char *)attr[1]);
863 AUDIO_LOG_ERROR("no iis_ctl index for extspk call!");
865 if (strcmp(attr[2], "switch") == 0) {
866 AUDIO_LOG_DEBUG("The iis_for_btcall switch is '%s'", attr[3]);
867 if(strcmp(attr[3],"1") == 0)
868 modem->i2s_extspk.is_switch = true;
869 else if(strcmp(attr[3],"0") == 0)
870 modem->i2s_extspk.is_switch = false;
872 AUDIO_LOG_ERROR("no iis_ctl switch for extspk call!");
874 if (strcmp(attr[4], "dst") == 0) {
875 if (strcmp(attr[5], "external") == 0)
876 modem->i2s_extspk.is_ext = 1;
877 else if(strcmp(attr[5], "internal") == 0)
878 modem->i2s_extspk.is_ext = 0;
880 AUDIO_LOG_DEBUG("The i2s_for_extspeaker dst is '%d'", modem->i2s_extspk.is_ext);
883 AUDIO_LOG_ERROR("no dst path for bt call!");
885 } else if (strcmp(tag_name, "debug") == 0) { //parse debug info
886 if (strcmp(attr[0], "enable") == 0) {
887 if (strcmp(attr[1], "0") == 0) {
888 modem->debug_info.enable = 0;
890 modem->debug_info.enable = 1;
893 AUDIO_LOG_ERROR("no adaptable type for debug!");
896 } else if (strcmp(tag_name, "debuginfo") == 0) { //parse debug info
897 if (strcmp(attr[0], "sleepdeltatimegate") == 0) {
898 AUDIO_LOG_DEBUG("The sleepdeltatimegate is '%s'", attr[1]);
899 modem->debug_info.sleeptime_gate=atoi((char *)attr[1]);
900 } else if (strcmp(attr[0], "pcmwritetimegate") == 0) {
901 AUDIO_LOG_DEBUG("The pcmwritetimegate is '%s'", attr[1]);
902 modem->debug_info.pcmwritetime_gate=atoi((char *)attr[1]);
903 } else if (strcmp(attr[0], "lastthiswritetimegate") == 0) {
904 AUDIO_LOG_DEBUG("The lastthiswritetimegate is '%s'", attr[1]);
905 modem->debug_info.lastthis_outwritetime_gate=atoi((char *)attr[1]);
907 AUDIO_LOG_ERROR("no adaptable info for debuginfo!");
915 static void __audio_modem_end_tag(void *data, const XML_Char *tag_name)
920 struct config_parse_state {
921 audio_modem_t *modem_info;
922 /* To do : pga control setting*/
923 /* struct audio_pga *pga; */
924 /* struct pga_profile *profile; */
925 /* struct pga_attribute_item *attribute_item; */
927 static audio_modem_t * __audio_modem_parse (void)
929 struct config_parse_state state;
934 audio_modem_t *modem = NULL;
936 modem = calloc(1, sizeof(audio_modem_t));
941 memset(modem, 0, sizeof(audio_modem_t));
943 modem->vbc_ctrl_pipe_info = NULL;
945 file = fopen(AUDIO_XML_PATH, "r");
947 AUDIO_LOG_ERROR("Failed to open %s", AUDIO_XML_PATH);
951 parser = XML_ParserCreate(NULL);
953 AUDIO_LOG_ERROR("Failed to create XML parser");
954 goto err_parser_create;
957 memset(&state, 0, sizeof(state));
958 state.modem_info = modem;
959 XML_SetUserData(parser, &state);
960 XML_SetElementHandler(parser, __audio_modem_start_tag, __audio_modem_end_tag);
963 buf = XML_GetBuffer(parser, BUF_SIZE);
967 bytes_read = fread(buf, 1, BUF_SIZE, file);
971 if (XML_ParseBuffer(parser, bytes_read, bytes_read == 0) == XML_STATUS_ERROR) {
972 AUDIO_LOG_ERROR("Error in codec PGA xml (%s)", AUDIO_XML_PATH);
979 XML_ParserFree(parser);
984 XML_ParserFree(parser);
994 audio_return_t _audio_modem_init(audio_hal_t *ah)
996 audio_return_t audio_ret = AUDIO_RET_OK;
998 AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
1000 ah->modem.vbc.vbpipe_count = 0;
1002 /* Initialize vbc interface */
1003 audio_ret = __vbc_control_open(ah);
1004 if (AUDIO_IS_ERROR(audio_ret)) {
1005 AUDIO_LOG_ERROR("__vbc_control_open failed");
1008 ah->modem.vbc.voice_pcm_handle_p = NULL;
1009 ah->modem.vbc.voice_pcm_handle_c = NULL;
1010 ah->modem.samplerate = 0;
1011 ah->modem.cp = __audio_modem_parse();
1012 if (ah->modem.cp == NULL) {
1013 AUDIO_LOG_ERROR("modem parse failed");
1016 ah->modem.cp_type = ah->modem.cp->vbc_ctrl_pipe_info->cp_type;
1018 /* This ctrl need to be set "0" always - SPRD */
1019 _audio_mixer_control_set_value(ah, PIN_SWITCH_BT_IIS_CON_SWITCH, 0);
1025 audio_return_t _audio_modem_deinit(audio_hal_t *ah)
1027 AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
1029 /* Close vbc interface */
1030 __vbc_control_close(ah);
1032 return AUDIO_RET_OK;