mirror of
https://github.com/signalwire/freeswitch.git
synced 2025-02-08 08:51:50 +00:00
6611 lines
206 KiB
C
Executable File
6611 lines
206 KiB
C
Executable File
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include <time.h>
|
|
#include "cpr_types.h"
|
|
#include "cpr_stdlib.h"
|
|
#include "cpr_locks.h"
|
|
#include "cpr_stdio.h"
|
|
#include "cpr_timers.h"
|
|
#include "cpr_in.h"
|
|
#include "cpr_errno.h"
|
|
#include "phone_types.h"
|
|
#include "phone.h"
|
|
#include "sdp.h"
|
|
#include "lsm.h"
|
|
#include "phone_debug.h"
|
|
#include "fsm.h"
|
|
#include "gsm_sdp.h"
|
|
#include "vcm.h"
|
|
#include "ccsip_pmh.h"
|
|
#include "dtmf.h"
|
|
#include "debug.h"
|
|
#include "rtp_defs.h"
|
|
#include "lsm_private.h"
|
|
#include "dialplanint.h"
|
|
#include "kpmlmap.h"
|
|
#include "prot_configmgr.h"
|
|
#include "dialplan.h"
|
|
#include "sip_interface_regmgr.h"
|
|
#include "gsm.h"
|
|
#include "phntask.h"
|
|
#include "fim.h"
|
|
#include "util_string.h"
|
|
#include "platform_api.h"
|
|
|
|
#ifndef NO
|
|
#define NO (0)
|
|
#endif
|
|
|
|
#ifndef YES
|
|
#define YES (1)
|
|
#endif
|
|
|
|
#define CALL_INFO_NONE (string_t)""
|
|
|
|
#define FROM_NOTIFY_PRI 1 // Same as SCCP phone behavior
|
|
#define LSM_DISPLAY_STR_LEN 256
|
|
|
|
static cc_rcs_t lsm_stop_tone (lsm_lcb_t *lcb, cc_action_data_tone_t *data);
|
|
|
|
extern cc_media_cap_table_t g_media_table;
|
|
|
|
static lsm_lcb_t *lsm_lcbs;
|
|
static uint32_t lsm_call_perline[MAX_REG_LINES];
|
|
boolean lsm_mnc_reached[MAX_REG_LINES]; // maxnumcalls reached
|
|
static boolean lsm_bt_reached[MAX_REG_LINES]; //busy trigger reached
|
|
|
|
/* This variable is used locally to reflect the CFA state (set/clear)
|
|
* when in CCM mode.
|
|
*/
|
|
static boolean cfwdall_state_in_ccm_mode[MAX_REG_LINES+1] ;
|
|
|
|
static const char *lsm_state_names[LSM_S_MAX] = {
|
|
"IDLE",
|
|
"PENDING",
|
|
"OFFHOOK",
|
|
"ONHOOK",
|
|
"PROCEED",
|
|
"RINGOUT",
|
|
"RINGIN",
|
|
"CONNECTED",
|
|
"BUSY",
|
|
"CONGESTION",
|
|
"HOLDING",
|
|
"CWT",
|
|
"XFER",
|
|
"ATTN_XFER",
|
|
"CONF",
|
|
"INVALID_NUMBER"
|
|
};
|
|
|
|
static const char *cc_state_names[] = {
|
|
"OFFHOOK",
|
|
"DIALING",
|
|
"DIALING_COMPLETED",
|
|
"CALL_SENT",
|
|
"FAR_END_PROCEEDING",
|
|
"FAR_END_ALERTING",
|
|
"CALL_RECEIVED",
|
|
"ALERTING",
|
|
"ANSWERED",
|
|
"CONNECTED",
|
|
"HOLD",
|
|
"RESUME",
|
|
"ONHOOK",
|
|
"CALL_FAILED",
|
|
"HOLD_REVERT",
|
|
"STATE_UNKNOWN"
|
|
};
|
|
|
|
|
|
static const char *cc_action_names[] = {
|
|
"SPEAKER",
|
|
"DIAL_MODE",
|
|
"MWI",
|
|
"MWI_LAMP",
|
|
"OPEN_RCV",
|
|
"UPDATE_UI",
|
|
"MEDIA",
|
|
"RINGER",
|
|
"LINE_RINGER",
|
|
"PLAY_TONE",
|
|
"STOP_TONE",
|
|
"STOP_MEDIA",
|
|
"START_RCV",
|
|
"ANSWER_PENDING",
|
|
"PLAY_BLF_ALERT_TONE"
|
|
};
|
|
|
|
/* names are corresponds to vcm_ring_mode_t structure */
|
|
static const char *vm_alert_names[] = {
|
|
"NONE",
|
|
// "RINGER_OFF",
|
|
"VCM_RING_OFF",
|
|
"VCM_INSIDE_RING",
|
|
"VCM_OUTSIDE_RING",
|
|
"VCM_FEATURE_RING",
|
|
"VCM_BELLCORE_DR1",
|
|
"VCM_RING_OFFSET",
|
|
"VCM_BELLCORE_DR2",
|
|
"VCM_BELLCORE_DR3",
|
|
"VCM_BELLCORE_DR4",
|
|
"VCM_BELLCORE_DR5",
|
|
"VCM_BELLCORE_MAX",
|
|
"VCM_FLASHONLY_RING",
|
|
"VCM_STATION_PRECEDENCE_RING",
|
|
"VCM_MAX_RING"
|
|
};
|
|
|
|
/* Enum just to make code read better */
|
|
/* the following values must be in sync with the values listed in edcs-387610 */
|
|
typedef enum {
|
|
DISABLE = 1,
|
|
FLASH_ONLY = 2,
|
|
RING_ONCE = 3,
|
|
RING = 4,
|
|
BEEP_ONLY = 5
|
|
} config_value_type_t;
|
|
|
|
cprTimer_t lsm_tmr_tones;
|
|
cprTimer_t lsm_continuous_tmr_tones;
|
|
cprTimer_t lsm_tone_duration_tmr;
|
|
static uint32_t lsm_tmr_tones_ticks;
|
|
static int callWaitingDelay;
|
|
static int ringSettingIdle;
|
|
static int ringSettingActive;
|
|
|
|
/* Ring mode set by remote-cc app */
|
|
static cc_rcc_ring_mode_e cc_line_ringer_mode[MAX_REG_LINES+1] =
|
|
{CC_RING_DEFAULT};
|
|
// Following data has to be non-stack b/c the way SIP stack uses it.
|
|
// It is used by the lsm_is_phone_forwarded() function only.
|
|
static char cfwdall_url[MAX_URL_LENGTH];
|
|
|
|
static void lsm_update_inalert_status(line_t line, callid_t call_id,
|
|
cc_state_data_alerting_t * data,
|
|
boolean notify);
|
|
static void lsm_util_start_tone(vcm_tones_t tone, short alert_info,
|
|
cc_call_handle_t call_handle, groupid_t group_id,
|
|
streamid_t stream_id, uint16_t direction);
|
|
|
|
const char *
|
|
lsm_state_name (lsm_states_t id)
|
|
{
|
|
if ((id <= LSM_S_MIN) || (id >= LSM_S_MAX)) {
|
|
return get_debug_string(GSM_UNDEFINED);
|
|
}
|
|
|
|
return (lsm_state_names[id]);
|
|
}
|
|
|
|
|
|
static const char *
|
|
cc_state_name (cc_states_t id)
|
|
{
|
|
if ((id <= CC_STATE_MIN) || (id >= CC_STATE_MAX)) {
|
|
return (get_debug_string(GSM_UNDEFINED));
|
|
}
|
|
|
|
return (cc_state_names[id]);
|
|
}
|
|
|
|
|
|
static const char *
|
|
cc_action_name (cc_actions_t id)
|
|
{
|
|
if ((id <= CC_ACTION_MIN) || (id >= CC_ACTION_MAX)) {
|
|
return (get_debug_string(GSM_UNDEFINED));
|
|
}
|
|
|
|
return (cc_action_names[id]);
|
|
}
|
|
|
|
|
|
char
|
|
lsm_digit2ch (int digit)
|
|
{
|
|
switch (digit) {
|
|
case 0x0:
|
|
case 0x1:
|
|
case 0x2:
|
|
case 0x3:
|
|
case 0x4:
|
|
case 0x5:
|
|
case 0x6:
|
|
case 0x7:
|
|
case 0x8:
|
|
case 0x9:
|
|
return (char)(digit + '0');
|
|
case 0x0e:
|
|
return ('*');
|
|
case 0x0f:
|
|
return ('#');
|
|
default:
|
|
return ('x');
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
lsm_debug_entry (callid_t call_id, line_t line, const char *fname)
|
|
{
|
|
LSM_DEBUG(get_debug_string(LSM_DBG_ENTRY), call_id, line, fname);
|
|
}
|
|
|
|
static void
|
|
lsm_ui_call_state (call_events event, line_t line, lsm_lcb_t *lcb, cc_causes_t cause)
|
|
{
|
|
if (lcb->previous_call_event != event) {
|
|
lcb->previous_call_event = event;
|
|
|
|
/* For local conference case, the second call is hidden
|
|
* so do not show that when the call is held, resumed,
|
|
* or moved to other state. This should be done only
|
|
* when local bridge is active
|
|
*/
|
|
ui_call_state(event, line, lcb->ui_id, cause);
|
|
}
|
|
else if(event == evConnected) {
|
|
//This is for Chaperone Conference case, if conference changed to a normal call,
|
|
//then need to update the call state to refresh the key's status. like re-enable
|
|
//Confrn key
|
|
ui_call_state(event, line, lcb->ui_id, cause);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This function will control the display of the ringingin call based on the hide arg.
|
|
*
|
|
* @param[in] call_id - call id
|
|
* @param[in] line - line on which call is ringing.
|
|
* @param[in] hide - whether to hide or not
|
|
*
|
|
* @return none
|
|
*
|
|
* @pre (call_id != CC_NO_CALL_ID) and (line != 0)
|
|
*/
|
|
void lsm_display_control_ringin_call (callid_t call_id, line_t line, boolean hide)
|
|
{
|
|
lsm_lcb_t *lcb;
|
|
|
|
lcb = lsm_get_lcb_by_call_id(call_id);
|
|
if (lcb != NULL) {
|
|
ui_call_state(evRingIn, line, lcb->ui_id, CC_CAUSE_NORMAL);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This function will be invoked by DEF SM to set if it is a dusting call.
|
|
* @param[in] call_id - GSM call id.
|
|
*
|
|
* @return none
|
|
*
|
|
* @pre (call_id != CC_NO_CALL_ID)
|
|
*/
|
|
void lsm_set_lcb_dusting_call (callid_t call_id)
|
|
{
|
|
lsm_lcb_t *lcb;
|
|
|
|
lcb = lsm_get_lcb_by_call_id(call_id);
|
|
if (lcb != NULL) {
|
|
FSM_SET_FLAGS(lcb->flags, LSM_FLAGS_DUSTING);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This function will be invoked by DEF SM to set call priority.
|
|
*
|
|
* @param[in] call_id - GSM call id.
|
|
*
|
|
* @return none
|
|
*
|
|
* @pre (call_id != CC_NO_CALL_ID)
|
|
*/
|
|
void lsm_set_lcb_call_priority (callid_t call_id)
|
|
{
|
|
lsm_lcb_t *lcb;
|
|
|
|
lcb = lsm_get_lcb_by_call_id(call_id);
|
|
if (lcb != NULL) {
|
|
FSM_SET_FLAGS(lcb->flags, LSM_FLAGS_CALL_PRIORITY_URGENT);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* This function sets the LSM_FLAGS_DIALED_STRING bit in lcb->flags
|
|
*
|
|
* @param[in] call_id - GSM call id.
|
|
*
|
|
* @return none
|
|
*
|
|
* @pre (call_id != CC_NO_CALL_ID)
|
|
*/
|
|
void lsm_set_lcb_dialed_str_flag (callid_t call_id)
|
|
{
|
|
lsm_lcb_t *lcb;
|
|
|
|
lcb = lsm_get_lcb_by_call_id(call_id);
|
|
if (lcb != NULL) {
|
|
FSM_SET_FLAGS(lcb->flags, LSM_FLAGS_DIALED_STRING);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This function will be invoked by DEF SM to set gcid in lcb.
|
|
*
|
|
* @param[in] call_id - GSM call id.
|
|
* @param[in] gcid - GCID provided by CUCM.
|
|
*
|
|
* @return none
|
|
*
|
|
* @pre (call_id != CC_NO_CALL_ID)
|
|
*/
|
|
void lsm_update_gcid (callid_t call_id, char * gcid)
|
|
{
|
|
lsm_lcb_t *lcb;
|
|
|
|
lcb = lsm_get_lcb_by_call_id(call_id);
|
|
if (lcb != NULL) {
|
|
if (lcb->gcid == NULL) {
|
|
lcb->gcid = (char *)cpr_malloc(CC_GCID_LEN);
|
|
sstrncpy(lcb->gcid, gcid, CC_GCID_LEN);
|
|
}
|
|
}
|
|
|
|
}
|
|
/**
|
|
* This function will be invoked by DEF SM.
|
|
* it will check if there is a RINGIN call
|
|
* with the same GCID. If so, it will set a flag to prevent ringing.
|
|
*
|
|
* @param[in] call_id - GSM call id.
|
|
*
|
|
* @return none
|
|
*
|
|
* @pre (call_id != CC_NO_CALL_ID)
|
|
*/
|
|
void lsm_set_lcb_prevent_ringing (callid_t call_id)
|
|
{
|
|
lsm_lcb_t *lcb;
|
|
char *gcid;
|
|
|
|
lcb = lsm_get_lcb_by_call_id(call_id);
|
|
if (lcb == NULL) {
|
|
return;
|
|
}
|
|
|
|
gcid = lcb->gcid;
|
|
if (gcid == NULL) {
|
|
return;
|
|
}
|
|
|
|
LSM_DEBUG(DEB_L_C_F_PREFIX"gcid=%d.\n",
|
|
DEB_L_C_F_PREFIX_ARGS(LSM, lcb->line, call_id, "lsm_set_lcb_prevent_ringing"), gcid);
|
|
|
|
FSM_FOR_ALL_CBS(lcb, lsm_lcbs, LSM_MAX_LCBS) {
|
|
if (lcb->state == LSM_S_RINGIN) {
|
|
if ((lcb->gcid != NULL) && (strncmp(gcid, lcb->gcid, CC_GCID_LEN) == 0)) {
|
|
LSM_DEBUG(DEB_L_C_F_PREFIX"found ringing call.\n",
|
|
DEB_L_C_F_PREFIX_ARGS(LSM, lcb->line, lcb->call_id, "lsm_set_lcb_prevent_ringing"), gcid);
|
|
FSM_SET_FLAGS(lcb->flags, LSM_FLAGS_PREVENT_RINGING);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void lsm_remove_lcb_prevent_ringing (callid_t call_id)
|
|
{
|
|
lsm_lcb_t *lcb;
|
|
char *gcid;
|
|
|
|
lcb = lsm_get_lcb_by_call_id(call_id);
|
|
if (lcb == NULL) {
|
|
return;
|
|
}
|
|
|
|
gcid = lcb->gcid;
|
|
if (gcid == NULL) {
|
|
return;
|
|
}
|
|
|
|
LSM_DEBUG(DEB_L_C_F_PREFIX"gcid=%d.\n",
|
|
DEB_L_C_F_PREFIX_ARGS(LSM, lcb->line, call_id, "lsm_remove_lcb_prevent_ringing"), gcid);
|
|
|
|
FSM_FOR_ALL_CBS(lcb, lsm_lcbs, LSM_MAX_LCBS) {
|
|
if (lcb->state == LSM_S_RINGIN) {
|
|
if ((lcb->gcid != NULL) && (strncmp(gcid, lcb->gcid, CC_GCID_LEN) == 0)) {
|
|
//FSM_RESET_FLAGS(lcb->flags, LSM_FLAGS_ANSWER_PENDING);
|
|
lcb->flags = 0;
|
|
LSM_DEBUG(DEB_L_C_F_PREFIX"found ringing call, gcid=%d, lcb->flags=%d.\n",
|
|
DEB_L_C_F_PREFIX_ARGS(LSM, lcb->line, lcb->call_id, "lsm_remove_lcb_prevent_ringing"), gcid, lcb->flags);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This function finds if the call is a priority call.
|
|
*
|
|
* @param[in] call_id - GSM call id.
|
|
*
|
|
* @return none
|
|
*
|
|
* @pre (call_id != CC_NO_CALL_ID)
|
|
*/
|
|
boolean lsm_is_it_priority_call (callid_t call_id)
|
|
{
|
|
lsm_lcb_t *lcb;
|
|
|
|
lcb = lsm_get_lcb_by_call_id(call_id);
|
|
if (lcb == NULL) {
|
|
return FALSE;
|
|
}
|
|
if (FSM_CHK_FLAGS(lcb->flags, LSM_FLAGS_CALL_PRIORITY_URGENT)) {
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* Function: lsm_internal_update_call_info
|
|
*
|
|
* Parameters:
|
|
* lcb - pointer to lsm_lcb_t.
|
|
* dcb - pointer to fsmdef_dcb_t.
|
|
*
|
|
* Description: This is an internal function of LSM for updating call
|
|
* information to the UI that is not directly driven by the
|
|
* the explicit CALL INFO event from call control.
|
|
*
|
|
* It is a convenient function that used by some of the
|
|
* LSM handling function that needs to update call information
|
|
* to the UI during media changes.
|
|
*
|
|
* Returns:
|
|
* None.
|
|
*
|
|
*/
|
|
static void
|
|
lsm_internal_update_call_info (lsm_lcb_t *lcb, fsmdef_dcb_t *dcb)
|
|
{
|
|
boolean inbound;
|
|
calltype_t call_type;
|
|
fsmcnf_ccb_t *ccb;
|
|
|
|
if ((lcb == NULL) || (dcb == NULL)) {
|
|
return;
|
|
}
|
|
|
|
if (!dcb->ui_update_required) {
|
|
return;
|
|
}
|
|
|
|
/* For local conference, do not update the primary
|
|
* call bubbles call-info. Primary call is already
|
|
* displaying To conference in this case
|
|
* But dcb-> caller_id should be updated to
|
|
* refresh the UI when the call is dropped
|
|
*/
|
|
ccb = fsmcnf_get_ccb_by_call_id(lcb->call_id);
|
|
if (ccb && (ccb->flags & LCL_CNF) && (ccb->active)
|
|
&& (ccb->cnf_call_id == lcb->call_id)) {
|
|
return;
|
|
}
|
|
dcb->ui_update_required = FALSE;
|
|
|
|
/* Derive orientation of the call */
|
|
switch (dcb->orientation) {
|
|
case CC_ORIENTATION_FROM:
|
|
inbound = TRUE;
|
|
break;
|
|
|
|
case CC_ORIENTATION_TO:
|
|
inbound = FALSE;
|
|
break;
|
|
|
|
default:
|
|
/*
|
|
* No orientation available, use the direction when call was started
|
|
*/
|
|
inbound = dcb->inbound;
|
|
break;
|
|
}
|
|
|
|
if ((dcb->call_type == FSMDEF_CALL_TYPE_FORWARD)
|
|
&& fsmdef_check_retain_fwd_info_state()) {
|
|
call_type = (inbound) ? (calltype_t)dcb->call_type:FSMDEF_CALL_TYPE_OUTGOING;
|
|
} else {
|
|
if (inbound) {
|
|
call_type = FSMDEF_CALL_TYPE_INCOMING;
|
|
} else {
|
|
call_type = FSMDEF_CALL_TYPE_OUTGOING;
|
|
}
|
|
}
|
|
|
|
ui_call_info(dcb->caller_id.calling_name,
|
|
dcb->caller_id.calling_number,
|
|
dcb->caller_id.alt_calling_number,
|
|
dcb->caller_id.display_calling_number,
|
|
dcb->caller_id.called_name,
|
|
dcb->caller_id.called_number,
|
|
dcb->caller_id.display_called_number,
|
|
dcb->caller_id.orig_called_name,
|
|
dcb->caller_id.orig_called_number,
|
|
dcb->caller_id.last_redirect_name,
|
|
dcb->caller_id.last_redirect_number,
|
|
call_type,
|
|
lcb->line, lcb->ui_id,
|
|
dcb->caller_id.call_instance_id,
|
|
FSM_GET_SECURITY_STATUS(dcb),
|
|
FSM_GET_POLICY(dcb));
|
|
|
|
}
|
|
|
|
/**
|
|
* The function opens receive channel or allocates receive port. It depends
|
|
* on the "keep" member of the cc_action_data_open_rcv_t structure set
|
|
* up by the caller to whether opens a receive channel or just
|
|
* to allocate a receive port.
|
|
*
|
|
* @param[in] lcb - pointer to the lsm_lcb_t.
|
|
* @param[in/out] data - pointer to the cc_action_data_open_rcv_t.
|
|
* Upon a successful return, the port element
|
|
* of this structure will be filled with the actual
|
|
* receive port.
|
|
* @param[in] media - pointer to the fsmdef_media_t if a specific
|
|
* media to be operated on.
|
|
*
|
|
* @return CC_RC_ERROR or CC_RC_SUCCESS.
|
|
*
|
|
* @pre (lcb is_not NULL) and (data is_not NULL)
|
|
*/
|
|
static cc_rcs_t
|
|
lsm_open_rx (lsm_lcb_t *lcb, cc_action_data_open_rcv_t *data,
|
|
fsmdef_media_t *media)
|
|
{
|
|
static const char fname[] = "lsm_open_rx";
|
|
int port_allocated = 0;
|
|
cc_rcs_t rc = CC_RC_ERROR;
|
|
fsmdef_dcb_t *dcb;
|
|
int sdpmode = 0;
|
|
|
|
dcb = lcb->dcb;
|
|
if (dcb == NULL) {
|
|
return (rc);
|
|
}
|
|
|
|
/*
|
|
* P2: At this point, it is a guess that refid from media structure
|
|
* may be needed. If it turns out to be not the case, then the
|
|
* code below that looks up media should be removed including
|
|
* the media parameter that is passed in.
|
|
*/
|
|
if (media == NULL) {
|
|
/* no explicit media parameter specified, look up based on refID */
|
|
if (data->media_refid != CC_NO_MEDIA_REF_ID) {
|
|
media = gsmsdp_find_media_by_refid(dcb,
|
|
data->media_refid);
|
|
}
|
|
if (media == NULL) {
|
|
LSM_DEBUG(get_debug_string(LSM_DBG_INT1), lcb->call_id,
|
|
lcb->line, fname, "no media refID %d found",
|
|
data->media_refid);
|
|
return (rc);
|
|
}
|
|
}
|
|
|
|
LSM_DEBUG(get_debug_string(LSM_DBG_INT1), lcb->call_id, lcb->line, fname,
|
|
"requested port", data->port);
|
|
|
|
|
|
sdpmode = 0;
|
|
config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
|
|
|
|
if (data->keep == TRUE) {
|
|
if (sdpmode && strlen(dcb->peerconnection)) {
|
|
/* If we are doing ICE, don't try to re-open */
|
|
port_allocated = data->port;
|
|
}
|
|
else {
|
|
//Todo IPv6: Add interface call for IPv6
|
|
(void) vcmRxOpen(media->cap_index, dcb->group_id, media->refid,
|
|
lsm_get_ms_ui_call_handle(lcb->line, lcb->call_id, lcb->ui_id), data->port,
|
|
media->is_multicast ? &media->dest_addr:&media->src_addr, data->is_multicast,
|
|
&port_allocated);
|
|
}
|
|
if (port_allocated != -1) {
|
|
data->port = (uint16_t)port_allocated;
|
|
rc = CC_RC_SUCCESS;
|
|
}
|
|
} else {
|
|
|
|
if (sdpmode) {
|
|
if (!strlen(dcb->peerconnection)) {
|
|
vcmRxAllocPort(media->cap_index, dcb->group_id, media->refid,
|
|
lsm_get_ms_ui_call_handle(lcb->line, lcb->call_id, lcb->ui_id),
|
|
data->port,
|
|
&port_allocated);
|
|
if (port_allocated != -1) {
|
|
data->port = (uint16_t)port_allocated;
|
|
rc = CC_RC_SUCCESS;
|
|
}
|
|
} else {
|
|
char **candidates;
|
|
int candidate_ct;
|
|
char *default_addr;
|
|
|
|
vcmRxAllocICE(media->cap_index, dcb->group_id, media->refid,
|
|
lsm_get_ms_ui_call_handle(lcb->line, lcb->call_id, lcb->ui_id),
|
|
dcb->peerconnection,
|
|
media->level,
|
|
&default_addr, &port_allocated,
|
|
&candidates, &candidate_ct);
|
|
|
|
// Check that we got a valid address and port
|
|
if (default_addr && (strlen(default_addr) > 0) && (port_allocated != -1)) {
|
|
sstrncpy(dcb->ice_default_candidate_addr, default_addr, sizeof(dcb->ice_default_candidate_addr));
|
|
|
|
data->port = (uint16_t)port_allocated;
|
|
media->candidate_ct = candidate_ct;
|
|
media->candidatesp = candidates;
|
|
rc = CC_RC_SUCCESS;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
LSM_DEBUG(get_debug_string(LSM_DBG_INT1), lcb->call_id, lcb->line, fname,
|
|
"allocated port", port_allocated);
|
|
|
|
return (rc);
|
|
}
|
|
/*
|
|
* This function updates the dscp value based on whether video is enable or not
|
|
* and video is active or not.
|
|
* @param[in] dcb - pointer to the fsmdef_dcb.
|
|
*/
|
|
|
|
void lsm_update_dscp_value(fsmdef_dcb_t *dcb)
|
|
{
|
|
static const char fname[] = "lsm_update_dscp_value";
|
|
int dscp = 184; /* default 184 used for DSCP */
|
|
// depending upon video is enabled or disabled ,set the dscp value.
|
|
if (dcb != NULL && dcb->cur_video_avail != SDP_DIRECTION_INACTIVE ) {
|
|
config_get_value(CFGID_DSCP_VIDEO, (int *)&dscp, sizeof(dscp));
|
|
} else {
|
|
config_get_value(CFGID_DSCP_AUDIO, (int *)&dscp, sizeof(dscp));
|
|
}
|
|
// We would use DSCP for video for both audio and video streams if this is a video call
|
|
if (dcb != NULL) {
|
|
LSM_DEBUG(DEB_L_C_F_PREFIX"Setting dscp=%d for Rx group_id=%d \n",
|
|
DEB_L_C_F_PREFIX_ARGS(LSM, dcb->line, dcb->call_id, fname), dscp, dcb->group_id);
|
|
vcmSetRtcpDscp(dcb->group_id, dscp);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The function closes receive channel for a given media entry.
|
|
* The receive channel may not be closed if the caller intents to
|
|
* fresh the channel i.e close if needed but otherwise leave it open.
|
|
* When the caller indicates refreshing, the receive channel
|
|
* will be closed only when there is a difference in current SDP and
|
|
* the previous SDP.
|
|
*
|
|
* @param[in] lcb - pointer to the lsm_lcb_t.
|
|
* @param[in] refresh - channel to be refreshed i.e. close if necessary.
|
|
* @param[in] media - pointer to the fsmdef_media_t for the
|
|
* media entry to be refresh.
|
|
*
|
|
* If the value of media is NULL, it indicates that
|
|
* all current inused media entries.
|
|
*
|
|
* @return None.
|
|
*
|
|
* @pre (lcb is_not NULL)
|
|
*/
|
|
static void
|
|
lsm_close_rx (lsm_lcb_t *lcb, boolean refresh, fsmdef_media_t *media)
|
|
{
|
|
static const char fname[] = "lsm_close_rx";
|
|
fsmdef_media_t *start_media, *end_media;
|
|
fsmdef_dcb_t *dcb;
|
|
int sdpmode = 0;
|
|
|
|
dcb = lcb->dcb;
|
|
if (dcb == NULL) {
|
|
LSM_ERR_MSG(get_debug_string(DEBUG_INPUT_NULL), fname);
|
|
return;
|
|
}
|
|
|
|
LSM_DEBUG(DEB_L_C_F_PREFIX"Called with refresh set to %d\n",
|
|
DEB_L_C_F_PREFIX_ARGS(LSM, dcb->line, dcb->call_id, fname), refresh);
|
|
|
|
if (media == NULL) {
|
|
/* NULL value of the given media indicates for all media */
|
|
start_media = GSMSDP_FIRST_MEDIA_ENTRY(dcb);
|
|
end_media = NULL; /* NULL means till the end of the list */
|
|
} else {
|
|
/* given media, uses the provided media */
|
|
start_media = media;
|
|
end_media = media;
|
|
}
|
|
|
|
/* close receive port on the media(s) */
|
|
GSMSDP_FOR_MEDIA_LIST(media, start_media, end_media, dcb) {
|
|
if (media->rcv_chan) {
|
|
/*
|
|
* If caller is releasing the port or if the caller is
|
|
* recycling the receive port and the codec has changed, close the
|
|
* receive port. Also stop bridging of media streams.
|
|
*/
|
|
if (!refresh ||
|
|
(refresh &&
|
|
gsmsdp_sdp_differs_from_previous_sdp(TRUE, media))) {
|
|
LSM_DEBUG(get_debug_string(LSM_DBG_INT1), dcb->call_id,
|
|
dcb->line, fname, "port closed",
|
|
media->src_port);
|
|
|
|
config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
|
|
if (!sdpmode) {
|
|
|
|
vcmRxClose(media->cap_index, dcb->group_id, media->refid,
|
|
lsm_get_ms_ui_call_handle(lcb->line, lcb->call_id, lcb->ui_id));
|
|
}
|
|
media->rcv_chan = FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The function closes transmit channel for a given media entry.
|
|
* The transmit channel may not be closed if the caller intents to
|
|
* fresh the port i.e close if needed but otherwise leave it open.
|
|
* When the caller indicates refreshing, the transmit channel
|
|
* will be closed only when there is a difference in current SDP and
|
|
* the previous SDP.
|
|
*
|
|
* @param[in] lcb - pointer to the lsm_lcb_t.
|
|
* @param[in] refresh - channel to be refreshed i.e. close if necessary.
|
|
* @param[in] media - pointer to the fsmdef_media_t for the
|
|
* media entry to be refresh.
|
|
*
|
|
* If the value of media is NULL, it indicates that
|
|
* all current inused media entries.
|
|
*
|
|
* @return None.
|
|
*
|
|
* @pre (lcb is_not NULL)
|
|
*/
|
|
static void
|
|
lsm_close_tx (lsm_lcb_t *lcb, boolean refresh, fsmdef_media_t *media)
|
|
{
|
|
fsmdef_media_t *start_media, *end_media;
|
|
fsmdef_dcb_t *dcb;
|
|
static const char fname[] = "lsm_close_tx";
|
|
int sdpmode = 0;
|
|
|
|
dcb = lcb->dcb;
|
|
if (dcb == NULL) {
|
|
LSM_ERR_MSG(get_debug_string(DEBUG_INPUT_NULL), fname);
|
|
return;
|
|
}
|
|
LSM_DEBUG(DEB_L_C_F_PREFIX"called with refresh set to %d\n",
|
|
DEB_L_C_F_PREFIX_ARGS(LSM, dcb->line, dcb->call_id, fname), refresh);
|
|
|
|
config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
|
|
|
|
if (media == NULL) {
|
|
/* NULL value of the given media indicates for all media */
|
|
start_media = GSMSDP_FIRST_MEDIA_ENTRY(dcb);
|
|
end_media = NULL; /* NULL means till the end of the list */
|
|
} else {
|
|
/* given media, uses the provided media */
|
|
start_media = media;
|
|
end_media = media;
|
|
}
|
|
|
|
/*
|
|
* Close the RTP, but only if this call is using it and the capabilities
|
|
* have changed.
|
|
*/
|
|
GSMSDP_FOR_MEDIA_LIST(media, start_media, end_media, dcb) {
|
|
if (media->xmit_chan == TRUE) {
|
|
|
|
if (!refresh ||
|
|
(refresh &&
|
|
gsmsdp_sdp_differs_from_previous_sdp(FALSE, media))) {
|
|
|
|
if (!sdpmode) {
|
|
vcmTxClose(media->cap_index, dcb->group_id, media->refid,
|
|
lsm_get_ms_ui_call_handle(lcb->line, lcb->call_id, lcb->ui_id));
|
|
}
|
|
|
|
if (dcb->active_tone == VCM_MONITORWARNING_TONE || dcb->active_tone == VCM_RECORDERWARNING_TONE) {
|
|
LSM_DEBUG(DEB_L_C_F_PREFIX"%s: Found active_tone: %d being played, current monrec_tone_action: %d. Need stop tone. \n",
|
|
DEB_L_C_F_PREFIX_ARGS(LSM, dcb->line, dcb->call_id, fname), fname,
|
|
dcb->active_tone, dcb->monrec_tone_action);
|
|
(void) lsm_stop_tone(lcb, NULL);
|
|
}
|
|
media->xmit_chan = FALSE;
|
|
LSM_DEBUG(DEB_L_C_F_PREFIX"closed",
|
|
DEB_L_C_F_PREFIX_ARGS(LSM, dcb->line, dcb->call_id, fname));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The function starts receive channel for a given media entry.
|
|
*
|
|
* @param[in] lcb - pointer to the lsm_lcb_t.
|
|
* @param[in] fname - pointer to to const. char for the name
|
|
* of the function that calls to this function.
|
|
* It is for debuging purpose.
|
|
* @param[in] media - pointer to the fsmdef_media_t for the
|
|
* media entry to be refresh.
|
|
*
|
|
* If the value of media is NULL, it indicates that
|
|
* all current inused media entries.
|
|
*
|
|
* @return None.
|
|
*
|
|
* @pre (lcb is_not NULL)
|
|
*/
|
|
static void
|
|
lsm_rx_start (lsm_lcb_t *lcb, const char *fname, fsmdef_media_t *media)
|
|
{
|
|
static const char fname1[] = "lsm_rx_start";
|
|
cc_action_data_open_rcv_t open_rcv;
|
|
uint16_t port;
|
|
groupid_t group_id = CC_NO_GROUP_ID;
|
|
callid_t call_id = lcb->call_id;
|
|
vcm_mixing_mode_t mix_mode = VCM_NO_MIX;
|
|
vcm_mixing_party_t mix_party = VCM_PARTY_NONE;
|
|
int ret_val;
|
|
fsmdef_media_t *start_media, *end_media;
|
|
boolean has_checked_conference = FALSE;
|
|
fsmdef_dcb_t *dcb, *grp_id_dcb;
|
|
vcm_mediaAttrs_t attrs;
|
|
int sdpmode = 0;
|
|
int pc_stream_id = 0;
|
|
int pc_track_id = 0;
|
|
attrs.video.opaque = NULL;
|
|
|
|
dcb = lcb->dcb;
|
|
if (dcb == NULL) {
|
|
LSM_ERR_MSG(get_debug_string(DEBUG_INPUT_NULL), fname1);
|
|
return;
|
|
}
|
|
group_id = dcb->group_id;
|
|
if (media == NULL) {
|
|
/* NULL value of the given media indicates for all media */
|
|
start_media = GSMSDP_FIRST_MEDIA_ENTRY(dcb);
|
|
end_media = NULL; /* NULL means till the end of the list */
|
|
} else {
|
|
/* given media, uses the provided media */
|
|
start_media = media;
|
|
end_media = media;
|
|
}
|
|
|
|
/* Start receive channel for the media(s) */
|
|
GSMSDP_FOR_MEDIA_LIST(media, start_media, end_media, dcb) {
|
|
if (!GSMSDP_MEDIA_ENABLED(media)) {
|
|
/* this entry is not enabled */
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* Check to see if the receive port can be opened.
|
|
* For SRTP, the receive can not be opened if the remote's crypto
|
|
* parameters are not received yet.
|
|
*/
|
|
if (!gsmsdp_is_crypto_ready(media, TRUE)) {
|
|
LSM_DEBUG(DEB_L_C_F_PREFIX"%s: Not ready to open receive port (%d)\n",
|
|
DEB_L_C_F_PREFIX_ARGS(LSM, dcb->line, dcb->call_id, fname1), fname, media->src_port);
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* Open the RTP receive channel if it is not already open.
|
|
*/
|
|
LSM_DEBUG(get_debug_string(LSM_DBG_INT1), dcb->call_id, dcb->line,
|
|
fname1, "rcv chan", media->rcv_chan);
|
|
if (media->rcv_chan == FALSE) {
|
|
|
|
memset(&open_rcv, 0, sizeof(open_rcv));
|
|
port = media->src_port;
|
|
|
|
if (media->is_multicast &&
|
|
(media->direction == SDP_DIRECTION_RECVONLY)) {
|
|
open_rcv.is_multicast = media->is_multicast;
|
|
open_rcv.listen_ip = media->dest_addr;
|
|
port = media->multicast_port;
|
|
}
|
|
open_rcv.port = port;
|
|
open_rcv.keep = TRUE;
|
|
open_rcv.media_type = media->type;
|
|
|
|
if (!has_checked_conference) {
|
|
switch(dcb->session)
|
|
{
|
|
case WHISPER_COACHING:
|
|
mix_mode = VCM_MIX;
|
|
mix_party = VCM_PARTY_TxBOTH_RxNONE;
|
|
grp_id_dcb = fsmdef_get_dcb_by_call_id(dcb->join_call_id);
|
|
if (grp_id_dcb == NULL) {
|
|
LSM_ERR_MSG(get_debug_string(DEBUG_INPUT_NULL), fname1);
|
|
} else {
|
|
group_id = grp_id_dcb->group_id;
|
|
}
|
|
break;
|
|
|
|
case MONITOR:
|
|
case LOCAL_CONF:
|
|
//AgentGreeting is MIX RXBOTH, SilentMonitoring is MIX TXBOTH
|
|
//so we have to use VCM_PARTY_BOTH for case MONITOR
|
|
mix_mode = VCM_MIX;
|
|
mix_party = VCM_PARTY_BOTH;
|
|
break;
|
|
case PRIMARY:
|
|
default:
|
|
mix_mode = VCM_NO_MIX;
|
|
mix_party = VCM_PARTY_NONE;
|
|
break;
|
|
}
|
|
has_checked_conference = TRUE;
|
|
}
|
|
|
|
if (lsm_open_rx(lcb, &open_rcv, media) != CC_RC_SUCCESS) {
|
|
LSM_ERR_MSG(LSM_L_C_F_PREFIX"%s: open receive port (%d) failed.\n",
|
|
dcb->line, dcb->call_id, fname1,
|
|
fname, media->src_port);
|
|
} else {
|
|
/* successful open receive channel */
|
|
media->rcv_chan = TRUE; /* recevied channel is created */
|
|
/* save the source RX port */
|
|
if (media->is_multicast) {
|
|
media->multicast_port = open_rcv.port;
|
|
} else {
|
|
media->src_port = open_rcv.port;
|
|
}
|
|
|
|
/* TODO(ekr@rtfm.com): Needs changing for when we have > 2 streams */
|
|
if ( media->cap_index == CC_VIDEO_1 ) {
|
|
attrs.video.opaque = media->video;
|
|
pc_stream_id = 1;
|
|
} else {
|
|
attrs.audio.packetization_period = media->packetization_period;
|
|
attrs.audio.max_packetization_period = media->max_packetization_period;
|
|
attrs.audio.avt_payload_type = media->avt_payload_type;
|
|
attrs.audio.mixing_mode = mix_mode;
|
|
attrs.audio.mixing_party = mix_party;
|
|
pc_stream_id = 0;
|
|
}
|
|
pc_track_id = 0;
|
|
dcb->cur_video_avail &= ~CC_ATTRIB_CAST;
|
|
|
|
config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
|
|
if (dcb->peerconnection) {
|
|
ret_val = vcmRxStartICE(media->cap_index, group_id, media->refid,
|
|
media->level,
|
|
pc_stream_id,
|
|
pc_track_id,
|
|
lsm_get_ms_ui_call_handle(dcb->line, call_id, CC_NO_CALL_ID),
|
|
dcb->peerconnection,
|
|
media->num_payloads,
|
|
media->payloads,
|
|
FSM_NEGOTIATED_CRYPTO_DIGEST_ALGORITHM(media),
|
|
FSM_NEGOTIATED_CRYPTO_DIGEST(media),
|
|
&attrs);
|
|
} else if (!sdpmode) {
|
|
if (media->payloads == NULL) {
|
|
LSM_ERR_MSG(get_debug_string(DEBUG_INPUT_NULL), fname1);
|
|
return;
|
|
}
|
|
ret_val = vcmRxStart(media->cap_index, group_id, media->refid,
|
|
lsm_get_ms_ui_call_handle(dcb->line, call_id, CC_NO_CALL_ID),
|
|
media->payloads,
|
|
media->is_multicast ? &media->dest_addr:&media->src_addr,
|
|
port,
|
|
FSM_NEGOTIATED_CRYPTO_ALGORITHM_ID(media),
|
|
FSM_NEGOTIATED_CRYPTO_RX_KEY(media),
|
|
&attrs);
|
|
if (ret_val == -1) {
|
|
dcb->dsp_out_of_resources = TRUE;
|
|
return;
|
|
}
|
|
} else {
|
|
ret_val = CC_RC_ERROR;
|
|
}
|
|
|
|
lsm_update_dscp_value(dcb);
|
|
|
|
if (dcb->play_tone_action == FSMDEF_PLAYTONE_ZIP)
|
|
{
|
|
vcm_tones_t tone = VCM_ZIP;
|
|
uint16_t direction = dcb->tone_direction;
|
|
|
|
LSM_DEBUG(DEB_L_C_F_PREFIX"%s: Found play_tone_action: %d. Need to play tone.\n",
|
|
DEB_L_C_F_PREFIX_ARGS(LSM, dcb->line, dcb->call_id, fname), fname, dcb->play_tone_action);
|
|
|
|
// reset to initialized values
|
|
dcb->play_tone_action = FSMDEF_PLAYTONE_NO_ACTION;
|
|
dcb->tone_direction = VCM_PLAY_TONE_TO_EAR;
|
|
|
|
lsm_util_tone_start_with_speaker_as_backup(tone, VCM_ALERT_INFO_OFF,
|
|
lsm_get_ms_ui_call_handle(dcb->line, dcb->call_id, CC_NO_CALL_ID),
|
|
dcb->group_id,
|
|
((media != NULL) ? media->refid : CC_NO_MEDIA_REF_ID),
|
|
direction);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The function starts transmit channel for a given media entry.
|
|
*
|
|
* @param[in] lcb - pointer to the lsm_lcb_t.
|
|
* @param[in] fname - pointer to to const. char for the name
|
|
* of the function that calls to this function.
|
|
* It is for debuging purpose.
|
|
* @param[in] media - pointer to the fsmdef_media_t for the
|
|
* media entry to be refresh.
|
|
*
|
|
* If the value of media is NULL, it indicates that
|
|
* all current inused media entries.
|
|
*
|
|
* @return None.
|
|
*
|
|
* @pre (lcb is_not NULL)
|
|
*/
|
|
|
|
#define LSM_TMP_VAD_LEN 64
|
|
|
|
static void
|
|
lsm_tx_start (lsm_lcb_t *lcb, const char *fname, fsmdef_media_t *media)
|
|
{
|
|
static const char fname1[] = "lsm_tx_start";
|
|
int dscp = 184; /* default 184 used for DSCP */
|
|
char tmp[LSM_TMP_VAD_LEN];
|
|
fsmcnf_ccb_t *ccb = NULL;
|
|
groupid_t group_id;
|
|
callid_t call_id = lcb->call_id;
|
|
vcm_mixing_mode_t mix_mode = VCM_NO_MIX;
|
|
vcm_mixing_party_t mix_party = VCM_PARTY_NONE;
|
|
fsmdef_media_t *start_media, *end_media;
|
|
boolean has_checked_conference = FALSE;
|
|
fsmdef_dcb_t *dcb;
|
|
vcm_mediaAttrs_t attrs;
|
|
int sdpmode;
|
|
long strtol_result;
|
|
char *strtol_end;
|
|
|
|
attrs.video.opaque = NULL;
|
|
|
|
dcb = lcb->dcb;
|
|
if (dcb == NULL) {
|
|
LSM_ERR_MSG(get_debug_string(DEBUG_INPUT_NULL), fname1);
|
|
return;
|
|
}
|
|
// Set the DSCP value for RTP stream.
|
|
if ( media != NULL ){
|
|
// We would use DSCP for video for both audio and video streams if this
|
|
// is a video call
|
|
if ( dcb->cur_video_avail != SDP_DIRECTION_INACTIVE ) {
|
|
config_get_value(CFGID_DSCP_VIDEO, (int *)&dscp, sizeof(dscp));
|
|
} else if ( CC_IS_AUDIO(media->cap_index)){
|
|
// audio stream for audio only call shall use the DSCP for audio
|
|
// value.
|
|
config_get_value(CFGID_DSCP_AUDIO, (int *)&dscp, sizeof(dscp));
|
|
}
|
|
}
|
|
group_id = dcb->group_id;
|
|
LSM_DEBUG(DEB_L_C_F_PREFIX"invoked\n", DEB_L_C_F_PREFIX_ARGS(LSM, dcb->line, dcb->call_id, fname1));
|
|
|
|
if (media == NULL) {
|
|
/* NULL value of the given media indicates for all media */
|
|
start_media = GSMSDP_FIRST_MEDIA_ENTRY(dcb);
|
|
end_media = NULL; /* NULL means till the end of the list */
|
|
} else {
|
|
/* given media, uses the provided media */
|
|
start_media = media;
|
|
end_media = media;
|
|
}
|
|
|
|
/* Start receive channel for the media(s) */
|
|
GSMSDP_FOR_MEDIA_LIST(media, start_media, end_media, dcb) {
|
|
if (!GSMSDP_MEDIA_ENABLED(media)) {
|
|
/* this entry is not enabled */
|
|
continue;
|
|
}
|
|
/*
|
|
* Check to see if the transmit port can be opened.
|
|
* For SRTP, the transmit port can not be opened if the remote's crypto
|
|
* parameters are not received yet.
|
|
*/
|
|
if (!gsmsdp_is_crypto_ready(media, FALSE)) {
|
|
LSM_DEBUG(DEB_L_C_F_PREFIX"%s: Not ready to open transmit port\n",
|
|
DEB_L_C_F_PREFIX_ARGS(LSM, dcb->line, dcb->call_id, fname1), fname);
|
|
continue;
|
|
}
|
|
if (media->xmit_chan == FALSE && dcb->remote_sdp_present &&
|
|
media->dest_addr.type != CPR_IP_ADDR_INVALID && media->dest_port) {
|
|
|
|
/* evaluate the mode and group id once for all media entries */
|
|
if (!has_checked_conference) {
|
|
switch(dcb->session)
|
|
{
|
|
case WHISPER_COACHING:
|
|
mix_mode = VCM_MIX;
|
|
mix_party = VCM_PARTY_TxBOTH_RxNONE;
|
|
group_id = fsmdef_get_dcb_by_call_id(dcb->join_call_id)->group_id;
|
|
break;
|
|
|
|
case MONITOR:
|
|
case LOCAL_CONF:
|
|
//AgentGreeting is MIX RXBOTH, SilentMonitoring is MIX TXBOTH
|
|
//so we have to use VCM_PARTY_BOTH for case MONITOR
|
|
mix_mode = VCM_MIX;
|
|
mix_party = VCM_PARTY_BOTH;
|
|
break;
|
|
case PRIMARY:
|
|
default:
|
|
mix_mode = VCM_NO_MIX;
|
|
mix_party = VCM_PARTY_NONE;
|
|
break;
|
|
}
|
|
has_checked_conference = TRUE;
|
|
}
|
|
|
|
/*
|
|
* Set the VAD value.
|
|
*/
|
|
/* can't use vad on conference calls - the dsp can't handle it. */
|
|
ccb = fsmcnf_get_ccb_by_call_id(lcb->call_id);
|
|
if (ccb != NULL) {
|
|
media->vad = VCM_VAD_OFF;
|
|
} else {
|
|
config_get_string(CFGID_ENABLE_VAD, tmp, sizeof(tmp));
|
|
|
|
errno = 0;
|
|
|
|
strtol_result = strtol(tmp, &strtol_end, 10);
|
|
|
|
if (errno || tmp == strtol_end ||
|
|
strtol_result < VCM_VAD_OFF || strtol_result > VCM_VAD_ON) {
|
|
LSM_ERR_MSG("%s parse error of vad: %s", __FUNCTION__, tmp);
|
|
return;
|
|
}
|
|
|
|
media->vad = (vcm_vad_t) strtol_result;
|
|
}
|
|
|
|
/*
|
|
* Open the transmit port and start sending, but only if we have
|
|
* the SDP for the remote end.
|
|
*/
|
|
|
|
sdpmode = 0;
|
|
config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
|
|
if (!sdpmode) {
|
|
|
|
if (vcmTxOpen(media->cap_index, dcb->group_id, media->refid,
|
|
lsm_get_ms_ui_call_handle(lcb->line, lcb->call_id, lcb->ui_id)) != 0) {
|
|
LSM_DEBUG(DEB_L_C_F_PREFIX"%s: vcmTxOpen failed\n",
|
|
DEB_L_C_F_PREFIX_ARGS(LSM, dcb->line, dcb->call_id, fname1), fname);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
media->xmit_chan = TRUE;
|
|
|
|
attrs.mute = FALSE;
|
|
if ( CC_IS_VIDEO(media->cap_index)) {
|
|
attrs.video.opaque = media->video;
|
|
if (lcb->vid_mute) {
|
|
attrs.mute = TRUE;
|
|
}
|
|
|
|
} else if ( CC_IS_AUDIO(media->cap_index)){
|
|
attrs.audio.packetization_period = media->packetization_period;
|
|
attrs.audio.max_packetization_period = media->max_packetization_period;
|
|
attrs.audio.avt_payload_type = media->avt_payload_type;
|
|
attrs.audio.vad = media->vad;
|
|
attrs.audio.mixing_mode = mix_mode;
|
|
attrs.audio.mixing_party = mix_party;
|
|
}
|
|
|
|
dcb->cur_video_avail &= ~CC_ATTRIB_CAST;
|
|
|
|
if (media->payloads == NULL) {
|
|
LSM_ERR_MSG(get_debug_string(DEBUG_INPUT_NULL), fname1);
|
|
return;
|
|
}
|
|
if (!strlen(dcb->peerconnection)){
|
|
if (vcmTxStart(media->cap_index, group_id,
|
|
media->refid,
|
|
lsm_get_ms_ui_call_handle(dcb->line, call_id, CC_NO_CALL_ID),
|
|
media->payloads,
|
|
(short)dscp,
|
|
&media->src_addr,
|
|
media->src_port,
|
|
&media->dest_addr,
|
|
media->dest_port,
|
|
FSM_NEGOTIATED_CRYPTO_ALGORITHM_ID(media),
|
|
FSM_NEGOTIATED_CRYPTO_TX_KEY(media),
|
|
&attrs) == -1)
|
|
{
|
|
LSM_DEBUG(DEB_L_C_F_PREFIX"%s: vcmTxStart failed\n",
|
|
DEB_L_C_F_PREFIX_ARGS(LSM, dcb->line, dcb->call_id, fname1), fname);
|
|
dcb->dsp_out_of_resources = TRUE;
|
|
return;
|
|
}
|
|
}
|
|
else {
|
|
if (vcmTxStartICE(media->cap_index, group_id,
|
|
media->refid,
|
|
media->level,
|
|
/* TODO(emannion): his perhaps needs some error checking for validity.
|
|
See gsmsdp_get_media_cap_entry_by_index. */
|
|
dcb->media_cap_tbl->cap[media->cap_index].pc_stream,
|
|
dcb->media_cap_tbl->cap[media->cap_index].pc_track,
|
|
lsm_get_ms_ui_call_handle(dcb->line, call_id, CC_NO_CALL_ID),
|
|
dcb->peerconnection,
|
|
media->payloads,
|
|
(short)dscp,
|
|
FSM_NEGOTIATED_CRYPTO_DIGEST_ALGORITHM(media),
|
|
FSM_NEGOTIATED_CRYPTO_DIGEST(media),
|
|
&attrs) == -1)
|
|
{
|
|
LSM_DEBUG(DEB_L_C_F_PREFIX"%s: vcmTxStartICE failed\n",
|
|
DEB_L_C_F_PREFIX_ARGS(LSM, dcb->line, dcb->call_id, fname1), fname);
|
|
dcb->dsp_out_of_resources = TRUE;
|
|
return;
|
|
}
|
|
}
|
|
|
|
lsm_update_dscp_value(dcb);
|
|
|
|
LSM_DEBUG(DEB_L_C_F_PREFIX"%s: vcmTxStart started\n",
|
|
DEB_L_C_F_PREFIX_ARGS(LSM, dcb->line, dcb->call_id, fname1), fname);
|
|
|
|
if ( dcb->monrec_tone_action != FSMDEF_MRTONE_NO_ACTION)
|
|
{
|
|
vcm_tones_t tone = VCM_NO_TONE;
|
|
uint16_t direction = VCM_PLAY_TONE_TO_EAR;
|
|
boolean play_both_tones = FALSE;
|
|
|
|
LSM_DEBUG(DEB_L_C_F_PREFIX"%s: Found monrec_tone_action: %d. Need to restart playing tone.\n",
|
|
DEB_L_C_F_PREFIX_ARGS(LSM, dcb->line, dcb->call_id, fname), fname, dcb->monrec_tone_action);
|
|
|
|
switch (dcb->monrec_tone_action) {
|
|
case FSMDEF_MRTONE_RESUME_MONITOR_TONE:
|
|
tone = VCM_MONITORWARNING_TONE;
|
|
direction = dcb->monitor_tone_direction;
|
|
break;
|
|
|
|
case FSMDEF_MRTONE_RESUME_RECORDER_TONE:
|
|
tone = VCM_RECORDERWARNING_TONE;
|
|
direction = dcb->recorder_tone_direction;
|
|
break;
|
|
|
|
case FSMDEF_MRTONE_RESUME_BOTH_TONES:
|
|
play_both_tones = TRUE;
|
|
tone = VCM_MONITORWARNING_TONE;
|
|
direction = dcb->monitor_tone_direction;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (play_both_tones == TRUE) {
|
|
lsm_util_tone_start_with_speaker_as_backup(VCM_RECORDERWARNING_TONE, VCM_ALERT_INFO_OFF,
|
|
lsm_get_ms_ui_call_handle(dcb->line, dcb->call_id, CC_NO_CALL_ID),
|
|
dcb->group_id,
|
|
((media != NULL) ? media->refid : CC_NO_MEDIA_REF_ID),
|
|
dcb->recorder_tone_direction);
|
|
}
|
|
|
|
lsm_util_tone_start_with_speaker_as_backup(tone, VCM_ALERT_INFO_OFF, lsm_get_ms_ui_call_handle(dcb->line, dcb->call_id, CC_NO_CALL_ID),
|
|
dcb->group_id,
|
|
((media != NULL) ? media->refid : CC_NO_MEDIA_REF_ID),
|
|
direction);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static cc_rcs_t
|
|
lsm_start_tone (lsm_lcb_t *lcb, cc_action_data_tone_t *data)
|
|
{
|
|
callid_t call_id = lcb->call_id;
|
|
fsmdef_media_t *media;
|
|
|
|
if (lcb->dcb == NULL) {
|
|
/* No dcb to work with */
|
|
return (CC_RC_ERROR);
|
|
}
|
|
media = gsmsdp_find_audio_media(lcb->dcb);
|
|
|
|
lsm_util_start_tone(data->tone, VCM_ALERT_INFO_OFF, lsm_get_ms_ui_call_handle(lcb->line, call_id, CC_NO_CALL_ID), lcb->dcb->group_id,
|
|
((media != NULL) ? media->refid : CC_NO_MEDIA_REF_ID),
|
|
VCM_PLAY_TONE_TO_EAR);
|
|
|
|
return (CC_RC_SUCCESS);
|
|
}
|
|
|
|
static cc_rcs_t
|
|
lsm_stop_tone (lsm_lcb_t *lcb, cc_action_data_tone_t *data)
|
|
{
|
|
/* NOTE: For now, ignore data input parameter that may contain the tone type.
|
|
* We'll check active_tone in the dcb for the call_id and see if there
|
|
* is a valid tone playing. If so, then and only then issue tone stop.
|
|
*/
|
|
static const char fname[] = "lsm_stop_tone";
|
|
callid_t call_id;
|
|
fsmdef_dcb_t *dcb;
|
|
|
|
if (lcb == NULL) {
|
|
LSM_DEBUG(DEB_F_PREFIX"NULL lcb passed\n", DEB_F_PREFIX_ARGS(LSM, fname));
|
|
return (CC_RC_ERROR);
|
|
}
|
|
call_id = lcb->call_id;
|
|
|
|
dcb = lcb->dcb;
|
|
if (dcb == NULL) {
|
|
LSM_DEBUG(DEB_F_PREFIX" NULL dcb passed for call_id = %d\n", DEB_F_PREFIX_ARGS(LSM, fname), call_id);
|
|
return (CC_RC_ERROR);
|
|
}
|
|
|
|
/* for tnp do call stop only if active_tone is other than VCM_NO_TONE */
|
|
if (dcb->active_tone != VCM_NO_TONE) {
|
|
fsmdef_media_t *media = gsmsdp_find_audio_media(lcb->dcb);
|
|
vcmToneStop(dcb->active_tone, dcb->group_id,
|
|
((media != NULL) ? media->refid : CC_NO_MEDIA_REF_ID),
|
|
lsm_get_ms_ui_call_handle(lcb->line, lcb->call_id, lcb->ui_id));
|
|
/*
|
|
* Both periodic tones, recording and monitoring, can be active at the
|
|
* same time. And because we only keep track of last tone, requested to
|
|
* play, through active_tone, so when the tone to be stopped is of
|
|
* periodic type, then it could be that both type of periodic tones
|
|
* could be playing and both should be stopped. If the second periodic
|
|
* tone is not playing then media server will ignore the stop request.
|
|
*/
|
|
if (dcb->active_tone == VCM_RECORDERWARNING_TONE ||
|
|
dcb->active_tone == VCM_MONITORWARNING_TONE)
|
|
{
|
|
vcmToneStop(dcb->active_tone == VCM_RECORDERWARNING_TONE ?
|
|
VCM_MONITORWARNING_TONE : VCM_RECORDERWARNING_TONE,
|
|
dcb->group_id,
|
|
((media != NULL) ? media->refid : CC_NO_MEDIA_REF_ID),
|
|
lsm_get_ms_ui_call_handle(lcb->line, lcb->call_id, lcb->ui_id));
|
|
|
|
/* in case need to play back the tone again when tx channel active */
|
|
switch (dcb->monrec_tone_action) {
|
|
case FSMDEF_MRTONE_PLAYED_MONITOR_TONE:
|
|
dcb->monrec_tone_action = FSMDEF_MRTONE_RESUME_MONITOR_TONE;
|
|
break;
|
|
|
|
case FSMDEF_MRTONE_PLAYED_RECORDER_TONE:
|
|
dcb->monrec_tone_action = FSMDEF_MRTONE_RESUME_RECORDER_TONE;
|
|
break;
|
|
|
|
case FSMDEF_MRTONE_PLAYED_BOTH_TONES:
|
|
dcb->monrec_tone_action = FSMDEF_MRTONE_RESUME_BOTH_TONES;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
LSM_DEBUG(DEB_L_C_F_PREFIX"%s: Setting monrec_tone_action: %d so resume to play correct tone.\n",
|
|
DEB_L_C_F_PREFIX_ARGS(LSM, dcb->line, dcb->call_id, fname), fname,
|
|
dcb->monrec_tone_action);
|
|
}
|
|
dcb->active_tone = VCM_NO_TONE;
|
|
} else {
|
|
LSM_DEBUG(DEB_L_C_F_PREFIX"Ignoring tone stop request\n",
|
|
DEB_L_C_F_PREFIX_ARGS(LSM, dcb->line, call_id, fname));
|
|
}
|
|
|
|
return (CC_RC_SUCCESS);
|
|
}
|
|
|
|
/*
|
|
* Function
|
|
*
|
|
* @param[in] tone - tone type
|
|
* @param[in] alert_info - alertinfo header
|
|
* @param[in] call_handle- call handle
|
|
* @param[in] direction - network, speaker, both
|
|
* @param[in] duration - length of time for tone to be played
|
|
*
|
|
* @return none
|
|
*/
|
|
void
|
|
lsm_tone_start_with_duration (vcm_tones_t tone, short alert_info,
|
|
cc_call_handle_t call_handle, groupid_t group_id,
|
|
streamid_t stream_id, uint16_t direction,
|
|
uint32_t duration)
|
|
{
|
|
|
|
static const char *fname = "lsm_tone_start_with_duration";
|
|
|
|
DEF_DEBUG(DEB_L_C_F_PREFIX"tone=%-2d: direction=%-2d duration=%-2d\n",
|
|
DEB_L_C_F_PREFIX_ARGS(LSM, GET_LINE_ID(call_handle), GET_CALL_ID(call_handle), fname),
|
|
tone, direction, duration);
|
|
|
|
/*
|
|
* play the tone. audio path is always set by MSUI module.
|
|
*/
|
|
vcmToneStart (tone, alert_info, call_handle, group_id, stream_id, direction);
|
|
|
|
lsm_update_active_tone (tone, GET_CALL_ID(call_handle));
|
|
|
|
lsm_start_tone_duration_timer (tone, duration, call_handle);
|
|
}
|
|
|
|
/*
|
|
* Function: lsm_get_used_instances_cnt
|
|
*
|
|
* @param line - line number
|
|
*
|
|
* Description: find the number of used instances for this particular line
|
|
*
|
|
* @return number of used instances
|
|
*
|
|
*/
|
|
int lsm_get_used_instances_cnt (line_t line)
|
|
{
|
|
static const char fname[] = "lsm_get_used_instances_cnt";
|
|
int used_instances = 0;
|
|
lsm_lcb_t *lcb;
|
|
|
|
if (!sip_config_check_line(line)) {
|
|
LSM_ERR_MSG(LSM_F_PREFIX"invalid line (%d)\n", fname, line);
|
|
|
|
return (-1);
|
|
}
|
|
|
|
/*
|
|
* Count home many instances are already in use for this particular line.
|
|
*/
|
|
FSM_FOR_ALL_CBS(lcb, lsm_lcbs, LSM_MAX_LCBS) {
|
|
if ((lcb->call_id != CC_NO_CALL_ID) &&
|
|
(lcb->line == line) &&
|
|
(lcb->state != LSM_S_IDLE)) {
|
|
used_instances++;
|
|
}
|
|
}
|
|
|
|
return (used_instances);
|
|
}
|
|
|
|
/*
|
|
* Function: lsm_get_all_used_instances_cnt
|
|
*
|
|
* Description: find the number of used instances for all lines
|
|
*
|
|
* @return number of used instances for all lines
|
|
*
|
|
*/
|
|
int lsm_get_all_used_instances_cnt ()
|
|
{
|
|
int used_instances = 0;
|
|
lsm_lcb_t *lcb;
|
|
|
|
/*
|
|
* Count home many instances are already in use for all lines.
|
|
*/
|
|
FSM_FOR_ALL_CBS(lcb, lsm_lcbs, LSM_MAX_LCBS) {
|
|
if ((lcb->call_id != CC_NO_CALL_ID) &&
|
|
(lcb->state != LSM_S_IDLE)) {
|
|
used_instances++;
|
|
}
|
|
}
|
|
|
|
return (used_instances);
|
|
}
|
|
|
|
/*
|
|
* Function: lsm_increment_call_chn_cnt
|
|
*
|
|
* @param line - line number
|
|
*
|
|
* Description:
|
|
*
|
|
* @return none
|
|
*
|
|
*/
|
|
void lsm_increment_call_chn_cnt (line_t line)
|
|
{
|
|
uint32_t maxnumcalls = 0;
|
|
uint32_t busy_trigger = 0;
|
|
static const char fname[] = "lsm_increment_call_chn_cnt";
|
|
|
|
if ( line <=0 || line > MAX_REG_LINES ) {
|
|
LSM_ERR_MSG(LSM_F_PREFIX"invalid line (%d)\n", fname, line);
|
|
return;
|
|
}
|
|
lsm_call_perline[line-1]++;
|
|
config_get_line_value(CFGID_LINE_MAXNUMCALLS, &maxnumcalls, sizeof(maxnumcalls), line);
|
|
config_get_line_value(CFGID_LINE_BUSY_TRIGGER, &busy_trigger, sizeof(busy_trigger), line);
|
|
if (lsm_call_perline[line-1] == maxnumcalls) {
|
|
lsm_mnc_reached[line-1] = TRUE;;
|
|
ui_mnc_reached(line, TRUE);
|
|
}
|
|
if (lsm_call_perline[line - 1] == busy_trigger) {
|
|
lsm_bt_reached[line - 1] = TRUE;;
|
|
}
|
|
|
|
LSM_DEBUG(DEB_F_PREFIX"number of calls on line[%d]=%d"
|
|
"MaxNumCalls[%d]_reached=%s BusyTrigger[%d]_reached=%s\n",
|
|
DEB_F_PREFIX_ARGS(LSM, fname),
|
|
line, lsm_call_perline[line-1],
|
|
maxnumcalls, (lsm_mnc_reached[line-1] == TRUE) ? "TRUE" : "FALSE",
|
|
busy_trigger,(lsm_bt_reached[line-1] == TRUE) ? "TRUE" : "FALSE");
|
|
}
|
|
|
|
/*
|
|
* Function: lsm_decrement_call_chn_cnt
|
|
*
|
|
* @param line - line number
|
|
*
|
|
* Description:
|
|
*
|
|
* @return none
|
|
*
|
|
*/
|
|
void lsm_decrement_call_chn_cnt (line_t line)
|
|
{
|
|
uint32_t maxnumcalls = 0;
|
|
uint32_t busy_trigger = 0;
|
|
static const char fname[] = "lsm_decrement_call_chn_cnt";
|
|
|
|
if ( line <=0 || line > MAX_REG_LINES ) {
|
|
LSM_ERR_MSG(LSM_F_PREFIX"invalid line (%d)\n", fname, line);
|
|
return;
|
|
}
|
|
|
|
lsm_call_perline[line-1]--;
|
|
config_get_line_value(CFGID_LINE_MAXNUMCALLS, &maxnumcalls, sizeof(maxnumcalls), line);
|
|
config_get_line_value(CFGID_LINE_BUSY_TRIGGER, &busy_trigger, sizeof(busy_trigger), line);
|
|
if (lsm_call_perline[line-1] <= (maxnumcalls-1)) {
|
|
lsm_mnc_reached[line-1] = FALSE;
|
|
ui_mnc_reached(line, FALSE);
|
|
}
|
|
if (lsm_call_perline[line - 1] == (busy_trigger -1)) {
|
|
lsm_bt_reached[line - 1] = FALSE;;
|
|
}
|
|
LSM_DEBUG(DEB_F_PREFIX"number of calls on line[%d]=%d"
|
|
"MaxNumCalls[%d]_reached=%s BusyTrigger[%d]_reached=%s\n",
|
|
DEB_F_PREFIX_ARGS(LSM, fname),
|
|
line, lsm_call_perline[line-1],
|
|
maxnumcalls, (lsm_mnc_reached[line-1] == TRUE) ? "TRUE" : "FALSE",
|
|
busy_trigger,(lsm_bt_reached[line-1] == TRUE) ? "TRUE" : "FALSE");
|
|
}
|
|
|
|
#define NO_ROLLOVER 0
|
|
#define ROLLOVER_ACROSS_SAME_DN 1
|
|
#define ROLLOVER_NEXT_AVAILABLE_LINE 2
|
|
|
|
/*
|
|
* Function: lsm_find_next_available_line
|
|
*
|
|
* @param line - line number
|
|
* @param same_dn - whether lines with same DN to be looked at.
|
|
* @param incoming - whether we are looking for an available line for an anticipated incoming call.
|
|
*
|
|
* Description:
|
|
*
|
|
*
|
|
* @return found line number
|
|
*
|
|
*/
|
|
line_t lsm_find_next_available_line (line_t line, boolean same_dn, boolean incoming)
|
|
{
|
|
char current_line_dn_name[MAX_LINE_NAME_SIZE];
|
|
char dn_name[MAX_LINE_NAME_SIZE];
|
|
uint32_t line_feature;
|
|
line_t i, j;
|
|
boolean *limit_reached;
|
|
|
|
/* determine whether to use MNC or BT limit */
|
|
if (incoming == TRUE) {
|
|
limit_reached = lsm_bt_reached;
|
|
}
|
|
else {
|
|
limit_reached = lsm_mnc_reached;
|
|
}
|
|
|
|
config_get_line_string(CFGID_LINE_NAME, current_line_dn_name, line, sizeof(current_line_dn_name));
|
|
/* This line has exhausted its limit, start rollover */
|
|
/* First, search the lines on top of the current one */
|
|
for (i=line+1; i <= MAX_REG_LINES; i++) {
|
|
config_get_line_value(CFGID_LINE_FEATURE, &line_feature, sizeof(line_feature), i);
|
|
|
|
/* if it is not a DN, skip it */
|
|
if (line_feature != cfgLineFeatureDN) {
|
|
continue;
|
|
}
|
|
/* Does this line have room to take the call */
|
|
if (limit_reached[i-1] == FALSE) {
|
|
if (same_dn == TRUE) {
|
|
config_get_line_string(CFGID_LINE_NAME, dn_name, i, sizeof(dn_name));
|
|
/* Does this line have the same DN */
|
|
if (cpr_strcasecmp(dn_name, current_line_dn_name) == 0) {
|
|
return (i);
|
|
}
|
|
} else {
|
|
return (i);
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
* We went up to the top and couldn't find an available line,
|
|
* start from line 1 and search up to the current line, thus
|
|
* we are treating the available lines as a circular pool
|
|
*/
|
|
|
|
for (j=1; j <= line; j++) {
|
|
config_get_line_value(CFGID_LINE_FEATURE, &line_feature, sizeof(line_feature), j);
|
|
|
|
/* if it is not a DN, skip it */
|
|
if (line_feature != cfgLineFeatureDN) {
|
|
continue;
|
|
}
|
|
/* Does this line have room to take the call */
|
|
if (limit_reached[j-1] == FALSE) {
|
|
if (same_dn == TRUE) {
|
|
config_get_line_string(CFGID_LINE_NAME, dn_name, j, sizeof(dn_name));
|
|
/* Does this line have the same DN */
|
|
if (cpr_strcasecmp(dn_name, current_line_dn_name) == 0) {
|
|
return (j);
|
|
}
|
|
} else {
|
|
return (j);
|
|
}
|
|
}
|
|
}
|
|
|
|
return (NO_LINES_AVAILABLE);
|
|
}
|
|
/*
|
|
* Function: lsm_get_newcall_line
|
|
*
|
|
* @param line - line number
|
|
*
|
|
* Description: find out a line that has room to make a
|
|
* new call based on the rollover settings
|
|
*
|
|
* @return found line number
|
|
*
|
|
*/
|
|
line_t lsm_get_newcall_line (line_t line)
|
|
{
|
|
static const char fname[] = "lsm_get_newcall_line";
|
|
int rollover;
|
|
line_t found_line;
|
|
|
|
if (!lsm_mnc_reached[line-1]) {
|
|
/* Still room for extra calls on this line */
|
|
return (line);
|
|
}
|
|
|
|
config_get_value(CFGID_ROLLOVER, &rollover, sizeof(int));
|
|
|
|
if (rollover == NO_ROLLOVER) {
|
|
DEF_DEBUG(DEB_F_PREFIX"NO Rollover, no lines\n", DEB_F_PREFIX_ARGS(LSM, fname));
|
|
return (NO_LINES_AVAILABLE);
|
|
}
|
|
|
|
|
|
if (rollover == ROLLOVER_ACROSS_SAME_DN) {
|
|
/* Look for a line with the same DN */
|
|
return (lsm_find_next_available_line(line, TRUE, FALSE));
|
|
}
|
|
|
|
if (rollover == ROLLOVER_NEXT_AVAILABLE_LINE) {
|
|
/* Look for a line with the same DN first */
|
|
found_line = lsm_find_next_available_line(line, TRUE, FALSE);
|
|
|
|
if (found_line == NO_LINES_AVAILABLE) {
|
|
/*
|
|
* If nothing found, just look for any line, does
|
|
* not necessarily have to have the same DN
|
|
*/
|
|
return (lsm_find_next_available_line(line, FALSE, FALSE));
|
|
} else {
|
|
return (found_line);
|
|
}
|
|
}
|
|
|
|
DEF_DEBUG(DEB_F_PREFIX"No lines available\n", DEB_F_PREFIX_ARGS(LSM, fname));
|
|
|
|
return (NO_LINES_AVAILABLE);
|
|
}
|
|
|
|
/*
|
|
* Function: lsm_get_available_line
|
|
*
|
|
* @param incoming - whether we are looking for an available line for an anticipated incoming call.
|
|
*
|
|
* Description: find out a line that has room to make a
|
|
* new call starting from the first line.
|
|
*
|
|
* @return found line number
|
|
*
|
|
*/
|
|
line_t lsm_get_available_line (boolean incoming)
|
|
{
|
|
line_t line = 1; /* start with line 1 */
|
|
|
|
if (incoming == FALSE) {
|
|
if (!lsm_mnc_reached[line-1]) {
|
|
/* Still room for extra calls on this line */
|
|
return (line);
|
|
}
|
|
}
|
|
else {
|
|
if (!lsm_bt_reached[line-1]) {
|
|
/* Still room for extra calls on this line */
|
|
return (line);
|
|
}
|
|
}
|
|
return (lsm_find_next_available_line(line, FALSE, incoming));
|
|
}
|
|
|
|
/*
|
|
* Function: lsm_is_line_available_for_outgoing_call
|
|
*
|
|
* @param line
|
|
* @param incoming - whether we are looking for an available line for an anticipated incoming call.
|
|
*
|
|
* Description: find out if the line has room to make a new call
|
|
*
|
|
* @return TRUE/FALSE
|
|
*
|
|
*/
|
|
boolean lsm_is_line_available (line_t line, boolean incoming)
|
|
{
|
|
if (incoming == FALSE) {
|
|
if (!lsm_mnc_reached[line-1]) {
|
|
/* Still room for extra calls on this line */
|
|
return (TRUE);
|
|
}
|
|
}
|
|
else {
|
|
if (!lsm_bt_reached[line-1]) {
|
|
/* Still room for incoming calls on this line */
|
|
return (TRUE);
|
|
}
|
|
}
|
|
return (FALSE);
|
|
}
|
|
|
|
/*
|
|
* lsm_get_instances_available_cnt
|
|
*
|
|
* return the number of available instances for this particular line
|
|
*
|
|
* NOTE: The function can return negative values, which the user should read
|
|
* as no available lines.
|
|
*/
|
|
int
|
|
lsm_get_instances_available_cnt (line_t line, boolean expline)
|
|
{
|
|
static const char fname[] = "lsm_get_instances_available_cnt";
|
|
int max_instances;
|
|
int used_instances = 0;
|
|
int free_instances;
|
|
|
|
if (!sip_config_check_line(line)) {
|
|
LSM_ERR_MSG(LSM_F_PREFIX"invalid line (%d)\n", fname, line);
|
|
|
|
return (-1);
|
|
}
|
|
|
|
used_instances = lsm_get_used_instances_cnt(line);
|
|
|
|
max_instances = (expline) ? (LSM_MAX_EXP_INSTANCES) : (LSM_MAX_INSTANCES);
|
|
|
|
free_instances = max_instances - used_instances;
|
|
|
|
if(free_instances > 0){
|
|
int all_used_instances = lsm_get_all_used_instances_cnt();
|
|
int all_max_instances = (expline) ? (LSM_MAX_CALLS) : (LSM_MAX_CALLS - 1);
|
|
int all_free_instances = all_max_instances - all_used_instances;
|
|
free_instances = ((free_instances < all_free_instances) ? free_instances : all_free_instances);
|
|
LSM_DEBUG("lsm_get_instances_available_cnt: line=%d, expline=%d, free=%d, all_used=%d, all_max=%d, all_free=%d\n",
|
|
line, expline, free_instances, all_used_instances, all_max_instances, all_free_instances);
|
|
|
|
}
|
|
LSM_DEBUG("lsm_get_instances_available_cnt: line=%d, expline=%d, free_instances=%d\n",
|
|
line, expline, free_instances);
|
|
return (free_instances);
|
|
}
|
|
|
|
|
|
static void
|
|
lsm_init_lcb (lsm_lcb_t *lcb)
|
|
{
|
|
lcb->call_id = CC_NO_CALL_ID;
|
|
lcb->line = LSM_NO_LINE;
|
|
lcb->previous_call_event = evMaxEvent;
|
|
lcb->state = LSM_S_IDLE;
|
|
lcb->mru = 0;
|
|
lcb->enable_ringback = TRUE;
|
|
lcb->flags = 0;
|
|
lcb->dcb = NULL;
|
|
lcb->gcid = NULL;
|
|
lcb->vid_flags = 0; //set to not visible
|
|
lcb->ui_id = CC_NO_CALL_ID;
|
|
}
|
|
|
|
/**
|
|
* Return the port back to Media service component
|
|
* @param [in] lcb - lsm control block
|
|
*
|
|
*/
|
|
static void lsm_release_port (lsm_lcb_t *lcb)
|
|
{
|
|
static const char fname[] = "lsm_release_port";
|
|
fsmdef_media_t *start_media, *end_media;
|
|
fsmdef_dcb_t *dcb;
|
|
fsmdef_media_t *media;
|
|
int sdpmode = 0;
|
|
|
|
dcb = lcb->dcb;
|
|
if (dcb == NULL) {
|
|
LSM_ERR_MSG(get_debug_string(DEBUG_INPUT_NULL), fname);
|
|
return;
|
|
}
|
|
|
|
config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
|
|
|
|
LSM_DEBUG(DEB_L_C_F_PREFIX,
|
|
DEB_L_C_F_PREFIX_ARGS(LSM, dcb->line, dcb->call_id, fname));
|
|
|
|
start_media = GSMSDP_FIRST_MEDIA_ENTRY(dcb);
|
|
end_media = NULL; /* NULL means till the end of the list */
|
|
|
|
GSMSDP_FOR_MEDIA_LIST(media, start_media, end_media, dcb) {
|
|
if (!sdpmode) {
|
|
vcmRxReleasePort(media->cap_index, dcb->group_id, media->refid,
|
|
lsm_get_ms_ui_call_handle(lcb->line, lcb->call_id, lcb->ui_id), media->src_port);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
lsm_free_lcb (lsm_lcb_t *lcb)
|
|
{
|
|
lsm_release_port(lcb);
|
|
cpr_free(lcb->gcid);
|
|
lsm_init_lcb(lcb);
|
|
}
|
|
|
|
|
|
/**
|
|
* lsm_get_free_lcb
|
|
* return a free instance of the given line
|
|
*
|
|
* @param[in]call_id - gsm call id to allocate the lcb instance with.
|
|
* @param[in]line - line that the lcb instnce will be associated with
|
|
* @param[in]dcb - fsmdef_dcb_t structure that the lcb instance will
|
|
* be associated with.
|
|
* @return pointer to lsm_lcb_t if there is an available lcb otherwise
|
|
* returns NULL.
|
|
* @pre (dcb not_eq NULL)
|
|
*/
|
|
static lsm_lcb_t *
|
|
lsm_get_free_lcb (callid_t call_id, line_t line, fsmdef_dcb_t *dcb)
|
|
{
|
|
static const char fname[] = "lsm_get_free_lcb";
|
|
static int mru = 0;
|
|
lsm_lcb_t *lcb;
|
|
lsm_lcb_t *lcb_found = NULL;
|
|
|
|
if (!sip_config_check_line(line)) {
|
|
LSM_ERR_MSG(LSM_F_PREFIX"invalid line (%d)\n", fname, line);
|
|
|
|
return (NULL);
|
|
}
|
|
|
|
|
|
/*
|
|
* Set mru (most recently used).
|
|
* Used to determine which call came in first.
|
|
*/
|
|
if (++mru < 0) {
|
|
mru = 1;
|
|
}
|
|
|
|
/*
|
|
* Find a free lcb.
|
|
*/
|
|
FSM_FOR_ALL_CBS(lcb, lsm_lcbs, LSM_MAX_LCBS) {
|
|
if ((lcb->call_id == CC_NO_CALL_ID) && (lcb->state == LSM_S_IDLE)) {
|
|
lcb_found = lcb;
|
|
lcb->call_id = call_id;
|
|
lcb->line = line;
|
|
lcb->state = LSM_S_PENDING;
|
|
lcb->mru = mru;
|
|
lcb->dcb = dcb;
|
|
// start unmuted if txPref is true
|
|
lcb->vid_mute = cc_media_getVideoAutoTxPref() ? FALSE : TRUE;
|
|
|
|
lcb->ui_id = call_id; /* default UI ID is the same as call_id */
|
|
break;
|
|
}
|
|
}
|
|
|
|
return (lcb_found);
|
|
}
|
|
|
|
|
|
lsm_lcb_t *
|
|
lsm_get_lcb_by_call_id (callid_t call_id)
|
|
{
|
|
lsm_lcb_t *lcb;
|
|
lsm_lcb_t *lcb_found = NULL;
|
|
LSM_DEBUG(DEB_L_C_F_PREFIX"call_id=%d.\n",
|
|
DEB_L_C_F_PREFIX_ARGS(LSM, 0, call_id, "lsm_get_lcb_by_call_id"), call_id);
|
|
|
|
FSM_FOR_ALL_CBS(lcb, lsm_lcbs, LSM_MAX_LCBS) {
|
|
if (lcb->call_id == call_id) {
|
|
lcb_found = lcb;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return (lcb_found);
|
|
}
|
|
|
|
/**
|
|
* This function returns the LSM state for the given call_id.
|
|
*
|
|
* @param[in] call_id - call id
|
|
*
|
|
* @return lsm_states_t of the given call_id. If the
|
|
* there is no call associated with the given
|
|
* call ID it returns the LSM_S_NONE.
|
|
*/
|
|
lsm_states_t
|
|
lsm_get_state (callid_t call_id)
|
|
{
|
|
lsm_lcb_t *lcb;
|
|
|
|
lcb = lsm_get_lcb_by_call_id(call_id);
|
|
|
|
if (lcb == NULL) {
|
|
/* there is no call for this call id */
|
|
return (LSM_S_NONE);
|
|
}
|
|
return (lcb->state);
|
|
}
|
|
|
|
static void
|
|
lsm_change_state (lsm_lcb_t *lcb, int line_num, lsm_states_t new_state)
|
|
{
|
|
static const char fname1[] = "lsm_change_state";
|
|
LSM_DEBUG(DEB_L_C_F_PREFIX"%d: %s -> %s\n",
|
|
DEB_L_C_F_PREFIX_ARGS(LSM, lcb->line, lcb->call_id, fname1),
|
|
line_num, lsm_state_name(lcb->state), lsm_state_name(new_state));
|
|
|
|
lcb->state = new_state;
|
|
}
|
|
|
|
boolean
|
|
lsm_is_phone_idle (void)
|
|
{
|
|
static const char fname[] = "lsm_is_phone_idle";
|
|
boolean idle = TRUE;
|
|
lsm_lcb_t *lcb;
|
|
|
|
if(!lsm_lcbs){
|
|
LSM_DEBUG(DEB_F_PREFIX"No lsm line cb\n", DEB_F_PREFIX_ARGS(LSM, fname));
|
|
return (idle);
|
|
}
|
|
|
|
FSM_FOR_ALL_CBS(lcb, lsm_lcbs, LSM_MAX_LCBS) {
|
|
if ((lcb->call_id != CC_NO_CALL_ID) && (lcb->state != LSM_S_IDLE)) {
|
|
idle = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return (idle);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Function: lsm_is_phone_inactive
|
|
*
|
|
* Parameters: None.
|
|
*
|
|
* Description: Determines if the phone is inactive. Inactive means the phone
|
|
* as active at some point, but now it is not - there are still
|
|
* calls on the phone but they are probably in a holding state.
|
|
* This is different from idle, which means that there are not
|
|
* any calls on the phone.
|
|
*
|
|
* Returns:
|
|
* inactive: FALSE: phone is not inactive
|
|
* TRUE: phone is inactive
|
|
*/
|
|
boolean
|
|
lsm_is_phone_inactive (void)
|
|
{
|
|
boolean inactive = TRUE;
|
|
lsm_lcb_t *lcb;
|
|
|
|
FSM_FOR_ALL_CBS(lcb, lsm_lcbs, LSM_MAX_LCBS) {
|
|
if ((lcb->call_id != CC_NO_CALL_ID) &&
|
|
((lcb->state == LSM_S_OFFHOOK) ||
|
|
(lcb->state == LSM_S_PENDING) ||
|
|
(lcb->state == LSM_S_PROCEED) ||
|
|
(lcb->state == LSM_S_RINGOUT) ||
|
|
(lcb->state == LSM_S_RINGIN) ||
|
|
(lcb->state == LSM_S_CONNECTED))) {
|
|
inactive = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return (inactive);
|
|
}
|
|
|
|
/*
|
|
* Function: lsm_callwaiting
|
|
*
|
|
* Parameters: None.
|
|
*
|
|
* Description: Determines if the phone is in a state that this
|
|
* call will be handled by the callwaiting code. TNP
|
|
* phones allow call-waiting when dialing digits while
|
|
* the legacy phones do not.
|
|
*
|
|
* Returns:
|
|
* inactive: FALSE: Treat as a normal call on an idle phone
|
|
* TRUE: Display incoming call and play call waiting tone
|
|
*/
|
|
boolean
|
|
lsm_callwaiting (void)
|
|
{
|
|
lsm_lcb_t *lcb;
|
|
|
|
FSM_FOR_ALL_CBS(lcb, lsm_lcbs, LSM_MAX_LCBS) {
|
|
if (lcb->call_id != CC_NO_CALL_ID) {
|
|
switch (lcb->state) {
|
|
case LSM_S_OFFHOOK:
|
|
case LSM_S_PROCEED:
|
|
case LSM_S_RINGOUT:
|
|
case LSM_S_CONNECTED:
|
|
return (TRUE);
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return (FALSE);
|
|
}
|
|
|
|
static callid_t
|
|
lsm_find_state (lsm_states_t state)
|
|
{
|
|
callid_t found_callid = CC_NO_CALL_ID;
|
|
lsm_lcb_t *lcb;
|
|
|
|
FSM_FOR_ALL_CBS(lcb, lsm_lcbs, LSM_MAX_LCBS) {
|
|
if ((lcb->call_id != CC_NO_CALL_ID) && (lcb->state == state)) {
|
|
found_callid = lcb->call_id;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return (found_callid);
|
|
}
|
|
|
|
/**
|
|
* lsm_get_facility_by_called_number
|
|
* return facility by the given called_number.
|
|
*
|
|
* @param[in]call_id - gsm's call_id for a new call.
|
|
* @param[in]called_number - pointer to the called number.
|
|
* @paran[in/out]free_line - pointer to the line_t to store
|
|
* the result line number corresponding
|
|
* to the called number given.
|
|
* @param[in]expline - boolean indicating extra instance
|
|
* is needed.
|
|
* @param[in]dcb - pointer to void but it must be
|
|
* a pointer to fsmdef_dcb_t to bind with
|
|
* the new LCB. The reason to use a void
|
|
* pointer is the declaration of the function
|
|
* is in lsm.h. The lsm.h file is used by
|
|
* components outside gsm environment. Those
|
|
* modules would need to include the fsm.h
|
|
* which is not desirable. Using void pointer
|
|
* avoids this problem.
|
|
*
|
|
* @return cc_cause_t
|
|
*
|
|
* @pre (called_number not_eq NULL)
|
|
* @pre (free_line not_eq NULL)
|
|
* @pre (dcb not_eq NULL)
|
|
*/
|
|
cc_causes_t
|
|
lsm_get_facility_by_called_number (callid_t call_id,
|
|
const char *called_number,
|
|
line_t *free_line, boolean expline,
|
|
void *dcb)
|
|
{
|
|
static const char fname[] = "lsm_get_facility_by_called_number";
|
|
line_t line;
|
|
lsm_lcb_t *lcb;
|
|
int free_instances;
|
|
line_t madn_line;
|
|
|
|
lsm_debug_entry(call_id, 0, fname);
|
|
LSM_DEBUG(DEB_F_PREFIX"called_number= %s\n", DEB_F_PREFIX_ARGS(LSM, fname), called_number);
|
|
|
|
//line = sip_config_get_line_by_called_number(1, called_number);
|
|
line = 1;
|
|
if (line == 0) {
|
|
return (CC_CAUSE_UNASSIGNED_NUM);
|
|
}
|
|
*free_line = line;
|
|
|
|
/* check for a MADN line */
|
|
madn_line = sip_config_get_line_by_called_number((line_t)(line + 1),
|
|
called_number);
|
|
|
|
/*
|
|
* Check to see if we even have any available instances.
|
|
*/
|
|
free_instances = lsm_get_instances_available_cnt(line, expline);
|
|
|
|
/* if it is a MADN line and it already has a call, then go to next
|
|
* line with this MADN number.
|
|
*/
|
|
if ((madn_line) && (free_instances < 2)) {
|
|
while (madn_line) {
|
|
free_instances = lsm_get_instances_available_cnt(madn_line, expline);
|
|
if (free_instances == 2) {
|
|
*free_line = line = madn_line;
|
|
break;
|
|
}
|
|
madn_line = sip_config_get_line_by_called_number((line_t)(madn_line + 1),
|
|
called_number);
|
|
}
|
|
if (madn_line == 0) {
|
|
return (CC_CAUSE_BUSY);
|
|
}
|
|
}
|
|
|
|
if (free_instances <= 0) {
|
|
return (CC_CAUSE_BUSY);
|
|
}
|
|
|
|
lcb = lsm_get_free_lcb(call_id, line, (fsmdef_dcb_t *)dcb);
|
|
if (lcb == NULL) {
|
|
return (CC_CAUSE_NO_RESOURCE);
|
|
}
|
|
|
|
return (CC_CAUSE_OK);
|
|
}
|
|
|
|
/**
|
|
* lsm_allocate_call_bandwidth
|
|
*
|
|
* @param[in] none.
|
|
*
|
|
* The wlan interface puts into unique situation where call control
|
|
* has to allocate the worst case bandwith before creating a
|
|
* inbound or outbound call. The function call will interface through
|
|
* media API into wlan to get the call bandwidth. The function
|
|
* return is asynchronous and will block till the return media
|
|
* callback signals to continue the execution.
|
|
*
|
|
* @return true if the bandwidth can be allocated else false.
|
|
* @pre none
|
|
*/
|
|
|
|
cc_causes_t lsm_allocate_call_bandwidth (callid_t call_id, int sessions)
|
|
{
|
|
//get line for vcm
|
|
line_t line = lsm_get_line_by_call_id(call_id);
|
|
//cc_feature(CC_SRC_GSM, call_id, 0, CC_FEATURE_CAC_RESP_PASS, NULL);
|
|
|
|
/* Activate the wlan before allocating bandwidth */
|
|
vcmActivateWlan(TRUE);
|
|
|
|
if (vcmAllocateBandwidth(lsm_get_ms_ui_call_handle(line, call_id, CC_NO_CALL_ID), sessions)) {
|
|
return(CC_CAUSE_OK);
|
|
}
|
|
|
|
return(CC_CAUSE_CONGESTION);
|
|
}
|
|
|
|
/**
|
|
* lsm_get_facility_by_line
|
|
* return facility by the given line
|
|
*
|
|
* @param[in]call_id - gsm's call_id for a new call.
|
|
* @param[in]line - line
|
|
* @param[in]expline - boolean indicating extra instance
|
|
* is needed.
|
|
* @param[in]dcb - pointer to void but it must be
|
|
* a pointer to fsmdef_dcb_t to bind with
|
|
* the new LCB. The reason to use a void
|
|
* pointer is the declaration of the function
|
|
* is in lsm.h. The lsm.h file is used by
|
|
* components outside gsm environment. Those
|
|
* modules would need to include the fsm.h
|
|
* which is not desirable. Using void pointer
|
|
* avoids this problem.
|
|
*
|
|
* @return cc_cause_t
|
|
* @pre (dcb not_eq NULL)
|
|
*/
|
|
cc_causes_t
|
|
lsm_get_facility_by_line (callid_t call_id, line_t line, boolean expline,
|
|
void *dcb)
|
|
{
|
|
static const char fname[] = "lsm_get_facility_by_line";
|
|
lsm_lcb_t *lcb;
|
|
int free_instances;
|
|
|
|
LSM_DEBUG(get_debug_string(LSM_DBG_INT1), call_id, line, fname,
|
|
"exp", expline);
|
|
|
|
/*
|
|
* Check to see if we even have any available instances
|
|
*/
|
|
free_instances = lsm_get_instances_available_cnt(line, expline);
|
|
if (free_instances <= 0) {
|
|
return (CC_CAUSE_BUSY);
|
|
}
|
|
|
|
lcb = lsm_get_free_lcb(call_id, line, (fsmdef_dcb_t *)dcb);
|
|
if (lcb == NULL) {
|
|
return (CC_CAUSE_NO_RESOURCE);
|
|
}
|
|
|
|
return (CC_CAUSE_OK);
|
|
}
|
|
|
|
|
|
#ifdef _WIN32
|
|
/* This function enumerates over the lcbs
|
|
* and attempts to terminate the call
|
|
* This is used by softphone when
|
|
* it exits and the softphone is
|
|
* still engaged in a call
|
|
*/
|
|
void
|
|
terminate_active_calls (void)
|
|
{
|
|
callid_t call_id = CC_NO_CALL_ID;
|
|
lsm_lcb_t *lcb;
|
|
line_t line;
|
|
|
|
FSM_FOR_ALL_CBS(lcb, lsm_lcbs, LSM_MAX_LCBS) {
|
|
if (lcb->call_id != CC_NO_CALL_ID) {
|
|
line = lsm_get_line_by_call_id(lcb->call_id);
|
|
/* Currently cc_feature does a better job of releasing the call
|
|
* compared to cc_onhook.
|
|
*/
|
|
//cc_onhook(CC_SRC_UI, call_id, line);
|
|
cc_feature(CC_SRC_UI, call_id, line, CC_FEATURE_END_CALL, NULL);
|
|
call_id = lcb->call_id;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
line_t
|
|
lsm_get_line_by_call_id (callid_t call_id)
|
|
{
|
|
fsmdef_dcb_t *dcb;
|
|
line_t line;
|
|
|
|
dcb = fsmdef_get_dcb_by_call_id(call_id);
|
|
|
|
if (dcb != NULL) {
|
|
line = dcb->line;
|
|
} else {
|
|
line = LSM_DEFAULT_LINE;
|
|
}
|
|
|
|
return (line);
|
|
}
|
|
|
|
/*
|
|
* This is a callback function for those tones that are
|
|
* played in two parts (stutter and msgwaiting) or played
|
|
* every x seconds, but are not steady tones (call waiting).
|
|
*
|
|
* @param[in] data The gsm ID (callid_t) of the call of the
|
|
* tones timer has timeout.
|
|
*
|
|
* @return N/A
|
|
*/
|
|
void
|
|
lsm_tmr_tones_callback (void *data)
|
|
{
|
|
static const char fname[] = "lsm_tmr_tones_callback";
|
|
callid_t call_id;
|
|
fsmdef_dcb_t *dcb = NULL;
|
|
fsmdef_media_t *media;
|
|
|
|
LSM_DEBUG(DEB_F_PREFIX"invoked", DEB_F_PREFIX_ARGS(LSM, fname));
|
|
|
|
call_id = (callid_t)(long)data;
|
|
if (call_id == CC_NO_CALL_ID) {
|
|
/* Invalid call id */
|
|
LSM_DEBUG(DEB_F_PREFIX"invalid call id\n", DEB_F_PREFIX_ARGS(LSM, fname));
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* A call-waiting tone should be played if these conditions are met:
|
|
* 1. A line must be ringing for an incoming call
|
|
* 2. The phone must be in a state that we handle callwaiting
|
|
*/
|
|
/* Retrieve dcb from call id */
|
|
dcb = fsmdef_get_dcb_by_call_id(call_id);
|
|
if (dcb == NULL) {
|
|
LSM_DEBUG(DEB_F_PREFIX"no dcb found for call_id %d\n", DEB_F_PREFIX_ARGS(LSM, fname), call_id);
|
|
return;
|
|
}
|
|
|
|
media = gsmsdp_find_audio_media(dcb);
|
|
|
|
if ((lsm_find_state(LSM_S_RINGIN) > CC_NO_CALL_ID) && (lsm_callwaiting())) {
|
|
|
|
/* Determine what tone/ringing pattern to play */
|
|
switch (dcb->alert_info) {
|
|
|
|
case ALERTING_RING:
|
|
|
|
/* Need to map the alerting patterns to the call waiting patterns */
|
|
switch (dcb->alerting_ring) {
|
|
case VCM_BELLCORE_DR2:
|
|
lsm_util_start_tone(VCM_CALL_WAITING_2_TONE, NO, lsm_get_ms_ui_call_handle(dcb->line, dcb->call_id, CC_NO_CALL_ID), dcb->group_id,
|
|
((media != NULL) ? media->refid : CC_NO_MEDIA_REF_ID),
|
|
dcb->tone_direction);
|
|
break;
|
|
case VCM_BELLCORE_DR3:
|
|
lsm_util_start_tone(VCM_CALL_WAITING_3_TONE, NO, lsm_get_ms_ui_call_handle(dcb->line, dcb->call_id, CC_NO_CALL_ID), dcb->group_id,
|
|
((media != NULL) ? media->refid : CC_NO_MEDIA_REF_ID),
|
|
dcb->tone_direction);
|
|
break;
|
|
case VCM_BELLCORE_DR4:
|
|
lsm_util_start_tone(VCM_CALL_WAITING_4_TONE, NO, lsm_get_ms_ui_call_handle(dcb->line, dcb->call_id, CC_NO_CALL_ID), dcb->group_id,
|
|
((media != NULL) ? media->refid : CC_NO_MEDIA_REF_ID),
|
|
dcb->tone_direction);
|
|
break;
|
|
default:
|
|
lsm_util_start_tone(VCM_CALL_WAITING_TONE, NO, lsm_get_ms_ui_call_handle(dcb->line, dcb->call_id, CC_NO_CALL_ID), dcb->group_id,
|
|
((media != NULL) ? media->refid : CC_NO_MEDIA_REF_ID),
|
|
dcb->tone_direction);
|
|
}
|
|
break;
|
|
|
|
case ALERTING_TONE:
|
|
|
|
/* Busy verify is just 2 secs of dialtone followed by
|
|
* a call waiting tone every 10 secs. The rest of the
|
|
* tones are just played once.
|
|
*/
|
|
switch (dcb->alerting_tone) {
|
|
case VCM_BUSY_VERIFY_TONE:
|
|
lsm_util_start_tone(VCM_CALL_WAITING_TONE, NO, lsm_get_ms_ui_call_handle(dcb->line, dcb->call_id, CC_NO_CALL_ID), dcb->group_id,
|
|
((media != NULL) ? media->refid : CC_NO_MEDIA_REF_ID),
|
|
dcb->tone_direction);
|
|
if (cprStartTimer(lsm_tmr_tones, BUSY_VERIFICATION_DELAY,
|
|
(void *)(long)dcb->call_id) == CPR_FAILURE) {
|
|
LSM_DEBUG(get_debug_string(DEBUG_GENERAL_SYSTEMCALL_FAILED),
|
|
fname, "cprStartTimer", cpr_errno);
|
|
}
|
|
break;
|
|
|
|
case VCM_CALL_WAITING_TONE:
|
|
case VCM_CALL_WAITING_2_TONE:
|
|
case VCM_CALL_WAITING_3_TONE:
|
|
case VCM_CALL_WAITING_4_TONE:
|
|
lsm_util_start_tone(dcb->alerting_tone, NO, lsm_get_ms_ui_call_handle(dcb->line, dcb->call_id, CC_NO_CALL_ID), dcb->group_id,
|
|
((media != NULL) ? media->refid : CC_NO_MEDIA_REF_ID),
|
|
dcb->tone_direction);
|
|
break;
|
|
|
|
case VCM_MSG_WAITING_TONE:
|
|
case VCM_STUTTER_TONE:
|
|
lsm_util_start_tone(VCM_INSIDE_DIAL_TONE, NO, lsm_get_ms_ui_call_handle(dcb->line, dcb->call_id, CC_NO_CALL_ID), dcb->group_id,
|
|
((media != NULL) ? media->refid : CC_NO_MEDIA_REF_ID),
|
|
dcb->tone_direction);
|
|
lsm_tmr_tones_ticks = 0;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
lsm_util_start_tone(VCM_CALL_WAITING_TONE, NO, lsm_get_ms_ui_call_handle(dcb->line, dcb->call_id, CC_NO_CALL_ID), dcb->group_id,
|
|
((media != NULL) ? media->refid : CC_NO_MEDIA_REF_ID),
|
|
dcb->tone_direction);
|
|
|
|
break;
|
|
}
|
|
|
|
} else if (dcb->dialplan_tone) {
|
|
dcb->dialplan_tone = FALSE;
|
|
switch (dcb->alert_info) {
|
|
|
|
case ALERTING_TONE:
|
|
/*
|
|
* Currently the only supported multi-part tones
|
|
* played via the dialplan are Message Waiting and
|
|
* Stutter dialtones.
|
|
*/
|
|
switch (dcb->alerting_tone) {
|
|
case VCM_MSG_WAITING_TONE:
|
|
case VCM_STUTTER_TONE:
|
|
lsm_util_start_tone(VCM_INSIDE_DIAL_TONE, NO, lsm_get_ms_ui_call_handle(dcb->line, dcb->call_id, CC_NO_CALL_ID), dcb->group_id,
|
|
((media != NULL) ? media->refid : CC_NO_MEDIA_REF_ID),
|
|
dcb->tone_direction);
|
|
break;
|
|
|
|
case VCM_HOLD_TONE:
|
|
lsm_util_start_tone(dcb->alerting_tone, NO, lsm_get_ms_ui_call_handle(dcb->line, dcb->call_id, CC_NO_CALL_ID), dcb->group_id,
|
|
((media != NULL) ? media->refid : CC_NO_MEDIA_REF_ID),
|
|
dcb->tone_direction);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Function : lsm_start_multipart_tone_timer
|
|
* Parameters : Tone: 2nd part of tone to play
|
|
* Delay: Time to delay between playing the 1st and 2nd parts of the tone
|
|
* CallId: Used to retrieve the dcb for this call
|
|
* Purpose : This function is used to set up the dcb to play the 2nd part of
|
|
* the tone. A timer is started to allow the 1st tone to played to
|
|
* completion before the 2nd part is started.
|
|
*/
|
|
void
|
|
lsm_start_multipart_tone_timer (vcm_tones_t tone,
|
|
uint32_t delay,
|
|
callid_t callId)
|
|
{
|
|
static const char fname[] = "lsm_start_multipart_tone_timer";
|
|
fsmdef_dcb_t *dcb;
|
|
|
|
/* Set up dcb for timer callback function */
|
|
dcb = fsmdef_get_dcb_by_call_id(callId);
|
|
dcb->alert_info = ALERTING_TONE;
|
|
dcb->alerting_tone = tone;
|
|
dcb->dialplan_tone = TRUE;
|
|
|
|
if (cprCancelTimer(lsm_tmr_tones) == CPR_FAILURE) {
|
|
LSM_DEBUG(get_debug_string(DEBUG_GENERAL_SYSTEMCALL_FAILED),
|
|
fname, "cprCancelTimer", cpr_errno);
|
|
}
|
|
if (cprStartTimer(lsm_tmr_tones, delay, (void *)(long)dcb->call_id) ==
|
|
CPR_FAILURE) {
|
|
LSM_DEBUG(get_debug_string(DEBUG_GENERAL_SYSTEMCALL_FAILED),
|
|
fname, "cprStartTimer", cpr_errno);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Function : lsm_stop_multipart_tone_timer
|
|
* Parameters : None
|
|
* Purpose : Called from vcm_stop_tones. That function
|
|
* will stop the 1st part of the tone, this
|
|
* function cancels the timer so the 2nd part
|
|
* will never be played.
|
|
*/
|
|
void
|
|
lsm_stop_multipart_tone_timer (void)
|
|
{
|
|
static const char fname[] = "lsm_stop_multipart_tone_timer";
|
|
|
|
if (cprCancelTimer(lsm_tmr_tones) == CPR_FAILURE) {
|
|
LSM_DEBUG(get_debug_string(DEBUG_GENERAL_SYSTEMCALL_FAILED),
|
|
fname, "cprCancelTimer", cpr_errno);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Function : lsm_start_continuous_tone_timer
|
|
* Parameters : Tone: tone to play
|
|
* Delay: Time to delay between playing the tone
|
|
* CallId: Used to retrieve the dcb for this call
|
|
* Purpose : This function is used to set up the dcb to play a tone continuously.
|
|
* An example being the tone on hold tone.
|
|
*/
|
|
void
|
|
lsm_start_continuous_tone_timer (vcm_tones_t tone,
|
|
uint32_t delay,
|
|
callid_t callId)
|
|
{
|
|
static const char fname[] = "lsm_start_continuous_tone_timer";
|
|
fsmdef_dcb_t *dcb;
|
|
|
|
/* Set up dcb for timer callback function */
|
|
dcb = fsmdef_get_dcb_by_call_id(callId);
|
|
dcb->alert_info = ALERTING_TONE;
|
|
dcb->alerting_tone = tone;
|
|
dcb->dialplan_tone = TRUE;
|
|
|
|
if (cprCancelTimer(lsm_continuous_tmr_tones) == CPR_FAILURE) {
|
|
LSM_DEBUG(get_debug_string(DEBUG_GENERAL_SYSTEMCALL_FAILED),
|
|
fname, "cprCancelTimer", cpr_errno);
|
|
}
|
|
if (cprStartTimer(lsm_continuous_tmr_tones, delay, (void *)(long)dcb->call_id)
|
|
== CPR_FAILURE) {
|
|
LSM_DEBUG(get_debug_string(DEBUG_GENERAL_SYSTEMCALL_FAILED),
|
|
fname, "cprStartTimer", cpr_errno);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Function : lsm_stop_continuous_tone_timer
|
|
* Parameters : None
|
|
* Purpose : Called from vcm_stop_tones. That function
|
|
* will stop the the tone, this function cancels
|
|
* the timer subsequent playing of the tone is not
|
|
* performed
|
|
*/
|
|
void
|
|
lsm_stop_continuous_tone_timer (void)
|
|
{
|
|
static const char fname[] = "lsm_stop_continuous_tone_timer";
|
|
|
|
if (cprCancelTimer(lsm_continuous_tmr_tones) == CPR_FAILURE) {
|
|
LSM_DEBUG(get_debug_string(DEBUG_GENERAL_SYSTEMCALL_FAILED),
|
|
fname, "cprCancelTimer", cpr_errno);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Function : lsm_start_tone_duration_timer
|
|
* Parameters : Tone: tone type to play
|
|
* Duration: length of time for tone to play
|
|
* call_handle: Used to retrieve the dcb for this call
|
|
* Purpose : This function is used to set up the dcb to play the tone for
|
|
* a specified length of time.
|
|
*/
|
|
void
|
|
lsm_start_tone_duration_timer (vcm_tones_t tone,
|
|
uint32_t duration,
|
|
cc_call_handle_t call_handle)
|
|
{
|
|
static const char fname[] = "lsm_start_tone_duration_timer";
|
|
fsmdef_dcb_t *dcb;
|
|
|
|
/* Set up dcb for timer callback function */
|
|
dcb = fsmdef_get_dcb_by_call_id(GET_CALL_ID(call_handle));
|
|
|
|
if (cprCancelTimer(lsm_tone_duration_tmr) == CPR_FAILURE) {
|
|
LSM_DEBUG(get_debug_string(DEBUG_GENERAL_SYSTEMCALL_FAILED),
|
|
fname, "cprCancelTimer", cpr_errno);
|
|
}
|
|
if (cprStartTimer(lsm_tone_duration_tmr, duration*1000, (void *)(long)dcb->call_id) ==
|
|
CPR_FAILURE) {
|
|
LSM_DEBUG(get_debug_string(DEBUG_GENERAL_SYSTEMCALL_FAILED),
|
|
fname, "cprStartTimer", cpr_errno);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Function : lsm_stop_tone_duration_timer
|
|
* Parameters : None
|
|
* Purpose : Called from vcm_stop_tones. That function
|
|
* will stop the tone.
|
|
*/
|
|
void
|
|
lsm_stop_tone_duration_timer (void)
|
|
{
|
|
static const char fname[] = "lsm_stop_tone_duration_timer";
|
|
|
|
if (cprCancelTimer(lsm_tone_duration_tmr) == CPR_FAILURE) {
|
|
LSM_DEBUG(get_debug_string(DEBUG_GENERAL_SYSTEMCALL_FAILED),
|
|
fname, "cprCancelTimer", cpr_errno);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* This is a callback function for those tones that are
|
|
* played in two parts (stutter and msgwaiting) or played
|
|
* every x seconds, but are not steady tones (call waiting).
|
|
*
|
|
* @param[in] data The gsm ID (callid_t) of the call of the
|
|
* tones timer has timeout.
|
|
*
|
|
* @return N/A
|
|
*/
|
|
void
|
|
lsm_tone_duration_tmr_callback (void *data)
|
|
{
|
|
static const char fname[] = "lsm_tone_duration_tmr_callback";
|
|
callid_t call_id;
|
|
fsmdef_dcb_t *dcb = NULL;
|
|
fsmdef_media_t *media;
|
|
|
|
LSM_DEBUG(DEB_F_PREFIX"invoked", DEB_F_PREFIX_ARGS(LSM, fname));
|
|
|
|
call_id = (callid_t)(long)data;
|
|
if (call_id == CC_NO_CALL_ID) {
|
|
/* Invalid call id */
|
|
LSM_DEBUG(DEB_F_PREFIX"invalid call id\n", DEB_F_PREFIX_ARGS(LSM, fname));
|
|
return;
|
|
}
|
|
|
|
/* Retrieve dcb from call id */
|
|
dcb = fsmdef_get_dcb_by_call_id(call_id);
|
|
if (dcb == NULL) {
|
|
LSM_DEBUG(DEB_F_PREFIX"no dcb found for call_id %d\n", DEB_F_PREFIX_ARGS(LSM, fname), call_id);
|
|
return;
|
|
}
|
|
|
|
media = gsmsdp_find_audio_media(dcb);
|
|
|
|
vcmToneStop(dcb->active_tone, dcb->group_id,
|
|
((media != NULL) ? media->refid : CC_NO_MEDIA_REF_ID),
|
|
lsm_get_ms_ui_call_handle(dcb->line, dcb->call_id, CC_NO_CALL_ID));
|
|
|
|
/* Up until this point, only sip core has started the call release procedure */
|
|
/* since upon receipt of the BYE. Now that tone is completed playing as requested */
|
|
/* in the BYE, need to continue processing with call clearing. */
|
|
|
|
cc_int_release(CC_SRC_GSM, CC_SRC_GSM, call_id, dcb->line, CC_CAUSE_NORMAL, NULL, NULL);
|
|
}
|
|
|
|
/*
|
|
* LSM internal function that checks if any calls are in a pending
|
|
* answer condition. Such a condition occurs when the GSM has delayed
|
|
* answering an incoming call while trying to clear other calls.
|
|
*
|
|
* @return call_id if found, else CC_NO_CALL_ID.
|
|
*/
|
|
static callid_t
|
|
lsm_answer_pending (void)
|
|
{
|
|
callid_t found_callid = CC_NO_CALL_ID;
|
|
lsm_lcb_t *lcb;
|
|
|
|
FSM_FOR_ALL_CBS(lcb, lsm_lcbs, LSM_MAX_LCBS) {
|
|
if ((lcb->call_id != CC_NO_CALL_ID) &&
|
|
(FSM_CHK_FLAGS(lcb->flags, LSM_FLAGS_ANSWER_PENDING))) {
|
|
|
|
found_callid = lcb->call_id;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return (found_callid);
|
|
}
|
|
|
|
/**
|
|
*
|
|
* Hold Reversion Alert - plays the ringer once.
|
|
*
|
|
* @param lsm_lcb_t lcb for this call
|
|
* @param callid_t gsm_id
|
|
* @param line_t line
|
|
*
|
|
* @return none
|
|
*
|
|
* @pre (lcb not_eq NULL)
|
|
*/
|
|
static void
|
|
lsm_reversion_ringer (lsm_lcb_t *lcb, callid_t call_id, line_t line)
|
|
{
|
|
vcm_ring_mode_t ringerMode = VCM_INSIDE_RING;
|
|
vcm_tones_t toneMode = VCM_CALL_WAITING_TONE;
|
|
|
|
if (!lsm_callwaiting()) {
|
|
config_get_line_value(CFGID_LINE_RING_SETTING_IDLE,
|
|
&ringSettingIdle, sizeof(ringSettingIdle),
|
|
line);
|
|
if (cc_line_ringer_mode[line] == CC_RING_DISABLE) {
|
|
ringerMode = VCM_FLASHONLY_RING;
|
|
} else if (ringSettingIdle == DISABLE) {
|
|
ringerMode = VCM_RING_OFF;
|
|
} else if (ringSettingIdle == FLASH_ONLY) {
|
|
ringerMode = VCM_FLASHONLY_RING;
|
|
}
|
|
|
|
vcmControlRinger(ringerMode, YES, NO, line, call_id);
|
|
|
|
} else {
|
|
lsm_tmr_tones_ticks = 0;
|
|
|
|
config_get_line_value(CFGID_LINE_RING_SETTING_ACTIVE,
|
|
&ringSettingActive, sizeof(ringSettingActive),
|
|
line);
|
|
if (ringSettingActive == DISABLE) {
|
|
ringerMode = VCM_RING_OFF;
|
|
} else if (ringSettingActive == FLASH_ONLY) {
|
|
ringerMode = VCM_FLASHONLY_RING;
|
|
}
|
|
|
|
if (ringSettingActive == BEEP_ONLY) {
|
|
fsmdef_media_t *media = gsmsdp_find_audio_media(lcb->dcb);
|
|
|
|
lsm_util_start_tone(toneMode, NO, lsm_get_ms_ui_call_handle(line, call_id, CC_NO_CALL_ID), lcb->dcb->group_id,
|
|
((media != NULL) ? media->refid : CC_NO_MEDIA_REF_ID),
|
|
VCM_PLAY_TONE_TO_EAR);
|
|
} else {
|
|
vcmControlRinger(ringerMode, YES, NO, line, call_id);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This function will set beep only settings.
|
|
*
|
|
* @param[in] dcb - DEF S/M control block
|
|
* @param[out] toneMode_p - pointer to tone mode
|
|
*
|
|
* @return none
|
|
*/
|
|
static void
|
|
lsm_set_beep_only_settings (fsmdef_dcb_t *dcb, vcm_tones_t *toneMode_p)
|
|
{
|
|
switch (dcb->alert_info) {
|
|
/*
|
|
* Map BTS requested ring pattern to corresponding call waiting
|
|
* pattern if phone is already offhook. All call waiting tones
|
|
* must be played every ten seconds and msg waiting and stutter
|
|
* dialtone are multi-part tones that play and then after
|
|
* 100 ms give steady dialtone. Set a timer to call the tone
|
|
* callback function for those tones.
|
|
*/
|
|
case ALERTING_RING:
|
|
lsm_tmr_tones_ticks = callWaitingDelay;
|
|
switch (dcb->alerting_ring) {
|
|
case VCM_BELLCORE_DR2:
|
|
*toneMode_p = VCM_CALL_WAITING_2_TONE;
|
|
break;
|
|
|
|
case VCM_BELLCORE_DR3:
|
|
*toneMode_p = VCM_CALL_WAITING_3_TONE;
|
|
break;
|
|
|
|
case VCM_BELLCORE_DR4:
|
|
*toneMode_p = VCM_CALL_WAITING_4_TONE;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
/* BTS wishes to override call waiting tone */
|
|
case ALERTING_TONE:
|
|
/*
|
|
* In violation of the spec, BTS will send tones in the
|
|
* Alert-Info header and if the phone is offhook, wants
|
|
* the phone to play the tone specified in the Alert-Info
|
|
* header instead of the normal call waiting tone. If this
|
|
* line is connected to a call manager follow the spec and
|
|
* always play the call waiting tone regardless of what was
|
|
* received in the Alert-Info header.
|
|
*/
|
|
if (sip_regmgr_get_cc_mode(dcb->line) == REG_MODE_CCM) {
|
|
dcb->alerting_tone = VCM_CALL_WAITING_TONE;
|
|
LSM_DEBUG(DEB_F_PREFIX"%s - Overriding value in Alert-Info header as line %d is \
|
|
connected to a Call Manager.\n",
|
|
DEB_F_PREFIX_ARGS(LSM, "lsm_set_beep_only_settings"), dcb->line);
|
|
}
|
|
*toneMode_p = dcb->alerting_tone;
|
|
switch (dcb->alerting_tone) {
|
|
case VCM_MSG_WAITING_TONE:
|
|
lsm_tmr_tones_ticks = MSG_WAITING_DELAY;
|
|
break;
|
|
|
|
case VCM_STUTTER_TONE:
|
|
lsm_tmr_tones_ticks = STUTTER_DELAY;
|
|
break;
|
|
|
|
case VCM_BUSY_VERIFY_TONE:
|
|
lsm_tmr_tones_ticks = BUSY_VERIFY_DELAY;
|
|
break;
|
|
|
|
case VCM_CALL_WAITING_TONE:
|
|
case VCM_CALL_WAITING_2_TONE:
|
|
case VCM_CALL_WAITING_3_TONE:
|
|
case VCM_CALL_WAITING_4_TONE:
|
|
lsm_tmr_tones_ticks = callWaitingDelay;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
lsm_tmr_tones_ticks = callWaitingDelay;
|
|
}
|
|
}
|
|
|
|
/**
|
|
*
|
|
* Set ringer mode based on remote-cc input and configuration parameters. If there
|
|
* any other call pending then it should play call waiting tone.
|
|
*
|
|
* @param lsm_lcb_t lcb for this call
|
|
* @param callid_t gsm_id
|
|
* @param line_t line
|
|
*
|
|
* @return none
|
|
*
|
|
* @pre (lcb not_eq NULL)
|
|
*/
|
|
static void
|
|
lsm_set_ringer (lsm_lcb_t *lcb, callid_t call_id, line_t line, int alerting)
|
|
{
|
|
static const char fname[] = "lsm_set_ringer";
|
|
fsmdef_dcb_t *dcb;
|
|
boolean ringer_set = FALSE;
|
|
callid_t other_call_id = CC_NO_CALL_ID;
|
|
callid_t priority_call_id = CC_NO_CALL_ID;
|
|
int callHoldRingback = 0;
|
|
int dcb_cnt = 0;
|
|
int i = 0;
|
|
fsmxfr_xcb_t *xcb;
|
|
fsmcnf_ccb_t *ccb;
|
|
lsm_lcb_t *lcb2;
|
|
fsmdef_dcb_t *dcbs[LSM_MAX_CALLS];
|
|
vcm_ring_mode_t ringerMode = VCM_INSIDE_RING;
|
|
short ringOnce = NO;
|
|
boolean alertInfo = NO;
|
|
vcm_tones_t toneMode = VCM_CALL_WAITING_TONE;
|
|
fsmdef_media_t *media;
|
|
boolean isDusting = FSM_CHK_FLAGS(lcb->flags, LSM_FLAGS_DUSTING) ? TRUE : FALSE;
|
|
int sdpmode = 0;
|
|
|
|
|
|
LSM_DEBUG(DEB_L_C_F_PREFIX"Entered, state=%d.\n",
|
|
DEB_L_C_F_PREFIX_ARGS(LSM, line, call_id, fname), lcb->state);
|
|
|
|
config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
|
|
|
|
/*
|
|
* The ringer (or call-waiting tone) should be on if these
|
|
* conditions are met:
|
|
* 1. A line is ringing for an incoming call and no calls
|
|
* with a pending answer
|
|
* 2. A line is on hold
|
|
* and
|
|
* 3. No lines are connected
|
|
*
|
|
* Otherwise, turn on the call-waiting tones.
|
|
*
|
|
*/
|
|
|
|
if (priority_call_id == CC_NO_CALL_ID) {
|
|
/* get the call_id of the line that triggers this if it is ringing and
|
|
pass down the correct line variable and its ring type and let the ring
|
|
manager decides. Originally we only find line first line in ringing state
|
|
which results in issue where Flash only line follows by audio ring line
|
|
ringing simultaneously, the phone does not ring audibly.
|
|
*/
|
|
if (lcb->state == LSM_S_RINGIN) {
|
|
other_call_id = call_id;
|
|
} else {
|
|
other_call_id = lsm_find_state(LSM_S_RINGIN);
|
|
}
|
|
}
|
|
|
|
if (((priority_call_id != CC_NO_CALL_ID) || (other_call_id != CC_NO_CALL_ID)) &&
|
|
(lsm_answer_pending() == CC_NO_CALL_ID)) {
|
|
/*sam
|
|
* may need to add (ringout and rtp open) to this check.
|
|
* It is possible that inband alerting is active for an outgoing call.
|
|
*/
|
|
dcb = fsmdef_get_dcb_by_call_id((priority_call_id != CC_NO_CALL_ID) ?
|
|
priority_call_id : other_call_id);
|
|
lcb = lsm_get_lcb_by_call_id((priority_call_id != CC_NO_CALL_ID) ?
|
|
priority_call_id : other_call_id);
|
|
isDusting = ((lcb != NULL) && FSM_CHK_FLAGS(lcb->flags, LSM_FLAGS_DUSTING)) ? TRUE : FALSE;
|
|
|
|
/*
|
|
* TNP has line-based ringing so update the line parameter so
|
|
* if reflects what line is ringing, not which line had an action
|
|
* taken against it, i.e. if line 1 hangs up and line 2 is ringing,
|
|
* line will be equal to 1 (since that line hung-up), but it needs
|
|
* to be 2 since that is the line actually ringing. 40/60 can
|
|
* get away with this since it is device-based ringing. If there
|
|
* are multiple lines in the RINGIN state, the ringing will be
|
|
* based on the first line in the RINGIN state found. Could add
|
|
* the check if (other_call_id != callid) but line will equal
|
|
* dcb->line if the callids are the same so save a few CPU cycles
|
|
* by not having the check. No need to do a #ifdef TNP since
|
|
* it does matter which line we use on the 40/60 as it is device based.
|
|
*/
|
|
line = dcb->line;
|
|
|
|
if (!lsm_callwaiting()) {
|
|
|
|
LSM_DEBUG(DEB_L_C_F_PREFIX"No call waiting, lcb->line=%d, lcb->flag=%d.\n",
|
|
DEB_L_C_F_PREFIX_ARGS(LSM, line, lcb->call_id, fname),
|
|
lcb->line,
|
|
lcb->flags);
|
|
|
|
ringer_set = TRUE;
|
|
lsm_tmr_tones_ticks = 0;
|
|
|
|
/*
|
|
* CFGID_LINE_RING_SETTING_IDLE is a config parameter that
|
|
* tells the phone what action to take for an incoming
|
|
* call on a phone with no active calls.
|
|
*
|
|
*/
|
|
|
|
if (isDusting) {
|
|
ringSettingIdle = FLASH_ONLY;
|
|
}
|
|
else if (FSM_CHK_FLAGS(lcb->flags, LSM_FLAGS_PREVENT_RINGING)) {
|
|
/*
|
|
* If this phone is both calling and called device, do not play ring.
|
|
*/
|
|
ringSettingIdle = DISABLE;
|
|
} else if (cc_line_ringer_mode[line] == CC_RING_DISABLE) {
|
|
/*
|
|
* Disable - no ring or flash
|
|
*/
|
|
ringSettingIdle = FLASH_ONLY;
|
|
} else if (cc_line_ringer_mode[line] == CC_RING_ENABLE) {
|
|
ringSettingIdle = RING;
|
|
} else {
|
|
config_get_line_value(CFGID_LINE_RING_SETTING_IDLE,
|
|
&ringSettingIdle, sizeof(ringSettingIdle),
|
|
line);
|
|
}
|
|
LSM_DEBUG(DEB_L_C_F_PREFIX"Ring set mode=%d.\n",
|
|
DEB_L_C_F_PREFIX_ARGS(LSM, line, call_id, fname), ringSettingIdle);
|
|
|
|
/*
|
|
* Disable - no ring or flash
|
|
*/
|
|
if (ringSettingIdle == DISABLE) {
|
|
ringerMode = VCM_RING_OFF;
|
|
|
|
/*
|
|
* Flash Only - No ringing, just flash.
|
|
*/
|
|
} else if (ringSettingIdle == FLASH_ONLY) {
|
|
ringerMode = VCM_FLASHONLY_RING;
|
|
|
|
/*
|
|
* Ring once - ring the phone once
|
|
*/
|
|
} else if (ringSettingIdle == RING_ONCE) {
|
|
ringOnce = YES;
|
|
|
|
/*
|
|
* Ring - normal operation. Ring the phone until answered,
|
|
* forwarded, or disconnected.
|
|
*/
|
|
} else if (ringSettingIdle == RING) {
|
|
|
|
/* Determine what tone/ringing pattern to play */
|
|
switch (dcb->alert_info) {
|
|
case ALERTING_NONE:
|
|
/* This is the default case nothing to do */
|
|
break;
|
|
|
|
case ALERTING_RING:
|
|
ringerMode = dcb->alerting_ring;
|
|
break;
|
|
|
|
case ALERTING_OLD:
|
|
default:
|
|
alertInfo = YES;
|
|
}
|
|
} else if (ringSettingIdle == BEEP_ONLY) {
|
|
lsm_set_beep_only_settings (dcb, &toneMode);
|
|
|
|
}
|
|
LSM_DEBUG(DEB_L_C_F_PREFIX"Alert info=%d, ringSettingIdle=%d, ringerMode=%d\n",
|
|
DEB_L_C_F_PREFIX_ARGS(LSM, line, call_id, fname),
|
|
dcb->alert_info,
|
|
ringSettingIdle,
|
|
ringerMode);
|
|
|
|
/*
|
|
* If an active call is being held while there is an incoming
|
|
* call AND ringSettingBusyStationPolicy is 0, this flag will
|
|
* be false.
|
|
*/
|
|
if (alerting) {
|
|
/*
|
|
* If the line is connected to a CCM, Bellcore-Dr1 means
|
|
* play the defined ringer once. Bellcore-dr2 means play
|
|
* the defined ringer twice.
|
|
*/
|
|
if (sip_regmgr_get_cc_mode(line) == REG_MODE_CCM) {
|
|
if (ringerMode == VCM_BELLCORE_DR1) {
|
|
ringerMode = VCM_INSIDE_RING;
|
|
} else if (ringerMode == VCM_BELLCORE_DR2) {
|
|
ringerMode = VCM_OUTSIDE_RING;
|
|
}
|
|
}
|
|
if (ringSettingIdle == BEEP_ONLY) {
|
|
|
|
LSM_DEBUG(DEB_L_C_F_PREFIX"Idle phone RING SETTING: Beep_only\n",
|
|
DEB_L_C_F_PREFIX_ARGS(LSM, line, call_id, fname));
|
|
|
|
media = gsmsdp_find_audio_media(lcb->dcb);
|
|
lsm_util_tone_start_with_speaker_as_backup(toneMode, NO, lsm_get_ms_ui_call_handle(line, call_id, CC_NO_CALL_ID),
|
|
lcb->dcb->group_id,
|
|
((media != NULL) ? media->refid : CC_NO_MEDIA_REF_ID),
|
|
VCM_PLAY_TONE_TO_EAR);
|
|
} else {
|
|
LSM_DEBUG(DEB_L_C_F_PREFIX"Idle phone RING SETTING: ringer Mode = %s,"
|
|
" Ring once = %d, alertInfo = %d\n",
|
|
DEB_L_C_F_PREFIX_ARGS(LSM, line, call_id, fname),
|
|
vm_alert_names[ringerMode], ringOnce, alertInfo);
|
|
|
|
vcmControlRinger(ringerMode, ringOnce, alertInfo, line, lcb->ui_id);
|
|
}
|
|
}
|
|
|
|
if ( lcb->state != LSM_S_HOLDING &&
|
|
lcb->state != LSM_S_RINGIN ) {
|
|
ui_set_call_status(platform_get_phrase_index_str(CALL_ALERTING),
|
|
line, lcb->ui_id);
|
|
}
|
|
} else {
|
|
|
|
// Ring off all lines.
|
|
FSM_FOR_ALL_CBS(lcb2, lsm_lcbs, LSM_MAX_LCBS) {
|
|
if ((lcb2->call_id != CC_NO_CALL_ID) &&
|
|
(lcb2->state == LSM_S_RINGIN) )
|
|
{
|
|
LSM_DEBUG(DEB_L_C_F_PREFIX"Call waiting RING SETTING: "
|
|
"ringer Mode = RING_OFF, Ring once = NO, alertInfo = NO\n",
|
|
DEB_L_C_F_PREFIX_ARGS(LSM, lcb2->line, lcb2->call_id, fname));
|
|
vcmControlRinger(VCM_RING_OFF, NO, NO, lcb2->line, call_id);
|
|
}
|
|
}
|
|
ringer_set = TRUE;
|
|
lsm_tmr_tones_ticks = 0;
|
|
|
|
/*
|
|
* ringSettingActive is a TNP only config parameter that
|
|
* tells the phone what action to take for an incoming
|
|
* call on a phone with an active call.
|
|
*/
|
|
if (isDusting) {
|
|
ringSettingActive = FLASH_ONLY;
|
|
} else {
|
|
config_get_line_value(CFGID_LINE_RING_SETTING_ACTIVE,
|
|
&ringSettingActive, sizeof(ringSettingActive),
|
|
line);
|
|
}
|
|
|
|
/*
|
|
* Disable - no ring or flash
|
|
*/
|
|
if (ringSettingActive == DISABLE) {
|
|
ringerMode = VCM_RING_OFF;
|
|
|
|
/*
|
|
* Flash Only - No ringing, just flash.
|
|
*/
|
|
} else if (ringSettingActive == FLASH_ONLY) {
|
|
ringerMode = VCM_FLASHONLY_RING;
|
|
|
|
/*
|
|
* Ring once - ring the phone once
|
|
*/
|
|
} else if (ringSettingActive == RING_ONCE) {
|
|
ringOnce = YES;
|
|
|
|
/*
|
|
* Ring - Ring the phone until answered, forwarded or
|
|
* disconnected.
|
|
*
|
|
* NOTE: This code is replicated above under checking
|
|
* RING_SETTING_IDLE above. Putting this common code
|
|
* in a function call saved a miniscule amount of memory
|
|
* at the cost of an additional function call for every
|
|
* call. It was decided it was not worth the cost, but
|
|
* has been documented in case the phone gets very,
|
|
* very low on memory in the future.
|
|
*/
|
|
} else if (ringSettingActive == RING) {
|
|
|
|
/* Determine what tone/ringing pattern to play */
|
|
switch (dcb->alert_info) {
|
|
case ALERTING_NONE:
|
|
/* This is the default case nothing to do */
|
|
break;
|
|
|
|
case ALERTING_RING:
|
|
ringerMode = dcb->alerting_ring;
|
|
break;
|
|
|
|
case ALERTING_OLD:
|
|
default:
|
|
alertInfo = YES;
|
|
}
|
|
|
|
/*
|
|
* BeepOnly - normal operation. Play call waiting tone.
|
|
*/
|
|
} else if (ringSettingActive == BEEP_ONLY) {
|
|
lsm_set_beep_only_settings (dcb, &toneMode);
|
|
|
|
}
|
|
|
|
/*
|
|
* If an active call is being held while there is an incoming
|
|
* call AND ringSettingBusyStationPolicy is 0, this flag will
|
|
* be false.
|
|
*/
|
|
if (alerting) {
|
|
/*
|
|
* The code above has set the variables to play either the ringer
|
|
* or a tone based on the ringSettingBusy. If the config variable
|
|
* is beeponly then call start_tone else call control_ringer.
|
|
*/
|
|
if (ringSettingActive == BEEP_ONLY) {
|
|
media = gsmsdp_find_audio_media(dcb);
|
|
|
|
lsm_util_start_tone(toneMode, NO, lsm_get_ms_ui_call_handle(line, call_id, CC_NO_CALL_ID), dcb->group_id,
|
|
((media != NULL) ? media->refid : CC_NO_MEDIA_REF_ID),
|
|
VCM_PLAY_TONE_TO_EAR);
|
|
} else {
|
|
|
|
LSM_DEBUG(DEB_L_C_F_PREFIX"Active call RING SETTING: "
|
|
"ringer Mode = %s, Ring once = %d, alertInfo = %d\n",
|
|
DEB_L_C_F_PREFIX_ARGS(LSM, line, call_id, fname),
|
|
vm_alert_names[ringerMode], ringOnce, alertInfo);
|
|
|
|
vcmControlRinger(ringerMode, ringOnce, alertInfo, line, lcb->ui_id);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Start a timer to play multiple part tones if needed.
|
|
*/
|
|
if (lsm_tmr_tones_ticks > 0) {
|
|
if (cprCancelTimer(lsm_tmr_tones) == CPR_FAILURE) {
|
|
LSM_DEBUG(get_debug_string(DEBUG_GENERAL_SYSTEMCALL_FAILED),
|
|
fname, "cprCancelTimer", cpr_errno);
|
|
}
|
|
if (cprStartTimer(lsm_tmr_tones, lsm_tmr_tones_ticks,
|
|
(void *)(long)dcb->call_id) == CPR_FAILURE) {
|
|
LSM_DEBUG(get_debug_string(DEBUG_GENERAL_SYSTEMCALL_FAILED),
|
|
fname, "cprStartTimer", cpr_errno);
|
|
}
|
|
}
|
|
}
|
|
} else if (lcb->state == LSM_S_IDLE) {
|
|
/*
|
|
* This line just hungup so let's check to see if call hold ringback
|
|
* is enabled and if we have any other holding lines. If so ring to
|
|
* alert the user that a line is still around.
|
|
*/
|
|
config_get_value(CFGID_CALL_HOLD_RINGBACK, &callHoldRingback,
|
|
sizeof(callHoldRingback));
|
|
if (callHoldRingback & 0x1) {
|
|
callid_t ui_id;
|
|
|
|
dcb_cnt = fsmdef_get_dcbs_in_held_state(dcbs, call_id);
|
|
for (i = 0, dcb = dcbs[i]; i < dcb_cnt; i++, dcb = dcbs[i]) {
|
|
ccb = fsmcnf_get_ccb_by_call_id(call_id);
|
|
xcb = fsmxfr_get_xcb_by_call_id(call_id);
|
|
if ((lsm_is_phone_inactive() == TRUE) &&
|
|
(ccb == NULL) && (xcb == NULL) &&
|
|
(lcb->enable_ringback == TRUE)) {
|
|
LSM_DEBUG(DEB_L_C_F_PREFIX"Applying ringback\n",
|
|
DEB_L_C_F_PREFIX_ARGS(LSM, lcb->line, lcb->call_id, fname));
|
|
ringer_set = TRUE;
|
|
|
|
LSM_DEBUG(DEB_L_C_F_PREFIX"Hold RINGBACK SETTING: ringer Mode = "
|
|
"VCM_INSIDE_RING, Ring once = YES, alertInfo = YES\n",
|
|
DEB_L_C_F_PREFIX_ARGS(LSM, line, dcb->call_id, fname));
|
|
vcmControlRinger(VCM_INSIDE_RING, YES, YES, line, call_id);
|
|
|
|
/* Find the corresponding LCB to get to the UI ID */
|
|
ui_id = lsm_get_ui_id(dcb->call_id);
|
|
ui_set_call_status(platform_get_phrase_index_str(CALL_INITIATE_HOLD),
|
|
dcb->line, ui_id);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ringer_set == FALSE) {
|
|
|
|
LSM_DEBUG(DEB_L_C_F_PREFIX"Ringer_set = False : "
|
|
"ringer Mode = VCM_RING_OFF, Ring once = NO, alertInfo = NO\n",
|
|
DEB_L_C_F_PREFIX_ARGS(LSM, line, call_id, fname));
|
|
|
|
|
|
if (!sdpmode) {
|
|
vcmControlRinger(VCM_RING_OFF, NO, NO, line, call_id);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
static cc_rcs_t
|
|
lsm_offhook (lsm_lcb_t *lcb, cc_state_data_offhook_t *data)
|
|
{
|
|
callid_t call_id = lcb->call_id;
|
|
line_t line = lcb->line;
|
|
fsmxfr_xcb_t *xcb;
|
|
lsm_lcb_t *lcb2;
|
|
callid_t call_id2;
|
|
int attr;
|
|
fsmdef_dcb_t *dcb;
|
|
|
|
dcb = lcb->dcb;
|
|
if (dcb == NULL) {
|
|
return (CC_RC_ERROR);
|
|
}
|
|
|
|
lsm_change_state(lcb, __LINE__, LSM_S_OFFHOOK);
|
|
|
|
/*
|
|
* Disable the ringer since the user is going offhook. Only calls
|
|
* in the RINGIN state should have ringing enabled.
|
|
*/
|
|
FSM_FOR_ALL_CBS(lcb2, lsm_lcbs, LSM_MAX_LCBS) {
|
|
if ((lcb2->call_id != CC_NO_CALL_ID) &&
|
|
(lcb2->state == LSM_S_RINGIN)) {
|
|
|
|
vcmControlRinger(VCM_RING_OFF, NO, NO, lcb2->line, lcb2->call_id);
|
|
}
|
|
}
|
|
|
|
dp_offhook(line, call_id);
|
|
|
|
attr = fsmutil_get_call_attr(dcb, line, call_id);
|
|
|
|
ui_new_call(evOffHook, line, lcb->ui_id, attr,
|
|
dcb->caller_id.call_instance_id,
|
|
(boolean)FSM_CHK_FLAGS(lcb->flags, LSM_FLAGS_DIALED_STRING));
|
|
|
|
xcb = fsmxfr_get_xcb_by_call_id(call_id);
|
|
if (xcb != NULL) {
|
|
call_id2 = ((lcb->call_id == xcb->xfr_call_id) ?
|
|
(xcb->cns_call_id) : (xcb->xfr_call_id));
|
|
lcb2 = lsm_get_lcb_by_call_id(call_id2);
|
|
}
|
|
|
|
//vcmActivateWlan(TRUE);
|
|
|
|
vcmEnableSidetone(YES);
|
|
|
|
return (CC_RC_SUCCESS);
|
|
}
|
|
|
|
|
|
static cc_rcs_t
|
|
lsm_dialing (lsm_lcb_t *lcb, cc_state_data_dialing_t *data)
|
|
{
|
|
fsmxfr_xcb_t *xcb = NULL;
|
|
int stutterMsgWaiting = 0;
|
|
fsmdef_dcb_t *dcb = lcb->dcb;
|
|
fsmdef_media_t *media = gsmsdp_find_audio_media(dcb);
|
|
|
|
|
|
if ( dcb == NULL) {
|
|
return (CC_RC_ERROR);
|
|
}
|
|
|
|
/* don't provide dial tone on transfer unless we are the transferor. */
|
|
xcb = fsmxfr_get_xcb_by_call_id(lcb->call_id);
|
|
if ((xcb != NULL) && (xcb->mode != FSMXFR_MODE_TRANSFEROR)) {
|
|
return (CC_RC_SUCCESS);
|
|
}
|
|
|
|
/*
|
|
* Start dial tone if no digits have been entered
|
|
*/
|
|
if ((data->play_dt == TRUE)
|
|
&& (dp_check_for_plar_line(lcb->line) == FALSE)
|
|
) {
|
|
|
|
/* get line based AMWI config */
|
|
config_get_value(CFGID_LINE_MESSAGE_WAITING_AMWI + lcb->line - 1, &stutterMsgWaiting,
|
|
sizeof(stutterMsgWaiting));
|
|
if ( stutterMsgWaiting != 1 && stutterMsgWaiting != 0) {
|
|
/* AMWI is not configured. Fallback on config for stutter dial tone */
|
|
config_get_value(CFGID_STUTTER_MSG_WAITING, &stutterMsgWaiting,
|
|
sizeof(stutterMsgWaiting));
|
|
stutterMsgWaiting &= 0x1; /* LSB indicates on/off */
|
|
}
|
|
|
|
if ( (data->suppress_stutter == FALSE) &&
|
|
(ui_line_has_mwi_active(lcb->line)) && /* has msgs waiting */
|
|
stutterMsgWaiting ) {
|
|
lsm_util_start_tone(VCM_STUTTER_TONE, FALSE, lsm_get_ms_ui_call_handle(lcb->line, CC_NO_CALL_ID, lcb->ui_id),
|
|
dcb->group_id,
|
|
((media != NULL) ? media->refid : CC_NO_MEDIA_REF_ID),
|
|
VCM_PLAY_TONE_TO_EAR);
|
|
} else {
|
|
lsm_util_start_tone(VCM_INSIDE_DIAL_TONE, FALSE, lsm_get_ms_ui_call_handle(lcb->line, CC_NO_CALL_ID, lcb->ui_id),
|
|
dcb->group_id,
|
|
((media != NULL) ? media->refid : CC_NO_MEDIA_REF_ID),
|
|
VCM_PLAY_TONE_TO_EAR);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* For round table phone, post WAITINGFORDIGITS event,
|
|
* so that UI can pop up dialing screen.
|
|
* For TNP, this event gets ignored.
|
|
*/
|
|
ui_call_state(evWaitingForDigits, lcb->line, lcb->ui_id, CC_CAUSE_NORMAL);
|
|
|
|
|
|
return (CC_RC_SUCCESS);
|
|
}
|
|
|
|
|
|
static cc_rcs_t
|
|
lsm_dialing_completed (lsm_lcb_t *lcb, cc_state_data_dialing_completed_t *data)
|
|
{
|
|
line_t line = lcb->line;
|
|
fsmdef_dcb_t *dcb = lcb->dcb;
|
|
|
|
if (dcb == NULL) {
|
|
return (CC_RC_ERROR);
|
|
}
|
|
|
|
lsm_change_state(lcb, __LINE__, LSM_S_PROCEED);
|
|
|
|
/* If KPML is enabled then do not change UI state to
|
|
* proceed, more digit to collect
|
|
*/
|
|
if (dp_get_kpml_state()) {
|
|
return (CC_RC_SUCCESS);
|
|
}
|
|
|
|
ui_call_info(data->caller_id.calling_name,
|
|
data->caller_id.calling_number,
|
|
data->caller_id.alt_calling_number,
|
|
data->caller_id.display_calling_number,
|
|
data->caller_id.called_name,
|
|
data->caller_id.called_number,
|
|
data->caller_id.display_called_number,
|
|
data->caller_id.orig_called_name,
|
|
data->caller_id.orig_called_number,
|
|
data->caller_id.last_redirect_name,
|
|
data->caller_id.last_redirect_number,
|
|
(calltype_t)dcb->call_type,
|
|
line, lcb->ui_id,
|
|
dcb->caller_id.call_instance_id,
|
|
FSM_GET_SECURITY_STATUS(dcb),
|
|
FSM_GET_POLICY(dcb));
|
|
|
|
lsm_ui_call_state(evProceed, line, lcb, CC_CAUSE_NORMAL);
|
|
|
|
(void) lsm_stop_tone(lcb, NULL);
|
|
|
|
return (CC_RC_SUCCESS);
|
|
}
|
|
|
|
|
|
static cc_rcs_t
|
|
lsm_call_sent (lsm_lcb_t *lcb, cc_state_data_call_sent_t *data)
|
|
{
|
|
line_t line = lcb->line;
|
|
fsmdef_dcb_t *dcb;
|
|
char tmp_str[STATUS_LINE_MAX_LEN];
|
|
fsmdef_media_t *media;
|
|
static const char fname[] = "lsm_call_sent";
|
|
|
|
dcb = lcb->dcb;
|
|
if (dcb == NULL) {
|
|
return (CC_RC_ERROR);
|
|
}
|
|
|
|
lsm_change_state(lcb, __LINE__, LSM_S_PROCEED);
|
|
|
|
(void) lsm_stop_tone(lcb, NULL);
|
|
|
|
/*
|
|
* We go ahead and start a rx port if our local SDP indicates
|
|
* the need in an attempt to be 3264 compliant. Since we have
|
|
* not yet locked down the codec, we will use preferred codec if
|
|
* configured. If not, we use the first codec in our local
|
|
* list of supported codecs. The codec list was initialized
|
|
* in fsmdef_init_local_sdp.
|
|
*/
|
|
GSMSDP_FOR_ALL_MEDIA(media, dcb) {
|
|
if (!GSMSDP_MEDIA_ENABLED(media)) {
|
|
continue;
|
|
}
|
|
LSM_DEBUG(DEB_F_PREFIX"%d %d %d\n", DEB_F_PREFIX_ARGS(LSM, fname), media->direction_set,
|
|
media->direction, media->is_multicast);
|
|
if ((media->direction_set) &&
|
|
((media->direction == SDP_DIRECTION_SENDRECV) ||
|
|
(media->direction == SDP_DIRECTION_RECVONLY))) {
|
|
|
|
lsm_rx_start(lcb, cc_state_name(CC_STATE_FAR_END_ALERTING),
|
|
media);
|
|
}
|
|
}
|
|
|
|
if (!dp_get_kpml_state()) {
|
|
if ((platGetPhraseText(STR_INDEX_CALLING,
|
|
(char *) tmp_str,
|
|
STATUS_LINE_MAX_LEN - 1)) == CPR_SUCCESS) {
|
|
ui_set_call_status(tmp_str, line, lcb->ui_id);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* cancel offhook to first digit timer.
|
|
*/
|
|
dp_int_cancel_offhook_timer(line, lcb->call_id);
|
|
|
|
return (CC_RC_SUCCESS);
|
|
}
|
|
|
|
|
|
static cc_rcs_t
|
|
lsm_far_end_proceeding (lsm_lcb_t *lcb,
|
|
cc_state_data_far_end_proceeding_t * data)
|
|
{
|
|
line_t line = lcb->line;
|
|
fsmdef_dcb_t *dcb;
|
|
|
|
lsm_change_state(lcb, __LINE__, LSM_S_PROCEED);
|
|
|
|
if (!dp_get_kpml_state()) {
|
|
ui_set_call_status(platform_get_phrase_index_str(CALL_PROCEEDING_IN),
|
|
line, lcb->ui_id);
|
|
/*
|
|
* update placed call info in call history with dialed digits
|
|
*/
|
|
dcb = lcb->dcb;
|
|
if (dcb != NULL && dcb->placed_call_update_required) {
|
|
lsm_update_placed_callinfo(dcb);
|
|
dcb->placed_call_update_required = FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
return (CC_RC_SUCCESS);
|
|
}
|
|
|
|
|
|
static cc_rcs_t
|
|
lsm_far_end_alerting (lsm_lcb_t *lcb, cc_state_data_far_end_alerting_t *data)
|
|
{
|
|
static const char fname[] = "lsm_far_end_alerting";
|
|
callid_t call_id = lcb->call_id;
|
|
line_t line = lcb->line;
|
|
fsmdef_dcb_t *dcb;
|
|
const char *status = NULL;
|
|
fsmcnf_ccb_t *ccb;
|
|
boolean rcv_port_started = FALSE;
|
|
char tmp_str[STATUS_LINE_MAX_LEN];
|
|
boolean spoof_ringout;
|
|
fsmdef_media_t *media;
|
|
call_events call_state;
|
|
fsmdef_media_t *audio_media;
|
|
boolean is_session_progress = FALSE;
|
|
|
|
|
|
/*
|
|
* Need to check if rcv_chan is already open and if we will be
|
|
* receiving inband ringing. The recv_chan should always be
|
|
* open since we always open a receive channel when initiating a
|
|
* call. If inband ringing will be sent by the far end, we
|
|
* will close the receive port and reopen it using the codec
|
|
* negotiated when we received the SDP in the far ends call
|
|
* proceeding message. We want to close the receive port well
|
|
* ahead of reopening it due to some issue in the dsp where
|
|
* a close followed immediately by an open causes a reset of
|
|
* the DSP.
|
|
*/
|
|
dcb = lcb->dcb;
|
|
if (dcb == NULL) {
|
|
return (CC_RC_ERROR);
|
|
}
|
|
audio_media = gsmsdp_find_audio_media(dcb);
|
|
|
|
if (dcb->inband) {
|
|
/* close (with refresh) all media entries */
|
|
lsm_close_rx(lcb, TRUE, NULL);
|
|
lsm_close_tx(lcb, TRUE, NULL);
|
|
}
|
|
|
|
/*
|
|
* Check to see if we need to spoof ring out in connected or holding
|
|
* state.
|
|
*
|
|
* The LSM can be in holding state when the user is resuming
|
|
* currently held call that was early transferred to another party
|
|
* and the other party has not answered the call yet.
|
|
*/
|
|
if (dcb->spoof_ringout_requested &&
|
|
((lcb->state == LSM_S_CONNECTED) || (lcb->state == LSM_S_HOLDING))) {
|
|
/* Spoof ring out is requested in the connected/holding state */
|
|
spoof_ringout = TRUE;
|
|
} else {
|
|
spoof_ringout = FALSE;
|
|
}
|
|
lsm_change_state(lcb, __LINE__, LSM_S_RINGOUT);
|
|
|
|
/* Don't send the dialplan update msg if CFWD_ALL. Otherwise the invalid
|
|
* redial numer is saved. (CSCsv08816)
|
|
*/
|
|
if (dcb->active_feature != CC_FEATURE_CFWD_ALL) {
|
|
dp_int_update(line, call_id, data->caller_id.called_number);
|
|
}
|
|
|
|
|
|
/*
|
|
* Check for inband alerting or spoof ringout.
|
|
* If no inband alerting and this is not a spoof ringout case,
|
|
* just update the status line to show we are alerting. The local
|
|
* ringback tone will not be started until the ringback delay timer
|
|
* expires.
|
|
*/
|
|
if (dcb->inband != TRUE || spoof_ringout) {
|
|
status = platform_get_phrase_index_str(CALL_ALERTING_LOCAL);
|
|
|
|
if (spoof_ringout) {
|
|
|
|
if (audio_media) {
|
|
|
|
/*
|
|
* Ringback delay timer is not used for spoof ringout case
|
|
* so start local ringback tone now.
|
|
*/
|
|
lsm_util_start_tone(VCM_ALERTING_TONE, FALSE, lsm_get_ms_ui_call_handle(line, call_id, CC_NO_CALL_ID),
|
|
dcb->group_id,audio_media->refid,
|
|
VCM_PLAY_TONE_TO_EAR);
|
|
}
|
|
|
|
}
|
|
} else {
|
|
is_session_progress = TRUE;
|
|
(void) lsm_stop_tone(lcb, NULL);
|
|
|
|
if ((platGetPhraseText(STR_INDEX_SESSION_PROGRESS,
|
|
(char *) tmp_str,
|
|
STATUS_LINE_MAX_LEN - 1)) == CPR_SUCCESS) {
|
|
status = tmp_str;
|
|
}
|
|
|
|
/* start receive and transmit for all media entries that are active */
|
|
GSMSDP_FOR_ALL_MEDIA(media, dcb) {
|
|
if (!GSMSDP_MEDIA_ENABLED(media)) {
|
|
/* this entry is not active */
|
|
continue;
|
|
}
|
|
LSM_DEBUG(DEB_L_C_F_PREFIX"direction_set:%d direction:%d"
|
|
" dest_addr:0x%x is_multicast:%d\n",
|
|
DEB_L_C_F_PREFIX_ARGS(LSM, dcb->line, dcb->call_id, fname),
|
|
media->direction_set,
|
|
media->direction, media->dest_addr,
|
|
media->is_multicast);
|
|
|
|
if (media->direction_set) {
|
|
if (media->direction == SDP_DIRECTION_SENDRECV ||
|
|
media->direction == SDP_DIRECTION_RECVONLY) {
|
|
lsm_rx_start(lcb,
|
|
cc_state_name(CC_STATE_FAR_END_ALERTING),
|
|
media);
|
|
rcv_port_started = TRUE;
|
|
}
|
|
|
|
if (media->direction == SDP_DIRECTION_SENDRECV ||
|
|
media->direction == SDP_DIRECTION_SENDONLY) {
|
|
lsm_tx_start(lcb,
|
|
cc_state_name(CC_STATE_FAR_END_ALERTING),
|
|
media);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!rcv_port_started) {
|
|
/*
|
|
* Since we had SDP we thought inband ringback was in order but
|
|
* media attributes indicate the receive port is to remain
|
|
* closed. In this case, go ahead and apply local ringback tone
|
|
* or user will hear silence. We do not depend on ringback delay
|
|
* timer to start the local ringback tone so we have to start it
|
|
* here.
|
|
*/
|
|
status = platform_get_phrase_index_str(CALL_ALERTING_LOCAL);
|
|
lsm_util_start_tone(VCM_ALERTING_TONE, FALSE, lsm_get_ms_ui_call_handle(line, call_id, CC_NO_CALL_ID), dcb->group_id,
|
|
((audio_media != NULL) ? audio_media->refid :
|
|
CC_NO_MEDIA_REF_ID),
|
|
VCM_PLAY_TONE_TO_EAR);
|
|
} else {
|
|
lsm_set_ringer(lcb, call_id, line, YES);
|
|
}
|
|
}
|
|
|
|
ccb = fsmcnf_get_ccb_by_call_id(call_id);
|
|
|
|
/* Update call information */
|
|
lsm_internal_update_call_info(lcb, dcb);
|
|
|
|
/* This is the case where remote end of the call has been early trasnfered
|
|
* to another endpoint.
|
|
*/
|
|
|
|
ccb = fsmcnf_get_ccb_by_call_id(lcb->call_id);
|
|
|
|
if ((ccb != NULL) && (ccb->active == TRUE) &&
|
|
(ccb->flags & LCL_CNF)) {
|
|
call_state = evConference;
|
|
} else {
|
|
call_state = evRingOut;
|
|
}
|
|
|
|
/* If an invalid DN is dialed during CFA then CCM sends 183/Session Progress
|
|
* (a.k.a. far end alerting) so it can play the invalid DN announcement. In
|
|
* this case CCM sends 404 Not Found after playing the announcement. If we
|
|
* are here due to that situation then don't propagate call info or status
|
|
* to UI side as it will display "Session Progress" on the status line and
|
|
* will log the DN in Placed calls; and we don't want either. Just skip the
|
|
* update and following 404 Not Found will take care of playing/displaying
|
|
* Reorder. Note that this condition may occur only in TNP/CCM mode.
|
|
*/
|
|
if (dcb->active_feature != CC_FEATURE_CFWD_ALL) {
|
|
if(!is_session_progress) {//CSCtc18750
|
|
/*
|
|
* update placed call info in call history with dialed digits
|
|
*/
|
|
if (dcb->placed_call_update_required) {
|
|
lsm_update_placed_callinfo(dcb);
|
|
dcb->placed_call_update_required = FALSE;
|
|
}
|
|
|
|
if (status) {
|
|
ui_set_call_status(status, line, lcb->ui_id);
|
|
}
|
|
}
|
|
|
|
lsm_ui_call_state(call_state, line, lcb, CC_CAUSE_NORMAL);
|
|
|
|
}
|
|
/* For roundtable phones, UI will be in dial state, which is different from TNP UI,
|
|
* TNP UI does not have different dialing layer. In this case offhook dialing screen
|
|
* does not vanish untill GSM provides procced call status, hence all the softkeys are
|
|
* available during CFWD, which is not correct
|
|
*/
|
|
if (dcb->active_feature == CC_FEATURE_CFWD_ALL) {
|
|
lsm_ui_call_state(evReorder, line, lcb, CC_CAUSE_NORMAL);
|
|
}
|
|
|
|
return (CC_RC_SUCCESS);
|
|
}
|
|
|
|
|
|
static cc_rcs_t
|
|
lsm_call_received (lsm_lcb_t *lcb, cc_state_data_call_received_t *data)
|
|
{
|
|
return (CC_RC_SUCCESS);
|
|
}
|
|
|
|
|
|
static cc_rcs_t
|
|
lsm_alerting (lsm_lcb_t *lcb, cc_state_data_alerting_t *data)
|
|
{
|
|
callid_t call_id = lcb->call_id;
|
|
line_t line = lcb->line;
|
|
fsmdef_dcb_t *dcb;
|
|
|
|
dcb = lcb->dcb;
|
|
if (dcb == NULL) {
|
|
return (CC_RC_ERROR);
|
|
}
|
|
|
|
lsm_change_state(lcb, __LINE__, LSM_S_RINGIN);
|
|
|
|
dcb->ui_update_required = TRUE;
|
|
lsm_internal_update_call_info(lcb, dcb);
|
|
|
|
ui_new_call(evRingIn, line, lcb->ui_id, NORMAL_CALL,
|
|
dcb->caller_id.call_instance_id, FALSE);
|
|
|
|
fsmutil_set_shown_calls_ci_element(dcb->caller_id.call_instance_id, line);
|
|
lsm_ui_call_state(evRingIn, line, lcb, CC_CAUSE_NORMAL);
|
|
lsm_update_inalert_status(line, lcb->ui_id, data, TRUE);
|
|
|
|
|
|
lsm_set_ringer(lcb, call_id, line, YES);
|
|
|
|
return (CC_RC_SUCCESS);
|
|
}
|
|
|
|
|
|
static cc_rcs_t
|
|
lsm_answered (lsm_lcb_t *lcb, cc_state_data_answered_t *data)
|
|
{
|
|
line_t line = lcb->line;
|
|
fsmdef_dcb_t *dcb;
|
|
|
|
dcb = lcb->dcb;
|
|
if (dcb == NULL) {
|
|
return (CC_RC_ERROR);
|
|
}
|
|
|
|
lsm_change_state(lcb, __LINE__, LSM_S_OFFHOOK);
|
|
|
|
|
|
lsm_internal_update_call_info(lcb, dcb);
|
|
|
|
vcmControlRinger(VCM_RING_OFF, NO, NO, line, dcb->call_id);
|
|
|
|
lsm_ui_call_state(evOffHook, line, lcb, CC_CAUSE_NORMAL);
|
|
|
|
//vcmActivateWlan(TRUE);
|
|
|
|
(void) lsm_stop_tone(lcb, NULL);
|
|
|
|
return (CC_RC_SUCCESS);
|
|
}
|
|
|
|
/**
|
|
*
|
|
* Function updates media paths based on the negotated parameters.
|
|
*
|
|
* @param lcb line control block
|
|
* @param caller_fname caller function name
|
|
*
|
|
* @return none
|
|
*
|
|
* @pre (dcb not_eq NULL)
|
|
* @pre (fname not_eq NULL)
|
|
*/
|
|
static void
|
|
lsm_update_media (lsm_lcb_t *lcb, const char *caller_fname)
|
|
{
|
|
static const char fname[] = "lsm_update_media";
|
|
fsmdef_dcb_t *dcb;
|
|
fsmdef_media_t *media;
|
|
boolean rx_refresh;
|
|
boolean tx_refresh;
|
|
char addr_str[MAX_IPADDR_STR_LEN];
|
|
int i;
|
|
|
|
dcb = lcb->dcb;
|
|
if (dcb == NULL) {
|
|
LSM_ERR_MSG(get_debug_string(DEBUG_INPUT_NULL),
|
|
fname);
|
|
return;
|
|
}
|
|
|
|
addr_str[0] = '\0';
|
|
|
|
/*
|
|
* Close rx and tx port for media change. Check media direction
|
|
* to see if port should be closed or remain open. If the port
|
|
* needs to be kept open, lsm_close_* functions will check to
|
|
* see if any media attributes have changed. If anything has
|
|
* changed, the port is closed, otherwise the port remains
|
|
* open. If media direction is not set, treat as if set to inactive.
|
|
* Also, if multicast leave rx_refresh and tx_refresh to FALSE to
|
|
* force a socket close.
|
|
*/
|
|
GSMSDP_FOR_ALL_MEDIA(media, dcb) {
|
|
if (!GSMSDP_MEDIA_ENABLED(media) ||
|
|
FSM_CHK_FLAGS(media->hold, FSM_HOLD_LCL)) {
|
|
/* this entry is not active or locally held */
|
|
continue;
|
|
}
|
|
|
|
rx_refresh = FALSE;
|
|
tx_refresh = FALSE;
|
|
|
|
if ((media->direction_set) && (media->is_multicast == FALSE)) {
|
|
if (media->direction == SDP_DIRECTION_SENDRECV ||
|
|
media->direction == SDP_DIRECTION_RECVONLY) {
|
|
rx_refresh = TRUE;
|
|
}
|
|
if (media->direction == SDP_DIRECTION_SENDRECV ||
|
|
media->direction == SDP_DIRECTION_SENDONLY) {
|
|
tx_refresh = TRUE;
|
|
}
|
|
}
|
|
|
|
lsm_close_rx(lcb, rx_refresh, media);
|
|
lsm_close_tx(lcb, tx_refresh, media);
|
|
|
|
if (LSMDebug) {
|
|
/* debug is enabled, format the dest addr into string */
|
|
ipaddr2dotted(addr_str, &media->dest_addr);
|
|
for (i = 0; i < media->num_payloads; i++)
|
|
{
|
|
LSM_DEBUG(DEB_L_C_F_PREFIX"%d rx, tx refresh's are %d %d"
|
|
", dir=%d, payload=%d addr=%s, multicast=%d\n",
|
|
DEB_L_C_F_PREFIX_ARGS(LSM, dcb->line,
|
|
dcb->call_id, fname), media->refid, rx_refresh,
|
|
tx_refresh, media->direction,
|
|
media->payloads[i], addr_str, media->is_multicast );
|
|
}
|
|
}
|
|
if (rx_refresh ||
|
|
(media->is_multicast &&
|
|
media->direction_set &&
|
|
media->direction == SDP_DIRECTION_RECVONLY)) {
|
|
lsm_rx_start(lcb, caller_fname, media);
|
|
}
|
|
if (tx_refresh) {
|
|
lsm_tx_start(lcb, caller_fname, media);
|
|
}
|
|
if ( rx_refresh &&
|
|
(media->cap_index == CC_VIDEO_1)) {
|
|
// force an additional update so UI can refresh the remote view
|
|
ui_update_video_avail(dcb->line, lcb->ui_id, dcb->cur_video_avail);
|
|
LSM_DEBUG(DEB_L_C_F_PREFIX"Video Avail Called %d",
|
|
DEB_L_C_F_PREFIX_ARGS(LSM, dcb->line, lcb->ui_id, fname), dcb->cur_video_avail);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
*
|
|
* Function to set media attributes and set the ui state.
|
|
*
|
|
* @param lcb line control block
|
|
* @param line line
|
|
* @param fname caller function name
|
|
*
|
|
* @return none
|
|
*
|
|
* @pre (dcb not_eq NULL)
|
|
* @pre (fname not_eq NULL)
|
|
*/
|
|
static void
|
|
lsm_call_state_media (lsm_lcb_t *lcb, line_t line, const char *fname)
|
|
{
|
|
fsmcnf_ccb_t *ccb;
|
|
fsmdef_dcb_t *dcb;
|
|
call_events call_state;
|
|
callid_t call_id = lcb->call_id;
|
|
|
|
dcb = lcb->dcb;
|
|
if (dcb == NULL) {
|
|
LSM_ERR_MSG(get_debug_string(DEBUG_INPUT_NULL),
|
|
"lsm_call_state_media");
|
|
return;
|
|
}
|
|
|
|
ccb = fsmcnf_get_ccb_by_call_id(call_id);
|
|
|
|
/* Update media parametes to the platform */
|
|
lsm_update_media(lcb, fname);
|
|
|
|
if ((ccb != NULL) && (ccb->active == TRUE)) {
|
|
/* For joined call leg, do not change UI state to conf. */
|
|
if ((ccb->flags & JOINED) ||
|
|
(fname == cc_state_name(CC_STATE_RESUME))) {
|
|
call_state = evConnected;
|
|
} else {
|
|
call_state = evConference;
|
|
}
|
|
} else {
|
|
call_state = evConnected;
|
|
}
|
|
|
|
/*
|
|
* Possible media changes, update call information and followed
|
|
* by the state update. This is important sequence for 7940/60
|
|
* SIP to force the BTXML update.
|
|
*/
|
|
// Commenting out original code for CSCsv72370. Leaving here for reference.
|
|
// lsm_internal_update_call_info(lcb, dcb);
|
|
|
|
lsm_ui_call_state(call_state, line, lcb, CC_CAUSE_NORMAL);
|
|
// CSCsv72370 - Important sequence for TNP this follows state change
|
|
lsm_internal_update_call_info(lcb, dcb);
|
|
}
|
|
|
|
|
|
static cc_rcs_t
|
|
lsm_connected (lsm_lcb_t *lcb, cc_state_data_connected_t *data)
|
|
{
|
|
callid_t call_id = lcb->call_id;
|
|
line_t line = lcb->line;
|
|
fsmdef_dcb_t *dcb;
|
|
int alerting = YES;
|
|
call_events original_call_event;
|
|
int ringSettingBusyStationPolicy;
|
|
boolean tone_stop_bool = TRUE;
|
|
int sdpmode = 0;
|
|
boolean start_ice = FALSE;
|
|
|
|
config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
|
|
|
|
dcb = lcb->dcb;
|
|
if (dcb == NULL) {
|
|
return (CC_RC_ERROR);
|
|
}
|
|
|
|
original_call_event = lcb->previous_call_event;
|
|
/*
|
|
* If a held call is being resumed, check the
|
|
* policy to see if the phone should resume alerting.
|
|
*/
|
|
if (lcb->state == LSM_S_HOLDING) {
|
|
config_get_value(CFGID_RING_SETTING_BUSY_POLICY,
|
|
&ringSettingBusyStationPolicy,
|
|
sizeof(ringSettingBusyStationPolicy));
|
|
if (0 == ringSettingBusyStationPolicy) {
|
|
alerting = NO;
|
|
}
|
|
|
|
/*
|
|
* CSCtd31671: When agent phone resumes from a held call with
|
|
* monitor warning tone, the tone should not be stopped.
|
|
*/
|
|
if(lcb->dcb->active_tone == VCM_MONITORWARNING_TONE || lcb->dcb->active_tone == VCM_RECORDERWARNING_TONE)
|
|
tone_stop_bool = FALSE;
|
|
}
|
|
|
|
/* Don't try to start ICE unless this is the first time connecting.
|
|
* TODO(ekr@rtfm.com): Is this the right ICE start logic? What about restarts
|
|
*/
|
|
if (strlen(dcb->peerconnection) && lcb->state != LSM_S_CONNECTED)
|
|
start_ice = TRUE;
|
|
|
|
lsm_change_state(lcb, __LINE__, LSM_S_CONNECTED);
|
|
|
|
if (!sdpmode) {
|
|
if (tone_stop_bool == TRUE)
|
|
(void) lsm_stop_tone(lcb, NULL);
|
|
}
|
|
|
|
/* Start ICE */
|
|
if (start_ice) {
|
|
short res = vcmStartIceChecks(dcb->peerconnection);
|
|
/* TODO(emannion): Set state to dead here. */
|
|
if (res)
|
|
return CC_RC_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Open the RTP receive channel.
|
|
*/
|
|
lsm_call_state_media(lcb, line, cc_state_name(CC_STATE_CONNECTED));
|
|
|
|
|
|
if (!sdpmode) {
|
|
vcmEnableSidetone(YES);
|
|
|
|
lsm_set_ringer(lcb, call_id, line, alerting);
|
|
}
|
|
|
|
FSM_RESET_FLAGS(lcb->flags, LSM_FLAGS_ANSWER_PENDING);
|
|
FSM_RESET_FLAGS(lcb->flags, LSM_FLAGS_DUSTING);
|
|
|
|
/*
|
|
* update placed call info in call history with dialed digits
|
|
*/
|
|
if (dcb->placed_call_update_required) {
|
|
lsm_update_placed_callinfo(dcb);
|
|
dcb->placed_call_update_required = FALSE;
|
|
}
|
|
|
|
/*
|
|
* If UI state was changed, update status line.
|
|
*/
|
|
if (lcb->previous_call_event != original_call_event) {
|
|
if (lcb->previous_call_event == evConference) {
|
|
} else {
|
|
|
|
ui_set_call_status(platform_get_phrase_index_str(CALL_CONNECTED),
|
|
line, lcb->ui_id);
|
|
}
|
|
}
|
|
ui_update_video_avail(line, lcb->ui_id, dcb->cur_video_avail);
|
|
return (CC_RC_SUCCESS);
|
|
}
|
|
|
|
/**
|
|
* Function: lsm_hold_reversion
|
|
* Perform Hold Reversion on the given call
|
|
* any other call pending then it should play call waiting tone.
|
|
*
|
|
* @param lsm_lcb_t lcb for this call
|
|
*
|
|
* @return cc_rcs_t SUCCESS or FAILURE of the operation
|
|
*
|
|
* @pre (lcb not_eq NULL)
|
|
*/
|
|
|
|
static cc_rcs_t
|
|
lsm_hold_reversion (lsm_lcb_t *lcb)
|
|
{
|
|
callid_t call_id = lcb->call_id;
|
|
line_t line = lcb->line;
|
|
|
|
// Update call state on the JAVA side
|
|
lsm_ui_call_state(evHoldRevert, line, lcb, CC_CAUSE_NORMAL);
|
|
|
|
if (lsm_find_state(LSM_S_RINGIN) > CC_NO_CALL_ID) {
|
|
// No Reversion ringing if we have calls in ringing state
|
|
return CC_RC_SUCCESS;
|
|
}
|
|
ui_set_notification(line, call_id,
|
|
(char *)INDEX_STR_HOLD_REVERSION, CALL_ALERT_TIMEOUT,
|
|
FALSE, HR_NOTIFY_PRI);
|
|
lsm_reversion_ringer(lcb, call_id, line);
|
|
|
|
return (CC_RC_SUCCESS);
|
|
}
|
|
|
|
/*
|
|
* lsm_hold_local
|
|
*
|
|
* Move the phone into the Hold state.
|
|
*
|
|
* Function is used when the local side initiated the hold.
|
|
*/
|
|
static cc_rcs_t
|
|
lsm_hold_local (lsm_lcb_t *lcb, cc_state_data_hold_t *data)
|
|
{
|
|
callid_t call_id = lcb->call_id;
|
|
line_t line = lcb->line;
|
|
fsmdef_dcb_t *dcb;
|
|
cc_causes_t cause;
|
|
int ringSettingBusyStationPolicy;
|
|
|
|
dcb = lcb->dcb;
|
|
if (dcb == NULL) {
|
|
return (CC_RC_ERROR);
|
|
}
|
|
|
|
/*
|
|
* Stop ringer if spoofing ringout for CCM
|
|
*/
|
|
if (dcb->spoof_ringout_applied) {
|
|
(void) lsm_stop_tone(lcb, NULL);
|
|
}
|
|
|
|
/* hard close receive and transmit channels for all media entries */
|
|
lsm_close_rx(lcb, FALSE, NULL);
|
|
lsm_close_tx(lcb, FALSE, NULL);
|
|
/*
|
|
* Note that local hold does not have any newer UI information from the
|
|
* network. Note need to update the call information and the UI will
|
|
* be collapsed with "blocked" icon to indicate hold.
|
|
*/
|
|
|
|
lsm_change_state(lcb, __LINE__, LSM_S_HOLDING);
|
|
/* Round table phones need cause for the transfer or conference
|
|
Do not set the cause if the conference or transfer is created by
|
|
remote-cc
|
|
*/
|
|
cause = CC_CAUSE_NORMAL;
|
|
if (data->reason == CC_REASON_XFER) {
|
|
cause = CC_CAUSE_XFER_LOCAL;
|
|
} else if (data->reason == CC_REASON_CONF) {
|
|
cause = CC_CAUSE_CONF;
|
|
}
|
|
|
|
lsm_ui_call_state(evHold, line, lcb, cause);
|
|
|
|
ui_set_call_status(platform_get_phrase_index_str(CALL_INITIATE_HOLD),
|
|
line, lcb->ui_id);
|
|
|
|
config_get_value(CFGID_RING_SETTING_BUSY_POLICY,
|
|
&ringSettingBusyStationPolicy,
|
|
sizeof(ringSettingBusyStationPolicy));
|
|
if (ringSettingBusyStationPolicy) {
|
|
lsm_set_ringer(lcb, call_id, line, YES);
|
|
} else {
|
|
/*
|
|
* If the hold reason is internal this means the phone logic is placing
|
|
* a call on hold, not the user. Thus don't update the alerting for the
|
|
* hold state as the user should not hear the alerting pattern change
|
|
* as they did not place the call on hold. The phone places calls on hold
|
|
* in cases such as the phone has an active call, another call comes in
|
|
* for that line and the new call is answered. Therefore the phone places the
|
|
* active call on hold before answering the incoming call.
|
|
*
|
|
*/
|
|
if (data->reason == CC_REASON_INTERNAL) {
|
|
lsm_set_ringer(lcb, call_id, line, NO);
|
|
} else {
|
|
lsm_set_ringer(lcb, call_id, line, YES);
|
|
}
|
|
}
|
|
|
|
vcmActivateWlan(FALSE);
|
|
|
|
return (CC_RC_SUCCESS);
|
|
}
|
|
|
|
|
|
/*
|
|
* lsm_hold_remote
|
|
*
|
|
* Move the phone into the Hold state.
|
|
*
|
|
* Function is used when the remote side initiated the hold.
|
|
*/
|
|
static cc_rcs_t
|
|
lsm_hold_remote (lsm_lcb_t *lcb, cc_state_data_hold_t *data)
|
|
{
|
|
static const char fname[] = "lsm_hold_remote";
|
|
callid_t call_id = lcb->call_id;
|
|
line_t line = lcb->line;
|
|
const char *prompt_status;
|
|
fsmdef_dcb_t *dcb;
|
|
fsmdef_media_t *media;
|
|
|
|
dcb = lcb->dcb;
|
|
if (dcb == NULL) {
|
|
return (CC_RC_ERROR);
|
|
}
|
|
|
|
/* close and re-open receive channel for all media entries */
|
|
GSMSDP_FOR_ALL_MEDIA(media, dcb) {
|
|
if (!GSMSDP_MEDIA_ENABLED(media)) {
|
|
/* this entry is not active */
|
|
continue;
|
|
}
|
|
if (media->direction_set &&
|
|
media->direction == SDP_DIRECTION_INACTIVE) {
|
|
lsm_close_rx(lcb, FALSE, media);
|
|
} else {
|
|
lsm_close_rx(lcb, TRUE, media);
|
|
}
|
|
|
|
/* reopen the receive channel if the direction is RECVONLY */
|
|
if (media->direction_set &&
|
|
media->direction == SDP_DIRECTION_RECVONLY) {
|
|
lsm_rx_start(lcb, fname, media);
|
|
}
|
|
/* close tx if media is not inactive or receive only */
|
|
if ((media->direction == SDP_DIRECTION_INACTIVE) ||
|
|
(media->direction == SDP_DIRECTION_RECVONLY)) {
|
|
lsm_close_tx(lcb, FALSE, media);
|
|
}
|
|
}
|
|
|
|
lsm_internal_update_call_info(lcb, dcb);
|
|
|
|
lsm_ui_call_state(evRemHold, line, lcb, CC_CAUSE_NORMAL);
|
|
|
|
prompt_status = ((lcb->state == LSM_S_CONNECTED) ?
|
|
platform_get_phrase_index_str(CALL_CONNECTED) :
|
|
platform_get_phrase_index_str(CALL_INITIATE_HOLD));
|
|
ui_set_call_status(prompt_status, line, lcb->ui_id);
|
|
|
|
lsm_set_ringer(lcb, call_id, line, YES);
|
|
|
|
|
|
return (CC_RC_SUCCESS);
|
|
}
|
|
|
|
|
|
static cc_rcs_t
|
|
lsm_hold (lsm_lcb_t *lcb, cc_state_data_hold_t *data)
|
|
{
|
|
cc_rcs_t cc_rc;
|
|
|
|
if (data == NULL) {
|
|
return (CC_RC_ERROR);
|
|
}
|
|
|
|
LSM_DEBUG(get_debug_string(LSM_DBG_INT1), lcb->call_id, lcb->line,
|
|
"lsm_hold", "local", data->local);
|
|
|
|
switch (data->local) {
|
|
case (TRUE):
|
|
cc_rc = lsm_hold_local(lcb, data);
|
|
break;
|
|
|
|
case (FALSE):
|
|
cc_rc = lsm_hold_remote(lcb, data);
|
|
break;
|
|
|
|
default:
|
|
cc_rc = CC_RC_ERROR;
|
|
break;
|
|
}
|
|
vcmEnableSidetone(NO);
|
|
return (cc_rc);
|
|
}
|
|
|
|
|
|
static cc_rcs_t
|
|
lsm_resume_local (lsm_lcb_t *lcb, cc_state_data_resume_t *data)
|
|
{
|
|
line_t line = lcb->line;
|
|
fsmdef_dcb_t *dcb;
|
|
|
|
lsm_change_state(lcb, __LINE__, LSM_S_HOLDING);
|
|
|
|
dcb = lcb->dcb;
|
|
if (dcb == NULL) {
|
|
return (CC_RC_ERROR);
|
|
}
|
|
|
|
ui_set_call_status(platform_get_phrase_index_str(CALL_CONNECTED),
|
|
line, lcb->ui_id);
|
|
|
|
return (CC_RC_SUCCESS);
|
|
}
|
|
|
|
|
|
static cc_rcs_t
|
|
lsm_resume_remote (lsm_lcb_t *lcb, cc_state_data_resume_t *data)
|
|
{
|
|
callid_t call_id = lcb->call_id;
|
|
line_t line = lcb->line;
|
|
const char *prompt_status;
|
|
|
|
if (lcb->dcb == NULL) {
|
|
return (CC_RC_ERROR);
|
|
}
|
|
|
|
lsm_update_media(lcb, cc_state_name(CC_STATE_RESUME));
|
|
|
|
prompt_status = ((lcb->state == LSM_S_CONNECTED) ?
|
|
platform_get_phrase_index_str(CALL_CONNECTED) :
|
|
platform_get_phrase_index_str(CALL_INITIATE_HOLD));
|
|
ui_set_call_status(prompt_status, line, lcb->ui_id);
|
|
|
|
lsm_set_ringer(lcb, call_id, line, YES);
|
|
|
|
return (CC_RC_SUCCESS);
|
|
}
|
|
|
|
|
|
static cc_rcs_t
|
|
lsm_resume (lsm_lcb_t *lcb, cc_state_data_resume_t *data)
|
|
{
|
|
cc_rcs_t cc_rc;
|
|
|
|
if (data == NULL) {
|
|
return (CC_RC_ERROR);
|
|
}
|
|
|
|
LSM_DEBUG(get_debug_string(LSM_DBG_INT1), lcb->call_id, lcb->line,
|
|
"lsm_resume", "local", data->local);
|
|
|
|
switch (data->local) {
|
|
case (TRUE):
|
|
cc_rc = lsm_resume_local(lcb, data);
|
|
break;
|
|
|
|
case (FALSE):
|
|
cc_rc = lsm_resume_remote(lcb, data);
|
|
break;
|
|
|
|
default:
|
|
cc_rc = CC_RC_ERROR;
|
|
break;
|
|
}
|
|
|
|
vcmActivateWlan(TRUE);
|
|
|
|
vcmEnableSidetone(YES);
|
|
return (cc_rc);
|
|
}
|
|
|
|
|
|
static cc_rcs_t
|
|
lsm_onhook (lsm_lcb_t *lcb, cc_state_data_onhook_t *data)
|
|
{
|
|
callid_t call_id = lcb->call_id;
|
|
line_t line = lcb->line;
|
|
fsmdef_dcb_t *dcb;
|
|
cc_causes_t cause;
|
|
int sdpmode = 0;
|
|
|
|
config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
|
|
|
|
|
|
dcb = lcb->dcb;
|
|
if (dcb == NULL) {
|
|
return (CC_RC_ERROR);
|
|
}
|
|
|
|
dp_int_onhook(line, call_id);
|
|
|
|
/* hard close receive and transmit channels for all media entries */
|
|
lsm_close_rx(lcb, FALSE, NULL);
|
|
lsm_close_tx(lcb, FALSE, NULL);
|
|
|
|
lsm_change_state(lcb, __LINE__, LSM_S_IDLE);
|
|
|
|
if (lsm_is_phone_inactive()) {
|
|
vcmEnableSidetone(NO);
|
|
}
|
|
|
|
ui_set_call_status(ui_get_idle_prompt_string(), line, lcb->ui_id);
|
|
|
|
|
|
(void) lsm_stop_tone(lcb, NULL);
|
|
|
|
if (!sdpmode) {
|
|
vcmControlRinger(VCM_RING_OFF, NO, NO, line, dcb->call_id);
|
|
}
|
|
|
|
lsm_set_ringer(lcb, call_id, line, YES);
|
|
|
|
cause = data->cause;
|
|
if (FSM_CHK_FLAGS(dcb->flags, FSMDEF_F_XFER_COMPLETE)) {
|
|
DEF_DEBUG(DEB_F_PREFIX"Transfer complete.\n", DEB_F_PREFIX_ARGS(LSM, "lsm_onhook"));
|
|
cause = CC_CAUSE_XFER_COMPLETE;
|
|
}
|
|
lsm_ui_call_state(evOnHook, line, lcb, cause);
|
|
|
|
|
|
lsm_free_lcb(lcb);
|
|
|
|
vcmActivateWlan(FALSE);
|
|
|
|
vcmRemoveBandwidth(lsm_get_ms_ui_call_handle(line, call_id, CC_NO_CALL_ID));
|
|
|
|
return (CC_RC_SUCCESS);
|
|
}
|
|
|
|
static cc_rcs_t
|
|
lsm_call_failed (lsm_lcb_t *lcb, cc_state_data_call_failed_t *data)
|
|
{
|
|
callid_t call_id = lcb->call_id;
|
|
line_t line = lcb->line;
|
|
vcm_tones_t tone;
|
|
lsm_states_t line_state;
|
|
const char *status = NULL;
|
|
call_events state;
|
|
boolean send_call_info = TRUE;
|
|
fsmdef_dcb_t *dcb;
|
|
boolean must_log = FALSE;
|
|
|
|
dcb = lcb->dcb;
|
|
if (dcb == NULL) {
|
|
return (CC_RC_ERROR);
|
|
}
|
|
|
|
/* For busy generated by UI-STATE in 183, do not manipulate the
|
|
* media port
|
|
*/
|
|
if (data->cause != CC_CAUSE_UI_STATE_BUSY) {
|
|
/* hard close receive and transmit channels for all media entries */
|
|
lsm_close_rx(lcb, FALSE, NULL);
|
|
lsm_close_tx(lcb, FALSE, NULL);
|
|
}
|
|
|
|
switch (data->cause) {
|
|
case (CC_CAUSE_BUSY):
|
|
line_state = LSM_S_BUSY;
|
|
state = evBusy;
|
|
tone = VCM_LINE_BUSY_TONE;
|
|
status = platform_get_phrase_index_str(LINE_BUSY);
|
|
dp_int_update(line, call_id, data->caller_id.called_number);
|
|
send_call_info = FALSE;
|
|
break;
|
|
|
|
case (CC_CAUSE_UI_STATE_BUSY):
|
|
line_state = LSM_S_BUSY;
|
|
state = evBusy;
|
|
tone = VCM_LINE_BUSY_TONE;
|
|
dp_int_update(line, call_id, data->caller_id.called_number);
|
|
break;
|
|
|
|
case (CC_CAUSE_INVALID_NUMBER):
|
|
line_state = LSM_S_INVALID_NUMBER;
|
|
state = evReorder;
|
|
tone = VCM_REORDER_TONE;
|
|
send_call_info = FALSE;
|
|
break;
|
|
|
|
case (CC_CAUSE_CONGESTION):
|
|
case (CC_CAUSE_PAYLOAD_MISMATCH):
|
|
dp_int_update(line, call_id, data->caller_id.called_number);
|
|
|
|
/* FALLTHROUGH */
|
|
/*sa_ignore FALL_THROUGH*/
|
|
default:
|
|
send_call_info = FALSE;
|
|
line_state = LSM_S_CONGESTION;
|
|
state = evReorder;
|
|
tone = VCM_REORDER_TONE;
|
|
if ( (data->cause == CC_CAUSE_NO_USER_ANS)||
|
|
(data->cause == CC_TEMP_NOT_AVAILABLE) ) {
|
|
must_log = TRUE;
|
|
}
|
|
break;
|
|
}
|
|
|
|
lsm_change_state(lcb, __LINE__, line_state);
|
|
|
|
if (status) {
|
|
ui_set_call_status(status, line, lcb->ui_id);
|
|
}
|
|
|
|
if (state == evReorder && !must_log) {
|
|
ui_log_disposition(dcb->call_id, CC_CALL_LOG_DISP_IGNORE);
|
|
}
|
|
|
|
/* Send call info only if not error */
|
|
if (send_call_info == TRUE) {
|
|
ui_call_info(data->caller_id.calling_name,
|
|
data->caller_id.calling_number,
|
|
data->caller_id.alt_calling_number,
|
|
data->caller_id.display_calling_number,
|
|
data->caller_id.called_name,
|
|
data->caller_id.called_number,
|
|
data->caller_id.display_called_number,
|
|
data->caller_id.orig_called_name,
|
|
data->caller_id.orig_called_number,
|
|
data->caller_id.last_redirect_name,
|
|
data->caller_id.last_redirect_number,
|
|
(calltype_t)dcb->call_type,
|
|
line, lcb->ui_id,
|
|
dcb->caller_id.call_instance_id,
|
|
FSM_GET_SECURITY_STATUS(dcb),
|
|
FSM_GET_POLICY(dcb));
|
|
}
|
|
|
|
lsm_ui_call_state(state, line, lcb, CC_CAUSE_NORMAL);
|
|
|
|
/* Tone played in remote-cc play tone request, so don't start tone again
|
|
*/
|
|
if ((data->cause != CC_CAUSE_UI_STATE_BUSY) && (data->cause != CC_CAUSE_REMOTE_DISCONN_REQ_PLAYTONE)) {
|
|
fsmdef_media_t *audio_media = gsmsdp_find_audio_media(dcb);
|
|
|
|
lsm_util_start_tone(tone, FALSE, lsm_get_ms_ui_call_handle(line, call_id, CC_NO_CALL_ID), dcb->group_id,
|
|
((audio_media != NULL) ? audio_media->refid :
|
|
CC_NO_MEDIA_REF_ID),
|
|
VCM_PLAY_TONE_TO_EAR);
|
|
}
|
|
|
|
return (CC_RC_SUCCESS);
|
|
}
|
|
|
|
static void
|
|
lsm_ringer (lsm_lcb_t *lcb, cc_action_data_ringer_t *data)
|
|
{
|
|
vcm_ring_mode_t ringer;
|
|
line_t line = lcb->line;
|
|
|
|
ringer = (data->on == FALSE) ? (VCM_RING_OFF) : (VCM_FEATURE_RING);
|
|
|
|
LSM_DEBUG(DEB_F_PREFIX"CTI RING SETTING: line = %d, ringer Mode = %s,"
|
|
"Ring once = NO, alertInfo = NO\n", DEB_F_PREFIX_ARGS(LSM, "lsm_ringer"),
|
|
line, vm_alert_names[ringer]);
|
|
|
|
vcmControlRinger(ringer, NO, NO, line, lcb->call_id);
|
|
}
|
|
|
|
static cc_rcs_t
|
|
lsm_dial_mode (lsm_lcb_t *lcb, cc_action_data_dial_mode_t *data)
|
|
{
|
|
return (CC_RC_SUCCESS);
|
|
}
|
|
|
|
|
|
static cc_rcs_t
|
|
lsm_mwi (lsm_lcb_t *lcb, callid_t call_id, line_t line,
|
|
cc_action_data_mwi_t *data)
|
|
{
|
|
ui_set_mwi(line, data->on, data->type, data->newCount, data->oldCount, data->hpNewCount, data->hpOldCount);
|
|
|
|
return (CC_RC_SUCCESS);
|
|
}
|
|
|
|
|
|
/*
|
|
* Function: lsm_update_ui
|
|
*
|
|
* Parameters:
|
|
* call_id:
|
|
* line:
|
|
* data:
|
|
*
|
|
* Description: This function is used to hide the UI platform details from
|
|
* the FSMs. This function is provided to allow the FSMs
|
|
* to update the UI in certain cases.
|
|
*
|
|
* Returns: rc
|
|
*
|
|
*/
|
|
cc_rcs_t
|
|
lsm_update_ui (lsm_lcb_t *lcb, cc_action_data_update_ui_t *data)
|
|
{
|
|
callid_t call_id = lcb->call_id;
|
|
line_t line = lcb->line;
|
|
lsm_states_t instance_state;
|
|
call_events call_state = evMaxEvent;
|
|
fsmcnf_ccb_t *ccb;
|
|
fsmdef_dcb_t *dcb;
|
|
boolean update = FALSE;
|
|
boolean inbound;
|
|
cc_feature_data_call_info_t *call_info;
|
|
call_events original_call_event;
|
|
lsm_lcb_t *lcb_tmp;
|
|
const char *conf_str;//[] = {(char)0x80, (char)0x34, (char)0x00};
|
|
|
|
instance_state = lcb->state;
|
|
|
|
switch (data->action) {
|
|
case CC_UPDATE_CONF_ACTIVE:
|
|
|
|
switch (instance_state) {
|
|
case LSM_S_RINGOUT:
|
|
call_state = evRingOut;
|
|
break;
|
|
|
|
case LSM_S_CONNECTED:
|
|
default:
|
|
ccb = fsmcnf_get_ccb_by_call_id(call_id);
|
|
if ((ccb != NULL) && (ccb->active == TRUE)) {
|
|
|
|
conf_str = platform_get_phrase_index_str(UI_CONFERENCE);
|
|
lcb_tmp = lsm_get_lcb_by_call_id(ccb->cnf_call_id);
|
|
dcb = lcb_tmp->dcb;
|
|
ui_call_info(CALL_INFO_NONE,
|
|
CALL_INFO_NONE,
|
|
CALL_INFO_NONE,
|
|
0,
|
|
conf_str,
|
|
CALL_INFO_NONE,
|
|
0,
|
|
CALL_INFO_NONE,
|
|
CALL_INFO_NONE,
|
|
CALL_INFO_NONE,
|
|
CALL_INFO_NONE,
|
|
FSMDEF_CALL_TYPE_OUTGOING,
|
|
dcb->line, lcb_tmp->ui_id,
|
|
dcb->caller_id.call_instance_id,
|
|
FSM_GET_SECURITY_STATUS(dcb),
|
|
FSM_GET_POLICY(dcb));
|
|
|
|
call_state = evConference;
|
|
|
|
} else if (instance_state == LSM_S_CONNECTED) {
|
|
|
|
call_state = evConnected;
|
|
|
|
} else {
|
|
|
|
call_state = evRingOut;
|
|
}
|
|
break;
|
|
} /* switch (instance_state) { */
|
|
|
|
break;
|
|
|
|
case CC_UPDATE_CALLER_INFO:
|
|
|
|
/* For local conference, do not update the primary
|
|
* call bubbles call-info. Primary call is already
|
|
* displaying To conference in this case
|
|
* But dcb-> caller_id should be updated to
|
|
* refresh the UI when the call is dropped
|
|
*/
|
|
ccb = fsmcnf_get_ccb_by_call_id(call_id);
|
|
if (ccb && (ccb->flags & LCL_CNF) &&
|
|
(ccb->cnf_call_id == call_id)) {
|
|
break;
|
|
}
|
|
|
|
call_info = &data->data.caller_info;
|
|
dcb = lcb->dcb;
|
|
if (dcb == NULL || call_info == NULL) {
|
|
return (CC_RC_ERROR);
|
|
}
|
|
|
|
inbound = dcb->inbound;
|
|
if (call_info->feature_flag & CC_ORIENTATION) {
|
|
inbound =
|
|
(call_info->orientation == CC_ORIENTATION_FROM) ? TRUE : FALSE;
|
|
update = TRUE;
|
|
}
|
|
|
|
if (call_info->feature_flag & CC_CALLER_ID) {
|
|
update = TRUE;
|
|
/*
|
|
* This "if" block, without the "&& inbound" condition, was put in by Serhad
|
|
* to fix CSCsm58054 and it results in CSCso98110. The "inbound" condition
|
|
* is added to narrow the scope of CSCsm58054's fix. Note that "inbound" here
|
|
* refers to the perceived orientation set in call info. So for example, in case
|
|
* of a 3-way conf, and phone is the last party to receive the call, is ringing
|
|
* and then be joined into a conference, direction would be outbound. The display
|
|
* would say "To Conference".
|
|
*/
|
|
if ( (instance_state == LSM_S_RINGIN) && inbound ) {
|
|
cc_state_data_alerting_t alerting_data;
|
|
|
|
alerting_data.caller_id = dcb->caller_id;
|
|
lsm_update_inalert_status(line, lcb->ui_id, &alerting_data, TRUE);
|
|
}
|
|
}
|
|
|
|
if (call_info->feature_flag & CC_CALL_INSTANCE) {
|
|
update = TRUE;
|
|
}
|
|
|
|
if (call_info->feature_flag & CC_SECURITY) {
|
|
update = TRUE;
|
|
}
|
|
|
|
if (call_info->feature_flag & CC_POLICY) {
|
|
update = TRUE;
|
|
}
|
|
|
|
/*
|
|
* If we are going to spoof ring out, skip the explicit UI update.
|
|
* the far end alerting handling will update the UI. Do not
|
|
* update UI twice.
|
|
*/
|
|
if (dcb->spoof_ringout_requested &&
|
|
!dcb->spoof_ringout_applied &&
|
|
lcb->state == LSM_S_CONNECTED) {
|
|
cc_state_data_far_end_alerting_t alerting_data;
|
|
|
|
alerting_data.caller_id = dcb->caller_id;
|
|
(void) lsm_far_end_alerting(lcb, &alerting_data);
|
|
dcb->spoof_ringout_applied = TRUE;
|
|
} else if (update && dcb->ui_update_required) {
|
|
|
|
calltype_t call_type;
|
|
|
|
if (dcb->call_type == FSMDEF_CALL_TYPE_FORWARD) {
|
|
call_type = (inbound) ? (calltype_t)dcb->call_type:FSMDEF_CALL_TYPE_OUTGOING;
|
|
} else {
|
|
if (inbound) {
|
|
call_type = FSMDEF_CALL_TYPE_INCOMING;
|
|
} else {
|
|
call_type = FSMDEF_CALL_TYPE_OUTGOING;
|
|
}
|
|
}
|
|
|
|
ui_call_info(dcb->caller_id.calling_name,
|
|
dcb->caller_id.calling_number,
|
|
dcb->caller_id.alt_calling_number,
|
|
dcb->caller_id.display_calling_number,
|
|
dcb->caller_id.called_name,
|
|
dcb->caller_id.called_number,
|
|
dcb->caller_id.display_called_number,
|
|
dcb->caller_id.orig_called_name,
|
|
dcb->caller_id.orig_called_number,
|
|
dcb->caller_id.last_redirect_name,
|
|
dcb->caller_id.last_redirect_number,
|
|
call_type,
|
|
line,
|
|
lcb->ui_id,
|
|
dcb->caller_id.call_instance_id,
|
|
FSM_GET_SECURITY_STATUS(dcb),
|
|
FSM_GET_POLICY(dcb));
|
|
|
|
dcb->ui_update_required = FALSE;
|
|
|
|
conf_str = platform_get_phrase_index_str(UI_CONFERENCE);
|
|
if(cpr_strncasecmp(dcb->caller_id.called_name, conf_str, strlen(conf_str)) == 0){
|
|
dcb->is_conf_call = TRUE;
|
|
} else {
|
|
dcb->is_conf_call = FALSE;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case CC_UPDATE_SET_CALL_STATUS:
|
|
{
|
|
/* set call status line */
|
|
cc_set_call_status_data_t *call_status_p =
|
|
&data->data.set_call_status_parms;
|
|
ui_set_call_status(call_status_p->phrase_str_p, call_status_p->line,
|
|
lcb->ui_id);
|
|
break;
|
|
}
|
|
case CC_UPDATE_SET_NOTIFICATION:
|
|
{
|
|
/* set status line notification */
|
|
cc_set_notification_data_t *call_notification_p =
|
|
&data->data.set_notification_parms;
|
|
ui_set_notification(line, lcb->ui_id,
|
|
call_notification_p->phrase_str_p,
|
|
call_notification_p->timeout, FALSE,
|
|
(char)call_notification_p->priority);
|
|
break;
|
|
}
|
|
case CC_UPDATE_CLEAR_NOTIFICATION:
|
|
/* clear status line notification */
|
|
ui_clear_notification();
|
|
break;
|
|
|
|
case CC_UPDATE_SECURITY_STATUS:
|
|
/* update security status */
|
|
break;
|
|
|
|
case CC_UPDATE_XFER_PRIMARY:
|
|
call_state = evConnected;
|
|
break;
|
|
|
|
case CC_UPDATE_CALL_PRESERVATION:
|
|
|
|
/* Call is in preservation mode. Update UI so that only endcall softkey is available */
|
|
ui_call_in_preservation(line, lcb->ui_id);
|
|
break;
|
|
|
|
case CC_UPDATE_CALL_CONNECTED:
|
|
if (instance_state == LSM_S_CONNECTED) {
|
|
call_state = evConnected;
|
|
}
|
|
break;
|
|
|
|
case CC_UPDATE_CONF_RELEASE:
|
|
dcb = lcb->dcb;
|
|
|
|
if (instance_state == LSM_S_CONNECTED) {
|
|
call_state = evConnected;
|
|
|
|
} else if (instance_state == LSM_S_RINGOUT) {
|
|
call_state = evRingOut;
|
|
}
|
|
|
|
/*
|
|
* If we are going to spoof ring out, skip the explicit UI update.
|
|
* the far end alerting handling will update the UI. Do not
|
|
* update UI twice.
|
|
*/
|
|
if (dcb->spoof_ringout_requested &&
|
|
!dcb->spoof_ringout_applied &&
|
|
lcb->state == LSM_S_CONNECTED) {
|
|
cc_state_data_far_end_alerting_t alerting_data;
|
|
|
|
alerting_data.caller_id = dcb->caller_id;
|
|
(void) lsm_far_end_alerting(lcb, &alerting_data);
|
|
dcb->spoof_ringout_applied = TRUE;
|
|
|
|
call_state = evRingOut;
|
|
|
|
} else {
|
|
calltype_t call_type;
|
|
if (dcb->orientation == CC_ORIENTATION_FROM) {
|
|
call_type = FSMDEF_CALL_TYPE_INCOMING;
|
|
} else if (dcb->orientation == CC_ORIENTATION_TO) {
|
|
call_type = FSMDEF_CALL_TYPE_OUTGOING;
|
|
} else {
|
|
call_type = (calltype_t)(dcb->call_type);
|
|
}
|
|
ui_call_info(dcb->caller_id.calling_name,
|
|
dcb->caller_id.calling_number,
|
|
dcb->caller_id.alt_calling_number,
|
|
dcb->caller_id.display_calling_number,
|
|
dcb->caller_id.called_name,
|
|
dcb->caller_id.called_number,
|
|
dcb->caller_id.display_called_number,
|
|
dcb->caller_id.orig_called_name,
|
|
dcb->caller_id.orig_called_number,
|
|
dcb->caller_id.last_redirect_name,
|
|
dcb->caller_id.last_redirect_number,
|
|
call_type,
|
|
line,
|
|
lcb->ui_id,
|
|
dcb->caller_id.call_instance_id,
|
|
FSM_GET_SECURITY_STATUS(dcb),
|
|
FSM_GET_POLICY(dcb));
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (call_state != evMaxEvent) {
|
|
original_call_event = lcb->previous_call_event;
|
|
|
|
lsm_ui_call_state(call_state, line, lcb, CC_CAUSE_NORMAL);
|
|
if (original_call_event != call_state) {
|
|
/* Call state changed, take care of special event */
|
|
switch (call_state) {
|
|
case evConference:
|
|
break;
|
|
|
|
case evConnected:
|
|
case evWhisper:
|
|
ui_set_call_status(
|
|
platform_get_phrase_index_str(CALL_CONNECTED),
|
|
line, lcb->ui_id);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return (CC_RC_SUCCESS);
|
|
}
|
|
|
|
|
|
/*
|
|
* Function: lsm_update_placed_callinfo
|
|
*
|
|
* Description: this helps log dialed digits (as opposed to RPID provided
|
|
* value) into placed calls. This also decides whether to
|
|
* log called party name received in RPID.
|
|
*
|
|
* Parameters: dcb - pointer to default SM control block
|
|
*
|
|
* Returns: none
|
|
*
|
|
*/
|
|
#define CISCO_PLAR_STRING "x-cisco-serviceuri-offhook"
|
|
void
|
|
lsm_update_placed_callinfo (void *data)
|
|
{
|
|
const char *tmp_called_number = NULL;
|
|
const char *called_name = NULL;
|
|
fsmdef_dcb_t *dcb = NULL;
|
|
lsm_lcb_t *lcb;
|
|
static const char fname[] = "lsm_update_placed_callinfo";
|
|
boolean has_called_number = FALSE;
|
|
|
|
LSM_DEBUG(DEB_F_PREFIX"Entering ...\n", DEB_F_PREFIX_ARGS(LSM, fname));
|
|
dcb = (fsmdef_dcb_t *) data;
|
|
lcb = lsm_get_lcb_by_call_id(dcb->call_id);
|
|
if (lcb == NULL) {
|
|
LSM_DEBUG(DEB_F_PREFIX"Exiting: lcb not found\n", DEB_F_PREFIX_ARGS(LSM, fname));
|
|
return;
|
|
}
|
|
|
|
if (dcb->caller_id.called_number != NULL &&
|
|
dcb->caller_id.called_number[0] != NUL) {
|
|
has_called_number = TRUE;
|
|
}
|
|
|
|
|
|
tmp_called_number = lsm_get_gdialed_digits();
|
|
|
|
|
|
/* if tmp_called_number is NULL or empty, return */
|
|
if (tmp_called_number == NULL || (*tmp_called_number) == NUL) {
|
|
LSM_DEBUG(DEB_L_C_F_PREFIX"Exiting : dialed digits is empty\n",
|
|
DEB_L_C_F_PREFIX_ARGS(LSM, lcb->line, lcb->call_id, fname));
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* if tmp_called_number is same as what we receive in RPID,
|
|
* then get the called name from RPID if provided.
|
|
*/
|
|
if (has_called_number) {
|
|
if (strcmp(tmp_called_number, CISCO_PLAR_STRING) == 0) {
|
|
tmp_called_number = dcb->caller_id.called_number;
|
|
}
|
|
/* if RPID number matches, dialed digits, use RPID name */
|
|
if (strcmp(dcb->caller_id.called_number, tmp_called_number) == 0) {
|
|
called_name = dcb->caller_id.called_name;
|
|
} else {
|
|
char tmp_str[STATUS_LINE_MAX_LEN];
|
|
platGetPhraseText(STR_INDEX_ANONYMOUS_SPACE, (char *)tmp_str, STATUS_LINE_MAX_LEN - 1);
|
|
if(strcmp(dcb->caller_id.called_number,tmp_str) == 0
|
|
&& strcmp(dcb->caller_id.orig_rpid_number, tmp_called_number) == 0
|
|
&& strcmp(dcb->caller_id.called_name, platform_get_phrase_index_str(UI_UNKNOWN)) != 0) {
|
|
called_name = dcb->caller_id.called_name;
|
|
}
|
|
}
|
|
}
|
|
ui_update_placed_call_info(lcb->line, lcb->call_id, called_name,
|
|
tmp_called_number);
|
|
LSM_DEBUG(DEB_L_C_F_PREFIX"Exiting: invoked ui_update_placed_call_info()\n",
|
|
DEB_L_C_F_PREFIX_ARGS(LSM, lcb->line, lcb->call_id, fname));
|
|
}
|
|
|
|
cc_int32_t
|
|
lsm_show_cmd (cc_int32_t argc, const char *arv[])
|
|
{
|
|
int i = 0;
|
|
lsm_lcb_t *lcb;
|
|
|
|
PR_ASSERT( i == 0 );
|
|
debugif_printf("\n------------------ LSM lcbs -------------------");
|
|
debugif_printf("\ni call_id line state lcb");
|
|
debugif_printf("\n-----------------------------------------------\n");
|
|
|
|
FSM_FOR_ALL_CBS(lcb, lsm_lcbs, LSM_MAX_LCBS) {
|
|
debugif_printf("%-2d %-7d %-4d %-16s 0x%8p\n",
|
|
i++, lcb->call_id, lcb->line,
|
|
lsm_state_name(lcb->state), lcb);
|
|
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
void
|
|
lsm_init_config (void)
|
|
{
|
|
/*
|
|
* The silent period between call waiting bursts is now configurable
|
|
* for TNP phones. Store away the value for the callwaiting code to use.
|
|
* The config is in seconds, but CPR expects the duration in milliseconds
|
|
* thus multiply the config value by 1000. Non-TNP phones default to
|
|
* 10 seconds.
|
|
*/
|
|
config_get_value(CFGID_CALL_WAITING_SILENT_PERIOD, &callWaitingDelay,
|
|
sizeof(callWaitingDelay));
|
|
callWaitingDelay = callWaitingDelay * 1000;
|
|
}
|
|
|
|
void
|
|
lsm_init (void)
|
|
{
|
|
static const char fname[] = "lsm_init";
|
|
lsm_lcb_t *lcb;
|
|
int i;
|
|
|
|
/*
|
|
* Init the lcbs.
|
|
*/
|
|
lsm_lcbs = (lsm_lcb_t *) cpr_calloc(LSM_MAX_LCBS, sizeof(lsm_lcb_t));
|
|
if (lsm_lcbs == NULL) {
|
|
LSM_ERR_MSG(LSM_F_PREFIX"lsm_lcbs cpr_calloc returned NULL\n", fname);
|
|
return;
|
|
}
|
|
|
|
FSM_FOR_ALL_CBS(lcb, lsm_lcbs, LSM_MAX_LCBS) {
|
|
lsm_init_lcb(lcb);
|
|
}
|
|
|
|
/*
|
|
* Create tones and continous tone timer. The same call back function
|
|
* is utilized for each of these timers.
|
|
*/
|
|
lsm_tmr_tones = cprCreateTimer("lsm_tmr_tones",
|
|
GSM_MULTIPART_TONES_TIMER,
|
|
TIMER_EXPIRATION, gsm_msg_queue);
|
|
lsm_continuous_tmr_tones = cprCreateTimer("lsm_continuous_tmr_tones",
|
|
GSM_CONTINUOUS_TONES_TIMER,
|
|
TIMER_EXPIRATION,
|
|
gsm_msg_queue);
|
|
lsm_tone_duration_tmr = cprCreateTimer("lsm_tone_duration_tmr",
|
|
GSM_TONE_DURATION_TIMER,
|
|
TIMER_EXPIRATION, gsm_msg_queue);
|
|
lsm_init_config();
|
|
|
|
for (i=0 ; i<MAX_REG_LINES; i++) {
|
|
lsm_call_perline[i] = 0;
|
|
lsm_mnc_reached[i] = FALSE;
|
|
lsm_bt_reached[i] = FALSE;
|
|
}
|
|
|
|
memset(cfwdall_state_in_ccm_mode, 0, sizeof(cfwdall_state_in_ccm_mode));
|
|
}
|
|
|
|
void
|
|
lsm_shutdown (void)
|
|
{
|
|
(void) cprDestroyTimer(lsm_tmr_tones);
|
|
|
|
(void) cprDestroyTimer(lsm_continuous_tmr_tones);
|
|
|
|
cpr_free(lsm_lcbs);
|
|
}
|
|
|
|
/**
|
|
*
|
|
* Peform reset for lsm, include all the variables that has to be reset
|
|
*
|
|
* @param none
|
|
*
|
|
* @return none
|
|
*
|
|
*/
|
|
void
|
|
lsm_reset (void)
|
|
{
|
|
line_t line;
|
|
int i;
|
|
lsm_lcb_t *lcb;
|
|
|
|
lsm_init_config();
|
|
|
|
FSM_FOR_ALL_CBS(lcb, lsm_lcbs, LSM_MAX_LCBS) {
|
|
lsm_init_lcb(lcb);
|
|
}
|
|
|
|
for (i=0 ; i<MAX_REG_LINES; i++) {
|
|
lsm_call_perline[i] = 0;
|
|
lsm_mnc_reached[i] = FALSE;
|
|
lsm_bt_reached[i] = FALSE;
|
|
}
|
|
|
|
for (line=0; line < MAX_REG_LINES+1; line++) {
|
|
|
|
cc_line_ringer_mode[line] = CC_RING_DEFAULT;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* cc_call_attribute
|
|
* This sets call attribute. During the conf or xfer consultation phase,
|
|
* far end of the 1st call may disconnect the call. In this case phone has to
|
|
* display the regular call softkey set instead of consultation softkey set.
|
|
* For this reason GSM will call cc_call_attribute to the remaining call,
|
|
* when original call is disconnected.
|
|
*/
|
|
void
|
|
cc_call_attribute (callid_t call_id, line_t line, call_attr_t attribute)
|
|
{
|
|
static const char fname[] = "cc_call_attribute";
|
|
|
|
|
|
LSM_DEBUG(DEB_L_C_F_PREFIX"attribute=%d",
|
|
DEB_L_C_F_PREFIX_ARGS(LSM, line, call_id, fname), attribute);
|
|
|
|
ui_set_call_attr(line, call_id, attribute);
|
|
}
|
|
|
|
|
|
/*
|
|
* lsm_call_state
|
|
* This routine is responsible for responding to requests from the CSM and
|
|
* doing whatever is required via platform specific routines.
|
|
*/
|
|
void
|
|
cc_call_state (callid_t call_id, line_t line, cc_states_t state,
|
|
cc_state_data_t *data)
|
|
{
|
|
static const char fname[] = "cc_call_state";
|
|
cc_rcs_t result = CC_RC_SUCCESS;
|
|
lsm_lcb_t *lcb;
|
|
|
|
LSM_DEBUG(get_debug_string(LSM_DBG_ENTRY), call_id, line,
|
|
cc_state_name(state));
|
|
|
|
lcb = lsm_get_lcb_by_call_id(call_id);
|
|
|
|
if (lcb == NULL) {
|
|
LSM_DEBUG(get_debug_string(DEBUG_INPUT_NULL), fname);
|
|
return;
|
|
}
|
|
|
|
switch (state) {
|
|
case CC_STATE_OFFHOOK:
|
|
result = lsm_offhook(lcb, &(data->offhook));
|
|
#ifdef TEST
|
|
test_dial_calls(line, call_id, 500, "10011234");
|
|
#endif
|
|
break;
|
|
|
|
case CC_STATE_DIALING:
|
|
result = lsm_dialing(lcb, &(data->dialing));
|
|
break;
|
|
|
|
case CC_STATE_DIALING_COMPLETED:
|
|
result = lsm_dialing_completed(lcb, &(data->dialing_completed));
|
|
break;
|
|
|
|
case CC_STATE_CALL_SENT:
|
|
result = lsm_call_sent(lcb, &(data->call_sent));
|
|
break;
|
|
|
|
case CC_STATE_FAR_END_PROCEEDING:
|
|
result = lsm_far_end_proceeding(lcb, &(data->far_end_proceeding));
|
|
break;
|
|
|
|
case CC_STATE_FAR_END_ALERTING:
|
|
result = lsm_far_end_alerting(lcb, &(data->far_end_alerting));
|
|
break;
|
|
|
|
case CC_STATE_CALL_RECEIVED:
|
|
result = lsm_call_received(lcb, &(data->call_received));
|
|
break;
|
|
|
|
case CC_STATE_ALERTING:
|
|
result = lsm_alerting(lcb, &(data->alerting));
|
|
break;
|
|
|
|
case CC_STATE_ANSWERED:
|
|
result = lsm_answered(lcb, &(data->answered));
|
|
break;
|
|
|
|
case CC_STATE_CONNECTED:
|
|
result = lsm_connected(lcb, &(data->connected));
|
|
#ifdef TEST
|
|
test_disc_call(line, call_id);
|
|
test_line_offhook(line, cc_get_new_call_id());
|
|
#endif
|
|
break;
|
|
|
|
case CC_STATE_HOLD:
|
|
result = lsm_hold(lcb, &(data->hold));
|
|
break;
|
|
|
|
case CC_STATE_HOLD_REVERT:
|
|
result = lsm_hold_reversion(lcb);
|
|
break;
|
|
|
|
case CC_STATE_RESUME:
|
|
result = lsm_resume(lcb, &(data->resume));
|
|
break;
|
|
|
|
case CC_STATE_ONHOOK:
|
|
result = lsm_onhook(lcb, &(data->onhook));
|
|
break;
|
|
|
|
case CC_STATE_CALL_FAILED:
|
|
result = lsm_call_failed(lcb, &(data->call_failed));
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (result == CC_RC_ERROR) {
|
|
LSM_DEBUG(get_debug_string(LSM_DBG_CC_ERROR), call_id, line, fname,
|
|
state, data);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static cc_rcs_t
|
|
lsm_media (lsm_lcb_t *lcb, callid_t call_id, line_t line)
|
|
{
|
|
fsmdef_dcb_t *dcb;
|
|
|
|
dcb = lcb->dcb;
|
|
if (dcb == NULL) {
|
|
return (CC_RC_ERROR);
|
|
}
|
|
|
|
if (!dcb->spoof_ringout_requested) {
|
|
lsm_update_media(lcb, "MEDIA");
|
|
vcmEnableSidetone(YES);
|
|
} else if (!dcb->spoof_ringout_applied &&
|
|
(lcb->state == LSM_S_CONNECTED)) {
|
|
cc_state_data_far_end_alerting_t alerting_data;
|
|
|
|
alerting_data.caller_id = dcb->caller_id;
|
|
(void) lsm_far_end_alerting(lcb, &alerting_data);
|
|
dcb->spoof_ringout_applied = TRUE;
|
|
}
|
|
|
|
return (CC_RC_SUCCESS);
|
|
}
|
|
|
|
/*
|
|
* Function: lsm_stop_media
|
|
*
|
|
* Parameters:
|
|
* lcb - pointer to lsm_lcb_t,
|
|
* call_id - gsm call id for the call in used.
|
|
* line - line_t for the line number (dn line).
|
|
* data - action data.
|
|
*
|
|
* Description:
|
|
* The function simply stops media (close Rx and Tx) and set the
|
|
* proper ringer.
|
|
*
|
|
* Returns: None.
|
|
*/
|
|
static void
|
|
lsm_stop_media (lsm_lcb_t *lcb, callid_t call_id, line_t line,
|
|
cc_action_data_t *data)
|
|
{
|
|
static const char fname[] = "lsm_stop_media";
|
|
fsmdef_dcb_t *dcb;
|
|
fsmdef_media_t *media;
|
|
|
|
dcb = lcb->dcb;
|
|
if (dcb == NULL) {
|
|
LSM_DEBUG(get_debug_string(DEBUG_INPUT_NULL), fname);
|
|
return;
|
|
}
|
|
|
|
/* hard close receive and transmit channels */
|
|
if ((data == NULL) ||
|
|
(data->stop_media.media_refid == CC_NO_MEDIA_REF_ID)) {
|
|
/* no data provided or no specific ref ID, defaul to all entries */
|
|
lsm_close_rx(lcb, FALSE, NULL);
|
|
lsm_close_tx(lcb, FALSE, NULL);
|
|
} else {
|
|
/* look up the media entry for the given reference ID */
|
|
media = gsmsdp_find_media_by_refid(dcb,
|
|
data->stop_media.media_refid);
|
|
if (media != NULL) {
|
|
lsm_close_rx(lcb, FALSE, media);
|
|
lsm_close_tx(lcb, FALSE, media);
|
|
} else {
|
|
/* no entry found */
|
|
LSM_DEBUG(DEB_L_C_F_PREFIX"no media with reference ID %d found\n",
|
|
DEB_L_C_F_PREFIX_ARGS(LSM, dcb->line, dcb->call_id, fname),
|
|
data->stop_media.media_refid);
|
|
return;
|
|
}
|
|
}
|
|
lsm_set_ringer(lcb, call_id, line, YES);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* lsm_add_remote_stream
|
|
*
|
|
* Description:
|
|
* The function adds a remote stream to the media subsystem
|
|
*
|
|
* Parameters:
|
|
* [in] line - line
|
|
* [in] call_id - GSM call ID
|
|
* [in] media - media line to add as remote stream
|
|
* [out] pc_stream_id
|
|
* Returns: None
|
|
*/
|
|
void lsm_add_remote_stream (line_t line, callid_t call_id, fsmdef_media_t *media, int *pc_stream_id)
|
|
{
|
|
static const char fname[] = "lsm_add_remote_stream";
|
|
fsmdef_dcb_t *dcb;
|
|
lsm_lcb_t *lcb;
|
|
|
|
lcb = lsm_get_lcb_by_call_id(call_id);
|
|
if (lcb != NULL) {
|
|
dcb = lcb->dcb;
|
|
if (dcb == NULL) {
|
|
LSM_ERR_MSG(get_debug_string(DEBUG_INPUT_NULL), fname);
|
|
return;
|
|
}
|
|
|
|
vcmCreateRemoteStream(media->cap_index, dcb->peerconnection,
|
|
pc_stream_id);
|
|
|
|
}
|
|
}
|
|
|
|
/*
|
|
* lsm_data_channel_negotiated
|
|
*
|
|
* Description:
|
|
* The function informs the API of a negotiated data channel m= line
|
|
*
|
|
* Parameters:
|
|
* [in] line - line
|
|
* [in] call_id - GSM call ID
|
|
* [in] media - media line to add as remote stream
|
|
* [out] pc_stream_id
|
|
* Returns: None
|
|
*/
|
|
void lsm_data_channel_negotiated (line_t line, callid_t call_id, fsmdef_media_t *media, int *pc_stream_id)
|
|
{
|
|
static const char fname[] = "lsm_data_channel_negotiated";
|
|
fsmdef_dcb_t *dcb;
|
|
lsm_lcb_t *lcb;
|
|
|
|
lcb = lsm_get_lcb_by_call_id(call_id);
|
|
if (lcb) {
|
|
dcb = lcb->dcb;
|
|
if (dcb == NULL) {
|
|
LSM_ERR_MSG(get_debug_string(DEBUG_INPUT_NULL), fname);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* have access to media->streams, media->protocol, media->sctp_port
|
|
* vcmSetDataChannelParameters may need renaming TODO: jesup
|
|
*/
|
|
|
|
vcmSetDataChannelParameters(dcb->peerconnection, media->streams, media->sctp_port, media->protocol);
|
|
|
|
}
|
|
}
|
|
|
|
/**
|
|
*
|
|
* Peform non call related action
|
|
*
|
|
* @param line_t line
|
|
* @param callid_t gsm_id
|
|
* @param action type of action
|
|
* @param cc_action_data_t line
|
|
*
|
|
* @return true if the action has been peformed, else false
|
|
*
|
|
* @pre (action == CC_ACTION_MWI_LAMP_ONLY || CC_ACTION_SET_LINE_RINGER ||
|
|
CC_ACTION_PLAY_BLF_ALERTING_TONE)
|
|
*/
|
|
static boolean
|
|
cc_call_non_call_action (callid_t call_id, line_t line,
|
|
cc_actions_t action, cc_action_data_t *data)
|
|
{
|
|
/* Certain requests are device based and does not contain any
|
|
* line number and call_id associated with it. So handle thoese
|
|
* requests here
|
|
*/
|
|
switch (action) {
|
|
|
|
case CC_ACTION_MWI_LAMP_ONLY:
|
|
if (data != NULL) {
|
|
ui_change_mwi_lamp(data->mwi.on);
|
|
return(TRUE);
|
|
}
|
|
break;
|
|
|
|
case CC_ACTION_SET_LINE_RINGER:
|
|
|
|
if (data != NULL) {
|
|
return(TRUE);
|
|
}
|
|
break;
|
|
|
|
case CC_ACTION_PLAY_BLF_ALERTING_TONE:
|
|
lsm_play_tone(CC_FEATURE_BLF_ALERT_TONE);
|
|
return TRUE;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
/*
|
|
* LSM API supports various actions such as play tone, stop tone,
|
|
* direct media operation etc.
|
|
*
|
|
* @param[in] call_id GSM call ID of an active call.
|
|
* @param[in] line line number of the line_t type.
|
|
* @param[in] action cc_actions_t for the desired action.
|
|
* @param[in] data cc_action_data_t data or parameters that may be
|
|
* required for certain action.
|
|
*
|
|
* @return cc_rcs_t status.
|
|
*
|
|
* @pre line not_eqs CC_NO_LINE
|
|
* @pre ((action equals CC_ACTION_PLAY_TONE) or
|
|
* (action equals CC_ACTION_STOP_TONE) or
|
|
* (action equals CC_ACTION_DIAL_MODE) or
|
|
* (action equals CC_ACTION_MWI) or
|
|
* (action equals CC_ACTION_OPEN_RCV) or
|
|
* (action equals CC_ACTION_UPDATE_UI) or
|
|
* (action equals CC_ACTION_RINGER))
|
|
*/
|
|
cc_rcs_t
|
|
cc_call_action (callid_t call_id, line_t line, cc_actions_t action,
|
|
cc_action_data_t *data)
|
|
{
|
|
static const char fname[] = "cc_call_action";
|
|
cc_rcs_t result = CC_RC_SUCCESS;
|
|
lsm_lcb_t *lcb;
|
|
fsmdef_dcb_t *dcb;
|
|
fsmdef_media_t *media;
|
|
|
|
LSM_DEBUG(get_debug_string(LSM_DBG_ENTRY), call_id, line,
|
|
cc_action_name(action));
|
|
|
|
/* perform non call related actions. lcb is not required
|
|
* for these actions
|
|
*/
|
|
if (cc_call_non_call_action(call_id, line, action, data)) {
|
|
return (result);
|
|
}
|
|
|
|
lcb = lsm_get_lcb_by_call_id(call_id);
|
|
|
|
if ((lcb == NULL) && (action != CC_ACTION_MWI)) {
|
|
LSM_DEBUG(get_debug_string(DEBUG_INPUT_NULL), fname);
|
|
return (CC_RC_ERROR);
|
|
}
|
|
|
|
switch (action) {
|
|
case CC_ACTION_PLAY_TONE:
|
|
if (data != NULL) {
|
|
result = lsm_start_tone(lcb, &(data->tone));
|
|
} else {
|
|
result = CC_RC_ERROR;
|
|
}
|
|
break;
|
|
|
|
case CC_ACTION_STOP_TONE:
|
|
if (data != NULL) {
|
|
result = lsm_stop_tone(lcb, &(data->tone));
|
|
} else {
|
|
result = CC_RC_ERROR;
|
|
}
|
|
break;
|
|
|
|
case CC_ACTION_SPEAKER:
|
|
break;
|
|
|
|
case CC_ACTION_DIAL_MODE:
|
|
if (data != NULL) {
|
|
result = lsm_dial_mode(lcb, &(data->dial_mode));
|
|
} else {
|
|
result = CC_RC_ERROR;
|
|
}
|
|
break;
|
|
|
|
case CC_ACTION_MWI:
|
|
if (data != NULL) {
|
|
result = lsm_mwi(NULL, call_id, line, &(data->mwi));
|
|
} else {
|
|
result = CC_RC_ERROR;
|
|
}
|
|
break;
|
|
|
|
case CC_ACTION_OPEN_RCV:
|
|
if (data != NULL) {
|
|
result = lsm_open_rx(lcb, &(data->open_rcv), NULL);
|
|
} else {
|
|
result = CC_RC_ERROR;
|
|
}
|
|
break;
|
|
|
|
case CC_ACTION_UPDATE_UI:
|
|
if (data != NULL) {
|
|
result = lsm_update_ui(lcb, &(data->update_ui));
|
|
} else {
|
|
result = CC_RC_ERROR;
|
|
}
|
|
break;
|
|
|
|
case CC_ACTION_MEDIA:
|
|
result = lsm_media(lcb, call_id, line);
|
|
break;
|
|
|
|
case CC_ACTION_RINGER:
|
|
if (data != NULL) {
|
|
lsm_ringer(lcb, &(data->ringer));
|
|
}
|
|
break;
|
|
|
|
case CC_ACTION_STOP_MEDIA:
|
|
lsm_stop_media(lcb, call_id, line, data);
|
|
break;
|
|
|
|
case CC_ACTION_START_RCV:
|
|
/* start receiving */
|
|
dcb = lcb->dcb;
|
|
if (dcb == NULL) {
|
|
/* No call ID */
|
|
result = CC_RC_ERROR;
|
|
break;
|
|
}
|
|
|
|
GSMSDP_FOR_ALL_MEDIA(media, dcb) {
|
|
if (!GSMSDP_MEDIA_ENABLED(media)) {
|
|
/* this entry is not active */
|
|
continue;
|
|
}
|
|
|
|
/* only support starting all receive channels for now */
|
|
lsm_rx_start(lcb, fname, media);
|
|
}
|
|
break;
|
|
|
|
case CC_ACTION_ANSWER_PENDING:
|
|
FSM_SET_FLAGS(lcb->flags, LSM_FLAGS_ANSWER_PENDING);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
|
|
if (result == CC_RC_ERROR) {
|
|
LSM_DEBUG(get_debug_string(LSM_DBG_CC_ERROR), call_id, line, fname,
|
|
action, data);
|
|
}
|
|
|
|
return (result);
|
|
}
|
|
|
|
|
|
void
|
|
lsm_ui_display_notify (const char *notify_str, unsigned long timeout)
|
|
{
|
|
/*
|
|
* add 0 as (default) priority; it is don't care in legacy mode
|
|
*/
|
|
ui_set_notification(CC_NO_LINE, CC_NO_CALL_ID,
|
|
(char *)notify_str, (int)timeout, FALSE,
|
|
DEF_NOTIFY_PRI);
|
|
}
|
|
|
|
void
|
|
lsm_ui_display_status (const char *status_str, line_t line, callid_t call_id)
|
|
{
|
|
lsm_lcb_t *lcb;
|
|
|
|
if (call_id == CC_NO_CALL_ID) {
|
|
/* Invalid call id */
|
|
return;
|
|
}
|
|
lcb = lsm_get_lcb_by_call_id(call_id);
|
|
if (lcb == NULL) {
|
|
return;
|
|
}
|
|
|
|
ui_set_call_status((char *) status_str, line, lcb->ui_id);
|
|
}
|
|
|
|
/**
|
|
* This function will display notification status line.
|
|
*
|
|
* @param[in] str_index - index into phrase dictionary
|
|
*
|
|
* @return none
|
|
*/
|
|
void lsm_ui_display_notify_str_index (int str_index)
|
|
{
|
|
char tmp_str[STATUS_LINE_MAX_LEN];
|
|
|
|
if ((platGetPhraseText(str_index,
|
|
(char *)tmp_str,
|
|
(STATUS_LINE_MAX_LEN - 1))) == CPR_SUCCESS) {
|
|
lsm_ui_display_notify(tmp_str, NO_FREE_LINES_TIMEOUT);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Function: lsm_parse_displaystr
|
|
*
|
|
* Parameters:string to be parsed
|
|
*
|
|
* Description:Wrapper function for parsing string to be displayed
|
|
*
|
|
* Returns: Pointer to parsed number
|
|
*
|
|
*/
|
|
string_t
|
|
lsm_parse_displaystr (string_t displaystr)
|
|
{
|
|
return (sippmh_parse_displaystr(displaystr));
|
|
}
|
|
|
|
void
|
|
lsm_speaker_mode (short mode)
|
|
{
|
|
ui_set_speaker_mode((boolean)mode);
|
|
}
|
|
|
|
/*
|
|
* Function:lsm_update_active_tone
|
|
*
|
|
* Parameters:
|
|
* tone - tone type
|
|
* call_id - call identifier
|
|
*
|
|
* Description: Update dcb->active_tone if starting infinite duration tone.
|
|
*
|
|
* Returns:none
|
|
*
|
|
*/
|
|
void
|
|
lsm_update_active_tone (vcm_tones_t tone, callid_t call_id)
|
|
{
|
|
static const char fname[] = "lsm_update_active_tone";
|
|
fsmdef_dcb_t *dcb;
|
|
|
|
/* if tone is any of following then set active_tone in dcb b/c these
|
|
* tones have infinite duration and need to be stopped. Other tones
|
|
* only play for a finite/short duration so no need to stop them as
|
|
* they will stop automatically.
|
|
*/
|
|
switch (tone) {
|
|
/* for all tones with infinite playing duration */
|
|
case VCM_INSIDE_DIAL_TONE:
|
|
case VCM_LINE_BUSY_TONE:
|
|
case VCM_ALERTING_TONE:
|
|
case VCM_STUTTER_TONE:
|
|
case VCM_REORDER_TONE:
|
|
case VCM_OUTSIDE_DIAL_TONE:
|
|
case VCM_PERMANENT_SIGNAL_TONE:
|
|
case VCM_RECORDERWARNING_TONE:
|
|
case VCM_MONITORWARNING_TONE:
|
|
dcb = fsmdef_get_dcb_by_call_id(call_id);
|
|
|
|
if (dcb == NULL) {
|
|
/* Possibibly the ui_id was passed in and the dcb is no longer existed.
|
|
* Try to retrieve the corresponding dcb.
|
|
*/
|
|
dcb = fsmdef_get_dcb_by_call_id(lsm_get_callid_from_ui_id(call_id));
|
|
}
|
|
|
|
if (dcb != NULL) {
|
|
/* Ideally a call should not make a infinite tone start request
|
|
* (without making a stop request) while there is already one playing.
|
|
* However, DSP will start playing the new request tone by overriding
|
|
* the current one. Technically its okay. So, just printing a log msg.
|
|
*/
|
|
if (dcb->active_tone != VCM_NO_TONE) {
|
|
LSM_DEBUG(DEB_L_C_F_PREFIX"Active Tone current = %d new = %d\n",
|
|
DEB_L_C_F_PREFIX_ARGS(LSM, dcb->line, call_id, fname),
|
|
dcb->active_tone, tone);
|
|
}
|
|
dcb->active_tone = tone;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
/* do nothing */
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Function: lsm_is_tx_channel_opened
|
|
*
|
|
* Parameters: call_id
|
|
*
|
|
* Description: check to see tx channel is openned
|
|
*
|
|
* Returns: TRUE or FALSE
|
|
*
|
|
*/
|
|
boolean
|
|
lsm_is_tx_channel_opened(callid_t call_id)
|
|
{
|
|
fsmdef_dcb_t *dcb_p = fsmdef_get_dcb_by_call_id(call_id);
|
|
fsmdef_media_t *media = NULL;
|
|
|
|
if (dcb_p == NULL) {
|
|
return (FALSE);
|
|
}
|
|
|
|
/*
|
|
* search the all entries that has a valid media and matches
|
|
* SDP_MEDIA_AUDIO type.
|
|
*/
|
|
GSMSDP_FOR_ALL_MEDIA(media, dcb_p) {
|
|
if (media->type == SDP_MEDIA_AUDIO) {
|
|
/* found a match */
|
|
if (media->xmit_chan)
|
|
return (TRUE);
|
|
}
|
|
}
|
|
return (FALSE);
|
|
}
|
|
|
|
/*
|
|
* Function:lsm_update_monrec_tone_action
|
|
*
|
|
* Parameters:
|
|
* tone - tone type
|
|
* call_id - call identifier
|
|
*
|
|
* Description: Update dcb->monrec_tone_action.
|
|
*
|
|
* Returns:none
|
|
*
|
|
*/
|
|
void
|
|
lsm_update_monrec_tone_action (vcm_tones_t tone, callid_t call_id, uint16_t direction)
|
|
{
|
|
static const char fname[] = "lsm_update_monrec_tone_action";
|
|
fsmdef_dcb_t *dcb;
|
|
boolean tx_opened = lsm_is_tx_channel_opened(call_id);
|
|
|
|
dcb = fsmdef_get_dcb_by_call_id(call_id);
|
|
|
|
if (dcb != NULL) {
|
|
switch(tone) {
|
|
case VCM_MONITORWARNING_TONE:
|
|
switch (dcb->monrec_tone_action) {
|
|
case FSMDEF_MRTONE_NO_ACTION:
|
|
if (!tx_opened) {
|
|
dcb->monrec_tone_action = FSMDEF_MRTONE_RESUME_MONITOR_TONE;
|
|
} else {
|
|
dcb->monrec_tone_action = FSMDEF_MRTONE_PLAYED_MONITOR_TONE;
|
|
}
|
|
break;
|
|
|
|
case FSMDEF_MRTONE_PLAYED_RECORDER_TONE:
|
|
dcb->monrec_tone_action = FSMDEF_MRTONE_PLAYED_BOTH_TONES;
|
|
break;
|
|
|
|
case FSMDEF_MRTONE_RESUME_RECORDER_TONE:
|
|
dcb->monrec_tone_action = FSMDEF_MRTONE_RESUME_BOTH_TONES;
|
|
break;
|
|
|
|
case FSMDEF_MRTONE_PLAYED_MONITOR_TONE:
|
|
case FSMDEF_MRTONE_PLAYED_BOTH_TONES:
|
|
case FSMDEF_MRTONE_RESUME_MONITOR_TONE:
|
|
case FSMDEF_MRTONE_RESUME_BOTH_TONES:
|
|
default:
|
|
DEF_DEBUG(DEB_F_PREFIX"Invalid action request... tone:%d monrec_tone_action:%d \n",
|
|
DEB_F_PREFIX_ARGS("RCC", fname), tone, dcb->monrec_tone_action);
|
|
break;
|
|
}
|
|
dcb->monitor_tone_direction = direction;
|
|
break;
|
|
|
|
case VCM_RECORDERWARNING_TONE:
|
|
switch (dcb->monrec_tone_action) {
|
|
case FSMDEF_MRTONE_NO_ACTION:
|
|
if (!tx_opened) {
|
|
dcb->monrec_tone_action = FSMDEF_MRTONE_RESUME_RECORDER_TONE;
|
|
} else {
|
|
dcb->monrec_tone_action = FSMDEF_MRTONE_PLAYED_RECORDER_TONE;
|
|
}
|
|
break;
|
|
|
|
case FSMDEF_MRTONE_PLAYED_MONITOR_TONE:
|
|
dcb->monrec_tone_action = FSMDEF_MRTONE_PLAYED_BOTH_TONES;
|
|
break;
|
|
|
|
case FSMDEF_MRTONE_RESUME_MONITOR_TONE:
|
|
dcb->monrec_tone_action = FSMDEF_MRTONE_RESUME_BOTH_TONES;
|
|
break;
|
|
|
|
case FSMDEF_MRTONE_PLAYED_RECORDER_TONE:
|
|
case FSMDEF_MRTONE_PLAYED_BOTH_TONES:
|
|
case FSMDEF_MRTONE_RESUME_RECORDER_TONE:
|
|
case FSMDEF_MRTONE_RESUME_BOTH_TONES:
|
|
default:
|
|
DEF_DEBUG(DEB_F_PREFIX"Invalid action request... tone:%d monrec_tone_action:%d \n",
|
|
DEB_F_PREFIX_ARGS("RCC", fname), tone, dcb->monrec_tone_action);
|
|
break;
|
|
}
|
|
dcb->recorder_tone_direction = direction;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
} /* end of switch */
|
|
|
|
LSM_DEBUG(DEB_L_C_F_PREFIX"Start request for tone: %d. Set monrec_tone_action: %d\n",
|
|
DEB_L_C_F_PREFIX_ARGS(LSM, dcb->line, call_id, fname),
|
|
tone, dcb->monrec_tone_action);
|
|
|
|
} /* end of if */
|
|
}
|
|
|
|
/*
|
|
* Function:lsm_downgrade_monrec_tone_action
|
|
*
|
|
* Parameters:
|
|
* tone - tone type
|
|
* call_id - call identifier
|
|
*
|
|
* Description: Update dcb->monrec_tone_action.
|
|
*
|
|
* Returns:none
|
|
*
|
|
*/
|
|
void
|
|
lsm_downgrade_monrec_tone_action (vcm_tones_t tone, callid_t call_id)
|
|
{
|
|
static const char fname[] = "lsm_downgrade_monrec_tone_action";
|
|
fsmdef_dcb_t *dcb;
|
|
|
|
dcb = fsmdef_get_dcb_by_call_id(call_id);
|
|
|
|
/* Need to downgrade the monrec_tone_action */
|
|
|
|
if (dcb != NULL) {
|
|
switch (tone){
|
|
case VCM_MONITORWARNING_TONE:
|
|
switch (dcb->monrec_tone_action) {
|
|
case FSMDEF_MRTONE_PLAYED_MONITOR_TONE:
|
|
case FSMDEF_MRTONE_RESUME_MONITOR_TONE:
|
|
dcb->monrec_tone_action = FSMDEF_MRTONE_NO_ACTION;
|
|
break;
|
|
|
|
case FSMDEF_MRTONE_RESUME_BOTH_TONES:
|
|
dcb->monrec_tone_action = FSMDEF_MRTONE_RESUME_RECORDER_TONE;
|
|
break;
|
|
|
|
case FSMDEF_MRTONE_PLAYED_BOTH_TONES:
|
|
dcb->monrec_tone_action = FSMDEF_MRTONE_PLAYED_RECORDER_TONE;
|
|
break;
|
|
|
|
case FSMDEF_MRTONE_NO_ACTION:
|
|
case FSMDEF_MRTONE_PLAYED_RECORDER_TONE:
|
|
case FSMDEF_MRTONE_RESUME_RECORDER_TONE:
|
|
default:
|
|
DEF_DEBUG(DEB_F_PREFIX"Invalid action request... tone:%d monrec_tone_action:%d \n",
|
|
DEB_F_PREFIX_ARGS("RCC", fname), tone, dcb->monrec_tone_action);
|
|
break;
|
|
}
|
|
dcb->monitor_tone_direction = VCM_PLAY_TONE_TO_EAR;
|
|
break;
|
|
|
|
case VCM_RECORDERWARNING_TONE:
|
|
switch (dcb->monrec_tone_action) {
|
|
case FSMDEF_MRTONE_PLAYED_RECORDER_TONE:
|
|
case FSMDEF_MRTONE_RESUME_RECORDER_TONE:
|
|
dcb->monrec_tone_action = FSMDEF_MRTONE_NO_ACTION;
|
|
break;
|
|
|
|
case FSMDEF_MRTONE_RESUME_BOTH_TONES:
|
|
dcb->monrec_tone_action = FSMDEF_MRTONE_RESUME_MONITOR_TONE;
|
|
break;
|
|
|
|
case FSMDEF_MRTONE_PLAYED_BOTH_TONES:
|
|
dcb->monrec_tone_action = FSMDEF_MRTONE_PLAYED_MONITOR_TONE;
|
|
break;
|
|
|
|
case FSMDEF_MRTONE_NO_ACTION:
|
|
case FSMDEF_MRTONE_PLAYED_MONITOR_TONE:
|
|
case FSMDEF_MRTONE_RESUME_MONITOR_TONE:
|
|
default:
|
|
DEF_DEBUG(DEB_F_PREFIX"Invalid action request... tone:%d monrec_tone_action:%d \n",
|
|
DEB_F_PREFIX_ARGS("RCC", fname), tone, dcb->monrec_tone_action);
|
|
break;
|
|
}
|
|
dcb->recorder_tone_direction = VCM_PLAY_TONE_TO_EAR;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
} /* end of switch */
|
|
|
|
LSM_DEBUG(DEB_L_C_F_PREFIX"Stop request for tone: %d Downgrade monrec_tone_action: %d \n",
|
|
DEB_L_C_F_PREFIX_ARGS(LSM, dcb->line, call_id, fname),
|
|
tone, dcb->monrec_tone_action);
|
|
} /* end of if */
|
|
}
|
|
|
|
/*
|
|
* Function: lsm_set_hold_ringback_status
|
|
*
|
|
* Parameters:
|
|
* callid_t - callid of the lcb
|
|
* ringback_status - status of call hold ringback
|
|
*
|
|
* Description: Function used to set the ringback status
|
|
*
|
|
* Returns:None
|
|
*
|
|
*/
|
|
void
|
|
lsm_set_hold_ringback_status(callid_t call_id, boolean ringback_status)
|
|
{
|
|
lsm_lcb_t *lcb;
|
|
|
|
FSM_FOR_ALL_CBS(lcb, lsm_lcbs, LSM_MAX_LCBS) {
|
|
if (lcb->call_id == call_id) {
|
|
LSM_DEBUG(DEB_F_PREFIX"Setting ringback to %d for lcb %d\n",
|
|
DEB_F_PREFIX_ARGS(LSM, "lsm_set_hold_ringback_status"), ringback_status, call_id);
|
|
lcb->enable_ringback = ringback_status;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void lsm_play_tone (cc_features_t feature_id)
|
|
{
|
|
int play_tone;
|
|
|
|
switch (feature_id) {
|
|
case CC_FEATURE_BLF_ALERT_TONE:
|
|
if (lsm_find_state(LSM_S_RINGIN) > CC_NO_CALL_ID) {
|
|
// No tone if we have calls in ringing state
|
|
return;
|
|
}
|
|
|
|
if (!lsm_callwaiting()) {
|
|
config_get_value(CFGID_BLF_ALERT_TONE_IDLE, &play_tone, sizeof(play_tone));
|
|
if (play_tone == 0) {
|
|
return;
|
|
}
|
|
lsm_util_tone_start_with_speaker_as_backup(VCM_CALL_WAITING_TONE, VCM_ALERT_INFO_OFF,
|
|
CC_NO_CALL_ID, CC_NO_GROUP_ID,
|
|
CC_NO_MEDIA_REF_ID, VCM_PLAY_TONE_TO_EAR);
|
|
} else {
|
|
config_get_value(CFGID_BLF_ALERT_TONE_BUSY, &play_tone, sizeof(play_tone));
|
|
if (play_tone == 0) {
|
|
return;
|
|
}
|
|
lsm_util_tone_start_with_speaker_as_backup(VCM_CALL_WAITING_TONE, VCM_ALERT_INFO_OFF,
|
|
CC_NO_CALL_ID, CC_NO_GROUP_ID,
|
|
CC_NO_MEDIA_REF_ID, VCM_PLAY_TONE_TO_EAR);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* lsm_update_inalert_status
|
|
*
|
|
* Description:
|
|
*
|
|
* TNP specific implementation of status line update for inalert state.
|
|
*
|
|
* Parameters:
|
|
*
|
|
* line_t line - Line facility of the call
|
|
* callid_t call_id - Call id of call whose state is being reported
|
|
* cc_state_data_alerting_t * data - alerting callinfo.
|
|
* boolean notify - whether the msg be displayed at notify level.
|
|
*
|
|
* Returns: None
|
|
*/
|
|
static void
|
|
lsm_update_inalert_status (line_t line, callid_t call_id,
|
|
cc_state_data_alerting_t * data,
|
|
boolean notify)
|
|
{
|
|
static const char fname[] = "lsm_update_inalert_status";
|
|
char disp_str[LSM_DISPLAY_STR_LEN];
|
|
|
|
// get localized tag index for From and append one space character
|
|
sstrncpy(disp_str, platform_get_phrase_index_str(UI_FROM),
|
|
sizeof(disp_str));
|
|
|
|
LSM_DEBUG(DEB_L_C_F_PREFIX"+++ calling number = %s\n",
|
|
DEB_L_C_F_PREFIX_ARGS(LSM, line, call_id, fname),
|
|
data->caller_id.calling_number);
|
|
|
|
// append calling number if present or localized tag for Unknown Number
|
|
// otherwise
|
|
if ((data->caller_id.calling_number) &&
|
|
(data->caller_id.calling_number[0] != '\0') &&
|
|
data->caller_id.display_calling_number) {
|
|
|
|
sstrncat(disp_str, data->caller_id.calling_number,
|
|
sizeof(disp_str) - strlen(disp_str));
|
|
} else {
|
|
sstrncat(disp_str, platform_get_phrase_index_str(UI_UNKNOWN),
|
|
sizeof(disp_str) - strlen(disp_str));
|
|
}
|
|
|
|
// we display (via notification) the "From ..." info for 10 seconds.
|
|
// Note that this will remain displayed for 10 sec even if the user
|
|
// answers the call or switches to another call. This happens because
|
|
// notification has higher priority than call status (e.g. connected).
|
|
// This is done to have parity with SCCP phone behavior.
|
|
if (notify == TRUE) {
|
|
ui_set_notification(line, call_id,
|
|
(char *)disp_str, (unsigned long)CALL_ALERT_TIMEOUT,
|
|
FALSE, FROM_NOTIFY_PRI);
|
|
}
|
|
// After the notification we wish to set the call status to From XXXX. Same as SCCP phone behavior
|
|
lsm_ui_display_status((char *)disp_str, line, call_id);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* lsm_set_cfwd_all_nonccm
|
|
* This function calls JNI API to set the CFA state and DN in non-ccm mode.
|
|
*
|
|
* @param[in] line - line on which to set the CFA
|
|
* @param[in] callfwd_dialstring: CFA DN (will be stored in flash)
|
|
*
|
|
* @return: None
|
|
*/
|
|
void
|
|
lsm_set_cfwd_all_nonccm (line_t line, char *callfwd_dialstring)
|
|
{
|
|
// call Java API
|
|
ui_cfwd_status(line, TRUE, callfwd_dialstring, TRUE);
|
|
}
|
|
|
|
/*
|
|
* lsm_set_cfwd_all_ccm
|
|
*
|
|
* Description:
|
|
* This function calls JNI API to set the CFA state and DN in ccm mode.
|
|
*
|
|
* Parameters:
|
|
* char * callfwd_dialstring: CFA DN (will NOT be stored in flash)
|
|
*
|
|
* Returns: None
|
|
*/
|
|
void
|
|
lsm_set_cfwd_all_ccm (line_t line, char *callfwd_dialstring)
|
|
{
|
|
// set locally maintained variable
|
|
cfwdall_state_in_ccm_mode[line] = TRUE;
|
|
|
|
// call Java API
|
|
ui_cfwd_status((line_t)line, TRUE, callfwd_dialstring, FALSE);
|
|
}
|
|
|
|
/*
|
|
* lsm_clear_cfwd_all_nonccm
|
|
* This function calls JNI API to clear the CFA state and DN in non-ccm mode.
|
|
*
|
|
* @param[in] line - line on which to clear the CFA
|
|
*
|
|
* @return: None
|
|
*/
|
|
void
|
|
lsm_clear_cfwd_all_nonccm (line_t line)
|
|
{
|
|
// call Java API
|
|
ui_cfwd_status(line, FALSE, "", TRUE);
|
|
}
|
|
|
|
|
|
/*
|
|
* lsm_clear_cfwd_all_ccm
|
|
*
|
|
* Description:
|
|
* This function calls JNI API to clear the CFA state and DN in ccm mode.
|
|
*
|
|
* Parameters: None
|
|
*
|
|
* Returns: None
|
|
*/
|
|
void
|
|
lsm_clear_cfwd_all_ccm (line_t line)
|
|
{
|
|
// clear locally maintained variable
|
|
cfwdall_state_in_ccm_mode[line] = FALSE;
|
|
|
|
// call Java API
|
|
ui_cfwd_status((line_t)line, FALSE, "", FALSE);
|
|
}
|
|
|
|
/*
|
|
* lsm_check_cfwd_all_nonccm
|
|
*
|
|
* Description:
|
|
* This function returns the CFA state in non-ccm mode.
|
|
*
|
|
* @param[in] line - line on which to check the CFA
|
|
*
|
|
* @return: TRUE (if CFA set) or FALSE (if CFA clear)
|
|
*/
|
|
int
|
|
lsm_check_cfwd_all_nonccm (line_t line)
|
|
{
|
|
char cfg_cfwd_url[MAX_URL_LENGTH];
|
|
|
|
cfg_cfwd_url[0] = '\0';
|
|
|
|
// get the callfwdall url value from the config/flash table
|
|
config_get_string(CFGID_LINE_CFWDALL+line-1, cfg_cfwd_url, MAX_URL_LENGTH);
|
|
|
|
// return appropriate value: TRUE if non-NULL and FALSE otherwise
|
|
if (cfg_cfwd_url[0]) {
|
|
return ((int) TRUE);
|
|
} else {
|
|
return ((int) FALSE);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* lsm_check_cfwd_all_ccm
|
|
*
|
|
* Description:
|
|
* This function returns the CFA state in ccm mode.
|
|
*
|
|
* Parameters: None
|
|
*
|
|
* Returns: TRUE or FALSE
|
|
*/
|
|
int
|
|
lsm_check_cfwd_all_ccm (line_t line)
|
|
{
|
|
return ((int) cfwdall_state_in_ccm_mode[line]);
|
|
}
|
|
|
|
/*
|
|
* lsm_is_phone_forwarded
|
|
*
|
|
* Description:
|
|
* This function is called from SIP stack to check if received INVITE
|
|
* should be responded with 302 or not. In the CCM mode this function
|
|
* will always return NULL... that is process the INVITE as normal and
|
|
* DO NOT 302 it. In the non-CCM mode, if the cfwdall_url is non-NULL
|
|
* then it will form a proper string to use in 302 response; otherwise
|
|
* a NULL will be returned and the INVITE will be processed as normal.
|
|
* NOTE: most all code is reused from the legacy phone code.
|
|
*
|
|
* Parameters: line - line for which to check the CFA status
|
|
*
|
|
* Returns: NULL if forwarding is not set;
|
|
* string to use in 302 response if forwarding is set (non-CCM only)
|
|
*/
|
|
char *
|
|
lsm_is_phone_forwarded (line_t line)
|
|
{
|
|
static const char fname[] = "lsm_is_phone_forwarded";
|
|
char proxy_ipaddr_str[MAX_IPADDR_STR_LEN];
|
|
int port_number = 5060; // use this value only if none found
|
|
char *domain = NULL;
|
|
char *port = NULL;
|
|
cpr_ip_addr_t proxy_ipaddr;
|
|
|
|
|
|
LSM_DEBUG(DEB_F_PREFIX"called\n", DEB_F_PREFIX_ARGS(LSM, fname));
|
|
|
|
// check if running in CCM mode. if so, return NULL that is cfwdall
|
|
// not applicable
|
|
if (sip_regmgr_get_cc_mode(TEL_CCB_START) == REG_MODE_CCM) {
|
|
return (NULL);
|
|
}
|
|
// get stored callfwdall url value from the config/flash table
|
|
|
|
config_get_string(CFGID_LINE_CFWDALL+line-1, cfwdall_url, sizeof(cfwdall_url));
|
|
|
|
if (cfwdall_url[0]) {
|
|
// find domain and port
|
|
domain = strchr(cfwdall_url, '@');
|
|
if (!domain) {
|
|
(void) sipTransportGetServerAddress(&proxy_ipaddr,
|
|
1, TEL_CCB_START);
|
|
if (proxy_ipaddr.type != CPR_IP_ADDR_INVALID) {
|
|
ipaddr2dotted(proxy_ipaddr_str, &proxy_ipaddr);
|
|
port_number = sipTransportGetServerPort(1, TEL_CCB_START);
|
|
}
|
|
} else {
|
|
port = strchr(domain + 1, ':');
|
|
}
|
|
|
|
// handle 3 cases
|
|
if (domain == NULL) {
|
|
/* case (1): no domain or port present
|
|
* We have proxy's dotted ip address format. So, not FQDN check.
|
|
* Append domain/ip-addr and port.
|
|
*/
|
|
snprintf(cfwdall_url + strlen(cfwdall_url),
|
|
MAX_URL_LENGTH - strlen(cfwdall_url),
|
|
"@%s:%d", proxy_ipaddr_str, port_number);
|
|
} else if (port == NULL) {
|
|
/* case (2): domain present but no port
|
|
* Check if the domain is dotted IP address and add port
|
|
* only if dotted IP address is used
|
|
*/
|
|
if (!str2ip((const char *) domain + 1, &proxy_ipaddr)) {
|
|
port_number = sipTransportGetServerPort(1, TEL_CCB_START);
|
|
snprintf(cfwdall_url + strlen(cfwdall_url),
|
|
MAX_URL_LENGTH - strlen(cfwdall_url),
|
|
":%d", port_number);
|
|
}
|
|
} else {
|
|
/* case (3): both domain and port present
|
|
* Both domain and port exists, but strip the port if the
|
|
* domain is FQDN
|
|
*/
|
|
memcpy(proxy_ipaddr_str, domain + 1, (port - domain - 1));
|
|
*(proxy_ipaddr_str + (port - domain - 1)) = '\0';
|
|
if (str2ip((const char *) proxy_ipaddr_str, &proxy_ipaddr) != 0) {
|
|
*port = '\0';
|
|
}
|
|
}
|
|
return ((char *)cfwdall_url);
|
|
} else {
|
|
return ((char *)NULL);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* lsm_get_callid_from_ui_id()
|
|
*
|
|
* Description:
|
|
* The function gets the UI id from LSM's LCB for a given GSM call ID.
|
|
*
|
|
* Parameters:
|
|
* ui_id - UI ID.
|
|
*
|
|
* Returns: callid_t
|
|
*/
|
|
callid_t
|
|
lsm_get_callid_from_ui_id (callid_t uid)
|
|
{
|
|
lsm_lcb_t *lcb;
|
|
FSM_FOR_ALL_CBS(lcb, lsm_lcbs, LSM_MAX_LCBS) {
|
|
if (lcb->ui_id == uid) {
|
|
return lcb->call_id;
|
|
}
|
|
}
|
|
return (CC_NO_CALL_ID);
|
|
}
|
|
|
|
/*
|
|
* lsm_get_ui_id
|
|
*
|
|
* Description:
|
|
* The function gets the UI id from LSM's LCB for a given GSM call ID.
|
|
*
|
|
* Parameters:
|
|
* call_id - GSM call ID
|
|
* ui_id - UI ID.
|
|
*
|
|
* Returns: None
|
|
*/
|
|
callid_t
|
|
lsm_get_ui_id (callid_t call_id)
|
|
{
|
|
lsm_lcb_t *lcb;
|
|
|
|
lcb = lsm_get_lcb_by_call_id(call_id);
|
|
if (lcb != NULL) {
|
|
return (lcb->ui_id);
|
|
}
|
|
return (CC_NO_CALL_ID);
|
|
}
|
|
|
|
/*
|
|
* lsm_get_ms_ui_id
|
|
*
|
|
* Description:
|
|
* The function gets the UI id from LSM's LCB for a given GSM call ID. During
|
|
* certain features like barge ui_id is set to CC_NO_CALL_ID.
|
|
*
|
|
* Parameters:
|
|
* call_id - GSM call ID
|
|
* ui_id - UI ID.
|
|
*
|
|
* Returns: None
|
|
*/
|
|
cc_call_handle_t
|
|
lsm_get_ms_ui_call_handle (line_t line, callid_t call_id, callid_t ui_id)
|
|
{
|
|
callid_t lsm_ui_id;
|
|
|
|
if (ui_id != CC_NO_CALL_ID) {
|
|
return CREATE_CALL_HANDLE(line, ui_id);
|
|
}
|
|
|
|
/* If ui_id present use that */
|
|
lsm_ui_id = lsm_get_ui_id(call_id);
|
|
|
|
if (lsm_ui_id != CC_NO_CALL_ID) {
|
|
return CREATE_CALL_HANDLE(line, lsm_ui_id);
|
|
}
|
|
|
|
return CREATE_CALL_HANDLE(line, call_id);
|
|
}
|
|
/*
|
|
* lsm_set_ui_id
|
|
*
|
|
* Description:
|
|
* The function sets the UI id to LSM's LCB for a given GSM call ID.
|
|
*
|
|
* Parameters:
|
|
* call_id - GSM call ID
|
|
* ui_id - UI ID.
|
|
*
|
|
* Returns: None
|
|
*/
|
|
void
|
|
lsm_set_ui_id (callid_t call_id, callid_t ui_id)
|
|
{
|
|
lsm_lcb_t *lcb;
|
|
|
|
lcb = lsm_get_lcb_by_call_id(call_id);
|
|
if (lcb != NULL) {
|
|
lcb->ui_id = ui_id;
|
|
}
|
|
}
|
|
|
|
char *
|
|
lsm_get_gdialed_digits (void)
|
|
{
|
|
return (dp_get_gdialed_digits());
|
|
}
|
|
|
|
/*
|
|
* lsm_update_video_avail
|
|
*
|
|
* Description:
|
|
* The function updates session about the video availability
|
|
*
|
|
* Parameters:
|
|
* line - line
|
|
* call_id - GSM call ID
|
|
* dir - video avail dir
|
|
*
|
|
* Returns: None
|
|
*/
|
|
void lsm_update_video_avail (line_t line, callid_t call_id, int dir)
|
|
{
|
|
static const char fname[] = "lsm_update_video_avail";
|
|
fsmdef_dcb_t *dcb;
|
|
lsm_lcb_t *lcb;
|
|
|
|
lcb = lsm_get_lcb_by_call_id(call_id);
|
|
if (lcb != NULL) {
|
|
dcb = lcb->dcb;
|
|
if (dcb == NULL) {
|
|
LSM_ERR_MSG(get_debug_string(DEBUG_INPUT_NULL), fname);
|
|
return;
|
|
}
|
|
|
|
dir &= ~CC_ATTRIB_CAST;
|
|
|
|
|
|
ui_update_video_avail (line, lcb->ui_id, dir);
|
|
|
|
lsm_update_dscp_value(dcb);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* lsm_update_video_offered
|
|
*
|
|
* Description:
|
|
* The function updates session about the video availability
|
|
*
|
|
* Parameters:
|
|
* line - line
|
|
* call_id - GSM call ID
|
|
* dir - video avail dir
|
|
*
|
|
* Returns: None
|
|
*/
|
|
void lsm_update_video_offered (line_t line, callid_t call_id, int dir)
|
|
{
|
|
lsm_lcb_t *lcb;
|
|
|
|
lcb = lsm_get_lcb_by_call_id(call_id);
|
|
if (lcb != NULL) {
|
|
ui_update_video_offered (line, lcb->ui_id, dir);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* lsm_set_video_mute
|
|
*
|
|
* Description:
|
|
* The function sets the video mute state for the call
|
|
*
|
|
* Parameters:
|
|
* line - line
|
|
* call_id - This is the UI_ID coming from UI
|
|
* mute - mute state
|
|
*
|
|
* Returns: None
|
|
*/
|
|
void lsm_set_video_mute (callid_t call_id, int mute)
|
|
{
|
|
lsm_lcb_t *lcb;
|
|
callid_t cid = lsm_get_callid_from_ui_id(call_id); // get GSM_ID from UI_ID
|
|
|
|
lcb = lsm_get_lcb_by_call_id(cid);
|
|
if (lcb != NULL) {
|
|
lcb->vid_mute = mute;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* lsm_get_video_mute
|
|
*
|
|
* Description:
|
|
* The function gets the video mute state for the call
|
|
*
|
|
* Parameters:
|
|
* line - line
|
|
* call_id - GSM call ID
|
|
*
|
|
* Returns: t_video_mute
|
|
*/
|
|
int lsm_get_video_mute (callid_t call_id)
|
|
{
|
|
lsm_lcb_t *lcb;
|
|
|
|
lcb = lsm_get_lcb_by_call_id(call_id);
|
|
if (lcb != NULL) {
|
|
return lcb->vid_mute;
|
|
}
|
|
return (-1);
|
|
}
|
|
|
|
|
|
/*
|
|
* lsm_set_video_window
|
|
*
|
|
* Description:
|
|
* The function sets the video window state for the call
|
|
*
|
|
* Parameters:
|
|
* call_id - This is the UI_ID coming from UI
|
|
* flags - video window flags
|
|
* x - video window x coordinate
|
|
* y - video window y coordinate
|
|
* h - video window height
|
|
* w - video window width
|
|
*
|
|
* Returns: None
|
|
*/
|
|
void lsm_set_video_window (callid_t call_id, int flags, int x, int y, int h, int w)
|
|
{
|
|
lsm_lcb_t *lcb;
|
|
callid_t cid = lsm_get_callid_from_ui_id(call_id); // get GSM_ID from UI_ID
|
|
|
|
lcb = lsm_get_lcb_by_call_id(cid);
|
|
if (lcb != NULL) {
|
|
lcb->vid_flags = flags;
|
|
lcb->vid_x = x;
|
|
lcb->vid_y = y;
|
|
lcb->vid_h = h;
|
|
lcb->vid_w = w;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* lsm_get_video_window
|
|
*
|
|
* Description:
|
|
* The function gets the video window for the call
|
|
*
|
|
* Parameters:
|
|
* call_id - GSM call ID
|
|
* *flags - video window flag
|
|
* *x - video window x coordinate
|
|
* *y - video window y coordinate
|
|
* *h - video window height
|
|
* *w - video window width
|
|
*
|
|
* Returns: void
|
|
*/
|
|
void lsm_get_video_window (callid_t call_id, int *flags, int *x, int *y, int *h, int *w)
|
|
{
|
|
lsm_lcb_t *lcb;
|
|
|
|
lcb = lsm_get_lcb_by_call_id(call_id);
|
|
if (lcb != NULL) {
|
|
*flags = lcb->vid_flags;
|
|
*x = lcb->vid_x;
|
|
*y = lcb->vid_y;
|
|
*h = lcb->vid_h;
|
|
*w = lcb->vid_w;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* lsm_is_kpml_subscribed
|
|
*
|
|
* Description:
|
|
* check if kpml is subscribed for this call
|
|
*
|
|
* Parameters:
|
|
* call_id - GSM call ID
|
|
*
|
|
* Returns: true/false
|
|
*/
|
|
boolean lsm_is_kpml_subscribed (callid_t call_id)
|
|
{
|
|
lsm_lcb_t *lcb;
|
|
|
|
lcb = lsm_get_lcb_by_call_id(call_id);
|
|
if (lcb == NULL) {
|
|
return FALSE;
|
|
}
|
|
return kpml_is_subscribed(call_id, lcb->line);
|
|
}
|
|
|
|
/**
|
|
* A helper method to start the tone.
|
|
*/
|
|
static void lsm_util_start_tone(vcm_tones_t tone, short alert_info,
|
|
cc_call_handle_t call_handle, groupid_t group_id,
|
|
streamid_t stream_id, uint16_t direction) {
|
|
|
|
int sdpmode = 0;
|
|
static const char fname[] = "lsm_util_start_tone";
|
|
line_t line = GET_LINE_ID(call_handle);
|
|
callid_t call_id = GET_CALL_ID(call_handle);
|
|
DEF_DEBUG(DEB_F_PREFIX"Enter, line=%d, call_id=%d.\n",
|
|
DEB_F_PREFIX_ARGS(MED_API, fname), line, call_id);
|
|
|
|
sdpmode = 0;
|
|
config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
|
|
if (!sdpmode) {
|
|
vcmToneStart(tone, alert_info, call_handle, group_id, stream_id, direction);
|
|
}
|
|
/*
|
|
* Set delay value for multi-part tones and repeated tones.
|
|
* Currently the only multi-part tones are stutter and message
|
|
* waiting tones. The only repeated tones are call waiting and
|
|
* tone on hold tones. If the DSP ever supports stutter and
|
|
* message waiting tones, these tones can be removed from this
|
|
* switch statement.
|
|
*/
|
|
switch (tone) {
|
|
case VCM_MSG_WAITING_TONE:
|
|
lsm_start_multipart_tone_timer(tone, MSG_WAITING_DELAY, call_id);
|
|
break;
|
|
|
|
case VCM_HOLD_TONE:
|
|
lsm_start_continuous_tone_timer(tone, TOH_DELAY, call_id);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* Update dcb->active_tone if start request
|
|
* is for an infinite duration tone.
|
|
*/
|
|
lsm_update_active_tone(tone, call_id);
|
|
}
|
|
|
|
/*
|
|
* Plays a short tone. uses the open audio path.
|
|
* If no audio path is open, plays on speaker.
|
|
*
|
|
* @param[in] tone - tone type
|
|
* @param[in] alert_info - alertinfo header
|
|
* @param[in] call_id - call identifier
|
|
* @param[in] direction - network, speaker, both
|
|
*
|
|
* @return none
|
|
*/
|
|
void
|
|
lsm_util_tone_start_with_speaker_as_backup (vcm_tones_t tone, short alert_info,
|
|
cc_call_handle_t call_handle, groupid_t group_id,
|
|
streamid_t stream_id, uint16_t direction) {
|
|
static const char *fname = "lsm_util_tone_start_with_speaker_as_backup";
|
|
line_t line = GET_LINE_ID(call_handle);
|
|
callid_t call_id = GET_CALL_ID(call_handle);
|
|
DEF_DEBUG(DEB_L_C_F_PREFIX"tone=%-2d: direction=%-2d\n",
|
|
DEB_L_C_F_PREFIX_ARGS(MED_API, line, call_id, fname),
|
|
tone, direction);
|
|
|
|
//vcmToneStart
|
|
vcmToneStart(tone, alert_info, call_handle, group_id, stream_id, direction);
|
|
|
|
/*
|
|
* Set delay value for multi-part tones and repeated tones.
|
|
* Currently the only multi-part tones are stutter and message
|
|
* waiting tones. The only repeated tones are call waiting and
|
|
* tone on hold tones. If the DSP ever supports stutter and
|
|
* message waiting tones, these tones can be removed from this
|
|
* switch statement.
|
|
*/
|
|
switch (tone) {
|
|
case VCM_MSG_WAITING_TONE:
|
|
lsm_start_multipart_tone_timer(tone, MSG_WAITING_DELAY, call_id);
|
|
break;
|
|
|
|
case VCM_HOLD_TONE:
|
|
lsm_start_continuous_tone_timer(tone, TOH_DELAY, call_id);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* Update dcb->active_tone if start request
|
|
* is for an infinite duration tone.
|
|
*/
|
|
lsm_update_active_tone(tone, call_id);
|
|
|
|
}
|