Friday, 26 August 2016

Skype for Business Busy Options: under the hood (sort of) part 1

Intro


Busy on Busy AKA BoB (or, more accurately as per Microsoft's wording, Busy Options) is a somewhat obvious feature in any PBX and, generally speaking, in the PSTN communications world. Initially, it was as simple as bouncing back a "busy signal" tone to the caller, but it then evolved in more pervasive features like send to voicemail, or the various mainstream "call back" functions in the mobile telephony world (e.g., if you call a busy number, you'll receive a text when it becomes available). Whatever the action is when the callee is busy, everyone expect some form of call treatment in such scenario. The purpose is clear at both ends of the wire:
  • The caller wants evidence that their called party is engaged in another conversation;
  • The callee wants evidence that someone tried to call them whilst in another conversation, and possibly be able to apply some form of second treatment to it.
Whilst Microsoft Lync and then Skype for Business have now established as a real time communications platform with rich features in the PSTN world (I am purposely avoiding the overused and misleading PBX replacement cliché), Busy Options were never part of it until the Skype for Business July 2016 Cumulative Update. Before then, it was only achievable through MSPL scripting or third party solutions.

The reason why it took so long before the feature was implemented is unknown, but one thing worth saying: it must have been not a trivial at all feature to implement, due to the complexities for the relevant algorithm to determine whether the user is actually busy or not before applying one of the two available "treatments":
  • bouncing back the busy tone (option 1: Busy on Busy);
  • send the call straight to voicemail (option 2: Voicemail on Busy).
Consider the following:
  • The multi-endpoint nature of the product: multiple sessions of multiple types may be active on different endpoints at any time;
  • Multiple states of presence: does the presence state impact the availability of a user? If so, how?
  • The many communications modalities (IM, audio, P2P, conference, PSTN)
  • The many advanced telephony features like Shared Line, Response Groups, Team Calling, Delegation: how to handle?
At the time of writing, I was unable to identify any low-level documentation around the Busy Options, so, in an attempt to try to find out more about how it works under-the-hood, I have leveraged the informational messages of a verbose trace with the specific (and new) scenario and here are my findings.


Pre-requirements

The analysis you're about to view is based on a log trace with the Centralized Logging Service using the specific Busy Options Scenario. I recall, the Busy Options are included in the July 2016 CU; the implementation involves several tasks as described in this TechNet article and consist of:
  1. Download and install the CU
  2. Enable Busy Options on the relevant Voice Policies (e.g. to enable globally: Set-CsVoicePolicy -EnableBusyOptions $true)
  3. Install the Busy Options application: CU installation will not automatically take care of this step
  4. Enable Busy Option for the users. As said, there are two options here:

    Set-CsBusyOptions -Identity sip:han.solo@giombini.lab -ActionType BusyOnBusy

    Will enable the user with the
    Busy on Busy option.
    Set-CsBusyOptions -Identity sip:luke.skywalker@giombini.lab  -ActionType VoicemailOnBusy

    Will enable the user with the
    Voicemail on Busy option.
  5. Create the specific BusyOptions scenario in the Centralized Logging Service. Like step 3, CU installation will not automatically take care of this step.


The analysis


This is the commented log of the audio session. I have stripped out a few lines and highlighted the key sections for better readability:

BoB begins processing a new SIP invite containing audio:

TL_INFO(TF_COMPONENT) [fe01\fe01]176C.4B20::08/24/2016-20:00:17.263.00026C87 (BusyOptions,BusyOnBusy.OnSipAudioInvite:busyonbusy.cs(359)) (000000000054029F)"Received a sip audio invite for call id [d6ae161097d3473f832ad2e618555843]
                    To Header:      [<sip:fe01.giombini.lab@giombini.lab;gruu;opaque=srvr:Microsoft.Rtc.Applications.TestBot:JAYVi887GVW5E593qO_7VAAA>]
                    From Header:    [<sip:administrator@giombini.lab>]
                    RequestUri:     [sip:fe01.giombini.lab@giombini.lab;gruu;opaque=srvr:Microsoft.Rtc.Applications.TestBot:JAYVi887GVW5E593qO_7VAAA]


