Customizing CPA and Tone Detection


Companion guides — this article covers grammar-level customization of CPA and tone detection. For the canonical implementation walkthroughs and the full Apple Call Screening flow, see:

Outbound contact centers rarely behave the same everywhere. A residential mortgage campaign answers differently from a B2B collections list; a region with heavy carrier intercept tones burns dial attempts that another region never sees; one tenant tolerates a longer pause before classifying a call as human while another cannot. The settings in this article let you tune Call Progress Analysis (CPA) and Answering Machine and tone Detection (AMD) for each of those situations without touching application code or redeploying the platform — the behavior travels in the grammar that the request loads.

That is the operational benefit: because every customization knob below lives in a "CPA" or "AMD" grammar rather than in platform configuration, you can ship per-campaign, per-tenant, or per-region behavior simply by activating a different grammar for a given session or request. In a multi-tenant deployment this keeps one shared platform serving many callers with different classification trade-offs, and lets you adjust one tenant's behavior without risk to the rest.

We recommend building variants of the standard grammars described in our Grammars in CPA and AMD article. In the majority of cases, you can use these sample grammars directly, or make your own copy and apply custom changes. These grammars are loaded and activated much like any other ASR grammar, so platforms with no built-in knowledge of CPA or AMD can use these advanced features seamlessly.



Enabling or Disabling Individual Tone Detection


Outcome controlled: which non-conversational call outcomes you stop wasting dial attempts on. Each class of tone you enable lets the dialer abandon a dead path — a fax line, a disconnected number, a busy signal — instead of routing it to an agent. Each class you disable spends no detection effort on a tone you do not care about. Within tone detection, the following classes of tones can be detected:

  • answering machine tones (AMD)
  • fax tones (FAX)
  • Special Information Tones (SIT)
  • or busy tones (BUSY)

A tone detection grammar can enable or disable the detection of any of these three types of tones: 

<meta name="AMD_CUSTOM_ENABLE" content="true"/>
<meta name="FAX_CUSTOM_ENABLE" content="true"/>
<meta name="SIT_CUSTOM_ENABLE" content="true"/>
<meta name="BUSY_CUSTOM_ENABLE" content="false"/>

Simply set your AMD_CUSTOM_ENABLE, FAX_CUSTOM_ENABLE, SIT_CUSTOM_ENABLE or BUSY_CUSTOM_ENABLE entries in the grammar to "true" or "false" to turn that type of tone detection on or off.

BUSY tone processing

By default BUSY_CUSTOM_ENABLE is set to "false" (disabled) to preserve backward compatibility with existing applications. Set it to "true" to enable busy-tone detection.



Changing CPA Timeouts


Outcome controlled: where the line falls between "keep the agent on this call" and "move on." CPA classifies a call by how long it hears human speech before the speaker pauses, so these timeouts are the levers that decide how a short residential greeting, a longer business greeting, and a recorded message are told apart — and they let you tune that boundary per campaign without changing application logic. CPA has four possible results:

  • human residence,
  • human business,
  • unknown speech (likely machine),
  • or unknown silence (also likely a machine).

CPA returns one of these based on how long it detects human speech (for the first three) or if no speech (silence) is detected. Three timeout settings control this that are specified in the meta tags in the CPA grammar: 

<meta name="STREAM|CPA_HUMAN_RESIDENCE_TIME" content="1800"/>
<meta name="STREAM|CPA_HUMAN_BUSINESS_TIME" content="3000"/>
<meta name="STREAM|CPA_UNKNOWN_SILENCE_TIMEOUT" content="5000"/>

These setting values are all represented in milliseconds (i.e. 1800ms or 1.8 seconds is the default value for CPA_HUMAN_RESIDENCE_TIME).  

If speech is detected that lasts for less than the value of CPA_HUMAN_RESIDENCE_TIME (default 1800 milliseconds), then the HUMAN RESIDENCE prediction result is returned. This is for short utterances typical of residential or mobile phones when answered by a human in a non-business setting (i.e. "Hello this is John")

If the length of speech detected  is greater than CPA_HUMAN_RESIDENCE_TIME, but less than CPA_HUMAN_BUSINESS_TIME, then the HUMAN BUSINESS prediction result is returned. This represents typically longer utterances for humans answering a business line (i.e. "This is Capacity, how may I direct your call today")

