<p>Harald Welte <strong>merged</strong> this change.</p><p><a href="https://gerrit.osmocom.org/12625">View Change</a></p><div style="white-space:pre-wrap">Approvals:
Jenkins Builder: Verified
tnt: Looks good to me, but someone else must approve
Harald Welte: Looks good to me, approved
</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">assignment_fsm: fix channel allocator preferences<br><br>When the MSC allocates a channel through the ASSIGNMENT REQUEST, it may<br>ask for a TCH/H and a TCH/F at the same time and tell which of the two<br>types it prefers.<br><br>The process of channel allocation currently selects, based on the BTS,<br>MSC and MS capabilites exactly one apropriate codec/rate (e.g. TCH/H)<br>and then tries to allocate it. If that allocation fails, there is no way<br>to try the second choice and the assignment fails.<br><br>For example: The MSC asks for TCH/F and TCH/H, prefering TCH/F, then the<br>channel allocator will try TCH/F and if it fails (all TCH/F are<br>currently in use), then TCH/H is never tried.<br><br>Since the BSC currently only trys the first best codec/rate that is<br>supported it also ignores the preference.<br><br>Lets fix those problems by including the preference information and both<br>possible codec/rate settings into the channel allocation decision.<br><br>Change-Id: I5239e05c1cfbcb8af28f43373a58fa6c2d216c51<br>Related: OS#3503<br>---<br>M include/osmocom/bsc/codec_pref.h<br>M include/osmocom/bsc/gsm_data.h<br>M src/osmo-bsc/assignment_fsm.c<br>M src/osmo-bsc/bsc_vty.c<br>M src/osmo-bsc/codec_pref.c<br>M src/osmo-bsc/handover_fsm.c<br>M src/osmo-bsc/osmo_bsc_bssap.c<br>M tests/codec_pref/codec_pref_test.c<br>8 files changed, 321 insertions(+), 113 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/osmocom/bsc/codec_pref.h b/include/osmocom/bsc/codec_pref.h</span><br><span>index 51340c1..adefe04 100644</span><br><span>--- a/include/osmocom/bsc/codec_pref.h</span><br><span>+++ b/include/osmocom/bsc/codec_pref.h</span><br><span>@@ -9,14 +9,19 @@</span><br><span> struct bts_codec_conf;</span><br><span> struct bsc_msc_data;</span><br><span> struct gsm_bts;</span><br><span style="color: hsl(120, 100%, 40%);">+struct channel_mode_and_rate;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-int match_codec_pref(enum gsm48_chan_mode *chan_mode,</span><br><span style="color: hsl(0, 100%, 40%);">- bool *full_rate,</span><br><span style="color: hsl(0, 100%, 40%);">- uint16_t *s15_s0,</span><br><span style="color: hsl(120, 100%, 40%);">+enum rate_pref {</span><br><span style="color: hsl(120, 100%, 40%);">+ RATE_PREF_NONE,</span><br><span style="color: hsl(120, 100%, 40%);">+ RATE_PREF_HR,</span><br><span style="color: hsl(120, 100%, 40%);">+ RATE_PREF_FR,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int match_codec_pref(struct channel_mode_and_rate *ch_mode_rate,</span><br><span> const struct gsm0808_channel_type *ct,</span><br><span> const struct gsm0808_speech_codec_list *scl,</span><br><span> const struct bsc_msc_data *msc,</span><br><span style="color: hsl(0, 100%, 40%);">- const struct gsm_bts *bts);</span><br><span style="color: hsl(120, 100%, 40%);">+ const struct gsm_bts *bts, enum rate_pref rate_pref);</span><br><span> </span><br><span> void gen_bss_supported_codec_list(struct gsm0808_speech_codec_list *scl,</span><br><span> const struct bsc_msc_data *msc,</span><br><span>diff --git a/include/osmocom/bsc/gsm_data.h b/include/osmocom/bsc/gsm_data.h</span><br><span>index f6c5129..4d27a2e 100644</span><br><span>--- a/include/osmocom/bsc/gsm_data.h</span><br><span>+++ b/include/osmocom/bsc/gsm_data.h</span><br><span>@@ -99,6 +99,12 @@</span><br><span> SUBSCR_SCCP_ST_CONNECTED</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct channel_mode_and_rate {</span><br><span style="color: hsl(120, 100%, 40%);">+ enum gsm48_chan_mode chan_mode;</span><br><span style="color: hsl(120, 100%, 40%);">+ bool full_rate;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint16_t s15_s0;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* Information retrieved during an Assignment Request from the MSC. This is storage of the Assignment instructions</span><br><span> * parsed from the Assignment Request message, to pass on until the gscon and assignment FSMs have decided whether an</span><br><span> * Assignment is actually going to be carried out. Should remain unchanged after initial decoding. */</span><br><span>@@ -110,9 +116,12 @@</span><br><span> char msc_rtp_addr[INET_ADDRSTRLEN];</span><br><span> uint16_t msc_rtp_port;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- enum gsm48_chan_mode chan_mode;</span><br><span style="color: hsl(0, 100%, 40%);">- bool full_rate;</span><br><span style="color: hsl(0, 100%, 40%);">- uint16_t s15_s0;</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Prefered rate/codec setting (mandatory) */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct channel_mode_and_rate ch_mode_rate_pref;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Alternate rate/codec setting (optional) */</span><br><span style="color: hsl(120, 100%, 40%);">+ bool ch_mode_rate_alt_present;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct channel_mode_and_rate ch_mode_rate_alt;</span><br><span> };</span><br><span> </span><br><span> /* State of an ongoing Assignment, while the assignment_fsm is still busy. This serves as state separation to keep the</span><br><span>@@ -629,6 +638,13 @@</span><br><span> struct gsm48_req_ref *rqd_ref;</span><br><span> </span><br><span> struct gsm_subscriber_connection *conn;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Depending on the preferences that where submitted together with</span><br><span style="color: hsl(120, 100%, 40%);">+ * the assignment and the current channel load, the BSC has to select</span><br><span style="color: hsl(120, 100%, 40%);">+ * one of the offered codec/rates. The final selection by the BSC is</span><br><span style="color: hsl(120, 100%, 40%);">+ * stored here and is used when sending the assignment complete or</span><br><span style="color: hsl(120, 100%, 40%);">+ * when performing a handover procedure. */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct channel_mode_and_rate ch_mode_rate;</span><br><span> };</span><br><span> </span><br><span> /* One Timeslot in a TRX */</span><br><span>diff --git a/src/osmo-bsc/assignment_fsm.c b/src/osmo-bsc/assignment_fsm.c</span><br><span>index 2ad3959..67937d6 100644</span><br><span>--- a/src/osmo-bsc/assignment_fsm.c</span><br><span>+++ b/src/osmo-bsc/assignment_fsm.c</span><br><span>@@ -170,7 +170,7 @@</span><br><span> if (gscon_is_aoip(conn)) {</span><br><span> /* Extrapolate speech codec from speech mode */</span><br><span> gsm0808_speech_codec_from_chan_type(&sc, perm_spch);</span><br><span style="color: hsl(0, 100%, 40%);">- sc.cfg = conn->assignment.req.s15_s0;</span><br><span style="color: hsl(120, 100%, 40%);">+ sc.cfg = conn->lchan->ch_mode_rate.s15_s0;</span><br><span> sc_ptr = ≻</span><br><span> }</span><br><span> }</span><br><span>@@ -248,9 +248,11 @@</span><br><span> new_lchan->nr);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static bool lchan_type_compat_with_mode(enum gsm_chan_t type,</span><br><span style="color: hsl(0, 100%, 40%);">- enum gsm48_chan_mode chan_mode, int full_rate)</span><br><span style="color: hsl(120, 100%, 40%);">+static bool lchan_type_compat_with_mode(enum gsm_chan_t type, const struct channel_mode_and_rate *ch_mode_rate)</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+ enum gsm48_chan_mode chan_mode = ch_mode_rate->chan_mode;</span><br><span style="color: hsl(120, 100%, 40%);">+ bool full_rate = ch_mode_rate->full_rate;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> switch (chan_mode) {</span><br><span> case GSM48_CMODE_SIGN:</span><br><span> switch (type) {</span><br><span>@@ -293,6 +295,107 @@</span><br><span> OSMO_ASSERT(osmo_fsm_register(&assignment_fsm) == 0);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static int check_requires_voice(bool *requires_voice, enum gsm48_chan_mode chan_mode)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ *requires_voice = false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (chan_mode) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case GSM48_CMODE_SPEECH_V1:</span><br><span style="color: hsl(120, 100%, 40%);">+ case GSM48_CMODE_SPEECH_EFR:</span><br><span style="color: hsl(120, 100%, 40%);">+ case GSM48_CMODE_SPEECH_AMR:</span><br><span style="color: hsl(120, 100%, 40%);">+ *requires_voice = true;</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case GSM48_CMODE_SIGN:</span><br><span style="color: hsl(120, 100%, 40%);">+ *requires_voice = false;</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ default:</span><br><span style="color: hsl(120, 100%, 40%);">+ return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Check if the incoming assignment requests requires a voice stream or not,</span><br><span style="color: hsl(120, 100%, 40%);">+ * we will look at the preferred and the alternate channel mode and also make</span><br><span style="color: hsl(120, 100%, 40%);">+ * sure that both are consistent. */</span><br><span style="color: hsl(120, 100%, 40%);">+static int check_requires_voice_stream(struct gsm_subscriber_connection *conn)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ bool result_requires_voice_alt;</span><br><span style="color: hsl(120, 100%, 40%);">+ bool result_requires_voice_pref;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct assignment_request *req = &conn->assignment.req;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_fsm_inst *fi = conn->fi;</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* When the assignment request indicates that there is an alternate</span><br><span style="color: hsl(120, 100%, 40%);">+ * rate available (e.g. "Full or Half rate channel, Half rate</span><br><span style="color: hsl(120, 100%, 40%);">+ * preferred..."), then both must be either voice or either signalling,</span><br><span style="color: hsl(120, 100%, 40%);">+ * a mismatch is not permitted */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Check the prefered setting */</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = check_requires_voice(&result_requires_voice_pref, req->ch_mode_rate_pref.chan_mode);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ assignment_fail(GSM0808_CAUSE_REQ_CODEC_TYPE_OR_CONFIG_NOT_SUPP,</span><br><span style="color: hsl(120, 100%, 40%);">+ "Prefered channel mode not supported: %s",</span><br><span style="color: hsl(120, 100%, 40%);">+ gsm48_chan_mode_name(req->ch_mode_rate_pref.chan_mode));</span><br><span style="color: hsl(120, 100%, 40%);">+ return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ conn->assignment.requires_voice_stream = result_requires_voice_pref;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* If there is an alternate setting, check that one as well */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!req->ch_mode_rate_alt_present)</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = check_requires_voice(&result_requires_voice_alt, req->ch_mode_rate_alt.chan_mode);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ assignment_fail(GSM0808_CAUSE_REQ_CODEC_TYPE_OR_CONFIG_NOT_SUPP,</span><br><span style="color: hsl(120, 100%, 40%);">+ "Alternate channel mode not supported: %s",</span><br><span style="color: hsl(120, 100%, 40%);">+ gsm48_chan_mode_name(req->ch_mode_rate_alt.chan_mode));</span><br><span style="color: hsl(120, 100%, 40%);">+ return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Make sure both settings match */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (result_requires_voice_pref != result_requires_voice_alt) {</span><br><span style="color: hsl(120, 100%, 40%);">+ assignment_fail(GSM0808_CAUSE_REQ_CODEC_TYPE_OR_CONFIG_NOT_SUPP,</span><br><span style="color: hsl(120, 100%, 40%);">+ "Inconsistent channel modes: %s != %s",</span><br><span style="color: hsl(120, 100%, 40%);">+ gsm48_chan_mode_name(req->ch_mode_rate_pref.chan_mode),</span><br><span style="color: hsl(120, 100%, 40%);">+ gsm48_chan_mode_name(req->ch_mode_rate_alt.chan_mode));</span><br><span style="color: hsl(120, 100%, 40%);">+ return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Check if the conn is already associated with an lchan. If yes, we will check</span><br><span style="color: hsl(120, 100%, 40%);">+ * if that lchan is compatible with the preferred rate/codec. If the lchan</span><br><span style="color: hsl(120, 100%, 40%);">+ * turns out to be incompatible we try with the alternate rate/codec. */</span><br><span style="color: hsl(120, 100%, 40%);">+static bool reuse_existing_lchan(struct gsm_subscriber_connection *conn)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct assignment_request *req = &conn->assignment.req;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!conn->lchan)</span><br><span style="color: hsl(120, 100%, 40%);">+ return false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Check if the currently existing lchan is compatible with the</span><br><span style="color: hsl(120, 100%, 40%);">+ * preferred rate/codec. */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (lchan_type_compat_with_mode(conn->lchan->type, &req->ch_mode_rate_pref))</span><br><span style="color: hsl(120, 100%, 40%);">+ conn->lchan->ch_mode_rate = req->ch_mode_rate_pref;</span><br><span style="color: hsl(120, 100%, 40%);">+ else if (req->ch_mode_rate_alt_present</span><br><span style="color: hsl(120, 100%, 40%);">+ && lchan_type_compat_with_mode(conn->lchan->type, &req->ch_mode_rate_alt))</span><br><span style="color: hsl(120, 100%, 40%);">+ conn->lchan->ch_mode_rate = req->ch_mode_rate_alt;</span><br><span style="color: hsl(120, 100%, 40%);">+ else</span><br><span style="color: hsl(120, 100%, 40%);">+ return false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (conn->lchan->tch_mode != conn->lchan->ch_mode_rate.chan_mode) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* FIXME: send Channel Mode Modify to put the current lchan in the right mode, and kick</span><br><span style="color: hsl(120, 100%, 40%);">+ * off its RTP stream setup code path. See gsm48_lchan_modify() and</span><br><span style="color: hsl(120, 100%, 40%);">+ * gsm48_rx_rr_modif_ack(), and see lchan_fsm.h LCHAN_EV_CHAN_MODE_MODIF_* */</span><br><span style="color: hsl(120, 100%, 40%);">+ LOG_ASSIGNMENT(conn, LOGL_DEBUG,</span><br><span style="color: hsl(120, 100%, 40%);">+ "Current lchan would be compatible, but Channel Mode Modify is not implemented\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return true;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> void assignment_fsm_start(struct gsm_subscriber_connection *conn, struct gsm_bts *bts,</span><br><span> struct assignment_request *req)</span><br><span> {</span><br><span>@@ -311,75 +414,77 @@</span><br><span> conn->assignment.fi = fi;</span><br><span> fi->priv = conn;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* Create a copy of the request data and use that copy from now on. */</span><br><span> conn->assignment.req = *req;</span><br><span style="color: hsl(120, 100%, 40%);">+ req = &conn->assignment.req;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- switch (req->chan_mode) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Check if we need a voice stream. If yes, set the approriate struct</span><br><span style="color: hsl(120, 100%, 40%);">+ * members in conn */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (check_requires_voice_stream(conn) < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- case GSM48_CMODE_SPEECH_V1:</span><br><span style="color: hsl(0, 100%, 40%);">- case GSM48_CMODE_SPEECH_EFR:</span><br><span style="color: hsl(0, 100%, 40%);">- case GSM48_CMODE_SPEECH_AMR:</span><br><span style="color: hsl(0, 100%, 40%);">- conn->assignment.requires_voice_stream = true;</span><br><span style="color: hsl(0, 100%, 40%);">- /* Select an lchan below. */</span><br><span style="color: hsl(0, 100%, 40%);">- break;</span><br><span style="color: hsl(120, 100%, 40%);">+ /* There may be an already existing lchan, if yes, try to work with</span><br><span style="color: hsl(120, 100%, 40%);">+ * the existing lchan */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (reuse_existing_lchan(conn)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOG_ASSIGNMENT(conn, LOGL_DEBUG,</span><br><span style="color: hsl(120, 100%, 40%);">+ "Current lchan is compatible with requested chan_mode,"</span><br><span style="color: hsl(120, 100%, 40%);">+ " sending BSSMAP Assignment Complete directly."</span><br><span style="color: hsl(120, 100%, 40%);">+ " requested chan_mode=%s; current lchan is %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ gsm48_chan_mode_name(conn->lchan->ch_mode_rate.chan_mode),</span><br><span style="color: hsl(120, 100%, 40%);">+ gsm_lchan_name(conn->lchan));</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- case GSM48_CMODE_SIGN:</span><br><span style="color: hsl(0, 100%, 40%);">- conn->assignment.requires_voice_stream = false;</span><br><span style="color: hsl(0, 100%, 40%);">- /* Select an lchan below. */</span><br><span style="color: hsl(0, 100%, 40%);">- break;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- default:</span><br><span style="color: hsl(0, 100%, 40%);">- assignment_fail(GSM0808_CAUSE_REQ_CODEC_TYPE_OR_CONFIG_NOT_SUPP,</span><br><span style="color: hsl(0, 100%, 40%);">- "Channel mode not supported: %s",</span><br><span style="color: hsl(0, 100%, 40%);">- gsm48_chan_mode_name(req->chan_mode));</span><br><span style="color: hsl(120, 100%, 40%);">+ send_assignment_complete(conn);</span><br><span style="color: hsl(120, 100%, 40%);">+ /* If something went wrong during send_assignment_complete(), the fi will be gone from</span><br><span style="color: hsl(120, 100%, 40%);">+ * error handling in there. */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (conn->assignment.fi) {</span><br><span style="color: hsl(120, 100%, 40%);">+ assignment_count_result(BSC_CTR_ASSIGNMENT_COMPLETED);</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_fsm_inst_term(conn->assignment.fi, OSMO_FSM_TERM_REGULAR, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span> return;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- if (conn->lchan</span><br><span style="color: hsl(0, 100%, 40%);">- && lchan_type_compat_with_mode(conn->lchan->type, req->chan_mode, req->full_rate)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Try to allocate a new lchan with the preferred codec/rate choice */</span><br><span style="color: hsl(120, 100%, 40%);">+ conn->assignment.new_lchan =</span><br><span style="color: hsl(120, 100%, 40%);">+ lchan_select_by_chan_mode(bts, req->ch_mode_rate_pref.chan_mode, req->ch_mode_rate_pref.full_rate);</span><br><span style="color: hsl(120, 100%, 40%);">+ conn->lchan->ch_mode_rate = req->ch_mode_rate_pref;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- if (conn->lchan->tch_mode == req->chan_mode) {</span><br><span style="color: hsl(0, 100%, 40%);">- /* current lchan suffices and already is in the right mode. We're done. */</span><br><span style="color: hsl(0, 100%, 40%);">- LOG_ASSIGNMENT(conn, LOGL_DEBUG,</span><br><span style="color: hsl(0, 100%, 40%);">- "Current lchan is compatible with requested chan_mode,"</span><br><span style="color: hsl(0, 100%, 40%);">- " sending BSSMAP Assignment Complete directly."</span><br><span style="color: hsl(0, 100%, 40%);">- " requested chan_mode=%s; current lchan is %s\n",</span><br><span style="color: hsl(0, 100%, 40%);">- gsm48_chan_mode_name(req->chan_mode),</span><br><span style="color: hsl(0, 100%, 40%);">- gsm_lchan_name(conn->lchan));</span><br><span style="color: hsl(0, 100%, 40%);">- send_assignment_complete(conn);</span><br><span style="color: hsl(0, 100%, 40%);">- return;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* FIXME: send Channel Mode Modify to put the current lchan in the right mode, and kick</span><br><span style="color: hsl(0, 100%, 40%);">- * off its RTP stream setup code path. See gsm48_lchan_modify() and</span><br><span style="color: hsl(0, 100%, 40%);">- * gsm48_rx_rr_modif_ack(), and see lchan_fsm.h LCHAN_EV_CHAN_MODE_MODIF_* */</span><br><span style="color: hsl(0, 100%, 40%);">- LOG_ASSIGNMENT(conn, LOGL_ERROR,</span><br><span style="color: hsl(0, 100%, 40%);">- "NOT IMPLEMENTED:"</span><br><span style="color: hsl(0, 100%, 40%);">- " Current lchan would be compatible, we should send Channel Mode Modify\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ /* In case the lchan allocation fails, we try with the alternat codec/</span><br><span style="color: hsl(120, 100%, 40%);">+ * rate choice (if possible) */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!conn->assignment.new_lchan && req->ch_mode_rate_alt_present) {</span><br><span style="color: hsl(120, 100%, 40%);">+ conn->assignment.new_lchan =</span><br><span style="color: hsl(120, 100%, 40%);">+ lchan_select_by_chan_mode(bts, req->ch_mode_rate_alt.chan_mode, req->ch_mode_rate_alt.full_rate);</span><br><span style="color: hsl(120, 100%, 40%);">+ conn->lchan->ch_mode_rate = req->ch_mode_rate_alt;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- conn->assignment.new_lchan = lchan_select_by_chan_mode(bts, req->chan_mode, req->full_rate);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Check whether the lchan allocation was successful or not and tear</span><br><span style="color: hsl(120, 100%, 40%);">+ * down the assignment in case of failure. */</span><br><span> if (!conn->assignment.new_lchan) {</span><br><span> assignment_count_result(BSC_CTR_ASSIGNMENT_NO_CHANNEL);</span><br><span> assignment_fail(GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE,</span><br><span> "BSSMAP Assignment Command:"</span><br><span style="color: hsl(0, 100%, 40%);">- " No lchan available for: chan_mode=%s, full_rate=%i\n",</span><br><span style="color: hsl(0, 100%, 40%);">- get_value_string(gsm48_chan_mode_names, req->chan_mode), req->full_rate);</span><br><span style="color: hsl(120, 100%, 40%);">+ " No lchan available for: preferred=%s%s / alternate=%s%s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ gsm48_chan_mode_name(req->ch_mode_rate_pref.chan_mode),</span><br><span style="color: hsl(120, 100%, 40%);">+ req->ch_mode_rate_pref.full_rate ? ",FR" : ",HR",</span><br><span style="color: hsl(120, 100%, 40%);">+ req->ch_mode_rate_alt_present ?</span><br><span style="color: hsl(120, 100%, 40%);">+ gsm48_chan_mode_name(req->ch_mode_rate_alt.chan_mode) : "none",</span><br><span style="color: hsl(120, 100%, 40%);">+ req->ch_mode_rate_alt_present ?</span><br><span style="color: hsl(120, 100%, 40%);">+ (req->ch_mode_rate_alt.full_rate ? ",FR" : ",HR") : "");</span><br><span> return;</span><br><span> }</span><br><span> </span><br><span> assignment_fsm_update_id(conn);</span><br><span> LOG_ASSIGNMENT(conn, LOGL_INFO, "Starting Assignment: chan_mode=%s, full_rate=%d,"</span><br><span> " aoip=%s MSC-rtp=%s:%u\n",</span><br><span style="color: hsl(0, 100%, 40%);">- gsm48_chan_mode_name(req->chan_mode), req->full_rate,</span><br><span style="color: hsl(120, 100%, 40%);">+ gsm48_chan_mode_name(conn->lchan->ch_mode_rate.chan_mode),</span><br><span style="color: hsl(120, 100%, 40%);">+ conn->lchan->ch_mode_rate.full_rate,</span><br><span> req->aoip ? "yes" : "no", req->msc_rtp_addr, req->msc_rtp_port);</span><br><span> </span><br><span> assignment_fsm_state_chg(ASSIGNMENT_ST_WAIT_LCHAN_ACTIVE);</span><br><span> info = (struct lchan_activate_info){</span><br><span> .activ_for = FOR_ASSIGNMENT,</span><br><span> .for_conn = conn,</span><br><span style="color: hsl(0, 100%, 40%);">- .chan_mode = req->chan_mode,</span><br><span style="color: hsl(0, 100%, 40%);">- .s15_s0 = req->s15_s0,</span><br><span style="color: hsl(120, 100%, 40%);">+ .chan_mode = conn->lchan->ch_mode_rate.chan_mode,</span><br><span style="color: hsl(120, 100%, 40%);">+ .s15_s0 = conn->lchan->ch_mode_rate.s15_s0,</span><br><span> .requires_voice_stream = conn->assignment.requires_voice_stream,</span><br><span> .msc_assigned_cic = req->msc_assigned_cic,</span><br><span> .re_use_mgw_endpoint_from_lchan = conn->lchan,</span><br><span>diff --git a/src/osmo-bsc/bsc_vty.c b/src/osmo-bsc/bsc_vty.c</span><br><span>index 357ee9e..9413d36 100644</span><br><span>--- a/src/osmo-bsc/bsc_vty.c</span><br><span>+++ b/src/osmo-bsc/bsc_vty.c</span><br><span>@@ -4802,6 +4802,7 @@</span><br><span> ts = vty_get_ts(vty, argv[0], argv[1], argv[2]);</span><br><span> if (!ts)</span><br><span> return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> lchan = &ts->lchan[ss_nr];</span><br><span> if (!lchan->fi)</span><br><span> return CMD_WARNING;</span><br><span>diff --git a/src/osmo-bsc/codec_pref.c b/src/osmo-bsc/codec_pref.c</span><br><span>index c99c383..a94d6a8 100644</span><br><span>--- a/src/osmo-bsc/codec_pref.c</span><br><span>+++ b/src/osmo-bsc/codec_pref.c</span><br><span>@@ -266,21 +266,18 @@</span><br><span> </span><br><span> /*! Match the codec preferences from local config with a received codec preferences IEs received from the</span><br><span> * MSC and the BTS' codec configuration.</span><br><span style="color: hsl(0, 100%, 40%);">- * \param[out] chan_mode GSM 04.08 channel mode.</span><br><span style="color: hsl(0, 100%, 40%);">- * \param[out] full_rate true if full-rate.</span><br><span style="color: hsl(0, 100%, 40%);">- * \param[out] s15_s0 codec configuration bits S15-S0 (AMR)</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[out] ch_mode_rate resulting codec and rate information</span><br><span> * \param[in] ct GSM 08.08 channel type received from MSC.</span><br><span> * \param[in] scl GSM 08.08 speech codec list received from MSC (optional).</span><br><span> * \param[in] msc associated msc (current codec settings).</span><br><span> * \param[in] bts associated bts (current codec settings).</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] pref selected rate preference (full, half or none).</span><br><span> * \returns 0 on success, -1 in case no match was found */</span><br><span style="color: hsl(0, 100%, 40%);">-int match_codec_pref(enum gsm48_chan_mode *chan_mode,</span><br><span style="color: hsl(0, 100%, 40%);">- bool *full_rate,</span><br><span style="color: hsl(0, 100%, 40%);">- uint16_t *s15_s0,</span><br><span style="color: hsl(120, 100%, 40%);">+int match_codec_pref(struct channel_mode_and_rate *ch_mode_rate,</span><br><span> const struct gsm0808_channel_type *ct,</span><br><span> const struct gsm0808_speech_codec_list *scl,</span><br><span> const struct bsc_msc_data *msc,</span><br><span style="color: hsl(0, 100%, 40%);">- const struct gsm_bts *bts)</span><br><span style="color: hsl(120, 100%, 40%);">+ const struct gsm_bts *bts, enum rate_pref rate_pref)</span><br><span> {</span><br><span> unsigned int i;</span><br><span> uint8_t perm_spch;</span><br><span>@@ -297,6 +294,18 @@</span><br><span> /* Pick a permitted speech value from the global codec configuration list */</span><br><span> perm_spch = audio_support_to_gsm88(msc->audio_support[i]);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* Determine if the result is a half or full rate codec */</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = full_rate_from_perm_spch(&ch_mode_rate->full_rate, perm_spch);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+ return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* If we have a preference for FR or HR in our request, we</span><br><span style="color: hsl(120, 100%, 40%);">+ * discard the potential match */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rate_pref == RATE_PREF_HR && ch_mode_rate->full_rate)</span><br><span style="color: hsl(120, 100%, 40%);">+ continue;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rate_pref == RATE_PREF_FR && !ch_mode_rate->full_rate)</span><br><span style="color: hsl(120, 100%, 40%);">+ continue;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* Check this permitted speech value against the BTS specific parameters.</span><br><span> * if the BTS does not support the codec, try the next one */</span><br><span> if (!test_codec_support_bts(bts, perm_spch))</span><br><span>@@ -312,19 +321,14 @@</span><br><span> </span><br><span> /* Exit without result, in case no match can be deteched */</span><br><span> if (!match) {</span><br><span style="color: hsl(0, 100%, 40%);">- *full_rate = false;</span><br><span style="color: hsl(0, 100%, 40%);">- *chan_mode = GSM48_CMODE_SIGN;</span><br><span style="color: hsl(0, 100%, 40%);">- *s15_s0 = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ ch_mode_rate->full_rate = false;</span><br><span style="color: hsl(120, 100%, 40%);">+ ch_mode_rate->chan_mode = GSM48_CMODE_SIGN;</span><br><span style="color: hsl(120, 100%, 40%);">+ ch_mode_rate->s15_s0 = 0;</span><br><span> return -1;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- /* Determine if the result is a half or full rate codec */</span><br><span style="color: hsl(0, 100%, 40%);">- rc = full_rate_from_perm_spch(full_rate, perm_spch);</span><br><span style="color: hsl(0, 100%, 40%);">- if (rc < 0)</span><br><span style="color: hsl(0, 100%, 40%);">- return -EINVAL;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> /* Lookup a channel mode for the selected codec */</span><br><span style="color: hsl(0, 100%, 40%);">- *chan_mode = gsm88_to_chan_mode(perm_spch);</span><br><span style="color: hsl(120, 100%, 40%);">+ ch_mode_rate->chan_mode = gsm88_to_chan_mode(perm_spch);</span><br><span> </span><br><span> /* Special handling for AMR */</span><br><span> if (perm_spch == GSM0808_PERM_HR3 || perm_spch == GSM0808_PERM_FR3) {</span><br><span>@@ -337,9 +341,9 @@</span><br><span> * result */</span><br><span> amr_s15_s0_supported = gen_bss_supported_amr_s15_s0(msc, bts, (perm_spch == GSM0808_PERM_HR3));</span><br><span> if (sc_match)</span><br><span style="color: hsl(0, 100%, 40%);">- *s15_s0 = sc_match->cfg & amr_s15_s0_supported;</span><br><span style="color: hsl(120, 100%, 40%);">+ ch_mode_rate->s15_s0 = sc_match->cfg & amr_s15_s0_supported;</span><br><span> else</span><br><span style="color: hsl(0, 100%, 40%);">- *s15_s0 = amr_s15_s0_supported;</span><br><span style="color: hsl(120, 100%, 40%);">+ ch_mode_rate->s15_s0 = amr_s15_s0_supported;</span><br><span> </span><br><span> /* NOTE: The function test_codec_pref() will populate the</span><br><span> * sc_match pointer from the searched speech codec list. For</span><br><span>@@ -349,7 +353,7 @@</span><br><span> * However s15_s0 is always populated with a meaningful value,</span><br><span> * regardless if AoIP is in use or not. */</span><br><span> } else</span><br><span style="color: hsl(0, 100%, 40%);">- *s15_s0 = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ ch_mode_rate->s15_s0 = 0;</span><br><span> </span><br><span> return 0;</span><br><span> }</span><br><span>diff --git a/src/osmo-bsc/handover_fsm.c b/src/osmo-bsc/handover_fsm.c</span><br><span>index 578cff3..30297f6 100644</span><br><span>--- a/src/osmo-bsc/handover_fsm.c</span><br><span>+++ b/src/osmo-bsc/handover_fsm.c</span><br><span>@@ -521,10 +521,8 @@</span><br><span> struct bsc_msc_data *msc = conn->sccp.msc;</span><br><span> struct handover_in_req *req = &ho->inter_bsc_in;</span><br><span> int match_idx;</span><br><span style="color: hsl(0, 100%, 40%);">- enum gsm48_chan_mode mode;</span><br><span style="color: hsl(0, 100%, 40%);">- bool full_rate = false;</span><br><span style="color: hsl(0, 100%, 40%);">- uint16_t s15_s0;</span><br><span> struct osmo_fsm_inst *fi;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct channel_mode_and_rate ch_mode_rate = {};</span><br><span> </span><br><span> handover_fsm_alloc(conn);</span><br><span> </span><br><span>@@ -562,7 +560,7 @@</span><br><span> bts->nr, req->cell_id_target_name);</span><br><span> </span><br><span> /* Figure out channel type */</span><br><span style="color: hsl(0, 100%, 40%);">- if (match_codec_pref(&mode, &full_rate, &s15_s0, &req->ct, &req->scl, msc, bts)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (match_codec_pref(&ch_mode_rate, &req->ct, &req->scl, msc, bts, RATE_PREF_NONE)) {</span><br><span> LOG_HO(conn, LOGL_DEBUG,</span><br><span> "BTS %u has no matching channel codec (%s, speech codec list len = %u)\n",</span><br><span> bts->nr, gsm0808_channel_type_name(&req->ct), req->scl.len);</span><br><span>@@ -570,10 +568,10 @@</span><br><span> }</span><br><span> </span><br><span> LOG_HO(conn, LOGL_DEBUG, "BTS %u: Found matching audio type: %s %s (for %s)\n",</span><br><span style="color: hsl(0, 100%, 40%);">- bts->nr, gsm48_chan_mode_name(mode), full_rate? "full-rate" : "half-rate",</span><br><span style="color: hsl(120, 100%, 40%);">+ bts->nr, gsm48_chan_mode_name(ch_mode_rate.chan_mode), ch_mode_rate.full_rate? "full-rate" : "half-rate",</span><br><span> gsm0808_channel_type_name(&req->ct));</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- lchan = lchan_select_by_chan_mode(bts, mode, full_rate);</span><br><span style="color: hsl(120, 100%, 40%);">+ lchan = lchan_select_by_chan_mode(bts, ch_mode_rate.chan_mode, ch_mode_rate.full_rate);</span><br><span> if (!lchan) {</span><br><span> LOG_HO(conn, LOGL_DEBUG, "BTS %u has no matching free channels\n", bts->nr);</span><br><span> continue;</span><br><span>@@ -605,9 +603,9 @@</span><br><span> info = (struct lchan_activate_info){</span><br><span> .activ_for = FOR_HANDOVER,</span><br><span> .for_conn = conn,</span><br><span style="color: hsl(0, 100%, 40%);">- .chan_mode = mode,</span><br><span style="color: hsl(0, 100%, 40%);">- .s15_s0 = s15_s0,</span><br><span style="color: hsl(0, 100%, 40%);">- .requires_voice_stream = chan_mode_is_tch(mode),</span><br><span style="color: hsl(120, 100%, 40%);">+ .chan_mode = ch_mode_rate.chan_mode,</span><br><span style="color: hsl(120, 100%, 40%);">+ .s15_s0 = ch_mode_rate.s15_s0,</span><br><span style="color: hsl(120, 100%, 40%);">+ .requires_voice_stream = chan_mode_is_tch(ch_mode_rate.chan_mode),</span><br><span> .msc_assigned_cic = req->msc_assigned_cic,</span><br><span> };</span><br><span> </span><br><span>@@ -715,7 +713,7 @@</span><br><span> if (gscon_is_aoip(conn)) {</span><br><span> /* Extrapolate speech codec from speech mode */</span><br><span> gsm0808_speech_codec_from_chan_type(&sc, ho_perf_params.speech_version_chosen);</span><br><span style="color: hsl(0, 100%, 40%);">- sc.cfg = conn->lchan->s15_s0;</span><br><span style="color: hsl(120, 100%, 40%);">+ sc.cfg = conn->lchan->ch_mode_rate.s15_s0;</span><br><span> memcpy(&ho_perf_params.speech_codec_chosen, &sc, sizeof(sc));</span><br><span> ho_perf_params.speech_codec_chosen_present = true;</span><br><span> }</span><br><span>diff --git a/src/osmo-bsc/osmo_bsc_bssap.c b/src/osmo-bsc/osmo_bsc_bssap.c</span><br><span>index ab7f79c..85aab22 100644</span><br><span>--- a/src/osmo-bsc/osmo_bsc_bssap.c</span><br><span>+++ b/src/osmo-bsc/osmo_bsc_bssap.c</span><br><span>@@ -616,6 +616,101 @@</span><br><span> return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/* Select a prefered and an alternative codec rate depending on the available</span><br><span style="color: hsl(120, 100%, 40%);">+ * capabilities. This decision does not include the actual channel load yet,</span><br><span style="color: hsl(120, 100%, 40%);">+ * this is also the reason why the result is a prefered and an alternate</span><br><span style="color: hsl(120, 100%, 40%);">+ * setting. The final decision is made in assignment_fsm.c when the actual</span><br><span style="color: hsl(120, 100%, 40%);">+ * lchan is requested. The preferred lchan will be requested first. If we</span><br><span style="color: hsl(120, 100%, 40%);">+ * find an alternate setting here, this one will be tried secondly if our</span><br><span style="color: hsl(120, 100%, 40%);">+ * primary coice fails. */</span><br><span style="color: hsl(120, 100%, 40%);">+static int select_codecs(struct assignment_request *req, struct gsm0808_channel_type *ct,</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gsm_subscriber_connection *conn)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct bsc_msc_data *msc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ msc = conn->sccp.msc;</span><br><span style="color: hsl(120, 100%, 40%);">+ req->ch_mode_rate_alt_present = false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (ct->ch_rate_type) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case GSM0808_SPEECH_FULL_BM:</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = match_codec_pref(&req->ch_mode_rate_pref, ct, &conn->codec_list, msc, conn_get_bts(conn),</span><br><span style="color: hsl(120, 100%, 40%);">+ RATE_PREF_FR);</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case GSM0808_SPEECH_HALF_LM:</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = match_codec_pref(&req->ch_mode_rate_pref, ct, &conn->codec_list, msc, conn_get_bts(conn),</span><br><span style="color: hsl(120, 100%, 40%);">+ RATE_PREF_HR);</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case GSM0808_SPEECH_PERM:</span><br><span style="color: hsl(120, 100%, 40%);">+ case GSM0808_SPEECH_PERM_NO_CHANGE:</span><br><span style="color: hsl(120, 100%, 40%);">+ case GSM0808_SPEECH_FULL_PREF_NO_CHANGE:</span><br><span style="color: hsl(120, 100%, 40%);">+ case GSM0808_SPEECH_FULL_PREF:</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = match_codec_pref(&req->ch_mode_rate_pref, ct, &conn->codec_list, msc, conn_get_bts(conn),</span><br><span style="color: hsl(120, 100%, 40%);">+ RATE_PREF_FR);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = match_codec_pref(&req->ch_mode_rate_pref, ct, &conn->codec_list, msc, conn_get_bts(conn),</span><br><span style="color: hsl(120, 100%, 40%);">+ RATE_PREF_HR);</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = match_codec_pref(&req->ch_mode_rate_alt, ct, &conn->codec_list, msc, conn_get_bts(conn),</span><br><span style="color: hsl(120, 100%, 40%);">+ RATE_PREF_HR);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+ req->ch_mode_rate_alt_present = true;</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case GSM0808_SPEECH_HALF_PREF_NO_CHANGE:</span><br><span style="color: hsl(120, 100%, 40%);">+ case GSM0808_SPEECH_HALF_PREF:</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = match_codec_pref(&req->ch_mode_rate_pref, ct, &conn->codec_list, msc, conn_get_bts(conn),</span><br><span style="color: hsl(120, 100%, 40%);">+ RATE_PREF_HR);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = match_codec_pref(&req->ch_mode_rate_pref, ct, &conn->codec_list, msc, conn_get_bts(conn),</span><br><span style="color: hsl(120, 100%, 40%);">+ RATE_PREF_FR);</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = match_codec_pref(&req->ch_mode_rate_alt, ct, &conn->codec_list, msc, conn_get_bts(conn),</span><br><span style="color: hsl(120, 100%, 40%);">+ RATE_PREF_FR);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+ req->ch_mode_rate_alt_present = true;</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ default:</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DMSC, LOGL_ERROR, "No supported audio type found for channel_type ="</span><br><span style="color: hsl(120, 100%, 40%);">+ " { ch_indctr=0x%x, ch_rate_type=0x%x, perm_spch=[%s] }\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ ct->ch_indctr, ct->ch_rate_type, osmo_hexdump(ct->perm_spch, ct->perm_spch_len));</span><br><span style="color: hsl(120, 100%, 40%);">+ /* TODO: actually output codec names, e.g. implement</span><br><span style="color: hsl(120, 100%, 40%);">+ * gsm0808_permitted_speech_names[] and iterate perm_spch. */</span><br><span style="color: hsl(120, 100%, 40%);">+ return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (req->ch_mode_rate_alt_present) {</span><br><span style="color: hsl(120, 100%, 40%);">+ DEBUGP(DMSC, "Found matching audio type (preferred): %s %s for channel_type ="</span><br><span style="color: hsl(120, 100%, 40%);">+ " { ch_indctr=0x%x, ch_rate_type=0x%x, perm_spch=[ %s] }\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ req->ch_mode_rate_pref.full_rate ? "full rate" : "half rate",</span><br><span style="color: hsl(120, 100%, 40%);">+ get_value_string(gsm48_chan_mode_names, req->ch_mode_rate_pref.chan_mode),</span><br><span style="color: hsl(120, 100%, 40%);">+ ct->ch_indctr, ct->ch_rate_type, osmo_hexdump(ct->perm_spch, ct->perm_spch_len));</span><br><span style="color: hsl(120, 100%, 40%);">+ DEBUGP(DMSC, "Found matching audio type (alternative): %s %s for channel_type ="</span><br><span style="color: hsl(120, 100%, 40%);">+ " { ch_indctr=0x%x, ch_rate_type=0x%x, perm_spch=[ %s] }\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ req->ch_mode_rate_alt.full_rate ? "full rate" : "half rate",</span><br><span style="color: hsl(120, 100%, 40%);">+ get_value_string(gsm48_chan_mode_names, req->ch_mode_rate_alt.chan_mode),</span><br><span style="color: hsl(120, 100%, 40%);">+ ct->ch_indctr, ct->ch_rate_type, osmo_hexdump(ct->perm_spch, ct->perm_spch_len));</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ DEBUGP(DMSC, "Found matching audio type: %s %s for channel_type ="</span><br><span style="color: hsl(120, 100%, 40%);">+ " { ch_indctr=0x%x, ch_rate_type=0x%x, perm_spch=[ %s] }\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ req->ch_mode_rate_pref.full_rate ? "full rate" : "half rate",</span><br><span style="color: hsl(120, 100%, 40%);">+ get_value_string(gsm48_chan_mode_names, req->ch_mode_rate_pref.chan_mode),</span><br><span style="color: hsl(120, 100%, 40%);">+ ct->ch_indctr, ct->ch_rate_type, osmo_hexdump(ct->perm_spch, ct->perm_spch_len));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*</span><br><span> * Handle the assignment request message.</span><br><span> *</span><br><span>@@ -625,18 +720,15 @@</span><br><span> struct msgb *msg, unsigned int length)</span><br><span> {</span><br><span> struct msgb *resp;</span><br><span style="color: hsl(0, 100%, 40%);">- struct bsc_msc_data *msc;</span><br><span> struct tlv_parsed tp;</span><br><span> uint16_t cic = 0;</span><br><span style="color: hsl(0, 100%, 40%);">- enum gsm48_chan_mode chan_mode = GSM48_CMODE_SIGN;</span><br><span style="color: hsl(0, 100%, 40%);">- bool full_rate = false;</span><br><span style="color: hsl(0, 100%, 40%);">- uint16_t s15_s0 = 0;</span><br><span> bool aoip = false;</span><br><span> struct sockaddr_storage rtp_addr;</span><br><span> struct gsm0808_channel_type ct;</span><br><span> uint8_t cause;</span><br><span> int rc;</span><br><span> struct assignment_request req = {};</span><br><span style="color: hsl(120, 100%, 40%);">+ struct channel_mode_and_rate ch_mode_rate_pref = {};</span><br><span> </span><br><span> if (!conn) {</span><br><span> LOGP(DMSC, LOGL_ERROR,</span><br><span>@@ -644,7 +736,6 @@</span><br><span> return -1;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- msc = conn->sccp.msc;</span><br><span> aoip = gscon_is_aoip(conn);</span><br><span> </span><br><span> tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l4h + 1, length - 1, 0, 0);</span><br><span>@@ -732,33 +823,19 @@</span><br><span> goto reject;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ req = (struct assignment_request){</span><br><span style="color: hsl(120, 100%, 40%);">+ .aoip = aoip,</span><br><span style="color: hsl(120, 100%, 40%);">+ .msc_assigned_cic = cic,</span><br><span style="color: hsl(120, 100%, 40%);">+ };</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* Match codec information from the assignment command against the</span><br><span> * local preferences of the BSC and BTS */</span><br><span style="color: hsl(0, 100%, 40%);">- rc = match_codec_pref(&chan_mode, &full_rate, &s15_s0, &ct, &conn->codec_list,</span><br><span style="color: hsl(0, 100%, 40%);">- msc, conn_get_bts(conn));</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = select_codecs(&req, &ct, conn);</span><br><span> if (rc < 0) {</span><br><span style="color: hsl(0, 100%, 40%);">- LOGP(DMSC, LOGL_ERROR, "No supported audio type found for channel_type ="</span><br><span style="color: hsl(0, 100%, 40%);">- " { ch_indctr=0x%x, ch_rate_type=0x%x, perm_spch=[ %s] }\n",</span><br><span style="color: hsl(0, 100%, 40%);">- ct.ch_indctr, ct.ch_rate_type, osmo_hexdump(ct.perm_spch, ct.perm_spch_len));</span><br><span style="color: hsl(0, 100%, 40%);">- /* TODO: actually output codec names, e.g. implement</span><br><span style="color: hsl(0, 100%, 40%);">- * gsm0808_permitted_speech_names[] and iterate perm_spch. */</span><br><span> cause = GSM0808_CAUSE_REQ_CODEC_TYPE_OR_CONFIG_UNAVAIL;</span><br><span> goto reject;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- DEBUGP(DMSC, "Found matching audio type: %s %s for channel_type ="</span><br><span style="color: hsl(0, 100%, 40%);">- " { ch_indctr=0x%x, ch_rate_type=0x%x, perm_spch=[ %s] }\n",</span><br><span style="color: hsl(0, 100%, 40%);">- full_rate? "full rate" : "half rate",</span><br><span style="color: hsl(0, 100%, 40%);">- get_value_string(gsm48_chan_mode_names, chan_mode),</span><br><span style="color: hsl(0, 100%, 40%);">- ct.ch_indctr, ct.ch_rate_type, osmo_hexdump(ct.perm_spch, ct.perm_spch_len));</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- req = (struct assignment_request){</span><br><span style="color: hsl(0, 100%, 40%);">- .aoip = aoip,</span><br><span style="color: hsl(0, 100%, 40%);">- .msc_assigned_cic = cic,</span><br><span style="color: hsl(0, 100%, 40%);">- .chan_mode = chan_mode,</span><br><span style="color: hsl(0, 100%, 40%);">- .full_rate = full_rate,</span><br><span style="color: hsl(0, 100%, 40%);">- .s15_s0 = s15_s0</span><br><span style="color: hsl(0, 100%, 40%);">- };</span><br><span> if (aoip) {</span><br><span> unsigned int rc = osmo_sockaddr_to_str_and_uint(req.msc_rtp_addr,</span><br><span> sizeof(req.msc_rtp_addr),</span><br><span>@@ -772,9 +849,13 @@</span><br><span> }</span><br><span> break;</span><br><span> case GSM0808_CHAN_SIGN:</span><br><span style="color: hsl(120, 100%, 40%);">+ ch_mode_rate_pref = (struct channel_mode_and_rate) {</span><br><span style="color: hsl(120, 100%, 40%);">+ .chan_mode = GSM48_CMODE_SIGN,</span><br><span style="color: hsl(120, 100%, 40%);">+ };</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> req = (struct assignment_request){</span><br><span> .aoip = aoip,</span><br><span style="color: hsl(0, 100%, 40%);">- .chan_mode = chan_mode,</span><br><span style="color: hsl(120, 100%, 40%);">+ .ch_mode_rate_pref = ch_mode_rate_pref,</span><br><span> };</span><br><span> break;</span><br><span> default:</span><br><span>diff --git a/tests/codec_pref/codec_pref_test.c b/tests/codec_pref/codec_pref_test.c</span><br><span>index 534b99e..bb5468a 100644</span><br><span>--- a/tests/codec_pref/codec_pref_test.c</span><br><span>+++ b/tests/codec_pref/codec_pref_test.c</span><br><span>@@ -380,9 +380,7 @@</span><br><span> {</span><br><span> int rc;</span><br><span> unsigned int i;</span><br><span style="color: hsl(0, 100%, 40%);">- bool full_rate;</span><br><span style="color: hsl(0, 100%, 40%);">- enum gsm48_chan_mode chan_mode;</span><br><span style="color: hsl(0, 100%, 40%);">- uint16_t s15_s0;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct channel_mode_and_rate ch_mode_rate = { };</span><br><span> </span><br><span> printf("Determining channel mode and rate:\n");</span><br><span> </span><br><span>@@ -407,9 +405,9 @@</span><br><span> printf(" codec->efr=%u\n", bts->codec.efr);</span><br><span> printf(" codec->amr=%u\n", bts->codec.amr);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- rc = match_codec_pref(&chan_mode, &full_rate, &s15_s0, ct, scl, msc, bts);</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = match_codec_pref(&ch_mode_rate, ct, scl, msc, bts, RATE_PREF_NONE);</span><br><span> printf(" * result: rc=%i, full_rate=%i, s15_s0=%04x, chan_mode=%s\n",</span><br><span style="color: hsl(0, 100%, 40%);">- rc, full_rate, s15_s0, gsm48_chan_mode_name(chan_mode));</span><br><span style="color: hsl(120, 100%, 40%);">+ rc, ch_mode_rate.full_rate, ch_mode_rate.s15_s0, gsm48_chan_mode_name(ch_mode_rate.chan_mode));</span><br><span> </span><br><span> printf("\n");</span><br><span> </span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/12625">change 12625</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/12625"/><meta itemprop="name" content="View Change"/></div></div>
<div style="display:none"> Gerrit-Project: osmo-bsc </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: merged </div>
<div style="display:none"> Gerrit-Change-Id: I5239e05c1cfbcb8af28f43373a58fa6c2d216c51 </div>
<div style="display:none"> Gerrit-Change-Number: 12625 </div>
<div style="display:none"> Gerrit-PatchSet: 12 </div>
<div style="display:none"> Gerrit-Owner: dexter <pmaier@sysmocom.de> </div>
<div style="display:none"> Gerrit-Assignee: Neels Hofmeyr <nhofmeyr@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: Harald Welte <laforge@gnumonks.org> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder (1000002) </div>
<div style="display:none"> Gerrit-Reviewer: Max <msuraev@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: Neels Hofmeyr <nhofmeyr@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: dexter <pmaier@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: tnt <tnt@246tNt.com> </div>
<div style="display:none"> Gerrit-CC: Vadim Yanitskiy <axilirator@gmail.com> </div>