Code Monkey home page Code Monkey logo

jambonz-feature-server's People

Contributors

ajukes avatar akirilyuk avatar avoylenko avatar catharsis68 avatar davehorton avatar dependabot[bot] avatar eglehelms avatar guilherme-rauen avatar juansalvatella avatar mhertogs avatar mrfabio avatar paulotelles avatar pgujjeti avatar radicaldrew avatar snyk-bot avatar two56 avatar vcidst avatar vdharashive avatar xquanluu avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

jambonz-feature-server's Issues

race condition: quickly arriving CANCEL after INVITE/dial does not cancel outbound leg

Scenario:

  • incoming invite
  • application immediately does a dial verb
  • before dial is started, a CANCEL arrives
  • incoming call correctly processed, but an outbound call is attempt is made even though caller is gone

The specific issue, I believe, is that when an inbound call is canceled, we check to see if we have an outdial in progress and if so cancel that leg as well. In this case, when the cancel arrives we have not yet launched the outbound invite, yet have queued it up in such a manner that it is subsequently launched.

Implement standard Trace Context Propagation for action hook http requests

To enable linking traces between jambonz and external services, it is necessary to propagate trace context between services. I've seen that you've added a "TraceId" field on the payload when communicating with other services via action hooks over HTTP but it would be great to implement a Trace Context Propagation standard such as the standard W3 (https://w3c.github.io/trace-context/) or B3 from OpenZipkin (https://github.com/openzipkin/b3-propagation).

More info here:

Non Success SIP Response causes error

When remote endpoint responds with 503 for example, logs show error and returns 500 Server error to application

WARNING: NODE_APP_INSTANCE value of '0' did not match any instance config file names.
WARNING: See https://github.com/lorenwest/node-config/wiki/Strict-Mode
TypeError: Cannot read property 'updateCallStatus' of undefined
    at new CallSession (/home/deploy/jambonz-feature-server/lib/session/call-session.js:21:50)
    at new RestCallSession (/home/deploy/jambonz-feature-server/lib/session/rest-call-session.js:7:5)
    at cbRequest (/home/deploy/jambonz-feature-server/lib/http-routes/api/create-call.js:124:16)
    at Object._app.request [as callback] (/home/deploy/jambonz-feature-server/node_modules/drachtio-srf/lib/srf.js:400:9)
    at DrachtioAgent.obj.pendingRequests.set (/home/deploy/jambonz-feature-server/node_modules/drachtio-srf/lib/drachtio-agent.js:310:16)
    at DrachtioAgent._onMsg (/home/deploy/jambonz-feature-server/node_modules/drachtio-srf/lib/drachtio-agent.js:717:11)
    at WireProtocol.emit (events.js:198:13)
    at WireProtocol.processMessageBuffer (/home/deploy/jambonz-feature-server/node_modules/drachtio-srf/lib/wire-protocol.js:270:12)
    at WireProtocol._onData (/home/deploy/jambonz-feature-server/node_modules/drachtio-srf/lib/wire-protocol.js:304:14)
    at Socket.emit (events.js:198:13)
    at addChunk (_stream_readable.js:287:12)
    at readableAddChunk (_stream_readable.js:264:13)
    at Socket.Readable.push (_stream_readable.js:223:10)
    at TCP.onStreamRead [as onread] (internal/stream_base_commons.js:94:17)

allow application to specify a specific SIP trunk / carrier on dial verb

Currently, the dial verb when used with type 'phone' will send the call out through a configured SIP trunk. If there are multiple SIP trunking providers with outbound trunk, then a least cost routing algorithm will be used (subject to configuration) to determine which SIP trunk to use. However, in many cases it would probably be useful to allow the application to specify the specific sip trunking provider / carrier to use, e.g. below where "trunk" would be a new, optional property on dial:

{
   "verb": "dial",
   "target" : [
      {
         "type" : "phone",
         "number": "+16173333456",
         "trunk": "peerless"
      
      }
   ]
}

REST API: Cannot hang-up call

I originate a new call (on Jambonz.us)

/v1/Accounts/myaccount/Calls %{
  call_hook: %{
    method: "POST",
    url: "---"
  },
  call_status_hook: %{
    method: "POST",
    url: "...."
  },
  from: "1111",
  to: %{name: ".....", overrideTo: "34", type: "user"}
} 

And I get

%{sid: "76ad1a2b-3f0f-4a6f-9141-591ad175c952"}}}

The call progresses and I get notified that it is ringing (SIP state 180)

I try hanging it up:

16:31:00.047 -- REq /v1/Accounts/myaccount/Calls/76ad1a2b-3f0f-4a6f-9141-591ad175c952 %{call_status: "completed"} -> {{:error,
  "{\"msg\":\"current call state is incompatible with requested action\"}"}}
16:31:00.185 -- REq /v1/Accounts/myaccount/Calls/76ad1a2b-3f0f-4a6f-9141-591ad175c952 %{call_status: "no-answer"} -> {{:error, "Accepted"}}

But my phone keeps on ringing (and I get no status updates)

If I do it again, I get errors, bu the call stays there

16:31:10.479 --- REq /v1/Accounts/myaccount/Calls/76ad1a2b-3f0f-4a6f-9141-591ad175c952 %{call_status: "completed"} -> {{:error, "{\"msg\":\"Cannot read property 'hasStableDialog' of undefined\"}"}}
16:31:10.599 --- REq /v1/Accounts/myaccount/Calls/76ad1a2b-3f0f-4a6f-9141-591ad175c952 %{call_status: "no-answer"} -> {{:error, "{\"msg\":\"Cannot read property 'direction' of undefined\"}"}}

In the end (after one minute or so) it closes and I get a status back:

{
    "call_sid": "76ad1a2b-3f0f-4a6f-9141-591ad175c952",
    "direction": "outbound",
    "from": "1111",
    "to": "....",
    "call_id": "e91be8e9-2c7b-123b-9f81-0e2793d0d4c3",
    "sip_status": 503,
    "call_status": "failed",
    "account_sid": "myaccount"
}

no alerts in the alert panel

my application was returning a object instead of an array of objects and all calls was terminated

and there was no alert in the alert panel

please advice

thanks
image

Call not hanged up after a 487 Request Terminated from callee

If I place a call using Jambonz and the callee never answers I can see on the SIP traces that eventually I’ll get a 487 Request Terminated from B but that’s not being picked up by Jambonz so the call is not hanged up and hence the action hook not triggered. After the 487 the progress tone is not heard anymore and when A finally hangs up, the action hook is triggered with a dial_call_status of early-media.

Initial Action Hook does not include a domain field when registered client

When we have a single applicationSid handling multiple tenants we need to somehow distinguish who "ajukes" belongs to. For example [email protected] vs [email protected]

Currently the initial payload does not include the domain. Suggest originatingDomainName or something similar if call is initiated from registered handset

	direction=inbound, 
	callSid=5424cfbb-00cf-484a-a3d1-3e9fee159e24,
	accountSid=fef61e75-cec3-496c-a7bc-8368e4d02a04, 
	applicationSid=508c3a11-4b6e-41cb-b162-a87dd37a8a42, 
	from=ajukes, 
	to=07956697540,
	callerName=, 
	callId=24766c3e-faaf-1238-cca4-02b574cefade, 
	sipStatus=100, 
	callStatus=trying, 
	originatingSipIp=78.33.150.124:5060,
	originatingSipTrunkName=null, 
	...

No dialSipStatus on action hook after out dial completion

When a Target or multiple Targets are called and the call completes, the subsequent action hook request does not contain the sip status of the failed (or successful) call leg.

The Action hooks do include the sipStatus of the A Leg however this does not help in further routing decisions:


Action Hook after 200OK