If the speech is longer than CPA_HUMAN_BUSINESS_TIME, then the UNKNOWN SPEECH prediction result is returned. This may be a recorded message or some other automated playback, so is designated as UNKNOWN SPEECH. This is often handled as though it were a machine in call flows. There is no timeout for unknown speech since it is anything longer than human business. Note that once speech had been detected that exceeds the amount of CPA_HUMAN_BUSINESS_TIME, the UNKNOWN SPEECH result will be returned (it does NOT wait for all of the speech to end), allowing your call flow to decide how it would like to proceed.

Note that if CPA_HUMAN_RESIDENCE_TIME and CPA_HUMAN_BUSINESS_TIME are set to the same value, then HUMAN BUSINESS will not be returned. Duration of speech will either be less than these two settings, in which case HUMAN RESIDENCE will be returned, or above these settings, in which case, UNKNOWN SPEECH will be returned. This configuration may be useful for applications that do not wish to distinguish between Residence and Business classifications, and instead only wish to process human versus machine responses. Note that similar behavior can be achieved by setting the appropriate Input Text and Semantic Interpretation values for both of these classifications in the grammar, providing developers maximum flexibility.

UNKNOWN_SILENCE_TIMEOUT controls how long CPA will wait for the start of speech to be detected before returning UNKNOWN SILENCE. Note that once start of human speech has been detected (prior to CPA_UNKNOWN_SILENCE_TIMEOUT), one of the other results will be returned. UNKNOWN SILENCE will only be returned if there is no detected human speech before this timeout is reached.

UNKNOWN_SILENCE_TIMEOUT vs BARGE_IN_TIMEOUT or END_OF_SPEECH_TIMEOUT

Note that when performing CPA, it is important to make sure that BARGE_IN_TIMEOUT is not reached, since this would return a No-Input-Timeout event, which may be unexpected in the context of CPA. If there is no human speech detected in the call, you instead want the UNKNOWN_SILENCE_TIMEOUT to be reached first, thus returning the more understandable UNKNOWN SILENCE result, which can be handled more predictably within your call flow.

The platform forces the BARGE_IN_TIMEOUT setting to be greater than the longest CPA time setting, ensuring this timeout is not reached during CPA.

Also worth noting is the END_OF_SPEECH_TIMEOUT setting (maximum duration of speech after human speech is first detected), which should not be confused with the VAD_EOS_DELAY setting (amount of silence following speech) described below; it should also never be reached when working with CPA interactions. The platform forces the value of this setting to be 10,000 ms (10 seconds) greater than the largest CPA time specified, ensuring it is never reached.

The default values for these CPA timing settings are applied in the client_property.conf configuration file. Any values (such as those shown above) detected within the grammar will override any defaults specified in the configuration file.


CPA_MAX_TIME_FROM_CONNECT


Outcome controlled: your end-to-end latency budget — the longest you are willing to make a connected call wait before CPA returns a decision. CPA_MAX_TIME_FROM_CONNECT is one of the most powerful CPA settings; read the full description and usage guidance in our dedicated CPA_MAX_TIME_FROM_CONNECT article.

Rather than tuning each of the timing values above individually, this setting overrides and automatically scales them to fit the maximum amount of time your application is willing to wait for a response. It applies to most applications and, being a single value to set, is considerably less complex to manage than the individual timeouts.


Modifying the End-Of-Speech Delay


Outcome controlled: how tolerant CPA is of a natural pause mid-greeting before it decides the speaker has finished — the direct trade-off between classification accuracy and how quickly a result returns. The Voice Activity Detection (VAD) End-Of-Speech setting (also known as VAD_EOS_DELAY) determines how much silence is allowed after the start of human speech is detected before the audio is processed and a response is generated. A larger value tolerates longer pauses between words; a shorter value risks triggering end-of-speech too soon when someone is merely pausing.

This value defaults to 1200 ms and should be configured using the CPA grammar file.

To change the value add the following line to your CPA grammar, placing the desired setting in milliseconds in the content attribute (900 ms in the example).

<meta name="STREAM|VAD_EOS_DELAY" content="900"/>

This value should only be modified with an understanding of the trade-offs, setting it too low will cause more false positive “HUMAN” responses (possibly misclassifying the prediction).  Setting too high of a value will cause the CPA responses to take longer to return.

By way of a simple guide for this, we have found the default value of 1200ms works best in most situations, however implementations that are more sensitive to machine-to-human misclassifications, as may be the case in many call centers, setting a slightly higher value of perhaps 1500ms would improve this accuracy, at the cost of a small amount of additional delay between when the person answering the call stops speaking, and when the system receives a CPA response. In the example here, the difference between 1200ms and 1500ms would mean an additional 300ms of delay (or observed silence) to the person answering the call. Application developers should consider what is an acceptable amount of delay that they wish humans to encounter and understand this trade-off against CPA accuracy.


