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.


Wednesday 24 August 2016

Skype for Business 2016 client only supports new v19 ICE

Skype for Business client was released on September 2015, and featured a number of new functionalities, as well as some discarded ones, as described here. The one I'd like to talk about is quite under-the-hood, but potentially important.

What you will not find in the article above (but you would have probably hoped for), is that the new client got support for the legacy (v6) ICE removed.
ICE (Interactive Connectivity Establishment) is, in simple terms, a set of protocols (STUN and TURN) used to facilitate media connectivity establishment for endpoints under various restricted network scenarios (e.g. when not directly routable, behind a NAT or firewall). If you'd like to know more, please refer to this excellent resource.

ICE has gone though several iterations. Until OCS 2007 "R1", only ICE v6 was used. OCS 2007 R2 introduced the new and more efficient ICE v19 version, but v6 was maintained for backward compatibility until the SfB 2015 client.

The implications of such change lie with intercommunicating with legacy systems because OCS 2007 "R1" and Exchange 2007 UM only understand ICE v6; so, expect issues if you need to interoperate with these systems. Examples:

- Skype for Business 2016 client calls to Exchange 2007 UM
- Skype for Business 2016 client calls Communicator 2007 "R1" client.

In case you are wondering, I haven't discovered anything new so I am just broadcasting. Credit goes to this blog and to Mastering Skype for Business 2015 book by Keith Hanna. Both are great reads to know more about the issue. Only, despite the potential implications, this doesn't seem to have been in the headlines (or perhaps I just missed it)?

A trace analysis from a Skype for Business 2015 server with the latest July 2016 cumulative update reveals both v6 and v19 ICE are presented in the call negotiations (some servers are also ICE clients).

Tuesday 23 August 2016

Skype for Business Busy on Busy: new performance counters

Busy on busy (or second treatment) is a neat and long-awaited feature that was eventually added in the Skype for Business July 2016 Cumulative Update.

For more info about BoB, what is it, how it works please check this blog by Randy Chapman.

Not surprisingly, a number of performance counters have been added to help monitoring and troubleshooting. Counter definitions can be found here:

C:\Program Files\Skype for Business Server 2015\Performance Counter Cumulative Update\en-US

 Here they are:

PERF_BUSYOPTIONS_BUSYOPTIONS_009_NAME=LS:BUSYOPTIONS - Busy Options
PERF_BUSYOPTIONS_BUSYOPTIONS_009_HELP=This object includes counters that apply the Busy Options component

PERF_BUSYOPTIONS_BUSYOPTIONS_TOTAL_CALLS_HANDLED_009_NAME=BUSYOPTIONS - Total number of calls handled by the Busy Options application
PERF_BUSYOPTIONS_BUSYOPTIONS_TOTAL_CALLS_HANDLED_009_HELP=Total number of calls handled by the Busy Options application.

PERF_BUSYOPTIONS_BUSYOPTIONS_TOTAL_REQUEST_FAILURES_009_NAME=BUSYOPTIONS - Total number of requests handled by the Busy Options application that failed
PERF_BUSYOPTIONS_BUSYOPTIONS_TOTAL_REQUEST_FAILURES_009_HELP=Total number of requests (INVITE or BYE) handled by the Busy Options application that failed.

PERF_BUSYOPTIONS_BUSYOPTIONS_TOTAL_CURRENT_CALLS_009_NAME=BUSYOPTIONS - Total number of on-going calls across all Busy Options-enabled users
PERF_BUSYOPTIONS_BUSYOPTIONS_TOTAL_CURRENT_CALLS_009_HELP=Total number of calls in progress for Busy Options-enabled users.

PERF_BUSYOPTIONS_BUSYOPTIONS_TOTAL_CALLS_DECLINED_WITH_BUSY_SIGNAL_009_NAME=BUSYOPTIONS - Total number calls declined with busy signal
PERF_BUSYOPTIONS_BUSYOPTIONS_TOTAL_CALLS_DECLINED_WITH_BUSY_SIGNAL_009_HELP=Total number calls declined with busy signal.

PERF_BUSYOPTIONS_BUSYOPTIONS_TOTAL_CALLS_SENT_TO_VOICEMAIL_009_NAME=BUSYOPTIONS - Total number of calls sent to Voicemail
PERF_BUSYOPTIONS_BUSYOPTIONS_TOTAL_CALLS_SENT_TO_VOICEMAIL_009_HELP=Total number of calls sent to Voicemail.

PERF_BUSYOPTIONS_BUSYOPTIONS_TOTAL_CALLS_SENT_TO_BUSY_USER_009_NAME=BUSYOPTIONS - Total number of calls sent to users while user is in a call
PERF_BUSYOPTIONS_BUSYOPTIONS_TOTAL_CALLS_SENT_TO_BUSY_USER_009_HELP=Total number of calls sent to busy users.