Handle HOLD/RETRIEVE notifications
[asterisk/asterisk.git] / channels / h323 / ast_h323.cxx
index cc02119..826be72 100644 (file)
 #include <ptlib.h>
 #include <h323.h>
 #include <h323pdu.h>
 #include <ptlib.h>
 #include <h323.h>
 #include <h323pdu.h>
+#include <h323neg.h>
 #include <mediafmt.h>
 #include <lid.h>
 #include <mediafmt.h>
 #include <lid.h>
+#ifdef H323_H450
+#include "h4501.h"
+#include "h4504.h"
+#include "h45011.h"
+#include "h450pdu.h"
+#endif
 
 #ifdef __cplusplus
 extern "C" {
 
 #ifdef __cplusplus
 extern "C" {
@@ -527,12 +534,22 @@ MyH323Connection::MyH323Connection(MyH323EndPoint & ep, unsigned callReference,
                                                        unsigned options)
        : H323Connection(ep, callReference, options)
 {
                                                        unsigned options)
        : H323Connection(ep, callReference, options)
 {
+#ifdef H323_H450
+       /* Dispatcher will free out all registered handlers */
+       if (h450dispatcher)
+               delete h450dispatcher;
+       h450dispatcher = new H450xDispatcher(*this);
+       h4502handler = new H4502Handler(*this, *h450dispatcher);
+       h4504handler = new MyH4504Handler(*this, *h450dispatcher);
+       h4506handler = new H4506Handler(*this, *h450dispatcher);
+       h45011handler = new H45011Handler(*this, *h450dispatcher);
+#endif
        cause = -1;
        sessionId = 0;
        bridging = FALSE;
        cause = -1;
        sessionId = 0;
        bridging = FALSE;
-       progressSetup = progressAlert = 0;
+       holdHandling = progressSetup = progressAlert = 0;
        dtmfMode = 0;
        dtmfMode = 0;
-       dtmfCodec = (RTP_DataFrame::PayloadTypes)0;
+       dtmfCodec[0] = dtmfCodec[1] = (RTP_DataFrame::PayloadTypes)0;
        redirect_reason = -1;
 #ifdef TUNNELLING
        tunnelOptions = remoteTunnelOptions = 0;
        redirect_reason = -1;
 #ifdef TUNNELLING
        tunnelOptions = remoteTunnelOptions = 0;
@@ -663,7 +680,9 @@ void MyH323Connection::SetCallOptions(void *o, BOOL isIncoming)
 
        progressSetup = opts->progress_setup;
        progressAlert = opts->progress_alert;
 
        progressSetup = opts->progress_setup;
        progressAlert = opts->progress_alert;
-       dtmfCodec = (RTP_DataFrame::PayloadTypes)opts->dtmfcodec;
+       holdHandling = opts->holdHandling;
+       dtmfCodec[0] = (RTP_DataFrame::PayloadTypes)opts->dtmfcodec[0];
+       dtmfCodec[1] = (RTP_DataFrame::PayloadTypes)opts->dtmfcodec[1];
        dtmfMode = opts->dtmfmode;
 
        if (isIncoming) {
        dtmfMode = opts->dtmfmode;
 
        if (isIncoming) {
@@ -1105,6 +1124,14 @@ BOOL MyH323Connection::OnReceivedSignalSetup(const H323SignalPDU & setupPDU)
 
        SetCallOptions(res, TRUE);
 
 
        SetCallOptions(res, TRUE);
 
+       /* Disable fastStart if requested by remote side */
+       if (h245Tunneling && !setupPDU.m_h323_uu_pdu.m_h245Tunneling) {
+               masterSlaveDeterminationProcedure->Stop();
+               capabilityExchangeProcedure->Stop();
+               PTRACE(3, "H225\tFast Start DISABLED!");
+               h245Tunneling = FALSE;
+       }
+
        return H323Connection::OnReceivedSignalSetup(setupPDU);
 }
 
        return H323Connection::OnReceivedSignalSetup(setupPDU);
 }
 
@@ -1204,7 +1231,8 @@ void MyH323Connection::SendUserInputTone(char tone, unsigned duration, unsigned
 
 void MyH323Connection::OnUserInputTone(char tone, unsigned duration, unsigned logicalChannel, unsigned rtpTimestamp)
 {
 
 void MyH323Connection::OnUserInputTone(char tone, unsigned duration, unsigned logicalChannel, unsigned rtpTimestamp)
 {
-       if ((dtmfMode & H323_DTMF_RFC2833)) {
+       /* Why we should check this? */
+       if ((dtmfMode & (H323_DTMF_CISCO | H323_DTMF_RFC2833 | H323_DTMF_SIGNAL)) != 0) {
                if (h323debug) {
                        cout << "\t-- Received user input tone (" << tone << ") from remote" << endl;
                }
                if (h323debug) {
                        cout << "\t-- Received user input tone (" << tone << ") from remote" << endl;
                }
@@ -1234,10 +1262,10 @@ void MyH323Connection::OnSendCapabilitySet(H245_TerminalCapabilitySet & pdu)
                        H245_Capability & cap = entry.m_capability;
                        if (cap.GetTag() == H245_Capability::e_receiveRTPAudioTelephonyEventCapability) {
                                H245_AudioTelephonyEventCapability & atec = cap;
                        H245_Capability & cap = entry.m_capability;
                        if (cap.GetTag() == H245_Capability::e_receiveRTPAudioTelephonyEventCapability) {
                                H245_AudioTelephonyEventCapability & atec = cap;
-                               atec.m_dynamicRTPPayloadType = dtmfCodec;
-//                             on_set_rfc2833_payload(GetCallReference(), (const char *)GetCallToken(), (int)dtmfCodec);
+                               atec.m_dynamicRTPPayloadType = dtmfCodec[0];
+//                             on_set_rfc2833_payload(GetCallReference(), (const char *)GetCallToken(), (int)dtmfCodec[0]);
                                if (h323debug) {
                                if (h323debug) {
-                                       cout << "\t-- Transmitting RFC2833 on payload " <<
+                                       cout << "\t-- Receiving RFC2833 on payload " <<
                                                atec.m_dynamicRTPPayloadType << endl;
                                }
                        }
                                                atec.m_dynamicRTPPayloadType << endl;
                                }
                        }
@@ -1290,21 +1318,12 @@ BOOL MyH323Connection::OnReceivedCapabilitySet(const H323Capabilities & remoteCa
        };
 #endif
        struct ast_codec_pref prefs;
        };
 #endif
        struct ast_codec_pref prefs;
+       RTP_DataFrame::PayloadTypes pt;
 
        if (!H323Connection::OnReceivedCapabilitySet(remoteCaps, muxCap, reject)) {
                return FALSE;
        }
 
 
        if (!H323Connection::OnReceivedCapabilitySet(remoteCaps, muxCap, reject)) {
                return FALSE;
        }
 
-       const H323Capability * cap = remoteCaps.FindCapability(H323_UserInputCapability::SubTypeNames[H323_UserInputCapability::SignalToneRFC2833]);
-       if (cap != NULL) {
-               RTP_DataFrame::PayloadTypes pt = ((H323_UserInputCapability*)cap)->GetPayloadType();
-               on_set_rfc2833_payload(GetCallReference(), (const char *)GetCallToken(), (int)pt);
-               if ((dtmfMode & H323_DTMF_RFC2833) && (sendUserInputMode == SendUserInputAsTone))
-                       sendUserInputMode = SendUserInputAsInlineRFC2833;
-               if (h323debug) {
-                       cout << "\t-- Inbound RFC2833 on payload " << pt << endl;
-               }
-       }
        memset(&prefs, 0, sizeof(prefs));
        int peer_capabilities = 0;
        for (int i = 0; i < remoteCapabilities.GetSize(); ++i) {
        memset(&prefs, 0, sizeof(prefs));
        int peer_capabilities = 0;
        for (int i = 0; i < remoteCapabilities.GetSize(); ++i) {
@@ -1337,6 +1356,32 @@ BOOL MyH323Connection::OnReceivedCapabilitySet(const H323Capabilities & remoteCa
                                }
                        }
                        break;
                                }
                        }
                        break;
+               case H323Capability::e_Data:
+                       if (!strcmp((const char *)remoteCapabilities[i].GetFormatName(), CISCO_DTMF_RELAY)) {
+                               pt = remoteCapabilities[i].GetPayloadType();
+                               if ((dtmfMode & H323_DTMF_CISCO) != 0) {
+                                       on_set_rfc2833_payload(GetCallReference(), (const char *)GetCallToken(), (int)pt, 1);
+//                                     if (sendUserInputMode == SendUserInputAsTone)
+//                                             sendUserInputMode = SendUserInputAsInlineRFC2833;
+                               }
+                               if (h323debug) {
+                                       cout << "\t-- Outbound Cisco RTP DTMF on payload " << pt << endl;
+                               }
+                       }
+                       break;
+               case H323Capability::e_UserInput:
+                       if (!strcmp((const char *)remoteCapabilities[i].GetFormatName(), H323_UserInputCapability::SubTypeNames[H323_UserInputCapability::SignalToneRFC2833])) {
+                               pt = remoteCapabilities[i].GetPayloadType();
+                               if ((dtmfMode & H323_DTMF_RFC2833) != 0) {
+                                       on_set_rfc2833_payload(GetCallReference(), (const char *)GetCallToken(), (int)pt, 0);
+//                                     if (sendUserInputMode == SendUserInputAsTone)
+//                                             sendUserInputMode = SendUserInputAsInlineRFC2833;
+                               }
+                               if (h323debug) {
+                                       cout << "\t-- Outbound RFC2833 on payload " << pt << endl;
+                               }
+                       }
+                       break;
 #if 0
                case H323Capability::e_Video:
                        for (int x = 0; vcodecs[x].asterisk_codec > 0; ++x) {
 #if 0
                case H323Capability::e_Video:
                        for (int x = 0; vcodecs[x].asterisk_codec > 0; ++x) {
@@ -1407,7 +1452,7 @@ BOOL MyH323Connection::OnStartLogicalChannel(H323Channel & channel)
        return connectionState != ShuttingDownConnection;
 }
 
        return connectionState != ShuttingDownConnection;
 }
 
-void MyH323Connection::SetCapabilities(int cap, int dtmf_mode, void *_prefs, int pref_codec)
+void MyH323Connection::SetCapabilities(int caps, int dtmf_mode, void *_prefs, int pref_codec)
 {
        PINDEX lastcap = -1; /* last common capability index */
        int alreadysent = 0;
 {
        PINDEX lastcap = -1; /* last common capability index */
        int alreadysent = 0;
@@ -1418,11 +1463,12 @@ void MyH323Connection::SetCapabilities(int cap, int dtmf_mode, void *_prefs, int
        struct ast_format_list format;
        int frames_per_packet;
        int max_frames_per_packet;
        struct ast_format_list format;
        int frames_per_packet;
        int max_frames_per_packet;
+       H323Capability *cap;
 
        localCapabilities.RemoveAll();
 
        if (h323debug) {
 
        localCapabilities.RemoveAll();
 
        if (h323debug) {
-               cout << "Setting capabilities to " << ast_getformatname_multiple(caps_str, sizeof(caps_str), cap) << endl;
+               cout << "Setting capabilities to " << ast_getformatname_multiple(caps_str, sizeof(caps_str), caps) << endl;
                ast_codec_pref_string(prefs, caps_str, sizeof(caps_str));
                cout << "Capabilities in preference order is " << caps_str << endl;
        }
                ast_codec_pref_string(prefs, caps_str, sizeof(caps_str));
                cout << "Capabilities in preference order is " << caps_str << endl;
        }
@@ -1440,7 +1486,7 @@ void MyH323Connection::SetCapabilities(int cap, int dtmf_mode, void *_prefs, int
                                y <<= 1;
                        codec = y;
                }
                                y <<= 1;
                        codec = y;
                }
-               if (!(cap & codec) || (alreadysent & codec) || !(codec & AST_FORMAT_AUDIO_MASK))
+               if (!(caps & codec) || (alreadysent & codec) || !(codec & AST_FORMAT_AUDIO_MASK))
                        continue;
                alreadysent |= codec;
                format = ast_codec_pref_getsize(prefs, codec);
                        continue;
                alreadysent |= codec;
                format = ast_codec_pref_getsize(prefs, codec);
@@ -1509,23 +1555,64 @@ void MyH323Connection::SetCapabilities(int cap, int dtmf_mode, void *_prefs, int
                }
        }
 
                }
        }
 
-       lastcap++;
-       lastcap = localCapabilities.SetCapability(0, lastcap, new H323_UserInputCapability(H323_UserInputCapability::HookFlashH245));
+       cap = new H323_UserInputCapability(H323_UserInputCapability::HookFlashH245);
+       if (cap && cap->IsUsable(*this)) {
+               lastcap++;
+               lastcap = localCapabilities.SetCapability(0, lastcap, cap);
+       } else if (cap)
+               delete cap;                             /* Capability is not usable */
 
 
-       lastcap++;
        dtmfMode = dtmf_mode;
        dtmfMode = dtmf_mode;
-       if ((dtmfMode & H323_DTMF_INBAND)) {
-               localCapabilities.SetCapability(0, lastcap, new H323_UserInputCapability(H323_UserInputCapability::BasicString));
-               sendUserInputMode = SendUserInputAsString;
-       } else {
-               lastcap = localCapabilities.SetCapability(0, lastcap, new H323_UserInputCapability(H323_UserInputCapability::SignalToneRFC2833));
-               /* Cisco sends DTMF only through h245-alphanumeric or h245-signal, no support for RFC2833 */
-               lastcap = localCapabilities.SetCapability(0, lastcap, new H323_UserInputCapability(H323_UserInputCapability::SignalToneH245));
-               sendUserInputMode = SendUserInputAsTone;        /* RFC2833 transmission handled at Asterisk level */
+       if (h323debug) {
+               cout << "DTMF mode is " << (int)dtmfMode << endl;
+       }
+       if (dtmfMode) {
+               lastcap++;
+               if (dtmfMode == H323_DTMF_INBAND) {
+                       cap = new H323_UserInputCapability(H323_UserInputCapability::BasicString);
+                       if (cap && cap->IsUsable(*this)) {
+                               lastcap = localCapabilities.SetCapability(0, lastcap, cap);
+                       } else if (cap)
+                               delete cap;             /* Capability is not usable */
+                       sendUserInputMode = SendUserInputAsString;
+               } else {
+                       if ((dtmfMode & H323_DTMF_RFC2833) != 0) {
+                               cap = new H323_UserInputCapability(H323_UserInputCapability::SignalToneRFC2833);
+                               if (cap && cap->IsUsable(*this))
+                                       lastcap = localCapabilities.SetCapability(0, lastcap, cap);
+                               else {
+                                       dtmfMode |= H323_DTMF_SIGNAL;
+                                       if (cap)
+                                               delete cap;     /* Capability is not usable */
+                               }
+                       }
+                       if ((dtmfMode & H323_DTMF_CISCO) != 0) {
+                               /* Try Cisco's RTP DTMF relay too, but prefer RFC2833 or h245-signal */
+                               cap = new AST_CiscoDtmfCapability();
+                               if (cap && cap->IsUsable(*this)) {
+                                       lastcap = localCapabilities.SetCapability(0, lastcap, cap);
+                                       /* We cannot send Cisco RTP DTMFs, use h245-signal instead */
+                                       dtmfMode |= H323_DTMF_SIGNAL;
+                               } else {
+                                       dtmfMode |= H323_DTMF_SIGNAL;
+                                       if (cap)
+                                               delete cap;     /* Capability is not usable */
+                               }
+                       }
+                       if ((dtmfMode & H323_DTMF_SIGNAL) != 0) {
+                               /* Cisco usually sends DTMF correctly only through h245-alphanumeric or h245-signal */
+                               cap = new H323_UserInputCapability(H323_UserInputCapability::SignalToneH245);
+                               if (cap && cap->IsUsable(*this))
+                                       lastcap = localCapabilities.SetCapability(0, lastcap, cap);
+                               else if (cap)
+                                       delete cap;     /* Capability is not usable */
+                       }
+                       sendUserInputMode = SendUserInputAsTone;        /* RFC2833 transmission handled at Asterisk level */
+               }
        }
 
        if (h323debug) {
        }
 
        if (h323debug) {
-               cout << "Allowed Codecs:\n\t" << setprecision(2) << localCapabilities << endl;
+               cout << "Allowed Codecs for " << GetCallToken() << " (" << GetSignallingChannel()->GetLocalAddress() << "):\n\t" << setprecision(2) << localCapabilities << endl;
        }
 }
 
        }
 }
 
@@ -1571,6 +1658,48 @@ BOOL MyH323Connection::StartControlChannel(const H225_TransportAddress & h245Add
        return TRUE;
 }
 
        return TRUE;
 }
 
+#ifdef H323_H450
+void MyH323Connection::OnReceivedLocalCallHold(int linkedId)
+{
+       if (on_hold)
+               on_hold(GetCallReference(), (const char *)GetCallToken(), 1);
+}
+
+void MyH323Connection::OnReceivedLocalCallRetrieve(int linkedId)
+{
+       if (on_hold)
+               on_hold(GetCallReference(), (const char *)GetCallToken(), 0);
+}
+#endif
+
+void MyH323Connection::MyHoldCall(BOOL isHold)
+{
+       if (((holdHandling & H323_HOLD_NOTIFY) != 0) || ((holdHandling & H323_HOLD_Q931ONLY) != 0)) {
+               PBYTEArray x ((const BYTE *)(isHold ? "\xF9" : "\xFA"), 1);
+               H323SignalPDU signal;
+               signal.BuildNotify(*this);
+               signal.GetQ931().SetIE((Q931::InformationElementCodes)39 /* Q931::NotifyIE */, x);
+               if (h323debug)
+                       cout << "Sending " << (isHold ? "HOLD" : "RETRIEVE") << " notification: " << signal << endl;
+               if ((holdHandling & H323_HOLD_Q931ONLY) != 0) {
+                       PBYTEArray rawData;
+                       signal.GetQ931().RemoveIE(Q931::UserUserIE);
+                       signal.GetQ931().Encode(rawData);
+                       signallingChannel->WritePDU(rawData);
+               } else
+                       WriteSignalPDU(signal);
+       }
+#ifdef H323_H450
+       if ((holdHandling & H323_HOLD_H450) != 0) {
+               if (isHold)
+                       h4504handler->HoldCall(TRUE);
+               else if (IsLocalHold())
+                       h4504handler->RetrieveCall();
+       }
+#endif
+}
+
+
 /* MyH323_ExternalRTPChannel */
 MyH323_ExternalRTPChannel::MyH323_ExternalRTPChannel(MyH323Connection & connection,
                                                        const H323Capability & capability,
 /* MyH323_ExternalRTPChannel */
 MyH323_ExternalRTPChannel::MyH323_ExternalRTPChannel(MyH323Connection & connection,
                                                        const H323Capability & capability,
@@ -1652,6 +1781,32 @@ BOOL MyH323_ExternalRTPChannel::OnReceivedAckPDU(const H245_H2250LogicalChannelA
        return FALSE;
 }
 
        return FALSE;
 }
 
+#ifdef H323_H450
+MyH4504Handler::MyH4504Handler(MyH323Connection &_conn, H450xDispatcher &_disp)
+       :H4504Handler(_conn, _disp)
+{
+       conn = &_conn;
+}
+
+void MyH4504Handler::OnReceivedLocalCallHold(int linkedId)
+{
+       if (conn) {
+               conn->Lock();
+               conn->OnReceivedLocalCallHold(linkedId);
+               conn->Unlock();
+       }
+}
+
+void MyH4504Handler::OnReceivedLocalCallRetrieve(int linkedId)
+{
+       if (conn) {
+               conn->Lock();
+               conn->OnReceivedLocalCallRetrieve(linkedId);
+               conn->Unlock();
+       }
+}
+#endif
+
 
 /** IMPLEMENTATION OF C FUNCTIONS */
 
 
 /** IMPLEMENTATION OF C FUNCTIONS */
 
@@ -1710,7 +1865,8 @@ void h323_callback_register(setup_incoming_cb             ifunc,
                                                        rfc2833_cb                              dtmffunc,
                                                        hangup_cb                               hangupfunc,
                                                        setcapabilities_cb              capabilityfunc,
                                                        rfc2833_cb                              dtmffunc,
                                                        hangup_cb                               hangupfunc,
                                                        setcapabilities_cb              capabilityfunc,
-                                                       setpeercapabilities_cb  peercapabilityfunc)
+                                                       setpeercapabilities_cb  peercapabilityfunc,
+                                                       onhold_cb                               holdfunc)
 {
        on_incoming_call = ifunc;
        on_outgoing_call = sfunc;
 {
        on_incoming_call = ifunc;
        on_outgoing_call = sfunc;
@@ -1726,6 +1882,7 @@ void h323_callback_register(setup_incoming_cb             ifunc,
        on_hangup = hangupfunc;
        on_setcapabilities = capabilityfunc;
        on_setpeercapabilities = peercapabilityfunc;
        on_hangup = hangupfunc;
        on_setcapabilities = capabilityfunc;
        on_setpeercapabilities = peercapabilityfunc;
+       on_hold = holdfunc;
 }
 
 /**
 }
 
 /**
@@ -2027,6 +2184,18 @@ void h323_native_bridge(const char *token, const char *them, char *capability)
 
 }
 
 
 }
 
+int h323_hold_call(const char *token, int is_hold)
+{
+       MyH323Connection *conn = (MyH323Connection *)endPoint->FindConnectionWithLock(token);
+       if (!conn) {
+               cout << "ERROR: No connection found, this is bad" << endl;
+               return -1;
+       }
+       conn->MyHoldCall((BOOL)is_hold);
+       conn->Unlock();
+       return 0;
+}
+
 #undef cout
 #undef endl
 void h323_end_process(void)
 #undef cout
 #undef endl
 void h323_end_process(void)