diff --git a/Makefile b/Makefile index eed819c01426f0766c06fd8dbcc84ed1f931f0a1..0e6a2432c9e82a4fec042303f262b7c1c3600523 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ CFLAGS += -I./ -Ilibvoice/ OBJS := $(SRCS:.c=.o) -LIBS += -lubox -lubus -lpthread -lpicoevent -luci -L./libvoice -lvoice +LIBS += -lubox -lubus -lpthread -lpicoevent -luci -L./libvoice -lvoice -lblobmsg_json all: debug $(VOICEMNGR) diff --git a/docs/api/endpt.md b/docs/api/endpt.md old mode 100755 new mode 100644 index dbab2cc093c5c3d97257e60334ea5adfe367c562..468c64d10cb22dfff0866861ff00c6e3b3d3f44e --- a/docs/api/endpt.md +++ b/docs/api/endpt.md @@ -1,7 +1,7 @@ # endpt Schema ``` -https://www.iopsys.eu/asterisk.json +https://www.iopsys.eu/endpt.json ``` | Custom Properties | Additional Properties | @@ -13,6 +13,7 @@ https://www.iopsys.eu/asterisk.json | List of Methods | | ------------------------- | | [call](#call) | Method | endpt (this schema) | +| [codecs](#codecs) | Method | endpt (this schema) | | [connection](#connection) | Method | endpt (this schema) | | [count](#count) | Method | endpt (this schema) | | [rtp_stats](#rtp_stats) | Method | endpt (this schema) | @@ -53,6 +54,7 @@ https://www.iopsys.eu/asterisk.json | ---------- | ------- | ------------ | | `add` | integer | **Required** | | `cid` | string | Optional | +| `pcm_id` | integer | **Required** | | `terminal` | integer | **Required** | #### add @@ -87,6 +89,20 @@ https://www.iopsys.eu/asterisk.json ^[0-9]*# ``` +#### pcm_id + +`pcm_id` + +- is **required** +- type: `integer` + +##### pcm_id Type + +`integer` + +- minimum value: `0` +- maximum value: `5` + #### terminal `terminal` @@ -108,6 +124,7 @@ https://www.iopsys.eu/asterisk.json | Property | Type | Required | | ---------- | ------- | ------------ | | `cid` | string | Optional | +| `pcm_id` | integer | **Required** | | `release` | integer | **Required** | | `terminal` | integer | **Required** | @@ -129,6 +146,20 @@ https://www.iopsys.eu/asterisk.json ^[0-9]*# ``` +#### pcm_id + +`pcm_id` + +- is **required** +- type: `integer` + +##### pcm_id Type + +`integer` + +- minimum value: `0` +- maximum value: `5` + #### release `release` @@ -160,7 +191,7 @@ https://www.iopsys.eu/asterisk.json ### Ubus CLI Example ``` -ubus call endpt call {"terminal":4,"release":1,"cid":"329337#"} +ubus call endpt call {"terminal":6,"add":1,"pcm_id":0,"cid":"018#"} ``` ### JSONRPC Example @@ -170,7 +201,7 @@ ubus call endpt call {"terminal":4,"release":1,"cid":"329337#"} "jsonrpc": "2.0", "id": 0, "method": "call", - "params": ["<SID>", "endpt", "call", { "terminal": 4, "release": 1, "cid": "329337#" }] + "params": ["<SID>", "endpt", "call", { "terminal": 6, "add": 1, "pcm_id": 0, "cid": "018#" }] } ``` @@ -227,7 +258,200 @@ ubus call endpt call {"terminal":4,"release":1,"cid":"329337#"} ### Output Example ```json -{ "terminal": 95818467, "pcm": -54557753, "errno": 49583331 } +{ "terminal": 73262276, "pcm": -31145049, "errno": -61339135 } +``` + +## codecs + +`codecs` + +- type: `Method` + +### codecs Type + +`object` with following properties: + +| Property | Type | Required | +| -------- | ------ | ------------ | +| `input` | object | Optional | +| `output` | object | **Required** | + +#### input + +`input` + +- is optional +- type: `object` + +##### input Type + +`object` with following properties: + +| Property | Type | Required | +| -------- | ---- | -------- | +| None | None | None | + +### Ubus CLI Example + +``` +ubus call endpt codecs {} +``` + +### JSONRPC Example + +```json +{ "jsonrpc": "2.0", "id": 0, "method": "call", "params": ["<SID>", "endpt", "codecs", {}] } +``` + +#### output + +`output` + +- is **Required** +- type: `object` + +##### output Type + +`object` with following properties: + +| Property | Type | Required | +| ----------- | ------ | ------------ | +| `codec_key` | object | **Required** | + +#### codec_key + +`codec_key` + +- is **Required** +- type: `object` + +##### codec_key Type + +`object` with following properties: + +| Property | Type | Required | +| ----------------- | ------- | ------------ | +| `bitrate` | number | **Required** | +| `name` | string | **Required** | +| `ptime_default` | integer | **Required** | +| `ptime_increment` | integer | **Required** | +| `ptime_max` | integer | **Required** | +| `ptime_min` | integer | **Required** | + +#### bitrate + +`bitrate` + +- is **required** +- type: `number` + +##### bitrate Type + +`number` + +- minimum value: `0` +- maximum value: `100` + +#### name + +`name` + +- is **required** +- type: `enum` + +##### name Type + +`string` + +The value of this property **must** be equal to one of the [known values below](#codecs-known-values). + +##### name Known Values + +| Value | +| ---------- | +| G.711MuLaw | +| G.711ALaw | +| G.729a | +| G.723.1 | +| G.726 | +| G.728 | +| G.729 | +| G.729e | +| GSM-FR | +| GSM-EFR | +| GSM-HR | +| GSM-AMR | +| iLBC | + +#### ptime_default + +`ptime_default` + +- is **required** +- type: `integer` + +##### ptime_default Type + +`integer` + +- minimum value: `0` +- maximum value: `50` + +#### ptime_increment + +`ptime_increment` + +- is **required** +- type: `integer` + +##### ptime_increment Type + +`integer` + +- minimum value: `0` +- maximum value: `50` + +#### ptime_max + +`ptime_max` + +- is **required** +- type: `integer` + +##### ptime_max Type + +`integer` + +- minimum value: `0` +- maximum value: `300` + +#### ptime_min + +`ptime_min` + +- is **required** +- type: `integer` + +##### ptime_min Type + +`integer` + +- minimum value: `0` +- maximum value: `50` + +### Output Example + +```json +{ + "codec_key": { + "name": "G.729e", + "ptime_min": 44, + "ptime_max": 36, + "ptime_default": 12, + "ptime_increment": 38, + "bitrate": 12.60194806517081 + } +} ``` ## connection @@ -314,7 +538,7 @@ The value of this property **must** be equal to one of the [known values below]( ### Ubus CLI Example ``` -ubus call endpt connection {"line":1,"id":80045812,"action":"stop_conference"} +ubus call endpt connection {"line":3,"id":4989534,"action":"start_conference"} ``` ### JSONRPC Example @@ -324,7 +548,7 @@ ubus call endpt connection {"line":1,"id":80045812,"action":"stop_conference"} "jsonrpc": "2.0", "id": 0, "method": "call", - "params": ["<SID>", "endpt", "connection", { "line": 1, "id": 80045812, "action": "stop_conference" }] + "params": ["<SID>", "endpt", "connection", { "line": 3, "id": 4989534, "action": "start_conference" }] } ``` @@ -476,10 +700,10 @@ ubus call endpt count {"effective":true} ```json { - "num_endpoints": 33328553, - "num_fxo_endpoints": 50973699, - "num_fxs_endpoints": 25375525, - "num_dect_endpoints": 17497288 + "num_endpoints": 28959373, + "num_fxo_endpoints": 16921710, + "num_fxs_endpoints": 5497405, + "num_dect_endpoints": 2393708 } ``` @@ -542,7 +766,7 @@ ubus call endpt count {"effective":true} ### Ubus CLI Example ``` -ubus call endpt rtp_stats {"line":1,"reset":false} +ubus call endpt rtp_stats {"line":0,"reset":true} ``` ### JSONRPC Example @@ -552,7 +776,7 @@ ubus call endpt rtp_stats {"line":1,"reset":false} "jsonrpc": "2.0", "id": 0, "method": "call", - "params": ["<SID>", "endpt", "rtp_stats", { "line": 1, "reset": false }] + "params": ["<SID>", "endpt", "rtp_stats", { "line": 0, "reset": true }] } ``` @@ -939,32 +1163,32 @@ ubus call endpt rtp_stats {"line":1,"reset":false} ```json { - "lineId": 0, - "localBurstDensity": 55283780, - "remoteBurstDensity": 62068585, - "localBurstDuration": 94260800, - "remoteBurstDuration": 99693375, - "localGapDensity": 71402386, - "remoteGapDensity": 47162230, - "localGapDuration": 7583318, - "remoteGapDuration": 6863264, - "localJbRate": 87945882, - "remoteJbRate": 14582824, - "localJbMax": 22999542, - "remoteJbMax": 29034128, - "localJbNominal": 15578543, - "remoteJbNominal": 31528270, - "localJbAbsMax": 9399794, - "remoteJbAbsMax": 29508034, - "discarded": 54075545, - "lost": 70983167, - "rxpkts": 17096099, - "txpkts": 59756075, - "jbAvg": 97568226, - "jitter": 56764254, - "uLossRate": 11873018, - "maxJitter": 95833762, - "averageRoundTripDelay": 82416645 + "lineId": 3, + "localBurstDensity": 72187314, + "remoteBurstDensity": 57272242, + "localBurstDuration": 550512, + "remoteBurstDuration": 9577445, + "localGapDensity": 31746248, + "remoteGapDensity": 5373655, + "localGapDuration": 93046060, + "remoteGapDuration": 6028757, + "localJbRate": 48187376, + "remoteJbRate": 42684338, + "localJbMax": 4617104, + "remoteJbMax": 68868842, + "localJbNominal": 97005535, + "remoteJbNominal": 37554392, + "localJbAbsMax": 15660701, + "remoteJbAbsMax": 15370482, + "discarded": 38026287, + "lost": 73256347, + "rxpkts": 77415865, + "txpkts": 30316611, + "jbAvg": 16648797, + "jitter": 12286104, + "uLossRate": 44899753, + "maxJitter": 68636630, + "averageRoundTripDelay": 25815554 } ``` @@ -1090,7 +1314,7 @@ The value of this property **must** be equal to one of the [known values below]( ### Ubus CLI Example ``` -ubus call endpt signal {"line":2,"signal":"dtmf8","state":"on","data":"exercitation do voluptate ut Ut"} +ubus call endpt signal {"line":0,"signal":"busy","state":"on","data":"dolor"} ``` ### JSONRPC Example @@ -1100,12 +1324,7 @@ ubus call endpt signal {"line":2,"signal":"dtmf8","state":"on","data":"exercitat "jsonrpc": "2.0", "id": 0, "method": "call", - "params": [ - "<SID>", - "endpt", - "signal", - { "line": 2, "signal": "dtmf8", "state": "on", "data": "exercitation do voluptate ut Ut" } - ] + "params": ["<SID>", "endpt", "signal", { "line": 0, "signal": "busy", "state": "on", "data": "dolor" }] } ``` @@ -1177,13 +1396,13 @@ ubus call endpt signal {"line":2,"signal":"dtmf8","state":"on","data":"exercitat ### Ubus CLI Example ``` -ubus call endpt status {"line":4} +ubus call endpt status {"line":1} ``` ### JSONRPC Example ```json -{ "jsonrpc": "2.0", "id": 0, "method": "call", "params": ["<SID>", "endpt", "status", { "line": 4 }] } +{ "jsonrpc": "2.0", "id": 0, "method": "call", "params": ["<SID>", "endpt", "status", { "line": 1 }] } ``` #### output @@ -1239,5 +1458,5 @@ The value of this property **must** be equal to one of the [known values below]( ### Output Example ```json -{ "line": 3, "offhook": 0 } +{ "line": 3, "offhook": 1 } ``` diff --git a/docs/functionspec.md b/docs/functionspec.md index a8a992aa9c8b7beed1e7191ad6eb8631b5b6026f..0fb26b05e52e3c4581f670a408a7ff579e243b2b 100644 --- a/docs/functionspec.md +++ b/docs/functionspec.md @@ -8,8 +8,9 @@ "signal":{"line":"Integer","signal":"String","state":"String","data":"String"} "connection":{"line":"Integer","id":"Integer","action":"String"} "status":{"line":"Integer"} - "call":{"terminal":"Integer","add":"Integer","release":"Integer","cid":"String"} - "rtp_stats":{"line":"Integer","reset":"Boolean"}``` + "call":{"terminal":"Integer","add":"Integer","release":"Integer","cid":"String","pcm_id":"Integer"} + "rtp_stats":{"line":"Integer","reset":"Boolean"} + "codecs":{} ``` # Contents @@ -27,8 +28,9 @@ | [signal](#signal) | Start/stop call progress tone or signals on a terminal, e.g. dial tone, ring signal, and etc. This is called by asterisk. | | [connection](#connection) | Create/destroy a connection for a terminal. This is called by asterisk. | | [status](#status) | Get the hook status of a terminal. This is called by asterisk. | -| [call](#call) | Establish/release a call on a terminal. This is called both by asterisk and by dectmngr. | +| [call](#call) | Establish/release a call on a terminal. This is called by dectmngr. | | [rtp_stats](#rtp_stats) | Get the RTP statistics of a terminal. This is called by asterisk. | +| [codecs](#codecs) | Get the hardware specific codec capability. This is called by "voice.asterisk codecs". | #### Methods @@ -58,3 +60,7 @@ Methods descriptions of the `endpt` object. ##### rtp_stats [rtp_stats documentation](./api/endpt.md#rtp_stats) + +##### codecs + +[codecs documentation](./api/endpt.md#codecs) diff --git a/libvoice/common.c b/libvoice/common.c index acd1ab72c0947e03671e3a85b77392d7df2fd779..32fa3df81a85d7381e17b80cf306682ca5d37078 100644 --- a/libvoice/common.c +++ b/libvoice/common.c @@ -72,6 +72,7 @@ const struct voice_signal_t signal_map[] = { // List of signals requested by Ast { .name = "dtmfC", .signal = VOICE_SIG_DTMFC }, { .name = "dtmfD", .signal = VOICE_SIG_DTMFD }, { .name = "keypad", .signal = VOICE_SIG_INGRESS_DTMF }, + { .name = "answer", .signal = VOICE_SIG_ANSWER }, { .name = "", .signal = VOICE_SIG_LAST }, }; @@ -119,8 +120,8 @@ int voice_line_preinit(void) { } for(i = 0; i < terminal_info.num_voice_ports; i++) { lines[i].type = VOICE_LINE_UNKNOWN; - lines[i].pcm_state[PCM_0] = LINE_PCM_STATE_NOT_USED; - lines[i].pcm_state[PCM_1] = LINE_PCM_STATE_NOT_USED; + lines[i].pcm_callid[PCM_0] = CALLID_INVALID; + lines[i].pcm_callid[PCM_1] = CALLID_INVALID; } return 0; diff --git a/libvoice/libvoice.h b/libvoice/libvoice.h index 19b8271e2bd2cc8293d446a18695c7568f9febce..c344235fac49cbbb2210b3dbae30b06864b6dac9 100644 --- a/libvoice/libvoice.h +++ b/libvoice/libvoice.h @@ -13,6 +13,8 @@ #define MAX_CALLER_ID_LEN 120 // Max length of caller id string we accept #define MAX_KEYPAD_DIGITS 100 // Max number of simulated keypad presses we accept +#define MAX_CODECS 20 +#define MAX_CODEC_NAMELEN 20 #define DEBUG_LOOPBACK 0 // Debug - feed received audio back to transmitter @@ -53,7 +55,6 @@ enum VOICE_EVENT }; enum DECT_EVENT { - DECT_EVT_START, DECT_EVT_SWITCH, DECT_EVT_JOIN, DECT_EVT_RELEASE, @@ -88,20 +89,21 @@ enum VOICE_SIGNAL { VOICE_SIG_DTMFC, VOICE_SIG_DTMFD, VOICE_SIG_INGRESS_DTMF, // Simulate phone keypad button pressing + VOICE_SIG_ANSWER, VOICE_SIG_LAST }; -enum LINE_PCM_ID { +typedef enum callid_state { + CALLID_INVALID = -1, + CALLID_OBTAINING = 0, + CALLID_ESTABLISHED = 1 +} callid_state; + +enum pcm_id { PCM_0, PCM_1 }; -enum LINE_PCM_STATE { - LINE_PCM_STATE_NOT_USED = -1, - LINE_PCM_STATE_RINGING = 0, - LINE_PCM_STATE_CONNECTED = 1 -}; - enum VOICE_LINE_TYPE { VOICE_LINE_UNKNOWN, // Invalid type VOICE_LINE_FXS, @@ -135,7 +137,7 @@ struct line_t { uint32_t simulated_busy_peer_id; // ID of remote who gets the above busy message uint16_t signaled_call_waiting; // True if Call waiting has already been signaled to DECT uint16_t conference_started; // True if conference has just been setup by DECT handset - enum LINE_PCM_STATE pcm_state[2]; // PCM call states on the line + int pcm_callid[2]; // -1: Invalid, 0: Obtaining, >0: Established pe_list_t *pending_digits; // List of keypad digits waiting to be sent void *priv; // Platform dependent data @@ -198,6 +200,19 @@ struct rtp_stats_t { uint32_t avg_round_trip_delay; }; +struct codec_capability { + int num_codecs; + struct { + char uciName[MAX_CODEC_NAMELEN]; + char codec[MAX_CODEC_NAMELEN]; + int ptimeMin; + int ptimeMax; + int ptimeDefault; + int ptimeIncrement; + float bitRate; + } codecs[MAX_CODECS]; +}; + #define ENABLE_VOICE_DEBUG 0 // Enable/disable voice debug #if ENABLE_VOICE_DEBUG // log to file @@ -263,6 +278,7 @@ int voice_get_max_rx_gain(void); int voice_get_terminal_info(const struct terminal_info_t *voice_port_cfg, struct terminal_info_t *terminal_info); 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_egress_media(void (*cb_egress_media)(const struct media_packet_t *packet, int size)); diff --git a/line-dect.c b/line-dect.c index 27075c9009111b20bb999a7cd454a7d9acf30a83..d505734f5668f87988a391cc02247a4ab5bfc36c 100644 --- a/line-dect.c +++ b/line-dect.c @@ -53,8 +53,8 @@ int ubus_process_queued_reqs_to_dectmngr(void) { return 0; ENDPT_DBG("%s: Poped DECT req %p from list, action: %d pcmId: %d\n", __func__, req, req->action, req->pcm_id); - ENDPT_DBG("%s: lines[%d].pcm_state[%d]: %d, lines[%d].pcm_state[%d]: %d\n", __func__, req->line, PCM_0, - lines[req->line].pcm_state[PCM_0], req->line, PCM_1, lines[req->line].pcm_state[PCM_1]); + pcm_states_dump(__func__, req->line); + switch (req->action) { case ACTION_CONN_CREATE: case ACTION_SIG_RING: @@ -69,6 +69,12 @@ int ubus_process_queued_reqs_to_dectmngr(void) { return -1; } break; + case ACTION_SIG_ANSWERED: + if(ubus_call_dectmngr(voicemngr_line_to_dectmngr_line(req->line), 2, 0, req->caller_id, req->pcm_id, req)) { + free(req); + return -1; + } + break; default: break; } @@ -127,8 +133,7 @@ int ubus_cb_dectmngr_replied(struct line_req_t *req, enum ubus_msg_status reply_ ENDPT_DBG("%s got answer req %p from dectmngr, action: %d, line: %d, pcmId: %d, conId: %d\n", __func__, req, req->action, req->line, req->pcm_id, req->connection_id); - ENDPT_DBG("%s lines[%d].pcm_state[%d]: %d, lines[%d].pcm_state[%d]: %d\n", __func__, req->line, PCM_0, - lines[req->line].pcm_state[PCM_0], req->line, PCM_1, lines[req->line].pcm_state[PCM_1]); + pcm_states_dump(__func__, req->line); switch (req->action) { case ACTION_CONN_CREATE: @@ -137,22 +142,18 @@ int ubus_cb_dectmngr_replied(struct line_req_t *req, enum ubus_msg_status reply_ } break; case ACTION_CONN_CLOSE: - lines[req->line].pcm_state[req->pcm_id] = LINE_PCM_STATE_NOT_USED; - ENDPT_DBG("%s changing value of lines[%d].pcm_state[%d] to %d\n", __func__, req->line, req->pcm_id, - lines[req->line].pcm_state[req->pcm_id]); - if (lines[req->line].pcm_state[PCM_0] > LINE_PCM_STATE_RINGING || - lines[req->line].pcm_state[PCM_1] > LINE_PCM_STATE_RINGING) + lines[req->line].pcm_callid[req->pcm_id] = CALLID_INVALID; + 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 && lines[req->line].pcm_state[PCM_1] == LINE_PCM_STATE_RINGING) || - (req->pcm_id == PCM_1 && lines[req->line].pcm_state[PCM_0] == LINE_PCM_STATE_RINGING)) + 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; - lines[req->line].pcm_state[req->pcm_id] = LINE_PCM_STATE_RINGING; - ENDPT_DBG("%s changing value of lines[%d].pcm_state[%d] to %d\n", __func__, req->line, req->pcm_id, - lines[req->line].pcm_state[req->pcm_id]); + lines[req->line].pcm_callid[req->pcm_id] = CALLID_OBTAINING; break; default: break; diff --git a/line.c b/line.c index 7545ad65c88eb5c0c4650b83dc3db953a2bb1414..5df9d2f7719494f37bc2794921b4853511f89e77 100644 --- a/line.c +++ b/line.c @@ -17,17 +17,32 @@ #include "main.h" #include "ubus.h" -enum { - STATE_OFF = 0, - STATE_ON, - STATE_LAST, -}; - -enum { - ACTION_CREATE, - ACTION_DESTROY, - ACTION_LAST, -}; + +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) +{ + 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; @@ -86,8 +101,7 @@ static int line_signal_ring(int line, int pcm, enum VOICE_SIGNAL signal, const c int start_ring = data && strcmp(data, "0") != 0; ENDPT_DBG("%s: line %d pcm: %d data: %s\n", __func__, line, pcm, data); - ENDPT_DBG("%s: pcm_state[%d]: %d, pcm_state[%d]: %d\n", __func__, PCM_0, lines[line].pcm_state[PCM_0], - PCM_1, lines[line].pcm_state[PCM_1]); + pcm_states_dump(__func__, line); // Relay the request to dectmngr if the line is DECT if(lines[line].type == VOICE_LINE_DECT) { @@ -159,6 +173,34 @@ static int line_signal_ring(int line, int pcm, enum VOICE_SIGNAL signal, const c 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("%s() line %d pcm: %d data: %s\n", __func__, 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) { @@ -183,12 +225,12 @@ int line_signal(int line, const char *signame, const char *data, struct voice_ub case VOICE_SIG_CALLID: case VOICE_SIG_RINGING: if(atoi(data) == 0) { - res = line_signal_ring(line, lines[line].pcm_state[PCM_0] == - LINE_PCM_STATE_RINGING ? PCM_0 : PCM_1, sig->signal, data, ubus_req); + 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; } else { - res = line_signal_ring(line, lines[line].pcm_state[PCM_0] == - LINE_PCM_STATE_NOT_USED ? PCM_0 : PCM_1, sig->signal, data, ubus_req); + 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); } break; @@ -201,13 +243,13 @@ int line_signal(int line, const char *signame, const char *data, struct voice_ub ENDPT_DBG("lines[%d].signaled_call_waiting: %d\n", line, lines[line].signaled_call_waiting); if((data[0] == '1') && (lines[line].signaled_call_waiting == 0)) { // start call waiting - res = line_signal_ring(line, lines[line].pcm_state[PCM_1] == - LINE_PCM_STATE_NOT_USED ? PCM_1 : PCM_0, VOICE_SIG_RINGING, data, ubus_req); + res = line_signal_ring(line, get_callid_state(lines[line].pcm_callid[PCM_1]) == CALLID_INVALID ? + PCM_1 : PCM_0, VOICE_SIG_RINGING, data, ubus_req); lines[line].signaled_call_waiting = 1; } else if((data[0] == '0')) { // stop call waiting - res = line_signal_ring(line, lines[line].pcm_state[PCM_1] == - LINE_PCM_STATE_RINGING ? PCM_1 : PCM_0, VOICE_SIG_RINGING, data, ubus_req); + res = line_signal_ring(line, get_callid_state(lines[line].pcm_callid[PCM_1]) == CALLID_OBTAINING ? + PCM_1 : PCM_0, VOICE_SIG_RINGING, data, ubus_req); lines[line].signaled_call_waiting = 0; } } else { @@ -232,6 +274,15 @@ int line_signal(int line, const char *signame, const char *data, struct voice_ub } break; + 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; + default: res = voice_line_signal(line, -1, sig->signal, atoi(data), NULL); break; @@ -257,18 +308,12 @@ int line_new_connection_by_asterisk(int line, int connection, struct voice_ubus_ return -1; ENDPT_DBG("%s line: %d, connection: %d\n", __func__, line, connection); - ENDPT_DBG("%s lines[%d].pcm_state[%d]: %d, lines[%d].pcm_state[%d]: %d\n", __func__, line, PCM_0, - lines[line].pcm_state[PCM_0], line, PCM_1, lines[line].pcm_state[PCM_1]); - - if (lines[line].pcm_state[PCM_0] == LINE_PCM_STATE_RINGING) { - lines[line].pcm_state[PCM_0] = connection; - ENDPT_DBG("%s changing value of lines[%d].pcm_state[PCM_0] to %d\n", __func__, line, - lines[line].pcm_state[PCM_0]); - } else if (lines[line].pcm_state[PCM_1] == LINE_PCM_STATE_RINGING) { - lines[line].pcm_state[PCM_1] = connection; - ENDPT_DBG("%s changing value of lines[%d].pcm_state[PCM_1] to %d\n", __func__, line, - lines[line].pcm_state[PCM_1]); - } + 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) { @@ -284,7 +329,7 @@ int line_new_connection_by_asterisk(int line, int connection, struct voice_ubus_ } line_req->line = line; line_req->connection_id = line; - line_req->pcm_id = lines[line].pcm_state[PCM_0] == connection ? PCM_0 : PCM_1; + line_req->pcm_id = lines[line].pcm_callid[PCM_0] == connection ? PCM_0 : PCM_1; 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()) @@ -309,11 +354,10 @@ int line_close_connection_by_asterisk(int line, int connection, struct voice_ubu return -1; ENDPT_DBG("%s line: %d, connection: %d\n", __func__, line, connection); - ENDPT_DBG("%s lines[%d].pcm_state[%d]: %d, lines[%d].pcm_state[%d]: %d\n", __func__, line, PCM_0, - lines[line].pcm_state[PCM_0], line, PCM_1, lines[line].pcm_state[PCM_1]); + pcm_states_dump(__func__, line); - if (lines[line].pcm_state[PCM_0] == LINE_PCM_STATE_NOT_USED && - lines[line].pcm_state[PCM_1] == LINE_PCM_STATE_NOT_USED) { + 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); } @@ -325,18 +369,14 @@ int line_close_connection_by_asterisk(int line, int connection, struct voice_ubu if(!line_req) return -1; line_req->line = line; line_req->connection_id = line; - if (lines[line].pcm_state[PCM_0] >= LINE_PCM_STATE_CONNECTED && - lines[line].pcm_state[PCM_1] == LINE_PCM_STATE_NOT_USED) { + if (get_callid_state(lines[line].pcm_callid[PCM_0]) == CALLID_ESTABLISHED && + get_callid_state(lines[line].pcm_callid[PCM_1]) == CALLID_INVALID) { line_req->pcm_id = PCM_0; - lines[line].pcm_state[PCM_0] = LINE_PCM_STATE_NOT_USED; - ENDPT_DBG("%s changing value of lines[%d].pcm_state[PCM_0] to %d\n", __func__, - line, lines[line].pcm_state[PCM_0]); - } else if (lines[line].pcm_state[PCM_1] >= LINE_PCM_STATE_CONNECTED && - lines[line].pcm_state[PCM_0] == LINE_PCM_STATE_NOT_USED) { + 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) { line_req->pcm_id = PCM_1; - lines[line].pcm_state[PCM_1] = LINE_PCM_STATE_NOT_USED; - ENDPT_DBG("%s changing value of lines[%d].pcm_state[PCM_1] to %d\n", __func__, - line, lines[line].pcm_state[PCM_1]); + lines[line].pcm_callid[PCM_1] = CALLID_INVALID; } line_req->action = ACTION_CONN_CLOSE; memcpy(&line_req->ubus, ubus_req, sizeof(struct voice_ubus_req_t)); @@ -347,13 +387,11 @@ int line_close_connection_by_asterisk(int line, int connection, struct voice_ubu break; default: - if (lines[line].pcm_state[PCM_0] >= LINE_PCM_STATE_CONNECTED) { - lines[line].pcm_state[PCM_0] = LINE_PCM_STATE_NOT_USED; - ENDPT_DBG("%s changing value of lines[%d].pcm_state[PCM_0] to %d\n", line, lines[line].pcm_state[PCM_0]); - } else if (lines[line].pcm_state[PCM_1] >= LINE_PCM_STATE_CONNECTED) { - lines[line].pcm_state[PCM_1] = LINE_PCM_STATE_NOT_USED; - ENDPT_DBG("%s changing value of lines[%d].pcm_state[PCM_1] to %d\n", line, lines[line].pcm_state[PCM_1]); - } + 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); } @@ -367,8 +405,7 @@ int line_release_connection_by_asterisk(int line, int connection, struct voice_u return -1; ENDPT_DBG("%s line: %d connection: %d\n", __func__, line, connection); - ENDPT_DBG("%s lines[%d].pcm_state[%d]: %d, lines[%d].pcm_state[%d]: %d\n", __func__, - line, PCM_0, lines[line].pcm_state[PCM_0], line, PCM_1, lines[line].pcm_state[PCM_1]); + 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 @@ -377,11 +414,12 @@ int line_release_connection_by_asterisk(int line, int connection, struct voice_u return 0; } - if (lines[line].pcm_state[PCM_0] < LINE_PCM_STATE_CONNECTED && lines[line].pcm_state[PCM_1] < LINE_PCM_STATE_CONNECTED) { + if (get_callid_state(lines[line].pcm_callid[PCM_0]) < CALLID_ESTABLISHED && + get_callid_state(lines[line].pcm_callid[PCM_1]) < CALLID_ESTABLISHED) { return 0; } - if (lines[line].pcm_state[PCM_0] != connection && lines[line].pcm_state[PCM_1] != connection) { + if (lines[line].pcm_callid[PCM_0] != connection && lines[line].pcm_callid[PCM_1] != connection) { return 0; } @@ -393,16 +431,12 @@ int line_release_connection_by_asterisk(int line, int connection, struct voice_u if(!line_req) return -1; line_req->line = line; line_req->connection_id = line; - if (lines[line].pcm_state[PCM_0] == connection) { + if (lines[line].pcm_callid[PCM_0] == connection) { line_req->pcm_id = PCM_0; - lines[line].pcm_state[PCM_0] = LINE_PCM_STATE_NOT_USED; - ENDPT_DBG("%s changing value of lines[%d].pcm_state[PCM_0] to %d\n", __func__, - line, lines[line].pcm_state[PCM_0]); - } else if (lines[line].pcm_state[PCM_1] == connection) { + lines[line].pcm_callid[PCM_0] = CALLID_INVALID; + } else if (lines[line].pcm_callid[PCM_1] == connection) { line_req->pcm_id = PCM_1; - lines[line].pcm_state[PCM_1] = LINE_PCM_STATE_NOT_USED; - ENDPT_DBG("%s changing value of lines[%d].pcm_state[PCM_1] to %d\n", __func__, - line, lines[line].pcm_state[PCM_1]); + lines[line].pcm_callid[PCM_1] = CALLID_INVALID; } line_req->action = ACTION_CONN_CLOSE; memcpy(&line_req->ubus, ubus_req, sizeof(struct voice_ubus_req_t)); @@ -413,40 +447,32 @@ int line_release_connection_by_asterisk(int line, int connection, struct voice_u break; default: - if (lines[line].pcm_state[PCM_0] == connection) { - lines[line].pcm_state[PCM_0] = LINE_PCM_STATE_NOT_USED; - ENDPT_DBG("%s changing value of lines[%d].pcm_state[PCM_0] to %d\n", __func__, - line, lines[line].pcm_state[PCM_0]); - } else if (lines[line].pcm_state[PCM_1] == connection) { - lines[line].pcm_state[PCM_1] = LINE_PCM_STATE_NOT_USED; - ENDPT_DBG("%s changing value of lines[%d].pcm_state[PCM_1] to %d\n", __func__, - line, lines[line].pcm_state[PCM_1]); - } + 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_state) { +int line_update_connection_by_pbx(int line, int pcm_callid) { if (!voice_line_is_ready(line)) return -1; - ENDPT_DBG("%s Received update connection for line: %d with pcm_state: %d\n", - __func__, line, pcm_state); - ENDPT_DBG("%s lines[%d].pcm_state[%d]: %d, lines[%d].pcm_state[%d]: %d\n", __func__, - line, PCM_0, lines[line].pcm_state[PCM_0], line, PCM_1, lines[line].pcm_state[PCM_1]); + ENDPT_DBG("%s Received update connection for line: %d with pcm_callid: %d\n", + __func__, line, pcm_callid); + pcm_states_dump(__func__, line); if(lines[line].type != VOICE_LINE_DECT) return 0; - if (lines[line].pcm_state[PCM_0] == LINE_PCM_STATE_RINGING) { - lines[line].pcm_state[PCM_0] = pcm_state; - ENDPT_DBG("%s changing value of lines[%d].pcm_state[PCM_0] to %d\n", __func__, line, lines[line].pcm_state[PCM_0]); - } else if(lines[line].pcm_state[PCM_1] == LINE_PCM_STATE_RINGING) { - lines[line].pcm_state[PCM_1] = pcm_state; - ENDPT_DBG("%s changing value of lines[%d].pcm_state[PCM_1] to %d\n", __func__, line, lines[line].pcm_state[PCM_1]); - } + 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; } @@ -465,14 +491,11 @@ int line_new_connection_by_dect(int line, const char *cid, int pcm, struct voice return -1; ENDPT_DBG("%s line: %d, pcm: %d, cid: %s\n", __func__, line, pcm, cid); - ENDPT_DBG("%s lines[%d].pcm_state[%d]: %d, lines[%d].pcm_state[%d]: %d\n", __func__, - line, PCM_0, lines[line].pcm_state[PCM_0], line, PCM_1, lines[line].pcm_state[PCM_1]); + pcm_states_dump(__func__, line); if(pcm <= PCM_1) { - lines[line].pcm_state[pcm] = LINE_PCM_STATE_RINGING; + lines[line].pcm_callid[pcm] = CALLID_OBTAINING; lines[line].signaled_call_waiting = 0; - ENDPT_DBG("%s changing value of lines[%d].pcm_state[%d] to %d\n", __func__, - line, pcm, lines[line].pcm_state[pcm]); } if(!voice_line_is_offhook(line) && voice_line_simulate_hook(line, VOICE_EVT_OFFHOOK)) @@ -537,8 +560,7 @@ int line_close_connection_by_dect(int line, int pcm, struct voice_ubus_req_t *ub return -1; } ENDPT_DBG("%s() for line %d, pcm: %d\n", __func__, line, pcm); - ENDPT_DBG("%s lines[%d].pcm_state[%d]: %d, lines[%d].pcm_state[%d]: %d\n", __func__, line, PCM_0, lines[line].pcm_state[PCM_0], - line, PCM_1, lines[line].pcm_state[PCM_1]); + pcm_states_dump(__func__, line); if (pcm == CALL_DECT_UNAVAILABLE) { struct line_event_t *msg; @@ -558,33 +580,43 @@ int line_close_connection_by_dect(int line, int pcm, struct voice_ubus_req_t *ub pcm, UBUS_STATUS_OK); } - if (lines[line].pcm_state[pcm] == LINE_PCM_STATE_RINGING) { - struct line_event_t *msg; + 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("%s: DECT handsets may have not answered the call yet. " - "Send CALL_REJECT event to Asterisk\n", __func__); + ENDPT_DBG("%s: DECT handsets may have not answered the call yet. " + "Send CALL_REJECT event to Asterisk\n", __func__); - 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); - } + 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); + return send_reply_dectmngr(ubus_req, line + 1, // +1 Dectmngr lines starting from 1 + pcm, UBUS_STATUS_OK); + } else { + pcm = pcm >> 16; + } } - if(lines[line].pcm_state[PCM_0] <= LINE_PCM_STATE_RINGING || - lines[line].pcm_state[PCM_1] <= LINE_PCM_STATE_RINGING) { + 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 -1; } - lines[line].pcm_state[pcm] = LINE_PCM_STATE_NOT_USED; - ENDPT_DBG("%s changing value of lines[%d].pcm_state[%d] to %d\n", __func__, - line, pcm, lines[line].pcm_state[pcm]); + 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; diff --git a/line.h b/line.h index 0da3741c233c8c9a1204b28a511a9a2ee109286f..8a420ba7c284e49bf03dba0ee90324836e8dfc0a 100644 --- a/line.h +++ b/line.h @@ -10,6 +10,7 @@ enum line_action_t { ACTION_CONN_CREATE, ACTION_CONN_CLOSE, ACTION_SIG_RING, + ACTION_SIG_ANSWERED, }; // In UBUS request to voicemngr we need to define what this request is about @@ -20,6 +21,7 @@ enum call_action { CALL_TOGGLE, // Switch in Call Waiting CALL_CONFERENCE, // Join - start Call Conference CALL_DECT_UNAVAILABLE, // No DECT handset available for call + CALL_REJECT, // indicate for call_reject event, upper 16 bits for pcm_id when using CALL_LAST }; @@ -52,9 +54,11 @@ int find_endpt_from_asterisk_id(int line); int line_new_connection_by_asterisk(int line, int connection, struct voice_ubus_req_t *ubus_req); 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_state); +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_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); #endif diff --git a/schemas/ubus/endpt.json b/schemas/ubus/endpt.json index 457d9ab7ac1b5895c3192f9fed08a979c26c3fe6..0366b62edc27e18a7f0c0ad4240bc30624dd9a67 100644 --- a/schemas/ubus/endpt.json +++ b/schemas/ubus/endpt.json @@ -139,20 +139,22 @@ "oneOf": [ { "type": "object", - "required": [ "terminal", "add" ], + "required": [ "terminal", "add", "pcm_id" ], "properties": { "terminal": { "type": "integer", "minimum": 1, "maximum": 6 }, "add": { "type": "integer", "minimum": 0, "maximum": 5 }, - "cid": { "type": "string", "minLength": 0, "maxLength": 32, "pattern": "^[0-9]*#" } + "cid": { "type": "string", "minLength": 0, "maxLength": 32, "pattern": "^[0-9]*#" }, + "pcm_id": { "type": "integer", "minimum": 0, "maximum": 5 } } }, { "type": "object", - "required": [ "terminal", "release" ], + "required": [ "terminal", "release", "pcm_id" ], "properties": { "terminal": { "type": "integer", "minimum": 1, "maximum": 6 }, "release": { "type": "integer", "minimum": 0, "maximum": 5 }, - "cid": { "type": "string", "minLength": 0, "maxLength": 32, "pattern": "^[0-9]*#" } + "cid": { "type": "string", "minLength": 0, "maxLength": 32, "pattern": "^[0-9]*#" }, + "pcm_id": { "type": "integer", "minimum": 0, "maximum": 5 } } } ] @@ -240,6 +242,78 @@ } } } + }, + "codecs": { + "type": "object", + "required": [ "output" ], + "properties": { + "input": { + "type": "object", + "properties": {} + }, + "output": { + "type": "object", + "required": [ "codec_key" ], + "properties": { + "codec_key": { + "type": "object", + "required": [ + "name", + "ptime_min", + "ptime_max", + "ptime_default", + "ptime_increment", + "bitrate" + ], + "properties": { + "name": { + "type": "string", + "enum": [ + "G.711MuLaw", + "G.711ALaw", + "G.729a", + "G.723.1", + "G.726", + "G.728", + "G.729", + "G.729e", + "GSM-FR", + "GSM-EFR", + "GSM-HR", + "GSM-AMR", + "iLBC" + ] + }, + "ptime_min": { + "type": "integer", + "minimum": 0, + "maximum": 50 + }, + "ptime_max": { + "type": "integer", + "minimum": 0, + "maximum": 300 + }, + "ptime_default": { + "type": "integer", + "minimum": 0, + "maximum": 50 + }, + "ptime_increment": { + "type": "integer", + "minimum": 0, + "maximum": 50 + }, + "bitrate": { + "type": "number", + "minimum": 0, + "maximum": 100 + } + } + } + } + } + } } } } diff --git a/ubus.c b/ubus.c index 2962fa27662599cd12bff5568930359a1dd6a792..65e55c249c9c9d21c4189d7fed06a7af5368ca27 100644 --- a/ubus.c +++ b/ubus.c @@ -110,6 +110,9 @@ static int ubus_request_call(struct ubus_context *uctx, struct ubus_object *obj static int ubus_request_rtp_stats(struct ubus_context *uctx, struct ubus_object *obj __attribute__((unused)), struct ubus_request_data *req, const char *method __attribute__((unused)), struct blob_attr *msg); +static int ubus_request_codec_capability(struct ubus_context *uctx, struct ubus_object *obj __attribute__((unused)), + struct ubus_request_data *req, const char *method __attribute__((unused)), + struct blob_attr *msg __attribute__((unused))); const char uciStrConfig[] = "asterisk"; // UCI package name @@ -180,6 +183,7 @@ static struct ubus_method rpc_methods[] = { UBUS_METHOD("status", ubus_request_status, request_status_policy), UBUS_METHOD("call", ubus_request_call, request_call_policy), UBUS_METHOD("rtp_stats", ubus_request_rtp_stats, request_rtp_stats_policy), + UBUS_METHOD_NOARG("codecs", ubus_request_codec_capability), }; static struct ubus_object_type rpc_obj_type = @@ -457,7 +461,8 @@ static int ubus_request_count(struct ubus_context *uctx, struct ubus_object *obj int32_t dectEndpoints, totEndpoints; struct blob_buf bb; - if(blobmsg_parse(request_count_policy, ARRAY_SIZE(request_count_policy), keys, blob_data(msg), blob_len(msg))) { + if(blobmsg_parse(request_count_policy, ARRAY_SIZE(request_count_policy), + keys, blob_data(msg), blob_len(msg)) && blob_len(msg)) { return UBUS_STATUS_INVALID_ARGUMENT; } @@ -624,7 +629,7 @@ static int ubus_request_status(struct ubus_context *uctx, struct ubus_object *ob int line, unpopulatedDectEndpoints, totEndpoints; if(blobmsg_parse(request_status_policy, ARRAY_SIZE(request_status_policy), - keys, blob_data(msg), blob_len(msg))) { + keys, blob_data(msg), blob_len(msg)) && blob_len(msg)) { return UBUS_STATUS_INVALID_ARGUMENT; } @@ -756,6 +761,51 @@ static int ubus_request_rtp_stats(struct ubus_context *uctx, struct ubus_object return UBUS_STATUS_OK; } +// RPC handler for ubus call endpt codecs : Provides list of supported codecs and parameters +static int ubus_request_codec_capability(struct ubus_context *uctx, struct ubus_object *obj __attribute__((unused)), + struct ubus_request_data *req, const char *method __attribute__((unused)), + struct blob_attr *msg __attribute__((unused))) +{ + struct codec_capability codecs_list = {0}; + struct blob_buf blob; + memset(&blob, 0, sizeof(blob)); + + if(blob_buf_init(&blob, 0)) + return UBUS_STATUS_UNKNOWN_ERROR; + + int status = voice_get_codec_capability(&codecs_list); + if(!status) + { + for(int count = 0 ; count < codecs_list.num_codecs; count++) + { + void *table; + table = blobmsg_open_table(&blob, codecs_list.codecs[count].uciName); + blobmsg_add_string(&blob, "name", codecs_list.codecs[count].codec); + blobmsg_add_u32(&blob, "ptime_min", codecs_list.codecs[count].ptimeMin); + blobmsg_add_u32(&blob, "ptime_max", codecs_list.codecs[count].ptimeMax); + blobmsg_add_u32(&blob, "ptime_default", codecs_list.codecs[count].ptimeDefault); + blobmsg_add_u32(&blob, "ptime_increment", codecs_list.codecs[count].ptimeIncrement); + blobmsg_add_double(&blob, "bitrate", codecs_list.codecs[count].bitRate); + blobmsg_close_table(&blob, table); + } + } + else + { + // Read the /lib/voice/codecs.json file + static const char *codecfile = "/lib/voice/codecs.json"; + ENDPT_DBG("Display codecs from file codecs.json !!\n"); + int res = blobmsg_add_json_from_file(&blob, codecfile); + if(!res) + { + ENDPT_DBG("brcm capability query returned with error %d and Json file is missing/invalid \n", status); + return UBUS_STATUS_UNKNOWN_ERROR; + } + } + ubus_send_reply(uctx, req, blob.head); + blob_buf_free(&blob); + return UBUS_STATUS_OK; +} + // RPC handler for ubus call endpt call '{ "terminal": x, "add": x }' static int ubus_request_call(struct ubus_context *uctx, struct ubus_object *obj __attribute__((unused)), struct ubus_request_data *req, const char *method __attribute__((unused)), @@ -803,7 +853,7 @@ static int ubus_request_call(struct ubus_context *uctx, struct ubus_object *obj ENDPT_DBG("pcmId %d\n", pcmId); } - if(pcmId < CALL_DEFAULT0 || pcmId >= CALL_LAST || (!add && !release)) { + if((pcmId & 0xFFFF) < CALL_DEFAULT0 || (pcmId & 0xFFFF) >= CALL_LAST || (!add && !release)) { return UBUS_STATUS_INVALID_ARGUMENT; }