It is important to note that when using the CPA_MAX_TIME_FROM_CONNECT option (described above), the VAD_EOS_DELAY setting is also automatically set, so specifying it within the grammar when using that setting will have no effect.


Customizing the Return


Outcome controlled: the exact tokens your call flow branches on — so you can reshape CPA and tone results to match what an existing platform or routing layer already expects, rather than rewriting that layer. The default return from a tone detection or CPA grammar is one of the strings listed above; however, a speech recognition result (which CPA and tone detection mirror) has two distinct components: 

  • The input sentence (also known as the "Input Text" or "Raw Text"). This is the usually the actual word or phrase spoken by the user.
  • The Semantic Interpretation (or "SI"). This is usually a formatted result that contains the meaning or intent of the input sentence. 

For example, imagine a user says "One two three" with a digits grammar. The ASR will perform a recognition, using the grammar, in order to produce the Raw Text (otherwise known as Input Text) "ONE TWO THREE." It will then parse the grammar's semantic tags, using the input "ONE TWO THREE" to get a Semantic Interpretation. It may also transform the phrase "ONE TWO THREE" into a string of digits: "123", known as the Semantic Interpretation. This is useful for a number of reasons within speech processing. Generally speaking, this Semantic Interpretation is what the voice application will make use of ("ONE TWO THREE" likely requires further processing, whereas "123" might be useful as-is within an application).

CPA / tone detection goes through a similar process because the platform mimics ASR behavior in order to be more compatible with voice platforms that expect both Raw Text and Semantic Interpretation to be provided in results. There is no actual raw text in a tone detection, but the system acts as though there were. The grammars allow you to customize both the Raw Text and the Semantic Interpretation that is returned for a CPA or tone detection response. 

The exact mechanism makes a little more sense if you are familiar with the syntax of SRGS grammars, but let's revisit part of the CPA grammar: 

    <meta name="HUMAN_RESIDENCE_CUSTOM_INPUT_TEXT" content="HUMAN RESIDENCE"/>
<meta name="HUMAN_BUSINESS_CUSTOM_INPUT_TEXT" content="HUMAN BUSINESS"/>
<meta name="UNKNOWN_SPEECH_CUSTOM_INPUT_TEXT" content="UNKNOWN SPEECH"/>
    <meta name="UNKNOWN_SILENCE_CUSTOM_INPUT_TEXT" content="UNKNOWN SILENCE"/>

Meta tags whose names include "CUSTOM_INPUT_TEXT" control what the Raw Text (sometimes called Input Text) gets set to if that event is returned. For instance, if the CPA detects human business, then the input text will be set to the value associate with HUMAN_BUSINESS_CUSTOM_INPUT_TEXT (by default this is HUMAN BUSINESS). 

   <rule id="root" scope="public">
<one-of>
<item>HUMAN RESIDENCE<tag>out="HUMAN RESIDENCE"</tag></item>
<item>HUMAN BUSINESS<tag>out="HUMAN BUSINESS"</tag></item>
<item>UNKNOWN SPEECH<tag>out="UNKNOWN SPEECH"</tag></item>
<item>UNKNOWN SILENCE<tag>out="UNKNOWN SILENCE"</tag></item>
</one-of>
    </rule>

The semantic interpretation is then defined within the grammar, as in the section shown above. If the Input Text is HUMAN BUSINESS then the corresponding semantic tag gets executed, setting the Semantic Interpretation to HUMAN BUSINESS, both of which are returned in the result. Thus if you ever alter the custom input text, you must also alter the grammar rule or else you will not get appropriate results. 

For CPA, there is little reason to change the input text or the interpretation. For AMD it may make a little more sense. Let's revisit that grammar:

<meta name="AMD_CUSTOM_INPUT_TEXT" content="AMD"/>
<meta name="FAX_CUSTOM_INPUT_TEXT" content="FAX"/>
<meta name="BUSY_CUSTOM_INPUT_TEXT" content="BUSY"/>

