assignment_fsm: Properly support assigning signalling mode TCH/x
To support the 3 possible preferences, the changes needed were: - Replace 'full_rate' bool with a 3 option enum to represent the channels types for signalling - Switch from _pref/_alt to using an array sorted in preference order Originally merged as Change-Id I4c7499c8c866ea3ff7b1327edb3615d003d927d3, reverted because the change broke voice calls. Re-submitting with the fix: don't forget to set conn->assignment.requires_voice_stream. Signed-off-by: Sylvain Munaut <tnt@246tNt.com> Change-Id: I7513d2cbe8b695ba6f031ad11560c63a6535cf2d
This commit is contained in:
parent
f14aaa4ba1
commit
aa82492ad6
|
@ -98,9 +98,15 @@ enum subscr_sccp_state {
|
|||
SUBSCR_SCCP_ST_CONNECTED
|
||||
};
|
||||
|
||||
enum channel_rate {
|
||||
CH_RATE_SDCCH,
|
||||
CH_RATE_HALF,
|
||||
CH_RATE_FULL,
|
||||
};
|
||||
|
||||
struct channel_mode_and_rate {
|
||||
enum gsm48_chan_mode chan_mode;
|
||||
bool full_rate;
|
||||
enum channel_rate chan_rate;
|
||||
uint16_t s15_s0;
|
||||
};
|
||||
|
||||
|
@ -115,12 +121,9 @@ struct assignment_request {
|
|||
char msc_rtp_addr[INET_ADDRSTRLEN];
|
||||
uint16_t msc_rtp_port;
|
||||
|
||||
/* Prefered rate/codec setting (mandatory) */
|
||||
struct channel_mode_and_rate ch_mode_rate_pref;
|
||||
|
||||
/* Alternate rate/codec setting (optional) */
|
||||
bool ch_mode_rate_alt_present;
|
||||
struct channel_mode_and_rate ch_mode_rate_alt;
|
||||
/* Rate/codec setting in preference order (need at least 1 !) */
|
||||
int n_ch_mode_rate;
|
||||
struct channel_mode_and_rate ch_mode_rate[3];
|
||||
};
|
||||
|
||||
/* State of an ongoing Assignment, while the assignment_fsm is still busy. This serves as state separation to keep the
|
||||
|
|
|
@ -3,4 +3,4 @@
|
|||
|
||||
struct gsm_lchan *lchan_select_by_type(struct gsm_bts *bts, enum gsm_chan_t type);
|
||||
struct gsm_lchan *lchan_select_by_chan_mode(struct gsm_bts *bts,
|
||||
enum gsm48_chan_mode chan_mode, bool full_rate);
|
||||
enum gsm48_chan_mode chan_mode, enum channel_rate chan_rate);
|
||||
|
|
|
@ -250,17 +250,15 @@ static void assignment_fsm_update_id(struct gsm_subscriber_connection *conn)
|
|||
static bool lchan_type_compat_with_mode(enum gsm_chan_t type, const struct channel_mode_and_rate *ch_mode_rate)
|
||||
{
|
||||
enum gsm48_chan_mode chan_mode = ch_mode_rate->chan_mode;
|
||||
bool full_rate = ch_mode_rate->full_rate;
|
||||
enum channel_rate chan_rate = ch_mode_rate->chan_rate;
|
||||
|
||||
switch (chan_mode) {
|
||||
case GSM48_CMODE_SIGN:
|
||||
switch (type) {
|
||||
case GSM_LCHAN_TCH_F:
|
||||
case GSM_LCHAN_TCH_H:
|
||||
case GSM_LCHAN_SDCCH:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
case GSM_LCHAN_TCH_F: return chan_rate == CH_RATE_FULL;
|
||||
case GSM_LCHAN_TCH_H: return chan_rate == CH_RATE_HALF;
|
||||
case GSM_LCHAN_SDCCH: return chan_rate == CH_RATE_SDCCH;
|
||||
default: return false;
|
||||
}
|
||||
|
||||
case GSM48_CMODE_SPEECH_V1:
|
||||
|
@ -268,12 +266,12 @@ static bool lchan_type_compat_with_mode(enum gsm_chan_t type, const struct chann
|
|||
case GSM48_CMODE_DATA_3k6:
|
||||
case GSM48_CMODE_DATA_6k0:
|
||||
/* these services can all run on TCH/H, but we may have
|
||||
* an explicit override by the 'full_rate' argument */
|
||||
* an explicit override by the 'chan_rate' argument */
|
||||
switch (type) {
|
||||
case GSM_LCHAN_TCH_F:
|
||||
return full_rate;
|
||||
return chan_rate == CH_RATE_FULL;
|
||||
case GSM_LCHAN_TCH_H:
|
||||
return !full_rate;
|
||||
return chan_rate == CH_RATE_HALF;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
@ -319,47 +317,37 @@ static int check_requires_voice(bool *requires_voice, enum gsm48_chan_mode chan_
|
|||
* sure that both are consistent. */
|
||||
static int check_requires_voice_stream(struct gsm_subscriber_connection *conn)
|
||||
{
|
||||
bool result_requires_voice_alt;
|
||||
bool result_requires_voice_pref;
|
||||
bool requires_voice_pref = false, requires_voice_alt;
|
||||
struct assignment_request *req = &conn->assignment.req;
|
||||
struct osmo_fsm_inst *fi = conn->fi;
|
||||
int rc;
|
||||
int i, rc;
|
||||
|
||||
/* When the assignment request indicates that there is an alternate
|
||||
* rate available (e.g. "Full or Half rate channel, Half rate
|
||||
* preferred..."), then both must be either voice or either signalling,
|
||||
* a mismatch is not permitted */
|
||||
|
||||
/* Check the prefered setting */
|
||||
rc = check_requires_voice(&result_requires_voice_pref, req->ch_mode_rate_pref.chan_mode);
|
||||
if (rc < 0) {
|
||||
assignment_fail(GSM0808_CAUSE_REQ_CODEC_TYPE_OR_CONFIG_NOT_SUPP,
|
||||
"Prefered channel mode not supported: %s",
|
||||
gsm48_chan_mode_name(req->ch_mode_rate_pref.chan_mode));
|
||||
return -EINVAL;
|
||||
}
|
||||
conn->assignment.requires_voice_stream = result_requires_voice_pref;
|
||||
for (i = 0; i < req->n_ch_mode_rate; i++) {
|
||||
rc = check_requires_voice(&requires_voice_alt, req->ch_mode_rate[i].chan_mode);
|
||||
if (rc < 0) {
|
||||
assignment_fail(GSM0808_CAUSE_REQ_CODEC_TYPE_OR_CONFIG_NOT_SUPP,
|
||||
"Channel mode not supported (prev level %d): %s", i,
|
||||
gsm48_chan_mode_name(req->ch_mode_rate[i].chan_mode));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* If there is an alternate setting, check that one as well */
|
||||
if (!req->ch_mode_rate_alt_present)
|
||||
return 0;
|
||||
rc = check_requires_voice(&result_requires_voice_alt, req->ch_mode_rate_alt.chan_mode);
|
||||
if (rc < 0) {
|
||||
assignment_fail(GSM0808_CAUSE_REQ_CODEC_TYPE_OR_CONFIG_NOT_SUPP,
|
||||
"Alternate channel mode not supported: %s",
|
||||
gsm48_chan_mode_name(req->ch_mode_rate_alt.chan_mode));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Make sure both settings match */
|
||||
if (result_requires_voice_pref != result_requires_voice_alt) {
|
||||
assignment_fail(GSM0808_CAUSE_REQ_CODEC_TYPE_OR_CONFIG_NOT_SUPP,
|
||||
"Inconsistent channel modes: %s != %s",
|
||||
gsm48_chan_mode_name(req->ch_mode_rate_pref.chan_mode),
|
||||
gsm48_chan_mode_name(req->ch_mode_rate_alt.chan_mode));
|
||||
return -EINVAL;
|
||||
if (i==0)
|
||||
requires_voice_pref = requires_voice_alt;
|
||||
else if (requires_voice_alt != requires_voice_pref) {
|
||||
assignment_fail(GSM0808_CAUSE_REQ_CODEC_TYPE_OR_CONFIG_NOT_SUPP,
|
||||
"Inconsistent channel modes: %s != %s",
|
||||
gsm48_chan_mode_name(req->ch_mode_rate[0].chan_mode),
|
||||
gsm48_chan_mode_name(req->ch_mode_rate[i].chan_mode));
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
conn->assignment.requires_voice_stream = requires_voice_pref;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -369,18 +357,20 @@ static int check_requires_voice_stream(struct gsm_subscriber_connection *conn)
|
|||
static bool reuse_existing_lchan(struct gsm_subscriber_connection *conn)
|
||||
{
|
||||
struct assignment_request *req = &conn->assignment.req;
|
||||
int i;
|
||||
|
||||
if (!conn->lchan)
|
||||
return false;
|
||||
|
||||
/* Check if the currently existing lchan is compatible with the
|
||||
* preferred rate/codec. */
|
||||
if (lchan_type_compat_with_mode(conn->lchan->type, &req->ch_mode_rate_pref))
|
||||
conn->lchan->ch_mode_rate = req->ch_mode_rate_pref;
|
||||
else if (req->ch_mode_rate_alt_present
|
||||
&& lchan_type_compat_with_mode(conn->lchan->type, &req->ch_mode_rate_alt))
|
||||
conn->lchan->ch_mode_rate = req->ch_mode_rate_alt;
|
||||
else
|
||||
for (i = 0; i < req->n_ch_mode_rate; i++)
|
||||
if (lchan_type_compat_with_mode(conn->lchan->type, &req->ch_mode_rate[i])) {
|
||||
conn->lchan->ch_mode_rate = req->ch_mode_rate[i];
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == req->n_ch_mode_rate)
|
||||
return false;
|
||||
|
||||
if (conn->lchan->tch_mode != conn->lchan->ch_mode_rate.chan_mode) {
|
||||
|
@ -398,8 +388,14 @@ static bool reuse_existing_lchan(struct gsm_subscriber_connection *conn)
|
|||
void assignment_fsm_start(struct gsm_subscriber_connection *conn, struct gsm_bts *bts,
|
||||
struct assignment_request *req)
|
||||
{
|
||||
static const char *rate_names[] = {
|
||||
[CH_RATE_SDCCH] = "SDCCH",
|
||||
[CH_RATE_HALF] = "HR",
|
||||
[CH_RATE_FULL] = "FR",
|
||||
};
|
||||
struct osmo_fsm_inst *fi;
|
||||
struct lchan_activate_info info;
|
||||
int i;
|
||||
|
||||
OSMO_ASSERT(conn);
|
||||
OSMO_ASSERT(conn->fi);
|
||||
|
@ -442,17 +438,13 @@ void assignment_fsm_start(struct gsm_subscriber_connection *conn, struct gsm_bts
|
|||
return;
|
||||
}
|
||||
|
||||
/* Try to allocate a new lchan with the preferred codec/rate choice */
|
||||
conn->assignment.new_lchan =
|
||||
lchan_select_by_chan_mode(bts, req->ch_mode_rate_pref.chan_mode, req->ch_mode_rate_pref.full_rate);
|
||||
conn->lchan->ch_mode_rate = req->ch_mode_rate_pref;
|
||||
|
||||
/* In case the lchan allocation fails, we try with the alternat codec/
|
||||
* rate choice (if possible) */
|
||||
if (!conn->assignment.new_lchan && req->ch_mode_rate_alt_present) {
|
||||
conn->assignment.new_lchan =
|
||||
lchan_select_by_chan_mode(bts, req->ch_mode_rate_alt.chan_mode, req->ch_mode_rate_alt.full_rate);
|
||||
conn->lchan->ch_mode_rate = req->ch_mode_rate_alt;
|
||||
/* Try to allocate a new lchan in order of preference */
|
||||
for (i = 0; i < req->n_ch_mode_rate; i++) {
|
||||
conn->assignment.new_lchan = lchan_select_by_chan_mode(bts,
|
||||
req->ch_mode_rate[i].chan_mode, req->ch_mode_rate[i].chan_rate);
|
||||
conn->lchan->ch_mode_rate = req->ch_mode_rate[i];
|
||||
if (conn->assignment.new_lchan)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check whether the lchan allocation was successful or not and tear
|
||||
|
@ -461,21 +453,22 @@ void assignment_fsm_start(struct gsm_subscriber_connection *conn, struct gsm_bts
|
|||
assignment_count_result(BSC_CTR_ASSIGNMENT_NO_CHANNEL);
|
||||
assignment_fail(GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE,
|
||||
"BSSMAP Assignment Command:"
|
||||
" No lchan available for: preferred=%s%s / alternate=%s%s\n",
|
||||
gsm48_chan_mode_name(req->ch_mode_rate_pref.chan_mode),
|
||||
req->ch_mode_rate_pref.full_rate ? ",FR" : ",HR",
|
||||
req->ch_mode_rate_alt_present ?
|
||||
gsm48_chan_mode_name(req->ch_mode_rate_alt.chan_mode) : "none",
|
||||
req->ch_mode_rate_alt_present ?
|
||||
(req->ch_mode_rate_alt.full_rate ? ",FR" : ",HR") : "");
|
||||
" No lchan available for: pref=%s:%s / alt1=%s:%s / alt2=%s:%s\n",
|
||||
gsm48_chan_mode_name(req->ch_mode_rate[0].chan_mode),
|
||||
rate_names[req->ch_mode_rate[0].chan_rate],
|
||||
req->n_ch_mode_rate >= 1 ? gsm48_chan_mode_name(req->ch_mode_rate[0].chan_mode) : "",
|
||||
req->n_ch_mode_rate >= 1 ? rate_names[req->ch_mode_rate[0].chan_rate] : "",
|
||||
req->n_ch_mode_rate >= 2 ? gsm48_chan_mode_name(req->ch_mode_rate[0].chan_mode) : "",
|
||||
req->n_ch_mode_rate >= 2 ? rate_names[req->ch_mode_rate[0].chan_rate] : ""
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
assignment_fsm_update_id(conn);
|
||||
LOG_ASSIGNMENT(conn, LOGL_INFO, "Starting Assignment: chan_mode=%s, full_rate=%d,"
|
||||
LOG_ASSIGNMENT(conn, LOGL_INFO, "Starting Assignment: chan_mode=%s, chan_type=%s,"
|
||||
" aoip=%s MSC-rtp=%s:%u\n",
|
||||
gsm48_chan_mode_name(conn->lchan->ch_mode_rate.chan_mode),
|
||||
conn->lchan->ch_mode_rate.full_rate,
|
||||
rate_names[conn->lchan->ch_mode_rate.chan_rate],
|
||||
req->aoip ? "yes" : "no", req->msc_rtp_addr, req->msc_rtp_port);
|
||||
|
||||
assignment_fsm_state_chg(ASSIGNMENT_ST_WAIT_LCHAN_ACTIVE);
|
||||
|
|
|
@ -324,6 +324,7 @@ int match_codec_pref(struct channel_mode_and_rate *ch_mode_rate,
|
|||
{
|
||||
unsigned int i;
|
||||
uint8_t perm_spch;
|
||||
bool full_rate;
|
||||
bool match = false;
|
||||
const struct gsm0808_speech_codec *sc_match = NULL;
|
||||
int rc;
|
||||
|
@ -337,15 +338,16 @@ int match_codec_pref(struct channel_mode_and_rate *ch_mode_rate,
|
|||
perm_spch = audio_support_to_gsm88(msc->audio_support[i]);
|
||||
|
||||
/* Determine if the result is a half or full rate codec */
|
||||
rc = full_rate_from_perm_spch(&ch_mode_rate->full_rate, perm_spch);
|
||||
rc = full_rate_from_perm_spch(&full_rate, perm_spch);
|
||||
if (rc < 0)
|
||||
return -EINVAL;
|
||||
ch_mode_rate->chan_rate = full_rate ? CH_RATE_FULL : CH_RATE_HALF;
|
||||
|
||||
/* If we have a preference for FR or HR in our request, we
|
||||
* discard the potential match */
|
||||
if (rate_pref == RATE_PREF_HR && ch_mode_rate->full_rate)
|
||||
if (rate_pref == RATE_PREF_HR && ch_mode_rate->chan_rate == CH_RATE_FULL)
|
||||
continue;
|
||||
if (rate_pref == RATE_PREF_FR && !ch_mode_rate->full_rate)
|
||||
if (rate_pref == RATE_PREF_FR && ch_mode_rate->chan_rate == CH_RATE_HALF)
|
||||
continue;
|
||||
|
||||
/* Check this permitted speech value against the BTS specific parameters.
|
||||
|
@ -375,8 +377,8 @@ int match_codec_pref(struct channel_mode_and_rate *ch_mode_rate,
|
|||
|
||||
/* Exit without result, in case no match can be deteched */
|
||||
if (!match) {
|
||||
ch_mode_rate->full_rate = false;
|
||||
ch_mode_rate->chan_mode = GSM48_CMODE_SIGN;
|
||||
ch_mode_rate->chan_rate = CH_RATE_SDCCH;
|
||||
ch_mode_rate->s15_s0 = 0;
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -582,10 +582,11 @@ void handover_start_inter_bsc_in(struct gsm_subscriber_connection *conn,
|
|||
}
|
||||
|
||||
LOG_HO(conn, LOGL_DEBUG, "BTS %u: Found matching audio type: %s %s (for %s)\n",
|
||||
bts->nr, gsm48_chan_mode_name(ch_mode_rate.chan_mode), ch_mode_rate.full_rate? "full-rate" : "half-rate",
|
||||
bts->nr, gsm48_chan_mode_name(ch_mode_rate.chan_mode),
|
||||
ch_mode_rate.chan_rate == CH_RATE_FULL ? "full-rate" : "half-rate",
|
||||
gsm0808_channel_type_name(&req->ct));
|
||||
|
||||
lchan = lchan_select_by_chan_mode(bts, ch_mode_rate.chan_mode, ch_mode_rate.full_rate);
|
||||
lchan = lchan_select_by_chan_mode(bts, ch_mode_rate.chan_mode, ch_mode_rate.chan_rate);
|
||||
if (!lchan) {
|
||||
LOG_HO(conn, LOGL_DEBUG, "BTS %u has no matching free channels\n", bts->nr);
|
||||
continue;
|
||||
|
|
|
@ -128,22 +128,31 @@ _lc_find_bts(struct gsm_bts *bts, enum gsm_phys_chan_config pchan)
|
|||
}
|
||||
|
||||
struct gsm_lchan *lchan_select_by_chan_mode(struct gsm_bts *bts,
|
||||
enum gsm48_chan_mode chan_mode, bool full_rate)
|
||||
enum gsm48_chan_mode chan_mode, enum channel_rate chan_rate)
|
||||
{
|
||||
enum gsm_chan_t type;
|
||||
|
||||
switch (chan_mode) {
|
||||
case GSM48_CMODE_SIGN:
|
||||
type = GSM_LCHAN_SDCCH;
|
||||
switch (chan_rate) {
|
||||
case CH_RATE_SDCCH: type = GSM_LCHAN_SDCCH; break;
|
||||
case CH_RATE_HALF: type = GSM_LCHAN_TCH_H; break;
|
||||
case CH_RATE_FULL: type = GSM_LCHAN_TCH_F; break;
|
||||
default: return NULL;
|
||||
}
|
||||
break;
|
||||
case GSM48_CMODE_SPEECH_EFR:
|
||||
/* EFR works over FR channels only */
|
||||
if (!full_rate)
|
||||
if (chan_rate != CH_RATE_FULL)
|
||||
return NULL;
|
||||
/* fall through */
|
||||
case GSM48_CMODE_SPEECH_V1:
|
||||
case GSM48_CMODE_SPEECH_AMR:
|
||||
type = full_rate ? GSM_LCHAN_TCH_F : GSM_LCHAN_TCH_H;
|
||||
switch (chan_rate) {
|
||||
case CH_RATE_HALF: type = GSM_LCHAN_TCH_H; break;
|
||||
case CH_RATE_FULL: type = GSM_LCHAN_TCH_F; break;
|
||||
default: return NULL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
|
|
|
@ -627,60 +627,48 @@ static int bssmap_handle_lcls_connect_ctrl(struct gsm_subscriber_connection *con
|
|||
static int select_codecs(struct assignment_request *req, struct gsm0808_channel_type *ct,
|
||||
struct gsm_subscriber_connection *conn)
|
||||
{
|
||||
int rc;
|
||||
int rc, i, nc = 0;
|
||||
struct bsc_msc_data *msc;
|
||||
|
||||
msc = conn->sccp.msc;
|
||||
req->ch_mode_rate_alt_present = false;
|
||||
|
||||
switch (ct->ch_rate_type) {
|
||||
case GSM0808_SPEECH_FULL_BM:
|
||||
rc = match_codec_pref(&req->ch_mode_rate_pref, ct, &conn->codec_list, msc, conn_get_bts(conn),
|
||||
rc = match_codec_pref(&req->ch_mode_rate[nc], ct, &conn->codec_list, msc, conn_get_bts(conn),
|
||||
RATE_PREF_FR);
|
||||
nc += (rc == 0);
|
||||
break;
|
||||
case GSM0808_SPEECH_HALF_LM:
|
||||
rc = match_codec_pref(&req->ch_mode_rate_pref, ct, &conn->codec_list, msc, conn_get_bts(conn),
|
||||
rc = match_codec_pref(&req->ch_mode_rate[nc], ct, &conn->codec_list, msc, conn_get_bts(conn),
|
||||
RATE_PREF_HR);
|
||||
nc += (rc == 0);
|
||||
break;
|
||||
case GSM0808_SPEECH_PERM:
|
||||
case GSM0808_SPEECH_PERM_NO_CHANGE:
|
||||
case GSM0808_SPEECH_FULL_PREF_NO_CHANGE:
|
||||
case GSM0808_SPEECH_FULL_PREF:
|
||||
rc = match_codec_pref(&req->ch_mode_rate_pref, ct, &conn->codec_list, msc, conn_get_bts(conn),
|
||||
rc = match_codec_pref(&req->ch_mode_rate[nc], ct, &conn->codec_list, msc, conn_get_bts(conn),
|
||||
RATE_PREF_FR);
|
||||
if (rc < 0) {
|
||||
rc = match_codec_pref(&req->ch_mode_rate_pref, ct, &conn->codec_list, msc, conn_get_bts(conn),
|
||||
RATE_PREF_HR);
|
||||
break;
|
||||
}
|
||||
rc = match_codec_pref(&req->ch_mode_rate_alt, ct, &conn->codec_list, msc, conn_get_bts(conn),
|
||||
nc += (rc == 0);
|
||||
rc = match_codec_pref(&req->ch_mode_rate[nc], ct, &conn->codec_list, msc, conn_get_bts(conn),
|
||||
RATE_PREF_HR);
|
||||
if (rc == 0)
|
||||
req->ch_mode_rate_alt_present = true;
|
||||
rc = 0;
|
||||
nc += (rc == 0);
|
||||
break;
|
||||
case GSM0808_SPEECH_HALF_PREF_NO_CHANGE:
|
||||
case GSM0808_SPEECH_HALF_PREF:
|
||||
rc = match_codec_pref(&req->ch_mode_rate_pref, ct, &conn->codec_list, msc, conn_get_bts(conn),
|
||||
rc = match_codec_pref(&req->ch_mode_rate[nc], ct, &conn->codec_list, msc, conn_get_bts(conn),
|
||||
RATE_PREF_HR);
|
||||
|
||||
if (rc < 0) {
|
||||
rc = match_codec_pref(&req->ch_mode_rate_pref, ct, &conn->codec_list, msc, conn_get_bts(conn),
|
||||
RATE_PREF_FR);
|
||||
break;
|
||||
}
|
||||
rc = match_codec_pref(&req->ch_mode_rate_alt, ct, &conn->codec_list, msc, conn_get_bts(conn),
|
||||
nc += (rc == 0);
|
||||
rc = match_codec_pref(&req->ch_mode_rate[nc], ct, &conn->codec_list, msc, conn_get_bts(conn),
|
||||
RATE_PREF_FR);
|
||||
if (rc == 0)
|
||||
req->ch_mode_rate_alt_present = true;
|
||||
rc = 0;
|
||||
nc += (rc == 0);
|
||||
break;
|
||||
default:
|
||||
rc = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc < 0) {
|
||||
if (!nc) {
|
||||
LOGP(DMSC, LOGL_ERROR, "No supported audio type found for channel_type ="
|
||||
" { ch_indctr=0x%x, ch_rate_type=0x%x, perm_spch=[%s] }\n",
|
||||
ct->ch_indctr, ct->ch_rate_type, osmo_hexdump(ct->perm_spch, ct->perm_spch_len));
|
||||
|
@ -689,29 +677,69 @@ static int select_codecs(struct assignment_request *req, struct gsm0808_channel_
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (req->ch_mode_rate_alt_present) {
|
||||
DEBUGP(DMSC, "Found matching audio type (preferred): %s %s for channel_type ="
|
||||
for (i = 0; i < nc; i++ ) {
|
||||
DEBUGP(DMSC, "Found matching audio type (pref=%d): %s %s for channel_type ="
|
||||
" { ch_indctr=0x%x, ch_rate_type=0x%x, perm_spch=[ %s] }\n",
|
||||
req->ch_mode_rate_pref.full_rate ? "full rate" : "half rate",
|
||||
get_value_string(gsm48_chan_mode_names, req->ch_mode_rate_pref.chan_mode),
|
||||
i,
|
||||
req->ch_mode_rate[i].chan_rate == CH_RATE_FULL ? "full rate" : "half rate",
|
||||
get_value_string(gsm48_chan_mode_names, req->ch_mode_rate[i].chan_mode),
|
||||
ct->ch_indctr, ct->ch_rate_type, osmo_hexdump(ct->perm_spch, ct->perm_spch_len));
|
||||
DEBUGP(DMSC, "Found matching audio type (alternative): %s %s for channel_type ="
|
||||
" { ch_indctr=0x%x, ch_rate_type=0x%x, perm_spch=[ %s] }\n",
|
||||
req->ch_mode_rate_alt.full_rate ? "full rate" : "half rate",
|
||||
get_value_string(gsm48_chan_mode_names, req->ch_mode_rate_alt.chan_mode),
|
||||
ct->ch_indctr, ct->ch_rate_type, osmo_hexdump(ct->perm_spch, ct->perm_spch_len));
|
||||
} else {
|
||||
DEBUGP(DMSC, "Found matching audio type: %s %s for channel_type ="
|
||||
" { ch_indctr=0x%x, ch_rate_type=0x%x, perm_spch=[ %s] }\n",
|
||||
req->ch_mode_rate_pref.full_rate ? "full rate" : "half rate",
|
||||
get_value_string(gsm48_chan_mode_names, req->ch_mode_rate_pref.chan_mode),
|
||||
ct->ch_indctr, ct->ch_rate_type, osmo_hexdump(ct->perm_spch, ct->perm_spch_len));
|
||||
|
||||
}
|
||||
|
||||
req->n_ch_mode_rate = nc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int select_sign_chan(struct assignment_request *req, struct gsm0808_channel_type *ct)
|
||||
{
|
||||
int i, nc = 0;
|
||||
|
||||
switch (ct->ch_rate_type) {
|
||||
case GSM0808_SIGN_ANY:
|
||||
req->ch_mode_rate[nc++].chan_rate = CH_RATE_SDCCH;
|
||||
req->ch_mode_rate[nc++].chan_rate = CH_RATE_HALF;
|
||||
req->ch_mode_rate[nc++].chan_rate = CH_RATE_FULL;
|
||||
break;
|
||||
case GSM0808_SIGN_SDCCH:
|
||||
req->ch_mode_rate[nc++].chan_rate = CH_RATE_SDCCH;
|
||||
break;
|
||||
case GSM0808_SIGN_SDCCH_FULL_BM:
|
||||
req->ch_mode_rate[nc++].chan_rate = CH_RATE_SDCCH;
|
||||
req->ch_mode_rate[nc++].chan_rate = CH_RATE_FULL;
|
||||
break;
|
||||
case GSM0808_SIGN_SDCCH_HALF_LM:
|
||||
req->ch_mode_rate[nc++].chan_rate = CH_RATE_SDCCH;
|
||||
req->ch_mode_rate[nc++].chan_rate = CH_RATE_HALF;
|
||||
break;
|
||||
case GSM0808_SIGN_FULL_BM:
|
||||
req->ch_mode_rate[nc++].chan_rate = CH_RATE_FULL;
|
||||
break;
|
||||
case GSM0808_SIGN_HALF_LM:
|
||||
req->ch_mode_rate[nc++].chan_rate = CH_RATE_HALF;
|
||||
break;
|
||||
case GSM0808_SIGN_FULL_PREF:
|
||||
case GSM0808_SIGN_FULL_PREF_NO_CHANGE:
|
||||
req->ch_mode_rate[nc++].chan_rate = CH_RATE_FULL;
|
||||
req->ch_mode_rate[nc++].chan_rate = CH_RATE_HALF;
|
||||
break;
|
||||
case GSM0808_SIGN_HALF_PREF:
|
||||
case GSM0808_SIGN_HALF_PREF_NO_CHANGE:
|
||||
req->ch_mode_rate[nc++].chan_rate = CH_RATE_HALF;
|
||||
req->ch_mode_rate[nc++].chan_rate = CH_RATE_FULL;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < nc; i++)
|
||||
req->ch_mode_rate[i].chan_mode = GSM48_CMODE_SIGN;
|
||||
|
||||
req->n_ch_mode_rate = nc;
|
||||
|
||||
return nc > 0 ? 0 : -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle the assignment request message.
|
||||
*
|
||||
|
@ -729,7 +757,6 @@ static int bssmap_handle_assignm_req(struct gsm_subscriber_connection *conn,
|
|||
uint8_t cause;
|
||||
int rc;
|
||||
struct assignment_request req = {};
|
||||
struct channel_mode_and_rate ch_mode_rate_pref = {};
|
||||
|
||||
if (!conn) {
|
||||
LOGP(DMSC, LOGL_ERROR,
|
||||
|
@ -850,14 +877,15 @@ static int bssmap_handle_assignm_req(struct gsm_subscriber_connection *conn,
|
|||
}
|
||||
break;
|
||||
case GSM0808_CHAN_SIGN:
|
||||
ch_mode_rate_pref = (struct channel_mode_and_rate) {
|
||||
.chan_mode = GSM48_CMODE_SIGN,
|
||||
};
|
||||
|
||||
req = (struct assignment_request){
|
||||
.aoip = aoip,
|
||||
.ch_mode_rate_pref = ch_mode_rate_pref,
|
||||
};
|
||||
|
||||
rc = select_sign_chan(&req, &ct);
|
||||
if (rc < 0) {
|
||||
cause = GSM0808_CAUSE_INCORRECT_VALUE;
|
||||
goto reject;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
cause = GSM0808_CAUSE_INVALID_MESSAGE_CONTENTS;
|
||||
|
|
|
@ -407,7 +407,7 @@ static int test_match_codec_pref(const struct gsm0808_channel_type *ct, const st
|
|||
|
||||
rc = match_codec_pref(&ch_mode_rate, ct, scl, msc, bts, RATE_PREF_NONE);
|
||||
printf(" * result: rc=%i, full_rate=%i, s15_s0=%04x, chan_mode=%s\n",
|
||||
rc, ch_mode_rate.full_rate, ch_mode_rate.s15_s0, gsm48_chan_mode_name(ch_mode_rate.chan_mode));
|
||||
rc, ch_mode_rate.chan_rate == CH_RATE_FULL, ch_mode_rate.s15_s0, gsm48_chan_mode_name(ch_mode_rate.chan_mode));
|
||||
|
||||
printf("\n");
|
||||
|
||||
|
|
Loading…
Reference in New Issue