diff --git a/include/osmo-bts/bts.h b/include/osmo-bts/bts.h index b1a594c48..e5fc90a2a 100644 --- a/include/osmo-bts/bts.h +++ b/include/osmo-bts/bts.h @@ -65,6 +65,11 @@ const char *btsvariant2str(enum gsm_bts_type_variant v); #define BTS_INTERNAL_FLAG_NM_RCHANNEL_DEPENDS_RCARRIER (1 << 2) /* Whether the BTS model reports interference measurements to L1SAP. */ #define BTS_INTERNAL_FLAG_INTERF_MEAS (1 << 3) +/* Whether the BTS model supports HR GSM RTP payload in + * GSM ETSI TS.101.138 (TIPHON) format */ +#define BTS_INTERNAL_FLAG_SPEECH_H_V1_TS101318 (1 << 4) +/* Whether the BTS model supports HR GSM RTP payload in RFC 5883 format */ +#define BTS_INTERNAL_FLAG_SPEECH_H_V1_RFC5993 (1 << 5) /* BTS implementation flags (internal use, not exposed via OML) */ #define bts_internal_flag_get(bts, flag) \ diff --git a/include/osmo-bts/lchan.h b/include/osmo-bts/lchan.h index d89aa1fd3..b8d99b72e 100644 --- a/include/osmo-bts/lchan.h +++ b/include/osmo-bts/lchan.h @@ -164,6 +164,7 @@ struct gsm_lchan { uint8_t rtp_payload; uint8_t rtp_payload2; uint8_t speech_mode; + bool rtp_hr_rfc5993; struct { bool use; uint8_t local_cid; diff --git a/src/common/l1sap.c b/src/common/l1sap.c index 22b5e8c13..e54733dc8 100644 --- a/src/common/l1sap.c +++ b/src/common/l1sap.c @@ -1253,6 +1253,28 @@ static bool rtppayload_is_valid(struct gsm_lchan *lchan, struct msgb *resp_msg) osmo_hexdump(resp_msg->data, resp_msg->len)); return false; } + + /* Avoid sending an incompatible HR GSM RTP format to lower layers. Two + * formats exist: ETSI TS 101.318 and RFC 5993. This check is only + * carried out when the BTS model explicitly states a preference. */ + if (lchan->tch_mode == GSM48_CMODE_SPEECH_V1 && lchan->type == GSM_LCHAN_TCH_H) { + if (bts_internal_flag_get(lchan->ts->trx->bts, BTS_INTERNAL_FLAG_SPEECH_H_V1_RFC5993)) { + if (resp_msg->len != GSM_HR_BYTES + 1) { + LOGPLCHAN(lchan, DL1P, LOGL_NOTICE, + "RTP->L1: Dropping unexpected HR GSM encoding (expected RFC 5993, got TS 101.318?) %s\n", + osmo_hexdump(resp_msg->data, resp_msg->len)); + return false; + } + } else if (bts_internal_flag_get(lchan->ts->trx->bts, BTS_INTERNAL_FLAG_SPEECH_H_V1_TS101318)) { + if (resp_msg->len != GSM_HR_BYTES) { + LOGPLCHAN(lchan, DL1P, LOGL_NOTICE, + "RTP->L1: Dropping unexpected HR GSM encoding (expected TS 101.318, got RFC 5993?) %s\n", + osmo_hexdump(resp_msg->data, resp_msg->len)); + return false; + } + } + } + return true; } @@ -1888,10 +1910,43 @@ void l1sap_rtp_rx_cb(struct osmo_rtp_socket *rs, const uint8_t *rtp_pl, if (lchan->loopback) return; - msg = l1sap_msgb_alloc(rtp_pl_len); - if (!msg) + /* There are two different specifications that describe how HR GSM audio should be encapsulated in RTP frames: + * RFC 5993 and ETSI TS 101.318 (TIPHON). In order to be able to accept both formats we convert them on + * reception depending on what the particular BTS model supports. */ + switch (lchan->tch_mode) { + case GSM48_CMODE_SPEECH_V1: + if (lchan->type == GSM_LCHAN_TCH_H && rtp_pl_len == GSM_HR_BYTES + && bts_internal_flag_get(lchan->ts->trx->bts, BTS_INTERNAL_FLAG_SPEECH_H_V1_RFC5993)) { + msg = l1sap_msgb_alloc(rtp_pl_len + 1); + if (!msg) + return; + /* Note: The only difference between both formats is that RFC 5993 specifies an additional one + * byte TOC header in front of the audio payload. (See also: RFC 5993, section 5.2) */ + msgb_put_u8(msg, 0x00); + memcpy(msgb_put(msg, rtp_pl_len), rtp_pl, rtp_pl_len); + break; + } else if (lchan->type == GSM_LCHAN_TCH_H && rtp_pl_len == GSM_HR_BYTES + 1 + && bts_internal_flag_get(lchan->ts->trx->bts, BTS_INTERNAL_FLAG_SPEECH_H_V1_TS101318)) { + msg = l1sap_msgb_alloc(rtp_pl_len - 1); + if (!msg) + return; + memcpy(msgb_put(msg, rtp_pl_len - 1), rtp_pl + 1, rtp_pl_len - 1); + break; + } + + /* NOTE: Each BTS model must specify which HR GSM RTP format it supports. Since forwarding a random + * payload format might lead to unexpected effects and unreliable operation in the field it is better + * to drop the payload early. */ + LOGP(DL1P, LOGL_ERROR, + "BTS model does not specify HR GSM RTP format (RFC5993 or ETSI TS 101.318?), dropping payload!\n"); return; - memcpy(msgb_put(msg, rtp_pl_len), rtp_pl, rtp_pl_len); + default: + msg = l1sap_msgb_alloc(rtp_pl_len); + if (!msg) + return; + memcpy(msgb_put(msg, rtp_pl_len), rtp_pl, rtp_pl_len); + } + msgb_pull(msg, sizeof(struct osmo_phsap_prim)); /* Store RTP header Marker bit in control buffer */ diff --git a/src/osmo-bts-lc15/main.c b/src/osmo-bts-lc15/main.c index cb2a9ac87..dd82f5ea0 100644 --- a/src/osmo-bts-lc15/main.c +++ b/src/osmo-bts-lc15/main.c @@ -113,6 +113,7 @@ int bts_model_init(struct gsm_bts *bts) bts_internal_flag_set(bts, BTS_INTERNAL_FLAG_MS_PWR_CTRL_DSP); bts_internal_flag_set(bts, BTS_INTERNAL_FLAG_NM_RCHANNEL_DEPENDS_RCARRIER); + bts_internal_flag_set(bts, BTS_INTERNAL_FLAG_SPEECH_H_V1_TS101318); return 0; } diff --git a/src/osmo-bts-oc2g/main.c b/src/osmo-bts-oc2g/main.c index 4484d58bd..560c6c309 100644 --- a/src/osmo-bts-oc2g/main.c +++ b/src/osmo-bts-oc2g/main.c @@ -114,6 +114,7 @@ int bts_model_init(struct gsm_bts *bts) bts_internal_flag_set(bts, BTS_INTERNAL_FLAG_MS_PWR_CTRL_DSP); bts_internal_flag_set(bts, BTS_INTERNAL_FLAG_NM_RCHANNEL_DEPENDS_RCARRIER); + bts_internal_flag_set(bts, BTS_INTERNAL_FLAG_SPEECH_H_V1_TS101318); return 0; } diff --git a/src/osmo-bts-sysmo/main.c b/src/osmo-bts-sysmo/main.c index 95492ebc1..e2a9882c3 100644 --- a/src/osmo-bts-sysmo/main.c +++ b/src/osmo-bts-sysmo/main.c @@ -81,6 +81,7 @@ int bts_model_init(struct gsm_bts *bts) bts_internal_flag_set(bts, BTS_INTERNAL_FLAG_MEAS_PAYLOAD_COMB); bts_internal_flag_set(bts, BTS_INTERNAL_FLAG_MS_PWR_CTRL_DSP); bts_internal_flag_set(bts, BTS_INTERNAL_FLAG_NM_RCHANNEL_DEPENDS_RCARRIER); + bts_internal_flag_set(bts, BTS_INTERNAL_FLAG_SPEECH_H_V1_TS101318); return 0; } diff --git a/src/osmo-bts-trx/main.c b/src/osmo-bts-trx/main.c index 4bd7f0f1d..19aaa8c33 100644 --- a/src/osmo-bts-trx/main.c +++ b/src/osmo-bts-trx/main.c @@ -157,6 +157,7 @@ int bts_model_init(struct gsm_bts *bts) bts_internal_flag_set(bts, BTS_INTERNAL_FLAG_MEAS_PAYLOAD_COMB); bts_internal_flag_set(bts, BTS_INTERNAL_FLAG_INTERF_MEAS); + bts_internal_flag_set(bts, BTS_INTERNAL_FLAG_SPEECH_H_V1_RFC5993); return 0; } diff --git a/src/osmo-bts-virtual/main.c b/src/osmo-bts-virtual/main.c index 20b480f48..ad0d27e18 100644 --- a/src/osmo-bts-virtual/main.c +++ b/src/osmo-bts-virtual/main.c @@ -71,6 +71,8 @@ int bts_model_init(struct gsm_bts *bts) osmo_bts_set_feature(bts->features, BTS_FEAT_SPEECH_H_AMR); osmo_bts_set_feature(bts->features, BTS_FEAT_SPEECH_H_V1); + bts_internal_flag_set(bts, BTS_INTERNAL_FLAG_SPEECH_H_V1_RFC5993); + return 0; }