diff options
author | Harald Welte <laforge@netfilter.org> | 2009-12-20 17:04:40 +0100 |
---|---|---|
committer | Harald Welte <laforge@netfilter.org> | 2009-12-20 17:04:40 +0100 |
commit | a03790232316edfc87de94012b110d8d8e2067f2 (patch) | |
tree | 03e17984e7100770f6eeb4b3d11d90cca08360f4 /openbsc/src/handover_logic.c | |
parent | a72273e176cf19a4d1352736a71698445d79b8fd (diff) |
[handover] implement TCH RTP stream handover
This patch takes care of handling the RTP streams / sockets during
an in-call handover from one BTS to another BTS.
It only works in combination with rtp_proxy mode.
Diffstat (limited to 'openbsc/src/handover_logic.c')
-rw-r--r-- | openbsc/src/handover_logic.c | 70 |
1 files changed, 69 insertions, 1 deletions
diff --git a/openbsc/src/handover_logic.c b/openbsc/src/handover_logic.c index 2c7549761..3007d2581 100644 --- a/openbsc/src/handover_logic.c +++ b/openbsc/src/handover_logic.c @@ -40,6 +40,7 @@ #include <openbsc/signal.h> #include <openbsc/talloc.h> #include <openbsc/transaction.h> +#include <openbsc/rtp_proxy.h> struct bsc_handover { struct llist_head list; @@ -173,6 +174,10 @@ static int ho_chan_activ_ack(struct gsm_lchan *new_lchan) ho->T3103.data = ho; bsc_schedule_timer(&ho->T3103, 10, 0); + /* create a RTP connection */ + if (is_ipaccess_bts(new_lchan->ts->trx->bts)) + rsl_ipacc_crcx(new_lchan); + return 0; } @@ -213,7 +218,6 @@ static int ho_gsm48_ho_compl(struct gsm_lchan *new_lchan) trans_lchan_change(ho->old_lchan, new_lchan); /* do something to re-route the actual speech frames ! */ - //tch_remap(ho->old_lchan, ho->new_lchan); talloc_free(ho); @@ -255,6 +259,61 @@ static int ho_rsl_detect(struct gsm_lchan *new_lchan) return 0; } +static int ho_ipac_crcx_ack(struct gsm_lchan *new_lchan) +{ + struct bsc_handover *ho; + struct rtp_socket *old_rs, *new_rs, *other_rs; + + ho = bsc_ho_by_new_lchan(new_lchan); + if (!ho) { + LOGP(DHO, LOGL_ERROR, "unable to find HO record\n"); + return -ENODEV; + } + + if (ipacc_rtp_direct) { + LOGP(DHO, LOGL_ERROR, "unable to handover in direct RTP mode\n"); + return 0; + } + + /* RTP Proxy mode */ + new_rs = new_lchan->abis_ip.rtp_socket; + old_rs = ho->old_lchan->abis_ip.rtp_socket; + + if (!new_rs) { + LOGP(DHO, LOGL_ERROR, "no RTP socket for new_lchan\n"); + return -EIO; + } + + rsl_ipacc_mdcx_to_rtpsock(new_lchan); + + if (!old_rs) { + LOGP(DHO, LOGL_ERROR, "no RTP socekt for old_lchan\n"); + return -EIO; + } + + /* copy rx_action and reference to other sock */ + new_rs->rx_action = old_rs->rx_action; + new_rs->tx_action = old_rs->tx_action; + new_rs->transmit = old_rs->transmit; + + switch (ho->old_lchan->abis_ip.rtp_socket->rx_action) { + case RTP_PROXY: + other_rs = old_rs->proxy.other_sock; + rtp_socket_proxy(new_rs, other_rs); + /* delete reference to other end socket to prevent + * rtp_socket_free() from removing the inverse reference */ + old_rs->proxy.other_sock = NULL; + break; + case RTP_RECV_UPSTREAM: + new_rs->receive = old_rs->receive; + break; + case RTP_NONE: + break; + } + + return 0; +} + static int ho_logic_sig_cb(unsigned int subsys, unsigned int signal, void *handler_data, void *signal_data) { @@ -276,6 +335,14 @@ static int ho_logic_sig_cb(unsigned int subsys, unsigned int signal, return ho_gsm48_ho_fail(lchan); } break; + case SS_ABISIP: + lchan = signal_data; + switch (signal) { + case S_ABISIP_CRCX_ACK: + return ho_ipac_crcx_ack(lchan); + break; + } + break; default: break; } @@ -286,4 +353,5 @@ static int ho_logic_sig_cb(unsigned int subsys, unsigned int signal, static __attribute__((constructor)) void on_dso_load_ho_logic(void) { register_signal_handler(SS_LCHAN, ho_logic_sig_cb, NULL); + register_signal_handler(SS_ABISIP, ho_logic_sig_cb, NULL); } |