DrachtioRequest(callSid=64883657-03c3-4987-87a1-316b4b25ca4b, callId=2ea258fb-47cb-123a-a7bf-06a78b9c3549, 
				parentCallSid=null, accountSid=9351f46a-678c-43f5-b8a6-d4eb58d131af, 
				from=+441179830003, to=02033888666, callStatus=in-progress, sipStatus=200, 
				direction=inbound, callerName=null, digits=null, speech=null, customerData=null,
   			    dialCallSid=c2d4aeee-ec3c-45e4-bed7-5658ff0cd492, dialCallStatus=completed, 
			    queueSid=null, queuePosition=null, queueTime=null, queueSize=null, queueResult=null)

Action Hook after 403

DrachtioRequest(callSid=b828ddd9-8c6b-468f-b7d3-2bfd24af0671, callId=3e932dba-47be-123a-efa6-02af80f5881b, 
				parentCallSid=null, accountSid=9351f46a-678c-43f5-b8a6-d4eb58d131af, 
				from=01383722538, to=013839, callStatus=trying, sipStatus=100, 
				direction=inbound, callerName=null, digits=null, speech=null,
				customerData=null, dialCallSid=447b9825-f2e2-4ec0-9f80-6042037eec3e, 
				dialCallStatus=failed, queueSid=null, queuePosition=null, queueTime=null,
				queueSize=null, queueResult=null)

dialCallStatus allows us to know if the call completed of failed, suggest dialSipStatus field to give us the sip code of the dial.

REST API: cancelling calls

When cancelling a call with PUT Update Call - Live Call Control, you are supposed to set its call_status to completed or not-answered. This is good if you know the current call status, but if you don't you have to try, match on error, and try again. And if you try "completed" and it does not work, you try "non-answered" and it might not work again if the call was connected in the meantime.

I believe the most common case is " just hangup", where it would be up to Jambonz to check the current state and hang up the call accordingly.

Multiple Redis connection strings for global cache

When using a Global replicated cache (such as Aws Global Datatore) , each replicated cluster is read only. The only writeable node is the primary cluster endpoint.

This means that every jambones cluster currently has to connect to the primary cluster to read and write, defeating the purpose of a distributed cache.

Ideally a separate read only connection string could be used for retrieving data from the closest replicated cache.

When a write to the cache is needed jambones would connect to the writeable primary cache which would in turn replicate to its slaves.

When returning sip:decline jambones does not send a completed event

After returning 480 response, we would expected to see a drachtio leg a event completed

