backup
[lcr.git] / callpbx.cpp
index bb644d0..418654d 100644 (file)
@@ -255,7 +255,8 @@ CallPBX::CallPBX(class Endpoint *epoint) : Call(epoint)
        c_caller_id[0] = '\0';
        c_dialed[0] = '\0';
        c_todial[0] = '\0';
-       c_mixer = 0;
+       c_pid = getpid();
+       c_updatebridge = 0;
        c_partyline = 0;
 
        /* initialize a relation only to the calling interface */
@@ -298,23 +299,27 @@ CallPBX::~CallPBX()
 }
 
 
-/* mixer sets the mixer of hisax bchannels
- * the mixer() will set the mixer for the hisax ports which is done
- * at kernel space. 
+/* bridge sets the audio flow of all bchannels assiociated to 'this' call
+ * also it changes and notifies active/hold/conference states
  */
-void CallPBX::mixer(void)
+void CallPBX::bridge(void)
 {
        struct call_relation *relation;
        struct message *message;
-       int numconnect, relations;
+       int numconnect = 0, relations = 0;
        class Endpoint *epoint;
        struct port_list *portlist;
        class Port *port;
-       int nodata = 1;
+       int allmISDN = 0; // set until a non-mISDN relation is found
+fix:
 
        relation = c_relation;
        while(relation)
        {
+               /* count all relations */
+               relations++;
+
+               /* check for relation's objects */
                epoint = find_epoint_id(relation->epoint_id);
                if (!epoint)
                {
@@ -325,7 +330,7 @@ void CallPBX::mixer(void)
                portlist = epoint->ep_portlist;
                if (!portlist)
                {
-                       PDEBUG((DEBUG_CALL|DEBUG_PORT), "ignoring relation without interfaces.\n");
+                       PDEBUG(DEBUG_CALL, "CALL%d ignoring relation without port object.\n", c_serial);
 //#warning testing: keep on hold until single audio stream available
                        relation->channel_state = CHANNEL_STATE_HOLD;
                        relation = relation->next;
@@ -333,7 +338,7 @@ void CallPBX::mixer(void)
                }
                if (portlist->next)
                {
-                       PDEBUG((DEBUG_CALL|DEBUG_PORT), "ignoring relation with ep%d due to port_list.\n", epoint->ep_serial);
+                       PDEBUG(DEBUG_CALL, "CALL%d ignoring relation with ep%d due to port_list.\n", c_serial, epoint->ep_serial);
 //#warning testing: keep on hold until single audio stream available
                        relation->channel_state = CHANNEL_STATE_HOLD;
                        relation = relation->next;
@@ -342,84 +347,84 @@ void CallPBX::mixer(void)
                port = find_port_id(portlist->port_id);
                if (!port)
                {
-                       PDEBUG((DEBUG_CALL|DEBUG_PORT), "software error: relation without existing port.\n");
+                       PDEBUG(DEBUG_CALL, "CALL%d ignoring relation without existing port object.\n", c_serial);
                        relation = relation->next;
                        continue;
                }
-               if (port->p_record)
-               {
-                       PDEBUG(DEBUG_CALL|DEBUG_PORT, "mixer(): relation ep%d does recording, so we must get data from all members.\n", epoint->ep_serial);
-                       if (nodata)
-                       {
-                               PDEBUG(DEBUG_CALL|DEBUG_PORT, "mixer(): at least one endpoint wants data.\n");
-                               nodata = 0;
-                       }
-               }
                if ((port->p_type&PORT_CLASS_MASK)!=PORT_CLASS_mISDN)
                {
-                       PDEBUG((DEBUG_CALL|DEBUG_PORT), "ignoring relation ep%d because it is not mISDN.\n", epoint->ep_serial);
-                       if (nodata)
+                       PDEBUG(DEBUG_CALL, "CALL%d ignoring relation ep%d because it's port is not mISDN.\n", c_serial, epoint->ep_serial);
+                       if (allmISDN)
                        {
-                               PDEBUG((DEBUG_CALL|DEBUG_PORT), "not all endpoints are mISDN.\n");
-                               nodata = 0;
+                               PDEBUG(DEBUG_CALL, "CALL%d not all endpoints are mISDN.\n", c_serial);
+                               allmISDN = 0;
                        }
                        relation = relation->next;
                        continue;
                }
-// remove unconnected parties from conference, also remove remotely disconnected parties so conference will not be disturbed.
+               
+               relation = relation->next;
+       }
+
+       PDEBUG(DEBUG_CALL, "CALL%d members=%d %s\n", c_serial, relations, (allmISDN)?"(all are mISDN-members)":"(not all are mISDN-members)");
+       /* we notify all relations about rxdata. */
+       relation = c_relation;
+       while(relation)
+       {
+               /* count connected relations */
+               if ((relation->channel_state == CHANNEL_STATE_CONNECT)
+                && (relation->rx_state != NOTIFY_STATE_SUSPEND)
+                && (relation->rx_state != NOTIFY_STATE_HOLD))
+                       numconnect ++;
+
+               /* remove unconnected parties from conference, also remove remotely disconnected parties so conference will not be disturbed. */
                if (relation->channel_state == CHANNEL_STATE_CONNECT
                 && relation->rx_state != NOTIFY_STATE_HOLD
-                && relation->rx_state != NOTIFY_STATE_SUSPEND)
+                && relation->rx_state != NOTIFY_STATE_SUSPEND
+                && relations>1 // no conf with one member
+                && allmISDN) // no conf if any member is not mISDN
                {
                        message = message_create(c_serial, relation->epoint_id, CALL_TO_EPOINT, MESSAGE_mISDNSIGNAL);
                        message->param.mISDNsignal.message = mISDNSIGNAL_CONF;
-                       message->param.mISDNsignal.conf = (c_serial<<1) + 1;
-                       PDEBUG(DEBUG_CALL, "%s +on+ id: 0x%08x\n", port->p_name, message->param.mISDNsignal.conf);
+                       message->param.mISDNsignal.conf = c_serial<<16 | c_pid;
+                       PDEBUG(DEBUG_CALL, "CALL%d EP%d +on+ id: 0x%08x\n", c_serial, relation->epoint_id, message->param.mISDNsignal.conf);
                        message_put(message);
                } else
                {
                        message = message_create(c_serial, relation->epoint_id, CALL_TO_EPOINT, MESSAGE_mISDNSIGNAL);
                        message->param.mISDNsignal.message = mISDNSIGNAL_CONF;
                        message->param.mISDNsignal.conf = 0;
-                       PDEBUG(DEBUG_CALL, "%s +off+ id: 0x%08x\n", port->p_name, message->param.mISDNsignal.conf);
+                       PDEBUG(DEBUG_CALL, "CALL%d EP%d +off+ id: 0x%08x\n", c_serial, relation->epoint_id, message->param.mISDNsignal.conf);
                        message_put(message);
                }
-               relation = relation->next;
-       }
-       /* we notify all relations about rxdata. */
-       relation = c_relation;
-       while(relation)
-       {
+
+               /*
+                * request data from endpoint/port if:
+                * - two relations
+                * - any without mISDN
+                * in this case we bridge
+                */
                message = message_create(c_serial, relation->epoint_id, CALL_TO_EPOINT, MESSAGE_mISDNSIGNAL);
-               message->param.mISDNsignal.message = mISDNSIGNAL_NODATA;
-               message->param.mISDNsignal.nodata = nodata;
-               PDEBUG(DEBUG_CALL, "call %d sets alldata on port %s to %d\n", c_serial, port->p_name, nodata);
+               message->param.mISDNsignal.message = mISDNSIGNAL_CALLDATA;
+               message->param.mISDNsignal.calldata = (relations==2 && !allmISDN);
+               PDEBUG(DEBUG_CALL, "CALL%d EP%d set calldata=%d\n", c_serial, relation->epoint_id, message->param.mISDNsignal.calldata);
                message_put(message);
-               relation = relation->next;
-       }
 
-       /* count relations and states */
-       relation = c_relation;
-       numconnect = 0;
-       relations = 0;
-       while(relation) /* count audio-connected and active relations */
-       {
-               relations ++;
-               if ((relation->channel_state == CHANNEL_STATE_CONNECT)
-                && (relation->rx_state != NOTIFY_STATE_SUSPEND)
-                && (relation->rx_state != NOTIFY_STATE_HOLD))
-                       numconnect ++;
                relation = relation->next;
        }
 
-       if (relations==2 && !c_partyline) /* two people just exchange their states */
+       /* two people just exchange their states */
+       if (relations==2 && !c_partyline)
        {
+               PDEBUG(DEBUG_CALL, "CALL%d 2 relations / no partyline\n", c_serial);
                relation = c_relation;
                relation->tx_state = notify_state_change(c_serial, relation->epoint_id, relation->tx_state, relation->next->rx_state);
                relation->next->tx_state = notify_state_change(c_serial, relation->next->epoint_id, relation->next->tx_state, relation->rx_state);
        } else
-       if ((relations==1 || numconnect==1) /*&& !c_partyline*/) /* one member in a call, so we put her on hold */
+       /* one member in a call, so we put her on hold */
+       if (relations==1 || numconnect==1)
        {
+               PDEBUG(DEBUG_CALL, "CALL%d 1 member or only 1 connected, put on hold\n");
                relation = c_relation;
                while(relation)
                {
@@ -432,6 +437,7 @@ void CallPBX::mixer(void)
        } else
        /* if conference/partyline or (more than two members and more than one is connected), so we set conference state */ 
        {
+               PDEBUG(DEBUG_CALL, "CALL%d %d members, %d connected, signal conference\n", relations, numconnect);
                relation = c_relation;
                while(relation)
                {
@@ -444,52 +450,46 @@ void CallPBX::mixer(void)
        }
 }
 
-
-/* send audio data to endpoints which do not come from an endpoint connected
- * to an isdn port and do not go to an endpoint which is connected to an
- * isdn port. in this case the mixing cannot be done with kernel space
+/*
+ * bridging is only possible with two connected endpoints
  */
-void CallPBX::call_mixer(unsigned long epoint_from, struct call_relation *relation_from, union parameter *param)
+void CallPBX::bridge_data(unsigned long epoint_from, struct call_relation *relation_from, union parameter *param)
 {
        struct call_relation *relation_to;
        struct message *message;
 
+       /* if we are alone */
+       if (!c_relation->next)
+               return;
+
+       /* if we are more than two */
+       if (c_relation->next->next)
+               return;
+
        /* skip if source endpoint has NOT audio mode CONNECT */
        if (relation_from->channel_state != CHANNEL_STATE_CONNECT)
-       {
                return;
-       }
 
-       /* loop all endpoints and skip the endpoint where the audio is from
-        * so we do not get a loop (echo)
-        */
+       /* get destination relation */
        relation_to = c_relation;
-       while(relation_to)
+       if (relation_to == relation_from)
        {
-               /* skip source endpoint */
-               if (relation_to->epoint_id == epoint_from)
-               {
-                       relation_to = relation_to->next;
-                       continue;
-               }
+               /* oops, we are the first, so destination is: */
+               relation_to = relation_to->next;
+       }
 
-               /* skip if destination endpoint has audio mode HOLD */
-               if (relation_to->channel_state != CHANNEL_STATE_CONNECT)
-               {
-                       relation_to = relation_to->next;
-                       continue;
-               }
+       /* skip if destination endpoint has NOT audio mode CONNECT */
+       if (relation_to->channel_state != CHANNEL_STATE_CONNECT)
+               return;
 
-               /* now we may send our data to the endpoint where it
-                * will be delivered to the port
-                */
+       /* now we may send our data to the endpoint where it
+        * will be delivered to the port
+        */
 //PDEBUG(DEBUG_CALL, "mixing from %d to %d\n", epoint_from, relation_to->epoint_id);
-               message = message_create(c_serial, relation_to->epoint_id, CALL_TO_EPOINT, MESSAGE_DATA);
-               memcpy(&message->param, param, sizeof(union parameter));
-               message_put(message);
-
-               relation_to = relation_to->next;
-       }
+printf("from %d, to %d\n", relation_from->epoint_id, relation_to->epoint_id);
+       message = message_create(c_serial, relation_to->epoint_id, CALL_TO_EPOINT, MESSAGE_DATA);
+       memcpy(&message->param, param, sizeof(union parameter));
+       message_put(message);
 }
 
 
@@ -527,11 +527,11 @@ void CallPBX::release(unsigned long epoint_id, int hold, int location, int cause
                return;
        }
 
-       /* remove from mixer */
+       /* remove from bridge */
        if (relation->channel_state != CHANNEL_STATE_HOLD)
        {
                relation->channel_state = CHANNEL_STATE_HOLD;
-               c_mixer = 1; /* update mixer flag */
+               c_updatebridge = 1; /* update bridge flag */
        }
 
        /* detach given interface */
@@ -604,6 +604,9 @@ int callpbx_countrelations(unsigned long call_id)
        if (!call)
                return(0);
 
+       if (call->c_type != CALL_TYPE_ASTERISK)
+               return(2);
+
        if (call->c_type != CALL_TYPE_PBX)
                return(0);
        callpbx = (class CallPBX *)call;
@@ -688,8 +691,7 @@ void CallPBX::message_epoint(unsigned long epoint_id, int message_type, union pa
        int new_state;
        struct message *message;
 //     int size, writesize, oldpointer;
-       class Endpoint *epoint;
-       char *number;
+       char *number, *numbers;
 
        if (!epoint_id)
        {
@@ -738,7 +740,7 @@ void CallPBX::message_epoint(unsigned long epoint_id, int message_type, union pa
                if (relation->channel_state != param->channel)
                {
                        relation->channel_state = param->channel;
-                       c_mixer = 1; /* update mixer flag */
+                       c_updatebridge = 1; /* update bridge flag */
                        if (options.deb & DEBUG_CALL)
                                callpbx_debug(this, "Call::message_epoint{after setting new channel state}");
                }
@@ -758,7 +760,7 @@ void CallPBX::message_epoint(unsigned long epoint_id, int message_type, union pa
                        if (new_state != relation->rx_state)
                        {
                                relation->rx_state = new_state;
-                               c_mixer = 1;
+                               c_updatebridge = 1;
                                if (options.deb & DEBUG_CALL)
                                        callpbx_debug(this, "Call::message_epoint{after setting new rx state}");
                        }
@@ -782,8 +784,8 @@ void CallPBX::message_epoint(unsigned long epoint_id, int message_type, union pa
 
                /* audio data */
                case MESSAGE_DATA:
-               /* now send audio data to all endpoints connected */
-               call_mixer(epoint_id, relation, param);
+               /* now send audio data to the other endpoint */
+               bridge_data(epoint_id, relation, param);
                return;
        }
 
@@ -795,7 +797,7 @@ void CallPBX::message_epoint(unsigned long epoint_id, int message_type, union pa
                message = message_create(c_serial, epoint_id, CALL_TO_EPOINT, MESSAGE_CONNECT);
                message->param.setup.partyline = c_partyline;
                message_put(message);
-               c_mixer = 1; /* update mixer flag */
+               c_updatebridge = 1; /* update bridge flag */
        }
        if (c_partyline)
        {
@@ -807,7 +809,7 @@ void CallPBX::message_epoint(unsigned long epoint_id, int message_type, union pa
                        message->param.disconnectinfo.cause = CAUSE_NORMAL;
                        message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
                        message_put(message);
-//                     c_mixer = 1; /* update mixer flag */
+//                     c_updatebridge = 1; /* update bridge flag */
                        return;
                }
        }
@@ -840,9 +842,10 @@ void CallPBX::message_epoint(unsigned long epoint_id, int message_type, union pa
                switch(message_type)
                {
                        case MESSAGE_SETUP:
-                       if (param->dialinginfo.itype == INFO_ITYPE_ISDN_EXTENSION)
+                       if (param->setup.dialinginfo.itype == INFO_ITYPE_ISDN_EXTENSION)
                        {
-                               while(number = strsep(&param->dialinginfo.number, ','))
+                               numbers = param->setup.dialinginfo.id;
+                               while((number = strsep(&numbers, ",")))
                                {
                                        if (out_setup(epoint_id, message_type, param, number))
                                                return; // call destroyed
@@ -880,11 +883,11 @@ int CallPBX::handler(void)
 //     int i, j;
 //     char *p;
 
-       /* the mixer must be updated */
-       if (c_mixer)
+       /* the bridge must be updated */
+       if (c_updatebridge)
        {
-               mixer();
-               c_mixer = 0;
+               bridge();
+               c_updatebridge = 0;
                return(1);
        }
 
@@ -945,8 +948,8 @@ int CallPBX::out_setup(unsigned long epoint_id, int message_type, union paramete
                relation = c_relation;
                while(relation)
                {
-                       message = message_create(c_serial, releation->epoint_id, CALL_TO_EPOINT, MESSAGE_RELEASE);
-                       message->param.disconnectinfo.cause = (relation->epoint_id==epoint_id)CAUSE_RESSOURCEUNAVAIL?:CAUSE_NORMAL; 
+                       message = message_create(c_serial, relation->epoint_id, CALL_TO_EPOINT, MESSAGE_RELEASE);
+                       message->param.disconnectinfo.cause = (relation->epoint_id==epoint_id)?CAUSE_RESSOURCEUNAVAIL:CAUSE_NORMAL; 
                        message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
                        message_put(message);
                        relation = relation->next;
@@ -980,14 +983,9 @@ int CallPBX::out_setup(unsigned long epoint_id, int message_type, union paramete
        message = message_create(c_serial, relation->epoint_id, CALL_TO_EPOINT, message_type);
        memcpy(&message->param, param, sizeof(union parameter));
        if (newnumber)
-               SCPY(message->param.setup.dialinginfo.number, newnumber);
-       PDEBUG(DEBUG_CALL, "setup message sent to ep %d with number='%s'.\n", relation->epoint_id, message->param.setup.dialinginfo.number);
+               SCPY(message->param.setup.dialinginfo.id, newnumber);
+       PDEBUG(DEBUG_CALL, "setup message sent to ep %d with number='%s'.\n", relation->epoint_id, message->param.setup.dialinginfo.id);
        message_put(message);
        return(0);
 }
 
-todo: beim release von einem relation_type_setup muss der cause gesammelt werden, bis keine weitere setup-relation mehr existiert
-beim letzten den collected cause senden
-mixer kann ruhig loslegen, das aber dokumentieren
-mixer überdenken: wer sendet, welche töne verfügbar sind, u.s.w
-