1

I'm stuck in TAPI programming. I've created a program to monitor activity of phone call. Everything is working fine, but now I want to implement a functionality to accept and reject a call from web directly.

what I've done is below:

namespace Shared
{
    public partial class Site : System.Web.UI.MasterPage
    {
        public static ITAddress ln;
        static int index = -1;
        static int line;
        static ITAddress[] ia;
        protected void Page_Load(object sender, EventArgs e)
        {
            #region TAPI
            TAPIClass tobj;
            int[] registertoken;
            tobj = new TAPI3Lib.TAPIClass();
            tobj.Initialize();

            IEnumAddress ea = tobj.EnumerateAddresses();

            uint lines;


            uint arg3 = 0;
            int TotalLines = 0;
            lines = 0;
            foreach (TAPI3Lib.ITAddress ad in (tobj.Addresses as TAPI3Lib.ITCollection))
            {
                TotalLines++;
            }

            callnotification cn = new callnotification();
            tobj.ITTAPIEventNotification_Event_Event += new TAPI3Lib.ITTAPIEventNotification_EventEventHandler(cn.Event);
            tobj.EventFilter = (int)(TAPI_EVENT.TE_CALLNOTIFICATION |
                TAPI_EVENT.TE_DIGITEVENT |
                TAPI_EVENT.TE_PHONEEVENT |
                TAPI_EVENT.TE_CALLSTATE |
                TAPI_EVENT.TE_GENERATEEVENT |
                TAPI_EVENT.TE_GATHERDIGITS |
                TAPI_EVENT.TE_REQUEST);


            registertoken = new int[TotalLines];
            ia = new TAPI3Lib.ITAddress[TotalLines];
            for (int i = 0; i = 0)
                                    {
                                        ln = ia[line];
                                    }
                                    IEnumCall ec = ln.EnumerateCalls();
                                    uint arg = 0;
                                    ITCallInfo ici;
                                    try
                                    {
                                        ec.Next(1, out ici, ref arg);
                                        ITBasicCallControl2 bc = (TAPI3Lib.ITBasicCallControl2)ici;
                                        if (ici != null && ici.CallState == CALL_STATE.CS_OFFERING)
                                        {
                                            if (bc != null)
                                            {
                                                bc.Answer();
                                            }
                                        }
                                    }
                                    catch (Exception ex)
                                    {
                                        COMException comEx = ex as COMException;
                                        if (comEx != null)
                                            comEx.ErrorCode.ToString();
                                        else
                                        {
                                            string aa = ex.Message;
                                        }
                                    }

                                    //addtolist("Call Offering from " + callernumber + " to Ext " + viaextension + " via DID " + DIDNumber);
                                    break;
                                case TAPI3Lib.CALL_STATE.CS_IDLE:
                                    //addtolist("Call is created!");
                                    break;
                            }
                            break;
                    }
                }
                catch (Exception ex)
                {
                    //MessageBox.Show(ex.StackTrace.ToString());
                }
            }
        }
        #endregion
    }
}

I'm always getting ITBasicCallControl2 bc NULL and when I press the Accept button, nothing happens.

Mafii
  • 7,227
  • 1
  • 35
  • 55
Asif Ghanchi
  • 236
  • 3
  • 11

1 Answers1

4

Okay, so the first thing you have to do in order to successfully answer calls, is to register your line with owner rights.

tobj.RegisterCallNotifications(ln, true, true, TapiConstants.TAPIMEDIATYPE_AUDIO, 2);

After that, you can either iterate through every call using EnumerateCalls(), or you can implement the ITTAPIEventNotification interface to get notified if there is a change in callstate (for example). One way or the other, at some point, you have found the call you want to answer. Now you need to make sure, that the call is in an alerting state (CS_OFFERING for inbound calls), before you can finally call the answer method.

        try
        {
            ec.Next(1, out ici, ref arg);
            if (ici != null && ici.CallState == CALL_STATE.CS_OFFERING)
            {
                ITBasicCallControl2 bc = (TAPI3Lib.ITBasicCallControl2)ici;
                if (bc != null)
                {
                    bc.Answer();
                }
            }
        }
        catch (Exception exp)
        {
            COMException comEx = exp as COMException;
            if (comEx != null)
                MessageBox.Show(comEx.ErrorCode.ToString());
            else
                MessageBox.Show(exp.Message);
        }

If the call you want to answer is not in the callstate CS_CONNECTED, the method will throw a COMException with an error code of 0x800040010.

For further information on the ITTAPIEventNotification interface, see https://msdn.microsoft.com/en-us/library/windows/desktop/ms732506(v=vs.85).aspx

EDIT:

If you want to detect new incoming calls, I'd recommend to use the TE_CALLNOTIFICATION-Event, because it is triggered only once per new incoming call. The TE_CALLSTATE-Event will be triggered every time the callstate changes.