BoB checks if Busy Options are enabled and the output is TRUE:

TL_VERBOSE(TF_STACKTRACE) [fe01\fe01]176C.4B20::08/24/2016-20:00:17.276.00026C8C (BusyOptions,PolicyReaderWrapper.ReadPolicy:policyreaderwrapper.cs(48)) (00000000014C5876)[Exit] Returning new BobVoicePolicy with policyName: [TenantId={00000000-0000-0000-0000-000000000000};0=1318020581;], vPolicy.EnableBusyOptions: [True]


BoB checks if there is at least one voice policy enabled for Busy Options and the output is TRUE:

TL_VERBOSE(TF_STACKTRACE) [fe01\fe01]176C.4B20::08/24/2016-20:00:17.277.00026C8D (BusyOptions,UserAttributeReader.ReadVoicePolicy:userattributereader.cs(155)) (000000000066037E)[Exit] Returninv voicePolicy with voicePolicy.PolicyName: [TenantId={00000000-0000-0000-0000-000000000000};0=1318020581;], voicePolicy.BobEnabled: [True]


BoB performs further checks on the voice policy assigned to the user and checks if Busy Options are enabled for the callee. In my case, the user had the global voice policy which had Busy Options enabled:

TL_VERBOSE(TF_STACKTRACE) [fe01\fe01]176C.4B20::08/24/2016-20:00:17.290.00026C9A (BusyOptions,PolicyReaderWrapper.ReadPolicy:policyreaderwrapper.cs(48)) (00000000014C5876)[Exit] Returning new BobVoicePolicy with policyName: [Global], vPolicy.EnableBusyOptions: [True]
TL_VERBOSE(TF_STACKTRACE) [fe01\fe01]176C.4B20::08/24/2016-20:00:17.290.00026C9B (BusyOptions,UserAttributeReader.ReadVoicePolicy:userattributereader.cs(155)) (000000000066037E)[Exit] Returninv voicePolicy with voicePolicy.PolicyName: [Global], voicePolicy.BobEnabled: [True]
TL_VERBOSE(TF_COMPONENT) [fe01\fe01]176C.4B20::08/24/2016-20:00:17.290.00026C9C (BusyOptions,UserAttributeReader.GetUserAttributes:userattributereader.cs(111)) (000000000066037E)User voice policy enabled: [True]


BoB checks on the user details, at this point you should have noticed the Busy Option is DISABLED for the callee (and the caller), however, BoB carries on with further checks:

TL_VERBOSE(TF_STACKTRACE) [fe01\fe01]176C.4B20::08/24/2016-20:00:17.290.00026C9F (BusyOptions,UserAttributeReader.GetUserAttributes:userattributereader.cs(126)) (000000000066037E)[Exit] Returning userDetails with userDetails.BusyOption: [Disabled], userDetails.ClientFlags [NULL]


BoB checks if it's a Team Call. The results is FALSE for all checks, confirming this is not a Team Call:

TL_VERBOSE(TF_STACKTRACE) [fe01\fe01]176C.4B20::08/24/2016-20:00:17.292.00026CA5 (BusyOptions,CallInfo.GetIsTeamCall:callinfo.cs(145)) (0000000000AA9FBC)[Enter] Querying history info header and callee clientflags to determine whether it is a team call.
TL_VERBOSE(TF_STACKTRACE) [fe01\fe01]176C.4B20::08/24/2016-20:00:17.292.00026CA8 (BusyOptions,CallInfo.GetIsTeamCall:callinfo.cs(153)) (0000000000AA9FBC)"[Exit]
historyInfoContainsTeamCallRetargetReason:  [False]
clientFlagsContainsTeamRing:                [False]
Return value:                               [False]


BoB checks if it's a Response Group call. The result is FALSE for all checks, confirming this is not RGS-related:

TL_VERBOSE(TF_STACKTRACE) [fe01\fe01]176C.4B20::08/24/2016-20:00:17.292.00026CA9 (BusyOptions,CallInfo.GetIsRgsCall:callinfo.cs(286)) (0000000000AA9FBC)[Enter] Querying History-Info and MS-Application-Aor headers to determine if this is an RGS related call.
TL_VERBOSE(TF_STACKTRACE) [fe01\fe01]176C.4B20::08/24/2016-20:00:17.292.00026CAA (BusyOptions,CallInfo.GetIsRgsCallFromHistoryInfo:callinfo.cs(309)) (0000000000AA9FBC)[Enter] Querying History-Info header to determine if this is an RGS related call.
TL_VERBOSE(TF_STACKTRACE) [fe01\fe01]176C.4B20::08/24/2016-20:00:17.292.00026CAE (BusyOptions,CallInfo.GetIsRgsCall:callinfo.cs(292)) (0000000000AA9FBC)"[Exit]
isRgsCallFromHistoryInfo:           [False]
getIsRgsCallFromMsApplicationAor:   [False]
Return value:                       [False]


Bob checks if it's a parked call, or a delegate call. The result is FALSE for all checks:

TL_VERBOSE(TF_STACKTRACE) [fe01\fe01]176C.4B20::08/24/2016-20:00:17.292.00026CAF (BusyOptions,CallInfo.GetIsCpsCall:callinfo.cs(380)) (0000000000AA9FBC)[Enter] Querying the Contact header for the [isCps] parameter to determine if this is a CPS call.
TL_VERBOSE(TF_STACKTRACE) [fe01\fe01]176C.4B20::08/24/2016-20:00:17.292.00026CB0 (BusyOptions,CallInfo.GetIsCpsCall:callinfo.cs(397)) (0000000000AA9FBC)[Exit] Contact header does not contain the [isCps] parameter, returning false.
TL_VERBOSE(TF_STACKTRACE) [fe01\fe01]176C.4B20::08/24/2016-20:00:17.292.00026CB1 (BusyOptions,CallInfo.GetIsReferredByHeaderPresent:callinfo.cs(263)) (0000000000AA9FBC)[Enter] Checking if the Referred-By header is present.
TL_VERBOSE(TF_STACKTRACE) [fe01\fe01]176C.4B20::08/24/2016-20:00:17.292.00026CB2 (BusyOptions,CallInfo.GetIsReferredByHeaderPresent:callinfo.cs(270)) (0000000000AA9FBC)[Exit] Referred-By header is not present, returning false.
TL_VERBOSE(TF_STACKTRACE) [fe01\fe01]176C.4B20::08/24/2016-20:00:17.292.00026CB3 (BusyOptions,CallInfo.GetIsDelegateCall:callinfo.cs(412)) (0000000000AA9FBC)[Enter] Check clientflags to determine whether this is a Delegate related call.
TL_VERBOSE(TF_COMPONENT) [fe01\fe01]176C.4B20::08/24/2016-20:00:17.292.00026CB4 (BusyOptions,CallInfo.GetIsDelegateCall:callinfo.cs(428)) (0000000000AA9FBC)"
clientFlagsContainsForwardAudioAppInvites:  [False]
clientFlagsContainsDelegateRing:            [False]
result:                                     [False]


BoB checks if it's a conference call:

TL_VERBOSE(TF_STACKTRACE) [fe01\fe01]176C.4B20::08/24/2016-20:00:17.292.00026CB6 (BusyOptions,CallInfo.GetIsConferenceInvite:callinfo.cs(201)) (0000000000AA9FBC)[Enter] Querying TO header to determine if this is a conference invite.
TL_VERBOSE(TF_STACKTRACE) [fe01\fe01]176C.4B20::08/24/2016-20:00:17.292.00026CB8 (BusyOptions,CallInfo.GetIsConferenceInvite:callinfo.cs(216)) (0000000000AA9FBC)[Exit] Request is not a conference invite, returning false.


BoB checks if call forwarding or simultaneous ring is enabled:

TL_VERBOSE(TF_STACKTRACE) [fe01\fe01]176C.4B20::08/24/2016-20:00:17.292.00026CB9 (BusyOptions,CallInfo.GetIsCallForwardingEnabled:callinfo.cs(482)) (0000000000AA9FBC)[Enter] Check clientflags to determine whether call forwarding is enabled.
TL_VERBOSE(TF_STACKTRACE) [fe01\fe01]176C.4B20::08/24/2016-20:00:17.292.00026CBA (BusyOptions,CallInfo.GetIsCallForwardingEnabled:callinfo.cs(487)) (0000000000AA9FBC)[Exit] Returning clientFlagsContainsForwardImmediate: [False]
TL_VERBOSE(TF_STACKTRACE) [fe01\fe01]176C.4B20::08/24/2016-20:00:17.292.00026CBB (BusyOptions,CallInfo.GetIsSimultaneousRingEnabled:callinfo.cs(500)) (0000000000AA9FBC)[Enter] Check clientflags to determine whether simultaneous ring is enabled.
TL_VERBOSE(TF_STACKTRACE) [fe01\fe01]176C.4B20::08/24/2016-20:00:17.292.00026CBC (BusyOptions,CallInfo.GetIsSimultaneousRingEnabled:callinfo.cs(505)) (0000000000AA9FBC)[Exit] Returning clientFlagsContainsSimultaneousRing: [False]


BoB checks if this is a re-invite. If you'd like to know more about re-invites, what are these and when/why they are issued then check this blog:

TL_VERBOSE(TF_STACKTRACE) [fe01\fe01]176C.4B20::08/24/2016-20:00:17.292.00026CBD (BusyOptions,CallInfo.GetIsReInvite:callinfo.cs(226)) (0000000000AA9FBC)[Enter] Querying TO header to determine if this is a re-invite.
TL_VERBOSE(TF_STACKTRACE) [fe01\fe01]176C.4B20::08/24/2016-20:00:17.292.00026CBE (BusyOptions,CallInfo.GetIsReInvite:callinfo.cs(248)) (0000000000AA9FBC)[Exit] TO header does not contain parameter [tag], returning false.


BoB checks if the call should be prioritized, based on the specific type, as we've seen, this is just a normal inbound call to a "vanilla" user who is not in any of the scenarios above:

TL_VERBOSE(TF_COMPONENT) [fe01\fe01]176C.4B20::08/24/2016-20:00:17.296.00026CC8 (BusyOptions,CallInfo.ShouldPrioritizeCall:callinfo.cs(104)) (0000000000AA9FBC)Querying history info header and callee routing preamble to determine whether should prioritize call.
TL_VERBOSE(TF_COMPONENT) [fe01\fe01]176C.4B20::08/24/2016-20:00:17.297.00026CC9 (BusyOptions,CallInfo.ShouldPrioritizeCall:callinfo.cs(121)) (0000000000AA9FBC)"
                IsTeamCall:                 [False]
                IsRgsCall:                  [False]
                IsCpsCall:                  [False]
                IsReferredByHeaderPresent:  [False]
                IsDelegateCall:             [False]
TL_VERBOSE(TF_COMPONENT) [fe01\fe01]176C.4B20::08/24/2016-20:00:17.299.00026CCA (BusyOptions,CallInfo.ShouldPrioritizeCall:callinfo.cs(130)) (0000000000AA9FBC)"
                IsConferenceInvite:         [False]
                IsCallForwardingEnabled:    [False]
                IsSimultaneousRingEnabled:  [False]
                OverridePrioritizeCallValue:[False]
TL_INFO(TF_COMPONENT) [fe01\fe01]176C.4B20::08/24/2016-20:00:17.299.00026CCB (BusyOptions,CallInfo.ShouldPrioritizeCall:callinfo.cs(138)) (0000000000AA9FBC)Return value: [False]


Next few lines in the log seem to be a summary of the findings so far:

TL_VERBOSE(TF_COMPONENT) [fe01\fe01]176C.4B20::08/24/2016-20:00:17.299.00026CCC (BusyOptions,BobManager.ProcessInviteMessage:bobmanager.cs(158)) (0000000001EC2612)"
                fromSipAddress:             [sip:administrator@giombini.lab]
                toSipAddress:               [sip:fe01.giombini.lab@giombini.lab]
                fromUserBusyOption:         [Disabled]
                toUserBusyOption:           [Disabled]