[
	{
		"@timestamp": "2020-02-20T14:22:07.427+00:00",
		"@version": "1",
		"message": "initial-drachtio-request DrachtioInitialRequest(direction=inbound, callSid=41770ea3-c431-4237-ac6e-597c74b99ff7, accountSid=fef61e75-cec3-496c-a7bc-8368e4d02a04, applicationSid=508c3a11-4b6e-41cb-b162-a87dd37a8a42, from=+447956697540, to=+442033885380, callerName=+447956697540, callId=372bdc56-ce8f-1238-fcb3-02b574cefade, sipStatus=100, callStatus=trying, originatingSipIp=99.80.180.248:5060, originatingSipTrunkName=customers, sip=SipPayload(headers={via=SIP/2.0/UDP 34.241.251.115;rport=5060;branch=z9hG4bK44aUc9U0Z0UrS;received=172.31.50.237, max-forwards=70, from=<sip:[email protected]:5060>;tag=g80ByUXK6yt7c, to=<sip:[email protected]:5060>, call-id=372bdc56-ce8f-1238-fcb3-02b574cefade, cseq=16550471 INVITE, contact=<sip:[email protected]:5060>, expires=330, user-agent=Orchid 3.1.7.2, allow=BYE, CANCEL, ACK, INVITE, INFO, OPTIONS, supported=timer, replaces, session-expires=1800;refresher=uas, min-se=90, content-type=application/sdp, content-length=687, X-CID=1b930280-183e4fd2-11230e-7fb2f6210828-de641fac-13e2-7225, X-Forwarded-For=99.80.180.248:5060, X-Originating-Carrier=customers, p-asserted-identity=<sip:[email protected];user=phone>}, payload=[{type=application/sdp, content=v=0\r\no=vibesbc01a 300924929 1582208528 IN IP4 54.76.13.114\r\ns=sip call\r\nc=IN IP4 54.76.13.114\r\nt=0 0\r\nm=audio 50086 RTP/AVP 9 113 8 0 18 112 110 3 101\r\na=silenceSupp:off - - - -\r\na=rtpmap:9 G722/8000\r\na=rtpmap:113 AMR-WB/16000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:18 G729/8000\r\na=rtpmap:112 AMR/8000\r\na=rtpmap:110 GSM-EFR/8000\r\na=rtpmap:3 GSM/8000\r\na=rtpmap:101 telephone-event/8000\r\na=fmtp:113 octet-align=0;mode-change-period=2;mode-change-capability=2;mode-change-neighbor=1;max-red=0\r\na=fmtp:18 annexb=no\r\na=fmtp:112 octet-align=0;mode-change-period=2;mode-change-capability=2;mode-change-neighbor=1;max-red=0\r\na=fmtp:101 0-15\r\na=sendrecv\r\na=rtcp:50087\r\na=ptime:20\r\n}], body=v=0\r\no=vibesbc01a 300924929 1582208528 IN IP4 54.76.13.114\r\ns=sip call\r\nc=IN IP4 54.76.13.114\r\nt=0 0\r\nm=audio 50086 RTP/AVP 9 113 8 0 18 112 110 3 101\r\na=silenceSupp:off - - - -\r\na=rtpmap:9 G722/8000\r\na=rtpmap:113 AMR-WB/16000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:18 G729/8000\r\na=rtpmap:112 AMR/8000\r\na=rtpmap:110 GSM-EFR/8000\r\na=rtpmap:3 GSM/8000\r\na=rtpmap:101 telephone-event/8000\r\na=fmtp:113 octet-align=0;mode-change-period=2;mode-change-capability=2;mode-change-neighbor=1;max-red=0\r\na=fmtp:18 annexb=no\r\na=fmtp:112 octet-align=0;mode-change-period=2;mode-change-capability=2;mode-change-neighbor=1;max-red=0\r\na=fmtp:101 0-15\r\na=sendrecv\r\na=rtcp:50087\r\na=ptime:20\r\n, method=INVITE, version=2.0, uri=sip:[email protected]:5060, raw=INVITE sip:[email protected]:5060 SIP/2.0\r\nVia: SIP/2.0/UDP 34.241.251.115;rport=5060;branch=z9hG4bK44aUc9U0Z0UrS;received=172.31.50.237\r\nMax-Forwards: 70\r\nFrom: <sip:[email protected]:5060>;tag=g80ByUXK6yt7c\r\nTo: <sip:[email protected]:5060>\r\nCall-ID: 372bdc56-ce8f-1238-fcb3-02b574cefade\r\nCSeq: 16550471 INVITE\r\nContact: <sip:[email protected]:5060>\r\nExpires: 330\r\nUser-Agent: Orchid 3.1.7.2\r\nAllow: BYE, CANCEL, ACK, INVITE, INFO, OPTIONS\r\nSupported: timer, replaces\r\nSession-Expires: 1800;refresher=uas\r\nMin-SE: 90\r\nContent-Type: application/sdp\r\nContent-Length: 687\r\nX-CID: 1b930280-183e4fd2-11230e-7fb2f6210828-de641fac-13e2-7225\r\nX-Forwarded-For: 99.80.180.248:5060\r\nX-Originating-Carrier: customers\r\nP-Asserted-Identity: <sip:[email protected];user=phone>\r\n\r\nv=0\r\no=vibesbc01a 300924929 1582208528 IN IP4 54.76.13.114\r\ns=sip call\r\nc=IN IP4 54.76.13.114\r\nt=0 0\r\nm=audio 50086 RTP/AVP 9 113 8 0 18 112 110 3 101\r\na=silenceSupp:off - - - -\r\na=rtpmap:9 G722/8000\r\na=rtpmap:113 AMR-WB/16000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:18 G729/8000\r\na=rtpmap:112 AMR/8000\r\na=rtpmap:110 GSM-EFR/8000\r\na=rtpmap:3 GSM/8000\r\na=rtpmap:101 telephone-event/8000\r\na=fmtp:113 octet-align=0;mode-change-period=2;mode-change-capability=2;mode-change-neighbor=1;max-red=0\r\na=fmtp:18 annexb=no\r\na=fmtp:112 octet-align=0;mode-change-period=2;mode-change-capability=2;mode-change-neighbor=1;max-red=0\r\na=fmtp:101 0-15\r\na=sendrecv\r\na=rtcp:50087\r\na=ptime:20\r\n))",
		"logger_name": "uk.co.viva.vdrachtioservice.controllers.IvrController",
		"thread_name": "http-nio-8080-exec-5",
		"level": "INFO",
		"level_value": 20000,
		"from": "+447956697540",
		"to": "+442033885380",
		"cid": "41770ea3-c431-4237-ac6e-597c74b99ff7"
	},
	{
		"@timestamp": "2020-02-20T14:22:07.540+00:00",
		"@version": "1",
		"message": "initial-drachtio-response [Verb(gather=null, say=null, play=null, reject=null, hangup=null, redirect=null, dial=null, tag=Tag(data={port=5060, ip=99.80.180.248, privacy=false, pAsserted=+447956697540})), Verb(gather=null, say=null, play=null, reject=null, hangup=null, redirect=null, dial=Dial(actionHook=/ivr/2e0debc1-fb1f-4730-ad9d-261a48f3f8ba, callerId=447956697540, dialMusic=https://vibe-public.s3-eu-west-1.amazonaws.com/en-gb.wav, timeLimit=14400, timeout=60, answerOnBridge=true, target=[Target(type=user, url=null, number=null, sipUri=null, [email protected], auth=null)], listen=Listen(url=/record, mixType=stereo, finishOnKey=#, maxLength=14400, metadata={}, passDtmf=true, playBeep=false, sampleRate=8000, timeout=null, transcribe=null), transcribe=null, dtmfCapture=[*06, *07, *08, *09, *01, *02, *03, *04, *05], dtmfHook=/ivr/dtmf), tag=null)]",
		"logger_name": "uk.co.viva.vdrachtioservice.controllers.IvrController",
		"thread_name": "http-nio-8080-exec-5",
		"level": "INFO",
		"level_value": 20000,
		"from": "+447956697540",
		"to": "+442033885380",
		"cid": "41770ea3-c431-4237-ac6e-597c74b99ff7"
	},
	{
		"@timestamp": "2020-02-20T14:22:07.707+00:00",
		"@version": "1",
		"message": "drachtio-event DrachtioRequest(callSid=41770ea3-c431-4237-ac6e-597c74b99ff7, callId=372bdc56-ce8f-1238-fcb3-02b574cefade, parentCallSid=null, accountSid=fef61e75-cec3-496c-a7bc-8368e4d02a04, from=+447956697540, to=+442033885380, callStatus=trying, sipStatus=100, direction=inbound, callerName=null, digits=null, speech=null, customerData=null, dialCallSid=null, dialCallStatus=null)",
		"logger_name": "uk.co.viva.vdrachtioservice.controllers.IvrController",
		"thread_name": "http-nio-8080-exec-4",
		"level": "INFO",
		"level_value": 20000,
		"from": "+447956697540",
		"to": "+442033885380",
		"cid": "41770ea3-c431-4237-ac6e-597c74b99ff7"
	},
	{
		"@timestamp": "2020-02-20T14:22:07.913+00:00",
		"@version": "1",
		"message": "drachtio-event DrachtioRequest(callSid=5ff6a736-d41a-4843-863c-08584a4d509d, callId=3775fd62-ce8f-1238-4e96-02996c8b2a60, parentCallSid=41770ea3-c431-4237-ac6e-597c74b99ff7, accountSid=fef61e75-cec3-496c-a7bc-8368e4d02a04, from=447956697540, [email protected], callStatus=trying, sipStatus=100, direction=outbound, callerName=null, digits=null, speech=null, customerData=null, dialCallSid=null, dialCallStatus=null)",
		"logger_name": "uk.co.viva.vdrachtioservice.controllers.IvrController",
		"thread_name": "http-nio-8080-exec-3",
		"level": "INFO",
		"level_value": 20000,
		"pid": "41770ea3-c431-4237-ac6e-597c74b99ff7",
		"from": "447956697540",
		"to": "[email protected]",
		"cid": "5ff6a736-d41a-4843-863c-08584a4d509d"
	},
	{
		"@timestamp": "2020-02-20T14:22:08.105+00:00",
		"@version": "1",
		"message": "drachtio-event DrachtioRequest(callSid=5ff6a736-d41a-4843-863c-08584a4d509d, callId=3775fd62-ce8f-1238-4e96-02996c8b2a60, parentCallSid=41770ea3-c431-4237-ac6e-597c74b99ff7, accountSid=fef61e75-cec3-496c-a7bc-8368e4d02a04, from=447956697540, [email protected], callStatus=ringing, sipStatus=180, direction=outbound, callerName=null, digits=null, speech=null, customerData=null, dialCallSid=null, dialCallStatus=null)",
		"logger_name": "uk.co.viva.vdrachtioservice.controllers.IvrController",
		"thread_name": "http-nio-8080-exec-6",
		"level": "INFO",
		"level_value": 20000,
		"pid": "41770ea3-c431-4237-ac6e-597c74b99ff7",
		"from": "447956697540",
		"to": "[email protected]",
		"cid": "5ff6a736-d41a-4843-863c-08584a4d509d"
	},
	{
		"@timestamp": "2020-02-20T14:22:10.008+00:00",
		"@version": "1",
		"message": "drachtio-request DrachtioRequest(callSid=41770ea3-c431-4237-ac6e-597c74b99ff7, callId=372bdc56-ce8f-1238-fcb3-02b574cefade, parentCallSid=null, accountSid=fef61e75-cec3-496c-a7bc-8368e4d02a04, from=+447956697540, to=+442033885380, callStatus=trying, sipStatus=100, direction=inbound, callerName=null, digits=null, speech=null, customerData={port=5060, ip=99.80.180.248, privacy=false, pAsserted=+447956697540}, dialCallSid=5ff6a736-d41a-4843-863c-08584a4d509d, dialCallStatus=failed)",
		"logger_name": "uk.co.viva.vdrachtioservice.controllers.IvrController",
		"thread_name": "http-nio-8080-exec-10",
		"level": "INFO",
		"level_value": 20000,
		"from": "+447956697540",
		"to": "+442033885380",
		"cid": "41770ea3-c431-4237-ac6e-597c74b99ff7"
	},
	{
		"@timestamp": "2020-02-20T14:22:10.084+00:00",
		"@version": "1",
		"message": "drachtio-request DrachtioRequest(callSid=41770ea3-c431-4237-ac6e-597c74b99ff7, callId=372bdc56-ce8f-1238-fcb3-02b574cefade, parentCallSid=null, accountSid=fef61e75-cec3-496c-a7bc-8368e4d02a04, from=+447956697540, to=+442033885380, callStatus=trying, sipStatus=100, direction=inbound, callerName=null, digits=null, speech=null, customerData={port=5060, ip=99.80.180.248, privacy=false, pAsserted=+447956697540}, dialCallSid=5ff6a736-d41a-4843-863c-08584a4d509d, dialCallStatus=failed)",
		"logger_name": "uk.co.viva.vdrachtioservice.controllers.IvrController",
		"thread_name": "http-nio-8080-exec-10",
		"level": "INFO",
		"level_value": 20000,
		"from": "+447956697540",
		"to": "+442033885380",
		"cid": "41770ea3-c431-4237-ac6e-597c74b99ff7"
	},
	{
		"@timestamp": "2020-02-20T14:22:10.095+00:00",
		"@version": "1",
		"message": "drachtio-event DrachtioRequest(callSid=5ff6a736-d41a-4843-863c-08584a4d509d, callId=3775fd62-ce8f-1238-4e96-02996c8b2a60, parentCallSid=41770ea3-c431-4237-ac6e-597c74b99ff7, accountSid=fef61e75-cec3-496c-a7bc-8368e4d02a04, from=447956697540, [email protected], callStatus=failed, sipStatus=480, direction=outbound, callerName=null, digits=null, speech=null, customerData=null, dialCallSid=null, dialCallStatus=null)",
		"logger_name": "uk.co.viva.vdrachtioservice.controllers.IvrController",
		"thread_name": "http-nio-8080-exec-9",
		"level": "INFO",
		"level_value": 20000,
		"pid": "41770ea3-c431-4237-ac6e-597c74b99ff7",
		"from": "447956697540",
		"to": "[email protected]",
		"cid": "5ff6a736-d41a-4843-863c-08584a4d509d"
	},
	{
		"@timestamp": "2020-02-20T14:22:10.192+00:00",
		"@version": "1",
		"message": "drachtio-response [Verb(gather=null, say=null, play=null, reject=Reject(status=480, reason=Temporary Unavailable, headers=null), hangup=null, redirect=null, dial=null, tag=null)]",
		"logger_name": "uk.co.viva.vdrachtioservice.controllers.IvrController",
		"thread_name": "http-nio-8080-exec-10",
		"level": "INFO",
		"level_value": 20000,
		"from": "+447956697540",
		"to": "+442033885380",
		"cid": "41770ea3-c431-4237-ac6e-597c74b99ff7"
	}
]

