aboutsummaryrefslogtreecommitdiffstats
path: root/src/common
diff options
context:
space:
mode:
authorJean-Francois Dionne <jf.dionne@nutaq.com>2017-01-24 12:10:13 -0500
committerHarald Welte <laforge@gnumonks.org>2017-02-01 19:13:16 +0000
commita760a043c4153770fe9577259989169cb2286a82 (patch)
treec9eae9c50a3e6bc6124f7e5c6a1b304d699c6bf1 /src/common
parent16b4179fbeaf3289e7aa41e4f9a0ac5d9d6206f6 (diff)
Fix AMR HR DTX FSM logic.
Fix SID_FIRST_INH detection during speech and when SID_FIRST is interrupted by FACCH. Fix SID_UPDATE_INH detection during silence and when SID_UPDATE is interrupted by FACCH. Add a delay for SID_FIRST to appear at the right time after FACCH. Fix extra byte sent in downlink for SID_FIRST and SID_UPDATE. Change-Id: Ia811305e15541f2376005df736bd610e8b0d2f69
Diffstat (limited to 'src/common')
-rw-r--r--src/common/dtx_dl_amr_fsm.c171
-rw-r--r--src/common/msg_utils.c42
2 files changed, 156 insertions, 57 deletions
diff --git a/src/common/dtx_dl_amr_fsm.c b/src/common/dtx_dl_amr_fsm.c
index 832e8b4e..d5990489 100644
--- a/src/common/dtx_dl_amr_fsm.c
+++ b/src/common/dtx_dl_amr_fsm.c
@@ -29,9 +29,14 @@ void dtx_fsm_voice(struct osmo_fsm_inst *fi, uint32_t event, void *data)
case E_FACCH:
break;
case E_SID_F:
- case E_SID_U:
osmo_fsm_inst_state_chg(fi, ST_SID_F1, 0, 0);
break;
+ case E_SID_U:
+ osmo_fsm_inst_state_chg(fi, ST_U_NOINH, 0, 0);
+ break;
+ case E_INHIB:
+ osmo_fsm_inst_state_chg(fi, ST_F1_INH_V, 0, 0);
+ break;
default:
LOGP(DL1P, LOGL_ERROR, "Inexpected event %d\n", event);
OSMO_ASSERT(0);
@@ -49,18 +54,12 @@ void dtx_fsm_sid_f1(struct osmo_fsm_inst *fi, uint32_t event, void *data)
case E_SID_U:
osmo_fsm_inst_state_chg(fi, ST_U_NOINH, 0, 0);
break;
- case E_VOICE:
- osmo_fsm_inst_state_chg(fi, ST_VOICE, 0, 0);
- break;
case E_FACCH:
- osmo_fsm_inst_state_chg(fi, ST_ONSET_F, 0, 0);
+ osmo_fsm_inst_state_chg(fi, ST_F1_INH_F, 0, 0);
break;
case E_FIRST:
osmo_fsm_inst_state_chg(fi, ST_SID_F2, 0, 0);
break;
- case E_INHIB:
- osmo_fsm_inst_state_chg(fi, ST_F1_INH, 0, 0);
- break;
case E_ONSET:
osmo_fsm_inst_state_chg(fi, ST_ONSET_V, 0, 0);
break;
@@ -75,10 +74,7 @@ void dtx_fsm_sid_f2(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
switch (event) {
case E_COMPL:
- osmo_fsm_inst_state_chg(fi, ST_SID_U, 0, 0);
- break;
- case E_VOICE:
- osmo_fsm_inst_state_chg(fi, ST_VOICE, 0, 0);
+ osmo_fsm_inst_state_chg(fi, ST_U_NOINH, 0, 0);
break;
case E_FACCH:
osmo_fsm_inst_state_chg(fi, ST_ONSET_F, 0, 0);
@@ -93,11 +89,37 @@ void dtx_fsm_sid_f2(struct osmo_fsm_inst *fi, uint32_t event, void *data)
}
}
-void dtx_fsm_f1_inh(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+void dtx_fsm_f1_inh_v(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ switch (event) {
+ case E_COMPL:
+ osmo_fsm_inst_state_chg(fi, ST_F1_INH_V_REC, 0, 0);
+ break;
+ default:
+ LOGP(DL1P, LOGL_ERROR, "Unexpected event %d\n", event);
+ OSMO_ASSERT(0);
+ break;
+ }
+}
+
+void dtx_fsm_f1_inh_f(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ switch (event) {
+ case E_COMPL:
+ osmo_fsm_inst_state_chg(fi, ST_F1_INH_F_REC, 0, 0);
+ break;
+ default:
+ LOGP(DL1P, LOGL_ERROR, "Unexpected event %d\n", event);
+ OSMO_ASSERT(0);
+ break;
+ }
+}
+
+void dtx_fsm_u_inh_v(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
switch (event) {
case E_COMPL:
- osmo_fsm_inst_state_chg(fi, ST_F1_INH_REC, 0, 0);
+ osmo_fsm_inst_state_chg(fi, ST_U_INH_V_REC, 0, 0);
break;
default:
LOGP(DL1P, LOGL_ERROR, "Unexpected event %d\n", event);
@@ -106,11 +128,11 @@ void dtx_fsm_f1_inh(struct osmo_fsm_inst *fi, uint32_t event, void *data)
}
}
-void dtx_fsm_u_inh(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+void dtx_fsm_u_inh_f(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
switch (event) {
case E_COMPL:
- osmo_fsm_inst_state_chg(fi, ST_U_INH_REC, 0, 0);
+ osmo_fsm_inst_state_chg(fi, ST_U_INH_F_REC, 0, 0);
break;
default:
LOGP(DL1P, LOGL_ERROR, "Unexpected event %d\n", event);
@@ -119,9 +141,10 @@ void dtx_fsm_u_inh(struct osmo_fsm_inst *fi, uint32_t event, void *data)
}
}
-void dtx_fsm_f1_inh_rec(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+void dtx_fsm_f1_inh_v_rec(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
switch (event) {
+ case E_VOICE:
case E_COMPL:
osmo_fsm_inst_state_chg(fi, ST_VOICE, 0, 0);
break;
@@ -132,9 +155,24 @@ void dtx_fsm_f1_inh_rec(struct osmo_fsm_inst *fi, uint32_t event, void *data)
}
}
-void dtx_fsm_u_inh_rec(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+void dtx_fsm_f1_inh_f_rec(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
switch (event) {
+ case E_FACCH:
+ case E_COMPL:
+ osmo_fsm_inst_state_chg(fi, ST_FACCH, 0, 0);
+ break;
+ default:
+ LOGP(DL1P, LOGL_ERROR, "Unexpected event %d\n", event);
+ OSMO_ASSERT(0);
+ break;
+ }
+}
+
+void dtx_fsm_u_inh_v_rec(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ switch (event) {
+ case E_VOICE:
case E_COMPL:
osmo_fsm_inst_state_chg(fi, ST_VOICE, 0, 0);
break;
@@ -145,6 +183,20 @@ void dtx_fsm_u_inh_rec(struct osmo_fsm_inst *fi, uint32_t event, void *data)
}
}
+void dtx_fsm_u_inh_f_rec(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ switch (event) {
+ case E_FACCH:
+ case E_COMPL:
+ osmo_fsm_inst_state_chg(fi, ST_FACCH, 0, 0);
+ break;
+ default:
+ LOGP(DL1P, LOGL_ERROR, "Unexpected event %d\n", event);
+ OSMO_ASSERT(0);
+ break;
+ }
+}
+
void dtx_fsm_u_noinh(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
switch (event) {
@@ -176,13 +228,13 @@ void dtx_fsm_sid_upd(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
switch (event) {
case E_FACCH:
- osmo_fsm_inst_state_chg(fi, ST_ONSET_F, 0, 0);
+ osmo_fsm_inst_state_chg(fi, ST_U_INH_F, 0, 0);
break;
case E_VOICE:
osmo_fsm_inst_state_chg(fi, ST_VOICE, 0, 0);
break;
case E_INHIB:
- osmo_fsm_inst_state_chg(fi, ST_U_INH, 0, 0);
+ osmo_fsm_inst_state_chg(fi, ST_U_INH_V, 0, 0);
break;
case E_SID_U:
case E_SID_F:
@@ -270,40 +322,54 @@ void dtx_fsm_facch(struct osmo_fsm_inst *fi, uint32_t event, void *data)
static struct osmo_fsm_state dtx_dl_amr_fsm_states[] = {
/* default state for non-DTX and DTX when SPEECH is in progress */
[ST_VOICE] = {
- .in_event_mask = X(E_SID_F) | X(E_SID_U) | X(E_VOICE) | X(E_FACCH),
- .out_state_mask = X(ST_SID_F1),
+ .in_event_mask = X(E_SID_F) | X(E_SID_U) | X(E_VOICE) | X(E_FACCH) | X(E_INHIB),
+ .out_state_mask = X(ST_SID_F1) | X(ST_U_NOINH) | X(ST_F1_INH_V),
.name = "Voice",
.action = dtx_fsm_voice,
},
/* SID-FIRST or SID-FIRST-P1 in case of AMR HR:
start of silence period (might be interrupted in case of AMR HR) */
[ST_SID_F1]= {
- .in_event_mask = X(E_SID_F) | X(E_SID_U) | X(E_VOICE) | X(E_FACCH) | X(E_FIRST) | X(E_INHIB) | X(E_ONSET),
- .out_state_mask = X(ST_U_NOINH) | X(ST_VOICE) | X(ST_ONSET_F) | X(ST_SID_F2) | X(ST_F1_INH) | X(ST_ONSET_V),
+ .in_event_mask = X(E_SID_F) | X(E_SID_U) | X(E_FACCH) | X(E_FIRST) | X(E_ONSET),
+ .out_state_mask = X(ST_U_NOINH) | X(ST_ONSET_F) | X(ST_SID_F2) | X(ST_ONSET_V),
.name = "SID-FIRST (P1)",
.action = dtx_fsm_sid_f1,
},
/* SID-FIRST P2 (only for AMR HR):
actual start of silence period in case of AMR HR */
[ST_SID_F2]= {
- .in_event_mask = X(E_COMPL) | X(E_VOICE) | X(E_FACCH) | X(E_ONSET),
- .out_state_mask = X(ST_SID_U) | X(ST_VOICE) | X(ST_ONSET_F) | X(ST_ONSET_V),
+ .in_event_mask = X(E_COMPL) | X(E_FACCH) | X(E_ONSET),
+ .out_state_mask = X(ST_U_NOINH) | X(ST_ONSET_F) | X(ST_ONSET_V),
.name = "SID-FIRST (P2)",
.action = dtx_fsm_sid_f2,
},
/* SID-FIRST Inhibited: incoming SPEECH (only for AMR HR) */
- [ST_F1_INH]= {
+ [ST_F1_INH_V]= {
+ .in_event_mask = X(E_COMPL),
+ .out_state_mask = X(ST_F1_INH_V_REC),
+ .name = "SID-FIRST (Inh, SPEECH)",
+ .action = dtx_fsm_f1_inh_v,
+ },
+ /* SID-FIRST Inhibited: incoming FACCH frame (only for AMR HR) */
+ [ST_F1_INH_F]= {
.in_event_mask = X(E_COMPL),
- .out_state_mask = X(ST_F1_INH_REC),
- .name = "SID-FIRST (Inh)",
- .action = dtx_fsm_f1_inh,
+ .out_state_mask = X(ST_F1_INH_F_REC),
+ .name = "SID-FIRST (Inh, FACCH)",
+ .action = dtx_fsm_f1_inh_f,
},
/* SID-UPDATE Inhibited: incoming SPEECH (only for AMR HR) */
- [ST_U_INH]= {
+ [ST_U_INH_V]= {
.in_event_mask = X(E_COMPL),
- .out_state_mask = X(ST_U_INH_REC),
- .name = "SID-UPDATE (Inh)",
- .action = dtx_fsm_u_inh,
+ .out_state_mask = X(ST_U_INH_V_REC),
+ .name = "SID-UPDATE (Inh, SPEECH)",
+ .action = dtx_fsm_u_inh_v,
+ },
+ /* SID-UPDATE Inhibited: incoming FACCH frame (only for AMR HR) */
+ [ST_U_INH_F]= {
+ .in_event_mask = X(E_COMPL),
+ .out_state_mask = X(ST_U_INH_F_REC),
+ .name = "SID-UPDATE (Inh, FACCH)",
+ .action = dtx_fsm_u_inh_f,
},
/* SID-UPDATE: Inhibited not allowed (only for AMR HR) */
[ST_U_NOINH]= {
@@ -314,24 +380,40 @@ static struct osmo_fsm_state dtx_dl_amr_fsm_states[] = {
},
/* SID-FIRST Inhibition recursion in progress:
Inhibit itself was already sent, now have to send the voice that caused it */
- [ST_F1_INH_REC]= {
- .in_event_mask = X(E_COMPL),
+ [ST_F1_INH_V_REC]= {
+ .in_event_mask = X(E_COMPL) | X(E_VOICE),
.out_state_mask = X(ST_VOICE),
- .name = "SID-FIRST (Inh, Rec)",
- .action = dtx_fsm_f1_inh_rec,
+ .name = "SID-FIRST (Inh, SPEECH, Rec)",
+ .action = dtx_fsm_f1_inh_v_rec,
+ },
+ /* SID-FIRST Inhibition recursion in progress:
+ Inhibit itself was already sent, now have to send the data that caused it */
+ [ST_F1_INH_F_REC]= {
+ .in_event_mask = X(E_COMPL) | X(E_FACCH),
+ .out_state_mask = X(ST_FACCH),
+ .name = "SID-FIRST (Inh, FACCH, Rec)",
+ .action = dtx_fsm_f1_inh_f_rec,
},
/* SID-UPDATE Inhibition recursion in progress:
Inhibit itself was already sent, now have to send the voice that caused it */
- [ST_U_INH_REC]= {
- .in_event_mask = X(E_COMPL),
+ [ST_U_INH_V_REC]= {
+ .in_event_mask = X(E_COMPL) | X(E_VOICE),
.out_state_mask = X(ST_VOICE),
- .name = "SID-UPDATE (Inh, Rec)",
- .action = dtx_fsm_u_inh_rec,
+ .name = "SID-UPDATE (Inh, SPEECH, Rec)",
+ .action = dtx_fsm_u_inh_v_rec,
+ },
+ /* SID-UPDATE Inhibition recursion in progress:
+ Inhibit itself was already sent, now have to send the data that caused it */
+ [ST_U_INH_F_REC]= {
+ .in_event_mask = X(E_COMPL) | X(E_FACCH),
+ .out_state_mask = X(ST_FACCH),
+ .name = "SID-UPDATE (Inh, FACCH, Rec)",
+ .action = dtx_fsm_u_inh_f_rec,
},
/* Silence period with periodic comfort noise data updates */
[ST_SID_U]= {
.in_event_mask = X(E_FACCH) | X(E_VOICE) | X(E_INHIB) | X(E_SID_U) | X(E_SID_F),
- .out_state_mask = X(ST_ONSET_F) | X(ST_VOICE) | X(ST_U_INH) | X(ST_U_NOINH),
+ .out_state_mask = X(ST_ONSET_F) | X(ST_VOICE) | X(ST_U_INH_V) | X(ST_U_INH_F) | X(ST_U_NOINH),
.name = "SID-UPDATE (AMR/HR)",
.action = dtx_fsm_sid_upd,
},
@@ -365,8 +447,7 @@ static struct osmo_fsm_state dtx_dl_amr_fsm_states[] = {
.name = "ONSET (FACCH, Rec)",
.action = dtx_fsm_onset_f_rec,
},
- /* FACCH sending state: no SPEECH was observed before so once we're done
- FSM should get back to silent period via SID-FIRST */
+ /* FACCH sending state */
[ST_FACCH]= {
.in_event_mask = X(E_FACCH) | X(E_VOICE) | X(E_COMPL) | X(E_SID_U) | X(E_SID_F),
.out_state_mask = X(ST_VOICE) | X(ST_SID_F1),
diff --git a/src/common/msg_utils.c b/src/common/msg_utils.c
index 062f5e3a..f936c983 100644
--- a/src/common/msg_utils.c
+++ b/src/common/msg_utils.c
@@ -137,7 +137,7 @@ void dtx_cache_payload(struct gsm_lchan *lchan, const uint8_t *l1_payload,
size_t length, uint32_t fn, int update)
{
size_t amr = (update < 0) ? 0 : 2,
- copy_len = OSMO_MIN(length + 1,
+ copy_len = OSMO_MIN(length,
ARRAY_SIZE(lchan->tch.dtx.cache) - amr);
lchan->tch.dtx.len = copy_len + amr;
@@ -230,7 +230,7 @@ int dtx_dl_amr_fsm_step(struct gsm_lchan *lchan, const uint8_t *rtp_pl,
if (osmo_amr_is_speech(ft)) {
/* AMR HR - SID-FIRST_P1 Inhibition */
- if (marker && dtx_is_first_p1(lchan))
+ if (marker && lchan->tch.dtx.dl_amr_fsm->state == ST_VOICE)
return osmo_fsm_inst_dispatch(lchan->tch.dtx.dl_amr_fsm,
E_INHIB, (void *)lchan);
@@ -261,7 +261,8 @@ int dtx_dl_amr_fsm_step(struct gsm_lchan *lchan, const uint8_t *rtp_pl,
as FIRST regardless of actually decoded type */
dtx_cache_payload(lchan, rtp_pl, rtp_pl_len, fn, false);
return osmo_fsm_inst_dispatch(lchan->tch.dtx.dl_amr_fsm,
- E_SID_F, (void *)lchan);
+ sti ? E_SID_U : E_SID_F,
+ (void *)lchan);
} else if (lchan->tch.dtx.dl_amr_fsm->state != ST_FACCH)
dtx_cache_payload(lchan, rtp_pl, rtp_pl_len, fn, sti);
if (lchan->tch.dtx.dl_amr_fsm->state == ST_SID_F2)
@@ -319,12 +320,24 @@ static inline bool dtx_amr_sid_optional(struct gsm_lchan *lchan, uint32_t fn)
already: we rely here on the order of RTS arrival from L1 - we
expect that PH-DATA.req ALWAYS comes before PH-TCH.req for the
same FN */
- if (lchan->tch.dtx.fn != LCHAN_FN_DUMMY) {
- /* FACCH interruption is over */
- dtx_dispatch(lchan, E_COMPL);
- return false;
- } else
- lchan->tch.dtx.fn = fn;
+ if(lchan->type == GSM_LCHAN_TCH_H) {
+ if (lchan->tch.dtx.fn != LCHAN_FN_DUMMY &&
+ lchan->tch.dtx.fn != LCHAN_FN_WAIT) {
+ /* FACCH interruption is over */
+ dtx_dispatch(lchan, E_COMPL);
+ return false;
+ } else if(lchan->tch.dtx.fn == LCHAN_FN_DUMMY) {
+ lchan->tch.dtx.fn = LCHAN_FN_WAIT;
+ } else
+ lchan->tch.dtx.fn = fn;
+ } else if(lchan->type == GSM_LCHAN_TCH_F) {
+ if (lchan->tch.dtx.fn != LCHAN_FN_DUMMY) {
+ /* FACCH interruption is over */
+ dtx_dispatch(lchan, E_COMPL);
+ return false;
+ } else
+ lchan->tch.dtx.fn = fn;
+ }
/* this FN was already used for FACCH or ONSET message so we just
prepare things for next one */
return true;
@@ -401,9 +414,14 @@ bool dtx_recursion(const struct gsm_lchan *lchan)
if (!dtx_dl_amr_enabled(lchan))
return false;
- if (lchan->tch.dtx.dl_amr_fsm->state == ST_U_INH ||
- lchan->tch.dtx.dl_amr_fsm->state == ST_U_INH_REC ||
- lchan->tch.dtx.dl_amr_fsm->state == ST_F1_INH ||
+ if (lchan->tch.dtx.dl_amr_fsm->state == ST_U_INH_V ||
+ lchan->tch.dtx.dl_amr_fsm->state == ST_U_INH_F ||
+ lchan->tch.dtx.dl_amr_fsm->state == ST_U_INH_V_REC ||
+ lchan->tch.dtx.dl_amr_fsm->state == ST_U_INH_F_REC ||
+ lchan->tch.dtx.dl_amr_fsm->state == ST_F1_INH_V ||
+ lchan->tch.dtx.dl_amr_fsm->state == ST_F1_INH_F ||
+ lchan->tch.dtx.dl_amr_fsm->state == ST_F1_INH_V_REC ||
+ lchan->tch.dtx.dl_amr_fsm->state == ST_F1_INH_F_REC ||
lchan->tch.dtx.dl_amr_fsm->state == ST_ONSET_F ||
lchan->tch.dtx.dl_amr_fsm->state == ST_ONSET_V ||
lchan->tch.dtx.dl_amr_fsm->state == ST_ONSET_F_REC ||