<div dir="ltr"><div dir="ltr">On Wed, Nov 9, 2022 at 11:38 AM <<a href="mailto:asterisk@phreaknet.org">asterisk@phreaknet.org</a>> wrote:<br></div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">On 10/21/2022 7:53 AM, Joshua C. Colp wrote:<br>
> On Fri, Oct 21, 2022 at 8:29 AM <<a href="mailto:asterisk@phreaknet.org" target="_blank">asterisk@phreaknet.org</a> <br>
> <mailto:<a href="mailto:asterisk@phreaknet.org" target="_blank">asterisk@phreaknet.org</a>>> wrote:<br>
><br>
>     On 10/21/2022 5:34 AM, Joshua C. Colp wrote:<br>
>     > On Thu, Oct 20, 2022 at 8:23 PM <<a href="mailto:asterisk@phreaknet.org" target="_blank">asterisk@phreaknet.org</a><br>
>     <mailto:<a href="mailto:asterisk@phreaknet.org" target="_blank">asterisk@phreaknet.org</a>><br>
>     > <mailto:<a href="mailto:asterisk@phreaknet.org" target="_blank">asterisk@phreaknet.org</a> <mailto:<a href="mailto:asterisk@phreaknet.org" target="_blank">asterisk@phreaknet.org</a>>>><br>
>     wrote:<br>
>     ><br>
>     >     Hi, all,<br>
>     ><br>
>     >          Something I have been working on recently is adding<br>
>     support to<br>
>     >     PJSIP for device feature key synchronization (the<br>
>     as-feature-event<br>
>     >     Broadworks spec that many common IP phones, e.g. Polycom<br>
>     support) to<br>
>     >     control server-side features from endpoints. It's using the<br>
>     PJSIP<br>
>     >     pub/sub capabilities; I had to add the ability to execute a<br>
>     custom<br>
>     >     module callback when a SUBSCRIBE is refreshed, but with that<br>
>     >     addition,<br>
>     >     it works as it's supposed to.<br>
>     ><br>
>     ><br>
>     > You should further elaborate on all of the server-side features you<br>
>     > expect to implement, if it extends beyond DND.<br>
><br>
>     The other one is Call Forwarding (Always/Busy/No Answer, with<br>
>     number of<br>
>     rings)<br>
><br>
>     ><br>
>     >     I wanted to solicit some input on what an ideal way of<br>
>     triggering<br>
>     >     updates should be. Currently we have hints, which actually work<br>
>     >     reasonably all right for Do Not Disturb, which is simply a<br>
>     boolean<br>
>     >     on/off, easily represented with a hint and custom device<br>
>     state for<br>
>     >     DND.<br>
>     >     The PJSIP module emits an AMI event, the user can process it and<br>
>     >     change<br>
>     >     the device state if needed, which will trigger a NOTIFY to<br>
>     go out<br>
>     >     to the<br>
>     >     endpoint.<br>
>     ><br>
>     ><br>
>     > What user? An outside AMI application? An internal consumer in<br>
>     Asterisk?<br>
><br>
>     The administrator of the Asterisk system, who can add AMI logic to<br>
>     receive the event and then do something with it.<br>
>     The reason this is needed is the phone isn't turning DND on directly,<br>
>     for example. It's merely a request. The server can decide to not<br>
>     allow<br>
>     it, for example if that phone isn't allowed to toggle DND. The server<br>
>     will process it, and send it the updated status. This usually<br>
>     reflects<br>
>     what the phone wanted, but not necessarily.<br>
>     (I've elaborated on this more below)<br>
><br>
><br>
> Okay, that's not the administrator of an Asterisk system. That's a <br>
> developer using Asterisk who may be the administrator. Those are two <br>
> separate things. As soon as you bring AMI into the mix then it's <br>
> making a solution using Asterisk. That's not a wrong thing, but it's <br>
> important to be clear in the audience. Many average users of Asterisk <br>
> doesn't know or care about AMI, 'nor do they code for it. They may use <br>
> additional solutions that utilize AMI but they themselves haven't the <br>
> foggiest of the details.<br>
><br>
><br>
>     ><br>
>     >     This sort of came up about 12 years ago[1]. The actual SIP stuff<br>
>     >     is not<br>
>     >     complicated; it's the user interface to it that requires more<br>
>     >     thought.<br>
>     >     For call forwarding, there are more moving pieces and abusing<br>
>     >     hints/custom device state for that is super clunky. You can't<br>
>     >     communicate the call forwarding target, # of rings, etc. in<br>
>     a device<br>
>     >     state, so additional hints are then needed for that. It<br>
>     works but<br>
>     >     it's<br>
>     >     super clunky and I don't think this is a great pipeline.<br>
>     ><br>
>     ><br>
>     > Okay, so this covers call forwarding as well.<br>
>     Yes.<br>
>     ><br>
>     ><br>
>     >     I'm wondering if people have thoughts on what an ideal mechanism<br>
>     >     would<br>
>     >     be for users, once they process a request to enable/disable<br>
>     a feature<br>
>     >     from the phone, to communicate that to the PJSIP module. The<br>
>     problem<br>
>     >     with abusing hints, especially for call forwarding, is it's<br>
>     not a<br>
>     >     good<br>
>     >     way to communicate details into the module. One option<br>
>     perhaps is to<br>
>     >     have dialplan extensions, setup in a manner similar to use with<br>
>     >     EVAL_EXTEN, where it returns the current value needed, as any<br>
>     >     relevant<br>
>     >     function, DB, ODBC, CURL, custom function, etc. could be used to<br>
>     >     retrieve the current feature value. The clunky part is more<br>
>     >     signaling to<br>
>     >     the PJSIP module that it needs to send the phone the updated<br>
>     >     status (by<br>
>     >     checking those extensions, for example). The device state<br>
>     callback<br>
>     >     happens to be convenient for this kind of signaling but not<br>
>     really<br>
>     >     appropriate here. It would be better to push the info into<br>
>     the module<br>
>     >     directly rather than the signaling it and making it retrieve the<br>
>     >     updated<br>
>     >     data in some arbitrary way.<br>
>     ><br>
>     >     So with this in mind, I'm currently leaning in the direction<br>
>     of a<br>
>     >     dialplan function/AMI action that could be used to set the<br>
>     >     appropriate<br>
>     >     info for a subscription, which would trigger the NOTIFY, and<br>
>     then<br>
>     >     nothing would actually need to be added to the dialplan at all<br>
>     >     (inasmuch<br>
>     >     as hints and things of that nature). One d I think starting<br>
>     purely<br>
>     >     from that perspective<br>
>     ><br>
>     >     isadvantage of this is that<br>
>     >     for every single update, unlike callbacks, we have to<br>
>     traverse the<br>
>     >     entire list of subscriptions (though maybe that's not a big<br>
>     deal).<br>
>     >     The<br>
>     >     bigger problem is this is push only and the PJSIP module still<br>
>     >     needs to<br>
>     >     be able to "pull" feature statuses on demand, which is where the<br>
>     >     hint/lookup model is useful. A potential middle ground<br>
>     solution is<br>
>     >     use<br>
>     >     the dialplan function/AMI action to push only, but cache all of<br>
>     >     this in<br>
>     >     AstDB (as subscriptions themselves are), so that we can<br>
>     retrieve the<br>
>     >     latest/most current value at any point if needed. Then we don't<br>
>     >     need to<br>
>     >     be concerned at all with how the user is managing state as<br>
>     that is<br>
>     >     fully<br>
>     >     decoupled, although obviously this would lead to a little<br>
>     >     duplication/redundancy. Any thoughts?<br>
>     ><br>
>     ><br>
>     > You've thrown a lot of lower level implementation details at us<br>
>     and to<br>
>     > be quite honest it's overwhelming. There's no full user facing<br>
>     > examples of how it would all work, beyond the bits and pieces in<br>
>     your<br>
>     > text that we'd then have to deduce and after reading a few times it<br>
>     > doesn't feel very friendly. To start off with: Is this a<br>
>     developer API<br>
>     > and interface, or is this also meant for the common everyday<br>
>     user? I<br>
>     > would hope it's for the common everyday user, in which case it<br>
>     should<br>
>     > be approached from that perspective first with implementation<br>
>     details<br>
>     > following.<br>
><br>
>     Yes, it's for the common every day end user. A callback mechanism if<br>
>     used would be more of a development one but that would be more a<br>
>     means<br>
>     to an end.<br>
><br>
>     Here's an example of what I have in my dialplan right now, in the<br>
>     subscribe_context for the endpoint:<br>
>     exten => dnd_Polycom5,hint,Custom:${EXTEN}<br>
>     exten => callfwd_Polycom5,hint,Custom:${EXTEN}<br>
>     exten => callfwdalways_Polycom5,1,${FOOBAR(callforward,2135)}<br>
>     exten => callfwdbusy_Polycom5,1,${FOOBAR(callforwardbusy,2135)}<br>
>     exten =><br>
>     callfwdnoanswer_Polycom5,1,${FOOBAR(callforwardnoanswer,2135)}<br>
><br>
>     The user gets the AMI event, processes it with whatever processing is<br>
>     needed (e.g. checking that the DND feature is available for that<br>
>     line,<br>
>     setting it in AstDB, ODBC, or whatever is the source of truth for<br>
>     feature statuses), and then updates the relevant hints above.<br>
><br>
>     The module is currently hardcoded to use these extensions in the<br>
>     subscribe context: the prefix + the endpoint name. Obviously<br>
>     that's also<br>
>     inflexible.<br>
>     Right now, the first 2 extensions the user will set to signal the<br>
>     module<br>
>     to send an updated NOTIFY. The first hint by virtue of being binary<br>
>     contains the DND status itself, and the 3 bottom extensions are<br>
>     needed<br>
>     to retrieve the call forwarding numbers from the source of truth for<br>
>     these features. (Here, FOOBAR is a custom - but any arbitrary -<br>
>     dialplan<br>
>     function I have that retrieves the status).<br>
><br>
>     I bring this up only to show the current implementation and how<br>
>     hacky it<br>
>     is; I don't like this at all or think it's appropriate (except for<br>
>     DND,<br>
>     possibly). It was more a proof of concept of testing the<br>
>     underlying SIP<br>
>     technology.<br>
><br>
>     A better implementation might look like:<br>
><br>
>     User gets the AMI event and processes it as usual, and then simply<br>
>     does<br>
>     Set(PJSIP_DEVICE_FEATURE_STATE(PJSIP/Polycom1,donotdisturb)=enabled)<br>
>     or<br>
>     Set(PJSIP_DEVICE_FEATURE_STATE(PJSIP/Polycom1,callforwardingnoanswer)=8675309,4)<br>
><br>
>     (forward on no answer to 8675309 after 4 rings).<br>
><br>
>     Internally, PJSIP_DEVICE_FEATURE_STATE could also persist input to<br>
>     AstDB<br>
>     so it's available to the module.<br>
><br>
>     > As an everyday user I'd expect not to have to deal with AMI or<br>
>     complex<br>
>     > dialplan. I'd expect to be able to set and get the information from<br>
>     > the dialplan using dialplan functions (or a single function) so I<br>
>     > could use that in the dialplan, and have it "just work" with my<br>
>     phones<br>
>     > that support the feature. I'd expect it to persist across Asterisk<br>
>     > restarts. For example ${EXTENSION_DND(alice)} for retrieving DND<br>
>     > status of Alice, and if Asterisk restarted then that should stay<br>
>     the same.<br>
><br>
>     That's a good point. The problem is that means that Asterisk<br>
>     internally<br>
>     is the source of truth of DND, and that may not necessarily be what<br>
>     people want. For instance, that wouldn't meet my own requirements.<br>
>     The<br>
>     way that Broadworks works is the phone is merely requesting a certain<br>
>     disposition, but the server isn't under any obligation to carry it<br>
>     out.<br>
>     So I think there needs to be some mechanism for the user to be<br>
>     involved<br>
>     in that pipeline, to be able to deny something that a phone wants.<br>
>     Maybe<br>
>     the user doesn't have DND, maybe certain phones aren't allowed to<br>
>     toggle, whatever. Lots of people store their feature states in MySQL<br>
>     databases and use them for Asterisk clusters. Some systems might have<br>
>     specific requirements for that. So users should have flexibility to<br>
>     reject it. On some systems, maybe the same DND status is used for<br>
>     several lines and Asterisk internally would not have any idea<br>
>     about this.<br>
>     There are lots of different scenarios that are beyond what I think<br>
>     Asterisk itself should handle, hence the "two-part" process described<br>
>     above: the user (system admin) can do whatever needs to be done, and<br>
>     then just tell PJSIP what the new state is. PJSIP doesn't need to<br>
>     know<br>
>     or care about where feature states are actually stored or what the<br>
>     logic<br>
>     is or how they are mapped to endpoints.<br>
><br>
>     I do see your point though and I think it would be nice to have a<br>
>     "simple, default mode" where Asterisk will internally just "approve<br>
>     everything" that the phone wants, and users can use that if that<br>
>     suits<br>
>     their needs, but fundamentally I think users should be able to be<br>
>     involved in the decision pipeline if they want/need to. I'm not<br>
>     yet sure<br>
>     what that would look like: maybe a pjsip.conf option to emit AMI<br>
>     events<br>
>     rather than auto-handling them? And then the<br>
>     PJSIP_DEVICE_FEATURE_STATE<br>
>     function would have to be used to tell PJSIP what to do, and Asterisk<br>
>     itself would not be the source of truth for feature statuses in this<br>
>     case (but it would cache them as described above) (though in this<br>
>     case<br>
>     reading the PJSIP_DEVICE_FEATURE_STATE could still return the cached<br>
>     disposition)<br>
><br>
><br>
> Okay, YOUR usage is based on an API interface for developers to allow <br>
> external source of truth and logic. That's what it is. My response did <br>
> not approach it from that perspective.<br>
><br>
> I don't have thoughts on that aspect currently. It requires more time.<br>
<br>
The new architecture proposed (not using hints) has been working pretty <br>
well for a few weeks. I'm using it in the more "developer" mode but the <br>
other mode exists as well. The last hurdle is being able to send a <br>
multipart XML response when necessary, since if more than one feature <br>
needs to be sent to the device, the Broadworks spec outlines a multipart <br>
response devices will accept.<br>
<br>
Right now I'm using a body_generator module in order to generate the <br>
actual content for the NOTIFY, similar to how res_pjsip_exten_state and <br>
res_pjsip_mwi do things. However the body generator only gets a pointer <br>
to an ast_str, so there's no way for it to do anything PJSIP related <br>
like multipart. I was thinking that one elegant option would be to have <br>
a separate body generator for each of the features, and then <br>
res_pjsip_pubsub would handle creating the multipart body.<br>
<br>
There is some stuff in res_pjsip_pubsub currently to handle multipart <br>
subscriptions, for subscriptions that have "children". The individual <br>
features are not "child subscriptions" in the right sense, but if they <br>
were, then it might work within the constraints of the pubsub interface. <br>
However, I know you suggested it would be preferable to handle any <br>
multipart stuff in the module itself using the PJSIP multipart APIs, as <br>
opposed to changing anything in res_pjsip_pubsub.<br>
<br>
Looking at the existing support for multipart in res_pjsip_pubsub, it <br>
seems this is limited to subscriptions as discussed in RFC 4662, which <br>
require a "Supported: eventlist" header in them, even if you define a <br>
resource list in pjsip.conf. The Broadworks device feature sync <br>
subscriptions do not include such a header in the SUBSCRIBE. So, the <br>
subscription in question seems to be a single, childless subscription, <br>
that nonetheless needs to send a multipart response, potentially.<br>
<br>
So, a couple questions, assuming my understanding of the above is correct:<br>
<br>
  * Since it doesn't appear that res_pjsip_pubsub currently supports<br>
    multipart in the way that's needed here, do you think there's any<br>
    approach we could take that retains being able to use body generator<br>
    modules? I don't see how we can, unless res_pjsip_pubsub itself<br>
    supported it. The support it has is close, but not really what it<br>
    would need to be. Would it be reasonable to extend such<br>
    functionality to support this kind of subscription? i.e. not require<br>
    "Supported: eventlist" in order to be considered a resource list?<br>
  * Alternately, if we didn't want to modify res_pjsip_pubsub to support<br>
    this unconventional usage, perhaps the module itself could directly<br>
    add some "dummy" child subscriptions to itself, one for each<br>
    feature, so that one body generator could then be used for each of<br>
    them. ast_sip_subscription is an opaque structure though, so this<br>
    would require breaking some abstraction and using the internals of<br>
    ast_sip_subscription in the module, in order to be able to add<br>
    children to it.<br>
  * Assuming we don't want to do anything with pubsub children, would it<br>
    be fine/preferred to ditch the body generator altogether and do<br>
    everything in a single module? It just feels a bit clunkier this<br>
    way, since it'll likely duplicate a lot of what res_pjsip_pubsub is<br>
    doing internally for building NOTIFYs, in fact this would likely<br>
    require bypassing much of what res_pjsip_pubsub does in order to<br>
    generate the entire response itself.<br>
  * Is it even worth trying to support multipart responses for non<br>
    resource list subscriptions? Would sending up to 4 NOTIFYs instead<br>
    of a single multipart one be an "acceptable kludge", given the<br>
    requirements of res_pjsip_pubsub?<br>
<br>
All of the approaches listed seem a bit hacky to me, though in different <br>
ways. Wondering if you think a particular approach is more promising <br>
than the others...<br></blockquote><div><br></div><div>I don't have any further input, and it is unlikely I will have any for quite some time. I'm also not that familiar with the res_pjsip_pubsub RLS implementation which is what you are referring to and haven't looked at the underlying specification for your Broadsoft stuff. Someone else may have input.</div></div><div><br></div>-- <br><div dir="ltr" class="gmail_signature"><div dir="ltr"><div><div dir="ltr"><div><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div style="font-family:tahoma,sans-serif"><font color="#073763">Joshua C. Colp</font></div><div style="font-family:tahoma,sans-serif"><font color="#073763">Asterisk Project Lead</font></div><div style="font-family:tahoma,sans-serif"><font color="#073763">Sangoma Technologies</font></div><div style="font-family:tahoma,sans-serif"><font color="#073763">Check us out at <a href="http://www.sangoma.com" target="_blank">www.sangoma.com</a> and <a href="http://www.asterisk.org" target="_blank">www.asterisk.org</a></font><br></div></div></div></div></div></div></div></div></div></div></div>