redis error updating call status

Seeing this at the end of a call:

[2021-11-22 13:09:28.410 +0000] INFO (7952 on ip-172-32-32-147): updateCallStatus result: Error: node_redis: The HMSET command contains a invalid argument type.
Only strings, dates and buffers are accepted. Please update your code to use valid argument types.,1

Teams target not supported on POST /v1/Accounts/{accountId}/Calls

When the "to" field is a Teams object and error is thrown

1|jambonz-api-server  | {"level":30, "time": "2020-09-30T09:39:57.285Z","pid":10277,"hostname":"ip-172-31-22-10","msg":"invalid client request","stack":"Error: missing or invalid to property: {\"type\":\"teams\",\"number\":\"+441273652002\",\"tenant\":\"5f51637ce390c45fbc95ace6.customers.viva-eu.net\",\"vmail\":false}\n    at validateTo (/home/admin/apps/jambonz-api-server/lib/routes/api/accounts.js:78:9)\n    at validateCreateCall (/home/admin/apps/jambonz-api-server/lib/routes/api/accounts.js:88:3)\n    at router.post (/home/admin/apps/jambonz-api-server/lib/routes/api/accounts.js:276:11)\n    at process._tickCallback (internal/process/next_tick.js:68:7)","type":"Error","v":1}

"dialMusic" continues to be played when dial is ended

When the verb dial is finished, if the call is still in progress with other verbs, you will notice that the audio file specified with the dialMusic attribute of the verb dial continues to be played.

To reproduce the bug, you have to reply to the call invitation with the following verbs for example:

  [
   {
      "verb": "dial",
      "dialMusic": "http://path_to_audio_file_1",
      "timeout": x
      ...
   },
   {
      "verb": "play",
      "url": "http://path_to_audio_file_2"
   }
   {
      "verb": "listen",
      "url": "wss://path_to_recorder_server"
   }
]

After the specified timeout you will notice that the file (http://path_to_audio_file_1) continues to be played even though the parent dial is finished

Local Cached Data - Outage Mitigation

Not an issue but here for discussion:

When reading from a central DB/Cache we run the risk of a service affecting outage. Be it MySQL Aurora or Redis Global DS etc. An ideal scenario would be to able to continue call routing even in the event of a MySQL issue, or even a Redis issue.

  1. MySQL being fairly static data could be written to a cache which would mitigate a MySQL outage and also improve performance as Jambones is heavy on reads. Another option could be a local MySQL and replication but this could bring extra overhead and complications?

  2. Redis is a little more difficult as Jambones uses it for more realtime data, If we have a redis issue, then its pretty much game over, however another option would be to replace Redis with IMDG (In memory datagrid) such as Hazelcast, Each FS,SBC & RTP Server would run a Hazelcast instance which joins and become part of a distributed data grid with no spf. As the Jambones cluster grows and shrinks so does the IMDG. Out of box you get Distributed locking, Nearside Cache, Queues, Topics etc. All traffic is local network so any external outage would not affect the running of the cache, each nodes data is backed up on other nodes so you can lose instances and keep data integrity.

For multiple Jambones clusters which are geographically distributed, instead of AWS Redis Global Datastore, AWS SNS could be used to keep distributed Hazelcast clusters in sync with each other such as SIP Client's AOR, Queue status etc.

Multiple Teams Targets only ring first Target

{"@timestamp":"2020-09-18T09:36:36.135+00:00","@version":"1","message":"Response From IVR","logger_name":"uk.co.viva.vdrachtioservice.services.RouteService","thread_name":"http-nio-8080-exec-7","level":"INFO","level_value":20000,"from":"+447956697540","to":"02033882120","cid":"7f6b4253-2dcf-47af-ac75-ab8ea1085e19","responseFromIVR":[{"dial":{"actionHook":"/ivr/987a7ccd-0b49-4363-9157-7b5944f19bc0","callerId":"+447956697540","dialMusic":"https://vibe-public.s3-eu-west-1.amazonaws.com/en-gb.wav","timeLimit":14400,"timeout":180,"answerOnBridge":true,"target":[{"type":"teams","number":"+442033882121","tenant":"5f51637ce390c45fbc95ace6.customers.viva-uk.net","vmail":false},{"type":"teams","number":"+442033882122","tenant":"5f51637ce390c45fbc95ace6.customers.viva-uk.net","vmail":false}],"listen":{"url":"/record","mixType":"stereo","finishOnKey":"#","maxLength":14400,"metadata":{},"passDtmf":true,"playBeep":false,"sampleRate":8000},"dtmfCapture":["*06","*07","*08","*09","*01","*02","*03","*04","*05"],"dtmfHook":"/ivr/dtmf","headers":{}}}]}

where we have multiple targets, it seems that only the first target is initiating an INVITE

[{"type":"teams","number":"+442033882121","tenant":"5f51637ce390c45fbc95ace6.customers.viva-uk.net","vmail":false},{"type":"teams","number":"+442033882122","tenant":"5f51637ce390c45fbc95ace6.customers.viva-uk.net","vmail":false}]

I checked the drachtio logs and cant see any INVITE for +442033882122

relative url for listen does not work if createCall REST supplied call_hook

When a user creates a call through REST, and supplies a 'call_hook' property rather than 'application_sid', a listen verb that uses a relative url fails with the following error

{"level":20,"time":1580832859316,"pid":15381,"hostname":"ip-172-31-3-33","callId":"3be80dce-c20c-1238-6185-06d91d68c9b0","callSid":"3b7607ec-12e9-4c36-b582-e816593ca14b","action":"/ivr/973e4b02-bc61-4fc0-8cdb-3ce4fa4df8d1","callerId":"447956697540","dialMusic":"https://vibe-public.s3-eu-west-1.amazonaws.com/en-gb.wav","timeLimit":14400,"timeout":30,"answerOnBridge":true,"target":[{"type":"user","name":"ajukes"},{"type":"user","name":"daveh"},{"type":"user","name":"brandon"}],"listen":{"url":"/record","mixType":"stereo","finishOnKey":"#","maxLength":14400,"metadata":{"customerId":null,"parentCallSid":"3b7607ec-12e9-4c36-b582-e816593ca14b"},"passDtmf":true,"playBeep":false,"sampleRate":8000},"msg":"makeTask: dial","v":1}
2|jambonz-feature-server  | {"level":20,"time":1580832859317,"pid":15381,"hostname":"ip-172-31-3-33","callId":"3be80dce-c20c-1238-6185-06d91d68c9b0","callSid":"3b7607ec-12e9-4c36-b582-e816593ca14b","url":"/record","mixType":"stereo","finishOnKey":"#","maxLength":14400,"metadata":{"customerId":null,"parentCallSid":"3b7607ec-12e9-4c36-b582-e816593ca14b"},"passDtmf":true,"playBeep":false,"sampleRate":8000,"msg":"makeTask: listen","v":1}
2|jambonz-feature-server  | TypeError: Cannot read property 'originalRequest' of undefined
2|jambonz-feature-server  |     at TaskListen.normalizeUrl (/home/deploy/jambonz-feature-server/lib/tasks/task.js:64:35)
2|jambonz-feature-server  |     at new TaskListen (/home/deploy/jambonz-feature-server/lib/tasks/listen.js:19:22)
2|jambonz-feature-server  |     at makeTask (/home/deploy/jambonz-feature-server/lib/tasks/make_task.js:41:14)
2|jambonz-feature-server  |     at new TaskDial (/home/deploy/jambonz-feature-server/lib/tasks/dial.js:59:25)
2|jambonz-feature-server  |     at makeTask (/home/deploy/jambonz-feature-server/lib/tasks/make_task.js:23:14)
2|jambonz-feature-server  |     at normalizeJamones.map (/home/deploy/jambonz-feature-server/lib/utils/retrieve-app.js:28:56)
2|jambonz-feature-server  |     at Array.map (<anonymous>)
2|jambonz-feature-server  |     at retrieveApp (/home/deploy/jambonz-feature-server/lib/utils/retrieve-app.js:28:41)
2|jambonz-feature-server  |     at Request.request [as _callback] (/home/deploy/jambonz-feature-server/lib/utils/notifiers.js:35:26)
2|jambonz-feature-server  |     at Request.self.callback (/home/deploy/jambonz-feature-server/node_modules/request/request.js:185:22)
2|jambonz-feature-server  | 

Subsequent Action hook does not include customerData

Subsequent Request

"drachtio-request" : {
    "callSid" : "5e9c92b6-f18d-4106-a47f-f20be61e82bc",
    "callId" : "5863ec22-c904-1238-6185-06d91d68c9b0",
    "parentCallSid" : null,
    "accountSid" : "fef61e75-cec3-496c-a7bc-8368e4d02a04",
    "from" : "+447956697540",
    "to" : "+442033885379",
    "callStatus" : "in-progress",
    "sipStatus" : "200",
    "direction" : "inbound",
    "callerName" : null,
    "digits" : "1",
    "speech" : null,
    "customerData" : null
  }

Call Status Events are ok and still carry the customerData payload

 "ivr-event" : {
    "callSid" : "5e9c92b6-f18d-4106-a47f-f20be61e82bc",
    "callId" : "5863ec22-c904-1238-6185-06d91d68c9b0",
    "parentCallSid" : null,
    "accountSid" : "fef61e75-cec3-496c-a7bc-8368e4d02a04",
    "from" : "+447956697540",
    "to" : "+442033885379",
    "callStatus" : "in-progress",
    "sipStatus" : "200",
    "direction" : "inbound",
    "callerName" : null,
    "digits" : null,
    "speech" : null,
    "customerData" : {
      "port" : "5060",
      "ip" : "99.80.180.248",
      "privacy" : "false",
      "pAsserted" : "+447956697540"
    }
  }

Close Websocket on Listen Verb

Not sure if its a bug or just the way its got to be but it takes 10+ seconds for my app to close the websocket connection.

Can you confirm that you close the socket after the listen verb ends?

WS-API: reconnection of WS session does not trigger reconnect event

Hi,

I tried to implement reconnection logic for the websocket conection, however during testing, I noticed that the reconnection itself works, upon losing the WS connection, Jambonz instantly recreates it. However to be able to identify this new WS connection I expected to get the session:reconnect event, which is never emitted by Jambonz. Instead upon reconnecting the WS connection, the flow just continues as nothing happened before (which is good :)), however since I didn't get the initial session reconnection event, I am not able to match the new connection to any existing call state on my end.

