Newer
Older
#include <stdio.h>
#include <ctype.h>
#include <unistd.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <libubus.h>
#include <libpicoevent.h> // for err_exit()
#include "line.h"
#include "line-dect.h"
#include "main.h"
#include "ubus.h"
static char *pcmState2Str(callid_state state)
{
if (state <= CALLID_INVALID)
return "Invalid";
else if (state == CALLID_OBTAINING)
return "Obtaining";
else
return "Established";
}
void pcm_states_dump(const char *func, int line)
{

Yalu Zhang
committed
ENDPT_DBG("%s: line=%d, pcm_callid[%d]=\'%s\', pcm_callid[%d]=\'%s\'\n", func, line,
PCM_0, pcmState2Str(lines[line].pcm_callid[PCM_0]),
PCM_1, pcmState2Str(lines[line].pcm_callid[PCM_1]));
}
// Get call_id state (-1, 0, 1)
callid_state get_callid_state(int call_id) {
if (call_id <= CALLID_INVALID)
return CALLID_INVALID;
else if (call_id == CALLID_OBTAINING)
return CALLID_OBTAINING;
else
return CALLID_ESTABLISHED;
}
static int send_dect_event_to_asterisk(int line, struct dect_event_t dectEvnt)
{
struct line_event_t *msg;
msg = malloc(sizeof(struct line_event_t));
msg->name = dectEvnt.name;
msg->data = 0;
msg->line = line;
ubus_call_asterisk(msg);
ubus_broadcast_event(msg);
return 0;
}
//-------------------------------------------------------------
// If a line has been disabled in run time we simulate
// it as always being busy by going off-hook forever. This
// is used by DECT when the HW is unpopulated.
static int perhaps_simulate_busy(int line, struct voice_ubus_req_t *ubus_req)
{
const struct voice_event_t *ev;
struct line_event_t *msg;
if(!lines[line].simulated_busy)
return 0;

Yalu Zhang
committed
// Inform Asterisk only once per UBUS session or we get a loop
assert(ubus_req && ubus_req->reqIn);
if(lines[line].simulated_busy_peer_id == ubus_req->reqIn->peer) {
lines[line].simulated_busy_peer_id = ubus_req->reqIn->peer;

Yalu Zhang
committed
for(ev = event_map; ev->event != VOICE_EVT_OFFHOOK; ev++)
continue;
msg = malloc(sizeof(struct line_event_t));

Yalu Zhang
committed
if (msg) {
msg->name = ev->name;
msg->data = 0;
msg->line = line;
send_event_main(msg, EVENT_MAIN_LINE);
} else {
ENDPT_ERR("%s: out of memory\n", __func__);

Yalu Zhang
committed
}
//----------------------------------------------------------------------------------
// DECT handset tone trigger
static int dect_tone_play(int line, int pcm, enum VOICE_SIGNAL signal, const char *data, struct voice_ubus_req_t *ubus_req)
{
struct line_req_t *line_req = NULL;
ENDPT_DBG("line=%d, pcm=%d, data=%s\n", line, pcm, data);
pcm_states_dump(__func__, line);
assert(ubus_req);
line_req = calloc(1, sizeof(struct line_req_t));
if(!line_req) {
ENDPT_ERR("%s: out of memory\n", __func__);
return -1;
}
line_req->line = line;
line_req->connection_id = -1;
line_req->pcm_id = pcm;
switch(signal) {
case VOICE_SIG_UNOBTAINABLE:
case VOICE_SIG_BUSY:
case VOICE_SIG_NETBUSY:
line_req->action = ACTION_SIG_BUSY_TONE; //only busy tone available
break;
default:
free(line_req);
return -1;
}
ENDPT_DBG("line %d set pcm to %d\n", line, line_req->pcm_id);
memcpy(&line_req->ubus, ubus_req, sizeof(struct voice_ubus_req_t));
assert(lines[line].type == VOICE_LINE_DECT);
assert(line_req);
if(ubus_queue_req_to_dectmngr(line_req) || ubus_process_queued_reqs_to_dectmngr())
return -1;
ubus_defer_request(line_req->ubus.ctx, line_req->ubus.reqIn, &line_req->ubus.reqOut);
line_req->ubus.reqIn = NULL;
return 0;
}
static void setCallerName(const char *data, char *callerName)
{
char *start;
if ( (start = strchr(data,'\"')) )
{
char *end;
start += 1;
if ( (end = strchr(start,'\"')) )
{
int len = ((end - start) < MAX_CALLER_NAME ? (end - start) : MAX_CALLER_NAME);
memcpy(callerName, start, len);
callerName[len] = '\0';
}
}
}
//----------------------------------------------------------------------------------
// Asterisk wants to make a FXS phone or DECT handset ring probably with a caller ID
static int line_signal_ring(int line, int pcm, enum VOICE_SIGNAL signal, const char *data, struct voice_ubus_req_t *ubus_req)
{

Yalu Zhang
committed
struct line_req_t *line_req = NULL;
int start_ring = data && strcmp(data, "0") != 0;
ENDPT_DBG("line=%d, pcm=%d, data=%s\n", line, pcm, data);
pcm_states_dump(__func__, line);

Yalu Zhang
committed
// Relay the request to dectmngr if the line is DECT
if(lines[line].type == VOICE_LINE_DECT) {

Yalu Zhang
committed
line_req = calloc(1, sizeof(struct line_req_t));
if(!line_req) {
ENDPT_ERR("%s: out of memory\n", __func__);

Yalu Zhang
committed
return -1;

Yalu Zhang
committed
}
line_req->line = line;
line_req->connection_id = -1;
line_req->pcm_id = pcm;
ENDPT_DBG("line %d set pcm to %d\n", line, line_req->pcm_id);

Yalu Zhang
committed
memcpy(&line_req->ubus, ubus_req, sizeof(struct voice_ubus_req_t));
// Parse the called ID string generated by Asterisk
if(data && strlen(data) >= MIN_CALLER_ID_LEN && strlen(data) <= MAX_CALLER_ID_LEN &&

Yalu Zhang
committed
data[CLID_TIME_DELIM] == ',' && data[CLID_NUMB_REC + 1] != ',') {
char cid_tmp[strlen(data) + 1], *end;

Yalu Zhang
committed
strcpy(cid_tmp, data);
if ((end = strchr(cid_tmp + CLID_NUMB_REC, ',')) != NULL)
*end = '\0'; // Find comma after digits and null it
strcpy(line_req->caller_id, cid_tmp + CLID_NUMB_REC); // Extract the number
setCallerName(data, line_req->caller_name);
}
}
// What type of ring signal?

Yalu Zhang
committed
switch(signal) {
case VOICE_SIG_CALLID:

Yalu Zhang
committed
if(line_req) {
line_req->action = start_ring ? ACTION_SIG_RING : ACTION_RINGING_STOP;

Yalu Zhang
committed
} else {
return voice_line_signal(line, -1, signal, start_ring, (void *)data);
}
break;

Yalu Zhang
committed
case VOICE_SIG_RINGING:
case VOICE_SIG_CALLID_RINGING:

Yalu Zhang
committed
if(line_req) {
if(start_ring) {

Yalu Zhang
committed
if(signal == VOICE_SIG_CALLID_RINGING) {
// Dect ignore this enable signal

Yalu Zhang
committed
free(line_req);

Yalu Zhang
committed
return 0;

Yalu Zhang
committed
line_req->action = ACTION_SIG_RING;
} else {
line_req->action = ACTION_RINGING_STOP;

Yalu Zhang
committed
line_req->caller_id[0] = 0; // Discard enable/disable char or it will become the caller ID
} else {

Yalu Zhang
committed
return voice_line_signal(line, -1, signal, start_ring, NULL);
}
break;
case VOICE_SIG_CALL_WAITING: // only used for stopping call waiting indication
if(line_req) {
if(!start_ring) {
line_req->action = ACTION_RINGING_STOP;
}
line_req->caller_id[0] = 0; // Discard enable/disable char or it will become the caller ID
break;
} else {
return -1;
}
default:

Yalu Zhang
committed
free(line_req);

Yalu Zhang
committed
return -1;
}

Yalu Zhang
committed
// If getting here the request is aimed for DECT
assert(lines[line].type == VOICE_LINE_DECT);

Yalu Zhang
committed
assert(line_req);
if(ubus_queue_req_to_dectmngr(line_req) || ubus_process_queued_reqs_to_dectmngr())

Yalu Zhang
committed
return -1;

Yalu Zhang
committed
ubus_defer_request(line_req->ubus.ctx, line_req->ubus.reqIn, &line_req->ubus.reqOut);
line_req->ubus.reqIn = NULL;

Yalu Zhang
committed
return 0;
//-------------------------------------------------------------
// Reception of a answer connection request from Asterisk. If
// line type is Dect we need to relay the requets to the Dectmngr.
static int line_signal_answer(int line, int pcm, const char *data, struct voice_ubus_req_t *ubus_req)
{
struct line_req_t *line_req = NULL;
ENDPT_DBG("line %d pcm: %d data: %s\n", line, pcm, data);
pcm_states_dump(__func__, line);
assert(ubus_req);
line_req = calloc(1, sizeof(struct line_req_t));
if(!line_req) return -1;
line_req->line = line;
line_req->connection_id = -1;
line_req->pcm_id = pcm;
line_req->action = ACTION_SIG_ANSWERED;
memcpy(&line_req->ubus, ubus_req, sizeof(struct voice_ubus_req_t));
assert(line_req);
if(ubus_queue_req_to_dectmngr(line_req) || ubus_process_queued_reqs_to_dectmngr())
return -1;
ubus_defer_request(line_req->ubus.ctx, line_req->ubus.reqIn, &line_req->ubus.reqOut);
line_req->ubus.reqIn = NULL;
return 0;
}
//-------------------------------------------------------------
// Generate a signal to the phone, such as DTMF tones or ringing
int line_signal(int line, const char *signame, const char *data, struct voice_ubus_req_t *ubus_req)
{

Yalu Zhang
committed
const struct voice_signal_t *sig;

Yalu Zhang
committed
int res = 0;
ENDPT_DBG("line=%d(type:%d), signame=%s, data=%s\n", line, lines[line].type, signame, data);

Yalu Zhang
committed

Yalu Zhang
committed
for(sig = signal_map; sig->signal != VOICE_SIG_LAST && strcmp(signame, sig->name) != 0; sig++)

Yalu Zhang
committed
continue;

Yalu Zhang
committed
if(sig->signal == VOICE_SIG_LAST) {
ENDPT_ERR("%s: signal %s is not supported\n", __func__, signame);
return -1;
}
// Is line disabled?
if(perhaps_simulate_busy(line, ubus_req))

Yalu Zhang
committed
switch(sig->signal) {
case VOICE_SIG_CALLID_RINGING:
case VOICE_SIG_CALLID:
case VOICE_SIG_RINGING:
res = line_signal_ring(line, get_callid_state(lines[line].pcm_callid[PCM_0]) == CALLID_OBTAINING ?
PCM_0 : PCM_1, sig->signal, data, ubus_req);
lines[line].signaled_call_waiting = 0;
res = line_signal_ring(line, get_callid_state(lines[line].pcm_callid[PCM_0]) == CALLID_INVALID ?
PCM_0 : PCM_1, sig->signal, data, ubus_req);

Yalu Zhang
committed

Yalu Zhang
committed
case VOICE_SIG_INGRESS_DTMF: // Simulate phone keypad button presses
res = voice_line_signal(line, -1, sig->signal, 1, (void *)data);

Yalu Zhang
committed
case VOICE_SIG_CALL_WAITING:
if (lines[line].type == VOICE_LINE_DECT) {
ENDPT_DBG("lines[%d].signaled_call_waiting: %d\n", line, lines[line].signaled_call_waiting);
if(data && strlen(data) >= MIN_CALLER_ID_LEN &&
strlen(data) <= MAX_CALLER_ID_LEN &&
data[CLID_TIME_DELIM] == ',' &&
data[CLID_NUMB_REC + 1] != ',' &&
lines[line].signaled_call_waiting == 0) {
pcm_states_dump(__func__, line);
res = line_signal_ring(line, get_callid_state(lines[line].pcm_callid[PCM_1]) == CALLID_INVALID ?
PCM_1 : PCM_0, VOICE_SIG_CALLID, data, ubus_req);
lines[line].signaled_call_waiting = 1;
// stop call waiting when accepted but not close the connection on the accepted line
res = line_signal_ring(line, get_callid_state(lines[line].pcm_callid[PCM_1]) == CALLID_OBTAINING ?
PCM_1 : PCM_0, VOICE_SIG_CALL_WAITING, data, ubus_req);
lines[line].signaled_call_waiting = 0;

Yalu Zhang
committed
res = voice_line_signal(line, -1, sig->signal, atoi(data), NULL);

Yalu Zhang
committed

Yalu Zhang
committed
case VOICE_SIG_UNOBTAINABLE:
if (lines[line].type == VOICE_LINE_DECT) {
send_dect_event_to_asterisk(line, dect_event_map[DECT_EVT_RELEASE]);

Yalu Zhang
committed
res = voice_line_signal(line, -1, sig->signal, atoi(data), NULL);

Yalu Zhang
committed
case VOICE_SIG_NETBUSY:
if (lines[line].type == VOICE_LINE_DECT) {
pcm_states_dump(__func__, line);
if (get_callid_state(lines[line].pcm_callid[PCM_0])==CALLID_ESTABLISHED && get_callid_state(lines[line].pcm_callid[PCM_1])==CALLID_ESTABLISHED){
send_dect_event_to_asterisk(line, dect_event_map[DECT_EVT_RELEASE]);
} else if (get_callid_state(lines[line].pcm_callid[PCM_0]) == CALLID_ESTABLISHED || get_callid_state(lines[line].pcm_callid[PCM_1]) == CALLID_ESTABLISHED){
// play tone on DECT
res = dect_tone_play(line, get_callid_state(lines[line].pcm_callid[PCM_0]) == CALLID_ESTABLISHED ? PCM_0 : PCM_1, sig->signal, data, ubus_req);
}
res = voice_line_signal(line, -1, sig->signal, atoi(data), NULL);

Yalu Zhang
committed
case VOICE_SIG_ANSWER:
if ((lines[line].type == VOICE_LINE_DECT) && (data[0] == '1')) {
res = line_signal_answer(line, get_callid_state(lines[line].pcm_callid[PCM_1]) >= CALLID_OBTAINING ?
PCM_1 : PCM_0, data, ubus_req);
} else {
res = 0;
}
break;
case VOICE_SIG_K_BREAK:
if (lines[line].type == VOICE_LINE_FXS) {
res = voice_line_signal(line, -1, sig->signal, atoi(data), NULL);
}
break;
res = voice_line_signal(line, -1, sig->signal, atoi(data), NULL);
if (res != 0) {
ENDPT_ERR("%s: failed to generate signal %s(%s) on line %d\n", __func__, sig->name, data, line);

Yalu Zhang
committed
return res;
//---------------------------------------------------------------------------------------------------
// Reception of a create connection request from Asterisk. If line type is DECT, we need to relay the
// request to the dectmngr.
int line_new_connection_by_asterisk(int line, int connection, struct voice_ubus_req_t *ubus_req)
{

Yalu Zhang
committed
struct line_req_t *line_req;
if (!voice_line_is_ready(line))
return -1;
ENDPT_DBG("%s line: %d, connection: %d\n", __func__, line, connection);
pcm_states_dump(__func__, line);
if (get_callid_state(lines[line].pcm_callid[PCM_0]) == CALLID_OBTAINING)
lines[line].pcm_callid[PCM_0] = connection;
else if (get_callid_state(lines[line].pcm_callid[PCM_1]) == CALLID_OBTAINING)
lines[line].pcm_callid[PCM_1] = connection;
if (lines[line].type == VOICE_LINE_DECT) {
if (voice_line_is_offhook(line) || voice_line_get_connection_count(line) > 0) {
/* dectmngr already has audio streaming, now libvoice and Asterisk should do the same. */
} else {
/* Relay request to dectmngr by putting the request in a queue, where it will wait until we get a
* chance to relay it to dectmngr. */

Yalu Zhang
committed
line_req = calloc(1, sizeof(struct line_req_t));
ENDPT_ERR("%s: out of memory\n", __func__);

Yalu Zhang
committed
line_req->line = line;
line_req->connection_id = line;
line_req->pcm_id = lines[line].pcm_callid[PCM_0] == connection ? PCM_0 : PCM_1;

Yalu Zhang
committed
line_req->action = ACTION_CONN_CREATE;
memcpy(&line_req->ubus, ubus_req, sizeof(struct voice_ubus_req_t));
if (ubus_queue_req_to_dectmngr(line_req) || ubus_process_queued_reqs_to_dectmngr())
return -1;
ubus_defer_request(line_req->ubus.ctx, line_req->ubus.reqIn, &line_req->ubus.reqOut);

Yalu Zhang
committed
line_req->ubus.reqIn = NULL; // Deny further use of input request
res = voice_connection_create(line, line);
}
return res;
}
//---------------------------------------------------------------------------------------------------
// Reception of a connection parameter update request from Asterisk.
int line_connection_parm_update_by_asterisk(int line, int connection, struct config_update_struct *data) {
int res = 0;
if (!voice_line_is_ready(line))
return -1;
ENDPT_DBG("parm_update request for line: %d, connection: %d, mask: %d, codec: %d, ptime: %d, dtmf_mode: %d \n", line, connection, data->mask, data->codec, data->ptime, data->dtmf_mode);
pcm_states_dump(__func__, line);
res = voice_connection_parm_update(line, line, data);
return res;
}
//------------------------------------------------------------------------------------------------------------
// Reception of a close connection request from Asterisk. If line type is DECT we need to relay the request to
// dectmngr.
int line_close_connection_by_asterisk(int line, int connection, struct voice_ubus_req_t *ubus_req)
{

Yalu Zhang
committed
struct line_req_t *line_req;
if (!voice_line_is_ready(line))
return -1;
ENDPT_DBG("%s line: %d, connection: %d\n", __func__, line, connection);
pcm_states_dump(__func__, line);
if (get_callid_state(lines[line].pcm_callid[PCM_0]) == CALLID_INVALID &&
get_callid_state(lines[line].pcm_callid[PCM_1]) == CALLID_INVALID) {
return voice_connection_close(line, line);
}
switch(lines[line].type) {
case VOICE_LINE_DECT:
/* Put the request in a queue, where it will wait
* until we get a chanse to relay it to dectmngr. */

Yalu Zhang
committed
line_req = calloc(1, sizeof(struct line_req_t));
if(!line_req) return -1;
line_req->line = line;
line_req->connection_id = line;
if (get_callid_state(lines[line].pcm_callid[PCM_0]) == CALLID_ESTABLISHED &&
get_callid_state(lines[line].pcm_callid[PCM_1]) == CALLID_INVALID) {

Yalu Zhang
committed
line_req->pcm_id = PCM_0;
lines[line].pcm_callid[PCM_0] = CALLID_INVALID;
} else if (get_callid_state(lines[line].pcm_callid[PCM_1]) == CALLID_ESTABLISHED &&
get_callid_state(lines[line].pcm_callid[PCM_0]) == CALLID_INVALID) {

Yalu Zhang
committed
line_req->pcm_id = PCM_1;
lines[line].pcm_callid[PCM_1] = CALLID_INVALID;

Yalu Zhang
committed
line_req->action = ACTION_CONN_CLOSE;
if (connection == -1) {
ENDPT_DBG("Set line_req->pcm_id to -1 for releasing all calls on the extension %d\n", line);
line_req->pcm_id = connection;
}

Yalu Zhang
committed
memcpy(&line_req->ubus, ubus_req, sizeof(struct voice_ubus_req_t));
if(ubus_queue_req_to_dectmngr(line_req) || ubus_process_queued_reqs_to_dectmngr())

Yalu Zhang
committed
ubus_defer_request(line_req->ubus.ctx, line_req->ubus.reqIn, &line_req->ubus.reqOut);
line_req->ubus.reqIn = NULL; // Deny further use of input request
if (get_callid_state(lines[line].pcm_callid[PCM_0]) == CALLID_ESTABLISHED)
lines[line].pcm_callid[PCM_0] = CALLID_INVALID;
else if (get_callid_state(lines[line].pcm_callid[PCM_1]) == CALLID_ESTABLISHED)
lines[line].pcm_callid[PCM_1] = CALLID_INVALID;
return voice_connection_close(line, line);
}
return 0;
}
int line_release_connection_by_asterisk(int line, int connection, struct voice_ubus_req_t *ubus_req)
{

Yalu Zhang
committed
struct line_req_t *line_req;
if (!voice_line_is_ready(line))
return -1;
ENDPT_DBG("%s line: %d connection: %d\n", __func__, line, connection);
pcm_states_dump(__func__, line);
// during start of call conference asterisk removes 1 of connection, we skip
// it because voicemngr<->dectmngr needs to keep it active
if (lines[line].conference_started == 1) {
lines[line].conference_started = 0;
if (get_callid_state(lines[line].pcm_callid[PCM_0]) < CALLID_ESTABLISHED &&
get_callid_state(lines[line].pcm_callid[PCM_1]) < CALLID_ESTABLISHED) {
if (lines[line].pcm_callid[PCM_0] != connection && lines[line].pcm_callid[PCM_1] != connection) {
switch(lines[line].type) {
case VOICE_LINE_DECT:
/* Put the request in a queue, where it will wait
* until we get a chanse to relay it to dectmngr. */

Yalu Zhang
committed
line_req = calloc(1, sizeof(struct line_req_t));
if(!line_req) return -1;
line_req->line = line;
line_req->connection_id = line;
if (lines[line].pcm_callid[PCM_0] == connection) {

Yalu Zhang
committed
line_req->pcm_id = PCM_0;
lines[line].pcm_callid[PCM_0] = CALLID_INVALID;
} else if (lines[line].pcm_callid[PCM_1] == connection) {

Yalu Zhang
committed
line_req->pcm_id = PCM_1;
lines[line].pcm_callid[PCM_1] = CALLID_INVALID;

Yalu Zhang
committed
line_req->action = ACTION_CONN_CLOSE;
memcpy(&line_req->ubus, ubus_req, sizeof(struct voice_ubus_req_t));
if(ubus_queue_req_to_dectmngr(line_req) || ubus_process_queued_reqs_to_dectmngr())

Yalu Zhang
committed
ubus_defer_request(line_req->ubus.ctx, line_req->ubus.reqIn, &line_req->ubus.reqOut);
line_req->ubus.reqIn = NULL; // Deny further use of input request
if (lines[line].pcm_callid[PCM_0] == connection)
lines[line].pcm_callid[PCM_0] = CALLID_INVALID;
else if (lines[line].pcm_callid[PCM_1] == connection)
lines[line].pcm_callid[PCM_1] = CALLID_INVALID;
return voice_connection_close(line, line);
}
return 0;
}
int line_update_connection_by_pbx(int line, int pcm_callid)
{
if (!voice_line_is_ready(line))
return -1;
ENDPT_DBG("Received update connection for line: %d with pcm_callid: %d\n", line, pcm_callid);
pcm_states_dump(__func__, line);
if(lines[line].type != VOICE_LINE_DECT)
return 0;
if (get_callid_state(lines[line].pcm_callid[PCM_0]) == CALLID_OBTAINING)
lines[line].pcm_callid[PCM_0] = pcm_callid;
else if (get_callid_state(lines[line].pcm_callid[PCM_1]) == CALLID_OBTAINING)
lines[line].pcm_callid[PCM_1] = pcm_callid;
return 0;
}
//-------------------------------------------------------------
// Reception of a create connection request from dectmngr.
// Generate a off-hook event and queue the request
// until Asterisk acknowledge the offh-ook event.
Lukasz Kotasa
committed
int line_new_connection_by_dect(int line, const char *cid, int pcm, struct voice_ubus_req_t *ubus_req)
{

Yalu Zhang
committed
struct line_req_t *line_req;

Yalu Zhang
committed
if (!voice_line_is_ready(line) || lines[line].type != VOICE_LINE_DECT)
ENDPT_DBG("line=%d, pcm=%d, cid=%s\n", line, pcm, cid);
pcm_states_dump(__func__, line);
if (pcm == PCM_0 || pcm == PCM_1) {
lines[line].pcm_callid[pcm] = CALLID_OBTAINING;
lines[line].signaled_call_waiting = 0;

Yalu Zhang
committed
if (!voice_line_is_offhook(line)) {
if (voice_line_simulate_hook(line, VOICE_EVT_OFFHOOK))
return -1;
} else {
if (send_dect_event_to_asterisk(line, dect_event_map[DECT_EVT_SWITCH]))
if (send_dect_event_to_asterisk(line, dect_event_map[DECT_EVT_JOIN]))
if (simulate_digits_pressing(line, cid) == -1)
/* Store the ubus request in a queue. It will be picked up
* later, via the Asterisk ubus answer handler. */

Yalu Zhang
committed
line_req = calloc(1, sizeof(struct line_req_t));

Yalu Zhang
committed
if (!line_req) return -1;

Yalu Zhang
committed
line_req->line = line;
line_req->connection_id = -1;
line_req->action = ACTION_CONN_CREATE;
memcpy(&line_req->ubus, ubus_req, sizeof(struct voice_ubus_req_t));

Yalu Zhang
committed
if (ubus_queue_req_to_asterisk(line_req)) {

Yalu Zhang
committed
free(line_req);

Yalu Zhang
committed
ubus_defer_request(line_req->ubus.ctx, line_req->ubus.reqIn, &line_req->ubus.reqOut);
line_req->ubus.reqIn = NULL; // Deny further use of input request
return 0;
}
//-------------------------------------------------------------
// Reception of a close connection request from dectmngr.
// Generate a libvoip onhook event and queue the request
// until Asterisk acknowledge the onhook event.
int line_close_connection_by_dect(int line, int pcm, struct voice_ubus_req_t *ubus_req)
{

Yalu Zhang
committed
struct line_req_t *line_req;
if (!voice_line_is_ready(line))
if(lines[line].type != VOICE_LINE_DECT) {
ENDPT_ERR("%s: lines[%d].type != VOICE_LINE_DECT\n", __func__, line);
ENDPT_DBG("line %d: pcm = %d\n", line, pcm);
pcm_states_dump(__func__, line);
ENDPT_DBG("There is no available DECT handsets for the call. "
"Send DECT_UNAVAILABLE event to Asterisk\n");
msg = malloc(sizeof(struct line_event_t));
if (msg) {
msg->name = "DECT_UNAVAILABLE";
msg->data = 0;
msg->line = line;
send_event_main(msg, EVENT_MAIN_LINE);
}
return send_reply_dectmngr(ubus_req, line + 1, // +1 Dectmngr lines starting from 1
pcm, UBUS_STATUS_OK);
if ((pcm & 0xFFFF) == CALL_REJECT && ((pcm >> 16) == CALL_DEFAULT0 || (pcm >> 16) == CALL_DEFAULT1)) {
if (get_callid_state(lines[line].pcm_callid[(pcm >> 16)]) == CALLID_OBTAINING) {
struct line_event_t *msg;
ENDPT_DBG("DECT handsets may have not answered the call yet. "
"Send CALL_REJECT event to Asterisk\n");
msg = malloc(sizeof(struct line_event_t));
if (msg) {
msg->name = "CALL_REJECT";
msg->data = 0;
msg->line = line;
send_event_main(msg, EVENT_MAIN_LINE);
}
return send_reply_dectmngr(ubus_req, line + 1, // +1 Dectmngr lines starting from 1
pcm, UBUS_STATUS_OK);
} else {
pcm = pcm >> 16;
}
if(get_callid_state(lines[line].pcm_callid[PCM_0]) <= CALLID_OBTAINING ||
get_callid_state(lines[line].pcm_callid[PCM_1]) <= CALLID_OBTAINING) {
if(pcm == CALL_DEFAULT0 || pcm == CALL_DEFAULT1) {
lines[line].pcm_callid[pcm] = CALLID_INVALID;
if (get_callid_state(lines[line].pcm_callid[1-pcm]) == CALLID_OBTAINING) {
lines[line].pcm_callid[1-pcm] = CALLID_INVALID;
}
}
voice_line_simulate_hook(line, VOICE_EVT_ONHOOK);
return send_reply_dectmngr(ubus_req, line + 1, // +1 Dectmngr lines starting from 1
pcm, UBUS_STATUS_OK);
if(pcm == CALL_DEFAULT0 || pcm == CALL_DEFAULT1)
lines[line].pcm_callid[pcm] = CALLID_INVALID;
if(send_dect_event_to_asterisk(line, dect_event_map[DECT_EVT_RELEASE]))
return -1;
/* Store the request in a queue. It will be picked up
* later, via the Asterisk ubus answer handler. */

Yalu Zhang
committed
line_req = calloc(1, sizeof(struct line_req_t));
if(!line_req) return -1;
line_req->line = line;
line_req->connection_id = -1;
line_req->action = ACTION_CONN_CLOSE;
memcpy(&line_req->ubus, ubus_req, sizeof(struct voice_ubus_req_t));
if(ubus_queue_req_to_asterisk(line_req)) {
free(line_req);

Yalu Zhang
committed
ubus_defer_request(line_req->ubus.ctx, line_req->ubus.reqIn, &line_req->ubus.reqOut);
line_req->ubus.reqIn = NULL;