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:
parent
9bbca1fb9e
commit
e6aa538562
|
@ -7,6 +7,7 @@ osmo_cc_misdn_endpoint_SOURCES = \
|
|||
ie.c \
|
||||
dss1.c \
|
||||
isdn.c \
|
||||
tones.c \
|
||||
bridge.c \
|
||||
ph_driver.c \
|
||||
main.c
|
||||
|
|
1006
src/isdn/bridge.c
1006
src/isdn/bridge.c
File diff suppressed because it is too large
Load Diff
|
@ -1,5 +1,8 @@
|
|||
|
||||
int bridge_msg_open(void);
|
||||
void bridge_msg_close(void);
|
||||
void bridge_process_local(call_t *call);
|
||||
int bridge_work(isdn_t *isdn_ep);
|
||||
int brigde_socket_server(int slots);
|
||||
void bridge_socket_server_child(int slots, int daemon);
|
||||
|
||||
int bridge_socket_client(void);
|
||||
void bridge_socket_client_work(isdn_t *isdn_ep);
|
||||
void bridge_socket_client_update(call_t *call, int enable);
|
||||
|
||||
|
|
118
src/isdn/dss1.c
118
src/isdn/dss1.c
|
@ -174,7 +174,7 @@ static void split_3pty(call_t *call)
|
|||
if (other) {
|
||||
other->conference_3pty = 0;
|
||||
/* process local briding capability */
|
||||
bridge_process_local(other);
|
||||
bridge_socket_client_update(other, 1);
|
||||
/* create osmo-cc message */
|
||||
msg = osmo_cc_new_msg(OSMO_CC_MSG_NOTIFY_IND);
|
||||
/* notify the facility */
|
||||
|
@ -297,15 +297,21 @@ void setup_ind(call_t *call, uint32_t pid, struct l3_msg *l3m)
|
|||
}
|
||||
|
||||
/* select codec */
|
||||
if (clearmode)
|
||||
if (clearmode) {
|
||||
codecs = codecs_offer_clearmode;
|
||||
else if (call->isdn_ep->law == 'a')
|
||||
codecs = codecs_offer_alaw_ulaw;
|
||||
else
|
||||
codecs = codecs_offer_ulaw_alaw;
|
||||
/* init jitter buffer */
|
||||
call_create_jitter(call, 1);
|
||||
} else {
|
||||
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 */
|
||||
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 */
|
||||
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)
|
||||
goto no_channel;
|
||||
|
||||
/* process local briding capability */
|
||||
bridge_socket_client_update(call, 1);
|
||||
|
||||
/* create endpoint */
|
||||
osmo_cc_call_t *cc_call = osmo_cc_call_new(&call->isdn_ep->cc_ep);
|
||||
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 */
|
||||
if (coding == OSMO_CC_CODING_ITU_T && (progress == 1 || progress == 8) && !call->codec_negotiated) {
|
||||
call->codec_negotiated = 1;
|
||||
if (call->sdp)
|
||||
if (call->sdp) {
|
||||
/* send SDP */
|
||||
osmo_cc_add_ie_sdp(msg, call->sdp);
|
||||
/* process local briding capability */
|
||||
bridge_socket_client_update(call, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
if (coding == OSMO_CC_CODING_ITU_T && (progress == 1 || progress == 8) && !call->codec_negotiated) {
|
||||
call->codec_negotiated = 1;
|
||||
if (call->sdp)
|
||||
if (call->sdp) {
|
||||
/* send SDP */
|
||||
osmo_cc_add_ie_sdp(msg, call->sdp);
|
||||
/* process local briding capability */
|
||||
bridge_socket_client_update(call, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
if (coding == OSMO_CC_CODING_ITU_T && (progress == 1 || progress == 8) && !call->codec_negotiated) {
|
||||
call->codec_negotiated = 1;
|
||||
if (call->sdp)
|
||||
if (call->sdp) {
|
||||
/* send SDP */
|
||||
osmo_cc_add_ie_sdp(msg, call->sdp);
|
||||
/* process local briding capability */
|
||||
bridge_socket_client_update(call, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
if (!call->codec_negotiated) {
|
||||
call->codec_negotiated = 1;
|
||||
if (call->sdp)
|
||||
if (call->sdp) {
|
||||
/* send SDP */
|
||||
osmo_cc_add_ie_sdp(msg, call->sdp);
|
||||
/* process local briding capability */
|
||||
bridge_socket_client_update(call, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
uint8_t location, cause;
|
||||
uint8_t coding, proglocation, progress;
|
||||
char display[128];
|
||||
int rc;
|
||||
|
||||
|
@ -722,15 +746,6 @@ void disconnect_ind(call_t *call, uint32_t pid, struct l3_msg *l3m)
|
|||
/* create osmo-cc message */
|
||||
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 */
|
||||
rc = dec_ie_cause(l3m, &location, &cause);
|
||||
if (rc < 0) {
|
||||
|
@ -743,18 +758,9 @@ void disconnect_ind(call_t *call, uint32_t pid, struct l3_msg *l3m)
|
|||
if (rc >= 0)
|
||||
osmo_cc_add_ie_display(msg, display);
|
||||
|
||||
/* send SDP answer */
|
||||
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);
|
||||
}
|
||||
/* note: disconnect does not assign channel ID */
|
||||
|
||||
/* the audio path is throughconnected */
|
||||
if (coding == OSMO_CC_CODING_ITU_T && (progress == 1 || progress == 8))
|
||||
call->audio_path = 1;
|
||||
else
|
||||
call->audio_path = 0;
|
||||
/* note: disconnect does not have progress indicator */
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* process local briding capability */
|
||||
bridge_socket_client_update(call, 0);
|
||||
|
||||
/* create osmo-cc message */
|
||||
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)
|
||||
goto no_channel;
|
||||
|
||||
/* process local briding capability */
|
||||
bridge_socket_client_update(call, 1);
|
||||
|
||||
/* set hold state */
|
||||
call->hold = 0;
|
||||
|
||||
/* reset jitter buffer */
|
||||
jitter_reset(&call->tx_dejitter);
|
||||
|
||||
/* acknowledge retrieve */
|
||||
PDEBUG(DDSS1, DEBUG_INFO, "RETRIEVE-ACKNOWLEDGE REQUEST (pid = 0x%x callref = %d)\n", pid, call->cc_callref);
|
||||
l3m = create_l3msg();
|
||||
|
@ -1039,6 +1054,9 @@ void suspend_ind(call_t *call, uint32_t pid, struct l3_msg *l3m)
|
|||
check = check->next;
|
||||
}
|
||||
|
||||
/* process local briding capability */
|
||||
bridge_socket_client_update(call, 0);
|
||||
|
||||
/* create osmo-cc message */
|
||||
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)
|
||||
goto no_channel;
|
||||
|
||||
/* process local briding capability */
|
||||
bridge_socket_client_update(call, 1);
|
||||
|
||||
/* create osmo-cc message */
|
||||
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;
|
||||
invokeid = fac.u.inv.invokeId;
|
||||
set_3pty = 1;
|
||||
jitter_clear(&call->dejitter);
|
||||
break;
|
||||
|
||||
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) {
|
||||
other->conference_3pty = call->conference_3pty = set_3pty;
|
||||
/* process local briding capability */
|
||||
bridge_process_local(call);
|
||||
bridge_process_local(other);
|
||||
jitter_clear(&other->dejitter);
|
||||
bridge_socket_client_update(call, 0);
|
||||
bridge_socket_client_update(other, 0);
|
||||
jitter_reset(&call->conf_dejitter);
|
||||
jitter_reset(&call->tx_dejitter);
|
||||
jitter_reset(&other->conf_dejitter);
|
||||
jitter_reset(&other->tx_dejitter);
|
||||
} else {
|
||||
PDEBUG(DDSS1, DEBUG_NOTICE, "Phone requests conference, but no call on hold!\n");
|
||||
notify = 0;
|
||||
|
@ -1273,8 +1296,12 @@ void progress_ind(call_t *call, uint32_t pid, struct l3_msg *l3m)
|
|||
/* send SDP answer */
|
||||
if (coding == OSMO_CC_CODING_ITU_T && (progress == 1 || progress == 8) && !call->codec_negotiated) {
|
||||
call->codec_negotiated = 1;
|
||||
if (call->sdp)
|
||||
if (call->sdp) {
|
||||
/* send SDP */
|
||||
osmo_cc_add_ie_sdp(msg, call->sdp);
|
||||
/* process local briding capability */
|
||||
bridge_socket_client_update(call, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
call = call_create(isdn_ep, DIRECTION_ORIGINATOR, 0, 0, B_MODE_TRANSPARENT);
|
||||
if (!call) {
|
||||
PDEBUG(DDSS1, DEBUG_ERROR, "Cannot create calll instance.\n");
|
||||
PDEBUG(DDSS1, DEBUG_ERROR, "Cannot create call instance.\n");
|
||||
abort();
|
||||
}
|
||||
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;
|
||||
|
||||
/* 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) {
|
||||
release_and_destroy(call, 47, 415/* Unsupported Media*/, 0);
|
||||
return;
|
||||
|
@ -1602,11 +1629,14 @@ void setup_req(call_t *call, osmo_cc_msg_t *msg)
|
|||
user = 2;
|
||||
else
|
||||
user = 3;
|
||||
/* init jitter buffer */
|
||||
call_create_jitter(call, 0);
|
||||
} else {
|
||||
has_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);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* 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);
|
||||
|
@ -2365,22 +2395,18 @@ void cc_message(osmo_cc_endpoint_t *ep, uint32_t callref, osmo_cc_msg_t *msg)
|
|||
break;
|
||||
case OSMO_CC_MSG_SETUP_ACK_REQ: /* more information is needed */
|
||||
osmo_cc_helper_audio_negotiate(msg, &call->cc_session, &call->codec);
|
||||
bridge_process_local(call);
|
||||
setup_ack_req(call, call->l3_pid, msg);
|
||||
break;
|
||||
case OSMO_CC_MSG_PROC_REQ: /* call of endpoint is proceeding */
|
||||
osmo_cc_helper_audio_negotiate(msg, &call->cc_session, &call->codec);
|
||||
bridge_process_local(call);
|
||||
proc_req(call, call->l3_pid, msg, 1);
|
||||
break;
|
||||
case OSMO_CC_MSG_ALERT_REQ: /* call of endpoint is ringing */
|
||||
osmo_cc_helper_audio_negotiate(msg, &call->cc_session, &call->codec);
|
||||
bridge_process_local(call);
|
||||
alert_req(call, call->l3_pid, msg);
|
||||
break;
|
||||
case OSMO_CC_MSG_SETUP_RSP: /* call of endpoint is connected */
|
||||
osmo_cc_helper_audio_negotiate(msg, &call->cc_session, &call->codec);
|
||||
bridge_process_local(call);
|
||||
setup_rsp(call, call->l3_pid, msg);
|
||||
break;
|
||||
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;
|
||||
case OSMO_CC_MSG_PROGRESS_REQ: /* progress */
|
||||
osmo_cc_helper_audio_negotiate(msg, &call->cc_session, &call->codec);
|
||||
bridge_process_local(call);
|
||||
if (isdn_ep->ntmode
|
||||
&& call->state != ISDN_STATE_OUT_OVERLAP
|
||||
&& 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;
|
||||
case OSMO_CC_MSG_DISC_REQ: /* call has been disconnected */
|
||||
osmo_cc_helper_audio_negotiate(msg, &call->cc_session, &call->codec);
|
||||
bridge_process_local(call);
|
||||
if (call->state != ISDN_STATE_IN_SETUP
|
||||
&& call->state != ISDN_STATE_IN_OVERLAP
|
||||
&& call->state != ISDN_STATE_IN_PROCEEDING
|
||||
|
|
491
src/isdn/isdn.c
491
src/isdn/isdn.c
|
@ -17,6 +17,22 @@
|
|||
* 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 <unistd.h>
|
||||
#include <errno.h>
|
||||
|
@ -49,32 +65,6 @@
|
|||
#define B_TIMER_ACTIVATING 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
|
||||
*/
|
||||
|
@ -687,7 +677,7 @@ void isdn_destroy(isdn_t *isdn_ep)
|
|||
}
|
||||
|
||||
/* 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;
|
||||
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->timeouts = timeouts;
|
||||
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->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, **call_p;
|
||||
int rc;
|
||||
|
||||
call = calloc(1, sizeof(*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_mode = mode;
|
||||
call->hold = 0;
|
||||
call->tx_gain = isdn_ep->tx_gain;
|
||||
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;
|
||||
call->isdn_tone.tone = 0;
|
||||
|
||||
/* if any channel requested by constructor */
|
||||
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
|
||||
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);
|
||||
|
||||
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)
|
||||
{
|
||||
call_t **call_p;
|
||||
|
||||
/* be sure to clean up bridge on server */
|
||||
bridge_socket_client_update(call, 0);
|
||||
|
||||
/* free jitter buffer */
|
||||
jitter_destroy(&call->dejitter);
|
||||
jitter_destroy(&call->tx_dejitter);
|
||||
jitter_destroy(&call->conf_dejitter);
|
||||
|
||||
/* remove B-channel relation */
|
||||
drop_bchannel(call);
|
||||
|
@ -863,56 +855,24 @@ void call_destroy(call_t *call)
|
|||
* bchannel handling
|
||||
*/
|
||||
|
||||
/* send control information to the channel (dsp-module) */
|
||||
static void ph_control(int sock, uint32_t c1, uint32_t c2)
|
||||
/* send control information to the channel (HFC hardware bridging) */
|
||||
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 mISDNhead *ctrl = (struct mISDNhead *)buffer;
|
||||
uint32_t *d = (uint32_t *)(buffer + MISDN_HEADER_LEN);
|
||||
int len = 8;
|
||||
struct mISDN_ctrl_req cq;
|
||||
int rc;
|
||||
|
||||
if (sock < 0)
|
||||
return;
|
||||
|
||||
if (c1 == DTMF_TONE_START && c2 == 0)
|
||||
len = 4;
|
||||
PDEBUG(DISDN, DEBUG_DEBUG, "sending IMCTRLREQ 0x%08x, %d, 0x%02x, 0x%02x\n", op, channel, p1, p2);
|
||||
|
||||
PDEBUG(DISDN, DEBUG_DEBUG, "sending PH_CONTROL_REQ %d, %d\n", c1, c2);
|
||||
|
||||
ctrl->prim = PH_CONTROL_REQ;
|
||||
ctrl->id = 0;
|
||||
*d++ = c1;
|
||||
*d++ = c2;
|
||||
rc = sendto(sock, buffer, MISDN_HEADER_LEN + len, 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();
|
||||
}
|
||||
}
|
||||
|
||||
/* 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();
|
||||
}
|
||||
cq.op = op;
|
||||
cq.channel = channel;
|
||||
cq.p1 = p1;
|
||||
cq.p2 = p2;
|
||||
rc = ioctl(sock, IMCTRLREQ, &cq);
|
||||
if (rc < 0)
|
||||
PDEBUG(DISDN, DEBUG_ERROR, "Failed to send IMCTRLREQ to socket %d (errno=%d:%s)\n", sock, errno, strerror(errno));
|
||||
}
|
||||
|
||||
/* 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) {
|
||||
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) {
|
||||
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);
|
||||
|
@ -1000,107 +960,45 @@ static void bchannel_activate(isdn_t *isdn_ep, int index, int activate, int time
|
|||
/* configure B-channel */
|
||||
static void bchannel_configure(isdn_t *isdn_ep, int index)
|
||||
{
|
||||
int channel = index + 1 + (index >= 15);
|
||||
call_t *call;
|
||||
int handle, mode;
|
||||
int handle;
|
||||
|
||||
if (isdn_ep->b_sock[index] <= 0)
|
||||
return;
|
||||
|
||||
handle = isdn_ep->b_sock[index];
|
||||
call = isdn_ep->b_call[index];
|
||||
mode = isdn_ep->b_mode[index];
|
||||
|
||||
/* set dsp features */
|
||||
if (call->txdata) {
|
||||
PDEBUG(DISDN, DEBUG_DEBUG, "PH_CONTROL: set DSP_TXDATA*\n");
|
||||
ph_control(handle, (call->txdata) ? DSP_TXDATA_ON : DSP_TXDATA_OFF, 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);
|
||||
}
|
||||
if (!call->tx_delay && mode == B_MODE_TRANSPARENT) {
|
||||
PDEBUG(DISDN, DEBUG_DEBUG, "PH_CONTROL: set DSP_TX_DEJITTER\n");
|
||||
ph_control(handle, DSP_TX_DEJITTER, 1);
|
||||
}
|
||||
if (call->tx_gain && mode == B_MODE_TRANSPARENT) {
|
||||
PDEBUG(DISDN, DEBUG_DEBUG, "PH_CONTROL: set DSP_VOL_CHANGE_TX\n");
|
||||
ph_control(handle, DSP_VOL_CHANGE_TX, call->tx_gain);
|
||||
}
|
||||
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);
|
||||
}
|
||||
/* set PCM bridge features */
|
||||
if (call->bridge_enabled)
|
||||
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));
|
||||
else
|
||||
im_control(handle, MISDN_CTRL_HFC_PCM_DISC, channel, 0, 0);
|
||||
}
|
||||
|
||||
void bchannel_bridge(call_t *call, int pcm_bridge, int rx_slot, int tx_slot, int rx_bank, int tx_bank)
|
||||
{
|
||||
/* bridge enabled */
|
||||
call->bridge_enabled = pcm_bridge;
|
||||
call->bridge_bank_tx = tx_bank;
|
||||
call->bridge_slot_tx = tx_slot;
|
||||
call->bridge_bank_rx = rx_bank;
|
||||
call->bridge_slot_rx = rx_slot;
|
||||
bchannel_configure(call->isdn_ep, call->b_index);
|
||||
}
|
||||
|
||||
void bchannel_tone(call_t *call, int tone)
|
||||
{
|
||||
call->tone = tone;
|
||||
|
||||
if (call->b_index < 0)
|
||||
return;
|
||||
|
||||
int handle = call->isdn_ep->b_sock[call->b_index];
|
||||
int mode = call->isdn_ep->b_mode[call->b_index];
|
||||
|
||||
if (mode != B_MODE_TRANSPARENT)
|
||||
return;
|
||||
|
||||
if (call->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;
|
||||
isdn_tone_set(&call->isdn_tone, tone);
|
||||
}
|
||||
|
||||
/* 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_configure(isdn_ep, index);
|
||||
state = B_STATE_ACTIVE;
|
||||
call->b_rx_time = 0.0;
|
||||
call->b_transmitting = 0;
|
||||
//FIXME: init buffer state for delay
|
||||
} else {
|
||||
/* 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);
|
||||
}
|
||||
|
||||
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) */
|
||||
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);
|
||||
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) {
|
||||
/* we don't care about confirms, we use rx data to sync tx */
|
||||
case PH_DATA_CNF:
|
||||
if (isdn_ep->b_call[index])
|
||||
bchannel_confirm(isdn_ep, index);
|
||||
break;
|
||||
|
||||
/* 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 PH_CONTROL_IND:
|
||||
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
|
||||
PDEBUG(DISDN, DEBUG_DEBUG, "b-channel is not associated to a call (channel %d), ignoring.\n", channel);
|
||||
break;
|
||||
|
@ -1393,10 +1296,14 @@ void bchannel_ph_sock_receive(void *priv, int channel, uint8_t prim, uint8_t *da
|
|||
return;
|
||||
|
||||
switch (prim) {
|
||||
case PH_PRIM_DATA_CNF:
|
||||
if (isdn_ep->b_call[index])
|
||||
bchannel_confirm(isdn_ep, index);
|
||||
break;
|
||||
case PH_PRIM_DATA_IND:
|
||||
if (isdn_ep->b_call[index]) {
|
||||
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
|
||||
PDEBUG(DISDN, DEBUG_DEBUG, "b-channel is not associated to a call (channel %d), ignoring.\n", channel);
|
||||
break;
|
||||
|
@ -1534,9 +1441,10 @@ static void send_to_rtp(call_t *call, unsigned char *data, int len)
|
|||
return;
|
||||
|
||||
if (call->conference_3pty) {
|
||||
int16_t *audio;
|
||||
int16_t *audio_local;
|
||||
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;
|
||||
|
||||
/* 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 */
|
||||
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
|
||||
g711_decode_ulaw_flipped(data, len, (uint8_t **)&audio, &audio_len);
|
||||
int16_to_samples(samples_local, audio, len);
|
||||
g711_decode_ulaw_flipped(data, len, (uint8_t **)&audio_local, &audio_len);
|
||||
// don't free audio, because we need that later when encoding
|
||||
|
||||
/* 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 */
|
||||
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 */
|
||||
if (other)
|
||||
jitter_load(&other->dejitter, samples_remote_hold, len);
|
||||
jitter_load(&other->conf_dejitter, audio_remote_hold, len);
|
||||
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 */
|
||||
for (i = 0; i < len; i++)
|
||||
mix[i] = samples_remote_active[i] + samples_remote_hold[i]; /* both remote parties */
|
||||
samples_to_int16(audio, mix, len);
|
||||
for (i = 0; i < len; i++) {
|
||||
spl = (int32_t)audio_remote_active[i] + (int32_t)audio_remote_hold[i]; /* both remote parties */
|
||||
if (spl < -32767)
|
||||
spl = -32767;
|
||||
if (spl > 32767)
|
||||
spl = 32767;
|
||||
audio_mix[i] = spl;
|
||||
}
|
||||
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
|
||||
g711_encode_ulaw_flipped((uint8_t *)audio, audio_len, &data, &len);
|
||||
if (call->b_index >= 0) {
|
||||
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));
|
||||
g711_encode_ulaw_flipped((uint8_t *)audio_mix, audio_len, &data, &len);
|
||||
if (call->b_index >= 0 && call->b_transmitting) {
|
||||
jitter_save(&call->tx_dejitter, data, len, 0, 0, 0, 0);
|
||||
}
|
||||
free(data);
|
||||
|
||||
/* mix audio for (active) remote interface and forward */
|
||||
for (i = 0; i < len; i++)
|
||||
mix[i] = samples_local[i] + samples_remote_hold[i]; /* local + remote (hold) party */
|
||||
samples_to_int16(audio, mix, len);
|
||||
for (i = 0; i < len; i++) {
|
||||
spl = audio_local[i] + audio_remote_hold[i]; /* local + remote (on hold) party */
|
||||
if (spl < -32767)
|
||||
spl = -32767;
|
||||
if (spl > 32767)
|
||||
spl = 32767;
|
||||
audio_mix[i] = spl;
|
||||
}
|
||||
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
|
||||
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);
|
||||
free(data);
|
||||
|
||||
/* mix audio for (hold) remote interface and forward */
|
||||
if (other) {
|
||||
for (i = 0; i < len; i++)
|
||||
mix[i] = samples_local[i] + samples_remote_active[i]; /* local + remote (active) party */
|
||||
samples_to_int16(audio, mix, len);
|
||||
for (i = 0; i < len; i++) {
|
||||
spl = audio_local[i] + audio_remote_active[i]; /* local + remote (active) party */
|
||||
if (spl < -32767)
|
||||
spl = -32767;
|
||||
if (spl > 32767)
|
||||
spl = 32767;
|
||||
audio_mix[i] = spl;
|
||||
}
|
||||
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
|
||||
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);
|
||||
free(data);
|
||||
}
|
||||
|
||||
free(audio);
|
||||
free(audio_local);
|
||||
return;
|
||||
}
|
||||
|
||||
/* bridging, don't forward */
|
||||
if (call->bridge)
|
||||
if (call->bridge_enabled)
|
||||
return;
|
||||
|
||||
osmo_cc_rtp_send(call->codec, data, len, 1, len);
|
||||
}
|
||||
|
||||
/* receive audio and control from B-channel */
|
||||
static void bchannel_receive(isdn_t *isdn_ep, int index, struct mISDNhead *hh, unsigned char *data, int len)
|
||||
/* receive audio and control from B-channel, transmit data from jitter buffer accoring to received length */
|
||||
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];
|
||||
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 (len < 4) {
|
||||
PDEBUG(DISDN, DEBUG_ERROR, "SHORT READ OF PH_CONTROL INDICATION\n");
|
||||
return;
|
||||
}
|
||||
if ((cont & (~DTMF_TONE_MASK)) == DTMF_TONE_VAL) {
|
||||
// send_cc_dtmf(call, cont & DTMF_TONE_MASK);
|
||||
// FIXME: DTMF via telephony events??
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (hh->prim != PH_DATA_IND && hh->prim != DL_DATA_IND)
|
||||
if (hh->prim != PH_DATA_IND)
|
||||
return;
|
||||
|
||||
/* add to buffer */
|
||||
while (len) {
|
||||
buffer[(*buffer_pos)++] = *data++;
|
||||
len--;
|
||||
if (!call) {
|
||||
PDEBUG(DISDN, DEBUG_DEBUG, "Dropping b-channel data from channel without call.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
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) {
|
||||
*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)
|
||||
|
@ -1675,8 +1655,8 @@ void isdn_rtp_work(isdn_t *isdn_ep)
|
|||
}
|
||||
}
|
||||
|
||||
/* send audio to B-channel */
|
||||
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)
|
||||
/* send audio from RTP to B-channel's jitter buffer */
|
||||
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;
|
||||
|
||||
|
@ -1684,38 +1664,31 @@ void bchannel_send(struct osmo_cc_session_codec *codec, uint16_t __attribute__((
|
|||
if (call->conference_3pty) {
|
||||
int16_t *audio;
|
||||
int audio_len;
|
||||
sample_t samples[len];
|
||||
/* alaw/ulaw to linear */
|
||||
if (call->isdn_ep->law == 'a')
|
||||
g711_decode_alaw_flipped(data, len, (uint8_t **)&audio, &audio_len);
|
||||
else
|
||||
g711_decode_ulaw_flipped(data, len, (uint8_t **)&audio, &audio_len);
|
||||
int16_to_samples(samples, audio, len);
|
||||
free(audio);
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
/* no conference, just forward to ISDN interface */
|
||||
if (call->b_index >= 0) {
|
||||
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));
|
||||
}
|
||||
jitter_save(&call->tx_dejitter, data, len, 1, sequence_number, timestamp, ssrc);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1955,6 +1928,15 @@ int isdn_open(isdn_t *isdn_ep)
|
|||
if (isdn_ep->portname)
|
||||
free(isdn_ep->portname);
|
||||
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->pri = pri;
|
||||
isdn_ep->ptp = ptp;
|
||||
|
@ -1978,9 +1960,6 @@ int isdn_open(isdn_t *isdn_ep)
|
|||
if (isdn_ep->ntmode && !isdn_ep->ptp)
|
||||
isdn_ep->l2link = 1;
|
||||
|
||||
if (isdn_ep->l2sock)
|
||||
PDEBUG(DISDN, DEBUG_DEBUG, "using 'mISDN_dsp.o' module\n");
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
|
@ -2155,7 +2134,7 @@ void isdn_bchannel_work(isdn_t *isdn_ep)
|
|||
for (i = 0; i < isdn_ep->b_num; i++) {
|
||||
do {
|
||||
if (isdn_ep->b_sock[i] > 0)
|
||||
w = bchannel_kernel_sock_work(isdn_ep, i);
|
||||
w = bchannel_kernel_sock_receive(isdn_ep, i);
|
||||
else
|
||||
w = 0;
|
||||
} while (w);
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "../libsample/sample.h"
|
||||
#include "../libjitter/jitter.h"
|
||||
#include "../libph_socket/ph_socket.h"
|
||||
#include "tones.h"
|
||||
|
||||
#define B_MODE_TRANSPARENT 0
|
||||
#define B_MODE_HDLC 1
|
||||
|
@ -78,10 +79,6 @@ typedef struct isdn {
|
|||
int serving_location; /* who we serve when sending causes towards interface */
|
||||
const char *timeouts;
|
||||
int tx_delay;
|
||||
int tx_gain;
|
||||
int rx_gain;
|
||||
const char *pipeline;
|
||||
int dtmf;
|
||||
int local_tones;
|
||||
|
||||
/* osmo-cc */
|
||||
|
@ -117,6 +114,11 @@ typedef struct isdn {
|
|||
uint8_t b_buffer[128][160];
|
||||
int b_buffer_pos[128];
|
||||
unsigned char l2mask[16]; /* 128 bits for each tei */
|
||||
|
||||
/* bridging */
|
||||
int bridge_possible;
|
||||
int bridge_cardnum;
|
||||
int bridge_portnum;
|
||||
} isdn_t;
|
||||
|
||||
typedef struct call_list {
|
||||
|
@ -126,18 +128,9 @@ typedef struct call_list {
|
|||
/* mISDN states */
|
||||
uint32_t l3_pid;
|
||||
uint16_t l3_ces;
|
||||
int tx_gain;
|
||||
int rx_gain;
|
||||
int mute;
|
||||
int txdata;
|
||||
int tx_delay;
|
||||
int echo;
|
||||
uint32_t bridge;
|
||||
int tone;
|
||||
int rxoff;
|
||||
int dtmf;
|
||||
int dtmf_threshold;
|
||||
const char *pipeline;
|
||||
|
||||
/* tone states */
|
||||
struct isdn_tone isdn_tone;
|
||||
|
||||
/* osmo-cc states */
|
||||
uint32_t cc_callref;
|
||||
|
@ -154,6 +147,8 @@ typedef struct call_list {
|
|||
int b_exclusive;
|
||||
int b_reserve;
|
||||
int b_mode;
|
||||
int b_transmitting;
|
||||
double b_rx_time;
|
||||
|
||||
/* call states */
|
||||
int direction; /* originator or terminator of call */
|
||||
|
@ -172,16 +167,19 @@ typedef struct call_list {
|
|||
uint8_t park_callid[8];
|
||||
|
||||
/* bridge states */
|
||||
int local_bridge; /* if local peer can bridge */
|
||||
int remote_bridge; /* if remote peer can bridge */
|
||||
int can_bridge; /* last state sent to the server */
|
||||
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_t dejitter;
|
||||
/* jitter buffer for tx and 3pty call */
|
||||
jitter_t tx_dejitter;
|
||||
jitter_t conf_dejitter;
|
||||
|
||||
} call_t;
|
||||
|
||||
int check_mISDN_dsp(void);
|
||||
|
||||
/* channel selection */
|
||||
int hunt_bchannel_in(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_t *isdn_create(void);
|
||||
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);
|
||||
void isdn_close(isdn_t *isdn_ep);
|
||||
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_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);
|
||||
|
||||
/* channel allocation and handling */
|
||||
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);
|
||||
int seize_bchannel(call_t *call, int channel, int exclusive);
|
||||
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);
|
||||
|
||||
|
|
122
src/isdn/main.c
122
src/isdn/main.c
|
@ -24,6 +24,7 @@
|
|||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <sched.h>
|
||||
#include "../libdebug/debug.h"
|
||||
#include "../liboptions/options.h"
|
||||
#include "../libg711/g711.h"
|
||||
|
@ -48,13 +49,13 @@ static const char *channel_out = NULL;
|
|||
static const char *channel_in = NULL;
|
||||
static const char *timeouts = NULL;
|
||||
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 debug_mISDN = 0;
|
||||
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
|
||||
static int cc_argc = 0;
|
||||
static const char *cc_argv[MAX_CC_ARGS];
|
||||
|
@ -118,23 +119,20 @@ static void print_help()
|
|||
printf(" --tx-delay <ms>\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(" This feature turns off the dejittering.\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(" This feature alters dejittering strategy.\n");
|
||||
printf(" -T --local-tones german | oldgerman | american\n");
|
||||
printf(" Send locally generated tones, if not provided by remote interface.\n");
|
||||
printf(" -D --debug-misdn\n");
|
||||
printf(" Enables mISDN stack debugging.\n");
|
||||
printf(" --serving-location (see Q.931)\n");
|
||||
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(" 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_DTMF 264
|
||||
#define OPT_SERVING 265
|
||||
#define OPT_PCM_SLOTS 266
|
||||
#define OPT_BR_ONLY 267
|
||||
|
||||
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_TIMEOUTS, "timeouts", 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('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);
|
||||
}
|
||||
|
||||
|
@ -234,18 +234,6 @@ static int handle_options(int short_option, int argi, char **argv)
|
|||
case OPT_TX_DELAY:
|
||||
tx_delay = atoi(argv[argi]);
|
||||
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':
|
||||
if (!strcasecmp(argv[argi], "american"))
|
||||
local_tones = TONES_TYPE_AMERICAN;
|
||||
|
@ -264,6 +252,18 @@ static int handle_options(int short_option, int argi, char **argv)
|
|||
case OPT_SERVING:
|
||||
serving_location = atoi(argv[argi]);
|
||||
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':
|
||||
if (!strcasecmp(argv[argi], "help")) {
|
||||
osmo_cc_help();
|
||||
|
@ -331,6 +331,17 @@ int main(int argc, char *argv[])
|
|||
if (argi <= 0)
|
||||
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) {
|
||||
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;
|
||||
|
@ -340,13 +351,6 @@ int main(int argc, char *argv[])
|
|||
goto error;
|
||||
}
|
||||
|
||||
/* check for DSP (kernel only) */
|
||||
if (misdn_kernel) {
|
||||
rc = check_mISDN_dsp();
|
||||
if (rc)
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* init user space mISDN */
|
||||
if (misdn_user) {
|
||||
rc = mISDNInit((debug_mISDN) ? 0xffffffff : 0);
|
||||
|
@ -365,20 +369,17 @@ int main(int argc, char *argv[])
|
|||
layer3_initialized = 1;
|
||||
mISDN_set_debug_level((debug_mISDN) ? 0xfffffeff : 0);
|
||||
|
||||
/* change tones to ulaw */
|
||||
if (law == 'u')
|
||||
isdn_tone_generate_ulaw_samples();
|
||||
|
||||
/* 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) {
|
||||
PDEBUG(DISDN, DEBUG_ERROR, "mISDN initializing failed!\n");
|
||||
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);
|
||||
if (rc) {
|
||||
PDEBUG(DISDN, DEBUG_ERROR, "mISDN open failed!\n");
|
||||
|
@ -388,10 +389,22 @@ int main(int argc, char *argv[])
|
|||
while ((p = strchr(portname, '/')))
|
||||
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)
|
||||
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(SIGHUP, sighandler);
|
||||
signal(SIGTERM, sighandler);
|
||||
|
@ -402,6 +415,7 @@ int main(int argc, char *argv[])
|
|||
process_timer();
|
||||
isdn_bchannel_work(isdn_ep);
|
||||
isdn_rtp_work(isdn_ep);
|
||||
bridge_socket_client_work(isdn_ep);
|
||||
if (misdn_user) {
|
||||
/* run workers of mISDN stacks in user space */
|
||||
mISDN_work();
|
||||
|
@ -410,7 +424,6 @@ int main(int argc, char *argv[])
|
|||
w = 0;
|
||||
w |= osmo_cc_handle();
|
||||
w |= isdn_dchannel_work(isdn_ep);
|
||||
w |= bridge_work(isdn_ep);
|
||||
if (misdn_user) {
|
||||
/* run workers of mISDN stacks in user space */
|
||||
w |= ph_socket_work(&ph_drv.ph_socket);
|
||||
|
@ -426,6 +439,15 @@ int main(int argc, char *argv[])
|
|||
signal(SIGTERM, 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:
|
||||
if (isdn_ep) {
|
||||
osmo_cc_delete(&isdn_ep->cc_ep);
|
||||
|
@ -441,8 +463,6 @@ error:
|
|||
if (misdn_initialized)
|
||||
mISDN_cleanup();
|
||||
|
||||
bridge_msg_close();
|
||||
|
||||
options_free();
|
||||
|
||||
return 0;
|
||||
|
|
Loading…
Reference in New Issue