I have attached an example WebSocket server code with a lot of logs which can be used to test the reconnection logic.

It will kill the ws connection after 5 seconds which will trigger a reconnect on Jambonz side.

I can see that the connection is recreated, since I am getting a vebr:hook events on the new connection. However as mentioned before, session:reconnect never reaches my end.

Example code which will send commands back and forth in a loop over the WS connection:

const express = require("express");
const WebSocket = require("ws");
const { WsSession } = require("@jambonz/node-client");

let wsCounter = 0;

const jambonzRedirectLoop = [{say: {
					text: "silence_stream://1000"
				}}, {
  				"verb": "redirect",
  				"actionHook": "/test",
				}];

const start = () => {
    const app = express();
    const port = 8000;
    const server = app.listen(port, ()=>{
        console.log("server listening at port", port);
    });
    const websocketServer = new WebSocket.Server({
        noServer: true,
        path: "/websockets",
    });
    server.on("upgrade", (request, socket, head) => {
		console.log(wsCounter, "received upgrade request", );
        websocketServer.handleUpgrade(request, socket, head, (websocket) => {
			websocket.counter = wsCounter;
			wsCounter += 1;
        	websocketServer.emit("connection", websocket, request);
     });
    });
    websocketServer.on(
        "connection",
        function connection(websocketConnection, connectionRequest) {
            console.log(websocketConnection.counter, "received ws connection");

			// we need to do this for monkeypatchin WS connection instance
			// no reference needed for later use
			new WsSession({
					logger: { info: () => { }, error: () => { }, debug: () => { } },
					router: { route: () => true },
					ws: websocketConnection,
					req: connectionRequest
			});

			websocketConnection.on("session:new", (data)=>{
				console.log(websocketConnection.counter, "received new session", data);
				const { msgid } = data;
				websocketConnection.ack(msgid, jambonzRedirectLoop);
			});

			websocketConnection.on("session:reconnect", (data)=>{
				console.log(websocketConnection.counter, "received reconnect session", data);
				const { msgid } = data;
				websocketConnection.ack(msgid, jambonzRedirectLoop);
			});

            websocketConnection.on("message", (message) => {
                const parsedMessage = JSON.parse(message);
                console.log(websocketConnection.counter, "received ws message", parsedMessage);
            });

			websocketConnection.on("close", (data) => console.log(websocketConnection.counter, "ws close", data));
			websocketConnection.on("error", (data) => console.log(websocketConnection.counter, "ws error", data));
			websocketConnection.on("verb:hook", (data) => {
				console.log(websocketConnection.counter, "verb:hook", data);
				const { hook, msgid } = data;
				websocketConnection.ack(msgid, jambonzRedirectLoop);

			});
			websocketConnection.on("call:status", (data) => console.log(websocketConnection.counter, "call:status", data));

			setTimeout(()=>{
				websocketConnection.close();
				websocketConnection.terminate();
			}, 5000);
    });
}

start();

WS-API: using ws protocol is not possible because of an error

Hi,

when trying to use a unsecured websocket connection, jambonz-feature-server throws an error that the protocol is not supported, is this expected?

