dgorski / app_tdd

TDD Module for Asterisk
3 stars 2 forks source link

Dialplan argument for custom name #10

Closed InterLinked1 closed 2 years ago

InterLinked1 commented 2 years ago

I think the TddStart application should accept an optional argument for a "TDDUserKey" and "TDDUserValue" or some user field like that, for as many key=value args as provided in that option.

The idea is it gets relayed to AMI as part of the TddStart AMI event. Since you're probably running different code for each TTY-related service that you provide, you need some way to differentiate which code should be executing. The field provides a mechanism to do that.

For example, I have an Asterisk relay that allows TDD users to join an IRC channel - in this case, the IRC channel is the custom argument so we know which channel it should be relaying between.

Obviously all this can be done with setting a variable in the dialplan and then issuing Getvar in the dialplan, but given that this kind of thing would be necessary to really use this extensively, would be nice and elegant to make it part of the TddStart event.

Also, I think the standard channel info, esp. CALLERID(num) should be provided as part of the TddStart event. Right now separate Getvar calls are needed to get that.

dgorski commented 2 years ago

You can use the "channelvars=" statement to your manager.conf file to cause variables to be exposed in all manager events for a given user. In my case I set a call identifier variable (UCID) on the channel in the dialplan before calling TDD. The manager config is set to expose this variable and I receive it any time I get a manager event (including the TDD events). I feel that this built-in asterisk capability satisfies the requirement without requiring special behaviour (and more code) in the TDD app.

[tdduser] secret=53cr3t read = system,call,log,verbose,agent,user,config,dtmf,cdr,dialplan write = system,call,agent,user,config,command,originate,message channelvars = UCID

There is also the correlation option (u), which allows you to pass an opaque string that will be delivered in the 'correlation' field of all TDD events. This was initially intended to provide a unique link between a call and the TDD events by extracting something from the sip call header and passing it in the u() option when calling TddRx. I later started using the manager channelvars feature described above instead, but this capability remains.

exten => _X.,n,TddRx(b(3)u(${UCID}))

InterLinked1 commented 2 years ago

channelvars isn't targeted so it would apply to all AMI events, which is probably overkill.

Nonetheless, that shouldn't be necessary to get the standard channel info like ${CALLERID(num)} and such.

dgorski commented 2 years ago

I actually wanted the value to be on all channel events so it wasn't a problem, but I can see where you may not want this side-effect.

I can't think of any other diaplan app that lets you send abritrary fields on it's manager events. I think that's a bit much to ask.

However, I think you sould try the 'correlation' feature (the 'u' option) - I think it will give you the functionality you need: it lets you pass arbitrary, channel-specific data on the TDD AMI events.

exten => _X.,n,TddRx(u(irc_channel_zero))

If you pass a value via u() when calling TddRx, that value will show up in a field called 'Correlation' on every TddRxMsg event for that channel.

/* if a correlation value wasn't provided (or was null), don't include the field */

    if(ast_strlen_zero(ti->correlation)) {
        ast_manager_event(chan, EVENT_FLAG_CALL, "TddRxMsg",
            "Channel: %s\r\nMessage: %s\r\n", ti->name, buf);

        stasis_message_blob = ast_json_pack("{s: s}", "message", msg);
    } else {

/* otherwise include the value in the Correlation field */

        ast_manager_event(chan, EVENT_FLAG_CALL, "TddRxMsg",
            "Channel: %s\r\nMessage: %s\r\nCorrelation: %s\r\n",
            ti->name, buf, ti->correlation);

        stasis_message_blob = ast_json_pack("{s: s, s: s}", "message", msg, "correlation", ti->correlation);
    }

I just noticed that the help doco says this option is called 'c' but it's really 'u' - I've just fixed that. It used to be called 'uniqueid' which is why it is processed as 'u' rather than 'c'.

asterisk*CLI> core show application tddrx

  -= Info about application 'TddRx' =-

[Synopsis]
Enable TDD transmit/receive processing on a channel.

[Description]
The TddRx application is used to begin listening for TDD tones from the
channel.  If TDD tones are detected, the received message will be posted via
manager/stasis events for this channel.

This application will exit immediately after setting up an audiohook.

[Syntax]
TddRx([options])

[Arguments]
options
    b(bufsiz):
        bufsiz - Specify a custom input buffer size. This controls received
        character delivery via manager/stasis events (a smaller value means
        more messages with less rx chars in each). Valid values are 1-256.

    u(correlation):
        correlation - Provide a correlation string for this channel, will be
        sent with TddRxMsg events.
dgorski commented 2 years ago

I realized in your initial message that you wanted this in TddStart, not neccessarily TddRxMsg - the value is also passed on the TddStart event:

    if(ast_strlen_zero(ti->correlation)) {
        ast_manager_event(chan, EVENT_FLAG_CALL, "TddStart", "Channel: %s\r\n", ti->name);

        stasis_message_blob = ast_json_pack("{s: s}", "tddstatus", "active");
    } else {
        ast_manager_event(chan, EVENT_FLAG_CALL, "TddStart", "Channel: %s\r\nCorrelation: %s\r\n", ti->name, ti->correlation);

        stasis_message_blob = ast_json_pack("{s: s, s: s}", "tddstatus", "active", "correlation", ti->correlation);
    }
InterLinked1 commented 2 years ago

I don't see the CallerID or related fields in the TddStart message...

Yeah, I guess we can forget about the specific field, just seemed more relevant for this. But I guess it's only an extra AMI Getvar I'll have to do once per call.

That said, I do still think CallerID should be included in the TddStart event. That's basic, essential info to have.

dgorski commented 2 years ago

Callerid is provided in the NewExten (and other) existing call and dialplan events. These are channel-state events. This app is not intended to replace any channel lifecycle events - you still need to be watching for those events in your app. On the upside, if you enable the dialplan events in your manager configuration, you'll see the SetVar events automatically (and will never have to query for variables via GetVar). The dialplan events all provide NewExten which shows up whenever a call moves from one exten to another - but more specifically when a new call arrives at the first extension, and it includes all kinds of call details.

So you can gather caller details from the NewExten event, and match up the the TddStart and TddRxMsg events using the the Channel: header:

Event: Newexten
Privilege: dialplan,all
Channel: PJSIP/dcmmtsbc11-00000000
ChannelState: 4
ChannelStateDesc: Ring
CallerIDNum: 5555805407
CallerIDName: WIRELESS CALLER
ConnectedLineNum: <unknown>
ConnectedLineName: <unknown>
Language: en
AccountCode: 
Context: from-external
Exten: 5553095740
Priority: 4
Uniqueid: 1657233103.0
Linkedid: 1657233103.0
Extension: 5553095740
Application: TddRx
AppData: 

Event: TddStart
Privilege: call,all
Channel: PJSIP/dcmmtsbc11-00000000
InterLinked1 commented 2 years ago

I disable NewExten events on my system completely at the stasis level. Too noisy and generally useless that it's not worth the performance impact.

The majority of AMI events do also contain the CallerIDNum, CallerIDName, ConnectedLine, etc. that type of thing on events. Look at all the Queue related events, for instance. NewExten isn't related and shouldn't be necessary to get them.

Logically, there's no way to know to do anything with Newexten events anyways in this context. You wouldn't care about them until you needed it, and there's no way to count on it then. The only way to get this is through another GetVar.