aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorNeels Hofmeyr <nhofmeyr@sysmocom.de>2023-11-17 04:12:29 +0100
committerKeith Whyte <keith@rhizomatica.org>2023-11-29 23:54:56 +0000
commit1cfc59e608d1746ef83d5f6f8464ee699c7d78ba (patch)
tree7cd781ea858b2691c006e140f5937323339eb048 /src
parent683d140d270582493bd65c5d7f6c13726bfb572f (diff)
implement re-assignment to match codecsrhizomatica/testing
This is the last missing piece that allows osmo-msc to make good TFO codecs choices. Since the codec_filter, osmo-msc properly gathers codec options and limitations. But the MO call leg still assigns a voice channel before getting a response from the MT call leg, and is then stuck with that. Add the capability to adjust the MO call leg's codec in case the MT side needs a different codec for TFO. This is only relevant for 2G; on 3G we always have AMR/IuUP. For inter-MSC handover, keep the behavior unchanged: offer only the currently assigned codec to the remote side. Codec-changing HO should be equally trivial to implement, but that is for another day. msc_vlr_test_call's codec tests are adjusted to test the new feature in Ib933554f826c1b4347dfa3f6c4f6fe086be8b133. For now, avoid change in these tests by validating the first codec in SDP lists only. Related: OS#6258 Related: osmo-ttcn3-hacks I402ed0523a2a87b83f29c5577b2c828102005d53 Change-Id: I8760feaa8598047369ef8c3ab2673013bac8ac8a
Diffstat (limited to 'src')
-rw-r--r--src/libmsc/codec_filter.c42
-rw-r--r--src/libmsc/gsm_04_08_cc.c44
-rw-r--r--src/libmsc/msc_a.c4
-rw-r--r--src/libmsc/msc_ho.c10
4 files changed, 54 insertions, 46 deletions
diff --git a/src/libmsc/codec_filter.c b/src/libmsc/codec_filter.c
index a9d93a70d..7511f9026 100644
--- a/src/libmsc/codec_filter.c
+++ b/src/libmsc/codec_filter.c
@@ -98,46 +98,16 @@ int codec_filter_run(struct codec_filter *codec_filter, struct sdp_msg *result,
if (remote->audio_codecs.count)
sdp_audio_codecs_intersection(r, &remote->audio_codecs, true);
-#if 0
- /* Future: If osmo-msc were able to trigger a re-assignment after the remote side has picked a codec mismatching
- * the initial Assignment, then this code here would make sense: keep the other codecs as available to choose
- * from, but put the currently assigned codec in the first position. So far we only offer the single assigned
- * codec, because we have no way to deal with the remote side picking a different codec.
- * Another approach would be to postpone assignment until we know the codecs from the remote side. */
if (sdp_audio_codec_is_set(a)) {
/* Assignment has completed, the chosen codec should be the first of the resulting SDP.
- * Make sure this is actually listed in the result SDP and move to first place. */
+ * If present, make sure this is listed in first place.
+ * If 'select' is NULL, the assigned codec is not present in the intersection of possible choices for
+ * TFO. Just omit the assigned codec from the filter result, and it is the CC code's responsibility to
+ * detect this and assign a working codec instead. */
struct sdp_audio_codec *select = sdp_audio_codecs_by_descr(r, a);
-
- if (!select) {
- /* Not present. Add. */
- if (sdp_audio_codec_by_payload_type(r, a->payload_type, false)) {
- /* Oh crunch, that payload type number is already in use.
- * Find an unused one. */
- for (a->payload_type = 96; a->payload_type <= 127; a->payload_type++) {
- if (!sdp_audio_codec_by_payload_type(r, a->payload_type, false))
- break;
- }
-
- if (a->payload_type > 127)
- return -ENOSPC;
- }
- select = sdp_audio_codecs_add_copy(r, a);
- }
-
- sdp_audio_codecs_select(r, select);
- }
-#else
- /* Currently, osmo-msc does not trigger re-assignment if the remote side has picked a codec that is different
- * from the already assigned codec.
- * So, if locally, Assignment has already chosen a codec, this is the single definitive result to be used
- * towards the CN. */
- if (sdp_audio_codec_is_set(a)) {
- /* Assignment has completed, the chosen codec should be the the only possible one. */
- *r = (struct sdp_audio_codecs){};
- sdp_audio_codecs_add_copy(r, a);
+ if (select)
+ sdp_audio_codecs_select(r, select);
}
-#endif
return 0;
}
diff --git a/src/libmsc/gsm_04_08_cc.c b/src/libmsc/gsm_04_08_cc.c
index a4c2ba258..7bab2554a 100644
--- a/src/libmsc/gsm_04_08_cc.c
+++ b/src/libmsc/gsm_04_08_cc.c
@@ -283,7 +283,16 @@ static void _log_mncc_rx_tx(const char *file, int line,
break;
}
- if (sdp && sdp[0] && (sdp_msg_from_sdp_str(&sdp_msg, sdp) == 0)) {
+ if (sdp && sdp[0]) {
+ int rc = sdp_msg_from_sdp_str(&sdp_msg, sdp);
+ if (rc != 0) {
+ LOG_TRANS_CAT_SRC(trans, DMNCC, LOGL_ERROR, file, line, "%s %s: invalid SDP message (trying anyway)\n",
+ rx_tx,
+ get_mncc_name(mncc->msg_type));
+ LOG_TRANS_CAT_SRC(trans, DMNCC, LOGL_DEBUG, file, line, "erratic SDP: %s\n",
+ osmo_quote_cstr_c(OTC_SELECT, sdp, -1));
+ return;
+ }
LOG_TRANS_CAT_SRC(trans, DMNCC, LOGL_DEBUG, file, line, "%s %s (RTP=%s)\n",
rx_tx,
get_mncc_name(mncc->msg_type),
@@ -1130,6 +1139,7 @@ static int gsm48_cc_tx_alerting(struct gsm_trans *trans, void *arg)
struct gsm_mncc *alerting = arg;
struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 CC ALERT");
struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
+ struct codec_filter *codecs = &trans->cc.codecs;
int rc;
gh->msg_type = GSM48_MT_CC_ALERTING;
@@ -1162,7 +1172,23 @@ static int gsm48_cc_tx_alerting(struct gsm_trans *trans, void *arg)
}
}
- return trans_tx_gsm48(trans, msg);
+ /* First handle the MNCC event */
+ rc = trans_tx_gsm48(trans, msg);
+
+ /* Now see if the codecs are fine for TFO:
+ * This is the first time we are told the MT call leg's codec capabilities, via the MNCC_ALERT_REQ from MT to
+ * MO. Here, at MO, we have already assigned a specific codec. If the MT call leg does not support this codec,
+ * but the MO does support one of MT's codecs, we need to re-assign our assigned codec to match MT. */
+ if (sdp_audio_codec_is_set(&codecs->assignment)
+ && trans->cc.remote.audio_codecs.count
+ && !sdp_audio_codecs_by_descr(&trans->cc.remote.audio_codecs, &codecs->assignment)) {
+ LOG_TRANS(trans, LOGL_INFO, "Remote call leg mismatches assigned codec: %s\n",
+ codec_filter_to_str(&trans->cc.codecs, &trans->cc.local, &trans->cc.remote));
+
+ msc_a_tx_assignment(trans->msc_a);
+ }
+
+ return rc;
}
static int gsm48_cc_tx_progress(struct gsm_trans *trans, void *arg)
@@ -2055,17 +2081,23 @@ int cc_on_assignment_done(struct gsm_trans *trans)
switch (trans->cc.state) {
case GSM_CSTATE_INITIATED:
case GSM_CSTATE_MO_CALL_PROC:
- /* MO call */
+ /* MO call, send ACK in form of an MNCC_RTP_CREATE (below) */
break;
case GSM_CSTATE_CALL_RECEIVED:
case GSM_CSTATE_MO_TERM_CALL_CONF:
- /* MT call */
+ /* MT call, send ACK in form of an MNCC_RTP_CREATE (below) */
break;
case GSM_CSTATE_ACTIVE:
- /* already active. MNCC finished before Abis completed the Assignment. */
- break;
+ /* already active. We decided to re-assign later on during the call - at time of writing this never
+ * happens. */
+ case GSM_CSTATE_CALL_DELIVERED:
+ case GSM_CSTATE_CONNECT_IND:
+ /* MNCC has progressed past the initial assignment. Usually it means that this happened: after
+ * MNCC_ALERT_REQ, MO has triggered a re-assignment, to adjust MO's codec to MT's codec. */
+ LOG_TRANS(trans, LOGL_DEBUG, "Re-Assignment complete\n");
+ return 0;
default:
LOG_TRANS(trans, LOGL_ERROR, "Assignment done in unexpected CC state: %d\n", trans->cc.state);
diff --git a/src/libmsc/msc_a.c b/src/libmsc/msc_a.c
index e64b54d8f..c10afb8e3 100644
--- a/src/libmsc/msc_a.c
+++ b/src/libmsc/msc_a.c
@@ -636,7 +636,7 @@ int msc_a_ensure_cn_local_rtp(struct msc_a *msc_a, struct gsm_trans *cc_trans)
}
/* The MGW has given us a local IP address for the RAN side. Ready to start the Assignment of a voice channel. */
-static void msc_a_call_leg_ran_local_addr_available(struct msc_a *msc_a)
+void msc_a_tx_assignment(struct msc_a *msc_a)
{
struct ran_msg msg;
struct gsm_trans *cc_trans = msc_a->cc.active_trans;
@@ -804,7 +804,7 @@ static void msc_a_fsm_communicating(struct osmo_fsm_inst *fi, uint32_t event, vo
rtps->use_osmux ? "yes" : "no", rtps->local_osmux_cid);
switch (rtps->dir) {
case RTP_TO_RAN:
- msc_a_call_leg_ran_local_addr_available(msc_a);
+ msc_a_tx_assignment(msc_a);
return;
case RTP_TO_CN:
cc_on_cn_local_rtp_port_known(rtps->for_trans);
diff --git a/src/libmsc/msc_ho.c b/src/libmsc/msc_ho.c
index f82697503..47f000b2f 100644
--- a/src/libmsc/msc_ho.c
+++ b/src/libmsc/msc_ho.c
@@ -380,7 +380,7 @@ static void msc_ho_send_handover_request(struct msc_a *msc_a)
struct vlr_subscr *vsub = msc_a_vsub(msc_a);
struct gsm_network *net = msc_a_net(msc_a);
struct gsm0808_channel_type channel_type;
- struct gsm0808_speech_codec_list scl;
+ struct gsm0808_speech_codec_list scl = {};
struct gsm_trans *cc_trans = msc_a->cc.active_trans;
struct ran_msg ran_enc_msg = {
.msg_type = RAN_MSG_HANDOVER_REQUEST,
@@ -442,7 +442,13 @@ static void msc_ho_send_handover_request(struct msc_a *msc_a)
ran_enc_msg.handover_request.call_id_present = true;
ran_enc_msg.handover_request.call_id = cc_trans->call_id;
- sdp_audio_codecs_to_speech_codec_list(&scl, &cc_trans->cc.local.audio_codecs);
+ /* Call assignment is now capable of re-assigning to overcome a codec mismatch with the remote call leg.
+ * But for inter-MSC handover, that is not supported yet. So keep here the old limitation of only
+ * offering the assigned codec. */
+ if (sdp_audio_codec_is_set(&cc_trans->cc.codecs.assignment))
+ sdp_audio_codec_to_speech_codec_list(&scl, &cc_trans->cc.codecs.assignment);
+ else
+ sdp_audio_codecs_to_speech_codec_list(&scl, &cc_trans->cc.local.audio_codecs);
if (!scl.len) {
msc_ho_failed(msc_a, GSM0808_CAUSE_EQUIPMENT_FAILURE, "Failed to compose"
" Codec List (MSC Preferred) for Handover Request message\n");