10|jambonz-feature-server | {"level":30, "time": "2022-04-29T08:25:23.236Z","pid":6353,"hostname":"ip-10-0-19-254","callId":"c168a0f1-4238-123b-8f94-060fa1c98f14","callSid":"36eaac50-4e86-454c-9caa-083a104bc9df","accountSid":"9351f46a-678c-43f5-b8a6-d4eb58d131af","callingNumber":"+17812856404","calledNumber":"+441603361413","traceId":"6430db61b090927f85cae6a29a05f75e","url":"ws://grauen-endpoint.eu.ngrok.io/284567ef77424421d9ae479b43df8be2ab68a2fa397ee62868b233eaca2d15a4/voiceGateway","err":{"type":"SyntaxError","message":"The URL's protocol must be one of \"ws:\", \"wss:\", or \"ws+unix:\"","stack":"SyntaxError: The URL's protocol must be one of \"ws:\", \"wss:\", or \"ws+unix:\"\n at initAsClient (/home/admin/apps/jambonz-feature-server/node_modules/ws/lib/websocket.js:692:17)\n at ClientRequest.<anonymous> (/home/admin/apps/jambonz-feature-server/node_modules/ws/lib/websocket.js:850:7)\n at ClientRequest.emit (events.js:400:28)\n at ClientRequest.emit (domain.js:475:12)\n at HTTPParser.parserOnIncomingClient (_http_client.js:647:27)\n at HTTPParser.parserOnHeadersComplete (_http_common.js:127:17)\n at Socket.socketOnData (_http_client.js:515:22)\n at Socket.emit (events.js:400:28)\n at Socket.emit (domain.js:475:12)\n at addChunk (internal/streams/readable.js:293:12)"},"msg":"WsRequestor:request - failed connecting"}

The same URI works fine with a wss:// in front.

Compilcated debugging of sending commands via WS

Hi,

when sending commands such as redirect via the websocket connection instead of using webhooks as app, it's is kind of complicated to debug them. Especially when queuing commands, its hard to debug them. It would be great to have a feedback look so when we are sending commands to feature server it would provide us some feedback.

My proposal would be the following:

Each command send should contain a id. So for example if we send a list of commands via the redirect command, the payload would look like this:

{
				type: "command",
				command: "redirect",
				queueCommand: true,
				data: [
					{
						gather: {
							input: ["speech"],
							listenDuringPrompt: false,
							bargein: false,
							minBargeinWordCount: 0,
							dtmfBargein: false,
							minDigits: 1,
							interDigitTimeout: 0,
							recognizer: {
								vendor: "default",
								language: "default",
								vad: { enable: true, mode: 0 }
							},
							actionHook: "voice",
							timeout: 10
						},
                                               verbid: "53edc152-3221-475b-8d61-6da7ea3a668c"
					}
				],
                             cmdid: "53edc152-3221-475b-8d61-6da7e13a668c"
			}

Then if its a redirect with quuing commands. Once the commmand was successfully executed, we get a confirmation back on the ws with the following

{
  cmdid :  "53edc152-3221-475b-8d61-6da7ea3a668c",
  status:  "SUCCESSS" | "ERROR",
  error: "in case of error send us the error object here (ideally jambonz should have an own one with some general error codes)"
  metrics: "we could also think of adding some metrics here such as receivedOnTime, executionTime, queueTime," etc
}

When each verb is executed, FS should send us a confirmation on this as well. So we would know what to do.

{
  cmdid :  "53edc152-3221-475b-8d61-6da7ea3a668c",
  status:  "SUCCESSS" | "ABORTED" | "ERROR",
  error: "in case of error send us the error object here (ideallyj ambonz should have an own one with some general error codes)"
  metrics: "we could also think of adding some metrics here such as receivedOnTime, executionTime, queueTime," etc
}

This would really help debugging and fixing issues faster and also identify wrong send verb configurations without the need of going into the feature-server logs and debugging the error messages there.

Also it would allow us to improve the integration between jambonz and other systems and make them more fault tolerant. For example in a use case where we have jambonz connected with a bot system, if something is not working right and the bot system sends some commands to JB which is not able to execute, or something within jambonz changed so the previously working commands are not valid, we could catch this on the bot side and redirect the caller to an escalation number so the caller is not left without any help but is still helped by some humans.

What do you think about this idea?

I am happy to provide a PR with a first implementation iteration if you think this is something beneficial for the feature server

No confirmHook for the "dequeue" verb

It looks like the confirmHook is not an accepted parameter to dequeue and will actually trigger an error.


  {
        "beep": true,
        "confirmHook": "/jambonz/01/hook/QAgentConnect?acd_queue=10&acd_room=99c11e62-f967-41ad-93fa-10796120d5c2",
        "name": "10-99c11e62-f967-41ad-93fa-10796120d5c2",
        "timeout": 5,
        "verb": "dequeue"
    }


I had a look at the source and the only reference to confirmHook is in a TODO:

// TODO: if we have a confirmHook, retrieve the app and pass it on

But it is still documented, so it should be removed from the docs until implemented.

Relative path on listen ws endpoint

When Listen verb has relative url. for example /record. Jambones throws the following error.

2|jambonz-feature-server  | TypeError: Cannot read property 'originalRequest' of undefined
2|jambonz-feature-server  |     at TaskListen.normalizeUrl (/home/deploy/jambonz-feature-server/lib/tasks/task.js:64:35)
2|jambonz-feature-server  |     at new TaskListen (/home/deploy/jambonz-feature-server/lib/tasks/listen.js:19:22)
2|jambonz-feature-server  |     at makeTask (/home/deploy/jambonz-feature-server/lib/tasks/make_task.js:41:14)
2|jambonz-feature-server  |     at new TaskDial (/home/deploy/jambonz-feature-server/lib/tasks/dial.js:59:25)
2|jambonz-feature-server  |     at makeTask (/home/deploy/jambonz-feature-server/lib/tasks/make_task.js:23:14)
2|jambonz-feature-server  |     at normalizeJamones.map (/home/deploy/jambonz-feature-server/lib/utils/retrieve-app.js:28:56)
2|jambonz-feature-server  |     at Array.map (<anonymous>)
2|jambonz-feature-server  |     at retrieveApp (/home/deploy/jambonz-feature-server/lib/utils/retrieve-app.js:28:41)
2|jambonz-feature-server  |     at Request.request [as _callback] (/home/deploy/jambonz-feature-server/lib/utils/notifiers.js:35:26)
2|jambonz-feature-server  |     at Request.self.callback (/home/deploy/jambonz-feature-server/node_modules/request/request.js:185:22)

I have tried secured and unsecured ws endpoints

Allow override of dial headers on dial target(s)

Currently there is no way of defining custom sip headers on a specific target. This would be useful when we are dialing multiple targets of different types. For example a dial with 2x Targets

{
  "verb": "dial",
  "headers" : {
       "X-Header-One" : "1234"
   },
  "target": [
      {
        "type": "sip",
        "sipUri": "sip:[email protected]",
        "headers" : {
             "X-Header-One" : "2468"
        }
      },
      {
        "type": "sip",
        "sipUri": "sip:[email protected]",
        "headers" : {
             "X-Header-Two" : "abcd"
        }
      },
     {
          "type": "sip",
          "sipUri": "sip:[email protected]"
      },
     {
          "type": "sip",
          "sipUri": "sip:[email protected]",
          "headers" : {}
      }
  ]
}

I think the simplest way would be if target headers is present then ignore dial headers. The other way would be to merge the two objects with target keys taking precedence. The problem with the latter approach is that there is no way to clear custom headers for a particular target.

WIth the above example and the first option, I would expect to see the following customer headers:

sip111 =  "X-Header-One" : "2468"
sip222 =   "X-Header-Two" : "abcd"
sip333 =  "X-Header-One" : "1234"
sip444 = ""

Sip Verb with PBX IP incorrectly routes to Carrier

When Target is not Carrier IP it routes to Carrier instead of intended destination causing a loop.

{
  "@timestamp" : "2020-02-06T08:31:10.231+00:00",
  "@version" : "1",
  "message" : "response",
  "logger_name" : "uk.co.viva.vdrachtioservice.controllers.IvrController",
  "thread_name" : "http-nio-8080-exec-1",
  "level" : "INFO",
  "level_value" : 20000,
  "activemq.broker" : "localhost",
  "drachtio-response" : [ {
    "tag" : {
      "data" : {
        "port" : "5060",
        "ip" : "99.80.180.248",
        "privacy" : "false",
        "pAsserted" : "+447956697540"
      }
    }
  }, {
    "dial" : {
      "action" : "/ivr/e672997e-9401-46e8-930f-0b8d9ffab60c",
      "callerId" : "447956697540",
      "dialMusic" : "https://vibe-public.s3-eu-west-1.amazonaws.com/en-gb.wav",
      "timeLimit" : 14400,
      "timeout" : 60,
      "answerOnBridge" : true,
      "target" : [ {
        "type" : "sip",
        "sipUri" : "sip:[email protected]:5060"
      } ]
    }
  } ]
}