TL_VERBOSE(TF_COMPONENT) [fe01\fe01]176C.4B20::08/24/2016-20:00:17.299.00026CCD (BusyOptions,BobManager.ProcessInviteMessage:bobmanager.cs(166)) (0000000001EC2612)"
                replacesCallId:             [NULL]
                isConferenceInvite:         [False]
                isPrioritizedCall:          [False]
                isReInvite:                 [False]


Finally, like we already saw, both caller and calle's do not have busy options enabled, therefore the call is passed through without further processing:

TL_INFO(TF_STACKTRACE) [fe01\fe01]176C.4B20::08/24/2016-20:00:17.299.00026CCE (BusyOptions,BobManager.ProcessInviteMessage:bobmanager.cs(180)) (0000000001EC2612)[Exit] Busy Options not enabled for both caller [sip:administrator@giombini.lab] and callee [sip:fe01.giombini.lab@giombini.lab]. Passing through the call.
(BusyOptions,DefaultProcessor.Run:defaultprocessor.cs(32)) (0000000001F12850)Passing request through.
(BusyOptions,BusyOnBusy.ProcessInviteMessage:busyonbusy.cs(487)) (000000000054029F)[Exit]
TL_VERBOSE(TF_STACKTRACE) [fe01\fe01]176C.4B20::08/24/2016-20:00:17.301.00026CD8 (BusyOptions,BusyOnBusy.OnSipAudioInvite:busyonbusy.cs(473)) (000000000054029F)[Exit]

Takeaways

The main takeaway from this brief analysis is understanding what type of interoperability you should expect from the Busy Options in various voice applications. Busy Options will apply to calls make to you as an individual user. It will not apply in case of:


Response Groups (RGS)


  • Busy Options set on Response Group numbers will be ignored by the system; multiple concurrent calls will be allowed.
  • The current Attendant routing experience in Response Groups will remain unchanged for the Agents with Busy Options settings.
  • The calls coming from Response Groups to the users who are Response Groups Agents will not be throttled by Busy Options settings and the current RGS experience will be maintained.
  • The non-RGS related calls to the Agents will be honored by their Busy Options settings.

Team Call


  • Incoming calls to users who are set up for a Team Call will be prioritized to ignore Busy on Busy and Voicemail on Busy settings.
  • The current Team Call experience will remain unchanged with Busy Options set for the users.
  • The non-Team Call related calls to such users will be honored by their Busy Options settings.

Boss/Admin Delegation


  • Incoming calls to users who are set up for a Boss/Admin Delegation either as Boss or an Admin will be prioritized to ignore Busy on Busy and Voicemail on Busy settings.
  • The current Boss/Admin Delegation experience will remain unchanged with Busy Options set for the Admins or Boss.
  • The non-Boss/Admin Delegation related calls to Admins will be honored by their Busy Options settings.

Shared Line Appearance (SLA)



  • Busy Options settings on user accounts set up for Shared Line Appearance will be ignored.
  • Shared Line Appearance’s native Busy on Busy and Voicemail on Busy options will be honored instead.

Call Parking Service (CPS)


  • Parked calls that were not retrieved and are ringing back due to timing out will be allowed to ring though to the user who parked the call by the Busy Options.

Call Conferencing


  • Users in conference calls are considered Busy and new incoming calls will be rejected with a busy signal or forwarded to voice mail according to their Busy Options settings.
  • Users in conferences are not prevented from initiating new calls or conferences by Busy Options.
  • Users in conferences are still able to receive new conference invitations, but new peer-to-peer calls will be rejected according to their Busy Options settings.



Busy Options work irrespective of the client or device the user logs on to (unlike SLA which only works on VVX phones).  Additionally, if you are logged on to multiple devices and are engaged in a call on one, this will be taken into account and the second call will be rejected.
If you get a call while busy and it is rejected, you will get a missed call notification.  Callers will see a notification that you are busy on another call.

In the second part of the article, I will analyze what happens when users are enabled for Busy Options.

Thanks for reading.


No comments:

Post a Comment