Remove DSP kernel module dependency

* Use raw bchannel instead of DSP feature
* Removed DSP features
* Use new jitter buffer and control TX FIFO load by this application
* Added bridging daemon to assign time slots for bridging
This commit is contained in:
Andreas Eversberg 2022-08-19 16:27:41 +02:00
parent 9bbca1fb9e
commit e6aa538562
7 changed files with 1136 additions and 662 deletions

View File

@ -7,6 +7,7 @@ osmo_cc_misdn_endpoint_SOURCES = \
ie.c \ ie.c \
dss1.c \ dss1.c \
isdn.c \ isdn.c \
tones.c \
bridge.c \ bridge.c \
ph_driver.c \ ph_driver.c \
main.c main.c

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,8 @@
int bridge_msg_open(void); int brigde_socket_server(int slots);
void bridge_msg_close(void); void bridge_socket_server_child(int slots, int daemon);
void bridge_process_local(call_t *call);
int bridge_work(isdn_t *isdn_ep); int bridge_socket_client(void);
void bridge_socket_client_work(isdn_t *isdn_ep);
void bridge_socket_client_update(call_t *call, int enable);

View File

@ -174,7 +174,7 @@ static void split_3pty(call_t *call)
if (other) { if (other) {
other->conference_3pty = 0; other->conference_3pty = 0;
/* process local briding capability */ /* process local briding capability */
bridge_process_local(other); bridge_socket_client_update(other, 1);
/* create osmo-cc message */ /* create osmo-cc message */
msg = osmo_cc_new_msg(OSMO_CC_MSG_NOTIFY_IND); msg = osmo_cc_new_msg(OSMO_CC_MSG_NOTIFY_IND);
/* notify the facility */ /* notify the facility */
@ -297,15 +297,21 @@ void setup_ind(call_t *call, uint32_t pid, struct l3_msg *l3m)
} }
/* select codec */ /* select codec */
if (clearmode) if (clearmode) {
codecs = codecs_offer_clearmode; codecs = codecs_offer_clearmode;
else if (call->isdn_ep->law == 'a') /* init jitter buffer */
codecs = codecs_offer_alaw_ulaw; call_create_jitter(call, 1);
else } else {
codecs = codecs_offer_ulaw_alaw; if (call->isdn_ep->law == 'a')
codecs = codecs_offer_alaw_ulaw;
else
codecs = codecs_offer_ulaw_alaw;
/* init jitter buffer */
call_create_jitter(call, 0);
}
/* sdp offer */ /* sdp offer */
call->cc_session = osmo_cc_helper_audio_offer(&call->isdn_ep->cc_ep.session_config, call, codecs, bchannel_send, msg, 1); call->cc_session = osmo_cc_helper_audio_offer(&call->isdn_ep->cc_ep.session_config, call, codecs, rtp_receive, msg, 1);
/* dialing complete */ /* dialing complete */
dec_ie_complete(l3m, &sending_complete); dec_ie_complete(l3m, &sending_complete);
@ -340,6 +346,9 @@ void setup_ind(call_t *call, uint32_t pid, struct l3_msg *l3m)
if (rc < 0) if (rc < 0)
goto no_channel; goto no_channel;
/* process local briding capability */
bridge_socket_client_update(call, 1);
/* create endpoint */ /* create endpoint */
osmo_cc_call_t *cc_call = osmo_cc_call_new(&call->isdn_ep->cc_ep); osmo_cc_call_t *cc_call = osmo_cc_call_new(&call->isdn_ep->cc_ep);
call->cc_callref = cc_call->callref; call->cc_callref = cc_call->callref;
@ -392,8 +401,12 @@ void setup_ack_ind(call_t *call, uint32_t cmd, uint32_t pid, struct l3_msg *l3m)
/* send SDP answer */ /* send SDP answer */
if (coding == OSMO_CC_CODING_ITU_T && (progress == 1 || progress == 8) && !call->codec_negotiated) { if (coding == OSMO_CC_CODING_ITU_T && (progress == 1 || progress == 8) && !call->codec_negotiated) {
call->codec_negotiated = 1; call->codec_negotiated = 1;
if (call->sdp) if (call->sdp) {
/* send SDP */
osmo_cc_add_ie_sdp(msg, call->sdp); osmo_cc_add_ie_sdp(msg, call->sdp);
/* process local briding capability */
bridge_socket_client_update(call, 1);
}
} }
/* the audio path is throughconnected */ /* the audio path is throughconnected */
@ -463,8 +476,12 @@ void proc_ind(call_t *call, uint32_t cmd, uint32_t pid, struct l3_msg *l3m)
/* send SDP answer */ /* send SDP answer */
if (coding == OSMO_CC_CODING_ITU_T && (progress == 1 || progress == 8) && !call->codec_negotiated) { if (coding == OSMO_CC_CODING_ITU_T && (progress == 1 || progress == 8) && !call->codec_negotiated) {
call->codec_negotiated = 1; call->codec_negotiated = 1;
if (call->sdp) if (call->sdp) {
/* send SDP */
osmo_cc_add_ie_sdp(msg, call->sdp); osmo_cc_add_ie_sdp(msg, call->sdp);
/* process local briding capability */
bridge_socket_client_update(call, 1);
}
} }
/* the audio path is throughconnected */ /* the audio path is throughconnected */
@ -534,8 +551,12 @@ void alert_ind(call_t *call, uint32_t cmd, uint32_t pid, struct l3_msg *l3m)
/* send SDP answer */ /* send SDP answer */
if (coding == OSMO_CC_CODING_ITU_T && (progress == 1 || progress == 8) && !call->codec_negotiated) { if (coding == OSMO_CC_CODING_ITU_T && (progress == 1 || progress == 8) && !call->codec_negotiated) {
call->codec_negotiated = 1; call->codec_negotiated = 1;
if (call->sdp) if (call->sdp) {
/* send SDP */
osmo_cc_add_ie_sdp(msg, call->sdp); osmo_cc_add_ie_sdp(msg, call->sdp);
/* process local briding capability */
bridge_socket_client_update(call, 1);
}
} }
/* the audio path is throughconnected */ /* the audio path is throughconnected */
@ -614,8 +635,12 @@ void setup_cnf(call_t *call, uint32_t cmd, uint32_t pid, struct l3_msg *l3m)
/* send SDP answer */ /* send SDP answer */
if (!call->codec_negotiated) { if (!call->codec_negotiated) {
call->codec_negotiated = 1; call->codec_negotiated = 1;
if (call->sdp) if (call->sdp) {
/* send SDP */
osmo_cc_add_ie_sdp(msg, call->sdp); osmo_cc_add_ie_sdp(msg, call->sdp);
/* process local briding capability */
bridge_socket_client_update(call, 1);
}
} }
/* the audio path is throughconnected */ /* the audio path is throughconnected */
@ -713,7 +738,6 @@ void disconnect_ind(call_t *call, uint32_t pid, struct l3_msg *l3m)
{ {
osmo_cc_msg_t *msg; osmo_cc_msg_t *msg;
uint8_t location, cause; uint8_t location, cause;
uint8_t coding, proglocation, progress;
char display[128]; char display[128];
int rc; int rc;
@ -722,15 +746,6 @@ void disconnect_ind(call_t *call, uint32_t pid, struct l3_msg *l3m)
/* create osmo-cc message */ /* create osmo-cc message */
msg = osmo_cc_new_msg(OSMO_CC_MSG_DISC_IND); msg = osmo_cc_new_msg(OSMO_CC_MSG_DISC_IND);
/* progress indicator */
rc = dec_ie_progress(l3m, &coding, &proglocation, &progress);
if (rc >= 0)
osmo_cc_add_ie_progress(msg, coding, proglocation, progress);
else {
coding = OSMO_CC_CODING_ITU_T;
progress = 0;
}
/* cause */ /* cause */
rc = dec_ie_cause(l3m, &location, &cause); rc = dec_ie_cause(l3m, &location, &cause);
if (rc < 0) { if (rc < 0) {
@ -743,18 +758,9 @@ void disconnect_ind(call_t *call, uint32_t pid, struct l3_msg *l3m)
if (rc >= 0) if (rc >= 0)
osmo_cc_add_ie_display(msg, display); osmo_cc_add_ie_display(msg, display);
/* send SDP answer */ /* note: disconnect does not assign channel ID */
if (coding == OSMO_CC_CODING_ITU_T && (progress == 1 || progress == 8) && !call->codec_negotiated) {
call->codec_negotiated = 1;
if (call->sdp)
osmo_cc_add_ie_sdp(msg, call->sdp);
}
/* the audio path is throughconnected */ /* note: disconnect does not have progress indicator */
if (coding == OSMO_CC_CODING_ITU_T && (progress == 1 || progress == 8))
call->audio_path = 1;
else
call->audio_path = 0;
new_state(call, ISDN_STATE_IN_DISCONNECT); new_state(call, ISDN_STATE_IN_DISCONNECT);
@ -928,6 +934,9 @@ void hold_ind(call_t *call, uint32_t pid, struct l3_msg *l3m)
return; return;
} }
/* process local briding capability */
bridge_socket_client_update(call, 0);
/* create osmo-cc message */ /* create osmo-cc message */
msg = osmo_cc_new_msg(OSMO_CC_MSG_NOTIFY_IND); msg = osmo_cc_new_msg(OSMO_CC_MSG_NOTIFY_IND);
@ -991,9 +1000,15 @@ void retrieve_ind(call_t *call, uint32_t pid, struct l3_msg *l3m)
if (rc < 0) if (rc < 0)
goto no_channel; goto no_channel;
/* process local briding capability */
bridge_socket_client_update(call, 1);
/* set hold state */ /* set hold state */
call->hold = 0; call->hold = 0;
/* reset jitter buffer */
jitter_reset(&call->tx_dejitter);
/* acknowledge retrieve */ /* acknowledge retrieve */
PDEBUG(DDSS1, DEBUG_INFO, "RETRIEVE-ACKNOWLEDGE REQUEST (pid = 0x%x callref = %d)\n", pid, call->cc_callref); PDEBUG(DDSS1, DEBUG_INFO, "RETRIEVE-ACKNOWLEDGE REQUEST (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
l3m = create_l3msg(); l3m = create_l3msg();
@ -1039,6 +1054,9 @@ void suspend_ind(call_t *call, uint32_t pid, struct l3_msg *l3m)
check = check->next; check = check->next;
} }
/* process local briding capability */
bridge_socket_client_update(call, 0);
/* create osmo-cc message */ /* create osmo-cc message */
msg = osmo_cc_new_msg(OSMO_CC_MSG_NOTIFY_IND); msg = osmo_cc_new_msg(OSMO_CC_MSG_NOTIFY_IND);
@ -1117,6 +1135,9 @@ void resume_ind(isdn_t *isdn_ep, uint32_t pid, struct l3_msg *l3m)
if (rc < 0) if (rc < 0)
goto no_channel; goto no_channel;
/* process local briding capability */
bridge_socket_client_update(call, 1);
/* create osmo-cc message */ /* create osmo-cc message */
msg = osmo_cc_new_msg(OSMO_CC_MSG_NOTIFY_IND); msg = osmo_cc_new_msg(OSMO_CC_MSG_NOTIFY_IND);
@ -1166,7 +1187,6 @@ void facility_ind(call_t *call, uint32_t pid, struct l3_msg *l3m)
notify = OSMO_CC_NOTIFY_CONFERENCE_ESTABLISHED; notify = OSMO_CC_NOTIFY_CONFERENCE_ESTABLISHED;
invokeid = fac.u.inv.invokeId; invokeid = fac.u.inv.invokeId;
set_3pty = 1; set_3pty = 1;
jitter_clear(&call->dejitter);
break; break;
case Fac_End3PTY: case Fac_End3PTY:
@ -1200,9 +1220,12 @@ void facility_ind(call_t *call, uint32_t pid, struct l3_msg *l3m)
if (set_3pty >= 0 && other) { if (set_3pty >= 0 && other) {
other->conference_3pty = call->conference_3pty = set_3pty; other->conference_3pty = call->conference_3pty = set_3pty;
/* process local briding capability */ /* process local briding capability */
bridge_process_local(call); bridge_socket_client_update(call, 0);
bridge_process_local(other); bridge_socket_client_update(other, 0);
jitter_clear(&other->dejitter); jitter_reset(&call->conf_dejitter);
jitter_reset(&call->tx_dejitter);
jitter_reset(&other->conf_dejitter);
jitter_reset(&other->tx_dejitter);
} else { } else {
PDEBUG(DDSS1, DEBUG_NOTICE, "Phone requests conference, but no call on hold!\n"); PDEBUG(DDSS1, DEBUG_NOTICE, "Phone requests conference, but no call on hold!\n");
notify = 0; notify = 0;
@ -1273,8 +1296,12 @@ void progress_ind(call_t *call, uint32_t pid, struct l3_msg *l3m)
/* send SDP answer */ /* send SDP answer */
if (coding == OSMO_CC_CODING_ITU_T && (progress == 1 || progress == 8) && !call->codec_negotiated) { if (coding == OSMO_CC_CODING_ITU_T && (progress == 1 || progress == 8) && !call->codec_negotiated) {
call->codec_negotiated = 1; call->codec_negotiated = 1;
if (call->sdp) if (call->sdp) {
/* send SDP */
osmo_cc_add_ie_sdp(msg, call->sdp); osmo_cc_add_ie_sdp(msg, call->sdp);
/* process local briding capability */
bridge_socket_client_update(call, 1);
}
} }
/* the audio path is throughconnected */ /* the audio path is throughconnected */
@ -1483,7 +1510,7 @@ int dss1_receive(isdn_t *isdn_ep, uint32_t cmd, uint32_t pid, struct l3_msg *l3m
/* creating call instance, transparent until setup with hdlc */ /* creating call instance, transparent until setup with hdlc */
call = call_create(isdn_ep, DIRECTION_ORIGINATOR, 0, 0, B_MODE_TRANSPARENT); call = call_create(isdn_ep, DIRECTION_ORIGINATOR, 0, 0, B_MODE_TRANSPARENT);
if (!call) { if (!call) {
PDEBUG(DDSS1, DEBUG_ERROR, "Cannot create calll instance.\n"); PDEBUG(DDSS1, DEBUG_ERROR, "Cannot create call instance.\n");
abort(); abort();
} }
dss1_message(isdn_ep, call, cmd, pid, l3m); dss1_message(isdn_ep, call, cmd, pid, l3m);
@ -1550,7 +1577,7 @@ void setup_req(call_t *call, osmo_cc_msg_t *msg)
codecs = codecs_accept_ulaw_alaw_clearmode; codecs = codecs_accept_ulaw_alaw_clearmode;
/* sdp accept, force our codec, so we can use bchannel bridging if remote side supports it too */ /* sdp accept, force our codec, so we can use bchannel bridging if remote side supports it too */
sdp = osmo_cc_helper_audio_accept(&call->isdn_ep->cc_ep.session_config, call, codecs, bchannel_send, msg, &call->cc_session, &call->codec, 1/*force*/); sdp = osmo_cc_helper_audio_accept(&call->isdn_ep->cc_ep.session_config, call, codecs, rtp_receive, msg, &call->cc_session, &call->codec, 1/*force*/);
if (!sdp) { if (!sdp) {
release_and_destroy(call, 47, 415/* Unsupported Media*/, 0); release_and_destroy(call, 47, 415/* Unsupported Media*/, 0);
return; return;
@ -1602,11 +1629,14 @@ void setup_req(call_t *call, osmo_cc_msg_t *msg)
user = 2; user = 2;
else else
user = 3; user = 3;
/* init jitter buffer */
call_create_jitter(call, 0);
} else { } else {
has_user = 0; has_user = 0;
user = 0; user = 0;
/* init jitter buffer */
call_create_jitter(call, 1);
} }
printf("rate=%d\n", rate);
enc_ie_bearer(l3m, coding, capability, 1, mode, rate, 0, 0, has_user, user); enc_ie_bearer(l3m, coding, capability, 1, mode, rate, 0, 0, has_user, user);
/* channel information */ /* channel information */
@ -1677,7 +1707,7 @@ void setup_req(call_t *call, osmo_cc_msg_t *msg)
call->isdn_ep->ml3->to_layer3(call->isdn_ep->ml3, MT_SETUP, call->l3_pid, l3m); call->isdn_ep->ml3->to_layer3(call->isdn_ep->ml3, MT_SETUP, call->l3_pid, l3m);
/* process local briding capability */ /* process local briding capability */
bridge_process_local(call); bridge_socket_client_update(call, 1);
} }
void proc_req(call_t *call, uint32_t pid, osmo_cc_msg_t *msg, int with_ies); void proc_req(call_t *call, uint32_t pid, osmo_cc_msg_t *msg, int with_ies);
@ -2365,22 +2395,18 @@ void cc_message(osmo_cc_endpoint_t *ep, uint32_t callref, osmo_cc_msg_t *msg)
break; break;
case OSMO_CC_MSG_SETUP_ACK_REQ: /* more information is needed */ case OSMO_CC_MSG_SETUP_ACK_REQ: /* more information is needed */
osmo_cc_helper_audio_negotiate(msg, &call->cc_session, &call->codec); osmo_cc_helper_audio_negotiate(msg, &call->cc_session, &call->codec);
bridge_process_local(call);
setup_ack_req(call, call->l3_pid, msg); setup_ack_req(call, call->l3_pid, msg);
break; break;
case OSMO_CC_MSG_PROC_REQ: /* call of endpoint is proceeding */ case OSMO_CC_MSG_PROC_REQ: /* call of endpoint is proceeding */
osmo_cc_helper_audio_negotiate(msg, &call->cc_session, &call->codec); osmo_cc_helper_audio_negotiate(msg, &call->cc_session, &call->codec);
bridge_process_local(call);
proc_req(call, call->l3_pid, msg, 1); proc_req(call, call->l3_pid, msg, 1);
break; break;
case OSMO_CC_MSG_ALERT_REQ: /* call of endpoint is ringing */ case OSMO_CC_MSG_ALERT_REQ: /* call of endpoint is ringing */
osmo_cc_helper_audio_negotiate(msg, &call->cc_session, &call->codec); osmo_cc_helper_audio_negotiate(msg, &call->cc_session, &call->codec);
bridge_process_local(call);
alert_req(call, call->l3_pid, msg); alert_req(call, call->l3_pid, msg);
break; break;
case OSMO_CC_MSG_SETUP_RSP: /* call of endpoint is connected */ case OSMO_CC_MSG_SETUP_RSP: /* call of endpoint is connected */
osmo_cc_helper_audio_negotiate(msg, &call->cc_session, &call->codec); osmo_cc_helper_audio_negotiate(msg, &call->cc_session, &call->codec);
bridge_process_local(call);
setup_rsp(call, call->l3_pid, msg); setup_rsp(call, call->l3_pid, msg);
break; break;
case OSMO_CC_MSG_SETUP_COMP_REQ: /* call of endpoint is connected */ case OSMO_CC_MSG_SETUP_COMP_REQ: /* call of endpoint is connected */
@ -2415,7 +2441,6 @@ void cc_message(osmo_cc_endpoint_t *ep, uint32_t callref, osmo_cc_msg_t *msg)
break; break;
case OSMO_CC_MSG_PROGRESS_REQ: /* progress */ case OSMO_CC_MSG_PROGRESS_REQ: /* progress */
osmo_cc_helper_audio_negotiate(msg, &call->cc_session, &call->codec); osmo_cc_helper_audio_negotiate(msg, &call->cc_session, &call->codec);
bridge_process_local(call);
if (isdn_ep->ntmode if (isdn_ep->ntmode
&& call->state != ISDN_STATE_OUT_OVERLAP && call->state != ISDN_STATE_OUT_OVERLAP
&& call->state != ISDN_STATE_OUT_PROCEEDING && call->state != ISDN_STATE_OUT_PROCEEDING
@ -2445,7 +2470,6 @@ void cc_message(osmo_cc_endpoint_t *ep, uint32_t callref, osmo_cc_msg_t *msg)
break; break;
case OSMO_CC_MSG_DISC_REQ: /* call has been disconnected */ case OSMO_CC_MSG_DISC_REQ: /* call has been disconnected */
osmo_cc_helper_audio_negotiate(msg, &call->cc_session, &call->codec); osmo_cc_helper_audio_negotiate(msg, &call->cc_session, &call->codec);
bridge_process_local(call);
if (call->state != ISDN_STATE_IN_SETUP if (call->state != ISDN_STATE_IN_SETUP
&& call->state != ISDN_STATE_IN_OVERLAP && call->state != ISDN_STATE_IN_OVERLAP
&& call->state != ISDN_STATE_IN_PROCEEDING && call->state != ISDN_STATE_IN_PROCEEDING

View File

@ -17,6 +17,22 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
/* Transmit algorithm:
*
* Transmit data is taken from jitter buffer.
*
* When data is received from b-channel the first time, two chunks of data are transmitted to ISDN interface in one block.
*
* When more data is received from b-channel, this extra chunk is transmitted to ISDN interface.
*
* This way the FIFO is kept with data all the time, to prevent underrund in hope that this application does not stall.
*
* The function that receives data and transmits data is bchannel_rx_tx().
*
* The jitter of received chunk is checked and debug is displayed accordingly.
*
*/
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
#include <errno.h> #include <errno.h>
@ -49,32 +65,6 @@
#define B_TIMER_ACTIVATING 1 // seconds #define B_TIMER_ACTIVATING 1 // seconds
#define B_TIMER_DEACTIVATING 1 // seconds #define B_TIMER_DEACTIVATING 1 // seconds
int check_mISDN_dsp(void)
{
char buffer[256];
int found = 0;
FILE *fp = fopen("/proc/modules", "r");
if (!fp) {
PDEBUG(DISDN, DEBUG_ERROR, "Failed to read /proc/modules.\n");
return -errno;
}
while((fgets(buffer, sizeof(buffer), fp))) {
buffer[sizeof(buffer) - 1] = '\0';
if (strstr(buffer, "mISDN_dsp"))
found = 1;
}
fclose(fp);
if (found)
return 0;
PDEBUG(DISDN, DEBUG_ERROR, "Required module 'mISDN_dsp' is not loaded. Run 'modprobe mISDN_dsp' to load the module!\n");
return -EINVAL;
}
/* /*
* Channel selection * Channel selection
*/ */
@ -687,7 +677,7 @@ void isdn_destroy(isdn_t *isdn_ep)
} }
/* initialization and configuration to isdn interface instance */ /* initialization and configuration to isdn interface instance */
int isdn_initialize(isdn_t *isdn_ep, ph_socket_t *ph_socket, char law, const char *portname, int ntmode, int ptp, int layer1hold, int layer2hold, const char *channel_out, const char *channel_in, const char *timeouts, int tx_delay, int tx_gain, int rx_gain, const char *pipeline, int dtmf, int local_tones, int serving_location) int isdn_initialize(isdn_t *isdn_ep, ph_socket_t *ph_socket, char law, const char *portname, int ntmode, int ptp, int layer1hold, int layer2hold, const char *channel_out, const char *channel_in, const char *timeouts, int tx_delay, int local_tones, int serving_location)
{ {
int rc; int rc;
void *mui; void *mui;
@ -721,10 +711,6 @@ int isdn_initialize(isdn_t *isdn_ep, ph_socket_t *ph_socket, char law, const cha
isdn_ep->l2hold = layer2hold; isdn_ep->l2hold = layer2hold;
isdn_ep->timeouts = timeouts; isdn_ep->timeouts = timeouts;
isdn_ep->tx_delay = tx_delay; isdn_ep->tx_delay = tx_delay;
isdn_ep->tx_gain = tx_gain;
isdn_ep->rx_gain = rx_gain;
isdn_ep->pipeline = pipeline;
isdn_ep->dtmf = dtmf;
isdn_ep->local_tones = local_tones; isdn_ep->local_tones = local_tones;
isdn_ep->serving_location = serving_location; isdn_ep->serving_location = serving_location;
@ -775,7 +761,6 @@ void isdn_add_msn(isdn_t *isdn_ep, const char *msn)
call_t *call_create(isdn_t *isdn_ep, int direction, int channel, int exclusive, int mode) call_t *call_create(isdn_t *isdn_ep, int direction, int channel, int exclusive, int mode)
{ {
call_t *call, **call_p; call_t *call, **call_p;
int rc;
call = calloc(1, sizeof(*call)); call = calloc(1, sizeof(*call));
if (!call) { if (!call) {
@ -796,18 +781,7 @@ call_t *call_create(isdn_t *isdn_ep, int direction, int channel, int exclusive,
call->b_reserve = 0; call->b_reserve = 0;
call->b_mode = mode; call->b_mode = mode;
call->hold = 0; call->hold = 0;
call->tx_gain = isdn_ep->tx_gain; call->isdn_tone.tone = 0;
call->rx_gain = isdn_ep->rx_gain;
call->bridge = 0;
call->mute = 0;
call->txdata = 0;
call->tx_delay = isdn_ep->tx_delay;
call->echo = 0;
call->tone = 0;
call->rxoff = 0;
call->dtmf = isdn_ep->dtmf;
call->dtmf_threshold = 0;
call->pipeline = isdn_ep->pipeline;
/* if any channel requested by constructor */ /* if any channel requested by constructor */
if (channel == CHANNEL_ANY) { if (channel == CHANNEL_ANY) {
@ -820,22 +794,40 @@ call_t *call_create(isdn_t *isdn_ep, int direction, int channel, int exclusive,
if (channel > 0) // only if constructor was called with a channel resevation if (channel > 0) // only if constructor was called with a channel resevation
seize_bchannel(call, channel, exclusive); seize_bchannel(call, channel, exclusive);
/* allocate jitter buffer */
rc = jitter_create(&call->dejitter, 8000 / 10); // FIXME: size
if (rc < 0)
abort();
PDEBUG(DISDN, DEBUG_DEBUG, "Created new call on port #%d:%s\n", isdn_ep->portnum, isdn_ep->portname); PDEBUG(DISDN, DEBUG_DEBUG, "Created new call on port #%d:%s\n", isdn_ep->portnum, isdn_ep->portname);
return call; return call;
} }
void call_create_jitter(call_t *call, int data)
{
isdn_t *isdn_ep = call->isdn_ep;
int rc;
/* allocate jitter buffer */
if (isdn_ep->tx_delay)
rc = jitter_create(&call->tx_dejitter, "tx", 8000, sizeof(uint8_t), (double)isdn_ep->tx_delay / 1000.0, (double)isdn_ep->tx_delay / 1000.0 * 2.0, JITTER_FLAG_NONE);
else if (data)
rc = jitter_create(&call->tx_dejitter, "tx", 8000, sizeof(uint8_t), JITTER_DATA);
else
rc = jitter_create(&call->tx_dejitter, "tx", 8000, sizeof(uint8_t), JITTER_AUDIO);
if (rc < 0)
abort();
rc = jitter_create(&call->conf_dejitter, "conference", 8000, sizeof(int16_t), JITTER_AUDIO);
if (rc < 0)
abort();
}
void call_destroy(call_t *call) void call_destroy(call_t *call)
{ {
call_t **call_p; call_t **call_p;
/* be sure to clean up bridge on server */
bridge_socket_client_update(call, 0);
/* free jitter buffer */ /* free jitter buffer */
jitter_destroy(&call->dejitter); jitter_destroy(&call->tx_dejitter);
jitter_destroy(&call->conf_dejitter);
/* remove B-channel relation */ /* remove B-channel relation */
drop_bchannel(call); drop_bchannel(call);
@ -863,56 +855,24 @@ void call_destroy(call_t *call)
* bchannel handling * bchannel handling
*/ */
/* send control information to the channel (dsp-module) */ /* send control information to the channel (HFC hardware bridging) */
static void ph_control(int sock, uint32_t c1, uint32_t c2) static void im_control(int sock, uint32_t op, uint32_t channel, uint32_t p1, uint32_t p2)
{ {
uint8_t buffer[MISDN_HEADER_LEN + 4 + 4]; struct mISDN_ctrl_req cq;
struct mISDNhead *ctrl = (struct mISDNhead *)buffer;
uint32_t *d = (uint32_t *)(buffer + MISDN_HEADER_LEN);
int len = 8;
int rc; int rc;
if (sock < 0) if (sock < 0)
return; return;
if (c1 == DTMF_TONE_START && c2 == 0) PDEBUG(DISDN, DEBUG_DEBUG, "sending IMCTRLREQ 0x%08x, %d, 0x%02x, 0x%02x\n", op, channel, p1, p2);
len = 4;
PDEBUG(DISDN, DEBUG_DEBUG, "sending PH_CONTROL_REQ %d, %d\n", c1, c2); cq.op = op;
cq.channel = channel;
ctrl->prim = PH_CONTROL_REQ; cq.p1 = p1;
ctrl->id = 0; cq.p2 = p2;
*d++ = c1; rc = ioctl(sock, IMCTRLREQ, &cq);
*d++ = c2; if (rc < 0)
rc = sendto(sock, buffer, MISDN_HEADER_LEN + len, 0, NULL, 0); PDEBUG(DISDN, DEBUG_ERROR, "Failed to send IMCTRLREQ to socket %d (errno=%d:%s)\n", sock, errno, strerror(errno));
if (rc <= 0) {
PDEBUG(DISDN, DEBUG_ERROR, "Failed to send to socket %d (errno=%d:%s)\n", sock, errno, strerror(errno));
abort();
}
}
/* send control information, but with different length */
static void ph_control_block(int sock, uint32_t c1, const void *c2, int c2_len)
{
uint8_t *buffer[MISDN_HEADER_LEN + 4 + c2_len];
struct mISDNhead *ctrl = (struct mISDNhead *)buffer;
uint32_t *d = (uint32_t *)(buffer + MISDN_HEADER_LEN);
int rc;
if (sock < 0)
return;
PDEBUG(DISDN, DEBUG_DEBUG, "sending PH_CONTROL_REQ %d\n", c1);
ctrl->prim = PH_CONTROL_REQ;
ctrl->id = 0;
*d++ = c1;
memcpy(d, c2, c2_len);
rc = sendto(sock, buffer, sizeof(buffer), 0, NULL, 0);
if (rc <= 0) {
PDEBUG(DISDN, DEBUG_ERROR, "Failed to send to socket %d (errno=%d:%s)\n", sock, errno, strerror(errno));
abort();
}
} }
/* create B-channel stack */ /* create B-channel stack */
@ -935,7 +895,7 @@ static int bchannel_create(isdn_t *isdn_ep, int index)
if (isdn_ep->b_mode[index] == B_MODE_HDLC) { if (isdn_ep->b_mode[index] == B_MODE_HDLC) {
PDEBUG(DISDN, DEBUG_NOTICE, "Use B-Channel with HDLC!!!\n"); PDEBUG(DISDN, DEBUG_NOTICE, "Use B-Channel with HDLC!!!\n");
} }
rc = socket(PF_ISDN, SOCK_DGRAM, (isdn_ep->b_mode[index] == B_MODE_HDLC) ? ISDN_P_B_L2DSPHDLC : ISDN_P_B_L2DSP); rc = socket(PF_ISDN, SOCK_DGRAM, (isdn_ep->b_mode[index] == B_MODE_HDLC) ? ISDN_P_B_HDLC : ISDN_P_B_RAW);
if (rc < 0) { if (rc < 0) {
PDEBUG(DISDN, DEBUG_ERROR, "Failed to open bchannel-socket for index %d with mISDN-DSP layer. Did you load mISDN_dsp.ko?\n", index); PDEBUG(DISDN, DEBUG_ERROR, "Failed to open bchannel-socket for index %d with mISDN-DSP layer. Did you load mISDN_dsp.ko?\n", index);
return(0); return(0);
@ -1000,107 +960,45 @@ static void bchannel_activate(isdn_t *isdn_ep, int index, int activate, int time
/* configure B-channel */ /* configure B-channel */
static void bchannel_configure(isdn_t *isdn_ep, int index) static void bchannel_configure(isdn_t *isdn_ep, int index)
{ {
int channel = index + 1 + (index >= 15);
call_t *call; call_t *call;
int handle, mode; int handle;
if (isdn_ep->b_sock[index] <= 0) if (isdn_ep->b_sock[index] <= 0)
return; return;
handle = isdn_ep->b_sock[index]; handle = isdn_ep->b_sock[index];
call = isdn_ep->b_call[index]; call = isdn_ep->b_call[index];
mode = isdn_ep->b_mode[index];
/* set dsp features */ /* set PCM bridge features */
if (call->txdata) { if (call->bridge_enabled)
PDEBUG(DISDN, DEBUG_DEBUG, "PH_CONTROL: set DSP_TXDATA*\n"); im_control(handle, MISDN_CTRL_HFC_PCM_CONN, channel, call->bridge_slot_tx | (call->bridge_bank_tx << 8), call->bridge_slot_rx | (call->bridge_bank_rx << 8));
ph_control(handle, (call->txdata) ? DSP_TXDATA_ON : DSP_TXDATA_OFF, 0); else
} im_control(handle, MISDN_CTRL_HFC_PCM_DISC, channel, 0, 0);
if (call->tx_delay && mode == B_MODE_TRANSPARENT) { }
PDEBUG(DISDN, DEBUG_DEBUG, "PH_CONTROL: set DSP_DELAY\n");
ph_control(handle, DSP_DELAY, call->tx_delay); void bchannel_bridge(call_t *call, int pcm_bridge, int rx_slot, int tx_slot, int rx_bank, int tx_bank)
} {
if (!call->tx_delay && mode == B_MODE_TRANSPARENT) { /* bridge enabled */
PDEBUG(DISDN, DEBUG_DEBUG, "PH_CONTROL: set DSP_TX_DEJITTER\n"); call->bridge_enabled = pcm_bridge;
ph_control(handle, DSP_TX_DEJITTER, 1); call->bridge_bank_tx = tx_bank;
} call->bridge_slot_tx = tx_slot;
if (call->tx_gain && mode == B_MODE_TRANSPARENT) { call->bridge_bank_rx = rx_bank;
PDEBUG(DISDN, DEBUG_DEBUG, "PH_CONTROL: set DSP_VOL_CHANGE_TX\n"); call->bridge_slot_rx = rx_slot;
ph_control(handle, DSP_VOL_CHANGE_TX, call->tx_gain); bchannel_configure(call->isdn_ep, call->b_index);
}
if (call->rx_gain && mode == B_MODE_TRANSPARENT) {
PDEBUG(DISDN, DEBUG_DEBUG, "PH_CONTROL: set DSP_VOL_CHANGE_RX\n");
ph_control(handle, DSP_VOL_CHANGE_RX, call->rx_gain);
}
if (call->pipeline && call->pipeline[0] && mode == B_MODE_TRANSPARENT) {
PDEBUG(DISDN, DEBUG_DEBUG, "PH_CONTROL: set DSP_PIPELINE_CFG\n");
ph_control_block(handle, DSP_PIPELINE_CFG, call->pipeline, strlen(call->pipeline) + 1);
}
if (call->bridge && !call->mute) {
PDEBUG(DISDN, DEBUG_DEBUG, "PH_CONTROL: set DSP_CONF_JOIN\n");
ph_control(handle, DSP_CONF_JOIN, call->bridge);
}
if (call->echo) {
PDEBUG(DISDN, DEBUG_DEBUG, "PH_CONTROL: set DSP_ECHO_ON\n");
ph_control(handle, DSP_ECHO_ON, 0);
}
if (call->tone && mode == B_MODE_TRANSPARENT) {
PDEBUG(DISDN, DEBUG_DEBUG, "PH_CONTROL: set DSP_TONE_PATT_ON (tone=%d)\n", call->tone);
ph_control(handle, DSP_TONE_PATT_ON, call->tone);
}
if (call->rxoff) {
PDEBUG(DISDN, DEBUG_DEBUG, "PH_CONTROL: set DSP_RECEIVE_OFF\n");
ph_control(handle, DSP_RECEIVE_OFF, 0);
}
if (call->dtmf && mode == B_MODE_TRANSPARENT) {
PDEBUG(DISDN, DEBUG_DEBUG, "PH_CONTROL: set DTMF_TONE_START\n");
ph_control(handle, DTMF_TONE_START, call->dtmf_threshold);
}
} }
void bchannel_tone(call_t *call, int tone) void bchannel_tone(call_t *call, int tone)
{ {
call->tone = tone;
if (call->b_index < 0) if (call->b_index < 0)
return; return;
int handle = call->isdn_ep->b_sock[call->b_index];
int mode = call->isdn_ep->b_mode[call->b_index]; int mode = call->isdn_ep->b_mode[call->b_index];
if (mode != B_MODE_TRANSPARENT) if (mode != B_MODE_TRANSPARENT)
return; return;
if (call->tone) { isdn_tone_set(&call->isdn_tone, tone);
PDEBUG(DISDN, DEBUG_DEBUG, "PH_CONTROL: set DSP_TONE_PATT_ON (tone=%d)\n", call->tone);
ph_control(handle, DSP_TONE_PATT_ON, call->tone);
} else {
PDEBUG(DISDN, DEBUG_DEBUG, "PH_CONTROL: set DSP_TONE_PATT_OFF\n");
ph_control(handle, DSP_TONE_PATT_OFF, 0);
}
}
/* set bridge ID for B-channel */
void bchannel_bridge(call_t *call, uint32_t bridge)
{
int *sock_p = &call->isdn_ep->b_sock[call->b_index];
int index, channel;
if (*sock_p <= 0) {
call->bridge = bridge;
return;
}
index = call->b_index;
channel = index + 1 + (index >= 15);
if (call->bridge != bridge) {
PDEBUG(DISDN, DEBUG_DEBUG, "Change bridge from %d to %d for channel %d.\n", call->bridge, bridge, channel);
if (index > -1 && call->isdn_ep->b_state[index] == B_STATE_ACTIVE)
ph_control(*sock_p, (bridge) ? DSP_CONF_JOIN : DSP_CONF_SPLIT, bridge);
} else
PDEBUG(DISDN, DEBUG_DEBUG, "We already have bridge=%d on channel %d.\n", bridge, channel);
call->bridge = bridge;
} }
/* destroy B-channel stack */ /* destroy B-channel stack */
@ -1220,6 +1118,8 @@ void bchannel_event(isdn_t *isdn_ep, int index, int event)
/* bchannel is active and used by a call instance, so we configure bchannel */ /* bchannel is active and used by a call instance, so we configure bchannel */
bchannel_configure(isdn_ep, index); bchannel_configure(isdn_ep, index);
state = B_STATE_ACTIVE; state = B_STATE_ACTIVE;
call->b_rx_time = 0.0;
call->b_transmitting = 0;
//FIXME: init buffer state for delay //FIXME: init buffer state for delay
} else { } else {
/* bchannel is active, but not used anymore (or has wrong stack config), so we deactivate */ /* bchannel is active, but not used anymore (or has wrong stack config), so we deactivate */
@ -1322,10 +1222,11 @@ void bchannel_event(isdn_t *isdn_ep, int index, int event)
timer_start(&isdn_ep->b_timer[index], timer); timer_start(&isdn_ep->b_timer[index], timer);
} }
static void bchannel_receive(isdn_t *isdn_ep, int index, struct mISDNhead *hh, unsigned char *data, int len); static void bchannel_rx_tx(isdn_t *isdn_ep, int index, struct mISDNhead *hh, unsigned char *data, int len);
static void bchannel_confirm(isdn_t *isdn_ep, int index);
/* handle frames from B-channel (kernel socket) */ /* handle frames from B-channel (kernel socket) */
static int bchannel_kernel_sock_work(isdn_t *isdn_ep, int index) static int bchannel_kernel_sock_receive(isdn_t *isdn_ep, int index)
{ {
int channel = index + 1 + (index >= 15); int channel = index + 1 + (index >= 15);
unsigned char buffer[2048+MISDN_HEADER_LEN]; unsigned char buffer[2048+MISDN_HEADER_LEN];
@ -1346,6 +1247,8 @@ static int bchannel_kernel_sock_work(isdn_t *isdn_ep, int index)
switch (hh->prim) { switch (hh->prim) {
/* we don't care about confirms, we use rx data to sync tx */ /* we don't care about confirms, we use rx data to sync tx */
case PH_DATA_CNF: case PH_DATA_CNF:
if (isdn_ep->b_call[index])
bchannel_confirm(isdn_ep, index);
break; break;
/* we receive audio data, we respond to it AND we send tones */ /* we receive audio data, we respond to it AND we send tones */
@ -1355,7 +1258,7 @@ static int bchannel_kernel_sock_work(isdn_t *isdn_ep, int index)
case DL_DATA_REQ: case DL_DATA_REQ:
case PH_CONTROL_IND: case PH_CONTROL_IND:
if (isdn_ep->b_call[index]) if (isdn_ep->b_call[index])
bchannel_receive(isdn_ep, index, hh, buffer + MISDN_HEADER_LEN, rc - MISDN_HEADER_LEN); bchannel_rx_tx(isdn_ep, index, hh, buffer + MISDN_HEADER_LEN, rc - MISDN_HEADER_LEN);
else else
PDEBUG(DISDN, DEBUG_DEBUG, "b-channel is not associated to a call (channel %d), ignoring.\n", channel); PDEBUG(DISDN, DEBUG_DEBUG, "b-channel is not associated to a call (channel %d), ignoring.\n", channel);
break; break;
@ -1393,10 +1296,14 @@ void bchannel_ph_sock_receive(void *priv, int channel, uint8_t prim, uint8_t *da
return; return;
switch (prim) { switch (prim) {
case PH_PRIM_DATA_CNF:
if (isdn_ep->b_call[index])
bchannel_confirm(isdn_ep, index);
break;
case PH_PRIM_DATA_IND: case PH_PRIM_DATA_IND:
if (isdn_ep->b_call[index]) { if (isdn_ep->b_call[index]) {
struct mISDNhead hh = { .prim = PH_DATA_IND }; struct mISDNhead hh = { .prim = PH_DATA_IND };
bchannel_receive(isdn_ep, index, &hh, data, length); bchannel_rx_tx(isdn_ep, index, &hh, data, length);
} else } else
PDEBUG(DISDN, DEBUG_DEBUG, "b-channel is not associated to a call (channel %d), ignoring.\n", channel); PDEBUG(DISDN, DEBUG_DEBUG, "b-channel is not associated to a call (channel %d), ignoring.\n", channel);
break; break;
@ -1534,9 +1441,10 @@ static void send_to_rtp(call_t *call, unsigned char *data, int len)
return; return;
if (call->conference_3pty) { if (call->conference_3pty) {
int16_t *audio; int16_t *audio_local;
int audio_len; int audio_len;
sample_t samples_local[len], samples_remote_active[len], samples_remote_hold[len], mix[len]; int16_t audio_mix[len], audio_remote_active[len], audio_remote_hold[len];
int32_t spl;
int i; int i;
/* there should be no call on hold with audio coming from */ /* there should be no call on hold with audio coming from */
@ -1545,14 +1453,13 @@ static void send_to_rtp(call_t *call, unsigned char *data, int len)
/* convert local audio from interface to samples */ /* convert local audio from interface to samples */
if (call->isdn_ep->law == 'a') if (call->isdn_ep->law == 'a')
g711_decode_alaw_flipped(data, len, (uint8_t **)&audio, &audio_len); g711_decode_alaw_flipped(data, len, (uint8_t **)&audio_local, &audio_len);
else else
g711_decode_ulaw_flipped(data, len, (uint8_t **)&audio, &audio_len); g711_decode_ulaw_flipped(data, len, (uint8_t **)&audio_local, &audio_len);
int16_to_samples(samples_local, audio, len);
// don't free audio, because we need that later when encoding // don't free audio, because we need that later when encoding
/* convert remote RTP to samples */ /* convert remote RTP to samples */
jitter_load(&call->dejitter, samples_remote_active, len); jitter_load(&call->conf_dejitter, audio_remote_active, len);
/* search other party on hold */ /* search other party on hold */
other = call->isdn_ep->call_list; other = call->isdn_ep->call_list;
@ -1566,101 +1473,174 @@ static void send_to_rtp(call_t *call, unsigned char *data, int len)
/* convert remote RTP to samples */ /* convert remote RTP to samples */
if (other) if (other)
jitter_load(&other->dejitter, samples_remote_hold, len); jitter_load(&other->conf_dejitter, audio_remote_hold, len);
else else
memset(samples_remote_hold, 0, sizeof(sample_t) * len); memset(audio_remote_hold, 0, sizeof(*audio_remote_hold) * len);
/* mix audio for local interface and forward */ /* mix audio for local interface and forward */
for (i = 0; i < len; i++) for (i = 0; i < len; i++) {
mix[i] = samples_remote_active[i] + samples_remote_hold[i]; /* both remote parties */ spl = (int32_t)audio_remote_active[i] + (int32_t)audio_remote_hold[i]; /* both remote parties */
samples_to_int16(audio, mix, len); if (spl < -32767)
spl = -32767;
if (spl > 32767)
spl = 32767;
audio_mix[i] = spl;
}
if (call->isdn_ep->law == 'a') if (call->isdn_ep->law == 'a')
g711_encode_alaw_flipped((uint8_t *)audio, audio_len, &data, &len); g711_encode_alaw_flipped((uint8_t *)audio_mix, audio_len, &data, &len);
else else
g711_encode_ulaw_flipped((uint8_t *)audio, audio_len, &data, &len); g711_encode_ulaw_flipped((uint8_t *)audio_mix, audio_len, &data, &len);
if (call->b_index >= 0) { if (call->b_index >= 0 && call->b_transmitting) {
unsigned char buf[MISDN_HEADER_LEN + len]; jitter_save(&call->tx_dejitter, data, len, 0, 0, 0, 0);
struct mISDNhead *frm = (struct mISDNhead *)buf;
int rc = 0;
memcpy(buf + MISDN_HEADER_LEN, data, len);
frm->prim = PH_DATA_REQ;
frm->id = 0;
if (call->isdn_ep->ph_socket)
ph_socket_tx_msg(call->isdn_ep->ph_socket, call->b_channel, PH_PRIM_DATA_REQ, buf + MISDN_HEADER_LEN, len);
else
rc = send(call->isdn_ep->b_sock[call->b_index], buf, MISDN_HEADER_LEN + len, 0);
if (rc < 0)
PDEBUG(DISDN, DEBUG_ERROR, "write error B-channel data (socket #%d errno=%d:%s)\n", call->isdn_ep->b_sock[call->b_index], errno, strerror(errno));
} }
free(data); free(data);
/* mix audio for (active) remote interface and forward */ /* mix audio for (active) remote interface and forward */
for (i = 0; i < len; i++) for (i = 0; i < len; i++) {
mix[i] = samples_local[i] + samples_remote_hold[i]; /* local + remote (hold) party */ spl = audio_local[i] + audio_remote_hold[i]; /* local + remote (on hold) party */
samples_to_int16(audio, mix, len); if (spl < -32767)
spl = -32767;
if (spl > 32767)
spl = 32767;
audio_mix[i] = spl;
}
if (call->isdn_ep->law == 'a') if (call->isdn_ep->law == 'a')
g711_encode_alaw_flipped((uint8_t *)audio, audio_len, &data, &len); g711_encode_alaw_flipped((uint8_t *)audio_mix, audio_len, &data, &len);
else else
g711_encode_ulaw_flipped((uint8_t *)audio, audio_len, &data, &len); g711_encode_ulaw_flipped((uint8_t *)audio_mix, audio_len, &data, &len);
osmo_cc_rtp_send(call->codec, data, len, 1, len); osmo_cc_rtp_send(call->codec, data, len, 1, len);
free(data); free(data);
/* mix audio for (hold) remote interface and forward */ /* mix audio for (hold) remote interface and forward */
if (other) { if (other) {
for (i = 0; i < len; i++) for (i = 0; i < len; i++) {
mix[i] = samples_local[i] + samples_remote_active[i]; /* local + remote (active) party */ spl = audio_local[i] + audio_remote_active[i]; /* local + remote (active) party */
samples_to_int16(audio, mix, len); if (spl < -32767)
spl = -32767;
if (spl > 32767)
spl = 32767;
audio_mix[i] = spl;
}
if (call->isdn_ep->law == 'a') if (call->isdn_ep->law == 'a')
g711_encode_alaw_flipped((uint8_t *)audio, audio_len, &data, &len); g711_encode_alaw_flipped((uint8_t *)audio_mix, audio_len, &data, &len);
else else
g711_encode_ulaw_flipped((uint8_t *)audio, audio_len, &data, &len); g711_encode_ulaw_flipped((uint8_t *)audio_mix, audio_len, &data, &len);
osmo_cc_rtp_send(other->codec, data, len, 1, len); osmo_cc_rtp_send(other->codec, data, len, 1, len);
free(data); free(data);
} }
free(audio); free(audio_local);
return; return;
} }
/* bridging, don't forward */ /* bridging, don't forward */
if (call->bridge) if (call->bridge_enabled)
return; return;
osmo_cc_rtp_send(call->codec, data, len, 1, len); osmo_cc_rtp_send(call->codec, data, len, 1, len);
} }
/* receive audio and control from B-channel */ /* receive audio and control from B-channel, transmit data from jitter buffer accoring to received length */
static void bchannel_receive(isdn_t *isdn_ep, int index, struct mISDNhead *hh, unsigned char *data, int len) static void bchannel_rx_tx(isdn_t *isdn_ep, int index, struct mISDNhead *hh, unsigned char *data, int len)
{ {
uint8_t *buffer = isdn_ep->b_buffer[index]; uint8_t *buffer = isdn_ep->b_buffer[index];
int *buffer_pos = &(isdn_ep->b_buffer_pos[index]); int *buffer_pos = &(isdn_ep->b_buffer_pos[index]);
unsigned int cont = *((unsigned int *)data); call_t *call = isdn_ep->b_call[index];
int i;
if (hh->prim == PH_CONTROL_IND) { if (hh->prim == PH_CONTROL_IND) {
if (len < 4) { if (len < 4) {
PDEBUG(DISDN, DEBUG_ERROR, "SHORT READ OF PH_CONTROL INDICATION\n"); PDEBUG(DISDN, DEBUG_ERROR, "SHORT READ OF PH_CONTROL INDICATION\n");
return; return;
} }
if ((cont & (~DTMF_TONE_MASK)) == DTMF_TONE_VAL) {
// send_cc_dtmf(call, cont & DTMF_TONE_MASK);
// FIXME: DTMF via telephony events??
return;
}
return; return;
} }
if (hh->prim != PH_DATA_IND && hh->prim != DL_DATA_IND) if (hh->prim != PH_DATA_IND)
return; return;
/* add to buffer */ if (!call) {
while (len) { PDEBUG(DISDN, DEBUG_DEBUG, "Dropping b-channel data from channel without call.\n");
buffer[(*buffer_pos)++] = *data++; return;
len--; }
if (isdn_ep->b_state[index] != B_STATE_ACTIVE) {
PDEBUG(DISDN, DEBUG_DEBUG, "Dropping b-channel data from inactive channel.\n");
return;
}
/* no transmission when bridging and playing no tones */
if (call->bridge_enabled && !call->isdn_tone.tone) {
call->b_transmitting = 0;
*buffer_pos = 0;
return;
}
/* check jitter of receved stream from ISDN */
double now = get_time();
if (call->b_rx_time) {
double elapsed = now - call->b_rx_time;
if ((int)(elapsed * 8000.0) - len > len / 4)
PDEBUG(DISDN, DEBUG_DEBUG, "Data received %d samples, time elapsed %d samples\n", len, (int)(elapsed * 8000.0));
}
call->b_rx_time = now;
/* add to buffer and send via RTP */
for (i = 0; i < len; i++) {
buffer[(*buffer_pos)++] = data[i];
if (*buffer_pos == 160) { if (*buffer_pos == 160) {
*buffer_pos = 0; *buffer_pos = 0;
send_to_rtp(isdn_ep->b_call[index], buffer, 160); send_to_rtp(call, buffer, 160);
} }
} }
/* prepare ISDN TX buffer */
unsigned char buf[MISDN_HEADER_LEN + len + len];
struct mISDNhead *frm = (struct mISDNhead *)buf;
int offset;
int rc = 0;
frm->prim = PH_DATA_REQ;
frm->id = 0;
if (!call->b_transmitting) {
PDEBUG(DISDN, DEBUG_DEBUG, "First received b-channel data, filling FIFO with double data of %d bytes.\n", len * 2);
memset(buf + MISDN_HEADER_LEN, 0xff, len);
offset = len;
} else {
// PDEBUG(DISDN, DEBUG_DEBUG, "More received b-channel data, filling FIFO with data of %d bytes.\n", len);
offset = 0;
}
/* load from TX jitter buffer and optionally overload with tones */
jitter_load(&call->tx_dejitter, buf + MISDN_HEADER_LEN + offset, len);
isdn_tone_copy(&call->isdn_tone, buf + MISDN_HEADER_LEN + offset, len);
/* forward to interface */
if (call->isdn_ep->ph_socket)
ph_socket_tx_msg(call->isdn_ep->ph_socket, call->b_channel, PH_PRIM_DATA_REQ, buf + MISDN_HEADER_LEN, offset + len);
else
rc = send(call->isdn_ep->b_sock[call->b_index], buf, MISDN_HEADER_LEN + offset + len, 0);
if (rc < 0)
PDEBUG(DISDN, DEBUG_ERROR, "Write error B-channel data (socket #%d errno=%d:%s)\n", call->isdn_ep->b_sock[call->b_index], errno, strerror(errno));
else
call->b_transmitting = 1;
}
/* receive confirm from bchannel */
static void bchannel_confirm(isdn_t *isdn_ep, int index)
{
call_t *call = isdn_ep->b_call[index];
if (!call) {
PDEBUG(DISDN, DEBUG_DEBUG, "Ignoring b-channel confirm of channel without call.\n");
return;
}
double now = get_time();
if (call->b_rx_time) {
double elapsed = now - call->b_rx_time;
if (elapsed > 4)
PDEBUG(DISDN, DEBUG_DEBUG, "Data confirmed, time elapsed %d samples\n", (int)(elapsed * 8000.0));
}
} }
void isdn_rtp_work(isdn_t *isdn_ep) void isdn_rtp_work(isdn_t *isdn_ep)
@ -1675,8 +1655,8 @@ void isdn_rtp_work(isdn_t *isdn_ep)
} }
} }
/* send audio to B-channel */ /* send audio from RTP to B-channel's jitter buffer */
void bchannel_send(struct osmo_cc_session_codec *codec, uint16_t __attribute__((unused)) sequence_number, uint32_t __attribute__((unused)) timestamp, uint8_t *data, int len) void rtp_receive(struct osmo_cc_session_codec *codec, uint16_t sequence_number, uint32_t timestamp, uint32_t ssrc, uint8_t *data, int len)
{ {
call_t *call = codec->media->session->priv; call_t *call = codec->media->session->priv;
@ -1684,38 +1664,31 @@ void bchannel_send(struct osmo_cc_session_codec *codec, uint16_t __attribute__((
if (call->conference_3pty) { if (call->conference_3pty) {
int16_t *audio; int16_t *audio;
int audio_len; int audio_len;
sample_t samples[len];
/* alaw/ulaw to linear */ /* alaw/ulaw to linear */
if (call->isdn_ep->law == 'a') if (call->isdn_ep->law == 'a')
g711_decode_alaw_flipped(data, len, (uint8_t **)&audio, &audio_len); g711_decode_alaw_flipped(data, len, (uint8_t **)&audio, &audio_len);
else else
g711_decode_ulaw_flipped(data, len, (uint8_t **)&audio, &audio_len); g711_decode_ulaw_flipped(data, len, (uint8_t **)&audio, &audio_len);
int16_to_samples(samples, audio, len);
free(audio);
/* enqueue data to jitter buffer */ /* enqueue data to jitter buffer */
jitter_save(&call->dejitter, samples, len); jitter_save(&call->conf_dejitter, audio, len, 1, sequence_number, timestamp, ssrc);
free(audio);
return; return;
} }
/* bridging, don't forward */ /* bridging, don't forward */
if (call->bridge) if (call->bridge_enabled)
return;
/* not yet b_transmitting on bchannel */
if (!call->b_transmitting)
return;
/* ignore voice, if call is on hold */
if (call->hold)
return; return;
/* no conference, just forward to ISDN interface */ /* no conference, just forward to ISDN interface */
if (call->b_index >= 0) { jitter_save(&call->tx_dejitter, data, len, 1, sequence_number, timestamp, ssrc);
unsigned char buf[MISDN_HEADER_LEN + len];
struct mISDNhead *frm = (struct mISDNhead *)buf;
int rc = 0;
memcpy(buf + MISDN_HEADER_LEN, data, len);
frm->prim = PH_DATA_REQ;
frm->id = 0;
if (call->isdn_ep->ph_socket)
ph_socket_tx_msg(call->isdn_ep->ph_socket, call->b_channel, PH_PRIM_DATA_REQ, buf + MISDN_HEADER_LEN, len);
else
rc = send(call->isdn_ep->b_sock[call->b_index], buf, MISDN_HEADER_LEN + len, 0);
if (rc < 0)
PDEBUG(DISDN, DEBUG_ERROR, "write error B-channel data (socket #%d errno=%d:%s)\n", call->isdn_ep->b_sock[call->b_index], errno, strerror(errno));
}
} }
/* /*
@ -1955,6 +1928,15 @@ int isdn_open(isdn_t *isdn_ep)
if (isdn_ep->portname) if (isdn_ep->portname)
free(isdn_ep->portname); free(isdn_ep->portname);
isdn_ep->portname = strdup(devinfo.name); isdn_ep->portname = strdup(devinfo.name);
if (!strncmp(isdn_ep->portname, "hfc-4s.", 7)
|| !strncmp(isdn_ep->portname, "hfc-8s.", 7)
|| !strncmp(isdn_ep->portname, "hfc-e1.", 7)) {
/* cards that support hardware bridging */
isdn_ep->bridge_possible = 1;
isdn_ep->bridge_cardnum = strtoul(isdn_ep->portname + 7, NULL, 10);
isdn_ep->bridge_portnum = portnum;
PDEBUG(DISDN, DEBUG_INFO, "Port can use HFC bridge of card %d.\n", isdn_ep->bridge_cardnum);
}
isdn_ep->ntmode = nt; isdn_ep->ntmode = nt;
isdn_ep->pri = pri; isdn_ep->pri = pri;
isdn_ep->ptp = ptp; isdn_ep->ptp = ptp;
@ -1978,9 +1960,6 @@ int isdn_open(isdn_t *isdn_ep)
if (isdn_ep->ntmode && !isdn_ep->ptp) if (isdn_ep->ntmode && !isdn_ep->ptp)
isdn_ep->l2link = 1; isdn_ep->l2link = 1;
if (isdn_ep->l2sock)
PDEBUG(DISDN, DEBUG_DEBUG, "using 'mISDN_dsp.o' module\n");
return 0; return 0;
error: error:
@ -2155,7 +2134,7 @@ void isdn_bchannel_work(isdn_t *isdn_ep)
for (i = 0; i < isdn_ep->b_num; i++) { for (i = 0; i < isdn_ep->b_num; i++) {
do { do {
if (isdn_ep->b_sock[i] > 0) if (isdn_ep->b_sock[i] > 0)
w = bchannel_kernel_sock_work(isdn_ep, i); w = bchannel_kernel_sock_receive(isdn_ep, i);
else else
w = 0; w = 0;
} while (w); } while (w);

View File

@ -6,6 +6,7 @@
#include "../libsample/sample.h" #include "../libsample/sample.h"
#include "../libjitter/jitter.h" #include "../libjitter/jitter.h"
#include "../libph_socket/ph_socket.h" #include "../libph_socket/ph_socket.h"
#include "tones.h"
#define B_MODE_TRANSPARENT 0 #define B_MODE_TRANSPARENT 0
#define B_MODE_HDLC 1 #define B_MODE_HDLC 1
@ -78,10 +79,6 @@ typedef struct isdn {
int serving_location; /* who we serve when sending causes towards interface */ int serving_location; /* who we serve when sending causes towards interface */
const char *timeouts; const char *timeouts;
int tx_delay; int tx_delay;
int tx_gain;
int rx_gain;
const char *pipeline;
int dtmf;
int local_tones; int local_tones;
/* osmo-cc */ /* osmo-cc */
@ -117,6 +114,11 @@ typedef struct isdn {
uint8_t b_buffer[128][160]; uint8_t b_buffer[128][160];
int b_buffer_pos[128]; int b_buffer_pos[128];
unsigned char l2mask[16]; /* 128 bits for each tei */ unsigned char l2mask[16]; /* 128 bits for each tei */
/* bridging */
int bridge_possible;
int bridge_cardnum;
int bridge_portnum;
} isdn_t; } isdn_t;
typedef struct call_list { typedef struct call_list {
@ -126,18 +128,9 @@ typedef struct call_list {
/* mISDN states */ /* mISDN states */
uint32_t l3_pid; uint32_t l3_pid;
uint16_t l3_ces; uint16_t l3_ces;
int tx_gain;
int rx_gain; /* tone states */
int mute; struct isdn_tone isdn_tone;
int txdata;
int tx_delay;
int echo;
uint32_t bridge;
int tone;
int rxoff;
int dtmf;
int dtmf_threshold;
const char *pipeline;
/* osmo-cc states */ /* osmo-cc states */
uint32_t cc_callref; uint32_t cc_callref;
@ -154,6 +147,8 @@ typedef struct call_list {
int b_exclusive; int b_exclusive;
int b_reserve; int b_reserve;
int b_mode; int b_mode;
int b_transmitting;
double b_rx_time;
/* call states */ /* call states */
int direction; /* originator or terminator of call */ int direction; /* originator or terminator of call */
@ -172,16 +167,19 @@ typedef struct call_list {
uint8_t park_callid[8]; uint8_t park_callid[8];
/* bridge states */ /* bridge states */
int local_bridge; /* if local peer can bridge */ int can_bridge; /* last state sent to the server */
int remote_bridge; /* if remote peer can bridge */ int bridge_enabled; /* last state received by the server */
int bridge_bank_tx;
int bridge_slot_tx;
int bridge_bank_rx;
int bridge_slot_rx;
/* jitter buffer for 3pty call */ /* jitter buffer for tx and 3pty call */
jitter_t dejitter; jitter_t tx_dejitter;
jitter_t conf_dejitter;
} call_t; } call_t;
int check_mISDN_dsp(void);
/* channel selection */ /* channel selection */
int hunt_bchannel_in(isdn_t *isdn_ep, int channel, int exclusive); int hunt_bchannel_in(isdn_t *isdn_ep, int channel, int exclusive);
int hunt_bchannel_out(isdn_t *isdn_ep, int *channel, int *exclusive); int hunt_bchannel_out(isdn_t *isdn_ep, int *channel, int *exclusive);
@ -191,7 +189,7 @@ int open_bchannel_out(call_t *call, unsigned int cmd, int channel, int exclusive
/* isdn instance */ /* isdn instance */
isdn_t *isdn_create(void); isdn_t *isdn_create(void);
void isdn_destroy(isdn_t *isdn_ep); void isdn_destroy(isdn_t *isdn_ep);
int isdn_initialize(isdn_t *isdn_ep, ph_socket_t *ph_socket, char law, const char *portname, int ntmode, int ptp, int layer1hold, int layer2hold, const char *channel_out, const char *channel_in, const char *timeouts, int tx_delay, int tx_gain, int rx_gain, const char *pipeline, int dtmf, int local_tones, int serving_location); int isdn_initialize(isdn_t *isdn_ep, ph_socket_t *ph_socket, char law, const char *portname, int ntmode, int ptp, int layer1hold, int layer2hold, const char *channel_out, const char *channel_in, const char *timeouts, int tx_delay, int local_tones, int serving_location);
int isdn_open(isdn_t *isdn_ep); int isdn_open(isdn_t *isdn_ep);
void isdn_close(isdn_t *isdn_ep); void isdn_close(isdn_t *isdn_ep);
void isdn_add_msn(isdn_t *isdn_ep, const char *msn); void isdn_add_msn(isdn_t *isdn_ep, const char *msn);
@ -201,13 +199,14 @@ void isdn_rtp_work(isdn_t *isdn_ep);
/* call instance */ /* call instance */
call_t *call_create(isdn_t *isdn_ep, int direction, int channel, int exclusive, int mode); call_t *call_create(isdn_t *isdn_ep, int direction, int channel, int exclusive, int mode);
void call_create_jitter(call_t *call, int data);
void call_destroy(call_t *call); void call_destroy(call_t *call);
/* channel allocation and handling */ /* channel allocation and handling */
void bchannel_tone(call_t *call, int tone); void bchannel_tone(call_t *call, int tone);
void bchannel_bridge(call_t *call, uint32_t bridge); void bchannel_bridge(call_t *call, int pcm_bridge, int rx_slot, int tx_slot, int rx_bank, int tx_bank);
void bchannel_event(isdn_t *isdn_ep, int index, int event); void bchannel_event(isdn_t *isdn_ep, int index, int event);
int seize_bchannel(call_t *call, int channel, int exclusive); int seize_bchannel(call_t *call, int channel, int exclusive);
void drop_bchannel(call_t *call); void drop_bchannel(call_t *call);
void bchannel_send(struct osmo_cc_session_codec *codec, uint16_t sequence_number, uint32_t timestamp, uint8_t *data, int len); void rtp_receive(struct osmo_cc_session_codec *codec, uint16_t sequence_number, uint32_t timestamp, uint32_t ssrc, uint8_t *data, int len);

View File

@ -24,6 +24,7 @@
#include <string.h> #include <string.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <sched.h>
#include "../libdebug/debug.h" #include "../libdebug/debug.h"
#include "../liboptions/options.h" #include "../liboptions/options.h"
#include "../libg711/g711.h" #include "../libg711/g711.h"
@ -48,13 +49,13 @@ static const char *channel_out = NULL;
static const char *channel_in = NULL; static const char *channel_in = NULL;
static const char *timeouts = NULL; static const char *timeouts = NULL;
static int tx_delay = 0; static int tx_delay = 0;
static int tx_gain = 0;
static int rx_gain = 0;
static const char *pipeline = NULL;
static int dtmf = 1;
static int local_tones = 0; static int local_tones = 0;
static int debug_mISDN = 0; static int debug_mISDN = 0;
static int serving_location = 1; /* private network serving local user */ static int serving_location = 1; /* private network serving local user */
static int use_hfc_bridging = 1;
static int bridging_server_only = 0;
static int pcm_slots = 32;
static int rt_prio = 1;
#define MAX_CC_ARGS 1024 #define MAX_CC_ARGS 1024
static int cc_argc = 0; static int cc_argc = 0;
static const char *cc_argv[MAX_CC_ARGS]; static const char *cc_argv[MAX_CC_ARGS];
@ -118,23 +119,20 @@ static void print_help()
printf(" --tx-delay <ms>\n"); printf(" --tx-delay <ms>\n");
printf(" Give a delay in milliseconds. This is required for modem/fax. Audio\n"); printf(" Give a delay in milliseconds. This is required for modem/fax. Audio\n");
printf(" toward ISDN interface is buffered with the given delay.\n"); printf(" toward ISDN interface is buffered with the given delay.\n");
printf(" This feature turns off the dejittering.\n"); printf(" This feature alters dejittering strategy.\n");
printf(" --tx-gain <dB>\n");
printf(" Changes gain of audio towards ISDN interface. Give Gain in steps of\n");
printf(" 6 dB. (-48 .. 48)\n");
printf(" --rx-gain <dB>\n");
printf(" Changes gain of audio coming from ISDN interface. Give Gain in steps\n");
printf(" of 6 dB. (-48 .. 48)\n");
printf(" --pipeline <string>\n");
printf(" mISDN allows to use echo cancellation modules. See mISDN documentation.\n");
printf(" --dtmf 1 | 0\n");
printf(" Turns DTMF detection on or off (default is %d).\n", dtmf);
printf(" -T --local-tones german | oldgerman | american\n"); printf(" -T --local-tones german | oldgerman | american\n");
printf(" Send locally generated tones, if not provided by remote interface.\n"); printf(" Send locally generated tones, if not provided by remote interface.\n");
printf(" -D --debug-misdn\n"); printf(" -D --debug-misdn\n");
printf(" Enables mISDN stack debugging.\n"); printf(" Enables mISDN stack debugging.\n");
printf(" --serving-location (see Q.931)\n"); printf(" --serving-location (see Q.931)\n");
printf(" 0 = user, 1 = private network serving local user (default=%d)\n", serving_location); printf(" 0 = user, 1 = private network serving local user (default=%d)\n", serving_location);
printf(" -B --bridging 0 | 1\n");
printf(" Enable or disable hardware bridging with HFC cards. (default = %d)\n", use_hfc_bridging);
printf(" --pcm-slots 32 | 64 | 128\n");
printf(" The number of slots must match the configured PCM bus size.\n");
printf(" (default = %d)\n", pcm_slots);
printf(" -r --realtime <prio>\n");
printf(" Set prio: 0 to disable, 99 for maximum (default = %d)\n", rt_prio);
printf(" -C --cc \"<osmo-cc arg>\" [--cc ...]\n"); printf(" -C --cc \"<osmo-cc arg>\" [--cc ...]\n");
printf(" Pass arguments to Osmo-CC endpoint. Use '-cc help' for description.\n"); printf(" Pass arguments to Osmo-CC endpoint. Use '-cc help' for description.\n");
} }
@ -149,6 +147,8 @@ static void print_help()
#define OPT_PIPELINE 263 #define OPT_PIPELINE 263
#define OPT_DTMF 264 #define OPT_DTMF 264
#define OPT_SERVING 265 #define OPT_SERVING 265
#define OPT_PCM_SLOTS 266
#define OPT_BR_ONLY 267
static void add_options(void) static void add_options(void)
{ {
@ -166,13 +166,13 @@ static void add_options(void)
option_add(OPT_CHANNEL_IN, "channel-in", 1); option_add(OPT_CHANNEL_IN, "channel-in", 1);
option_add(OPT_TIMEOUTS, "timeouts", 1); option_add(OPT_TIMEOUTS, "timeouts", 1);
option_add(OPT_TX_DELAY, "tx-delay", 1); option_add(OPT_TX_DELAY, "tx-delay", 1);
option_add(OPT_TX_GAIN, "tx-gain", 1);
option_add(OPT_RX_GAIN, "rx-gain", 1);
option_add(OPT_PIPELINE, "pipeline", 1);
option_add(OPT_DTMF, "dtmf", 1);
option_add('T', "local-tones", 1); option_add('T', "local-tones", 1);
option_add('D', "debug-misdn", 0); option_add('D', "debug-misdn", 0);
option_add(OPT_SERVING, "serving-location", 0); option_add(OPT_SERVING, "serving-location", 1);
option_add('B', "bridging", 1);
option_add(OPT_PCM_SLOTS, "pcm-slots", 1);
option_add(OPT_BR_ONLY, "bridging-server-only", 0);
option_add('r', "realtime", 1);
option_add('C', "cc", 1); option_add('C', "cc", 1);
} }
@ -234,18 +234,6 @@ static int handle_options(int short_option, int argi, char **argv)
case OPT_TX_DELAY: case OPT_TX_DELAY:
tx_delay = atoi(argv[argi]); tx_delay = atoi(argv[argi]);
break; break;
case OPT_TX_GAIN:
tx_gain = atoi(argv[argi]) / 6;
break;
case OPT_RX_GAIN:
rx_gain = atoi(argv[argi]) / 6;
break;
case OPT_PIPELINE:
pipeline = options_strdup(argv[argi]);
break;
case OPT_DTMF:
dtmf = atoi(argv[argi]);
break;
case 'T': case 'T':
if (!strcasecmp(argv[argi], "american")) if (!strcasecmp(argv[argi], "american"))
local_tones = TONES_TYPE_AMERICAN; local_tones = TONES_TYPE_AMERICAN;
@ -264,6 +252,18 @@ static int handle_options(int short_option, int argi, char **argv)
case OPT_SERVING: case OPT_SERVING:
serving_location = atoi(argv[argi]); serving_location = atoi(argv[argi]);
break; break;
case 'B':
use_hfc_bridging = atoi(argv[argi]);
break;
case OPT_PCM_SLOTS:
pcm_slots = strtoul(argv[argi], NULL, 10);
break;
case OPT_BR_ONLY:
bridging_server_only = 1;
break;
case 'r':
rt_prio = atoi(argv[argi]);
break;
case 'C': case 'C':
if (!strcasecmp(argv[argi], "help")) { if (!strcasecmp(argv[argi], "help")) {
osmo_cc_help(); osmo_cc_help();
@ -331,6 +331,17 @@ int main(int argc, char *argv[])
if (argi <= 0) if (argi <= 0)
return argi; return argi;
if (bridging_server_only) {
bridge_socket_server_child(pcm_slots, 1);
return 0;
}
/* start bridge server */
if (use_hfc_bridging) {
brigde_socket_server(pcm_slots);
bridge_socket_client();
}
if (!misdn_kernel && !misdn_user) { if (!misdn_kernel && !misdn_user) {
fprintf(stderr, "You defined no mISDN port or layer 1 socket. You must define either one of them! Use '-h' for help.\n"); fprintf(stderr, "You defined no mISDN port or layer 1 socket. You must define either one of them! Use '-h' for help.\n");
goto error; goto error;
@ -340,13 +351,6 @@ int main(int argc, char *argv[])
goto error; goto error;
} }
/* check for DSP (kernel only) */
if (misdn_kernel) {
rc = check_mISDN_dsp();
if (rc)
goto error;
}
/* init user space mISDN */ /* init user space mISDN */
if (misdn_user) { if (misdn_user) {
rc = mISDNInit((debug_mISDN) ? 0xffffffff : 0); rc = mISDNInit((debug_mISDN) ? 0xffffffff : 0);
@ -365,20 +369,17 @@ int main(int argc, char *argv[])
layer3_initialized = 1; layer3_initialized = 1;
mISDN_set_debug_level((debug_mISDN) ? 0xfffffeff : 0); mISDN_set_debug_level((debug_mISDN) ? 0xfffffeff : 0);
/* change tones to ulaw */
if (law == 'u')
isdn_tone_generate_ulaw_samples();
/* init instance */ /* init instance */
rc = isdn_initialize(isdn_ep, (misdn_user) ? &ph_drv.ph_socket : NULL, law, portname, ntmode, ptp, layer1hold, layer2hold, channel_out, channel_in, timeouts, tx_delay, tx_gain, rx_gain, pipeline, dtmf, local_tones, serving_location); rc = isdn_initialize(isdn_ep, (misdn_user) ? &ph_drv.ph_socket : NULL, law, portname, ntmode, ptp, layer1hold, layer2hold, channel_out, channel_in, timeouts, tx_delay, local_tones, serving_location);
if (rc) { if (rc) {
PDEBUG(DISDN, DEBUG_ERROR, "mISDN initializing failed!\n"); PDEBUG(DISDN, DEBUG_ERROR, "mISDN initializing failed!\n");
goto error; goto error;
} }
/* open bridge notification socket */
rc = bridge_msg_open();
if (rc) {
PDEBUG(DISDN, DEBUG_ERROR, "This means that direct bridging is not supported!\n");
sleep(3);
}
rc = isdn_open(isdn_ep); rc = isdn_open(isdn_ep);
if (rc) { if (rc) {
PDEBUG(DISDN, DEBUG_ERROR, "mISDN open failed!\n"); PDEBUG(DISDN, DEBUG_ERROR, "mISDN open failed!\n");
@ -388,10 +389,22 @@ int main(int argc, char *argv[])
while ((p = strchr(portname, '/'))) while ((p = strchr(portname, '/')))
portname = p + 1; portname = p + 1;
rc = osmo_cc_new(&isdn_ep->cc_ep, OSMO_CC_VERSION, portname, serving_location, cc_message, NULL, isdn_ep, cc_argc, cc_argv); rc = osmo_cc_new(&isdn_ep->cc_ep, OSMO_CC_VERSION, isdn_ep->portname, serving_location, cc_message, NULL, isdn_ep, cc_argc, cc_argv);
if (rc < 0) if (rc < 0)
goto error; goto error;
/* real time priority */
if (rt_prio > 0) {
struct sched_param schedp;
int rc;
memset(&schedp, 0, sizeof(schedp));
schedp.sched_priority = rt_prio;
rc = sched_setscheduler(0, SCHED_RR, &schedp);
if (rc)
fprintf(stderr, "Error setting SCHED_RR with prio %d\n", rt_prio);
}
signal(SIGINT, sighandler); signal(SIGINT, sighandler);
signal(SIGHUP, sighandler); signal(SIGHUP, sighandler);
signal(SIGTERM, sighandler); signal(SIGTERM, sighandler);
@ -402,6 +415,7 @@ int main(int argc, char *argv[])
process_timer(); process_timer();
isdn_bchannel_work(isdn_ep); isdn_bchannel_work(isdn_ep);
isdn_rtp_work(isdn_ep); isdn_rtp_work(isdn_ep);
bridge_socket_client_work(isdn_ep);
if (misdn_user) { if (misdn_user) {
/* run workers of mISDN stacks in user space */ /* run workers of mISDN stacks in user space */
mISDN_work(); mISDN_work();
@ -410,7 +424,6 @@ int main(int argc, char *argv[])
w = 0; w = 0;
w |= osmo_cc_handle(); w |= osmo_cc_handle();
w |= isdn_dchannel_work(isdn_ep); w |= isdn_dchannel_work(isdn_ep);
w |= bridge_work(isdn_ep);
if (misdn_user) { if (misdn_user) {
/* run workers of mISDN stacks in user space */ /* run workers of mISDN stacks in user space */
w |= ph_socket_work(&ph_drv.ph_socket); w |= ph_socket_work(&ph_drv.ph_socket);
@ -426,6 +439,15 @@ int main(int argc, char *argv[])
signal(SIGTERM, SIG_DFL); signal(SIGTERM, SIG_DFL);
signal(SIGPIPE, SIG_DFL); signal(SIGPIPE, SIG_DFL);
/* reset real time prio */
if (rt_prio > 0) {
struct sched_param schedp;
memset(&schedp, 0, sizeof(schedp));
schedp.sched_priority = 0;
sched_setscheduler(0, SCHED_OTHER, &schedp);
}
error: error:
if (isdn_ep) { if (isdn_ep) {
osmo_cc_delete(&isdn_ep->cc_ep); osmo_cc_delete(&isdn_ep->cc_ep);
@ -441,8 +463,6 @@ error:
if (misdn_initialized) if (misdn_initialized)
mISDN_cleanup(); mISDN_cleanup();
bridge_msg_close();
options_free(); options_free();
return 0; return 0;