From 2d4d1ba5d41fe0818de6763cb17e7261623d8ffd Mon Sep 17 00:00:00 2001
From: Grzegorz Sluja <grzegorz.sluja@iopsys.eu>
Date: Wed, 8 Sep 2021 11:04:48 +0200
Subject: [PATCH] Implementation for new ubus call to get call_status

Call Status for each line can be get by:
ubus call asterisk call_status '{ "line" : X }', where X is line:
{0, 1, 2, or 3}

callStatus is set in chan_brcm according to TR-104 requirements:
Idle: no ongoing calls
Dialing: the process of collecting digits for the calling number in an outgoing call, and ringing in outgoing call.
Delivered: N/A
Connected: a call is established
Alerting: ringing when an incoming call is received
Disconnected: the remote party has ended a call. but the local party has not gone on-hook.
---
 channels/chan_brcm.c | 63 ++++++++++++++++++++++++++++++++++++++++++++
 channels/chan_brcm.h |  2 ++
 2 files changed, 65 insertions(+)

diff --git a/channels/chan_brcm.c b/channels/chan_brcm.c
index 1e82c66d52..ad9b5f5af2 100644
--- a/channels/chan_brcm.c
+++ b/channels/chan_brcm.c
@@ -211,6 +211,11 @@ enum {
 	__EVENT_MAX,
 };
 