<meta name="SIT_REORDER_LOCAL_CUSTOM_INPUT_TEXT" content="SIT REORDER LOCAL"/>
<meta name="SIT_VACANT_CODE_CUSTOM_INPUT_TEXT" content="SIT VACANT CODE"/>
<meta name="SIT_NO_CIRCUIT_LOCAL_CUSTOM_INPUT_TEXT" content="SIT NO CIRCUIT LOCAL"/>
<meta name="SIT_INTERCEPT_CUSTOM_INPUT_TEXT" content="SIT INTERCEPT"/>
<meta name="SIT_REORDER_DISTANT_CUSTOM_INPUT_TEXT" content="SIT REORDER DISTANT"/>
<meta name="SIT_NO_CIRCUIT_DISTANT_CUSTOM_INPUT_TEXT" content="SIT NO CIRCUIT DISTANT"/>
<meta name="SIT_OTHER_CUSTOM_INPUT_TEXT" content="SIT OTHER"/>

<rule id="root" scope="public">
<one-of>
<item>AMD<tag>out="AMD"</tag></item>
<item>FAX<tag>out="FAX"</tag></item>
<item>BUSY<tag>out="BUSY"</tag></item>
<item>SIT REORDER LOCAL<tag>out="SIT"</tag></item>
<item>SIT VACANT CODE<tag>out="SIT"</tag></item>
<item>SIT NO CIRCUIT LOCAL<tag>out="SIT"</tag></item>
<item>SIT INTERCEPT<tag>out="SIT"</tag></item>
<item>SIT REORDER DISTANT<tag>out="SIT"</tag></item>
<item>SIT NO CIRCUIT DISTANT<tag>out="SIT"</tag></item>
<item>SIT OTHER<tag>out="SIT"</tag></item>
</one-of>
</rule>

Here notice that all of the SIT (Special Information Tone) detection events will return the same interpretation of SIT. If an application wanted to treat the SIT intercept differently from the other SIT events, then the interpretation for that item would need to be edited, as shown in this example:

    <item>SIT INTERCEPT<tag>out="INTERCEPT"</tag>
    </item>

The other tones can also be modified as needed too, should your application require the distinction.


Customizing for Apple Call Screening


Outcome controlled: not losing a live human to a misread screening interaction. Apple Call Screening sits between the dialer and a real person on an iOS device, and to a classifier that does not understand it the screening announcement looks like a recorded message — exactly the kind of false negative that drops a reachable contact and hurts right-party-contact rates. The device answers automatically, plays an announcement asking the caller to identify themselves, transcribes the reply for the Apple user, then plays a distinctive warble tone while the user decides whether to accept, decline, or send the call to voicemail. CPA and tone detection expose dedicated customization knobs for each stage of this flow so an application can advance through the screening interaction deterministically and reach the person on the other side. The standard CPA and AMD timeout and grammar settings described above still apply — the settings below layer on top of them.

Detecting the end of the screening announcement (Prompt End)

After an initial CPA result of UNKNOWN SPEECH — which indicates the Apple screening announcement is playing — use Prompt End detection to identify the moment the announcement finishes so the screening payload can be delivered at the right time. Under MRCP this is the cpa_prompt_end.grxml grammar; under gRPC it is the cpa_prompt_end_enable=true field on the interaction. CPA returns PROMPT END when the announcement speech concludes.

Prompt End overrides other CPA settings

Prompt End detection must be used on its own: when it is enabled, all other CPA settings are ignored. Configure it in a dedicated CPA grammar or interaction rather than combining it with the standard residence/business/silence timing settings.

Detecting the Apple screening tone

Once the screening payload has been delivered, listen for the distinctive Apple warble tone that signals the user is reviewing the transcribed message. Under MRCP this uses the amd_screening_tone.grxml grammar; under gRPC it is the screening_tone_enable=true field. When tone detection returns SCREENING, the application has confirmation that Apple Call Screening is active and the user is deciding how to handle the call.

Extending the wait for the screening outcome

After the screening tone is confirmed, the application must wait for the Apple user to choose an outcome — accept (human answered), decline (call dropped), or ignore (voicemail). Because a person needs time to read the transcription and decide, the standard silence timeout is too short. Extend it by setting CPA_UNKNOWN_SILENCE_TIMEOUT to a larger value — 30000 ms (30 seconds) is a good starting point — and adjust it based on the response times you observe for your campaign. Under MRCP this is a CPA grammar variant carrying the extended timeout; under gRPC it is the cpa_unknown_silence_timeout=30000 field.

For the complete Apple Call Screening process flow, message sequences, and decision tables, see the CPA & AMD Integration: MRCP guide (grammar-based) and the CPA & AMD Integration: gRPC guide (protobuf-based).

For more details relating to working with grammars when using CPA and Tone Detection, see our Grammars in CPA and AMD article.



Was this article helpful?