FreeSwitch的AMR/AMR-WB编码通话因解码问题导致通话杂音

FreeSwitch使用自带的AMR和AMR-WB编解码器BUG,双方通话协商为AMR或AMR-WB时,通话在录音的情况下可能变为杂音,导致无法正常通话。此问题可以通过修改FreeSwitch处理相关的代码来解决。

本文章是在FreeSwitch 1.10.9的代码基础上进行的改动,过早的版本,或者过于未来的版本可能有改动,如果时间不长应该大同小异。

  1. 问题原因
  2. 解决方案
  3. 代码改动

1.问题原因:

AMR和AMR-WB在RTP传输过程中,有两种模式:

字节对齐模式(OA)

带宽效率模式(BE)

当协商为带宽效率模式(BE)时,会对每个RTP报文的CMR后面的F、FT、Q位进行位移。

BE模式

OA模式

FreeSwitch在解码AMR和AMR-WB编码部分直接对读取到的switch_frame_t结构体内的数据进行unpack操作,对于将要传输的原始数据进行了位移修改,导致了被叫侧发出去的数据是被位移函数破坏的数据,产生了杂音。

mod_amr.c的switch_amr_decode函数:


static switch_status_t switch_amr_decode(switch_codec_t *codec,
										 switch_codec_t *other_codec,
										 void *encoded_data,
										 uint32_t encoded_data_len,
										 uint32_t encoded_rate, void *decoded_data, uint32_t *decoded_data_len, uint32_t *decoded_rate,
										 unsigned int *flag)
{
#ifdef AMR_PASSTHROUGH
	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "This codec is only usable in passthrough mode!\n");
	return SWITCH_STATUS_FALSE;
#else
    struct amr_context *context = codec->private_info;
    //此处直接将编码数据赋值给buf指针进行操作,造成了数据破坏
    unsigned char *buf = encoded_data;
    uint8_t tmp[SWITCH_AMR_OUT_MAX_SIZE];

    if (!context) {
        return SWITCH_STATUS_FALSE;
    }

    if (globals.debug) {
        switch_amr_info(codec, buf, encoded_data_len, switch_test_flag(context, AMR_OPT_OCTET_ALIGN) ? 1 : 0, "AMR decoder");
    }

    if (switch_test_flag(context, AMR_OPT_OCTET_ALIGN)) {
        /* Octed Aligned */
        if (!switch_amr_unpack_oa(buf, tmp, encoded_data_len)) {
            return SWITCH_STATUS_FALSE;
        }
    } else {
        /* Bandwidth Efficient */
        if (!switch_amr_unpack_be(buf, tmp, encoded_data_len)) {
            return SWITCH_STATUS_FALSE;
        }
    }

    Decoder_Interface_Decode(context->decoder_state, tmp, (int16_t *) decoded_data, 0);
    *decoded_data_len = codec->implementation->decoded_bytes_per_packet;

    return SWITCH_STATUS_SUCCESS;
#endif
}

mod_amrwb.c的switch_amrwb_decode函数:


static switch_status_t switch_amrwb_decode(switch_codec_t *codec,
										   switch_codec_t *other_codec,
										   void *encoded_data,
										   uint32_t encoded_data_len,
										   uint32_t encoded_rate, void *decoded_data, uint32_t *decoded_data_len, uint32_t *decoded_rate,
										   unsigned int *flag)
{
#ifdef AMRWB_PASSTHROUGH
	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "This codec is only usable in passthrough mode!\n");
	return SWITCH_STATUS_FALSE;
#else
	struct amrwb_context *context = codec->private_info;
    //此处直接将编码数据赋值给buf指针进行操作,造成了数据破坏
	unsigned char *buf = encoded_data;
	uint8_t tmp[SWITCH_AMRWB_OUT_MAX_SIZE];

    if (!context) {
        return SWITCH_STATUS_FALSE;
    }

    if (globals.debug) {
        switch_amrwb_info(codec, buf, encoded_data_len, switch_test_flag(context, AMRWB_OPT_OCTET_ALIGN) ? 1 : 0, "AMRWB decoder");
    }

    if (switch_test_flag(context, AMRWB_OPT_OCTET_ALIGN)) {
        /* Octed Aligned */
        if (!switch_amrwb_unpack_oa(buf, tmp, encoded_data_len)) {
            return SWITCH_STATUS_FALSE;
        }
    } else {
        /* Bandwidth Efficient */
        if (!switch_amrwb_unpack_be(buf, tmp, encoded_data_len)) {
            return SWITCH_STATUS_FALSE;
        }
    }

    D_IF_decode(context->decoder_state, tmp, (int16_t *) decoded_data, 0);

    *decoded_data_len = codec->implementation->decoded_bytes_per_packet;

    return SWITCH_STATUS_SUCCESS;
