Answering machine detector

The Ozeki Answering Machine Detector is a VoIP feature that helps applications determine whether a call has been answered by a real person or an answering machine. By analyzing the audio received immediately after call connection, it can identify common characteristics such as recorded greetings, extended speech, silence, and voicemail tones. This allows developers to automate call handling, connect live calls to agents, end voicemail calls, or leave prerecorded messages. The feature is particularly useful for call centers, automated notification systems, and other SIP-based applications that need reliable and efficient outbound call processing.

What is answering machine detection

Answering Machine Detection (AMD) is a telephony feature that determines whether an outbound call has been answered by a live person, voicemail, an answering machine, a fax device, or another automated system. After the call connects, the detector analyzes the first seconds of audio, including speech patterns, greeting length, pauses, silence intervals, background noise, tones, and the presence of a voicemail beep. A person commonly answers with a short greeting such as “Hello” and then pauses, while an answering machine usually plays a longer, continuous recorded message followed by a tone. Based on these characteristics, the system classifies the call and triggers the appropriate action. If a human answers, the call can be connected to an agent, voice application, or interactive voice response menu. If a machine is detected, the system may hang up, wait for the beep and leave a prerecorded message, or mark the call for later processing. AMD is especially useful in call centers, automated notification systems, sales dialers, and VoIP applications because it prevents agents and resources from being wasted on voicemail calls.

In an Ozeki VoIP SIP application, the detector can receive audio from an active call through a media connector, process it using a speech-recognition engine, and report the result through a detection-completed event. The application can then inspect the returned result and terminate the call if it is classified as an answering machine. Detection is not perfect because greetings differ between users, languages, carriers, and devices. Short voicemail messages may be mistaken for human answers, while people with long greetings or background noise may be classified incorrectly. Therefore, AMD settings should be tested with real calls and tuned to balance false positives against false negatives.

How to implement answering machine detection feature using C#?

To implement answering machine detection in C#, create and initialize the Ozeki VoIP SIP SDK, establish a SIP account, and place or receive a call. After the call is connected, attach an answering machine detector or speech-recognition media connector to the call’s audio stream. Configure detection parameters, such as the maximum greeting duration, silence intervals, and analysis timeout, then start detection. Handle the detector’s completion event and inspect the returned result, such as human, answering machine, fax, or unknown. If an answering machine is identified, stop media processing and terminate the call or leave a recorded message. Test the configuration with different greetings and network conditions.

Answering Machine Detector example in C#

using System;
using Ozeki.Media;
using Ozeki.VoIP;
using System.Threading.Tasks;
using System.Threading;
using System.Linq;

namespace Answering_Machine_Detector
{
    class Program
    {
        static ISoftPhone _softphone; // _softphone object
        static IPhoneLine _phoneLine; // _phoneLine object
        static IPhoneCall _call;      // _call object

        static PhoneCallAudioReceiver _phoneCallAudioReceiver;
        static AudioQualityEnhancer _aqEnhancer;

        static AnswerMachineDetector _amDetector;
        static MediaConnector _connector;

        static void Main(string[] args)
        {
            // Create a softphone object with RTP port range 5000-10000
            var userAgent = "AnsweringMachineDetection-example";
            _softphone = SoftPhoneFactory.CreateSoftPhone(5000, 10000, userAgent);

            // SIP account registration data, (supplied by your VoIP service provider)
            var registrationRequired = true;
            var userName = "107";
            var displayName = "107";
            var authenticationId = "107";
            var registerPassword = "107";
            var domainHost = "192.168.115.60";
            var domainPort = 5060;

            var account = new SIPAccount(registrationRequired, displayName, userName, 
            authenticationId, registerPassword, domainHost, domainPort);

            _aqEnhancer = new AudioQualityEnhancer(new AudioFormat(8000, 1, 16, 20))
            {
                NoiseReductionLevel = NoiseReductionLevel.Medium,
                AutoGainControl = false
            };

            _phoneCallAudioReceiver = new PhoneCallAudioReceiver();

            var stt = new MSSpeechPlatformSTT();
            _amDetector = new AnswerMachineDetector(stt);

            // Select English recognizer
            var recognizers = stt.GetRecognizers();
            var recognizerEnglish = recognizers
                .FirstOrDefault(r => r.Culture.Name.StartsWith("en-", StringComparison.OrdinalIgnoreCase))
                ?? throw new InvalidOperationException("No English speech recognizer (en-*) is installed.");
            stt.ChangeRecognizer(recognizerEnglish.ID);

            _connector = new MediaConnector();

            _connector.Connect(_phoneCallAudioReceiver, _aqEnhancer);
            _connector.Connect(_aqEnhancer, _amDetector);
			
			// subscribes to the event to get notified about the _amDetector's completed
            _amDetector.DetectionCompleted += amDetector_DetectionCompleted; 

            // Send SIP regitration request
            RegisterAccount(account);

            // prevents the termination of the application 
            Console.ReadLine();
        }

        static void RegisterAccount(SIPAccount account)
        {
            try
            {
                // With the SIP account and the NAT configuration, we can create a phoneline.
                _phoneLine = _softphone.CreatePhoneLine(account);
                _phoneLine.RegistrationStateChanged += sipAccount_RegStateChanged;
                // If our phoneline is created, we can register that.
                _softphone.RegisterPhoneLine(_phoneLine);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error during SIP registration: " + ex);
            }
        }

        static void sipAccount_RegStateChanged(object sender, RegistrationStateChangedArgs e)
        {
            Console.WriteLine(e.State);
            if (e.State == RegState.RegistrationSucceeded)
                CreateCall(); // start the call
        }

        static void CreateCall()
        {
            var dial = new DialParameters("106") { CallType = CallType.Audio };
            Console.WriteLine("Calling number is: " + dial.DialInfo.Dialed);

            _call = _softphone.CreateCallObject(_phoneLine, dial);
			
			// subscribes to the event to get notified about the call's states
            _call.CallStateChanged += call_CallStateChanged; 

            _aqEnhancer.Start();
            // attach the _phoneCallAudioReceiver to the call
            _phoneCallAudioReceiver.AttachToCall(_call); 
            _call.Start();
        }

        static void amDetector_DetectionCompleted(object sender, VoIPEventArgs<AnswerMachineDetectionResult> e)
        {
            Console.WriteLine("Detection completed: " + e.Item);
            if (e.Item == AnswerMachineDetectionResult.Machine)
            {
                Console.WriteLine("Call is hang up.");
                _call.HangUp();
            }
        }

        static void call_CallStateChanged(object sender, CallStateChangedArgs e)
        {
            Console.WriteLine("Call state: {0}.", e.State);

            if (e.State == CallState.InCall)
                _amDetector.Start(); // start the detection
            if (e.State.IsCallEnded())
            {
                _phoneCallAudioReceiver.Detach();
                _call.CallStateChanged -= call_CallStateChanged;
                _amDetector.Stop(); // stop the detection
                _aqEnhancer.Stop();
                Console.WriteLine("-------------------------------------------");
            }
        }
    }
}

More information