Asterisk 16 - ARI - Showing Caller number on multiple outgoing channels

Hi All,

I’m developing a telephony app which is using ARI Stasis The app basically does the following:

  1. Accept incoming channel
  2. Create a bridge and add the incoming channel into the bridge
  3. Create multiple outgoing channels and add those outgoing channels to the bridge
  4. Dial out all outgoing channels.

The problem is when I test on real phones, only the first outgoing channels can show the caller number from the incoming channel, the others see private number. Why is that? Am I missing anything?

What does this give you that the built-in Page application doesn’t give?

Why are you early bridging?

Did you specify an originator when creating the channel?

I don’t see how we can really answer this well if we cannot see your actual ARI application code.

What is the actual SIP signaling involved? (If using SIP). As well answers to David’s questions would also be good.

Hi @david551,

  1. What does this give you that the built-in Page application doesn’t give? I guess you are asking for the Asterisk logs, if so see the log from Asterisk CLI below
  2. Why are you early bridging? We have a business logic that for each extension defined in Asterisk’s dial plan, a dtmf input is required and if the input is correct we will dial out one or many destination numbers and I think this is one of the ways to do that.
  3. Did you specify an originator when creating the channel? I did. See the code below.

Log from Asterisk CLI

Asterisk 16.1.1, Copyright (C) 1999 - 2018, Digium, Inc. and others.
Created by Mark Spencer <markster@digium.com>
Asterisk comes with ABSOLUTELY NO WARRANTY; type 'core show warranty' for details.
This is free software, with components licensed under the GNU General Public
License version 2 and other licenses; you are welcome to redistribute it under
certain conditions. Type 'core show license' for details.
=========================================================================
Connected to Asterisk 16.1.1 currently running on ip-10-224-73-184 (pid = 10499)
 Creating Stasis app 'app'
  == WebSocket connection from '10.1.56.209:59131' for protocol '' accepted using version '13'
  == Using SIP RTP CoS mark 5
       > 0x7fd64400a970 -- Strict RTP learning after remote address set to: 125.213.160.13:20328
    -- Executing [61370182002@ari-test:1] Verbose("SIP/125.213.160.7-00000000", "1, Inbound call: From 61434466477 to 61370182002|<sip:61370182002@13.55.19.101;user=phone>") in new stack
  Inbound call: From 61434466477 to 61370182002|<sip:61370182002@13.55.19.101;user=phone>
    -- Executing [61370182002@ari-test:2] Set("SIP/125.213.160.7-00000000", "CALLERID(name)=carsales") in new stack
    -- Executing [61370182002@ari-test:3] Stasis("SIP/125.213.160.7-00000000", "app,61434466477,61370182002,<sip:61370182002@13.55.19.101;user=phone>") in new stack
    -- Channel SIP/125.213.160.7-00000000 joined 'simple_bridge' stasis-bridge <eb9a98ed-4573-4112-be91-8ce716197501>
       > 0x7fd64400a970 -- Strict RTP switching to RTP target address 125.213.160.13:20328 as source
    -- <SIP/125.213.160.7-00000000> Playing 'agent-pass.gsm' (language 'en')