#endif
}

2.解决方案:

增加一个临时的buffer数组,将编码数据复制到buffer中,使解码操作只操作临时的buffer,不对原始数据造成影响。

3.代码改动:

        将第一步的代码改为如下代码

        mod_amr.c的switch_amr_decode函数:


static switch_status_t switch_amr_decode(switch_codec_t *codec,
										 switch_codec_t *other_codec,
										 void *encoded_data,
										 uint32_t encoded_data_len,
										 uint32_t encoded_rate, void *decoded_data, uint32_t *decoded_data_len, uint32_t *decoded_rate,
										 unsigned int *flag)
{
#ifdef AMR_PASSTHROUGH
	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "This codec is only usable in passthrough mode!\n");
	return SWITCH_STATUS_FALSE;
#else
    struct amr_context *context = codec->private_info;
    //此处直接将编码数据赋值给buf指针进行操作,造成了数据破坏
    unsigned char *buf = encoded_data;
    uint8_t tmp[SWITCH_AMR_OUT_MAX_SIZE];
    uint8_t tmp_enc[128] = {0};

    if (!context) {
        return SWITCH_STATUS_FALSE;
    }

    if (encoded_data_len > 128) {
        return SWITCH_STATUS_FALSE;
    }

    memcpy(tmp_enc, buf, encoded_data_len);
    if (globals.debug) {
        switch_amr_info(codec, buf, encoded_data_len, switch_test_flag(context, AMR_OPT_OCTET_ALIGN) ? 1 : 0, "AMR decoder");
    }

    if (switch_test_flag(context, AMR_OPT_OCTET_ALIGN)) {
        /* Octed Aligned */
        if (!switch_amr_unpack_oa(tmp_enc, tmp, encoded_data_len)) {
            return SWITCH_STATUS_FALSE;
        }
    } else {
        /* Bandwidth Efficient */
        if (!switch_amr_unpack_be(tmp_enc, tmp, encoded_data_len)) {
            return SWITCH_STATUS_FALSE;
        }
    }

    Decoder_Interface_Decode(context->decoder_state, tmp, (int16_t *) decoded_data, 0);
    *decoded_data_len = codec->implementation->decoded_bytes_per_packet;

    return SWITCH_STATUS_SUCCESS;
#endif
}

mod_amrwb.c的switch_amrwb_decode函数:


static switch_status_t switch_amrwb_decode(switch_codec_t *codec,
										   switch_codec_t *other_codec,
										   void *encoded_data,
										   uint32_t encoded_data_len,
										   uint32_t encoded_rate, void *decoded_data, uint32_t *decoded_data_len, uint32_t *decoded_rate,
										   unsigned int *flag)
{
#ifdef AMRWB_PASSTHROUGH
	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "This codec is only usable in passthrough mode!\n");
	return SWITCH_STATUS_FALSE;
#else
	struct amrwb_context *context = codec->private_info;
    //此处直接将编码数据赋值给buf指针进行操作,造成了数据破坏
	unsigned char *buf = encoded_data;
	uint8_t tmp[SWITCH_AMRWB_OUT_MAX_SIZE];
    uint8_t tmp_enc[128] = {0};

    if (!context) {
        return SWITCH_STATUS_FALSE;
    }

    if (globals.debug) {
        switch_amrwb_info(codec, buf, encoded_data_len, switch_test_flag(context, AMRWB_OPT_OCTET_ALIGN) ? 1 : 0, "AMRWB decoder");
    }

    if (encoded_data_len > 128) {
        return SWITCH_STATUS_FALSE;
    }
    memcpy(tmp_enc, buf, encoded_data_len);
    if (switch_test_flag(context, AMRWB_OPT_OCTET_ALIGN)) {
        /* Octed Aligned */
        if (!switch_amrwb_unpack_oa(tmp_enc, tmp, encoded_data_len)) {
            return SWITCH_STATUS_FALSE;
        }
    } else {
        /* Bandwidth Efficient */
        if (!switch_amrwb_unpack_be(tmp_enc, tmp, encoded_data_len)) {
            return SWITCH_STATUS_FALSE;
        }
    }

    D_IF_decode(context->decoder_state, tmp, (int16_t *) decoded_data, 0);

    *decoded_data_len = codec->implementation->decoded_bytes_per_packet;

    return SWITCH_STATUS_SUCCESS;
#endif
}

改动后,重新编译即可正常。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jkkj1630

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值