+ case B_STATE_ACTIVATING:
+ case B_STATE_EXPORTING:
+ /* do nothing, because it is already activating */
+ break;
+
+ case B_STATE_DEACTIVATING:
+ case B_STATE_IMPORTING:
+ /* do nothing, because we must wait until we can reactivate */
+ break;
+
+ default:
+ /* problems that might ocurr:
+ * B_EVENT_USE is received when channel already in use.
+ * bchannel exported, but not freed by other port
+ */
+ PERROR("Illegal event %d at state %d, please correct.\n", event, state);
+ }
+ break;
+
+ case B_EVENT_EXPORTREQUEST:
+ /* special case where the bchannel is requested by remote */
+ if (!p_m_remote_ref) {
+ PERROR("export request without remote channel set, please correct.\n");
+ break;
+ }
+ switch(state) {
+ case B_STATE_IDLE:
+ /* in case, the bchannel is exported right after seize_bchannel */
+ /* export bchannel */
+ /* p_m_remote_id is set, when this event happens. */
+ message_bchannel_to_remote(p_m_remote_id, p_m_remote_ref, BCHANNEL_ASSIGN, portid, p_m_tx_gain, p_m_rx_gain, p_m_pipeline, p_m_crypt_key, p_m_crypt_key_len, p_m_crypt_key_type);
+ chan_trace_header(mISDNport, b_port, "MESSAGE_BCHANNEL (to remote application)", DIRECTION_NONE);
+ add_trace("type", NULL, "assign");
+ add_trace("channel", NULL, "%d.%d", portid>>8, portid&0xff);
+ end_trace();
+ state = B_STATE_EXPORTING;
+ mISDNport->b_remote_id[i] = p_m_remote_id;
+ mISDNport->b_remote_ref[i] = p_m_remote_ref;
+ break;
+
+ case B_STATE_ACTIVATING:
+ case B_STATE_EXPORTING:
+ /* do nothing, because it is already activating */
+ break;
+
+ case B_STATE_DEACTIVATING:
+ case B_STATE_IMPORTING:
+ /* do nothing, because we must wait until we can reactivate */
+ break;
+
+ case B_STATE_ACTIVE:
+ /* bchannel is active, so we deactivate */
+ _bchannel_activate(mISDNport, i, 0);
+ state = B_STATE_DEACTIVATING;
+ timer = now_d + B_TIMER_DEACTIVATING;
+ break;
+
+ default:
+ /* problems that might ocurr:
+ * ... when channel already in use.
+ * bchannel exported, but not freed by other port
+ */
+ PERROR("Illegal event %d at state %d, please correct.\n", event, state);
+ }
+ break;
+
+ case B_EVENT_IMPORTREQUEST:
+ /* special case where the bchannel is released by remote */
+ if (p_m_remote_ref) {
+ PERROR("import request with remote channel set, please correct.\n");
+ break;
+ }
+ switch(state) {
+ case B_STATE_IDLE:
+ case B_STATE_ACTIVE:
+ /* bchannel is not exported */
+ break;
+
+ case B_STATE_ACTIVATING:
+ case B_STATE_EXPORTING:
+ /* do nothing because we must wait until bchanenl is active before deactivating */
+ break;
+
+ case B_STATE_REMOTE:
+ /* bchannel is exported, so we re-import */
+ message_bchannel_to_remote(mISDNport->b_remote_id[i], 0, BCHANNEL_REMOVE, portid, 0,0,0,0,0,0);
+ chan_trace_header(mISDNport, b_port, "MESSAGE_BCHANNEL (to remote application)", DIRECTION_NONE);
+ add_trace("type", NULL, "remove");
+ add_trace("channel", NULL, "%d.%d", portid>>8, portid&0xff);
+ end_trace();
+ state = B_STATE_IMPORTING;
+ break;
+
+ case B_STATE_DEACTIVATING:
+ case B_STATE_IMPORTING:
+ /* we may have taken an already deactivating bchannel, but do not require it anymore, so we do nothing */
+ break;
+
+ default:
+ PERROR("Illegal event %d at state %d, please correct.\n", event, state);
+ }
+ break;
+
+ case B_EVENT_ACTIVATED:
+ timer = 0;
+ switch(state) {
+ case B_STATE_ACTIVATING:
+ if (b_port && !p_m_remote_id) {
+ /* bchannel is active and used by Port class, so we configure bchannel */
+ _bchannel_configure(mISDNport, i);
+ state = B_STATE_ACTIVE;
+ b_port->p_m_load = 0;
+ } else {
+ /* bchannel is active, but exported OR not used anymore (or has wrong stack config), so we deactivate */
+ _bchannel_activate(mISDNport, i, 0);
+ state = B_STATE_DEACTIVATING;
+ timer = now_d + B_TIMER_DEACTIVATING;
+ }
+ break;
+
+ default:
+ PERROR("Illegal event %d at state %d, please correct.\n", event, state);
+ }
+ break;
+
+ case B_EVENT_EXPORTED:
+ switch(state) {
+ case B_STATE_EXPORTING:
+ if (b_port && p_m_remote_ref && p_m_remote_ref==mISDNport->b_remote_ref[i]) {
+ /* remote export done */
+ state = B_STATE_REMOTE;
+ } else {
+ /* bchannel is now exported, but we need bchannel back
+ * OR bchannel is not used anymore
+ * OR bchannel has been exported to an obsolete ref,
+ * so reimport, to later export to new remote */
+ message_bchannel_to_remote(mISDNport->b_remote_id[i], 0, BCHANNEL_REMOVE, portid, 0,0,0,0,0,0);
+ chan_trace_header(mISDNport, b_port, "MESSAGE_BCHANNEL (to remote application)", DIRECTION_NONE);
+ add_trace("type", NULL, "remove");
+ add_trace("channel", NULL, "%d.%d", portid>>8, portid&0xff);
+ end_trace();
+ state = B_STATE_IMPORTING;
+ }
+ break;
+
+ default:
+ PERROR("Illegal event %d at state %d, please correct.\n", event, state);
+ }
+ break;
+
+ case B_EVENT_DROP:
+ if (!b_port)
+ FATAL("bchannel must be linked to a Port class\n");
+ switch(state) {
+ case B_STATE_IDLE:
+ /* bchannel is idle due to an error, so we do nothing */
+ break;
+
+ case B_STATE_ACTIVATING:
+ case B_STATE_EXPORTING:
+ /* do nothing because we must wait until bchanenl is active before deactivating */
+ break;
+
+ case B_STATE_ACTIVE:
+ /* bchannel is active, so we deactivate */
+ _bchannel_activate(mISDNport, i, 0);
+ state = B_STATE_DEACTIVATING;
+ timer = now_d + B_TIMER_DEACTIVATING;
+ break;
+
+ case B_STATE_REMOTE:
+ /* bchannel is exported, so we re-import */
+ message_bchannel_to_remote(mISDNport->b_remote_id[i], 0, BCHANNEL_REMOVE, portid, 0,0,0,0,0,0);
+ chan_trace_header(mISDNport, b_port, "MESSAGE_BCHANNEL (to remote application)", DIRECTION_NONE);
+ add_trace("type", NULL, "remove");
+ add_trace("channel", NULL, "%d.%d", portid>>8, portid&0xff);
+ end_trace();
+ state = B_STATE_IMPORTING;
+ break;
+
+ case B_STATE_DEACTIVATING:
+ case B_STATE_IMPORTING:
+ /* we may have taken an already deactivating bchannel, but do not require it anymore, so we do nothing */
+ break;
+
+ default:
+ PERROR("Illegal event %d at state %d, please correct.\n", event, state);
+ }
+ break;
+
+ case B_EVENT_DEACTIVATED:
+ timer = 0;
+ switch(state) {
+ case B_STATE_IDLE:
+ /* ignore due to deactivation confirm after unloading */
+ break;
+
+ case B_STATE_DEACTIVATING:
+ _bchannel_destroy(mISDNport, i);
+ state = B_STATE_IDLE;
+ if (b_port) {
+ /* bchannel is now deactivate, but is requied by Port class, so we reactivate / export */
+ if (p_m_remote_ref) {
+ message_bchannel_to_remote(p_m_remote_id, p_m_remote_ref, BCHANNEL_ASSIGN, portid, p_m_tx_gain, p_m_rx_gain, p_m_pipeline, p_m_crypt_key, p_m_crypt_key_len, p_m_crypt_key_type);
+ chan_trace_header(mISDNport, b_port, "MESSAGE_BCHANNEL (to remote application)", DIRECTION_NONE);
+ add_trace("type", NULL, "assign");
+ add_trace("channel", NULL, "%d.%d", portid>>8, portid&0xff);
+ end_trace();
+ state = B_STATE_EXPORTING;
+ mISDNport->b_remote_id[i] = p_m_remote_id;
+ mISDNport->b_remote_ref[i] = p_m_remote_ref;
+ } else {
+ if (_bchannel_create(mISDNport, i)) {
+ _bchannel_activate(mISDNport, i, 1);
+ state = B_STATE_ACTIVATING;
+ timer = now_d + B_TIMER_ACTIVATING;
+ }
+ }
+ }
+ break;
+
+ default:
+ PERROR("Illegal event %d at state %d, please correct.\n", event, state);
+ }
+ break;
+
+ case B_EVENT_IMPORTED:
+ switch(state) {
+ case B_STATE_IMPORTING:
+ state = B_STATE_IDLE;
+ mISDNport->b_remote_id[i] = 0;
+ mISDNport->b_remote_ref[i] = 0;
+ if (b_port) {
+ /* bchannel is now imported, but is requied by Port class, so we reactivate / export */
+ if (p_m_remote_ref) {
+ message_bchannel_to_remote(p_m_remote_id, p_m_remote_ref, BCHANNEL_ASSIGN, portid, p_m_tx_gain, p_m_rx_gain, p_m_pipeline, p_m_crypt_key, p_m_crypt_key_len, p_m_crypt_key_type);
+ chan_trace_header(mISDNport, b_port, "MESSAGE_BCHANNEL (to remote application)", DIRECTION_NONE);
+ add_trace("type", NULL, "assign");
+ add_trace("channel", NULL, "%d.%d", portid>>8, portid&0xff);
+ end_trace();
+ state = B_STATE_EXPORTING;
+ mISDNport->b_remote_id[i] = p_m_remote_id;
+ mISDNport->b_remote_ref[i] = p_m_remote_ref;
+ } else {
+ if (_bchannel_create(mISDNport, i)) {
+ _bchannel_activate(mISDNport, i, 1);
+ state = B_STATE_ACTIVATING;
+ timer = now_d + B_TIMER_ACTIVATING;
+ }
+ }
+ }
+ break;
+
+ default:
+ /* ignore, because not assigned */
+ ;
+ }
+ break;
+
+ case B_EVENT_TIMEOUT:
+ timer = 0;
+ switch(state) {
+ case B_STATE_IDLE:
+ /* ignore due to deactivation confirm after unloading */
+ break;
+
+ case B_STATE_ACTIVATING:
+ _bchannel_activate(mISDNport, i, 1);
+ timer = now_d + B_TIMER_ACTIVATING;
+ break;
+
+ case B_STATE_DEACTIVATING:
+ _bchannel_activate(mISDNport, i, 0);
+ timer = now_d + B_TIMER_DEACTIVATING;
+ break;
+
+ default:
+ PERROR("Illegal event %d at state %d, please correct.\n", event, state);
+ }
+ break;
+
+ default:
+ PERROR("Illegal event %d, please correct.\n", event);
+ }
+
+ mISDNport->b_state[i] = state;
+ mISDNport->b_timer[i] = timer;
+}
+
+
+
+
+/*
+ * check for available channel and reserve+set it.
+ * give channel number or SEL_CHANNEL_ANY or SEL_CHANNEL_NO
+ * give exclusiv flag
+ * returns -(cause value) or x = channel x or 0 = no channel
+ * NOTE: no activation is done here
+ */
+int PmISDN::seize_bchannel(int channel, int exclusive)
+{
+ int i;
+
+ /* the channel is what we have */
+ if (p_m_b_channel == channel)
+ return(channel);
+
+ /* if channel already in use, release it */
+ if (p_m_b_channel)
+ drop_bchannel();
+
+ /* if CHANNEL_NO */
+ if (channel==CHANNEL_NO || channel==0)
+ return(0);
+
+ /* is channel in range ? */
+ if (channel==16
+ || (channel>p_m_mISDNport->b_num && channel<16)
+ || ((channel-1)>p_m_mISDNport->b_num && channel>16)) /* channel-1 because channel 16 is not counted */
+ return(-6); /* channel unacceptable */
+
+ /* request exclusive channel */
+ if (exclusive && channel>0) {
+ i = channel-1-(channel>16);
+ if (p_m_mISDNport->b_port[i])
+ return(-44); /* requested channel not available */
+ goto seize;
+ }
+
+ /* ask for channel */
+ if (channel>0) {
+ i = channel-1-(channel>16);
+ if (p_m_mISDNport->b_port[i] == NULL)
+ goto seize;
+ }
+
+ /* search for channel */
+ i = 0;
+ while(i < p_m_mISDNport->b_num) {
+ if (!p_m_mISDNport->b_port[i]) {
+ channel = i+1+(i>=15);
+ goto seize;
+ }
+ i++;
+ }
+ return(-34); /* no free channel */
+
+seize:
+ PDEBUG(DEBUG_BCHANNEL, "PmISDN(%s) seizing bchannel %d (index %d)\n", p_name, channel, i);
+
+ /* link Port, set parameters */
+ p_m_mISDNport->b_port[i] = this;
+ p_m_b_index = i;
+ p_m_b_channel = channel;
+ p_m_b_exclusive = exclusive;
+ p_m_mISDNport->b_mode[i] = p_m_b_mode;
+
+ /* reserve channel */
+ if (!p_m_b_reserve) {
+ p_m_b_reserve = 1;
+ p_m_mISDNport->b_reserved++;
+ }
+
+ return(channel);
+}
+
+/*
+ * drop reserved channel and unset it.
+ * deactivation is also done
+ */
+void PmISDN::drop_bchannel(void)
+{
+ /* unreserve channel */
+ if (p_m_b_reserve)
+ p_m_mISDNport->b_reserved--;
+ p_m_b_reserve = 0;
+
+ /* if not in use */
+ if (p_m_b_index < 0)
+ return;
+ if (!p_m_b_channel)
+ return;
+
+ PDEBUG(DEBUG_BCHANNEL, "PmISDN(%s) dropping bchannel\n", p_name);
+
+ if (p_m_mISDNport->b_state[p_m_b_index] != B_STATE_IDLE)
+ bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_DROP);
+ p_m_mISDNport->b_port[p_m_b_index] = NULL;
+ p_m_mISDNport->b_mode[p_m_b_index] = 0;
+ p_m_b_index = -1;
+ p_m_b_channel = 0;
+ p_m_b_exclusive = 0;
+}
+
+/* process bchannel export/import message from join */
+void message_bchannel_from_remote(class JoinRemote *joinremote, int type, unsigned int handle)
+{
+ class Endpoint *epoint;
+ class Port *port;
+ class PmISDN *isdnport;
+ struct mISDNport *mISDNport;
+ int i, ii;
+
+ switch(type) {
+ case BCHANNEL_REQUEST:
+ /* find the port object for the join object ref */
+ if (!(epoint = find_epoint_id(joinremote->j_epoint_id))) {
+ PDEBUG(DEBUG_BCHANNEL, "join %d has no endpoint (anymore)\n", joinremote->j_serial);
+ return;
+ }
+ if (!epoint->ep_portlist) {
+ PDEBUG(DEBUG_BCHANNEL, "join %d has no port (anymore in portlist)\n", joinremote->j_serial);
+ return;
+ }
+ if (epoint->ep_portlist->next) {
+ PERROR("join %d has enpoint %d with more than one port. this shall not happen to remote joins.\n", joinremote->j_serial, epoint->ep_serial);
+ }
+ if (!(port = find_port_id(epoint->ep_portlist->port_id))) {
+ PDEBUG(DEBUG_BCHANNEL, "join %d has no port (anymore as object)\n", joinremote->j_serial);
+ return;
+ }
+ if ((port->p_type&PORT_CLASS_MASK) != PORT_CLASS_mISDN) {
+ PERROR("join %d has port %d not of mISDN type. This shall not happen.\n", joinremote->j_serial, port->p_serial);
+ }
+ isdnport = (class PmISDN *)port;
+
+ /* assign */
+ if (isdnport->p_m_remote_id) {
+ PERROR("join %d recevied bchannel request from remote, but channel is already assinged.\n", joinremote->j_serial);
+ break;
+ }
+ mISDNport = isdnport->p_m_mISDNport;
+ i = isdnport->p_m_b_index;
+ chan_trace_header(mISDNport, isdnport, "MESSAGE_BCHANNEL (from remote application)", DIRECTION_NONE);
+ add_trace("type", NULL, "export request");
+ end_trace();
+ isdnport->p_m_remote_ref = joinremote->j_serial;
+ isdnport->p_m_remote_id = joinremote->j_remote_id;
+ if (mISDNport && i>=0) {
+ bchannel_event(mISDNport, i, B_EVENT_EXPORTREQUEST);
+ }
+ break;
+
+ case BCHANNEL_RELEASE:
+ case BCHANNEL_ASSIGN_ACK:
+ case BCHANNEL_REMOVE_ACK:
+ /* find mISDNport for stack ID */
+ mISDNport = mISDNport_first;
+ while(mISDNport) {
+ i = 0;
+ ii = mISDNport->b_num;
+ while(i < ii) {
+ if ((unsigned int)(mISDNport->portnum<<8)+i+1+(i>=15) == handle)
+ break;
+ i++;
+ }
+ if (i != ii)
+ break;
+ mISDNport = mISDNport->next;
+ }
+ if (!mISDNport) {
+ PERROR("received assign/remove ack for bchannel's handle=%x, but handle does not exist in any mISDNport structure.\n", handle);
+ break;
+ }
+
+ if (type!=BCHANNEL_RELEASE) {
+ /* ack */
+ chan_trace_header(mISDNport, mISDNport->b_port[i], "MESSAGE_BCHANNEL (from remote application)", DIRECTION_NONE);
+ add_trace("type", NULL, (type==BCHANNEL_ASSIGN_ACK)?"assign_ack":"remove_ack");
+ end_trace();
+ bchannel_event(mISDNport, i, (type==BCHANNEL_ASSIGN_ACK)?B_EVENT_EXPORTED:B_EVENT_IMPORTED);
+ } else {
+ /* release */
+ isdnport = mISDNport->b_port[i];
+ chan_trace_header(mISDNport, isdnport, "MESSAGE_BCHANNEL (from remote application)", DIRECTION_NONE);
+ add_trace("type", NULL, "import request");
+ end_trace();
+ if (isdnport) {
+ isdnport->p_m_remote_ref = 0;
+ isdnport->p_m_remote_id = 0;
+ }
+ bchannel_event(mISDNport, i, B_EVENT_IMPORTREQUEST);
+ }
+ break;
+ default:
+ PERROR("received wrong bchannel message type %d from remote\n", type);
+ }
+}
+
+
+/*
+ * handler
+
+audio transmission procedure:
+-----------------------------
+
+* priority
+three sources of audio transmission:
+- crypto-data high priority
+- tones high priority (also high)
+- remote-data low priority
+
+* elapsed
+a variable that temporarily shows the number of samples elapsed since last transmission process.
+p_m_last_tv_* is used to store that last timestamp. this is used to calculate the time elapsed.
+
+* load
+a variable that is increased whenever data is transmitted.
+it is decreased while time elapses. it stores the number of samples that
+are currently loaded to dsp module.
+since clock in dsp module is the same clock for user space process, these
+times have no skew.
+
+* levels
+there are two levels:
+ISDN_LOAD will give the load that have to be kept in dsp.
+ISDN_MAXLOAD will give the maximum load before dropping.
+
+* procedure for low priority data
+see txfromup() for procedure
+in short: remote data is ignored during high priority tones
+
+* procedure for high priority data
+whenever load is below ISDN_LOAD, load is filled up to ISDN_LOAD
+if no more data is available, load becomes empty again.
+
+'load' variable:
+0 ISDN_LOAD ISDN_MAXLOAD
++--------------------+----------------------+
+| | |
++--------------------+----------------------+
+
+on empty load or on load below ISDN_LOAD, the load is inceased to ISDN_LOAD:
+0 ISDN_LOAD ISDN_MAXLOAD
++--------------------+----------------------+
+|TTTTTTTTTTTTTTTTTTTT| |
++--------------------+----------------------+
+
+on empty load, remote-audio causes the load with the remote audio to be increased to ISDN_LOAD.
+0 ISDN_LOAD ISDN_MAXLOAD
++--------------------+----------------------+
+|TTTTTTTTTTTTTTTTTTTTRRRRR |
++--------------------+----------------------+
+
+ */
+int PmISDN::handler(void)
+{
+ struct lcr_msg *message;
+ int elapsed = 0;
+ int ret;
+
+ if ((ret = Port::handler()))
+ return(ret);
+
+ /* get elapsed */
+ if (p_m_last_tv_sec) {
+ elapsed = 8000 * (now_tv.tv_sec - p_m_last_tv_sec)
+ + 8 * (now_tv.tv_usec/1000 - p_m_last_tv_msec);
+ } else {
+ /* set clock of first process ever in this instance */
+ p_m_last_tv_sec = now_tv.tv_sec;
+ p_m_last_tv_msec = now_tv.tv_usec/1000;
+ }
+ /* process only if we have a minimum of samples, to make packets not too small */
+ if (elapsed >= ISDN_TRANSMIT
+ && p_m_mISDNport->b_state[p_m_b_index] == B_STATE_ACTIVE) {
+ /* set clock of last process! */
+ p_m_last_tv_sec = now_tv.tv_sec;
+ p_m_last_tv_msec = now_tv.tv_usec/1000;
+
+ /* update load */
+ if (elapsed < p_m_load)
+ p_m_load -= elapsed;
+ else
+ p_m_load = 0;
+
+ /* to send data, tone must be on */
+ if ((p_tone_name[0] || p_m_crypt_msg_loops || p_m_inband_send_on) /* what tones? */
+ && (p_m_load < ISDN_LOAD) /* enough load? */
+ && (p_state==PORT_STATE_CONNECT || p_m_mISDNport->tones || p_m_inband_send_on)) { /* connected or inband-tones? */
+ int tosend = ISDN_LOAD - p_m_load, length;
+ unsigned char buf[MISDN_HEADER_LEN+tosend];
+ struct mISDNhead *frm = (struct mISDNhead *)buf;
+ unsigned char *p = buf+MISDN_HEADER_LEN;
+
+ /* copy inband signalling (e.g. used by ss5) */
+ if (p_m_inband_send_on && tosend) {
+ tosend -= inband_send(p, tosend);
+ }
+
+ /* copy crypto loops */
+ while (p_m_crypt_msg_loops && tosend) {
+ /* how much do we have to send */
+ length = p_m_crypt_msg_len - p_m_crypt_msg_current;
+
+ /* clip tosend */
+ if (length > tosend)
+ length = tosend;
+
+ /* copy message (part) to buffer */
+ memcpy(p, p_m_crypt_msg+p_m_crypt_msg_current, length);
+
+ /* new position */
+ p_m_crypt_msg_current += length;
+ if (p_m_crypt_msg_current == p_m_crypt_msg_len) {
+ /* next loop */
+ p_m_crypt_msg_current = 0;
+ p_m_crypt_msg_loops--;
+// puts("eine loop weniger");
+ }
+
+ /* new length */
+ tosend -= length;
+ }
+
+ /* copy tones */
+ if (p_tone_name[0] && tosend) {
+ tosend -= read_audio(p, tosend);
+ }
+
+ /* send data */
+ if (ISDN_LOAD - p_m_load - tosend > 0) {
+ frm->prim = PH_DATA_REQ;
+ frm->id = 0;
+ ret = sendto(p_m_mISDNport->b_socket[p_m_b_index], buf, MISDN_HEADER_LEN+ISDN_LOAD-p_m_load-tosend, 0, NULL, 0);
+ if (ret <= 0)
+ PERROR("Failed to send to socket %d (samples = %d)\n", p_m_mISDNport->b_socket[p_m_b_index], ISDN_LOAD-p_m_load-tosend);
+ p_m_load += ISDN_LOAD - p_m_load - tosend;
+ }
+ }
+ }
+
+ // NOTE: deletion is done by the child class
+
+ /* handle timeouts */
+ if (p_m_timeout) {
+ if (p_m_timer+p_m_timeout < now_d) {
+ PDEBUG(DEBUG_ISDN, "(%s) timeout after %d seconds detected (state=%d).\n", p_name, p_m_timeout, p_state);
+ p_m_timeout = 0;
+ /* send timeout to endpoint */
+ message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_TIMEOUT);
+ message->param.state = p_state;
+ message_put(message);
+ return(1);
+ }
+ }
+
+ return(0); /* nothing done */
+}
+
+
+/*
+ * whenever we get audio data from bchannel, we process it here
+ */
+void PmISDN::bchannel_receive(struct mISDNhead *hh, unsigned char *data, int len)
+{
+ unsigned int cont = *((unsigned int *)data);
+ unsigned char *data_temp;
+ unsigned int length_temp;
+ struct lcr_msg *message;
+ unsigned char *p;
+ int l;
+
+ if (hh->prim == PH_CONTROL_IND) {
+ if (len < 4) {