[Mar  5 14:30:27] WARNING[10694][C-00000001]: app.c:938 dtmf_stream: Illegal DTMF character 't' in string. (0-9*#aAbBcCdD allowed)
[Mar  5 14:30:27] WARNING[10694][C-00000001]: app.c:938 dtmf_stream: Illegal DTMF character 'm' in string. (0-9*#aAbBcCdD allowed)
       > 0x7fd64400a970 -- Strict RTP learning complete - Locking on source address 125.213.160.13:20328
    -- <SIP/125.213.160.7-00000000> Playing 'priv-introsaved.gsm' (language 'en')
  == Using SIP RTP CoS mark 5
    -- Channel SIP/symbio-00000001 joined 'simple_bridge' stasis-bridge <eb9a98ed-4573-4112-be91-8ce716197501>
  == Using SIP RTP CoS mark 5
    -- Channel SIP/symbio-00000002 joined 'simple_bridge' stasis-bridge <eb9a98ed-4573-4112-be91-8ce716197501>
       > Bridge eb9a98ed-4573-4112-be91-8ce716197501: switching from simple_bridge technology to softmix
       > 0x7fd650008780 -- Strict RTP learning after remote address set to: 125.213.162.241:35550
       > 0x7fd650008780 -- Strict RTP switching to RTP target address 125.213.162.241:35550 as source
       > 0x7fd644016260 -- Strict RTP learning after remote address set to: 125.213.162.240:35238
       > 0x7fd644016260 -- Strict RTP switching to RTP target address 125.213.162.240:35238 as source
       > 0x7fd650008780 -- Strict RTP learning complete - Locking on source address 125.213.162.241:35550
       > 0x7fd644016260 -- Strict RTP learning complete - Locking on source address 125.213.162.240:35238
    -- Channel SIP/symbio-00000001 left 'softmix' stasis-bridge <eb9a98ed-4573-4112-be91-8ce716197501>
       > Bridge eb9a98ed-4573-4112-be91-8ce716197501: switching from softmix technology to simple_bridge
    -- Channel SIP/symbio-00000001 joined 'simple_bridge' stasis-bridge <eb9a98ed-4573-4112-be91-8ce716197501>
       > Bridge eb9a98ed-4573-4112-be91-8ce716197501: switching from simple_bridge technology to softmix
    -- Channel SIP/symbio-00000002 left 'softmix' stasis-bridge <eb9a98ed-4573-4112-be91-8ce716197501>
       > Bridge eb9a98ed-4573-4112-be91-8ce716197501: switching from softmix technology to simple_bridge
    -- Channel Recorder/ARI-00000000;2 joined 'simple_bridge' stasis-bridge <eb9a98ed-4573-4112-be91-8ce716197501>
       > Bridge eb9a98ed-4573-4112-be91-8ce716197501: switching from simple_bridge technology to softmix
    -- x=0, open writing:  /var/spool/asterisk/recording/48356e6b-aea0-4ee8-9bf1-926bedbe276c format: WAV, 0x7fd664004540
    -- Channel SIP/125.213.160.7-00000000 left 'softmix' stasis-bridge <eb9a98ed-4573-4112-be91-8ce716197501>
       > Bridge eb9a98ed-4573-4112-be91-8ce716197501: switching from softmix technology to simple_bridge
    -- Message ended by control
    -- Channel Recorder/ARI-00000000;2 left 'simple_bridge' stasis-bridge <eb9a98ed-4573-4112-be91-8ce716197501>
    -- Channel SIP/symbio-00000001 left 'simple_bridge' stasis-bridge <eb9a98ed-4573-4112-be91-8ce716197501>
ip-10-224-73-184*CLI>

Code

private void OnChannelDtmfReceivedEvent(IAriClient sender, ChannelDtmfReceivedEvent e)
{
	_callContextService.HandleDtmf(sender, e);
}

public void HandleDtmf(IAriClient ariClient, ChannelDtmfReceivedEvent e)
{
	var ariCallManager = _ariCallFactory.Instance(ariClient);

	var dtmfResult = _dtmfService.HandleDtmf(ariClient, e.Channel.Id, e.Digit);

	if (dtmfResult == DtmfEnum.Invalid)
	{
		ariClient.Channels.Play(e.Channel.Id, "sound:auth-incorrect");
	}
	else if (dtmfResult == DtmfEnum.Valid)
	{
		ariClient.Channels.Play(e.Channel.Id, "sound:priv-introsaved");
		var contextCall = ariCallManager.GetContextCallByChannelId(e.Channel.Id);
		_dialService.Dial(ariClient, _numberRouteService.GetDestinationNumbers(e.Channel.Dialplan.Exten), contextCall);
	}
}

public void Dial(IAriClient ariClient, List<string> numbers, CallContext callContext)
{
	var callerChan = callContext.Bridge.Channels.FirstOrDefault(x => x.Role == "Caller");
	if (callerChan == null)
	{
		throw new ArgumentException("Invalid context call: caller/originator channel not found.");
	}

	foreach (var number in numbers)
	{
		if (!string.IsNullOrEmpty(number))
		{
			var chan = ariClient.Channels.Create($"SIP/symbio/{number}", _asteriskSettings.StasisAppName(),
				null, null, callerChan.CallerId, callerChan.Id);

			ariClient.Channels.SetChannelVar(chan.Id, "BridgeId", callContext.Bridge.Id);
			ariClient.Channels.SetChannelVar(chan.Id, "Role", "Callee");
			ariClient.Channels.SetChannelVar(chan.Id, "CallerId", callerChan.CallerId);
			ariClient.Channels.SetChannelVar(chan.Id, "CallerName", callerChan.CallerName);
			ariClient.Channels.SetChannelVar(chan.Id, "CalleeId", number);

			ariClient.Bridges.AddChannel(callContext.Bridge.Id, chan.Id);

			ariClient.Channels.Dial(chan.Id, callerChan.CallerName, 30);

			callContext.Bridge.Channels.Add(new ChannelContext()
			{
				Id = chan.Id,
				Role = "Callee",
				Variables = new Dictionary<string, string>()
				{
					{"BridgeId", callContext.Bridge.Id},
					{"Role", "Callee"},
					{"CalleeId", number},
					{"CallerId", callerChan.CallerId},
					{"CallerName", callerChan.CallerName}
				},
				State = chan.State
			});
		}
	}
}

Hi @jcolp,

Sorry I’m a Asterisk newbie not sure how to get actual involved SIP signaling? Can we retrieve it from Asterisk CLI?

  1. I meant why do you have to build a custom application, rather than us the built-in, and presumably tested, Page application.

  2. I was asking why you needed to set up the bridge before dialling, rather than adding answered calls to it as they are answered.

Information on enabling protocol debugging can be found at https://wiki.asterisk.org/wiki/display/AST/Collecting+Debug+Information#CollectingDebugInformation-Enablechanneltechorfeaturespecificdebug

Hi @david551,

  1. I was not aware of that built-in Page application in the first place. However it appears that I can’t use it via ARI, correct me if I’m wrong.
  2. Will try what you suggested and see how it goes and let you know.

Thanks.

The question was why use ARI at all.

Hi @david551,

I finally got it working by using ARI’s Originate method instead.

The question was why use ARI at all. Our legacy app is using AGI and we want to experiment ARI to rebuild the app and so far our devs love it because 1) they are REST 2) we don’t have to write heavy lifting dial plans that means we can move our business logic on top of the application.
Did you mean ARI isn’t suitable for creating an app like this?

I meant that, on a quick read, it looked like you might be re-implementing Page, and maybe generating 200 lines of code when one would have done.

An awful lot of software development effort seems to go into doing things almost, but not quite, the way the chosen tool was designed to do it, when the way the tool was intended to be used would actually meet the overall objective.

1 Like

@thanhp : how are you handling the channelstate event for this multiple channels. each number can answer at different time. i need to make an outbound call to multiple number and play a message when the channels answer.