blob: 8fea8219ed13bbae416d48ce837edb0ce7cb0c1e [file] [log] [blame]
/* Copyright Statement:
*
* This software/firmware and related documentation ("MediaTek Software") are
* protected under relevant copyright laws. The information contained herein
* is confidential and proprietary to MediaTek Inc. and/or its licensors.
* Without the prior written permission of MediaTek inc. and/or its licensors,
* any reproduction, modification, use or disclosure of MediaTek Software,
* and information contained herein, in whole or in part, shall be strictly prohibited.
*/
/* MediaTek Inc. (C) 2010. All rights reserved.
*
* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
*
* The following software/firmware and/or related documentation ("MediaTek Software")
* have been modified by MediaTek Inc. All revisions are subject to any receiver's
* applicable license agreements with MediaTek Inc.
*/
#include "cc.h"
#include <alloca.h>
#include <stdlib.h>
#include <stdio.h>
#include <cutils/jstring.h>
#include <stdbool.h>
#include <glib.h>
#include <string.h>
#include <string>
#include <thread>
#include "eCall.h"
static int dtmf_volume = 0;
void *dtmf_handle = NULL;
extern "C" {
#include <dtmf.h>
#include "mixer_ctrl.h"
}
#undef LOG_TAG
#define LOG_TAG "DEMO_CC"
static speech_status speechStatus = SPEECH_OFF;
int autoAnswerMode = 0;
static int inCallRecordMode = 0;
static call_status inCallstatus = CALL_OFF;
//int callIndex = 0;
const char g_card_name[] = "mtk_phonecall";
/*for speech on*/
const char g_mixer_name[] = "Speech_on";
const char g_mixer_name_ecall[] = "Speech_on_ecall";
const char g_mixer_reset_name[] = "Modem_reset_notify";
const char g_mixer_name_bt[] = "Speech_on_bt";
const char g_bt_has_ecnr_name[] = "BT_HAS_ECNR";
const char g_bt_wbs_name[] = "BT_WBS";
int g_audio_path = 0; // 0: normal, 1: bt
int g_bt_has_ecnr_value = 0; // 0: ecnr, 1, no ecnr
int g_bt_wbs_value = 0; // 0: 8000, 1, 16000
/*for DL call volume*/
const char g_mixer_name_volume[] = "DL Call";
const char g_mixer_name_volume_bt[] = "DL BT";
const char g_DL_mute_name[] = "Speech_DL_mute";
const char g_UL_mute_name[] = "Speech_UL_mute";
const char *RING_PATH = "/system/etc/tele/ring/ring.wav";
static bool isRingStart = false;
#if defined(TARGET_PLATFORM_MT2731)||defined(TARGET_PLATFORM_MT2735)
#define MAX_VOLUME (6)
#define MIN_VOLUME (0)
#endif
#ifdef TARGET_PLATFORM_MT2635
#define MAX_VOLUME (17)
#define MIN_VOLUME (-23)
#endif
#define BT_MAX_VOLUME (15)
#define BT_MIN_VOLUME (0)
#define DTMF_MAX_VOLUME (36)
#define DTMF_MIN_VOLUME (0)
int get_call_status(void)
{
return inCallstatus;
}
void set_audio_path(int path)
{
if ((path != 0) && (path != 1)) {
RLOGE("set_audio_path() illegal value %d, we support 0: normal, 1: bt", path);
return;
}
g_audio_path = path;
}
int get_audio_path(void)
{
return g_audio_path;
}
void set_bt_has_ecnr(int ecnr)
{
if ((ecnr != 0) && (ecnr != 1)) {
RLOGE("set_bt_has_ecnr() illegal value %d, we support 0: do ecnr, 1: no ecnr", ecnr);
return;
}
g_bt_has_ecnr_value = ecnr;
}
int get_bt_has_ecnr(void)
{
return g_bt_has_ecnr_value;
}
void set_bt_wbs(int wbs)
{
if ((wbs < 0) || (wbs > 15)) {
RLOGE("set_bt_wbs() illegal value %d, we support 0~15", wbs);
return;
}
g_bt_wbs_value = wbs;
}
int get_bt_wbs(void)
{
return g_bt_wbs_value;
}
int mixer_init()
{
int ret;
// only need to set card name once
ret = set_card_name(g_card_name);
RLOGD("mixer_init(%s) = %d", g_card_name, ret);
return ret;
}
int mixer_set(int value )
{
int ret;
//set mixer ctl to om:1 or off:0
if(value){
ret = set_mixer_ctrl_value_int(isEcallAudioPath() ? g_mixer_name_ecall: g_mixer_name, value);
RLOGD("mixer_set(%s) = %d, ret: %d", (isEcallAudioPath() ? g_mixer_name_ecall: g_mixer_name), value, ret);
} else {
//setEcallAudioPathOn(false);
ret = get_mixer_ctrl_value_int(g_mixer_name);
RLOGD("mixer_set(get_mixer_ctrl_value_int: %s) = %d", g_mixer_name, ret);
if(ret == 0) {
ret = set_mixer_ctrl_value_int(g_mixer_name, value);
RLOGD("mixer_set(%s) = %d", g_mixer_name, ret);
} else {
ret = set_mixer_ctrl_value_int(g_mixer_name_ecall, value);
RLOGD("mixer_set(%s) = %d", g_mixer_name_ecall, ret);
}
}
return ret;
}
int mixer_reset_set(int value )
{
int ret;
// set mixer to reset:1
ret = set_mixer_ctrl_value_int(g_mixer_reset_name, value);
RLOGD("mixer_reset_set(%s) = %d", g_mixer_reset_name, ret);
return ret;
}
int bt_mixer_set(int value)
{
int ret;
//set mixer ctrl to on:1 or off:0
// bt speech
int bt_has_ecnr = get_bt_has_ecnr();
int bt_wbs = get_bt_wbs();
ret = set_mixer_ctrl_value_int(g_bt_has_ecnr_name, bt_has_ecnr);
ret = set_mixer_ctrl_value_int(g_bt_wbs_name, bt_wbs);
ret = set_mixer_ctrl_value_int(g_mixer_name_bt, value);
if (ret)
RLOGE("set_mixer_ctrl_value_int err: %d", ret);
return ret;
}
int mixer_check(int mix)
{
int ret;
if (mix == 0) {
ret = get_mixer_ctrl_value_int(g_mixer_name);
} else if (mix == 1){
ret = get_mixer_ctrl_value_int(g_mixer_name_bt);
} else {
RLOGE("mixer_check wrong mix %d", mix);
}
RLOGD("The ctrl \"%s\" is set to %d ", g_mixer_name, ret);
return ret;
}
int mixer_set_volume(int value)
{
int ret;
if (get_audio_path() == 0) {
ret = set_mixer_ctrl_volume_value(g_mixer_name_volume, value);
} else {
ret = set_mixer_ctrl_volume_value(g_mixer_name_volume_bt, value);
}
if (ret)
RLOGE("set_mixer_ctrl_volume_value_int err: %d", ret);
return ret;
}
long int mixer_get_volume()
{
long int vol_value;
if (get_audio_path() == 0) {
vol_value = get_mixer_ctrl_volume_value(g_mixer_name_volume);
} else {
vol_value = get_mixer_ctrl_volume_value(g_mixer_name_volume_bt);
}
RLOGD("The ctrl \"%s\" is set to %d", g_mixer_name_volume, vol_value);
return vol_value;
}
GstElement *pipeline_element;
GstState gst_cur_state = GST_STATE_NULL;
static int gst_status = 0;
int GSM_Init(char* filepath)
{
GstElement *pipeline, *source, *mux, *encoder, *sink;
RLOGD("[GSM]GSM Init Start!");
/* Initialisation */
gst_init (NULL, NULL);
pipeline = gst_pipeline_new ("3gppmux-test");
source = gst_element_factory_make ("pulsesrc", "file-source");
encoder = gst_element_factory_make ("faac", "encoder");
mux = gst_element_factory_make ("3gppmux", "muxer");
sink = gst_element_factory_make ("filesink", "output");
g_object_set(mux, "fragment-duration", 100, NULL);
g_object_set(sink, "location", filepath, NULL);
if (!pipeline || !source || !encoder || !mux || !sink) {
if(pipeline) {
gst_object_unref (GST_OBJECT (pipeline));
pipeline = NULL;
}
if(source) {
gst_object_unref (GST_OBJECT (source));
source = NULL;
}
if(encoder) {
gst_object_unref (GST_OBJECT (encoder));
encoder = NULL;
}
if(mux) {
gst_object_unref (GST_OBJECT (mux));
mux = NULL;
}
if(sink) {
gst_object_unref (GST_OBJECT (sink));
sink = NULL;
}
RLOGE ("[GSM]One element could not be created. Exiting");
return -1;
}
gst_bin_add_many (GST_BIN (pipeline), source, encoder, mux, sink, NULL);
gst_element_link_many (source, encoder, mux, sink, NULL);
pipeline_element = pipeline;
gst_status = 1; //initial done
RLOGD("[GSM]GSM Init Done!");
return 0;
}
int GSM_Start(void)
{
RLOGD("[GSM]GSM Start start!");
if(gst_status == 2)
return 0;
if(gst_status == 1 || gst_status ==3) {
GstStateChangeReturn ret = gst_element_set_state (pipeline_element, GST_STATE_PLAYING);
RLOGD("[GSM]Running... return: %d", ret);
//g_main_loop_run (gst_loop);
gst_status = 2; //start done
} else {
return -1;
}
RLOGD("[GSM]GSM Start End!");
return 0;
}
int GSM_Stop()
{
RLOGD("[GSM]GSM Stop Start!");
if (gst_status == 4)
return 0;
if(gst_status == 2 || gst_status == 3) {
/* Out of the main loop, clean up nicely */
gboolean isSend = gst_element_send_event (pipeline_element, gst_event_new_eos ());
GstStateChangeReturn ret = gst_element_set_state (pipeline_element, GST_STATE_NULL);
RLOGD("[GSM]Returned, stopping playback. ret: %d, isSend: %d", ret, isSend);
gst_status = 4;
} else {
return -1;
}
RLOGD("[GSM]GSM Stop End!");
return 0;
}
int GSM_Close()
{
RLOGD("[GSM]Deleting pipeline");
gst_object_unref (GST_OBJECT (pipeline_element));
gst_deinit ();
gst_status = 0;
RLOGD("[GSM]GSM Close Done!");
return 0;
}
/*cmd:1, address,
*2, clirMode,
*3, if present, uusinfo.type
*4, as above, uusinfo.Dcs
*5, as above, uusinfo.userdatalength
*6, as above, uusinfo.UserData
*/
//RIL_REQUEST_DIAL
int dial(int argc, char **argv, RIL_SOCKET_ID socket_id, RequestInfo *pRI)
{
android::Parcel p;
size_t pos = p.dataPosition();
if (argc < 3 || argv[1]==NULL) {
//add log msg
free(pRI);
return -1;
}
//address;
writeStringToParcel(p, (const char *)argv[1]);
//clirMode
if (argc >=2) {
p.writeInt32(atoi(argv[2]));
if (argc == 7 && argv[3] != NULL
&& argv[4] != NULL && argv[5] != NULL
&& argv[6] != NULL ) {
p.writeInt32(1); // UUS information is present
p.writeInt32(atoi(argv[3]));
p.writeInt32(atoi(argv[4]));
p.writeByteArray((size_t)atoi(argv[5]),(uint8_t*)argv[6]);
} else {
p.writeInt32(0); // UUS information is absent
}
}
p.setDataPosition(pos);
setEcallAudioPathOn(false);
pRI->pCI->dispatchFunction(p, pRI);
inCallstatus = CALL_ON;
return 0;
}
#if 0 //not need user setup
//RIL_REQUEST_OEM_HOOK_STRINGS
int invokeOemRilRequestStrings(int argc, char **argv, RIL_SOCKET_ID socket_id, RequestInfo *pRI)
{
android::Parcel p;
size_t pos = p.dataPosition();
RLOGD("OEM_HOOK_STRINGS: p1->\"%s\",p2->\"%s\"",argv[1],argv[2]);
p.writeInt32(2);
writeStringToParcel(p, (const char *)argv[1]);
writeStringToParcel(p, "\"\"");//(const char *)argv[2]);
p.setDataPosition(pos);
pRI->pCI->dispatchFunction(p, pRI);
return 0;
}
#endif
extern void ARspRequest (int request,RIL_SOCKET_ID socket_id);
//RIL_REQUEST_SET_AUDIO_PATH
/*cmd:1, speech mode,
*2, bt_has_ecnr
*3, bt_wbs
*/
int setAudioPath(int argc, char **argv, RIL_SOCKET_ID socket_id, RequestInfo *pRI)
{
if (argc < 1) {
free(pRI);
RLOGE("set bt mode need bt_has_encr and bt_wbs");
return -1;
}
int temp_audio_path = atoi(argv[1]);
int bt_has_ecnr;
int bt_wbs;
int current_audio_path = get_audio_path();
RLOGD("setAudioPath enter");
if ((temp_audio_path != 0) && (temp_audio_path != 1)) {
RLOGE("audio path illegal %d, only support 0 and 1", temp_audio_path);
return -1;
}
set_audio_path(temp_audio_path);
RLOGD("set audio path to %d, current audio path is %d", temp_audio_path, current_audio_path);
if (temp_audio_path == 1) {
/* bt speech need BT_HAS_ECNR and BT_WBS */
bt_has_ecnr = atoi(argv[2]);
bt_wbs = atoi(argv[3]);
set_bt_has_ecnr(bt_has_ecnr);
set_bt_wbs(bt_wbs);
RLOGD("set bt_has_ecnr %d, bt_wbs %d", bt_has_ecnr, bt_wbs);
}
if ((current_audio_path != temp_audio_path)
&& (get_call_status() == CALL_ON)) {
if (current_audio_path == 0) {
if (getSpeechStatus() == NORMAL_SPEECH_ON) {
RLOGD("normal speech off then bt speech on");
mixer_set(0);
setSpeechAndStatus(2);
}
} else {
if (getSpeechStatus() == BT_SPEECH_ON) {
RLOGD("bt speech off then normal speech on");
bt_mixer_set(0);
setSpeechAndStatus(1);
}
}
}
if (pRI != NULL) {
free(pRI);
}
RLOGD("setAudioPath done");
return 0;
}
//RIL_REQUEST_HANGUP
int hangupConnection(int argc, char **argv, RIL_SOCKET_ID socket_id, RequestInfo *pRI)
{
android::Parcel p;
size_t pos = p.dataPosition();
p.writeInt32(1);
p.writeInt32(atoi(argv[1]));
p.setDataPosition(pos);
pRI->pCI->dispatchFunction(p, pRI);
return 0;
}
//RIL_REQUEST_FORCE_RELEASE_CALL
int forceReleaseCall(int argc, char **argv, RIL_SOCKET_ID socket_id, RequestInfo *pRI)
{
android::Parcel p;
size_t pos = p.dataPosition();
p.writeInt32(1);
p.writeInt32(atoi(argv[1]));
p.setDataPosition(pos);
pRI->pCI->dispatchFunction(p, pRI);
return 0;
}
//RIL_REQUEST_SEPARATE_CONNECTION
int separateConnection(int argc, char **argv, RIL_SOCKET_ID socket_id, RequestInfo *pRI)
{
android::Parcel p;
size_t pos = p.dataPosition();
p.writeInt32(1);
p.writeInt32(atoi(argv[1]));
p.setDataPosition(pos);
pRI->pCI->dispatchFunction(p, pRI);
return 0;
}
//RIL_REQUEST_DTMF
//RIL_REQUEST_DTMF_START
int sendDtmf(int argc, char **argv, RIL_SOCKET_ID socket_id, RequestInfo *pRI)
{
android::Parcel p;
int number;
size_t pos = p.dataPosition();
char * c_num = NULL;
c_num = argv[1];
if (c_num == NULL) {
free(pRI);
return -1;
}
number = int(c_num[0] - '0');
if(number == -6)
number = 10;
if(number == -13)
number = 11;
RLOGD("DTMF input number is %s-->%d",c_num,number);
if ( number < 0 || number > 15 ) {
RLOGE("DTMF input number error");
free(pRI);
return -1;
}
writeStringToParcel(p, (const char *)argv[1]);
p.setDataPosition(pos);
dtmf_stop(dtmf_handle);
gint time_ms = 500;
if (pRI->pCI->requestNumber == RIL_REQUEST_DTMF_START) {
time_ms = 0;
}
RLOGD("request: %d, time_ms = %d", pRI->pCI->requestNumber, time_ms);
dtmf_handle = dtmf_start(number, time_ms, dtmf_volume, NULL);
pRI->pCI->dispatchFunction(p, pRI);
if (dtmf_handle == NULL)
RLOGE("[DTMF] dtmf_start return NULL!");
return 0;
}
//RIL_REQUEST_UDUB
int rejectCall(int argc, char **argv, RIL_SOCKET_ID socket_id, RequestInfo *pRI)
{
android::Parcel p;
pRI->pCI->dispatchFunction(p, pRI);
return 0;
}
//RIL_REQUEST_ANSWER
int acceptCall(int argc, char **argv, RIL_SOCKET_ID socket_id, RequestInfo *pRI)
{
android::Parcel p;
pRI->pCI->dispatchFunction(p, pRI);
inCallstatus = CALL_ON;
return 0;
}
//RIL_REQUEST_HANGUP_ALL
int hangupAll(int argc, char **argv, RIL_SOCKET_ID socket_id, RequestInfo *pRI)
{
android::Parcel p;
pRI->pCI->dispatchFunction(p, pRI);
return 0;
}
//RIL_REQUEST_CONFERENCE
int conference(int argc, char **argv, RIL_SOCKET_ID socket_id, RequestInfo *pRI)
{
android::Parcel p;
pRI->pCI->dispatchFunction(p, pRI);
return 0;
}
//RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND
int hangupWaitingOrBackground(int argc, char **argv, RIL_SOCKET_ID socket_id, RequestInfo *pRI)
{
android::Parcel p;
pRI->pCI->dispatchFunction(p, pRI);
return 0;
}
//RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE
int switchWaitingOrHoldingAndActive(int argc, char **argv, RIL_SOCKET_ID socket_id, RequestInfo *pRI)
{
android::Parcel p;
pRI->pCI->dispatchFunction(p, pRI);
return 0;
}
//RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND
int hangupForegroundResumeBackground(int argc, char **argv, RIL_SOCKET_ID socket_id, RequestInfo *pRI)
{
android::Parcel p;
pRI->pCI->dispatchFunction(p, pRI);
return 0;
}
//RIL_REQUEST_EXPLICIT_CALL_TRANSFER
int explicitCallTransfer(int argc, char **argv, RIL_SOCKET_ID socket_id, RequestInfo *pRI)
{
android::Parcel p;
pRI->pCI->dispatchFunction(p, pRI);
return 0;
}
//RIL_REQUEST_ADD_IMS_CONFERENCE_CALL_MEMBER
int addImsConferenceCallMember(int argc, char **argv, RIL_SOCKET_ID socket_id, RequestInfo *pRI)
{
android::Parcel p;
size_t pos = p.dataPosition();
p.writeInt32(3);
writeStringToParcel(p, (const char *)argv[1]);//confCallId
writeStringToParcel(p, (const char *)argv[2]);//address
writeStringToParcel(p, (const char *)argv[3]);//CallIdToAdd
p.setDataPosition(pos);
pRI->pCI->dispatchFunction(p, pRI);
return 0;
}
//RIL_REQUEST_REMOVE_IMS_CONFERENCE_CALL_MEMBER
int removeImsConferenceCallMember(int argc, char **argv, RIL_SOCKET_ID socket_id, RequestInfo *pRI)
{
android::Parcel p;
size_t pos = p.dataPosition();
p.writeInt32(3);
writeStringToParcel(p, (const char *)argv[1]);//confCallId
writeStringToParcel(p, (const char *)argv[2]);//address
writeStringToParcel(p, (const char *)argv[3]);//CallIdToRemove
p.setDataPosition(pos);
pRI->pCI->dispatchFunction(p, pRI);
return 0;
}
//RIL_REQUEST_CONFERENCE_DIAL
//argv[1]:DialMethod
//argv[2]:ParticipantsNumber
//argv[2+ParticipantsNumber]:addresss
//argv[2+ParticipantsNumber+1]:clir
int conferenceDial(int argc, char **argv, RIL_SOCKET_ID socket_id, RequestInfo *pRI)
{
android::Parcel p;
size_t pos = p.dataPosition();
int ParticipantsNumber,i;
if( argc < 3 ) {
free(pRI);
RLOGE("Error: conference Dial parameter is error!");
return -1;
}
ParticipantsNumber = atoi(argv[2]);
if( argc < (ParticipantsNumber+3) ) {
free(pRI);
RLOGE("Error: Dial With SIP URI parameter is error! \
argc is %d, and need parameter %d",argc,(ParticipantsNumber+3));
return -1;
}
p.writeInt32((ParticipantsNumber+3));
writeStringToParcel(p, (const char *)argv[1]); //DialMethod
writeStringToParcel(p, (const char *)argv[2]); //ParticipantsNumber
for( i=0; i<ParticipantsNumber; i++ ){ //address
writeStringToParcel(p, (const char *)argv[3+i]);
}
writeStringToParcel(p, (const char *)argv[3+ParticipantsNumber]);//clir
p.setDataPosition(pos);
setEcallAudioPathOn(false);
pRI->pCI->dispatchFunction(p, pRI);
return 0;
}
//RIL_REQUEST_DIAL_WITH_SIP_URI
int dialWithSipUri(int argc, char **argv, RIL_SOCKET_ID socket_id, RequestInfo *pRI)
{
android::Parcel p;
size_t pos = p.dataPosition();
if (argc < 3 || argv[1]==NULL) {
free(pRI);
return -1;
}
writeStringToParcel(p, (const char *)argv[1]);//address
/* for compatibility of test script, still receive clirMode and UUS,
but don't send them to libvendor-ril */
#if 0
p.writeInt32(atoi(argv[2]));//clirMode
p.writeInt32(0); // UUS information is absent
#endif
p.setDataPosition(pos);
setEcallAudioPathOn(false);
pRI->pCI->dispatchFunction(p, pRI);
return 0;
}
//RIL_REQUEST_HOLD_CALL
int holdCall(int argc, char **argv, RIL_SOCKET_ID socket_id, RequestInfo *pRI)
{
android::Parcel p;
size_t pos = p.dataPosition();
if (argc < 2 || argv[1]==NULL) {
free(pRI);
return -1;
}
//callIDToHold
p.writeInt32(1);
p.writeInt32(atoi(argv[1]));
p.setDataPosition(pos);
pRI->pCI->dispatchFunction(p, pRI);
return 0;
}
//RIL_REQUEST_RESUME_CALL
int resumeCall(int argc, char **argv, RIL_SOCKET_ID socket_id, RequestInfo *pRI)
{
android::Parcel p;
size_t pos = p.dataPosition();
if (argc < 2 || argv[1]==NULL) {
free(pRI);
return -1;
}
//callIDToResume
p.writeInt32(1);
p.writeInt32(atoi(argv[1]));
p.setDataPosition(pos);
pRI->pCI->dispatchFunction(p, pRI);
return 0;
}
int getCurrentCalls(int argc, char **argv, RIL_SOCKET_ID socket_id, RequestInfo *pRI)
{
android::Parcel p;
pRI->pCI->dispatchFunction(p, pRI);
return 0;
}
int autoAnswerCall(int argc, char **argv, RIL_SOCKET_ID socket_id, RequestInfo *pRI)
{
if(argc < 2) {
RLOGW("[error],set auto answer call parameter error!");
free(pRI);
return 0;
}
//need add lock to pretect.
autoAnswerMode = atoi(argv[1]) ? 1 : 0;
RLOGD("SetAutoAnserMode is %s",autoAnswerMode ? "On" :"Off");
if(pRI) {
free(pRI);
}
return 0;
}
int inCallRecord(int argc, char **argv, RIL_SOCKET_ID socket_id, RequestInfo *pRI)
{
int recordEnable = 0;
char* filepath = NULL;
if(inCallstatus == CALL_OFF || speechStatus == SPEECH_OFF) {
RLOGW("[warning],not in calling status. Can't do record!");
return 0;
}
if(argc < 3) {
free(pRI);
RLOGW("[error],inCallRecord parameter error!");
return 0;
}
recordEnable = atoi(argv[1]) ? 1 : 0;
RLOGD("InCall record %s!",recordEnable ? "enable" : "disable");
filepath = argv[2];
RLOGD("InCall record file path as \'%s\'",filepath);
if (recordEnable == 1) {//enable record
RLOGD("start GSM!");
if(-1 != GSM_Init(filepath) && -1 != GSM_Start()) {
inCallRecordMode = 1;
RLOGW("inCallRecord Start OK!");
}else{
inCallRecordMode = 0;
RLOGW("[error],inCallRecord Start fail!");
}
} else { //disable record
if (inCallRecordMode == 1) {
if(!(-1 != GSM_Stop() && -1 != GSM_Close()))
RLOGW("[error],inCallRecord fail!");
inCallRecordMode = 0;
}
}
if(pRI != NULL) {
free(pRI);
}
return 0;
}
int StopRecord()
{
RLOGD("After Handup, stop record! Before Record is %s",inCallRecordMode ? "Enable" : "Disable");
if (inCallRecordMode == 1) {
if(!(-1 != GSM_Stop() && -1 != GSM_Close()))
RLOGW("[error],inCallRecord fail!");
inCallRecordMode = 0;
/*From GSM report stop_record to PulseAudio send record_off need 15ms. so after stop record delay 30ms*/
usleep(30*1000);
}
return 0;
}
int setSpeechVolume(int argc, char **argv, RIL_SOCKET_ID socket_id, RequestInfo *pRI)
{
int setValue = 0;
RLOGD("setSpeechVolume start!");
if(argc < 2) {
free(pRI);
RLOGW("Warning: no set volume value!");
return -1;
}
setValue = atoi(argv[1]);
RLOGD("set Speech Volume value is %d!",setValue);
if (get_audio_path() == 0) {
if(setValue < MIN_VOLUME || setValue > MAX_VOLUME) {
RLOGW("Warning: set volume value is over-range!");
return -1;
}
} else {
if(setValue < BT_MIN_VOLUME || setValue > BT_MAX_VOLUME) {
RLOGW("Warning: set bt volume value is over-range!");
return -1;
}
}
//paramter is from 1 to 7
mixer_set_volume(setValue);
free(pRI);
return 0;
}
int setDtmfVolume(int argc, char **argv, RIL_SOCKET_ID socket_id, RequestInfo *pRI)
{
int setValue = 0;
RLOGD("setDtmfVolume start!");
if(argc < 2) {
RLOGW("Warning: no set volume value!");
free(pRI);
return -1;
}
setValue = atoi(argv[1]);
RLOGD("set dtmf Volume value is %d!",setValue);
if(setValue < DTMF_MIN_VOLUME || setValue > DTMF_MAX_VOLUME) {
RLOGW("Warning: set volume value is over-range!");
free(pRI);
return -1;
}
//paramter is from 0 to 36
dtmf_volume = setValue;
free(pRI);
return 0;
}
speech_status getSpeechStatus()
{
return speechStatus;
}
void setSpeechAndStatus(int value)
{
RLOGD("setSpeechAndStatus value: %d, speechStatus: %d", value, speechStatus);
if (value == 1) {
speechStatus = NORMAL_SPEECH_ON;
mixer_set(1);
} else if (value == 2) {
speechStatus = BT_SPEECH_ON;
bt_mixer_set(1);
} else if (value == 0) {
speechStatus == BT_SPEECH_ON ? bt_mixer_set(0) : mixer_set(0);
speechStatus = SPEECH_OFF;
} else {
RLOGE("set speech value is invaild!\n");
}
}
//RIL_REQUEST_EMERGENCY_DIAL
/*cmd:1, address,
*2, clirMode,
*3, if present, uusinfo.type
*4, as above, uusinfo.Dcs
*5, as above, uusinfo.userdatalength
*6, as above, uusinfo.UserData
*/
int emergencyDial(int argc, char **argv, RIL_SOCKET_ID socket_id, RequestInfo *pRI)
{
android::Parcel p;
size_t pos = p.dataPosition();
if (argc < 3 || argv[1] == NULL)
{
//add log msg
free(pRI);
return -1;
}
//address;
writeStringToParcel(p, (const char *) argv[1]);
//clirMode
if (argc >= 2)
{
p.writeInt32(atoi(argv[2]));
if (argc == 7&& argv[3] != NULL
&& argv[4] != NULL && argv[5] != NULL
&& argv[6] != NULL)
{
p.writeInt32(1); // UUS information is present
p.writeInt32(atoi(argv[3]));
p.writeInt32(atoi(argv[4]));
p.writeByteArray((size_t) atoi(argv[5]), (uint8_t*) argv[6]);
} else
{
p.writeInt32(0); // UUS information is absent
}
}
p.setDataPosition(pos);
setEcallAudioPathOn(false);
pRI->pCI->dispatchFunction(p, pRI);
return 0;
}
//RIL_REQUEST_SET_ECC_SERVICE_CATEGORY
int setEccServiceCategory(int argc, char **argv, RIL_SOCKET_ID socket_id, RequestInfo *pRI)
{
android::Parcel p;
size_t pos = p.dataPosition();
//if ( getSpeechStatus() != 1)
// setSpeechAndStatus(1);
p.writeInt32(1);
p.writeInt32(atoi(argv[1]));
p.setDataPosition(pos);
pRI->pCI->dispatchFunction(p, pRI);
return 0;
}
//RIL_REQUEST_SET_ECC_LIST
/* argv[1]: list number
argv[2+i]: ECC string
argv[3+i]: Categroy
argv[4+i]: Conditon
*/
int setEccList(int argc, char **argv, RIL_SOCKET_ID socket_id, RequestInfo *pRI)
{
android::Parcel p;
size_t pos = p.dataPosition();
int num = 0;
//if ( getSpeechStatus() != 1)
// setSpeechAndStatus(1);
if(argc < 3) {
RLOGE("%s parameter error!",__func__);
free(pRI);
return -1;
}
num = atoi(argv[1]);
RLOGD("list number is %d, argc is %d",num, argc);
if((num == 0) || ((argc-2) < num*3)) {
RLOGE("%s parameter error!",__func__);
free(pRI);
return -1;
}
p.writeInt32(num*3);
for(int i = 0; i < num; i++){
writeStringToParcel(p, (const char *)argv[2+i*3+0]); //ECC
writeStringToParcel(p, (const char *)argv[2+i*3+1]); //Category
writeStringToParcel(p, (const char *)argv[2+i*3+2]); //Condition
RLOGD("list[%d],ECC is %s, Category is %s, Condition is %s!",i+1,argv[2+i*3+0],argv[2+i*3+1],argv[2+i*3+2]);
}
p.setDataPosition(pos);
pRI->pCI->dispatchFunction(p, pRI);
return 0;
}
//RIL_REQUEST_SET_ECC_NUM
int setEccNum(int argc, char **argv, RIL_SOCKET_ID socket_id, RequestInfo *pRI)
{
android::Parcel p;
size_t pos = p.dataPosition();
int num = 0;
if(argc < 2 || argc > 3) {
RLOGE("%s parameter error!",__func__);
free(pRI);
return -1;
}
num = (argc > 2)?2:1;
p.writeInt32(num);
writeStringToParcel(p, (const char *)argv[1]); //ECC number with card
RLOGD("Set ECC number with card: %s",argv[1]);
if (num>1){
writeStringToParcel(p, (const char *)argv[2]); //ECC number without card
RLOGD("Set ECC number without card: %s",argv[2]);
}
p.setDataPosition(pos);
pRI->pCI->dispatchFunction(p, pRI);
return 0;
}
//RIL_REQUEST_GET_ECC_NUM
int getEccNum(int argc, char **argv, RIL_SOCKET_ID socket_id, RequestInfo *pRI)
{
android::Parcel p;
pRI->pCI->dispatchFunction(p, pRI);
return 0;
}
int handleECCNumResponse(const void *data, int datalen, RIL_SOCKET_ID socket_id){
if (data == NULL || datalen <= 0){
RLOGE("%s parameter error!",__func__);
return -1;
}
printf("[ECC NUM][Slot%d] %s\n", socket_id, (const char*)data);
RLOGD("[ECC NUM][Slot%d] %s\n", socket_id, (const char*)data);
return 0;
}
//RIL_REQUEST_LAST_CALL_FAIL_CAUSE
int getLastCallFailCause(int argc, char **argv, RIL_SOCKET_ID socket_id, RequestInfo *pRI) {
if(argc != 1)
{
RLOGD("the peremeters numbers isn't right , so return");
free(pRI);
return -1;
}
RLOGD("getLastCallFailCause %d: " , pRI->pCI->requestNumber);
android::Parcel p;
pRI->pCI->dispatchFunction(p, pRI);
return 0;
}
#ifdef C2K_SUPPORT
static bool is12Key(char c) {
return (c >= '0' && c <= '9') || c == '*' || c == '#';
}
//RIL_REQUEST_CDMA_BURST_DTMF
int sendBurstDtmf(int argc, char **argv, RIL_SOCKET_ID socket_id, RequestInfo *pRI){
if(argc < 4) {
RLOGE("%s parameter error!",__func__);
free(pRI);
return -1;
}
int number;
char * c_num = NULL;
c_num = argv[1];
if (c_num == NULL) {
free(pRI);
return -1;
}
number = int(c_num[0] - '0');
if(number == -6)
number = 10;
if(number == -13)
number = 11;
RLOGD("DTMF input number is %s-->%d",c_num,number);
if ( number < 0 || number > 15 ) {
RLOGE("DTMF input number error");
free(pRI);
return -1;
}
dtmf_stop(dtmf_handle);
dtmf_handle = dtmf_start(number, 500, dtmf_volume, NULL);
android::Parcel p;
size_t pos = p.dataPosition();
p.writeInt32(3);
writeStringToParcel(p, c_num);
writeStringToParcel(p, argv[2]);
writeStringToParcel(p, argv[3]);
p.setDataPosition(pos);
pRI->pCI->dispatchFunction(p, pRI);
if (dtmf_handle == NULL)
RLOGE("[DTMF] dtmf_start return NULL!");
return 0;
}
//RIL_REQUEST_CDMA_FLASH
int sendCDMAFeatureCode(int argc, char **argv, RIL_SOCKET_ID socket_id, RequestInfo *pRI){
if(argc > 2)
{
RLOGD("the peremeters numbers isn't right , so return");
free(pRI);
return -1;
}
android::Parcel p;
size_t pos = p.dataPosition();
writeStringToParcel(p, ((argc == 1) ? "" : argv[1]));
p.setDataPosition(pos);
pRI->pCI->dispatchFunction(p, pRI);
return 0;
}
#endif /*C2K_SUPPORT*/
static int mixer_set_mute(int path, int value)
{
RLOGD("mixer_set_mute path: %d , value: %d", path, value);
int ret;
/* DL:0 UL:1 */
if (path == 0) {
ret = set_mixer_ctrl_value_int(g_DL_mute_name, value);
} else {
ret = set_mixer_ctrl_value_int(g_UL_mute_name, value);
}
if (ret) {
RLOGE("set_mixer_ctrl_volume_value_int err: %d", ret);
}
return ret;
}
static long int mixer_get_mute(int path)
{
long int is_mute;
/* DL:0 UL:1 */
if (path == 0) {
is_mute = get_mixer_ctrl_value_int(g_DL_mute_name);
RLOGD("The ctrl \"%s\" is set to %d", g_DL_mute_name, is_mute);
} else {
is_mute = get_mixer_ctrl_value_int(g_UL_mute_name);
RLOGD("The ctrl \"%s\" is set to %d", g_UL_mute_name, is_mute);
}
return is_mute;
}
int setCallMute(bool mute) {
RLOGD("setCallMute: %d", mute);
return mixer_set_mute(1, (mute ? 1: 0));
}
int getCallMute() {
long int cc_mute = mixer_get_mute(1);
RLOGD("getCallMute: %d", cc_mute);
return cc_mute;
}
void resetMute() {
if (getCallMute() > 0) {
setCallMute(false);
}
}
void callRing(RIL_SOCKET_ID soc_id)
{
resetMute();
if (autoAnswerMode) {
RLOGD("Auto Answer MT Call!");
android::requestAnswer(soc_id);
}
return;
}
void autoAnswerForCdma(RIL_SOCKET_ID socket_id)
{
resetMute();
if (autoAnswerMode) {
RLOGD("Auto Answer MT Call for cdma");
ARspRequest(RIL_REQUEST_CDMA_FLASH, socket_id);
}
return;
}
//void callStateChange(void)
void speechonoff(int callnum)
{
static int callIndex = 0;
RLOGD("callnum = %d, Call State Change then judge speech on/off!", callnum);
callIndex = callnum;
if( callIndex == 1 && speechStatus == SPEECH_OFF) { //speech on
//RLOGD("DemoAPP Call shell command (pactl set-card-profile 0 phonecall)");
//system("pactl set-card-profile 0 phonecall");
//RLOGD("DemoAPP Call shell command end");
if (get_audio_path() == 0) {
mixer_set(1);
speechStatus = NORMAL_SPEECH_ON;
} else {
bt_mixer_set(1);
speechStatus = BT_SPEECH_ON;
}
inCallstatus = CALL_ON;
RLOGD("[speech]: set on");
sendCallMsg(true); //for Power Manager test
} else if (callIndex == 0
&& (speechStatus == NORMAL_SPEECH_ON
|| speechStatus == BT_SPEECH_ON)) { //speech off
StopRecord();
sendCallMsg(false); // for Power Manager test.
dtmf_stop(dtmf_handle);
if (speechStatus == NORMAL_SPEECH_ON) {
mixer_set(0);
} else {
bt_mixer_set(0);
}
//RLOGD("DemoAPP Call shell command (pactl set-card-profile 0 HiFi)");
//system("pactl set-card-profile 0 HiFi");
//RLOGD("DemoAPP Call(pactl set-card-profile 0 HiFi) command end");
speechStatus = SPEECH_OFF;
inCallstatus = CALL_OFF;
resetMute();
RLOGD("[speech]: set off");
} else {
RLOGD("callIndex is %d, speechStatus is %d.",callIndex, speechStatus);
}
return;
}
//RIL_REQUEST_SET_MUTE
int setMute(int argc, char **argv, RIL_SOCKET_ID socket_id, RequestInfo *pRI)
{
if(pRI) {
free(pRI);
}
bool mute = (atoi(argv[1]) > 0) ? true: false;
RLOGD("set mute %s", ((atoi(argv[1]) > 0) ? "on": "off"));
int ret = setCallMute(mute);
std::string str;
if(ret) {
str.append("set mute fail, please try agian\n");
} else {
str.append("set mute ");
str.append((atoi(argv[1]) > 0) ? "on ": "off ");
str.append("success\n");
}
android::emResultNotify(str.c_str());
return 0;
}
//RIL_REQUEST_GET_MUTE
int getMute(int argc, char **argv, RIL_SOCKET_ID socket_id, RequestInfo *pRI)
{
if(pRI) {
free(pRI);
}
std::string str;
int mute = getCallMute();
//TBC -200 fail status
if(mute == -200) {
str.append("get mute state fail, please check whether does call exsit. \n");
} else {
str.append("current mute state is ");
str.append((mute == 1) ? "on\n" : "off\n");
}
android::emResultNotify(str.c_str());
return 0;
}
//RIL_UNSOL_SIP_CALL_PROGRESS_INDICATOR
int handleUnsolSipCallProgressInd(const void *response, size_t responselen) {
if (response == NULL && responselen != 0) {
RLOGE("handleUnsolSipCallProgressInd: invalid response: NULL");
return -1;
}
if (responselen % sizeof(char *) != 0) {
RLOGE("handleUnsolSipCallProgressInd: invalid response length %d expected multiple of %d\n",
(int)responselen, (int)sizeof(char *));
return -1;
}
int numStrings = responselen / sizeof(char *);
RLOGD("handleUnsolSipCallProgressInd: numStrings: %d", numStrings);
if(numStrings < 6) {
RLOGE("handleUnsolSipCallProgressInd: invalid response numbers: NULL");
return -1;
}
char **p_cur = (char **) response;
//<call_id>,<dir>,<SIP_msg_type>,<method>,<response_code>,"<reason_text>"
//if response == <id>, 1, 0, 4, 0, "call completed elsewhere" ,printf "SIP CANCEL:Call completed elsewhere"
//if response == <id>, 1, 0, 4, 0, " declined" ,printf "SIP CANCEL:declined"
std::string call_id(p_cur[0]);
std::string dir(p_cur[1]);
std::string sip_msg_type(p_cur[2]);
std::string method(p_cur[3]);
std::string resp_code(p_cur[4]);
std::string reason_text(p_cur[5]);
RLOGD("%s, call_id=%s, dir=%s, sip_msg_type=%s, method=%s, resp_code=%s, reason_text=%s",
__FUNCTION__, call_id.c_str(),dir.c_str(),sip_msg_type.c_str(),method.c_str(),resp_code.c_str(), reason_text.c_str());
printf("call_id=%s, dir=%s, sip_msg_type=%s, method=%s, resp_code=%s, reason_text=%s\n",
call_id.c_str(),dir.c_str(),sip_msg_type.c_str(),method.c_str(),resp_code.c_str(), reason_text.c_str());
if ((std::stoi(dir) == 1) && (std::stoi(sip_msg_type) == 0)
&& (std::stoi(method) == 4) && (std::stoi(resp_code) == 0)) {
std::string msg("SIP CANCEL:");
msg.append(reason_text);
printf("%s", msg.c_str());
}
return 0;
}
//RIL_UNSOL_CALL_INFO_INDICATION
int handleUnsolCallInfoInd(const void *response, size_t responselen, RIL_SOCKET_ID socket_id) {
int numStrings = 0;
if (response == NULL && responselen != 0) {
RLOGE("[slot%d]handleUnsolCallInfoInd, invalid response: NULL", socket_id);
return -1;
}
if (responselen % sizeof(char *) != 0) {
RLOGE("[slot%d]handleUnsolCallInfoInd: invalid response length %d expected multiple of %d\n",socket_id,
(int)responselen, (int)sizeof(char *));
return -1;
}
if (response == NULL) {
RLOGE("[slot%d]handleUnsolCallInfoInd, length and invalid response : NULL", socket_id);
} else {
char **p_cur = (char **) response;
numStrings = responselen / sizeof(char *);
RLOGD("[slot%d]handleUnsolCallInfoInd: numStrings: %d",socket_id, numStrings);
if(numStrings < 9) {
RLOGE("[slot%d]handleUnsolCallInfoInd, invalid numStrings(%d) < 9, no pau value : numStrings", socket_id);
return -1;
} else {
RLOGD("[slot%d]handleUnsolCallInfoInd(): pau: %s", socket_id, p_cur[8]);
printf("[slot%d]handleUnsolCallInfoInd(): pau: %s\n", socket_id, p_cur[8]);
}
}
return 0;
}
static void playtone(int start) {
RLOGD("playtone(): start: %d, isRingStart %d", start, isRingStart);
char cmd[256];
sprintf(cmd, "aplay %s", RING_PATH);
system(cmd);
isRingStart = false;
}
//RIL_UNSOL_RINGBACK_TONE
int handleRingbackTone(const void *response, size_t responselen, RIL_SOCKET_ID socket_id) {
int numInts = 0;
if (response == NULL && responselen != 0) {
RLOGE("[slot%d]handleRingbackTone, invalid response: NULL", socket_id);
return -1;
}
if (responselen % sizeof(int) != 0) {
RLOGE("[slot%d]handleRingbackTone: invalid response length %d expected multiple of %d\n",socket_id,
(int)responselen, (int)sizeof(char *));
return -1;
}
int *p_int = (int *) response;
numInts = responselen / sizeof(int);
RLOGD("[slot%d]handleRingbackTone: numInts: %d",socket_id, numInts);
if(numInts < 1) {
RLOGE("[slot%d]handleRingbackTone, invalid numStrings(%d) < 1", socket_id);
return -1;
} else {
int start = p_int[0];
RLOGD("[slot%d]handleRingbackTone(): start: %d, isRingStart %d", socket_id, start, isRingStart);
printf("[slot%d]handleRingbackTone(): start: %d, isRingStart %d\n", socket_id, start, isRingStart);
#if defined(TARGET_PLATFORM_MT2731)
if(start && (!isRingStart)) {
isRingStart = true;
std::thread t(playtone, start);
t.detach();
} else if((!start) && isRingStart) {
isRingStart = false;
system("kill $(ps aux | grep '[a]play' | awk '{print $2}')");
}
#endif
}
return 0;
}
//RIL_REQUEST_DTMF_STOP
int stopDtmf(int argc, char **argv, RIL_SOCKET_ID socket_id, RequestInfo *pRI)
{
android::Parcel p;
dtmf_stop(dtmf_handle);
pRI->pCI->dispatchFunction(p, pRI);
return 0;
}