Actual INVITE seen was to sip:[email protected]:5060

Add engine parameter to say verb

I’ve been investigating a bit on the synth options available on Jambonz and I’ve realized that it’s not possible to use any neural voices (https://docs.aws.amazon.com/polly/latest/dg/ntts-voices-main.html) from AWS as there is no way to provide the engine parameter to the say action: https://docs.aws.amazon.com/polly/latest/dg/API_SynthesizeSpeech.html. By default this parameter is set to standard if none is provided and I’ve checked that it’s not added on the payload:

const synthPolly = (stats, language, voice, text) => {
const polly = new Polly();
const opts = {
OutputFormat: 'mp3',
Text: text,
LanguageCode: language,
TextType: text.startsWith('') ? 'ssml' : 'text',
VoiceId: voice
};
[...]

Registrations: forward IP address

It would be nice to have the IP address of the entity trying to register, so that one could implement an APIBAN-style protection.

Now we only get:

{
    "method": "REGISTER",
    "expires": 3600,
    "scheme": "digest",
    "username": "xxxxx",
    "realm": "xxxx.sip.jambonz.us",
    "nonce": "164882756524300",
    "uri": "sip:xxx.sip.jambonz.us",
    "algorithm": "MD5",
    "response": "ee14e3daf59ccb3fa80d3e133fbbb861",
    "qop": "auth",
    "cnonce": "08911326",
    "nc": "00004676"
}

Even better it would be to have the "headers" struct where you have it all, like when a call is started.


    "sip": {
        "headers": {
            "via": "SIP/2.0/UDP 52.55.111.178;rport=5060;branch=z9hG4bK3c113XmS7gcvg;received=xxxx",
            "max-forwards": "70",
            "from": "<sip:31@xxx:5060>;tag=29132U3yS6SZa",
            "to": "<sip:[email protected]>",
            "call-id": "80d9b6b1-31f3-123b-63a3-0ea24be4d211",
            "X-Forwarded-For": "23.88.37.9",
            "X-Authenticated-User": "....sip.jambonz.us"
            .....

Incorrect From field on initial action hook request

In the below scenario, the FROM field passed to application is incorrect

"from": "<sip:[email protected]:5060>;tag=eN6Fy272e7NvN" should be sent as {"from" :"07962564063"} but is incorrectly sent as {"from" :"01273202020"} which is the PAID

POST https://drachtio-service.viva-uk.net/ivr/start
    callId: "c934a2ab-f2ae-1238-f6ae-062ecac8df46"
    callSid: "b6ae2aea-b85f-4238-ab3a-255dd354fbc2"
    hook: {
      "webhook_sid": "faebf58e-f84f-4438-82ff-3dee16a6f184",
      "url": "https://drachtio-service.viva-uk.net/ivr/start",
      "method": "POST",
      "username": "drachtio",
      "password": "3298fn238hf9n823hf93h24398gj93n84h"
    }
    params: {
      "sip": {
        "headers": {
          "via": "SIP/2.0/UDP 35.179.41.104;rport=5060;branch=z9hG4bK64FjjKv3Nrgvg;received=172.31.51.15",
          "max-forwards": "70",
          "from": "<sip:[email protected]:5060>;tag=eN6Fy272e7NvN",
          "to": "<sip:[email protected]>",
          "call-id": "c934a2ab-f2ae-1238-f6ae-062ecac8df46",
          "cseq": "18536372 INVITE",
          "contact": "<sip:35.179.41.104:5060>",
          "user-agent": "Orchid 3.1.7.2",
          "allow": "BYE, CANCEL, ACK, INVITE, INFO, OPTIONS",
          "supported": "timer, replaces",
          "session-expires": "1800;refresher=uas",
          "min-se": "90",
          "content-type": "application/sdp",
          "content-length": "257",
          "X-CID": "263b84a5-282626ca-4dbde7-7fb2f41ca130-de641fac-13e2-7225",
          "X-Forwarded-For": "99.80.180.248:5060",
          "X-Originating-Carrier": "customers",
          "X-Application-Sid": "99eca0c0-194a-4c66-926d-b62f3cedd948",
          "p-asserted-identity": "<sip:[email protected];user=phone>"
        },
        "body": "v=0\r\no=- 246575 46575 IN IP4 3.10.35.78\r\ns=Cataleya\r\nc=IN IP4 3.10.35.78\r\nt=0 0\r\nm=audio 42772 RTP/AVP 8 18 101\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:18 G729/8000\r\na=rtpmap:101 telephone-event/8000\r\na=fmtp:18 annexb=no\r\na=fmtp:101 0-15\r\na=sendrecv\r\na=rtcp:42773\r\n",
        "payload": [
          {
            "type": "application/sdp",
            "content": "v=0\r\no=- 246575 46575 IN IP4 3.10.35.78\r\ns=Cataleya\r\nc=IN IP4 3.10.35.78\r\nt=0 0\r\nm=audio 42772 RTP/AVP 8 18 101\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:18 G729/8000\r\na=rtpmap:101 telephone-event/8000\r\na=fmtp:18 annexb=no\r\na=fmtp:101 0-15\r\na=sendrecv\r\na=rtcp:42773\r\n"
          }
        ],
        "method": "INVITE",
        "version": "2.0",
        "uri": "sip:[email protected]",
        "raw": "INVITE sip:[email protected] SIP/2.0\r\nVia: SIP/2.0/UDP 35.179.41.104;rport=5060;branch=z9hG4bK64FjjKv3Nrgvg;received=172.31.51.15\r\nMax-Forwards: 70\r\nFrom: <sip:[email protected]:5060>;tag=eN6Fy272e7NvN\r\nTo: <sip:[email protected]>\r\nCall-ID: c934a2ab-f2ae-1238-f6ae-062ecac8df46\r\nCSeq: 18536372 INVITE\r\nContact: <sip:35.179.41.104:5060>\r\nUser-Agent: Orchid 3.1.7.2\r\nAllow: BYE, CANCEL, ACK, INVITE, INFO, OPTIONS\r\nSupported: timer, replaces\r\nSession-Expires: 1800;refresher=uas\r\nMin-SE: 90\r\nContent-Type: application/sdp\r\nContent-Length: 257\r\nX-CID: 263b84a5-282626ca-4dbde7-7fb2f41ca130-de641fac-13e2-7225\r\nX-Forwarded-For: 99.80.180.248:5060\r\nX-Originating-Carrier: customers\r\nX-Application-Sid: 99eca0c0-194a-4c66-926d-b62f3cedd948\r\nP-Asserted-Identity: <sip:[email protected];user=phone>\r\n\r\nv=0\r\no=- 246575 46575 IN IP4 3.10.35.78\r\ns=Cataleya\r\nc=IN IP4 3.10.35.78\r\nt=0 0\r\nm=audio 42772 RTP/AVP 8 18 101\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:18 G729/8000\r\na=rtpmap:101 telephone-event/8000\r\na=fmtp:18 annexb=no\r\na=fmtp:101 0-15\r\na=sendrecv\r\na=rtcp:42773\r\n"
      },
      "direction": "inbound",
      "callSid": "b6ae2aea-b85f-4238-ab3a-255dd354fbc2",
      "accountSid": "06da1b6b-642d-43e5-953a-0c6ab8296314",
      "applicationSid": "99eca0c0-194a-4c66-926d-b62f3cedd948",
      "from": "01273202020",
      "to": "01273202020",
      "callerName": "01273202020",
      "callId": "c934a2ab-f2ae-1238-f6ae-062ecac8df46",
      "sipStatus": 100,
      "callStatus": "trying",
      "originatingSipIp": "99.80.180.248:5060",
      "originatingSipTrunkName": "customers"
    }

Mixing Teams & SIP targets causes all targets to be routed to MS Teams tenant

The following targets cause jambones to ignore sip uri and route to teams tenant.

[{"type":"sip","sipUri":"sip:[email protected]:5060"},{"type":"teams","number":"+441582363701","tenant":"2cc-demo-a.customers.viva-uk.net","vmail":false}]

SIP URI Target INVITE from FS => SBC

INVITE sip:[email protected]:5060 SIP/2.0
Via: SIP/2.0/UDP 172.31.23.236;rport;branch=z9hG4bK1vp6eepQ2DpNe
Max-Forwards: 70
From: <sip:[email protected]:5060>;tag=r6NpQXv02S5mB
To: <sip:[email protected]:5060>
Call-ID: 6b960d47-7687-1239-5993-0a90b3ff9f3c
CSeq: 25784695 INVITE
Contact: <sip:[email protected]:5060>
Content-Type: application/sdp
Content-Length: 469
X-CID: 6bb8764b-5c5d9e78-12af16d-7fb2f34ba1f8-de641fac-13e2-7225
X-MS-Teams-FQDN: customers.viva-uk.net
X-MS-Teams-Tenant-FQDN: 2cc-demo-a.customers.viva-uk.net
P-Asserted-Identity: "+442033882105" <sip:[email protected]:5060>

v=0
o=VIVA 1600645780 1600645781 IN IP4 172.31.23.236
s=VIVA
c=IN IP4 172.31.23.236
t=0 0
m=audio 31194 RTP/AVP 0 8 102 9 101 103
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:102 opus/48000/2
a=fmtp:102 useinbandfec=1; maxaveragebitrate=30000; maxplaybackrate=48000; ptime=20; minptime=10; maxptime=40
a=rtpmap:9 G722/8000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-16
a=rtpmap:103 telephone-event/48000
a=fmtp:103 0-16
a=ptime:20
a=sendrecv

misleading alert when AWS rejects tts due to unknown voice

we got an alert that "tts credentials for aws have not been provisioned" but the actual error in the logs was:

'es-ES-Lucia' at 'voiceId' failed to satisfy constraint: Member must satisfy enum value set: [Nicole, Kevin, Enrique, Tatyana, Russell, Olivia, Lotte, Geraint, Carmen, Ayanda, Mads, Penelope, Mia, Joanna, Matthew, Brian, Seoyeon, Ruben, Ricardo, Maxim, Lea, Giorgio, Carla, Aria, Naja, Maja, Astrid, Ivy, Kimberly, Chantal, Amy, Vicki, Marlene, Ewa, Conchita, Camila, Karl, Zeina, Miguel, Mathieu, Justin, Lucia, Jacek, Bianca, Takumi, Ines, Gwyneth, Cristiano, Mizuki, Celine, Zhiyu, Jan, Liv, Joey, Raveena, Filiz, Dora, Salli, Aditi, Vitoria, Emma, Lupe, Hans, Kendra, Gabrielle]

dialMusic is ignored if the A leg is not an inbound leg

dialMusic is ignored if the A leg is not an inbound leg - We receive no ringback tone when A leg answers from API call as the A Leg.

[2020-04-15 08:51:02.086 +0000] DEBUG (31802 on ip-172-31-50-11): normalizeJambones: returning document with 1 tasks
    document: [
      {
        "dial": {
          "actionHook": "/ivr/hangup",
          "callerId": "442033880222",
          "dialMusic": "https://vibe-public.s3-eu-west-1.amazonaws.com/en-gb.wav",
          "timeLimit": 14400,
          "timeout": 180,
          "answerOnBridge": true,
          "target": [
            {
              "type": "sip",
              "sipUri": "sip:[email protected]:5060"
            }
          ],
          "listen": {
            "url": "/record",
            "mixType": "stereo",
            "finishOnKey": "#",
            "maxLength": 14400,
            "metadata": {},
            "passDtmf": true,
            "playBeep": false,
            "sampleRate": 8000
          },
          "dtmfCapture": [
            "*06",
            "*07",
            "*08",
            "*09",
            "*01",
            "*02",
            "*03",
            "*04",
            "*05"
          ],
          "dtmfHook": "/ivr/dtmf"
        }
      }
    ]

Azure STT results are not processed in order of confidence level

As per the below, Azure does not return the NBest alternatives in order of confidence decreasing, which causes an issue since in the gather verb we take the first entry in the array, e.g.

{
 	"Id": "9c6a879181ee4af9801993ca562ff6d7",
 	"RecognitionStatus": "Success",
 	"Offset": 106700000,
 	"Duration": 8300000,
 	"DisplayText": "",
 	"NBest": [{
 		"Confidence": 0.0,
 		"Lexical": "",
 		"ITN": "",
 		"MaskedITN": "",
 		"Display": ""
 	}, {
 		"Confidence": 0.86060256,
 		"Lexical": "un",
 		"ITN": "un",
 		"MaskedITN": "un",
 		"Display": "un"
 	}, {
 		"Confidence": 0.7017915,
 		"Lexical": "nou",
 		"ITN": "nou",
 		"MaskedITN": "nou",
 		"Display": "nou"
 	}, {
 		"Confidence": 0.6646924,
 		"Lexical": "set",
 		"ITN": "set",
 		"MaskedITN": "set",
 		"Display": "set"
 	}, {
 		"Confidence": 0.6564128,
 		"Lexical": "cinc",
 		"ITN": "cinc",
 		"MaskedITN": "cinc",
 		"Display": "cinc"
 	}]
 }

deprecated dependency of UUID package inside docker container

When running the feature server inside of docker container by itself I receive an error with several files
related to the uuid package. The latest version of uuid does not support Deep Requires and the require
has changed. I have forked the repo and have fixed on my end by replacing the requires.
Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: Package subpath './v4' is not defined by "exports" in /usr/src/app/node_modules/uuid/package.json

I can submit a pull request for this.

Gather expects STT credentials, even when only specifying digits for input

When returning webhook response like
[{"verb“:“gather“,“actionHook“:“https://my.webhook.com“,“finishOnKey“:“#",“timeout“:30,“input“:[“digits“]}]

Jambonz is expecting there to be STT credentials configured (defaulting to Google):
"TaskGather:exec - ERROR stt using google requested but not creds supplied"

No Completed event on outbound-api call when Jambones ends call

When Jambones ends call instead of called party on outbound api call, the app never receives completed event.

Example API Call

curl -X POST "http://3.10.235.99:3000/v1/Accounts/fef61e75-cec3-496c-a7bc-8368e4d02a04/Calls" -H "accept: application/json" -H "Authorization: Bearer 9604e5f7-9a77-4bcc-b0fa-5665ace28ab3" -H "Content-Type: application/json" -d "{\"from\":\"+442033885379\",\"to\":{\"type\":\"sip\",\"sipUri\":\"sip:[email protected]:5060\"},\"timeout\":10,\"application_sid\":null,\"call_hook\":{\"url\":\"http://drachtio-service-default.viva-api.net/ivr/dml/W3sic2F5Ijp7InRleHQiOiJPb29vaCBFcnJycnIsIE1ycyBCaWxsaWkgQm9uZywgVGhpcyBpcyB0aGUgUmluZ2JhY2sgdGVtcGxhdGVZb3VyIHRheGkgaGFzIGFycml2ZWQhIiwibG9vcCI6MSwic3ludGhlc2l6ZXIiOnsidmVuZG9yIjoiZ29vZ2xlIiwidm9pY2UiOiJlbi1HQi1XYXZlbmV0LUEifX19XQ==\",\"method\":\"POST\",\"username\":\"drachtio\",\"password\":\"3298fn238hf9n823hf93h24398gj93n84h\"},\"call_status_hook\":{\"url\":\"http://drachtio-service-default.viva-api.net/ivr/event/api\",\"method\":\"POST\",\"username\":\"drachtio\",\"password\":\"3298fn238hf9n823hf93h24398gj93n84h\"}}"

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.