+enum {
+	CALL_STATUS_LINE_ID,
+	__CALL_STATUS_MAX,
+};
+
 enum {																			// New ubus objects in global context
 	OBJ_ID,																		// UBUS ID of object
 	OBJ_PATH,																	// String path of object
@@ -265,6 +270,10 @@ static const struct blobmsg_policy asterisk_event_policy[] = {
 	[EVENT_LINE_ID] = { .name = "line", .type = BLOBMSG_TYPE_INT32 },
 };
 
+static const struct blobmsg_policy asterisk_call_status_policy[] = {
+	[CALL_STATUS_LINE_ID] = { .name = "line", .type = BLOBMSG_TYPE_INT32 },
+};
+
 static const struct blobmsg_policy new_obj_policy[] = {
 	[OBJ_ID] = { .name = "id", .type = BLOBMSG_TYPE_INT32 },					// UBUS ID of object
 	[OBJ_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING },				// String path of object
@@ -828,6 +837,7 @@ static int brcm_call(struct ast_channel *chan, const char *dest, int timeout)
 	pvt_lock(sub->parent, "brcm_call");
 
 	p = sub->parent;
+	strncpy(p->callStatus, "Alerting", CALL_STATUS_MAX_LEN);
 	sub_peer = brcm_subchannel_get_peer(sub);
 	if (!line_config[p->line_id].enabled) {
 		ast_debug(1, "tel_line %d disabled!\n", p->line_id);
@@ -897,6 +907,12 @@ static int brcm_hangup(struct ast_channel *ast)
 	}
 	pvt_lock(sub->parent, "TELCHAN hangup");
 	p = sub->parent;
+
+	if (!strcasecmp(p->callStatus, "Connected") || !strcasecmp(p->callStatus, "Dialing"))
+		strncpy(p->callStatus, "Disconnected", CALL_STATUS_MAX_LEN);
+	else
+		strncpy(p->callStatus, "Idle", CALL_STATUS_MAX_LEN);
+
 	sub_peer = brcm_subchannel_get_peer(sub);
 	ast_debug(1, "brcm_hangup(%s) line_id=%d connection_id=%d dialtone=%s channel_state=%s\n",
 		ast_channel_name(ast), p->line_id, sub->connection_id, dialtone_map[p->dialtone].str,
@@ -1023,6 +1039,7 @@ static int brcm_answer(struct ast_channel *ast)
 	ast_debug(1, "brcm_answer(%s)\n", ast_channel_name(ast));
 
 	pvt_lock(pvt, "TELCHAN answer");
+	strncpy(pvt->callStatus, "Connected", CALL_STATUS_MAX_LEN);
 
 	/* For attended call transfer, if the transfer target has accepted the call initiated by
 	 * us as the tranferee, we can terminate the original call with the transferor */
@@ -1672,6 +1689,7 @@ static int handle_dialtone_timeout(const void *data)
 	struct brcm_pvt *p = (struct brcm_pvt *) data;
 
 	pvt_lock(p, "dialtone timeout");
+	strncpy(p->callStatus, "Disconnected", CALL_STATUS_MAX_LEN);
 	//ast_mutex_lock(&p->lock);
 	p->dialtone_timeout_timer_id = -1;
 
@@ -2394,6 +2412,10 @@ static void *brcm_process_event(struct endpt_event *ev)
 		switch (ev->event) {
 		case EVENT_OFFHOOK: {
 			ast_debug(9, "EVENT_OFFHOOK detected\n");
+			if (!strlen(p->callStatus) || !strcasecmp(p->callStatus, "Idle"))
+				strncpy(p->callStatus, "Dialing", CALL_STATUS_MAX_LEN);
+			else if (!strcasecmp(p->callStatus, "Alerting"))
+				strncpy(p->callStatus, "Connected", CALL_STATUS_MAX_LEN);
 
 			/* Reset the dtmf buffer */
 			memset(p->dtmfbuf, 0, sizeof(p->dtmfbuf));
@@ -2456,6 +2478,7 @@ static void *brcm_process_event(struct endpt_event *ev)
 		}
 		case EVENT_ONHOOK: {
 			ast_debug(9, "EVENT_ONHOOK detected\n");
+			strncpy(p->callStatus, "Idle", CALL_STATUS_MAX_LEN);
 			if (sub->channel_state == OFFHOOK || sub->channel_state == AWAITONHOOK) {
 				/* Received EVENT_ONHOOK in state OFFHOOK/AWAITONHOOK, stop dial/congestion tone */
 				brcm_stop_dialtone(p);
@@ -3707,8 +3730,48 @@ static int asterisk_event(struct ubus_context *ctx, struct ubus_object *obj,
 	return UBUS_STATUS_OK;
 }
 
+// Reception of RPC call
+// ubus call asterisk call_status '{ "line" : 1 }'
+static int asterisk_call_status(struct ubus_context *ctx, struct ubus_object *obj,
+				   struct ubus_request_data *req, const char *method,
+				   struct blob_attr *msg)
+{
+	struct blob_attr *tb[__EVENT_MAX];
+	enum ubus_msg_status res = UBUS_STATUS_UNKNOWN_ERROR;
+	struct blob_buf blob;
+	int line;
+
+	blobmsg_parse(asterisk_call_status_policy, __CALL_STATUS_MAX,
+				  tb, blob_data(msg), blob_len(msg));
+
+	if (!tb[CALL_STATUS_LINE_ID] )
+		return UBUS_STATUS_INVALID_ARGUMENT;
+
+	memset(&blob, 0, sizeof(blob));
+	if(blob_buf_init(&blob, 0))
+		return UBUS_STATUS_UNKNOWN_ERROR;
+
+	line = blobmsg_get_u32(tb[CALL_STATUS_LINE_ID]);
+
+	struct brcm_pvt *p = iflist;
+	while(p) {
+		if (line == p->line_id) {
+			blobmsg_add_u32(&blob, "line", p->line_id);
+			blobmsg_add_string(&blob, "call_status", strlen(p->callStatus) ? p->callStatus : "Idle");
+			res = UBUS_STATUS_OK;
+			break;
+		}
+		p = brcm_get_next_pvt(p);
+	}
+
+	ubus_send_reply(ctx, req, blob.head);
+	blob_buf_free(&blob);
+	return res;
+}
+
 static struct ubus_method asterisk_methods[] = {
 	UBUS_METHOD("event", asterisk_event, asterisk_event_policy),
+	UBUS_METHOD("call_status", asterisk_call_status, asterisk_call_status_policy),
 };
 
 static struct ubus_object_type asterisk_obj_type = UBUS_OBJECT_TYPE("asterisk", asterisk_methods);
diff --git a/channels/chan_brcm.h b/channels/chan_brcm.h
index 33a7da3fa1..375d1dd78c 100644
--- a/channels/chan_brcm.h
+++ b/channels/chan_brcm.h
@@ -10,6 +10,7 @@
 
 #define DEFAULT_CALLER_ID "Unknown"
 #define PHONE_MAX_BUF 480
+#define CALL_STATUS_MAX_LEN 14
 
 #define TIMEMSEC 1000
 
@@ -145,6 +146,7 @@ struct brcm_pvt {
 	char language[MAX_LANGUAGE];
 	char cid_num[AST_MAX_EXTENSION];
 	char cid_name[AST_MAX_EXTENSION];
+	char callStatus[CALL_STATUS_MAX_LEN];
 
 	struct brcm_subchannel *sub[NUM_SUBCHANNELS];	/* List of sub-channels, needed for callwaiting and 3-way support */
 	int hf_detected;			/* Hook flash detected */
-- 
GitLab