Now, i've updated the callnotification class:

    public class callnotification : TAPI3Lib.ITTAPIEventNotification
    {
        public InboundCall OnNewIncomingCall;

        public void Event(TAPI_EVENT TapiEvent, object pEvent)
        {
            switch (TapiEvent)
            {
                case TAPI_EVENT.TE_CALLNOTIFICATION:
                    this.OnCallNotification((ITCallNotificationEvent)pEvent);
                    break;
            }
        }

        private void OnCallNotification(ITCallNotificationEvent callNotification)
        {
            ITCallInfo ici = callNotification.Call;

            if (ici != null && ici.CallState == CALL_STATE.CS_OFFERING)
                this.OnNewIncomingCall(ici);
        }
    }

I've also declared a delegate Method to use if there is a new inbound call:

public delegate void InboundCall(ITCallInfo ici);

So your initialization of the callnotification event could look like this:

        callnotification cn = new callnotification();
        cn.OnNewIncomingCall += this.OnNewIncomingCall;

And finally, in the OnNewIncomingCallMethod, you can answer the call:

    private void OnNewIncomingCall(ITCallInfo ici)
    {
        ITBasicCallControl bcc = (ITBasicCallControl)ici;
        if (bcc != null)
        {
            string caller = ici.get_CallInfoString(CALLINFO_STRING.CIS_CALLERIDNUMBER);
            DialogResult dlg = MessageBox.Show(string.Format("New incoming call from {0}\r\nDo you wish to answer the call now?", caller), "New incoming call", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
            if (dlg == System.Windows.Forms.DialogResult.Yes)
                bcc.Answer();
        }
    }

I've tested your code with the additions of mine and it worked fine. Should you be having any exceptions when answering or during the initialization, let me know.

Oerk
  • 148
  • 10
  • Hi @Oerk, Thanks for your reply, i have done same as you have added in your reply but when i debug my code i m getting an error at "ITBasicCallControl2 bc = (TAPI3Lib.ITBasicCallControl2)ici" The error is "Unable to cast COM object of type 'System.__ComObject' to interface type 'TAPI3Lib.ITBasicCallControl'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{B1EFC389-9355-11D0-835C-00AA003CCABD}' failed due to the following error: No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE))." Please help me out. – Asif Ghanchi May 19 '17 at 05:33
  • HI @AsifGhanchi, did you register the line, you want to answer a call with, before you tried to answer it? This Exception is most likely to be thrown, when the line is not registered with owner rights. If you do not have owner Rights on a line, you cannot cast an ITCallControl into an ITBasicCallControl, because youre not allowed to manipulate a call. – Oerk May 19 '17 at 07:40
  • Hi @Oerk, i have updated my latest code, could you please look into it i have registered line before making any operation. Please help me out. Thanks in advance. – Asif Ghanchi May 19 '17 at 09:40
  • Hi @AsifGhanchi, when i run your code, it seems to be working just fine. I'd only recommend to use the TE_CALLNOTIFICATION-Event instead of TE_CALLSTATE-Event, if you want to detect an incoming call. I've updated my post for you, so can see what i mean. – Oerk May 19 '17 at 15:20
  • Hi @Oerk, its working after open visual studio (Run as Admin), but after bc.Answer() execute the phone still ringing and when i hang up the call its giving me an error like "This implementation doesn't take advises Error" at ici.ReleaseUserUserInfo(); Could you please help me out why phone is not answer even there is no error and also why this error came for disconnecting the call? Thanks in Advance. – Asif Ghanchi May 20 '17 at 09:42
  • Hi @AsifGhanchi, the error you received when trying to hang up a call, did it have an error code of 0x80040003? If yes, you might want to look into [this post](https://stackoverflow.com/questions/24311504/exception-on-call-hangup-for-landline-phone). As far as your answering problem goes, i have no idea why it isn't working, I am sorry! – Oerk May 23 '17 at 08:46
  • Hi Oerk, i have a question can you please help me out. as per your comment i have to register TAPI Line with owner rights, what does it means? because when i run my visual studio as administrator and register a TAPI Line the "ITCallInfo" (ici) object content a "CALL_PRIVILEGE" class and it shows me "1" in value it means i only have monitor rights. how i register a TAPI Line using owner rights? Please help me out. Thanks in advance. – Asif Ghanchi Jun 07 '17 at 06:02
  • Hi Oerk, ignore my previous comment. i have registered a line with both monitor and owner priviledge but still when i debug my program the ici (ITCallInfo object) shows me priviledge as "1" which means i only have monitor rights not owner. am i doing anything wrong, please help me out. Thanks in advance. – Asif Ghanchi Jun 07 '17 at 06:31
  • HI @AsifGhanchi, as far as i know, your PBX needs to be configured in a way, that it allows an application to request ownership of calls. But unfortunately, i am not much of an expert in regards to hardware configuration. – Oerk Jun 09 '17 at 07:56
  • Hi @Oerk, now i am able to answer and reject call in windows form application as i am getting owner rights in windows form application but i am not able to answer and reject call in web application because of the Monitor Rights only.. could you please help me out for this. Thanks in advance. – Asif Ghanchi Jun 12 '17 at 05:29