diff --git a/libvoice/common.c b/libvoice/common.c index f75cdd43852e439bb0e335f5ed536e6a5d40add4..210eeff0801bdcc9b91e840783232cc6c4e78225 100644 --- a/libvoice/common.c +++ b/libvoice/common.c @@ -52,9 +52,13 @@ const struct voice_signal_t signal_map[] = { // List of signals requested by Ast { .name = "callwt", .signal = VOICE_SIG_CALL_WAITING }, { .name = "busy", .signal = VOICE_SIG_BUSY }, { .name = "ringing", .signal = VOICE_SIG_RINGING }, + { .name = "ringing_int", .signal = VOICE_SIG_RINGING_INTERNAL }, { .name = "callid_ringing", .signal = VOICE_SIG_CALLID_RINGING }, + { .name = "callid_ringing_int", .signal = VOICE_SIG_CALLID_RINGING_INTERNAL }, { .name = "callid", .signal = VOICE_SIG_CALLID }, { .name = "congestion", .signal = VOICE_SIG_NETBUSY }, + { .name = "positive", .signal = VOICE_SIG_POSITIVE }, + { .name = "negative", .signal = VOICE_SIG_NEGATIVE }, { .name = "dtmf0", .signal = VOICE_SIG_DTMF0 }, { .name = "dtmf1", .signal = VOICE_SIG_DTMF1 }, { .name = "dtmf2", .signal = VOICE_SIG_DTMF2 }, @@ -78,7 +82,7 @@ const struct voice_signal_t signal_map[] = { // List of signals requested by Ast }; // Callback function which is invoked when an event is detected from the voice engine -void (*voice_cb_event_report)(int line, const char *event, int data) = NULL; +void (*voice_cb_event_report)(int line, const char *event, const char *data) = NULL; // Callback function which is invoked when an encoded media packet is generated by the voice engine void (*voice_cb_egress_media)(const struct media_packet_t *packet, int size) = NULL; @@ -124,7 +128,9 @@ int voice_line_preinit(void) { lines[i].type = terminal_info.voice_ports[i]; ENDPT_DBG("lines[%d].type=%d\n", i, lines[i].type); lines[i].pcm_callid[PCM_0] = CALLID_INVALID; + ENDPT_DBG("line: %d set pcm_callid[%d] to %d\n", i, PCM_0, lines[i].pcm_callid[PCM_0]); lines[i].pcm_callid[PCM_1] = CALLID_INVALID; + ENDPT_DBG("line: %d set pcm_callid[%d] to %d\n", i, PCM_1, lines[i].pcm_callid[PCM_1]); } return 0; @@ -164,7 +170,7 @@ int voice_line_deinit(void) { } // Register the callback function for event report -int voice_register_cb_event_report(void (*cb_event_report)(int line, const char *event, int data)) { +int voice_register_cb_event_report(void (*cb_event_report)(int line, const char *event, const char *data)) { voice_cb_event_report = cb_event_report; return 0; diff --git a/libvoice/libvoice.h b/libvoice/libvoice.h index 3a704831573eab99a4bd2acbc3803c54115b0ce7..9f64f4828db976b3b06826282fdcda089695ecc8 100644 --- a/libvoice/libvoice.h +++ b/libvoice/libvoice.h @@ -13,17 +13,26 @@ #include <libpicoevent.h> #include "voice-types.h" -#define MAX_CALLER_ID_LEN 120 // Max length of caller id string we accept +#define MIN_CALLER_ID_LEN 14 // Minimum string length to be valid. +#define MAX_CALLER_ID_LEN (CLID_MAX_DATE + CLID_MAX_NUMBER + CLID_MAX_NAME + 3 + 5) // Max length of caller id string +#define CLID_TIME_DELIM 8 // String index where time record ends. +#define CLID_NUMB_REC (CLID_TIME_DELIM + 2) // String index where number starts. + #define MAX_KEYPAD_DIGITS 100 // Max number of simulated keypad presses we accept #define MAX_CODECS 20 #define MAX_CODEC_NAMELEN 20 -#define MIN_CALLER_ID_LEN 14 // Minimum string length to be valid. -#define CLID_TIME_DELIM 8 // String index where time record ends. -#define CLID_NUMB_REC CLID_TIME_DELIM + 2 // String index where number starts. -#define MAX_CALLER_NAME 60 // Max length of caller's name to be displayed on the DECT handset #define DEBUG_LOOPBACK 0 // Debug - feed received audio back to transmitter +enum PAGING_STATUS +{ + PAGING_IDLE, + PAGING_IN_PROGRESS, + PAGING_SUCCESS, + PAGING_NOT_IN_REACH, + PAGING_TIMEOUT +}; + enum VOICE_EVENT { VOICE_EVT_START, @@ -75,7 +84,9 @@ enum VOICE_SIGNAL { VOICE_SIG_CALL_WAITING, VOICE_SIG_BUSY, VOICE_SIG_RINGING, + VOICE_SIG_RINGING_INTERNAL, VOICE_SIG_CALLID_RINGING, + VOICE_SIG_CALLID_RINGING_INTERNAL, VOICE_SIG_CALLID, VOICE_SIG_NETBUSY, VOICE_SIG_DTMF0, @@ -97,6 +108,8 @@ enum VOICE_SIGNAL { VOICE_SIG_INGRESS_DTMF, // Simulate phone keypad button pressing VOICE_SIG_ANSWER, VOICE_SIG_K_BREAK, + VOICE_SIG_POSITIVE, + VOICE_SIG_NEGATIVE, VOICE_SIG_LAST }; @@ -142,6 +155,10 @@ struct line_t { uint16_t conference_started; // True if conference has just been setup by DECT handset int pcm_callid[2]; // -1: Invalid, 0: Obtaining, >0: Established pe_list_t *pending_digits; // List of keypad digits waiting to be sent + enum PAGING_STATUS paging_status; // Line's paging status +#define VOICEMNGR_LINE_FLAG_NARROW_BAND_ONLY 0x1 +#define VOICEMNGR_LINE_FLAG_OVERLAP_DIALING 0x2 + uint32_t flags; void *priv; // Platform dependent data }; @@ -212,33 +229,40 @@ struct codec_capability { } codecs[MAX_CODECS]; }; -#define ENABLE_VOICE_DEBUG 0 // Enable/disable voice debug +#define ENABLE_VOICE_DEBUG 1 // Enable/disable voice debug #if ENABLE_VOICE_DEBUG // log to file -#define ENDPT_DBG(fmt, ...) do { \ - FILE *fp = fopen("/tmp/voicemngr.log", "a"); \ - if (fp) { \ - struct timeval tv_now; \ - struct tm tm_now; \ - gettimeofday(&tv_now, NULL); \ - localtime_r(&tv_now.tv_sec, &tm_now); \ - fprintf(fp, "%04d-%02d-%02d %02d:%02d:%02d.%03d %s()@%s:%d: " fmt, \ - 1900 + tm_now.tm_year, tm_now.tm_mon + 1, tm_now.tm_mday, \ - tm_now.tm_hour, tm_now.tm_min, tm_now.tm_sec, (int)(tv_now.tv_usec / 1000), \ - __func__, __FILE__, __LINE__, ##__VA_ARGS__); \ - fclose(fp); \ - } \ - printf(fmt, ##__VA_ARGS__); \ - } while (0) +#define ENDPT_LOG(level, fmt, ...) do { \ + FILE *fp = fopen("/tmp/voicemngr.log", "a"); \ + if (fp) { \ + struct timeval tv_now; \ + struct tm tm_now; \ + gettimeofday(&tv_now, NULL); \ + localtime_r(&tv_now.tv_sec, &tm_now); \ + fprintf(fp, "%04d-%02d-%02d %02d:%02d:%02d.%03d [%s] %s()@%s:%d: " fmt, \ + 1900 + tm_now.tm_year, tm_now.tm_mon + 1, tm_now.tm_mday, \ + tm_now.tm_hour, tm_now.tm_min, tm_now.tm_sec, (int)(tv_now.tv_usec / 1000), \ + level, __func__, __FILE__, __LINE__, ##__VA_ARGS__); \ + fclose(fp); \ + } \ + printf(fmt, ##__VA_ARGS__); \ +} while (0) + +#define ENDPT_DBG(fmt, ...) ENDPT_LOG("DEBUG", fmt, ##__VA_ARGS__) +#define ENDPT_INFO(fmt, ...) ENDPT_LOG("INFO ", fmt, ##__VA_ARGS__) +#define ENDPT_WARN(fmt, ...) ENDPT_LOG("WARN ", fmt, ##__VA_ARGS__) +#define ENDPT_ERR(fmt, ...) ENDPT_LOG("ERROR", fmt, ##__VA_ARGS__) #else #define ENDPT_DBG(format, ...) voice_syslog(LOG_DEBUG, "%s:%d %s: " format, \ - __FILE__, __LINE__, __func__, ##__VA_ARGS__) -#endif -#define CHECK_POINT() ENDPT_DBG("Check point at %s@%s:%d\n", __func__, __FILE__, __LINE__) - + __FILE__, __LINE__, __func__, ##__VA_ARGS__) #define ENDPT_INFO(...) voice_syslog(LOG_INFO, __VA_ARGS__) #define ENDPT_WARN(...) voice_syslog(LOG_WARNING, __VA_ARGS__) #define ENDPT_ERR(...) voice_syslog(LOG_ERR, __VA_ARGS__) +#endif /* ENABLE_VOICE_DEBUG */ + +#define CHECK_POINT() ENDPT_DBG("Check point\n") + + extern struct terminal_info_t terminal_info; extern struct line_t *lines; @@ -248,7 +272,7 @@ extern const struct voice_event_t event_map[]; extern const struct dect_event_t dect_event_map[]; extern const struct voice_signal_t signal_map[]; -extern void (*voice_cb_event_report)(int line, const char *event, int data); +extern void (*voice_cb_event_report)(int line, const char *event, const char *data); extern void (*voice_cb_egress_media)(const struct media_packet_t *packet, int size); @@ -284,7 +308,7 @@ void voice_hook_simulation_maintain(int line); int voice_get_rtp_stats(int line, int connection, int reset, struct rtp_stats_t *rtp_stats); int voice_get_codec_capability(struct codec_capability *pcodecs); int voice_set_country(const char *country_code); -int voice_register_cb_event_report(void (*voice_cb_event_report)(int line, const char *event, int data)); +int voice_register_cb_event_report(void (*voice_cb_event_report)(int line, const char *event, const char *data)); int voice_register_cb_egress_media(void (*cb_egress_media)(const struct media_packet_t *packet, int size)); int voice_write_media_packet(const struct media_packet_t *packet); diff --git a/libvoice/voice-types.h b/libvoice/voice-types.h index 74cfb67b65604e11ecf3359af1401ad14f665add..b278447c1a36c22fd91c034b450b2b48a4d14a8b 100644 --- a/libvoice/voice-types.h +++ b/libvoice/voice-types.h @@ -68,6 +68,21 @@ enum call_action { CALL_LAST }; +typedef enum flash_spec { + FLASH_SPEC_UK = 0, + FLASH_SPEC_ETSI, +} flash_spec; + +// The possible values of DECTMNGR_RPC_PARAM_HANGUPCAUSE +enum hangup_cause { + HANGUPCAUSE_UNANSWERED = 0, + HANGUPCAUSE_ANSWERED_ELSEWERE, +}; + +#define CLID_MAX_DATE 10 +#define CLID_MAX_NUMBER 30 +#define CLID_MAX_NAME 60 + /* * UBUS related definitions */ @@ -79,5 +94,8 @@ enum call_action { // Parameters #define DECTMNGR_RPC_PARAM_EXTENSION_ID "extension_id" #define DECTMNGR_RPC_PARAM_PCM_ID "pcm_id" +#define DECTMNGR_RPC_PARAM_HANGUPCAUSE "hangupcause" +// Parameter values +#define EVENT_DATA_NARROW_BAND_ONLY "narrow_band_only" #endif diff --git a/line-dect.c b/line-dect.c index af839a8939322271bda3276ff7800615d2811256..3738cc6b18c0d0bc39fcf00fcf21ee15436bccd9 100644 --- a/line-dect.c +++ b/line-dect.c @@ -111,7 +111,7 @@ int ubus_process_queued_reqs_to_dectmngr(void) { switch (req->action) { case ACTION_CONN_CREATE: case ACTION_SIG_RING: - if(ubus_call_dectmngr(voicemngr_line_to_dectmngr_line(req->line), 1, 0, req->caller_id, req->caller_name, req->pcm_id, req)) { + if(ubus_call_dectmngr(voicemngr_line_to_dectmngr_line(req->line), 1, 0, req->caller_id, req->caller_name, req->sip_client_id, req->pcm_id, req)) { free(req); return -1; } @@ -123,7 +123,16 @@ int ubus_process_queued_reqs_to_dectmngr(void) { return 0; } // ACTION_CONN_CLOSE: could not just skip due to compile warning is treated as error. - if(ubus_call_dectmngr(voicemngr_line_to_dectmngr_line(req->line), 0, 1, req->caller_id, req->caller_name, req->pcm_id, req)) { + if(ubus_call_dectmngr(voicemngr_line_to_dectmngr_line(req->line), 0, 1, req->caller_id, req->caller_name, req->sip_client_id, req->pcm_id, req)) { + free(req); + return -1; + } + break; + case ACTION_RINGING_STOP: + dectmngr_rpc.action = req->action; + dectmngr_rpc.extension_id = voicemngr_line_to_dectmngr_line(req->line); + dectmngr_rpc.params.hangupcause = req->hangupcause; + if(ubus_dectmngr_rpc(&dectmngr_rpc, req)) { free(req); return -1; } @@ -146,13 +155,13 @@ int ubus_process_queued_reqs_to_dectmngr(void) { } break; case ACTION_SIG_BUSY_TONE: - if(ubus_call_dectmngr(voicemngr_line_to_dectmngr_line(req->line), 0, 2, req->caller_id, req->caller_name, req->pcm_id, req)) { + if(ubus_call_dectmngr(voicemngr_line_to_dectmngr_line(req->line), 0, 2, req->caller_id, req->caller_name, req->sip_client_id, req->pcm_id, req)) { free(req); return -1; } break; case ACTION_SIG_ANSWERED: - if(ubus_call_dectmngr(voicemngr_line_to_dectmngr_line(req->line), 2, 0, req->caller_id, req->caller_name, req->pcm_id, req)) { + if(ubus_call_dectmngr(voicemngr_line_to_dectmngr_line(req->line), 2, 0, req->caller_id, req->caller_name, req->sip_client_id, req->pcm_id, req)) { free(req); return -1; } @@ -179,6 +188,12 @@ int simulate_digits_pressing(int line, const char *pressed_digits) { if(lines[line].type != VOICE_LINE_DECT) return 0; + if (!pressed_digits) { + ENDPT_DBG("line: %d overlap dialing\n", line); + lines[line].flags |= VOICEMNGR_LINE_FLAG_OVERLAP_DIALING; + return 0; + } + ENDPT_DBG("line: %d pressed_digits: %s\n", line, (pressed_digits ? pressed_digits : "")); // Store digits in a list. @@ -215,6 +230,8 @@ int ubus_cb_dectmngr_replied(struct line_req_t *req, enum ubus_msg_status reply_ if(!req) return -1; + struct line_t *line = &lines[req->line]; + ENDPT_DBG("got answer req %p from dectmngr, action: %d, line: %d, pcmId: %d, conId: %d\n", req, req->action, req->line, req->pcm_id, req->connection_id); pcm_states_dump(__func__, req->line); @@ -225,28 +242,40 @@ int ubus_cb_dectmngr_replied(struct line_req_t *req, enum ubus_msg_status reply_ reply_status = UBUS_STATUS_UNKNOWN_ERROR; } break; - case ACTION_CONN_CLOSE: case ACTION_RINGING_STOP: - if (req->pcm_id == PCM_0 || req->pcm_id == PCM_1) { - lines[req->line].pcm_callid[req->pcm_id] = CALLID_INVALID; + if (get_callid_state(line->pcm_callid[req->pcm_id]) == CALLID_ESTABLISHED) + break; // Don't clear if call is already established + // intentional fallthrough + case ACTION_CONN_CLOSE: + if (is_valid_pcm_id(req->pcm_id)) { + line->pcm_callid[req->pcm_id] = CALLID_INVALID; + ENDPT_DBG("line: %d set pcm_callid[%d] to %d\n", req->line, req->pcm_id, line->pcm_callid[req->pcm_id]); } else if (req->pcm_id == -1) { - // Close all calls - lines[req->line].pcm_callid[PCM_0] = CALLID_INVALID; - lines[req->line].pcm_callid[PCM_1] = CALLID_INVALID; + // Clear both PCM slots + for (int i = 0; i <= PCM_1; ++i) { + line->pcm_callid[i] = CALLID_INVALID; + ENDPT_DBG("line: %d set pcm_callid[%d] to %d\n", req->line, i, CALLID_INVALID); + } + } + // If no established calls left, close connection + if (get_callid_state(line->pcm_callid[PCM_0]) != CALLID_ESTABLISHED && + get_callid_state(line->pcm_callid[PCM_1]) != CALLID_ESTABLISHED) { + reply_status = voice_connection_close(req->line, req->line) + ? UBUS_STATUS_UNKNOWN_ERROR + : UBUS_STATUS_OK; } - if (get_callid_state(lines[req->line].pcm_callid[PCM_0]) == CALLID_ESTABLISHED || - get_callid_state(lines[req->line].pcm_callid[PCM_1]) == CALLID_ESTABLISHED) - break; - reply_status = voice_connection_close(req->line, req->line) ? // Close regardless of any dectmngr error. - UBUS_STATUS_UNKNOWN_ERROR : UBUS_STATUS_OK; break; case ACTION_SIG_RING: - if ((req->pcm_id == PCM_0 && get_callid_state(lines[req->line].pcm_callid[PCM_1]) == CALLID_OBTAINING) || - (req->pcm_id == PCM_1 && get_callid_state(lines[req->line].pcm_callid[PCM_0]) == CALLID_OBTAINING)) - break; - if (req->pcm_id == PCM_0 || req->pcm_id == PCM_1) - lines[req->line].pcm_callid[req->pcm_id] = CALLID_OBTAINING; + { + int other_pcm = (req->pcm_id == PCM_0) ? PCM_1 : PCM_0; + if (is_valid_pcm_id(req->pcm_id)) { + if (get_callid_state(line->pcm_callid[other_pcm]) != CALLID_OBTAINING) { + line->pcm_callid[req->pcm_id] = CALLID_OBTAINING; + ENDPT_DBG("line: %d set pcm_callid[%d] to %d\n", req->line, req->pcm_id, CALLID_OBTAINING); + } + } break; + } default: break; } diff --git a/line.c b/line.c index 5cb22034e988106582e8b5da2eb2ff2234571e3b..5d93e96f83417a66b30cfca366472010b66ef854 100644 --- a/line.c +++ b/line.c @@ -44,13 +44,18 @@ callid_state get_callid_state(int call_id) { return CALLID_ESTABLISHED; } +bool is_valid_pcm_id(int id) +{ + return id == PCM_0 || id == PCM_1; +} + 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->data = NULL; msg->line = line; ubus_call_asterisk(msg); @@ -83,7 +88,7 @@ static int perhaps_simulate_busy(int line, struct voice_ubus_req_t *ubus_req) msg = malloc(sizeof(struct line_event_t)); if (msg) { msg->name = ev->name; - msg->data = 0; + msg->data = NULL; msg->line = line; send_event_main(msg, EVENT_MAIN_LINE); } else { @@ -94,7 +99,7 @@ static int perhaps_simulate_busy(int line, struct voice_ubus_req_t *ubus_req) } //---------------------------------------------------------------------------------- // 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) +/*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); @@ -131,23 +136,52 @@ static int dect_tone_play(int line, int pcm, enum VOICE_SIGNAL signal, const cha line_req->ubus.reqIn = NULL; return 0; -} +}*/ -static void setCallerName(const char *data, char *callerName) +static void setCLIDinfo(const char *data, struct line_req_t *line_req) { - char *start; + if (!data || !line_req) { + return; + } - 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'; + size_t data_len = strlen(data); + char cid_tmp[data_len + 1]; + + strcpy(cid_tmp, data); + char* ptr = cid_tmp; + + // Initialize struct fields to empty strings + line_req->caller_id[0] = '\0'; + line_req->caller_name[0] = '\0'; + + char *token = strtok_r(cid_tmp, ", ", &ptr); // Skip the first field (date) + if (!token) return; + + token = strtok_r(NULL, ", ", &ptr); // Extract Caller ID + if (token) { + strncpy(line_req->caller_id, token, sizeof(line_req->caller_id) - 1); + line_req->caller_id[sizeof(line_req->caller_id) - 1] = '\0'; + } + + token = strtok_r(NULL, ",", &ptr); // Extract Caller Name (quoted, may be empty) + if (token) { + // Check if it's enclosed in quotes + if (token[0] == '"') { + token++; // Move past opening quote + char *end_quote = strchr(token, '"'); + if (end_quote) { + *end_quote = '\0'; // Terminate at closing quote + } } + if (strlen(token) > 0) { // Only copy if non-empty + strncpy(line_req->caller_name, token, sizeof(line_req->caller_name) - 1); + line_req->caller_name[sizeof(line_req->caller_name) - 1] = '\0'; + } + } + + token = strtok_r(NULL, ", ", &ptr); // Extract Line Number + if (token) { + line_req->sip_client_id = atoi(token); } } @@ -156,9 +190,9 @@ static void setCallerName(const char *data, char *callerName) static int line_signal_ring(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; - int start_ring = data && strcmp(data, "0") != 0; + int start_ring = data && strcmp(data, "0") != 0 && strcmp(data, "answered") != 0; - ENDPT_DBG("line=%d, pcm=%d, data=%s\n", line, pcm, data); + ENDPT_DBG("line=%d, pcm=%d, data=%s, start_ring: %d\n", line, pcm, data, start_ring); pcm_states_dump(__func__, line); // Relay the request to dectmngr if the line is DECT @@ -178,13 +212,7 @@ static int line_signal_ring(int line, int pcm, enum VOICE_SIGNAL signal, const c // Parse the called ID string generated by Asterisk if(data && strlen(data) >= MIN_CALLER_ID_LEN && strlen(data) <= MAX_CALLER_ID_LEN && data[CLID_TIME_DELIM] == ',' && data[CLID_NUMB_REC + 1] != ',') { - char cid_tmp[strlen(data) + 1], *end; - - 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); + setCLIDinfo(data, line_req); } } @@ -199,10 +227,12 @@ static int line_signal_ring(int line, int pcm, enum VOICE_SIGNAL signal, const c break; case VOICE_SIG_RINGING: + case VOICE_SIG_RINGING_INTERNAL: case VOICE_SIG_CALLID_RINGING: + case VOICE_SIG_CALLID_RINGING_INTERNAL: if(line_req) { if(start_ring) { - if(signal == VOICE_SIG_CALLID_RINGING) { + if(signal == VOICE_SIG_CALLID_RINGING || VOICE_SIG_CALLID_RINGING_INTERNAL) { // Dect ignore this enable signal free(line_req); return 0; @@ -210,6 +240,10 @@ static int line_signal_ring(int line, int pcm, enum VOICE_SIGNAL signal, const c line_req->action = ACTION_SIG_RING; } else { line_req->action = ACTION_RINGING_STOP; + if (strcmp(data, "answered") == 0) + line_req->hangupcause = HANGUPCAUSE_ANSWERED_ELSEWERE; + else + line_req->hangupcause = HANGUPCAUSE_UNANSWERED; } line_req->caller_id[0] = 0; // Discard enable/disable char or it will become the caller ID } else { @@ -220,6 +254,10 @@ static int line_signal_ring(int line, int pcm, enum VOICE_SIGNAL signal, const c if(line_req) { if(!start_ring) { line_req->action = ACTION_RINGING_STOP; + if (strcmp(data, "answered") == 0) + line_req->hangupcause = HANGUPCAUSE_ANSWERED_ELSEWERE; + else + line_req->hangupcause = HANGUPCAUSE_UNANSWERED; } line_req->caller_id[0] = 0; // Discard enable/disable char or it will become the caller ID break; @@ -278,6 +316,7 @@ int line_signal(int line, const char *signame, const char *data, struct voice_ub { const struct voice_signal_t *sig; int res = 0; + int pcm = PCM_0; ENDPT_DBG("line=%d(type:%d), signame=%s, data=%s\n", line, lines[line].type, signame, data); @@ -294,15 +333,22 @@ int line_signal(int line, const char *signame, const char *data, struct voice_ub switch(sig->signal) { case VOICE_SIG_CALLID_RINGING: + case VOICE_SIG_CALLID_RINGING_INTERNAL: case VOICE_SIG_CALLID: case VOICE_SIG_RINGING: + case VOICE_SIG_RINGING_INTERNAL: if(atoi(data) == 0) { - 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); + if ( get_callid_state(lines[line].pcm_callid[PCM_0]) == CALLID_OBTAINING || + get_callid_state(lines[line].pcm_callid[PCM_0]) == CALLID_INVALID ) + pcm = PCM_0; + else + pcm = PCM_1; + + res = line_signal_ring(line, pcm, sig->signal, data, ubus_req); lines[line].signaled_call_waiting = 0; } else { - 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); + pcm = get_callid_state(lines[line].pcm_callid[PCM_0]) == CALLID_INVALID ? PCM_0 : PCM_1; + res = line_signal_ring(line, pcm, sig->signal, data, ubus_req); } break; @@ -313,20 +359,18 @@ int line_signal(int line, const char *signame, const char *data, struct voice_ub 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] != ',' && + 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); // start call waiting - 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); + pcm = get_callid_state(lines[line].pcm_callid[PCM_1]) == CALLID_INVALID ? PCM_1 : PCM_0; + res = line_signal_ring(line, pcm, VOICE_SIG_CALLID, data, ubus_req); lines[line].signaled_call_waiting = 1; - } else if(data && (data[0] == '0')) { + } else if(data && ((data[0] == '0') || (strcmp(data, "answered") == 0))) { // 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); + pcm = get_callid_state(lines[line].pcm_callid[PCM_1]) == CALLID_OBTAINING ? PCM_1 : PCM_0; + res = line_signal_ring(line, pcm, VOICE_SIG_CALL_WAITING, data, ubus_req); lines[line].signaled_call_waiting = 0; } } else { @@ -346,12 +390,10 @@ int line_signal(int line, const char *signame, const char *data, struct voice_ub 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){ + 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); - } + else + res = voice_line_signal(line, -1, sig->signal, atoi(data), NULL); } else { res = voice_line_signal(line, -1, sig->signal, atoi(data), NULL); } @@ -398,10 +440,14 @@ int line_new_connection_by_asterisk(int line, int connection, struct voice_ubus_ 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) + 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) + ENDPT_DBG("line: %d set pcm_callid[%d] to %d\n", line, PCM_0, lines[line].pcm_callid[PCM_0]); + } + else if (get_callid_state(lines[line].pcm_callid[PCM_1]) == CALLID_OBTAINING) { lines[line].pcm_callid[PCM_1] = connection; + ENDPT_DBG("line: %d set pcm_callid[%d] to %d\n", line, PCM_1, lines[line].pcm_callid[PCM_1]); + } if (lines[line].type == VOICE_LINE_DECT) { if (voice_line_is_offhook(line) || voice_line_get_connection_count(line) > 0) { @@ -477,10 +523,12 @@ int line_close_connection_by_asterisk(int line, int connection, struct voice_ubu get_callid_state(lines[line].pcm_callid[PCM_1]) == CALLID_INVALID) { line_req->pcm_id = PCM_0; lines[line].pcm_callid[PCM_0] = CALLID_INVALID; + ENDPT_DBG("line: %d set pcm_callid[%d] to %d\n", line, PCM_0, lines[line].pcm_callid[PCM_0]); } else if (get_callid_state(lines[line].pcm_callid[PCM_1]) == CALLID_ESTABLISHED && get_callid_state(lines[line].pcm_callid[PCM_0]) == CALLID_INVALID) { line_req->pcm_id = PCM_1; lines[line].pcm_callid[PCM_1] = CALLID_INVALID; + ENDPT_DBG("line: %d set pcm_callid[%d] to %d\n", line, PCM_1, lines[line].pcm_callid[PCM_1]); } line_req->action = ACTION_CONN_CLOSE; if (connection == -1) { @@ -495,10 +543,14 @@ int line_close_connection_by_asterisk(int line, int connection, struct voice_ubu break; default: - if (get_callid_state(lines[line].pcm_callid[PCM_0]) == CALLID_ESTABLISHED) + 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) + ENDPT_DBG("line: %d set pcm_callid[%d] to %d\n", line, PCM_0, lines[line].pcm_callid[PCM_0]); + } + else if (get_callid_state(lines[line].pcm_callid[PCM_1]) == CALLID_ESTABLISHED) { lines[line].pcm_callid[PCM_1] = CALLID_INVALID; + ENDPT_DBG("line: %d set pcm_callid[%d] to %d\n", line, PCM_1, lines[line].pcm_callid[PCM_1]); + } return voice_connection_close(line, line); } @@ -543,9 +595,11 @@ int line_release_connection_by_asterisk(int line, int connection, struct voice_u if (lines[line].pcm_callid[PCM_0] == connection) { line_req->pcm_id = PCM_0; lines[line].pcm_callid[PCM_0] = CALLID_INVALID; + ENDPT_DBG("line: %d set pcm_callid[%d] to %d\n", line, PCM_0, lines[line].pcm_callid[PCM_0]); } else if (lines[line].pcm_callid[PCM_1] == connection) { line_req->pcm_id = PCM_1; lines[line].pcm_callid[PCM_1] = CALLID_INVALID; + ENDPT_DBG("line: %d set pcm_callid[%d] to %d\n", line, PCM_1, lines[line].pcm_callid[PCM_1]); } line_req->action = ACTION_CONN_CLOSE; memcpy(&line_req->ubus, ubus_req, sizeof(struct voice_ubus_req_t)); @@ -556,10 +610,14 @@ int line_release_connection_by_asterisk(int line, int connection, struct voice_u break; default: - if (lines[line].pcm_callid[PCM_0] == connection) + 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) + ENDPT_DBG("line: %d set pcm_callid[%d] to %d\n", line, PCM_0, lines[line].pcm_callid[PCM_0]); + } + else if (lines[line].pcm_callid[PCM_1] == connection) { lines[line].pcm_callid[PCM_1] = CALLID_INVALID; + ENDPT_DBG("line: %d set pcm_callid[%d] to %d\n", line, PCM_1, lines[line].pcm_callid[PCM_1]); + } return voice_connection_close(line, line); } @@ -578,10 +636,14 @@ int line_update_connection_by_pbx(int line, int pcm_callid) if(lines[line].type != VOICE_LINE_DECT) return 0; - if (get_callid_state(lines[line].pcm_callid[PCM_0]) == CALLID_OBTAINING) + 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) + ENDPT_DBG("line: %d set pcm_callid[%d] to %d\n", line, PCM_0, lines[line].pcm_callid[PCM_0]); + } + else if (get_callid_state(lines[line].pcm_callid[PCM_1]) == CALLID_OBTAINING) { lines[line].pcm_callid[PCM_1] = pcm_callid; + ENDPT_DBG("line: %d set pcm_callid[%d] to %d\n", line, PCM_1, lines[line].pcm_callid[PCM_1]); + } return 0; } @@ -590,22 +652,29 @@ int line_update_connection_by_pbx(int line, int pcm_callid) // Reception of a create connection request from dectmngr. // Generate a off-hook event and queue the request // until Asterisk acknowledge the offh-ook event. -int line_new_connection_by_dect(int line, const char *cid, int pcm, struct voice_ubus_req_t *ubus_req) +int line_new_connection_by_dect(int line, const char *cid, int pcm, const char *data, struct voice_ubus_req_t *ubus_req) { struct line_req_t *line_req; if (!voice_line_is_ready(line) || lines[line].type != VOICE_LINE_DECT) return -1; - ENDPT_DBG("line=%d, pcm=%d, cid=%s\n", line, pcm, cid); + ENDPT_DBG("line=%d, pcm=%d, cid=%s, data=%s\n", line, pcm, cid, data ? data : "<null>"); pcm_states_dump(__func__, line); - if (pcm == PCM_0 || pcm == PCM_1) { + if (is_valid_pcm_id(pcm)) { lines[line].pcm_callid[pcm] = CALLID_OBTAINING; + ENDPT_DBG("line: %d set pcm_callid[%d] to %d\n", line, pcm, lines[line].pcm_callid[pcm]); lines[line].signaled_call_waiting = 0; } if (!voice_line_is_offhook(line)) { + if (data && strcmp(data, EVENT_DATA_NARROW_BAND_ONLY) == 0) { + lines[line].flags |= VOICEMNGR_LINE_FLAG_NARROW_BAND_ONLY; + ENDPT_DBG("The DECT handset which goes off hook supports narrow band only\n"); + } else { + lines[line].flags &= ~VOICEMNGR_LINE_FLAG_NARROW_BAND_ONLY; + } if (voice_line_simulate_hook(line, VOICE_EVT_OFFHOOK)) return -1; } else { @@ -672,7 +741,7 @@ int line_close_connection_by_dect(int line, int pcm, struct voice_ubus_req_t *ub msg = malloc(sizeof(struct line_event_t)); if (msg) { msg->name = "DECT_UNAVAILABLE"; - msg->data = 0; + msg->data = NULL; msg->line = line; send_event_main(msg, EVENT_MAIN_LINE); } @@ -691,7 +760,7 @@ int line_close_connection_by_dect(int line, int pcm, struct voice_ubus_req_t *ub msg = malloc(sizeof(struct line_event_t)); if (msg) { msg->name = "CALL_REJECT"; - msg->data = 0; + msg->data = NULL; msg->line = line; send_event_main(msg, EVENT_MAIN_LINE); } @@ -707,8 +776,10 @@ int line_close_connection_by_dect(int line, int pcm, struct voice_ubus_req_t *ub 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; + ENDPT_DBG("line: %d set pcm_callid[%d] to %d\n", line, pcm, lines[line].pcm_callid[pcm]); if (get_callid_state(lines[line].pcm_callid[1-pcm]) == CALLID_OBTAINING) { lines[line].pcm_callid[1-pcm] = CALLID_INVALID; + ENDPT_DBG("line: %d set pcm_callid[%d] to %d\n", line, 1-pcm, lines[line].pcm_callid[1-pcm]); } } voice_line_simulate_hook(line, VOICE_EVT_ONHOOK); @@ -716,8 +787,10 @@ int line_close_connection_by_dect(int line, int pcm, struct voice_ubus_req_t *ub pcm, UBUS_STATUS_OK); } - if(pcm == CALL_DEFAULT0 || pcm == CALL_DEFAULT1) + if(pcm == CALL_DEFAULT0 || pcm == CALL_DEFAULT1) { lines[line].pcm_callid[pcm] = CALLID_INVALID; + ENDPT_DBG("line: %d set pcm_callid[%d] to %d\n", line, pcm, lines[line].pcm_callid[pcm]); + } if(send_dect_event_to_asterisk(line, dect_event_map[DECT_EVT_RELEASE])) return -1; @@ -739,3 +812,28 @@ int line_close_connection_by_dect(int line, int pcm, struct voice_ubus_req_t *ub return 0; } + +//--------------------------------------------------------------- +// Return the paging status in string from the value of lines[line].paging_status +char *voice_line_get_paging_status(int line) +{ + if (line < 0 || line >= terminal_info.num_voice_ports) { + ENDPT_DBG("Line number %d is out of range\n", line); + return "Idle"; + } + + switch(lines[line].paging_status) + { + case PAGING_IN_PROGRESS: + return "InProgress"; + case PAGING_SUCCESS: + return "Success"; + case PAGING_NOT_IN_REACH: + return "Error_Not_In_Reach"; + case PAGING_TIMEOUT: + return "Error_TimeOut"; + case PAGING_IDLE: + default: + return "Idle"; + } +} diff --git a/line.h b/line.h index 64a212d4d744c8d305d47477a5a01c7b00436484..850fc9229ef12a58e3ebc43438a36aec58545438 100644 --- a/line.h +++ b/line.h @@ -19,9 +19,9 @@ enum line_action_t { // Event sent with UBUS when something has happened with a phone line struct line_event_t { - const char *name; // String communicated with Asterisk - int data; // True/false is a DTMF button is pressed/depressed - int line; // Line number + const char *name; // String communicated with Asterisk + const char *data; // Event specific data + int line; // Line number }; // Deferred UBUS request @@ -36,12 +36,14 @@ struct voice_ubus_req_t { struct line_req_t { int line; int pcm_id; - int connection_id; // Connection ID from Asterisk - enum line_action_t action; // The requested action from origin - char caller_id[MAX_CALLER_ID_LEN]; // Caller ID - char caller_name[MAX_CALLER_NAME]; // Caller Name + int connection_id; // Connection ID from Asterisk + enum line_action_t action; // The requested action from origin + char caller_id[CLID_MAX_NUMBER]; // Caller ID + char caller_name[CLID_MAX_NAME]; // Caller Name + int sip_client_id; // sip client id struct voice_ubus_req_t ubus; struct timespec time_stamp; + enum hangup_cause hangupcause; }; struct dectmngr_rpc_t { @@ -50,6 +52,7 @@ struct dectmngr_rpc_t { int pcm_id; union { // Action specific parameters will be added here + enum hangup_cause hangupcause; } params; }; @@ -58,11 +61,13 @@ int line_new_connection_by_asterisk(int line, int connection, struct voice_ubus_ int line_close_connection_by_asterisk(int line, int connection, struct voice_ubus_req_t *ubus_req); int line_release_connection_by_asterisk(int line, int connection, struct voice_ubus_req_t *ubus_req); int line_update_connection_by_pbx(int line, int pcm_callid); -int line_new_connection_by_dect(int line, const char *cid, int pcm, struct voice_ubus_req_t *ubus_req); +int line_new_connection_by_dect(int line, const char *cid, int pcm, const char *data, struct voice_ubus_req_t *ubus_req); int line_connection_parm_update_by_asterisk(int line, int connection, struct config_update_struct *data); int line_close_connection_by_dect(int line, int pcm, struct voice_ubus_req_t *ubus_req); int line_signal(int line, const char *signame, const char *data, struct voice_ubus_req_t *ubus_req); void pcm_states_dump(const char* func, int line); callid_state get_callid_state(int call_id); +bool is_valid_pcm_id(int id); +char *voice_line_get_paging_status(int line); #endif diff --git a/main.c b/main.c index 8635d7eeecba65bc3351bc0a127fd620f0dbde92..dd970087f233a8e1b1012328c05fc38e1a134621 100644 --- a/main.c +++ b/main.c @@ -19,6 +19,10 @@ #include "main.h" #include "ubus.h" +#ifdef INCLUDE_BREAKPAD +#include "breakpad_wrapper.h" +#endif + #ifndef UCI_CONFIG_DIR #define UCI_CONFIG_DIR "/etc/config/" #endif @@ -91,7 +95,7 @@ static void event_stream_handler(pe_stream_t *stream __attribute__((unused)), pe case EVENT_MAIN_LINE: ev = (struct line_event_t*) pe_list_get(event_list); if(!ev) break; - ENDPT_DBG("Main event handler line %d event %s\n", ev->line, ev->name); + ENDPT_DBG("Main event handler line %d event %s data %s\n", ev->line, ev->name, ev->data ? ev->data : "<null>"); ubus_call_asterisk(ev); ubus_broadcast_event(ev); // Also broadcast event to all break; @@ -172,6 +176,9 @@ static int signals_init(void) { struct sigaction action; unsigned int i; +#ifdef INCLUDE_BREAKPAD + breakpad_ExceptionHandler(); +#endif memset(&action, 0, sizeof(action)); action.sa_sigaction = signal_handler; action.sa_flags = SA_SIGINFO | SA_RESTART; @@ -191,7 +198,7 @@ static int signals_init(void) { return 0; } -static void voicemngr_event_report(int line, const char *event, int data) { +static void voicemngr_event_report(int line, const char *event, const char *data) { /* Re-send the event to the main thread, which in turn re-send * to Asterisk. We need to do this due to UBUS is not thread safe, * so all UBUS calls must be done from a single thread. */ @@ -203,8 +210,9 @@ static void voicemngr_event_report(int line, const char *event, int data) { return; } msg->name = event; - msg->data = (data < 0 ? 0 : data); // Discard negative values + msg->data = data; msg->line = line; + ENDPT_ERR("%s: event: %s, data: %s, line: %d\n", __func__, msg->name ? msg->name : "null", msg->data ? msg->data : "null", msg->line); send_event_main(msg, EVENT_MAIN_LINE); } } diff --git a/ubus.c b/ubus.c index ce4f3cf3e5723a73e8cb2bda53745f66458f0d1e..ab5a77df37b1bb9f764a92ed63658f8c08479c37 100644 --- a/ubus.c +++ b/ubus.c @@ -78,7 +78,9 @@ enum { DECT_REL, // Release call using PCMx DECT_CID, // Caller ID DECT_CALLER_NAME, // Caller Name + DECT_SIP_CLIENT_ID, DECT_PCM_ID, // PCM ID + DECT_DATA, // Extra parameter which is request (call creation, release, and etc.) specific }; // Keeping track of sent but not yet answered UBUS requests, for timeout. @@ -136,7 +138,7 @@ static const char broadcast_path[] = "voice.endpoint"; // UBUS path name for b static const char uciStrComSect[] = "tel_options"; // Common endpoint section name static const char uciStrLineSect[] = "extension"; // Line specific section name static const char uciStrCountry[] = "country"; // Endpoint country -static const char uciStrLoglevel[] = "vmloglevel"; // syslog level of voicemngr +static const char uciStrLoglevel[] = "vmloglevel"; // syslog level of voicemngr static const char ubusStrObjAdd[] = "ubus.object.add"; // UBUS objects added to global context static const char ubusStrObjRm[] = "ubus.object.remove"; // UBUS objects added removed from global context @@ -182,7 +184,9 @@ static const struct blobmsg_policy request_call_policy[] = { [DECT_REL] = { .name = "release", .type = BLOBMSG_TYPE_INT32 }, [DECT_CID] = { .name = "cid", .type = BLOBMSG_TYPE_STRING }, [DECT_CALLER_NAME] = { .name = "caller_name", .type = BLOBMSG_TYPE_STRING }, + [DECT_SIP_CLIENT_ID] = { .name = "sip_client_id", .type = BLOBMSG_TYPE_INT32 }, [DECT_PCM_ID] = { .name = "pcm_id", .type = BLOBMSG_TYPE_INT32 }, + [DECT_DATA] = { .name = "data", .type = BLOBMSG_TYPE_STRING }, }; // Our ubus RPC methods @@ -568,22 +572,24 @@ static int ubus_request_signal(struct ubus_context *uctx, struct ubus_object *ob } signame = blobmsg_get_string(keys[SIGNAL_TYPE]); - ENDPT_DBG("line=%d, signame=%s\n", line, signame); // on or off signal? enable = "0"; - data = NULL; state = blobmsg_get_string(keys[SIGNAL_STATE]); if (strcmp(state, "on") == 0) { enable = "1"; - // Do we have extra data that should be passed to endpoint? - if (keys[SIGNAL_DATA]) - data = blobmsg_get_string(keys[SIGNAL_DATA]); } else if (strcmp(state, "off")) { ENDPT_ERR("Error! invalid state %s\n", state); return UBUS_STATUS_INVALID_ARGUMENT; } + // Do we have extra data that should be passed to endpoint? + if (keys[SIGNAL_DATA]) + data = blobmsg_get_string(keys[SIGNAL_DATA]); + else + data = NULL; + + ENDPT_DBG("line=%d, signame=%s, state=%s, data=%s\n", line, signame, state, data?data:""); // Prepare for possibly deferring the request memset(&ubusReq, 0, sizeof(struct voice_ubus_req_t)); clock_gettime(CLOCK_MONOTONIC, &ubusReq.timeStamp); @@ -727,6 +733,7 @@ static int ubus_request_status(struct ubus_context *uctx, struct ubus_object *ob if (line >= 0 && line < totEndpoints) { blobmsg_add_u32(&blob, "line", line); blobmsg_add_u32(&blob, "offhook", voice_line_is_offhook(line + unpopulatedDectEndpoints)); + blobmsg_add_string(&blob, "paging_status", voice_line_get_paging_status(line)); res = UBUS_STATUS_OK; } else { ENDPT_ERR("Error! No such line value: %d\n", line); @@ -739,10 +746,9 @@ static int ubus_request_status(struct ubus_context *uctx, struct ubus_object *ob for(line = 0; line < totEndpoints; line++) { void *tbl; tbl = blobmsg_open_table(&blob, NULL); - blobmsg_add_u32(&blob, "line", line); blobmsg_add_u32(&blob, "offhook", voice_line_is_offhook(line + unpopulatedDectEndpoints)); - + blobmsg_add_string(&blob, "paging_status", voice_line_get_paging_status(line)); blobmsg_close_table(&blob, tbl); } @@ -889,15 +895,9 @@ static int ubus_request_call(struct ubus_context *uctx, struct ubus_object *obj struct blob_attr *msg) { struct blob_attr *keys[ARRAY_SIZE(request_call_policy)]; - int termId, pcmId, add, release; + int termId = -1, pcmId = -1, add = 0, release = 0; struct voice_ubus_req_t ubusReq; - const char *cid; - - termId = -1; - pcmId = -1; - add = 0; - release = 0; - cid = NULL; + const char *cid = NULL, *data = NULL; // Tokenize message key/value paris into an array if(blobmsg_parse(request_call_policy, ARRAY_SIZE(request_call_policy), @@ -927,7 +927,12 @@ static int ubus_request_call(struct ubus_context *uctx, struct ubus_object *obj if(keys[DECT_PCM_ID]) { pcmId = blobmsg_get_u32(keys[DECT_PCM_ID]); - ENDPT_DBG("pcmId %d\n", pcmId); + ENDPT_DBG("call pcmId %d\n", pcmId); + } + + if(keys[DECT_DATA]) { + data = blobmsg_get_string(keys[DECT_DATA]); + ENDPT_DBG("call data %s\n", data); } if((pcmId & 0xFFFF) < CALL_DEFAULT0 || (pcmId & 0xFFFF) >= CALL_LAST) { @@ -947,7 +952,7 @@ static int ubus_request_call(struct ubus_context *uctx, struct ubus_object *obj return UBUS_STATUS_UNKNOWN_ERROR; } } else if(add && termId >= 0) { - if(line_new_connection_by_dect(dectmngr_line_to_voicemngr_line(termId), cid, pcmId, &ubusReq)) { + if (line_new_connection_by_dect(dectmngr_line_to_voicemngr_line(termId), cid, pcmId, data, &ubusReq)) { send_reply_dectmngr(&ubusReq, termId, pcmId, UBUS_STATUS_UNKNOWN_ERROR); return UBUS_STATUS_UNKNOWN_ERROR; } @@ -960,7 +965,7 @@ static int ubus_request_call(struct ubus_context *uctx, struct ubus_object *obj struct line_event_t *ast_msg = malloc(sizeof(struct line_event_t)); if (ast_msg) { ast_msg->name = pcmId == CALL_MODE_MULTIPLE ? "LINE_CALL_MODE_MULTIPLE" : "LINE_CALL_MODE_SINGLE"; - ast_msg->data = 0; + ast_msg->data = NULL; ast_msg->line = dectmngr_line_to_voicemngr_line(termId); send_event_main(ast_msg, EVENT_MAIN_LINE); } @@ -999,7 +1004,7 @@ int ubus_call_asterisk(const struct line_event_t* const ev) struct blob_buf bb; int res; - ENDPT_DBG("ubus call to asterisk, line:%d, event:%s, data:%d\n", ev->line, ev->name, ev->data); + ENDPT_DBG("ubus call to asterisk, line:%d, event:%s, data:%s\n", ev->line, ev->name, ev->data ? ev->data : "<null>"); // Do we know ubus address of Asterisk? if (!asterisk_id) { @@ -1010,7 +1015,8 @@ int ubus_call_asterisk(const struct line_event_t* const ev) memset(&bb, 0, sizeof(bb)); if (blob_buf_init(&bb, 0)) return -1; blobmsg_add_string(&bb, "event", ev->name); - blobmsg_add_u32(&bb, "data", ev->data); + if (ev->data && *ev->data) + blobmsg_add_string(&bb, "data", ev->data); blobmsg_add_u32(&bb, "line", ev->line); req = calloc(1, sizeof(struct ubus_request)); @@ -1045,10 +1051,6 @@ int ubus_broadcast_event(const struct line_event_t* const ev) struct blob_buf blob; int res = 0; - // Filter out repeated DTMF events - if (strncasecmp(ev->name, "DTMF", strlen("DTMF")) == 0 && ev->data == 1) - return 0; - memset(&blob, 0, sizeof(blob)); if(blob_buf_init(&blob, 0)) return -1; @@ -1129,7 +1131,8 @@ static void got_dectmngr_complete(struct ubus_request *req, int ret __attribute_ // Send a request to dectmngr by "ubus call dect call". Don't wait for completion. Instead, when the invocation // finishes, we get "called back". -int ubus_call_dectmngr(int terminal, int add, int release, const char *cid, const char *caller_name, int pcmId, struct line_req_t *lineReq) +int ubus_call_dectmngr(int terminal, int add, int release, const char *cid, const char *caller_name, int sip_client_id, + int pcmId, struct line_req_t *lineReq) { struct ubus_request *req; struct blob_buf bb; @@ -1151,10 +1154,14 @@ int ubus_call_dectmngr(int terminal, int add, int release, const char *cid, cons blobmsg_add_u32(&bb, request_call_policy[DECT_REL].name, release); if(cid && *cid) blobmsg_add_string(&bb, request_call_policy[DECT_CID].name, cid); - if(caller_name && *caller_name) blobmsg_add_string(&bb, request_call_policy[DECT_CALLER_NAME].name, caller_name); + if(caller_name && *caller_name) + blobmsg_add_string(&bb, request_call_policy[DECT_CALLER_NAME].name, caller_name); + if(sip_client_id >= 0) + blobmsg_add_u32(&bb, request_call_policy[DECT_SIP_CLIENT_ID].name, sip_client_id); + blobmsg_add_u32(&bb, request_call_policy[DECT_PCM_ID].name, pcmId); - ENDPT_DBG("Sending ubus request to dectmngr %d %d %d %s %s %d\n", terminal, add, release, cid, caller_name, pcmId); + ENDPT_DBG("Sending ubus request to dectmngr %d %d %d %s %s %d %d\n", terminal, add, release, cid, caller_name, sip_client_id, pcmId); req = calloc(1, sizeof(struct ubus_request)); if (!req) { @@ -1205,9 +1212,11 @@ int ubus_dectmngr_rpc(const struct dectmngr_rpc_t *dectmngr_rpc, const struct li switch (dectmngr_rpc->action) { case ACTION_RINGING_STOP: blobmsg_add_u32(&bb, DECTMNGR_RPC_PARAM_EXTENSION_ID, dectmngr_rpc->extension_id); + blobmsg_add_u32(&bb, DECTMNGR_RPC_PARAM_HANGUPCAUSE, dectmngr_rpc->params.hangupcause); res = ubus_invoke_async(ctx, dectmngr_rpc_id, DECTMNGR_RPC_RINGING_STOP, bb.head, req); ENDPT_DBG("Invoke ubus call %s %s {'%s':%d}\n", DECTMNGR_RPC_UBUS_OBJECT, DECTMNGR_RPC_RINGING_STOP, - DECTMNGR_RPC_PARAM_EXTENSION_ID, dectmngr_rpc->extension_id); + DECTMNGR_RPC_PARAM_EXTENSION_ID, dectmngr_rpc->extension_id, + DECTMNGR_RPC_PARAM_HANGUPCAUSE, dectmngr_rpc->params.hangupcause); break; case ACTION_CONN_CLOSE: diff --git a/ubus.h b/ubus.h index 145a2ea364e9eae4054b89a430a55611125834bf..0f84b10f2a611a0760ae91fde51bb63bdeeea09f 100644 --- a/ubus.h +++ b/ubus.h @@ -15,7 +15,8 @@ int ubus_call_asterisk(const struct line_event_t* const ev); int ubus_broadcast_event(const struct line_event_t* const ev); int send_reply_asterisk(struct voice_ubus_req_t *req, enum ubus_msg_status ubusRet); int send_reply_dectmngr(struct voice_ubus_req_t *req, int terminal, int pcmId, enum ubus_msg_status ubusRet); -int ubus_call_dectmngr(int terminal, int add, int release, const char *cid, const char *caller_name, int pcmId, struct line_req_t *lineReq); +int ubus_call_dectmngr(int terminal, int add, int release, const char *cid, const char *caller_name, int sip_client_id, + int pcmId, struct line_req_t *lineReq); int ubus_dectmngr_rpc(const struct dectmngr_rpc_t *dectmngr_rpc, const struct line_req_t *line_req); int config_init(struct uci_context *context, struct uci_package *package); void config_syslog(struct uci_context *context, struct uci_package *package);